diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 94a88c095b..5413014fbf 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -820,6 +820,7 @@ include_directories("${OPENAIR_DIR}/targets/ARCH/EXMIMO/USERSPACE/LIB/") include_directories("${OPENAIR_DIR}/targets/ARCH/EXMIMO/DEFS") include_directories("${OPENAIR2_DIR}/ENB_APP") include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC") +include_directories("${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC") include_directories("${OPENAIR2_DIR}/UTIL/OSA") include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds6.1.1/liblfds611/inc") include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds7.0.0/liblfds700/inc") @@ -905,8 +906,11 @@ if (FLEXRAN_AGENT_SB_IF) add_library(FLEXRAN_AGENT ${OPENAIR2_DIR}/ENB_APP/flexran_agent_handler.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_common.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_ran_api.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_timer.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_common_internal.c ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c + ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_task_manager.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_net_comm.c diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 119c013832..07278d82b1 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -33,6 +33,13 @@ ORIGIN_PATH=$PWD THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) source $THIS_SCRIPT_PATH/tools/build_helper +# set environment variables (OPENAIR_HOME, ...) +set_openair_env + +#variables for UE data generation +gen_nvram_path=$OPENAIR_DIR/targets/bin +conf_nvram_path=$OPENAIR_DIR/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf + MSC_GEN="False" XFORMS="True" FLEXRAN_AGENT_SB_IF="True" @@ -55,11 +62,10 @@ T_TRACER="False" DISABLE_HARDWARE_DEPENDENCY="False" CMAKE_BUILD_TYPE="" UE_AUTOTEST_TRACE="False" +BUILD_ECLIPSE=0 +CMAKE_CMD='cmake' trap handle_ctrl_c INT -gen_nvram_path=$OPENAIR_DIR/targets/bin -conf_nvram_path=$OPENAIR_DIR/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf - function print_help() { echo_info " This program installs OpenAirInterface Software @@ -141,6 +147,8 @@ Options Disable HW dependency during installation --ue-autotest-trace Enable specific traces for UE autotest framework +--build-eclipse + Build eclipse project files. Paths are auto corrected by fixprj.sh Usage (first build): oaisim (eNB + UE): ./build_oai -I --oaisim -x --install-system-files Eurecom EXMIMO + COTS UE : ./build_oai -I --eNB -x --install-system-files @@ -179,6 +187,7 @@ function main() { GDB=1 CMAKE_BUILD_TYPE="Debug" echo_info "Will Compile with gdb symbols and disable compiler optimization" + CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=Debug" shift;; --eNB) eNB=1 @@ -311,6 +320,11 @@ function main() { UHD_IMAGES_DIR=$2 echo_info "Downloading UHD images in the indicated location" shift 2;; + --build-eclipse) + BUILD_ECLIPSE=1 + CMAKE_CMD="$CMAKE_CMD"' -DCMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT=TRUE -G"Eclipse CDT4 - Unix Makefiles"' + echo_info "Enabling build eclipse project support" + shift 1;; -h | --help) print_help exit 1;; @@ -321,6 +335,9 @@ function main() { esac done + CMAKE_CMD="$CMAKE_CMD .." + echo_info "CMAKE_CMD=$CMAKE_CMD" + ######################################################### # check validity of HW and TP parameters for RRH and eNB ######################################################### @@ -391,7 +408,6 @@ function main() { echo_info "2. Setting the OAI PATHS ..." - set_openair_env cecho "OPENAIR_DIR = $OPENAIR_DIR" $green # for conf files copy in this bash script @@ -495,7 +511,7 @@ function main() { fi echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file cd $DIR/$lte_build_dir/build - cmake .. + eval $CMAKE_CMD fi if [ "$eNB" = "1" -o "$UE" = "1" ] ; then @@ -524,7 +540,7 @@ function main() { # mkdir -p $DIR/at_commands/build # cd $DIR/at_commands/build -# cmake .. +# eval $CMAKE_CMD # compilations \ # at_commands at_nas_ue \ # at_nas_ue $dbin/at_nas_ue @@ -533,7 +549,7 @@ function main() { mkdir -p $DIR/nas_sim_tools/build cd $DIR/nas_sim_tools/build - cmake .. + eval $CMAKE_CMD compilations \ nas_sim_tools usim \ usim $dbin/usim @@ -562,7 +578,7 @@ function main() { mkdir -p build cd build rm -f *sim - cmake .. + eval $CMAKE_CMD fi if [ "$SIMUS_PHY" = "1" ] ; then @@ -640,7 +656,7 @@ function main() { [ "$CLEAN" = "1" ] && rm -rf $DIR/$oaisim_build_dir/build mkdir -p $DIR/$oaisim_build_dir/build cd $DIR/$oaisim_build_dir/build - cmake .. + eval $CMAKE_CMD compilations \ $oaisim_build_dir $oaisim_exec \ $oaisim_exec $dbin/$oaisim_exec.$REL @@ -651,7 +667,7 @@ function main() { echo_info "Compiling at_nas_ue" mkdir -p $DIR/at_commands/build cd $DIR/at_commands/build - cmake .. + eval $CMAKE_CMD compilations \ at_commands at_nas_ue \ at_nas_ue $dbin/at_nas_ue @@ -665,7 +681,7 @@ function main() { [ "$CLEAN" = "1" ] && rm -rf $DIR/nas_sim_tools/build mkdir -p $DIR/nas_sim_tools/build cd $DIR/nas_sim_tools/build - cmake .. + eval $CMAKE_CMD compilations \ nas_sim_tools usim \ usim $dbin/usim @@ -722,7 +738,7 @@ function main() { #[ "$CLEAN" = "1" ] && rm -rf $DIR/oaisim_mme_build_oai/build #mkdir -p $DIR/oaisim_mme_build_oai/build #cd $DIR/oaisim_mme_build_oai/build - #cmake .. + #eval $CMAKE_CMD #compilations \ # oaisim_mme_build_oai oaisim_mme \ # oaisim_mme $dbin/oaisim_mme.$REL @@ -752,7 +768,7 @@ function main() { echo "set ( T_TRACER $T_TRACER )" >> $cmake_file echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file cd $DIR/$rrh_build_dir/build - cmake .. + eval $CMAKE_CMD compilations \ rrh_gw rrh_gw \ rrh_gw $dbin/rrh_gw @@ -761,9 +777,9 @@ function main() { # build RF device and transport protocol libraries ##################################### - if [ "$eNB" = "1" -o "$RRH" = "1" ] ; then + if [ "$eNB" = "1" -o "$UE" = "1" -o "$RRH" = "1" ] ; then - if [ "$eNB" = "1" ] ; then + if [ "$eNB" = "1" -o "$UE" = "1" ] ; then build_dir=$lte_build_dir else build_dir=$rrh_build_dir @@ -847,7 +863,7 @@ fi [ "$CLEAN" = "1" ] && rm -rf $OPENAIR_DIR/cmake_targets/doxygen/build mkdir -p $OPENAIR_DIR/cmake_targets/doxygen/build cd $OPENAIR_DIR/cmake_targets/doxygen/build - cmake .. + eval $CMAKE_CMD make doc ) >& $doxygen_log fi diff --git a/cmake_targets/build_ue b/cmake_targets/build_ue new file mode 100644 index 0000000000..9d9ca839d1 --- /dev/null +++ b/cmake_targets/build_ue @@ -0,0 +1,6 @@ +#!/bin/bash +#sudo ./build_oai -c -C -I --install-optional-packages --install-system-files --UE -w USRP -V +#sudo ./build_oai -c -C -I --install-optional-packages --UE -w USRP -V +#sudo ./build_oai -c -C --UE -w USRP -V +sudo ./build_oai -c -C --UE -w USRP +#sudo ./build_oai -c -C --UE -w USRP --build-eclipse diff --git a/cmake_targets/tools/init_nas_s1 b/cmake_targets/tools/init_nas_s1 index 5f27c52837..003a3ae600 100644 --- a/cmake_targets/tools/init_nas_s1 +++ b/cmake_targets/tools/init_nas_s1 @@ -33,7 +33,7 @@ # ####################################### -LTEIF=oip0 +LTEIF=oip1 #OPENAIR_DIR=/home/oai/svn-oai/openair4G load_module() { @@ -48,11 +48,11 @@ load_module() { sudo insmod $1 } -load_module $OPENAIR_DIR/targets/bin/ue_ip.ko +load_module ../../targets/bin/ue_ip.ko if [ "$1" = "UE" ]; then - echo "bring up oip0 interface for UE" - ifconfig oip0 up + echo "bring up $LTEIF interface for UE" + ifconfig $LTEIF up fi ip route flush cache diff --git a/cmake_targets/tools/run_ue_s1 b/cmake_targets/tools/run_ue_s1 new file mode 100644 index 0000000000..56b18d72b9 --- /dev/null +++ b/cmake_targets/tools/run_ue_s1 @@ -0,0 +1,33 @@ +#!/bin/bash + +# Carrier frequency in Hz +#FREQ=2660000000 #FDD +FREQ=2350000000 #TDD +NRB=50 +TA=0 + +#9:trace, 8/7:debug, 6:info, 4:warn, 3:error +LOGLEVEL=6 + +#enable or disable soft scope +#SCOPE='' +SCOPE='-d' + +#enable or disable VCD logging +VCD='' +#VCD='-V' + +ISTDD='-T' +#ISTDD='' + +#use external clock +ECLK="--external-clock" +#ECLK="" + +#UE scan carrier +#ISSCAN="--ue-scan-carrier" +ISSCAN="" + +sudo sh -c './init_nas_s1 UE' +cd ../../targets/bin/ +sudo -E ./lte-softmodem.Rel10 -U -C$FREQ -r$NRB $ISSCAN --ue-txgain 70 --ue-rxgain 80 -A $TA $ECLK -W $ISTDD -g $LOGLEVEL $SCOPE 2>&1 | sudo tee /tmp/UE.log diff --git a/openair1/PHY/INIT/README.txt b/openair1/PHY/INIT/README.txt index d40d0feecd..520e0acd4f 100644 --- a/openair1/PHY/INIT/README.txt +++ b/openair1/PHY/INIT/README.txt @@ -2,4 +2,6 @@ This directory contains files related to initialization of variables/structures init_top.c : initialize top-level variables and signal buffers, FFT twiddle factors, etc. lte_init.c : LTE specific initlization routines (DLSCH/ULSCH signal buffers for RX, data buffers for TX, etc.) -init.c : non-LTE initialization routines (to be removed) +lte_param_init.c: used only in unitary simulations. initializes the global variables eNB and UE. +lte_parms.c: contains init_frame_parms to initialize frame parameters structure + diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 2a8e442563..6c0c4ff94c 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -4799,7 +4799,7 @@ int check_dci_format1_1a_coherency(DCI_format_t dci_format, return(0); } - if(harq_pid >8) + if(harq_pid>=8) { LOG_I(PHY,"bad harq id \n"); return(0); @@ -5013,7 +5013,7 @@ int check_dci_format2_2a_coherency(DCI_format_t dci_format, #endif // I- check dci content minimum coherency - if(harq_pid >8) + if(harq_pid>=8) { LOG_I(PHY,"bad harq pid\n"); return(0); diff --git a/openair1/PHY/LTE_TRANSPORT/rar_tools.c b/openair1/PHY/LTE_TRANSPORT/rar_tools.c index 2629c6ba7f..b7550d5573 100644 --- a/openair1/PHY/LTE_TRANSPORT/rar_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/rar_tools.c @@ -258,7 +258,7 @@ int generate_ue_ulsch_params_from_rar(PHY_VARS_UE *ue, if (ulsch->harq_processes[harq_pid]->nb_rb > 4) { msg("rar_tools.c: unlikely rb count for RAR grant : nb_rb > 3\n"); - return(-1); + // return(-1); } // ulsch->harq_processes[harq_pid]->Ndi = 1; diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c index bd49fdacb0..9ae1dc6603 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c @@ -242,7 +242,7 @@ uint32_t ulsch_encoding(uint8_t *a, return(-1); } - if (harq_pid > 7) { + if (harq_pid >= 8) { LOG_E(PHY,"Illegal harq_pid %d\n",harq_pid); return(-1); } diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c index a4bcd802f5..6dced43b5f 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c @@ -402,7 +402,7 @@ void ulsch_modulation(int32_t **txdataF, // x1 is set in lte_gold_generic x2 = (ulsch->rnti<<14) + (subframe<<9) + frame_parms->Nid_cell; //this is c_init in 36.211 Sec 6.3.1 - if (harq_pid > 7) { + if (harq_pid>=8) { printf("ulsch_modulation.c: Illegal harq_pid %d\n",harq_pid); return; } diff --git a/openair1/PHY/TOOLS/lte_phy_scope.c b/openair1/PHY/TOOLS/lte_phy_scope.c index dd057f9975..cea702ef78 100644 --- a/openair1/PHY/TOOLS/lte_phy_scope.c +++ b/openair1/PHY/TOOLS/lte_phy_scope.c @@ -493,7 +493,8 @@ void phy_scope_UE(FD_lte_phy_scope_ue *form, int16_t **chest_f; int16_t *pdsch_llr; int16_t *pdsch_comp; - int8_t *pdcch_llr; + int16_t *pdsch_mag; + int8_t *pdcch_llr; int16_t *pdcch_comp; int8_t *pbch_llr; int16_t *pbch_comp; @@ -571,6 +572,7 @@ void phy_scope_UE(FD_lte_phy_scope_ue *form, pdsch_llr = (int16_t*) phy_vars_ue->pdsch_vars[subframe&0x1][eNB_id]->llr[0]; // stream 0 // pdsch_llr = (int16_t*) phy_vars_ue->lte_ue_pdsch_vars_SI[eNB_id]->llr[0]; // stream 0 pdsch_comp = (int16_t*) phy_vars_ue->pdsch_vars[subframe&0x1][eNB_id]->rxdataF_comp0[0]; + pdsch_mag = (int16_t*) phy_vars_ue->pdsch_vars[subframe&0x1][eNB_id]->dl_ch_mag0[0]; // Received signal in time domain of receive antenna 0 if (rxsig_t != NULL) { @@ -752,8 +754,9 @@ void phy_scope_UE(FD_lte_phy_scope_ue *form, for (k=0; ksymbols_per_tti; k++) { for (i=0; i<12*frame_parms->N_RB_DL/2; i++) { - I[ind] = pdsch_comp[(2*frame_parms->N_RB_DL*12*k)+4*i]; - Q[ind] = pdsch_comp[(2*frame_parms->N_RB_DL*12*k)+4*i+1]; + int j = (2*frame_parms->N_RB_DL*12*k)+4*i; + I[ind] = (pdsch_mag[j ]!=0? 1.0/pdsch_mag[j ]: 0.0) * pdsch_comp[j ]*1.0; + Q[ind] = (pdsch_mag[j+1]!=0? 1.0/pdsch_mag[j+1]: 0.0) * pdsch_comp[j+1]*1.0; ind++; } } diff --git a/openair1/README.TXT b/openair1/README.TXT index 34d3144105..23c86e888e 100644 --- a/openair1/README.TXT +++ b/openair1/README.TXT @@ -1,40 +1,5 @@ This folder contains the software for the device driver of CBMIMO1 and the physical layer signal processing. - -|-- ARCH // contains drivers for hardware -| |-- CBMIMO1 // contains everything related to CBMIMO1 -| | `-- DEVICE_DRIVER -| | |-- Makefile // main Makefile used to compile the driver; usually invoked from the top level Makefile -| | |-- cbmimo1_device.c // main file for device driver (initializes the card, bigphys, main variables) -| | |-- cbmimo1_device.h -| | |-- cbmimo1_dma.c -| | |-- cbmimo1_fileops.c // file that processes IOCTL commands coming from the userspace control utility (USERSPACE_TOOLS/OPENAIR_RF/) -| | |-- cbmimo1_generate_fs4.c // generates test signals (DEBUGGING) -| | |-- cbmimo1_generate_ofdm.c // generates test signals (DEBUGGING) -| | |-- cbmimo1_get_frame.c // code to grab a frame from the card -| | |-- cbmimo1_init.c // code to set up the registers of the card -| | |-- cbmimo1_pci.h -| | |-- cbmimo1_proc.c // generates the proc entries /proc/openair1/bch_stats and /proc/openair1/openair1_state -| | |-- cbmimo1_rf_cntl.c // controls the RF chipset on the card -| | |-- cbmimo1_test.c -| | |-- from_grlib_softconfig.h -| | |-- from_grlib_softregs.h -| | |-- defs.h -| | |-- extern.h -| | `-- vars.h -| |-- COMMON // common for all hardware (mainly bigphys) -| |-- EXPRESS_MIMO // contains everything related to EXPRESS MIMO -|-- DOCS // Documentation -| |-- DOXYGEN // Automaitcally generated DOXYGEN documentation in latex and html -| `-- PAPERS // papers related to openair1 -|-- EMOS // this contains everything related to Eurecom MIMO Openair Sounder (EMOS) -| |-- DOC -| |-- DUMP // program that dumps channel estimate to disk using a FIFO -| |-- GUI -| |-- MATLAB // Matlab code to process measurements -| |-- SIM // EMOS simulator (for DEBUGGING) -| `-- UTIL -|-- MAC_INTERFACE // interface with MAC layer (in openair2) |-- PHY // contains all signal processing related to physical layer (used in real-time AND simulation) General remarks: every directory contains at least defs.h (for declaration of structure and functions), vars.h (for definitions of variables), and extern.h (variables are defined only once in cbmimo1_device.c (for real-time HW operation) or a top-level simulation (in SIMULATION/xxx), if variables are needed in another file, use extern.h) @@ -57,17 +22,19 @@ General remarks: every directory contains at least defs.h (for declaration of st | |-- spec_defs_top.h | |-- types.h | `-- vars.h -|-- SCHED // schedules the different PHY functions according to the nodes role (CH=BS, MR=UE) +|-- SCHED // schedules the different PHY functions according to the nodes role | |-- defs.h | |-- extern.h -| |-- phy_procedures.c // non-LTE PHY procedures this is used in synchronized mode to schedule the slot processing | |-- phy_procedures_emos.c // non-LTE PHY procedures for EMOS | |-- phy_procedures_emos.h | |-- phy_procedures_lte_eNb.c // LTE PHY procedures for eNB (from 36-213) | |-- phy_procedures_lte_ue.c // LTE PHY procedures for UE (from 36-213) +| |-- phy_procedures_lte_common.c // LTE PHY procedures common for UE and eNB (from 36-213) +| |-- phy_mac_stub.c //MAC stub that generates channels when used in phy-test-mode +| |-- pucch_pc.c // power control for PUCCH +| |-- pusch_pc.c // power control for PUSCH +| |-- srs_pc.c // power control for SRS | |-- rt_compat.h -| |-- sched.c // contains the top level scheduler (only for CBMIMO1 HW) -| |-- sched_lte.c // same as sched.c for LTE (only for CBMIMO1 HW) | `-- vars.h |-- SIMULATION // contains simulation routines to test PHY | |-- LTE_PHY // LTE simulation testbenches for unitary simulation of transport/physical channels @@ -76,17 +43,9 @@ General remarks: every directory contains at least defs.h (for declaration of st | | |-- dlsim.c // PDSCH simulation testbench | | |-- ulsim.c // PUSCH simulation testbench | | |-- pucchsim.c // PUCCH simulation testbench -| |-- LTE_PHY_L2 // LTE simulation testbench for full system simulation (PHY,MAC,RLC,RRC,PDCP) -| `-- TOOLS | |-- RF -|-- USERSPACE_TOOLS // tools that run in userspace (not kernel) -| |-- OCTAVE -| | |-- AGILE_RF_TOOLS // octave tools to test agile RF -| | |-- CBMIMO1_TOOLS // octave interface for CBMIMO1 -| | |-- GPIB // octave tools to control signal generator (used for calibration) -| | `-- PHY_SIM // octave implementation of sync -| |-- OPENAIR_RF // tool to interface with the device driver using IOCTL -| |-- SCOPE // tool to visualize data from PHY (channel estimates, IQ plots, etc.). Communicates with kernel module using shared memory. -| `-- SENSING // tools related to sensing +| |-- ETH_TRANSPORT +| `-- TOOLS + diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index a9142a9918..2f2be51aaa 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -190,7 +190,7 @@ int mac_phy_remove_ue(module_id_t Mod_idP,rnti_t rntiP) { eNB = PHY_vars_eNB_g[Mod_idP][CC_id]; for (i=0; idlsch[i]==NULL) || (eNB->ulsch[i]==NULL)) { - MSC_LOG_EVENT(MSC_PHY_ENB, "0 Failed remove ue %"PRIx16" (ENOMEM)", rnti); + 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 { diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 776de2335d..83eeee1f31 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -633,7 +633,13 @@ PUCCH_FMT_t get_pucch_format(lte_frame_type_t frame_type, } if(SR_payload == 1) { - return pucch_format1; + if (frame_type == FDD) { + return pucch_format1; + } else if (frame_type == TDD) { + return pucch_format1b; + } else { + AssertFatal(1==0,"Unknown frame_type"); + } } } else @@ -729,7 +735,7 @@ uint16_t get_n1_pucch(PHY_VARS_UE *ue, } else if (subframe == 8) { // ACK subframes 4 candidate_dl[0] = 4; } else { - LOG_E(PHY,"[UE%d] : Frame %d phy_procedures_lte.c: get_n1pucch, illegal subframe %d for tdd_config %d\n", + LOG_E(PHY,"[UE%d] : Frame %d phy_procedures_lte.c: get_n1pucch, illegal tx-subframe %d for tdd_config %d\n", ue->Mod_id,proc->frame_tx,subframe,frame_parms->tdd_config); return(0); } @@ -743,8 +749,8 @@ uint16_t get_n1_pucch(PHY_VARS_UE *ue, } } if (last_dl >= 10) { - LOG_E(PHY,"[UE%d] : Frame %d phy_procedures_lte.c: get_n1pucch, illegal subframe %d for tdd_config %d\n", - ue->Mod_id,proc->frame_tx,last_dl,frame_parms->tdd_config); + LOG_E(PHY,"[UE%d] : Frame %d phy_procedures_lte.c: get_n1pucch, illegal rx-subframe %d (tx-subframe %d) for tdd_config %d\n", + ue->Mod_id,proc->frame_tx,last_dl,subframe,frame_parms->tdd_config); return (0); } @@ -1775,13 +1781,13 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin } } - ack_status_cw0 = reset_ack(&ue->frame_parms, + ack_status_cw0 = get_ack(&ue->frame_parms, ue->dlsch[proc->subframe_rx&0x1][eNB_id][0]->harq_ack, subframe_tx, pucch_ack_payload, 0); - ack_status_cw1 = reset_ack(&ue->frame_parms, + ack_status_cw1 = get_ack(&ue->frame_parms, ue->dlsch[proc->subframe_rx&0x1][eNB_id][1]->harq_ack, subframe_tx, pucch_ack_payload, @@ -3236,7 +3242,8 @@ void process_rar(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, int eNB_id, runmode_t mo ue->prach_resources[eNB_id]->ra_RNTI, dlsch0->harq_processes[0]->b, &ue->pdcch_vars[subframe_rx & 0x1][eNB_id]->crnti, - ue->prach_resources[eNB_id]->ra_PreambleIndex); + ue->prach_resources[eNB_id]->ra_PreambleIndex, + dlsch0->harq_processes[0]->b); // alter the 'b' buffer so it contains only the selected RAR header and RAR payload ue->pdcch_vars[(subframe_rx+1) & 0x1][eNB_id]->crnti = ue->pdcch_vars[subframe_rx & 0x1][eNB_id]->crnti; diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index aa8e9360ea..b8e23f2d98 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -1301,7 +1301,7 @@ int main(int argc, char **argv) unsigned int ret; unsigned int coded_bits_per_codeword=0,nsymb; //,tbs=0; - unsigned int tx_lev=0,tx_lev_dB=0,trials,errs[4]= {0,0,0,0},errs2[4]= {0,0,0,0},round_trials[4]= {0,0,0,0},dci_errors=0;//,num_layers; + unsigned int tx_lev=0,tx_lev_dB=0,trials,errs[4]= {0,0,0,0},errs2[4]= {0,0,0,0},round_trials[4]= {0,0,0,0},dci_errors[4]={0,0,0,0};//,num_layers; //int re_allocated; char fname[32],vname[32]; FILE *bler_fd; @@ -1998,7 +1998,7 @@ int main(int argc, char **argv) } */ - UE->pdcch_vars[0][0]->crnti = n_rnti; + UE->pdcch_vars[subframe & 0x1][0]->crnti = n_rnti; // Fill in UL_alloc UL_alloc_pdu.type = 0; @@ -2246,7 +2246,10 @@ int main(int argc, char **argv) round_trials[2] = 0; round_trials[3] = 0; - dci_errors=0; + dci_errors[0]=0; + dci_errors[1]=0; + dci_errors[2]=0; + dci_errors[3]=0; // avg_ber = 0; round=0; @@ -2499,6 +2502,9 @@ int main(int argc, char **argv) if (UE->dlsch[subframe&0x1][0][0]->active == 0) { //printf("DCI not received\n"); + dci_errors[round]++; + UE->dlsch_errors[0] = 1; + /* write_output("pdcchF0_ext.m","pdcchF_ext", UE->pdcch_vars[eNB_id]->rxdataF_ext[0],2*3*UE->frame_parms.ofdm_symbol_size,1,1); write_output("pdcch00_ch0_ext.m","pdcch00_ch0_ext",UE->pdcch_vars[eNB_id]->dl_ch_estimates_ext[0],12*UE->frame_parms.N_RB_DL*3,1,1); @@ -2837,13 +2843,13 @@ int main(int argc, char **argv) double std_phy_proc_rx_demod=0; double std_phy_proc_rx_dec=0; - effective_rate = ((double)(round_trials[0]-dci_errors)/((double)round_trials[0] + round_trials[1] + round_trials[2] + round_trials[3])); + effective_rate = 1.0-((double)(errs[0]+errs[1]+errs[2]+errs[3])/((double)round_trials[0] + round_trials[1] + round_trials[2] + round_trials[3])); printf("\n**********************SNR = %f dB (tx_lev %f)**************************\n", SNR, (double)tx_lev_dB+10*log10(UE->frame_parms.ofdm_symbol_size/(NB_RB*12))); - printf("Errors (%d(%d)/%d %d/%d %d/%d %d/%d), Pe = (%e,%e,%e,%e), dci_errors %d/%d, Pe = %e => effective rate %f (%2.1f%%,%f, %f), normalized delay %f (%f)\n", + printf("Errors (%d(%d)/%d %d/%d %d/%d %d/%d), Pe = (%e,%e,%e,%e), dci_errors %d/%d, Pe = %e => effective rate %f, normalized delay %f (%f)\n", errs[0], errs2[0], round_trials[0], @@ -2857,13 +2863,13 @@ int main(int argc, char **argv) (double)errs[1]/(round_trials[0]), (double)errs[2]/(round_trials[0]), (double)errs[3]/(round_trials[0]), - dci_errors, - round_trials[0], - (double)dci_errors/(round_trials[0]), - rate*effective_rate, + dci_errors[0]+dci_errors[1]+dci_errors[2]+dci_errors[3], + round_trials[0]+round_trials[1]+round_trials[2]+round_trials[3], + (double)(dci_errors[0]+dci_errors[1]+dci_errors[2]+dci_errors[3])/(round_trials[0]+round_trials[1]+round_trials[2]+round_trials[3]), + //rate*effective_rate, 100*effective_rate, - rate, - rate*get_Qm(UE->dlsch[subframe&0x1][0][0]->harq_processes[UE->dlsch[subframe&0x1][0][0]->current_harq_pid]->mcs), + //rate, + //rate*get_Qm(UE->dlsch[subframe&0x1][0][0]->harq_processes[UE->dlsch[subframe&0x1][0][0]->current_harq_pid]->mcs), (1.0*(round_trials[0]-errs[0])+2.0*(round_trials[1]-errs[1])+3.0*(round_trials[2]-errs[2])+4.0*(round_trials[3]-errs[3]))/((double)round_trials[0])/ (double)eNB->dlsch[0][0]->harq_processes[0]->TBS, (1.0*(round_trials[0]-errs[0])+2.0*(round_trials[1]-errs[1])+3.0*(round_trials[2]-errs[2])+4.0*(round_trials[3]-errs[3]))/((double)round_trials[0])); @@ -2986,7 +2992,7 @@ int main(int argc, char **argv) round_trials[2], errs[3], round_trials[3], - dci_errors); + dci_errors[0]); } else { fprintf(bler_fd,"%f;%d;%d;%d;%d;%f;%d;%d;%d;%d;%d;%d;%d;%d;%d\n", SNR, @@ -3002,7 +3008,7 @@ int main(int argc, char **argv) round_trials[2], errs[3], round_trials[3], - dci_errors); + dci_errors[0]); } @@ -3035,7 +3041,7 @@ int main(int argc, char **argv) round_trials[2], errs[3], round_trials[3], - dci_errors); + dci_errors[0]); //fprintf(time_meas_fd,"SNR; MCS; TBS; rate; DL_DECOD_ITER; err0; trials0; err1; trials1; err2; trials2; err3; trials3; PE; dci_err;PE;ND;\n"); fprintf(time_meas_fd,"%f;%d;%d;%f; %2.1f%%;%f;%f;%d;%d;%d;%d;%d;%d;%d;%d;%e;%e;%e;%e;%d;%d;%e;%f;%f;", @@ -3058,9 +3064,9 @@ int main(int argc, char **argv) (double)errs[1]/(round_trials[0]), (double)errs[2]/(round_trials[0]), (double)errs[3]/(round_trials[0]), - dci_errors, + dci_errors[0], round_trials[0], - (double)dci_errors/(round_trials[0]), + (double)dci_errors[0]/(round_trials[0]), (1.0*(round_trials[0]-errs[0])+2.0*(round_trials[1]-errs[1])+3.0*(round_trials[2]-errs[2])+4.0*(round_trials[3]-errs[3]))/((double)round_trials[0])/ (double)eNB->dlsch[0][0]->harq_processes[0]->TBS, (1.0*(round_trials[0]-errs[0])+2.0*(round_trials[1]-errs[1])+3.0*(round_trials[2]-errs[2])+4.0*(round_trials[3]-errs[3]))/((double)round_trials[0])); @@ -3079,7 +3085,7 @@ int main(int argc, char **argv) round_trials[2], errs[3], round_trials[3], - dci_errors); + dci_errors[0]); //fprintf(time_meas_fd,"SNR; MCS; TBS; rate; DL_DECOD_ITER; err0; trials0; err1; trials1; err2; trials2; err3; trials3; PE; dci_err;PE;ND;\n"); fprintf(time_meas_fd,"%f;%d;%d;%d;%d;%f;%2.1f;%f;%f;%d;%d;%d;%d;%d;%d;%d;%d;%e;%e;%e;%e;%d;%d;%e;%f;%f;", @@ -3103,9 +3109,9 @@ int main(int argc, char **argv) (double)errs[1]/(round_trials[0]), (double)errs[2]/(round_trials[0]), (double)errs[3]/(round_trials[0]), - dci_errors, + dci_errors[0], round_trials[0], - (double)dci_errors/(round_trials[0]), + (double)dci_errors[0]/(round_trials[0]), (1.0*(round_trials[0]-errs[0])+2.0*(round_trials[1]-errs[1])+3.0*(round_trials[2]-errs[2])+4.0*(round_trials[3]-errs[3]))/((double)round_trials[0])/ (double)eNB->dlsch[0][0]->harq_processes[0]->TBS, (1.0*(round_trials[0]-errs[0])+2.0*(round_trials[1]-errs[1])+3.0*(round_trials[2]-errs[2])+4.0*(round_trials[3]-errs[3]))/((double)round_trials[0])); diff --git a/openair1/SIMULATION/LTE_PHY/pdcchsim.c b/openair1/SIMULATION/LTE_PHY/pdcchsim.c index 4c50aaa5d5..2b13449c61 100644 --- a/openair1/SIMULATION/LTE_PHY/pdcchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pdcchsim.c @@ -653,6 +653,7 @@ int main(int argc, char **argv) printf("-h This message\n"); printf("-a Use AWGN channel and not multipath\n"); printf("-c TDD config\n"); + printf("-S Subframe number (0..9)\n"); printf("-R N_RB_DL\n"); printf("-F use FDD frame\n"); printf("-p Use extended prefix mode\n"); diff --git a/openair2/COMMON/mac_rrc_primitives.h b/openair2/COMMON/mac_rrc_primitives.h index 79172276f5..9a8c363b02 100644 --- a/openair2/COMMON/mac_rrc_primitives.h +++ b/openair2/COMMON/mac_rrc_primitives.h @@ -388,9 +388,9 @@ typedef struct { struct PMCH_InfoList_r9 *pmch_InfoList #endif ); - unsigned int (*mac_rlc_data_req)(module_id_t, unsigned int, char*); + unsigned int (*mac_rlc_data_req)(module_id_t, unsigned int, const unsigned int,char*); void (*mac_rlc_data_ind)(module_id_t, logical_chan_id_t, char*, tb_size_t, num_tb_t, crc_t* ); - mac_rlc_status_resp_t (*mac_rlc_status_ind) (module_id_t enb_mod_idP, module_id_t ue_mod_idP, frame_t frameP, eNB_flag_t eNB_flagP, MBMS_flag_t MBMS_flagP, + mac_rlc_status_resp_t (*mac_rlc_status_ind) (module_id_t enb_mod_idP, module_id_t ue_mod_idP, frame_t frameP, sub_frame_t subframeP, eNB_flag_t eNB_flagP, MBMS_flag_t MBMS_flagP, logical_chan_id_t channel_idP, tb_size_t tb_sizeP); signed int (*rrc_rlc_data_req)(module_id_t, rb_id_t, mui_t, confirm_t, sdu_size_t, char *); void (*rrc_rlc_register_rrc) (void (*rrc_data_indP)(module_id_t , rb_id_t , sdu_size_t , char* ), diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c index 1a43f203df..73ae74a32f 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -31,6 +31,8 @@ #include "flexran_agent_common.h" #include "flexran_agent_mac_internal.h" #include "flexran_agent_net_comm.h" +#include "flexran_agent_timer.h" +#include "flexran_agent_ran_api.h" #include "LAYER2/MAC/proto.h" #include "LAYER2/MAC/flexran_agent_mac_proto.h" @@ -54,683 +56,499 @@ struct lfds700_ringbuffer_element *dl_mac_config_array[NUM_MAX_ENB]; struct lfds700_ringbuffer_state ringbuffer_state[NUM_MAX_ENB]; -int flexran_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg){ +int flexran_agent_mac_stats_reply(mid_t mod_id, + const report_config_t *report_config, + Protocol__FlexUeStatsReport **ue_report, + Protocol__FlexCellStatsReport **cell_report) { - // TODO: Must deal with sanitization of input - // TODO: Must check if RNTIs and cell ids of the request actually exist - // TODO: Must resolve conflicts among stats requests - int i; - err_code_t err_code; - xid_t xid; - uint32_t usec_interval, sec_interval; - - //TODO: We do not deal with multiple CCs at the moment and eNB id is 0 - int enb_id = mod_id; - - //eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; - //UE_list_t *eNB_UE_list= &eNB->UE_list; - - report_config_t report_config; - - uint32_t ue_flags = 0; - uint32_t c_flags = 0; - - Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; - - Protocol__FlexStatsRequest *stats_req = input->stats_request_msg; - xid = (stats_req->header)->xid; - - // Check the type of request that is made - switch(stats_req->body_case) { - case PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ; - Protocol__FlexCompleteStatsRequest *comp_req = stats_req->complete_stats_request; - if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_OFF) { - /*Disable both periodic and continuous updates*/ - flexran_agent_disable_cont_mac_stats_update(mod_id); - flexran_agent_destroy_timer_by_task_id(xid); - *msg = NULL; - return 0; - } else { //One-off, periodical or continuous reporting - //Set the proper flags - ue_flags = comp_req->ue_report_flags; - c_flags = comp_req->cell_report_flags; - //Create a list of all eNB RNTIs and cells - - //Set the number of UEs and create list with their RNTIs stats configs - report_config.nr_ue = flexran_get_num_ues(mod_id); //eNB_UE_list->num_UEs - report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t) * report_config.nr_ue); - if (report_config.ue_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - for (i = 0; i < report_config.nr_ue; i++) { - report_config.ue_report_type[i].ue_rnti = flexran_get_ue_crnti(enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].crnti; - report_config.ue_report_type[i].ue_report_flags = ue_flags; - } - //Set the number of CCs and create a list with the cell stats configs - report_config.nr_cc = MAX_NUM_CCs; - report_config.cc_report_type = (cc_report_type_t *) malloc(sizeof(cc_report_type_t) * report_config.nr_cc); - if (report_config.cc_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - for (i = 0; i < report_config.nr_cc; i++) { - //TODO: Must fill in the proper cell ids - report_config.cc_report_type[i].cc_id = i; - report_config.cc_report_type[i].cc_report_flags = c_flags; - } - /* Check if request was periodical */ - if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_PERIODICAL) { - /* Create a one off flexran message as an argument for the periodical task */ - Protocol__FlexranMessage *timer_msg; - stats_request_config_t request_config; - request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS; - request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE; - request_config.period = 0; - /* Need to make sure that the ue flags are saved (Bug) */ - if (report_config.nr_ue == 0) { - report_config.nr_ue = 1; - report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t)); - if (report_config.ue_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - report_config.ue_report_type[0].ue_rnti = 0; // Dummy value - report_config.ue_report_type[0].ue_report_flags = ue_flags; - } - request_config.config = &report_config; - flexran_agent_mac_stats_request(enb_id, xid, &request_config, &timer_msg); - /* Create a timer */ - long timer_id = 0; - flexran_agent_timer_args_t *timer_args; - timer_args = malloc(sizeof(flexran_agent_timer_args_t)); - memset (timer_args, 0, sizeof(flexran_agent_timer_args_t)); - timer_args->mod_id = enb_id; - timer_args->msg = timer_msg; - /*Convert subframes to usec time*/ - usec_interval = 1000*comp_req->sf; - sec_interval = 0; - /*add seconds if required*/ - if (usec_interval >= 1000*1000) { - sec_interval = usec_interval/(1000*1000); - usec_interval = usec_interval%(1000*1000); - } - flexran_agent_create_timer(sec_interval, usec_interval, FLEXRAN_AGENT_DEFAULT, enb_id, FLEXRAN_AGENT_TIMER_TYPE_PERIODIC, xid, flexran_agent_handle_timed_task,(void*) timer_args, &timer_id); - } else if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_CONTINUOUS) { - /*If request was for continuous updates, disable the previous configuration and - set up a new one*/ - flexran_agent_disable_cont_mac_stats_update(mod_id); - stats_request_config_t request_config; - request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS; - request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE; - request_config.period = 0; - /* Need to make sure that the ue flags are saved (Bug) */ - if (report_config.nr_ue == 0) { - report_config.nr_ue = 1; - report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t)); - if (report_config.ue_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - report_config.ue_report_type[0].ue_rnti = 0; // Dummy value - report_config.ue_report_type[0].ue_report_flags = ue_flags; - } - request_config.config = &report_config; - flexran_agent_enable_cont_mac_stats_update(enb_id, xid, &request_config); - } - } - break; - case PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST:; - Protocol__FlexCellStatsRequest *cell_req = stats_req->cell_stats_request; - // UE report config will be blank - report_config.nr_ue = 0; - report_config.ue_report_type = NULL; - report_config.nr_cc = cell_req->n_cell; - report_config.cc_report_type = (cc_report_type_t *) malloc(sizeof(cc_report_type_t) * report_config.nr_cc); - if (report_config.cc_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - for (i = 0; i < report_config.nr_cc; i++) { - //TODO: Must fill in the proper cell ids - report_config.cc_report_type[i].cc_id = cell_req->cell[i]; - report_config.cc_report_type[i].cc_report_flags = cell_req->flags; - } - break; - case PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST:; - Protocol__FlexUeStatsRequest *ue_req = stats_req->ue_stats_request; - // Cell report config will be blank - report_config.nr_cc = 0; - report_config.cc_report_type = NULL; - report_config.nr_ue = ue_req->n_rnti; - report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t) * report_config.nr_ue); - if (report_config.ue_report_type == NULL) { - // TODO: Add appropriate error code - err_code = -100; - goto error; - } - for (i = 0; i < report_config.nr_ue; i++) { - report_config.ue_report_type[i].ue_rnti = ue_req->rnti[i]; - report_config.ue_report_type[i].ue_report_flags = ue_req->flags; - } - break; - default: - //TODO: Add appropriate error code - err_code = -100; - goto error; - } - - if (flexran_agent_mac_stats_reply(enb_id, xid, &report_config, msg) < 0 ){ - err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; - goto error; - } - - free(report_config.ue_report_type); - free(report_config.cc_report_type); - - return 0; - - error : - LOG_E(FLEXRAN_AGENT, "errno %d occured\n", err_code); - return err_code; -} - -int flexran_agent_mac_stats_request(mid_t mod_id, - xid_t xid, - const stats_request_config_t *report_config, - Protocol__FlexranMessage **msg) { - Protocol__FlexHeader *header; - int i; - - Protocol__FlexStatsRequest *stats_request_msg; - stats_request_msg = malloc(sizeof(Protocol__FlexStatsRequest)); - if(stats_request_msg == NULL) - goto error; - protocol__flex_stats_request__init(stats_request_msg); - - if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REQUEST, &header) != 0) - goto error; - - stats_request_msg->header = header; - - stats_request_msg->type = report_config->report_type; - stats_request_msg->has_type = 1; - - switch (report_config->report_type) { - case PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS: - stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST; - Protocol__FlexCompleteStatsRequest *complete_stats; - complete_stats = malloc(sizeof(Protocol__FlexCompleteStatsRequest)); - if(complete_stats == NULL) - goto error; - protocol__flex_complete_stats_request__init(complete_stats); - complete_stats->report_frequency = report_config->report_frequency; - complete_stats->has_report_frequency = 1; - complete_stats->sf = report_config->period; - complete_stats->has_sf = 1; - complete_stats->has_cell_report_flags = 1; - complete_stats->has_ue_report_flags = 1; - if (report_config->config->nr_cc > 0) { - complete_stats->cell_report_flags = report_config->config->cc_report_type[0].cc_report_flags; - } - if (report_config->config->nr_ue > 0) { - complete_stats->ue_report_flags = report_config->config->ue_report_type[0].ue_report_flags; - } - stats_request_msg->complete_stats_request = complete_stats; - break; - case PROTOCOL__FLEX_STATS_TYPE__FLST_CELL_STATS: - stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST; - Protocol__FlexCellStatsRequest *cell_stats; - cell_stats = malloc(sizeof(Protocol__FlexCellStatsRequest)); - if(cell_stats == NULL) - goto error; - protocol__flex_cell_stats_request__init(cell_stats); - cell_stats->n_cell = report_config->config->nr_cc; - cell_stats->has_flags = 1; - if (cell_stats->n_cell > 0) { - uint32_t *cells; - cells = (uint32_t *) malloc(sizeof(uint32_t)*cell_stats->n_cell); - for (i = 0; i < cell_stats->n_cell; i++) { - cells[i] = report_config->config->cc_report_type[i].cc_id; - } - cell_stats->cell = cells; - cell_stats->flags = report_config->config->cc_report_type[i].cc_report_flags; - } - stats_request_msg->cell_stats_request = cell_stats; - break; - case PROTOCOL__FLEX_STATS_TYPE__FLST_UE_STATS: - stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST; - Protocol__FlexUeStatsRequest *ue_stats; - ue_stats = malloc(sizeof(Protocol__FlexUeStatsRequest)); - if(ue_stats == NULL) - goto error; - protocol__flex_ue_stats_request__init(ue_stats); - ue_stats->n_rnti = report_config->config->nr_ue; - ue_stats->has_flags = 1; - if (ue_stats->n_rnti > 0) { - uint32_t *ues; - ues = (uint32_t *) malloc(sizeof(uint32_t)*ue_stats->n_rnti); - for (i = 0; i < ue_stats->n_rnti; i++) { - ues[i] = report_config->config->ue_report_type[i].ue_rnti; - } - ue_stats->rnti = ues; - ue_stats->flags = report_config->config->ue_report_type[i].ue_report_flags; - } - stats_request_msg->ue_stats_request = ue_stats; - break; - default: - goto error; - } - *msg = malloc(sizeof(Protocol__FlexranMessage)); - if(*msg == NULL) - goto error; - protocol__flexran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG; - (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; - (*msg)->stats_request_msg = stats_request_msg; - return 0; - - error: - // TODO: Need to make proper error handling - if (header != NULL) - free(header); - if (stats_request_msg != NULL) - free(stats_request_msg); - if(*msg != NULL) - free(*msg); - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - return -1; -} - -int flexran_agent_mac_destroy_stats_request(Protocol__FlexranMessage *msg) { - if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG) - goto error; - free(msg->stats_request_msg->header); - if (msg->stats_request_msg->body_case == PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST) { - free(msg->stats_request_msg->cell_stats_request->cell); - } - if (msg->stats_request_msg->body_case == PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST) { - free(msg->stats_request_msg->ue_stats_request->rnti); - } - free(msg->stats_request_msg); - free(msg); - return 0; - - error: - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - return -1; -} - -int flexran_agent_mac_stats_reply(mid_t mod_id, - xid_t xid, - const report_config_t *report_config, - Protocol__FlexranMessage **msg) { - Protocol__FlexHeader *header; + // Protocol__FlexHeader *header; int i, j, k; + // int cc_id = 0; int enb_id = mod_id; - //eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; - //UE_list_t *eNB_UE_list= &eNB->UE_list; - - Protocol__FlexStatsReply *stats_reply_msg; - stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply)); - if (stats_reply_msg == NULL) - goto error; - protocol__flex_stats_reply__init(stats_reply_msg); - - if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) - goto error; - - stats_reply_msg->header = header; - - stats_reply_msg->n_ue_report = report_config->nr_ue; - stats_reply_msg->n_cell_report = report_config->nr_cc; - - Protocol__FlexUeStatsReport **ue_report; - Protocol__FlexCellStatsReport **cell_report; - /* Allocate memory for list of UE reports */ if (report_config->nr_ue > 0) { - ue_report = malloc(sizeof(Protocol__FlexUeStatsReport *) * report_config->nr_ue); - if (ue_report == NULL) - goto error; - for (i = 0; i < report_config->nr_ue; i++) { - ue_report[i] = malloc(sizeof(Protocol__FlexUeStatsReport)); - protocol__flex_ue_stats_report__init(ue_report[i]); - ue_report[i]->rnti = report_config->ue_report_type[i].ue_rnti; - ue_report[i]->has_rnti = 1; - ue_report[i]->flags = report_config->ue_report_type[i].ue_report_flags; - ue_report[i]->has_flags = 1; - /* Check the types of reports that need to be constructed based on flag values */ - /* Check flag for creation of buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_BSR) { - ue_report[i]->n_bsr = 4; - uint32_t *elem; - elem = (uint32_t *) malloc(sizeof(uint32_t)*ue_report[i]->n_bsr); - if (elem == NULL) - goto error; - for (j = 0; j < ue_report[i]->n_bsr; j++) { - // NN: we need to know the cc_id here, consider the first one - elem[j] = flexran_get_ue_bsr (enb_id, i, j); - } - ue_report[i]->bsr = elem; - } + + for (i = 0; i < report_config->nr_ue; i++) { - /* Check flag for creation of PRH report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PRH) { - ue_report[i]->phr = flexran_get_ue_phr (enb_id, i); // eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].phr_info; - ue_report[i]->has_phr = 1; - } - /* Check flag for creation of RLC buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RLC_BS) { - ue_report[i]->n_rlc_report = 3; // Set this to the number of LCs for this UE. This needs to be generalized for for LCs - Protocol__FlexRlcBsr ** rlc_reports; - rlc_reports = malloc(sizeof(Protocol__FlexRlcBsr *) * ue_report[i]->n_rlc_report); - if (rlc_reports == NULL) - goto error; - // NN: see LAYER2/openair2_proc.c for rlc status - for (j = 0; j < ue_report[i]->n_rlc_report; j++) { - rlc_reports[j] = malloc(sizeof(Protocol__FlexRlcBsr)); - if (rlc_reports[j] == NULL) - goto error; - protocol__flex_rlc_bsr__init(rlc_reports[j]); - rlc_reports[j]->lc_id = j + 1; - rlc_reports[j]->has_lc_id = 1; - rlc_reports[j]->tx_queue_size = flexran_get_tx_queue_size(enb_id,i,j + 1); - rlc_reports[j]->has_tx_queue_size = 1; - - //TODO:Set tx queue head of line delay in ms - rlc_reports[j]->tx_queue_hol_delay = flexran_get_hol_delay(enb_id, i, j+1); - rlc_reports[j]->has_tx_queue_hol_delay = 1; - //TODO:Set retransmission queue size in bytes - rlc_reports[j]->retransmission_queue_size = 10; - rlc_reports[j]->has_retransmission_queue_size = 0; - //TODO:Set retransmission queue head of line delay in ms - rlc_reports[j]->retransmission_queue_hol_delay = 100; - rlc_reports[j]->has_retransmission_queue_hol_delay = 0; - //TODO:Set current size of the pending message in bytes - rlc_reports[j]->status_pdu_size = 100; - rlc_reports[j]->has_status_pdu_size = 0; - } - // Add RLC buffer status reports to the full report - if (ue_report[i]->n_rlc_report > 0) - ue_report[i]->rlc_report = rlc_reports; - } + /* Check flag for creation of buffer status report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_BSR) { + //TODO should be automated + ue_report[i]->n_bsr = 4; + uint32_t *elem; + elem = (uint32_t *) malloc(sizeof(uint32_t)*ue_report[i]->n_bsr); + if (elem == NULL) + goto error; + for (j = 0; j < ue_report[i]->n_bsr; j++) { + // NN: we need to know the cc_id here, consider the first one + elem[j] = flexran_get_ue_bsr (enb_id, i, j); + } + + ue_report[i]->bsr = elem; + } + + /* Check flag for creation of PHR report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PHR) { + ue_report[i]->phr = flexran_get_ue_phr (enb_id, i); // eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].phr_info; + ue_report[i]->has_phr = 1; + + } - /* Check flag for creation of MAC CE buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_CE_BS) { - // TODO: Fill in the actual MAC CE buffer status report - ue_report[i]->pending_mac_ces = (flexran_get_MAC_CE_bitmap_TA(enb_id,i,0) | (0 << 1) | (0 << 2) | (0 << 3)) & 15; /* Use as bitmap. Set one or more of the - PROTOCOL__FLEX_CE_TYPE__FLPCET_ values - found in stats_common.pb-c.h. See - flex_ce_type in FlexRAN specification */ - ue_report[i]->has_pending_mac_ces = 1; - } + /* Check flag for creation of RLC buffer status report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RLC_BS) { + ue_report[i]->n_rlc_report = 3; // Set this to the number of LCs for this UE. This needs to be generalized for for LCs + Protocol__FlexRlcBsr ** rlc_reports; + rlc_reports = malloc(sizeof(Protocol__FlexRlcBsr *) * ue_report[i]->n_rlc_report); + if (rlc_reports == NULL) + goto error; - /* Check flag for creation of DL CQI report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_DL_CQI) { - // TODO: Fill in the actual DL CQI report for the UE based on its configuration - Protocol__FlexDlCqiReport * dl_report; - dl_report = malloc(sizeof(Protocol__FlexDlCqiReport)); - if (dl_report == NULL) - goto error; - protocol__flex_dl_cqi_report__init(dl_report); + // NN: see LAYER2/openair2_proc.c for rlc status + for (j = 0; j < ue_report[i]->n_rlc_report; j++) { - dl_report->sfn_sn = flexran_get_sfn_sf(enb_id); - dl_report->has_sfn_sn = 1; - //Set the number of DL CQI reports for this UE. One for each CC - dl_report->n_csi_report = flexran_get_active_CC(enb_id,i); + rlc_reports[j] = malloc(sizeof(Protocol__FlexRlcBsr)); + if (rlc_reports[j] == NULL) + goto error; + protocol__flex_rlc_bsr__init(rlc_reports[j]); + rlc_reports[j]->lc_id = j+1; + rlc_reports[j]->has_lc_id = 1; + rlc_reports[j]->tx_queue_size = flexran_get_tx_queue_size(enb_id, i, j + 1); + rlc_reports[j]->has_tx_queue_size = 1; - //Create the actual CSI reports. - Protocol__FlexDlCsi **csi_reports; - csi_reports = malloc(sizeof(Protocol__FlexDlCsi *)*dl_report->n_csi_report); - if (csi_reports == NULL) - goto error; - for (j = 0; j < dl_report->n_csi_report; j++) { - csi_reports[j] = malloc(sizeof(Protocol__FlexDlCsi)); - if (csi_reports[j] == NULL) - goto error; - protocol__flex_dl_csi__init(csi_reports[j]); - //The servCellIndex for this report - csi_reports[j]->serv_cell_index = j; - csi_reports[j]->has_serv_cell_index = 1; - //The rank indicator value for this cc - csi_reports[j]->ri = flexran_get_current_RI(enb_id,i,j); - csi_reports[j]->has_ri = 1; - //TODO: the type of CSI report based on the configuration of the UE - //For now we only support type P10, which only needs a wideband value - //The full set of types can be found in stats_common.pb-c.h and - //in the FlexRAN specifications - csi_reports[j]->type = PROTOCOL__FLEX_CSI_TYPE__FLCSIT_P10; - csi_reports[j]->has_type = 1; - csi_reports[j]->report_case = PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI; - if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI){ - Protocol__FlexCsiP10 *csi10; - csi10 = malloc(sizeof(Protocol__FlexCsiP10)); - if (csi10 == NULL) - goto error; - protocol__flex_csi_p10__init(csi10); - //TODO: set the wideband value - // NN: this is also depends on cc_id - csi10->wb_cqi = flexran_get_ue_wcqi (enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].dl_cqi; - csi10->has_wb_cqi = 1; - //Add the type of measurements to the csi report in the proper union type - csi_reports[j]->p10csi = csi10; - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P11CSI){ + //TODO:Set tx queue head of line delay in ms + rlc_reports[j]->tx_queue_hol_delay = flexran_get_hol_delay(enb_id, i, j + 1); + rlc_reports[j]->has_tx_queue_hol_delay = 1; + //TODO:Set retransmission queue size in bytes + rlc_reports[j]->retransmission_queue_size = 10; + rlc_reports[j]->has_retransmission_queue_size = 0; + //TODO:Set retransmission queue head of line delay in ms + rlc_reports[j]->retransmission_queue_hol_delay = 100; + rlc_reports[j]->has_retransmission_queue_hol_delay = 0; + //TODO DONE:Set current size of the pending message in bytes + rlc_reports[j]->status_pdu_size = flexran_get_tx_queue_size(enb_id, i, j + 1); + rlc_reports[j]->has_status_pdu_size = 1; - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P20CSI){ + } + // Add RLC buffer status reports to the full report + if (ue_report[i]->n_rlc_report > 0) + ue_report[i]->rlc_report = rlc_reports; - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P21CSI){ + + } - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A12CSI){ + /* Check flag for creation of MAC CE buffer status report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_CE_BS) { + // TODO: Fill in the actual MAC CE buffer status report + ue_report[i]->pending_mac_ces = (flexran_get_MAC_CE_bitmap_TA(enb_id,i,0) | (0 << 1) | (0 << 2) | (0 << 3)) & 15; + // Use as bitmap. Set one or more of the; /* Use as bitmap. Set one or more of the + // PROTOCOL__FLEX_CE_TYPE__FLPCET_ values + // found in stats_common.pb-c.h. See + // flex_ce_type in FlexRAN specification + ue_report[i]->has_pending_mac_ces = 1; + + } - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A22CSI){ + /* Check flag for creation of DL CQI report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_DL_CQI) { + // TODO: Fill in the actual DL CQI report for the UE based on its configuration + Protocol__FlexDlCqiReport * dl_report; + dl_report = malloc(sizeof(Protocol__FlexDlCqiReport)); + if (dl_report == NULL) + goto error; + protocol__flex_dl_cqi_report__init(dl_report); - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A20CSI){ + dl_report->sfn_sn = flexran_get_sfn_sf(enb_id); + dl_report->has_sfn_sn = 1; + //Set the number of DL CQI reports for this UE. One for each CC + dl_report->n_csi_report = flexran_get_active_CC(enb_id,i); + dl_report->n_csi_report = 1 ; + //Create the actual CSI reports. + Protocol__FlexDlCsi **csi_reports; + csi_reports = malloc(sizeof(Protocol__FlexDlCsi *)*dl_report->n_csi_report); + if (csi_reports == NULL) + goto error; + for (j = 0; j < dl_report->n_csi_report; j++) { - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A30CSI){ + csi_reports[j] = malloc(sizeof(Protocol__FlexDlCsi)); + if (csi_reports[j] == NULL) + goto error; + protocol__flex_dl_csi__init(csi_reports[j]); + //The servCellIndex for this report + csi_reports[j]->serv_cell_index = j; + csi_reports[j]->has_serv_cell_index = 1; + //The rank indicator value for this cc + csi_reports[j]->ri = flexran_get_current_RI(enb_id,i,j); + csi_reports[j]->has_ri = 1; + //TODO: the type of CSI report based on the configuration of the UE + //For now we only support type P10, which only needs a wideband value + //The full set of types can be found in stats_common.pb-c.h and + //in the FlexRAN specifications + csi_reports[j]->type = PROTOCOL__FLEX_CSI_TYPE__FLCSIT_P10; + csi_reports[j]->has_type = 1; + csi_reports[j]->report_case = PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI; - } - else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A31CSI){ + if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI){ - } - } - //Add the csi reports to the full DL CQI report - dl_report->csi_report = csi_reports; - //Add the DL CQI report to the stats report - ue_report[i]->dl_cqi_report = dl_report; - } + Protocol__FlexCsiP10 *csi10; + csi10 = malloc(sizeof(Protocol__FlexCsiP10)); + if (csi10 == NULL) + goto error; + protocol__flex_csi_p10__init(csi10); + //TODO: set the wideband value + // NN: this is also depends on cc_id + csi10->wb_cqi = flexran_get_ue_wcqi (enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].dl_cqi; + csi10->has_wb_cqi = 1; + //Add the type of measurements to the csi report in the proper union type + csi_reports[j]->p10csi = csi10; + } - /* Check flag for creation of paging buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PBS) { - //TODO: Fill in the actual paging buffer status report. For this field to be valid, the RNTI - //set in the report must be a P-RNTI - Protocol__FlexPagingBufferReport *paging_report; - paging_report = malloc(sizeof(Protocol__FlexPagingBufferReport)); - if (paging_report == NULL) - goto error; - protocol__flex_paging_buffer_report__init(paging_report); - //Set the number of pending paging messages - paging_report->n_paging_info = 1; - //Provide a report for each pending paging message - Protocol__FlexPagingInfo **p_info; - p_info = malloc(sizeof(Protocol__FlexPagingInfo *) * paging_report->n_paging_info); - if (p_info == NULL) - goto error; - for (j = 0; j < paging_report->n_paging_info; j++) { - p_info[j] = malloc(sizeof(Protocol__FlexPagingInfo)); - if(p_info[j] == NULL) - goto error; - protocol__flex_paging_info__init(p_info[j]); - //TODO: Set paging index. This index is the same that will be used for the scheduling of the - //paging message by the controller - p_info[j]->paging_index = 10; - p_info[j]->has_paging_index = 0; - //TODO:Set the paging message size - p_info[j]->paging_message_size = 100; - p_info[j]->has_paging_message_size = 0; - //TODO: Set the paging subframe - p_info[j]->paging_subframe = 10; - p_info[j]->has_paging_subframe = 0; - //TODO: Set the carrier index for the pending paging message - p_info[j]->carrier_index = 0; - p_info[j]->has_carrier_index = 0; - } - //Add all paging info to the paging buffer rerport - paging_report->paging_info = p_info; - //Add the paging report to the UE report - ue_report[i]->pbr = paging_report; - } + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P11CSI){ - /* Check flag for creation of UL CQI report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_UL_CQI) { - //Fill in the full UL CQI report of the UE - Protocol__FlexUlCqiReport *full_ul_report; - full_ul_report = malloc(sizeof(Protocol__FlexUlCqiReport)); - if(full_ul_report == NULL) - goto error; - protocol__flex_ul_cqi_report__init(full_ul_report); - //TODO:Set the SFN and SF of the generated report - full_ul_report->sfn_sn = flexran_get_sfn_sf(enb_id); - full_ul_report->has_sfn_sn = 1; - //TODO:Set the number of UL measurement reports based on the types of measurements - //configured for this UE and on the servCellIndex - full_ul_report->n_cqi_meas = 1; - Protocol__FlexUlCqi **ul_report; - ul_report = malloc(sizeof(Protocol__FlexUlCqi *) * full_ul_report->n_cqi_meas); - if(ul_report == NULL) - goto error; - //Fill each UL report of the UE for each of the configured report types - for(j = 0; j < full_ul_report->n_cqi_meas; j++) { - ul_report[j] = malloc(sizeof(Protocol__FlexUlCqi)); - if(ul_report[j] == NULL) - goto error; - protocol__flex_ul_cqi__init(ul_report[j]); - //TODO: Set the type of the UL report. As an example set it to SRS UL report - // See enum flex_ul_cqi_type in FlexRAN specification for more details - ul_report[j]->type = PROTOCOL__FLEX_UL_CQI_TYPE__FLUCT_SRS; - ul_report[j]->has_type = 1; - //TODO:Set the number of SINR measurements based on the report type - //See struct flex_ul_cqi in FlexRAN specification for more details - ul_report[j]->n_sinr = 0; - uint32_t *sinr_meas; - sinr_meas = (uint32_t *) malloc(sizeof(uint32_t) * ul_report[j]->n_sinr); - if (sinr_meas == NULL) - goto error; - //TODO:Set the SINR measurements for the specified type - for (k = 0; k < ul_report[j]->n_sinr; k++) { - sinr_meas[k] = 10; - } - ul_report[j]->sinr = sinr_meas; - //TODO: Set the servCellIndex for this report - ul_report[j]->serv_cell_index = 0; - ul_report[j]->has_serv_cell_index = 1; - - //Set the list of UL reports of this UE to the full UL report - full_ul_report->cqi_meas = ul_report; - full_ul_report->n_pucch_dbm = MAX_NUM_CCs; - full_ul_report->pucch_dbm = malloc(sizeof(Protocol__FlexPucchDbm *) * full_ul_report->n_pucch_dbm); + Protocol__FlexCsiP11 *csi11; + csi11 = malloc(sizeof(Protocol__FlexCsiP11)); + if (csi11 == NULL) + goto error; + protocol__flex_csi_p11__init(csi11); + + csi11->wb_cqi = malloc(sizeof(csi11->wb_cqi)); + csi11->n_wb_cqi = 1; + csi11->wb_cqi[0] = flexran_get_ue_wcqi (enb_id, i); + // According To spec 36.213 + + if (flexran_get_antenna_ports(enb_id, j) == 2 && csi_reports[j]->ri == 1) { + // TODO PMI + csi11->wb_pmi = flexran_get_ue_pmi(enb_id); + csi11->has_wb_pmi = 1; - for (j = 0; j < MAX_NUM_CCs; j++) { - full_ul_report->pucch_dbm[j] = malloc(sizeof(Protocol__FlexPucchDbm)); - protocol__flex_pucch_dbm__init(full_ul_report->pucch_dbm[j]); - full_ul_report->pucch_dbm[j]->has_serv_cell_index = 1; - full_ul_report->pucch_dbm[j]->serv_cell_index = j; - if(flexran_get_p0_pucch_dbm(enb_id,i, j) != -1){ - full_ul_report->pucch_dbm[j]->p0_pucch_dbm = flexran_get_p0_pucch_dbm(enb_id,i,j); - full_ul_report->pucch_dbm[j]->has_p0_pucch_dbm = 1; - } - full_ul_report->pucch_dbm[j]->has_p0_pucch_updated = 1; - full_ul_report->pucch_dbm[j]->p0_pucch_updated = flexran_get_p0_pucch_status(enb_id, i, j); - } + } - //Add full UL CQI report to the UE report - ue_report[i]->ul_cqi_report = full_ul_report; - } - } - } - /* Add list of all UE reports to the message */ - stats_reply_msg->ue_report = ue_report; - } + else if (flexran_get_antenna_ports(enb_id, j) == 2 && csi_reports[j]->ri == 2){ + // TODO PMI + csi11->wb_pmi = flexran_get_ue_pmi(enb_id); + csi11->has_wb_pmi = 1; + + } + + else if (flexran_get_antenna_ports(enb_id, j) == 4 && csi_reports[j]->ri == 2){ + // TODO PMI + csi11->wb_pmi = flexran_get_ue_pmi(enb_id); + csi11->has_wb_pmi = 1; + + + } + + csi11->has_wb_pmi = 0; + + csi_reports[j]->p11csi = csi11; + + } + + + + + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P20CSI){ + + Protocol__FlexCsiP20 *csi20; + csi20 = malloc(sizeof(Protocol__FlexCsiP20)); + if (csi20 == NULL) + goto error; + protocol__flex_csi_p20__init(csi20); + + csi20->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + csi20->has_wb_cqi = 1; + + + csi20->bandwidth_part_index = 1 ;//TODO + csi20->has_bandwidth_part_index = 1; + + csi20->sb_index = 1 ;//TODO + csi20->has_sb_index = 1 ; + + + csi_reports[j]->p20csi = csi20; + + + } + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P21CSI){ + + // Protocol__FlexCsiP21 *csi21; + // csi21 = malloc(sizeof(Protocol__FlexCsiP21)); + // if (csi21 == NULL) + // goto error; + // protocol__flex_csi_p21__init(csi21); + + // csi21->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + + + // csi21->wb_pmi = flexran_get_ue_pmi(enb_id); //TDO inside + // csi21->has_wb_pmi = 1; + + // csi21->sb_cqi = 1; // TODO + + // csi21->bandwidth_part_index = 1 ; //TDO inside + // csi21->has_bandwidth_part_index = 1 ; + + // csi21->sb_index = 1 ;//TODO + // csi21->has_sb_index = 1 ; + + + // csi_reports[j]->p20csi = csi21; + + } + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A12CSI){ + + + // Protocol__FlexCsiA12 *csi12; + // csi12 = malloc(sizeof(Protocol__FlexCsiA12)); + // if (csi12 == NULL) + // goto error; + // protocol__flex_csi_a12__init(csi12); + + // csi12->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + + // csi12->sb_pmi = 1 ; //TODO inside + + // TODO continou + } + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A22CSI){ + + // Protocol__FlexCsiA22 *csi22; + // csi22 = malloc(sizeof(Protocol__FlexCsiA22)); + // if (csi22 == NULL) + // goto error; + // protocol__flex_csi_a22__init(csi22); + + // csi22->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + + // csi22->sb_cqi = 1 ; //TODO inside + + // csi22->wb_pmi = flexran_get_ue_wcqi (enb_id, i); + // csi22->has_wb_pmi = 1; + + // csi22->sb_pmi = 1 ; //TODO inside + // csi22->has_wb_pmi = 1; + + // csi22->sb_list = flexran_get_ue_wcqi (enb_id, i); + + + } + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A20CSI){ + + // Protocol__FlexCsiA20 *csi20; + // csi20 = malloc(sizeof(Protocol__FlexCsiA20)); + // if (csi20 == NULL) + // goto error; + // protocol__flex_csi_a20__init(csi20); + + // csi20->wb_cqi = flexran_get_ue_wcqi (enb_id, i); + // csi20->has_wb_cqi = 1; + + // csi20>sb_cqi = 1 ; //TODO inside + // csi20>has_sb_cqi = 1 ; + + // csi20->sb_list = 1; // TODO inside + + + } + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A30CSI){ + + } + + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A31CSI){ + + } + + } + //Add the csi reports to the full DL CQI report + dl_report->csi_report = csi_reports; + //Add the DL CQI report to the stats report + ue_report[i]->dl_cqi_report = dl_report; + + } + + /* Check flag for creation of paging buffer status report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PBS) { + //TODO: Fill in the actual paging buffer status report. For this field to be valid, the RNTI + //set in the report must be a P-RNTI + Protocol__FlexPagingBufferReport *paging_report; + paging_report = malloc(sizeof(Protocol__FlexPagingBufferReport)); + if (paging_report == NULL) + goto error; + protocol__flex_paging_buffer_report__init(paging_report); + //Set the number of pending paging messages + paging_report->n_paging_info = 1; + //Provide a report for each pending paging message + Protocol__FlexPagingInfo **p_info; + p_info = malloc(sizeof(Protocol__FlexPagingInfo *) * paging_report->n_paging_info); + if (p_info == NULL) + goto error; + + for (j = 0; j < paging_report->n_paging_info; j++) { + + p_info[j] = malloc(sizeof(Protocol__FlexPagingInfo)); + if(p_info[j] == NULL) + goto error; + protocol__flex_paging_info__init(p_info[j]); + //TODO: Set paging index. This index is the same that will be used for the scheduling of the + //paging message by the controller + p_info[j]->paging_index = 10; + p_info[j]->has_paging_index = 1; + //TODO:Set the paging message size + p_info[j]->paging_message_size = 100; + p_info[j]->has_paging_message_size = 1; + //TODO: Set the paging subframe + p_info[j]->paging_subframe = 10; + p_info[j]->has_paging_subframe = 1; + //TODO: Set the carrier index for the pending paging message + p_info[j]->carrier_index = 0; + p_info[j]->has_carrier_index = 1; + + } + //Add all paging info to the paging buffer rerport + paging_report->paging_info = p_info; + //Add the paging report to the UE report + ue_report[i]->pbr = paging_report; + } + + /* Check flag for creation of UL CQI report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_UL_CQI) { + + //Fill in the full UL CQI report of the UE + Protocol__FlexUlCqiReport *full_ul_report; + full_ul_report = malloc(sizeof(Protocol__FlexUlCqiReport)); + if(full_ul_report == NULL) + goto error; + protocol__flex_ul_cqi_report__init(full_ul_report); + //TODO:Set the SFN and SF of the generated report + full_ul_report->sfn_sn = flexran_get_sfn_sf(enb_id); + full_ul_report->has_sfn_sn = 1; + //TODO:Set the number of UL measurement reports based on the types of measurements + //configured for this UE and on the servCellIndex + full_ul_report->n_cqi_meas = 1; + Protocol__FlexUlCqi **ul_report; + ul_report = malloc(sizeof(Protocol__FlexUlCqi *) * full_ul_report->n_cqi_meas); + if(ul_report == NULL) + goto error; + //Fill each UL report of the UE for each of the configured report types + for(j = 0; j < full_ul_report->n_cqi_meas; j++) { + + ul_report[j] = malloc(sizeof(Protocol__FlexUlCqi)); + if(ul_report[j] == NULL) + goto error; + protocol__flex_ul_cqi__init(ul_report[j]); + //TODO: Set the type of the UL report. As an example set it to SRS UL report + // See enum flex_ul_cqi_type in FlexRAN specification for more details + ul_report[j]->type = PROTOCOL__FLEX_UL_CQI_TYPE__FLUCT_SRS; + ul_report[j]->has_type = 1; + //TODO:Set the number of SINR measurements based on the report type + //See struct flex_ul_cqi in FlexRAN specification for more details + ul_report[j]->n_sinr = 0; + uint32_t *sinr_meas; + sinr_meas = (uint32_t *) malloc(sizeof(uint32_t) * ul_report[j]->n_sinr); + if (sinr_meas == NULL) + goto error; + //TODO:Set the SINR measurements for the specified type + for (k = 0; k < ul_report[j]->n_sinr; k++) { + sinr_meas[k] = 10; + } + ul_report[j]->sinr = sinr_meas; + //TODO: Set the servCellIndex for this report + ul_report[j]->serv_cell_index = 0; + ul_report[j]->has_serv_cell_index = 1; + + //Set the list of UL reports of this UE to the full UL report + full_ul_report->cqi_meas = ul_report; + + full_ul_report->n_pucch_dbm = MAX_NUM_CCs; + full_ul_report->pucch_dbm = malloc(sizeof(Protocol__FlexPucchDbm *) * full_ul_report->n_pucch_dbm); + + for (j = 0; j < MAX_NUM_CCs; j++) { + + full_ul_report->pucch_dbm[j] = malloc(sizeof(Protocol__FlexPucchDbm)); + protocol__flex_pucch_dbm__init(full_ul_report->pucch_dbm[j]); + full_ul_report->pucch_dbm[j]->has_serv_cell_index = 1; + full_ul_report->pucch_dbm[j]->serv_cell_index = j; + + if(flexran_get_p0_pucch_dbm(enb_id,i, j) != -1){ + full_ul_report->pucch_dbm[j]->p0_pucch_dbm = flexran_get_p0_pucch_dbm(enb_id,i,j); + full_ul_report->pucch_dbm[j]->has_p0_pucch_dbm = 1; + } + } + + + } + // Add full UL CQI report to the UE report + ue_report[i]->ul_cqi_report = full_ul_report; + + + } + + + + + } + + + + + } /* Allocate memory for list of cell reports */ if (report_config->nr_cc > 0) { - cell_report = malloc(sizeof(Protocol__FlexCellStatsReport *) * report_config->nr_cc); - if (cell_report == NULL) - goto error; - // Fill in the Cell reports - for (i = 0; i < report_config->nr_cc; i++) { - cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport)); - if(cell_report[i] == NULL) - goto error; - protocol__flex_cell_stats_report__init(cell_report[i]); - cell_report[i]->carrier_index = report_config->cc_report_type[i].cc_id; - cell_report[i]->has_carrier_index = 1; - cell_report[i]->flags = report_config->cc_report_type[i].cc_report_flags; - cell_report[i]->has_flags = 1; + + + // Fill in the Cell reports + for (i = 0; i < report_config->nr_cc; i++) { - /* Check flag for creation of noise and interference report */ - if(report_config->cc_report_type[i].cc_report_flags & PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE) { - // TODO: Fill in the actual noise and interference report for this cell - Protocol__FlexNoiseInterferenceReport *ni_report; - ni_report = malloc(sizeof(Protocol__FlexNoiseInterferenceReport)); - if(ni_report == NULL) - goto error; - protocol__flex_noise_interference_report__init(ni_report); - // Current frame and subframe number - ni_report->sfn_sf = flexran_get_sfn_sf(enb_id); - ni_report->has_sfn_sf = 1; - //TODO:Received interference power in dbm - ni_report->rip = 0; - ni_report->has_rip = 0; - //TODO:Thermal noise power in dbm - ni_report->tnp = 0; - ni_report->has_tnp = 0; - ni_report->p0_nominal_pucch = flexran_get_p0_nominal_pucch(enb_id, 0); - ni_report->has_p0_nominal_pucch = 1; - cell_report[i]->noise_inter_report = ni_report; - } - } - /* Add list of all cell reports to the message */ - stats_reply_msg->cell_report = cell_report; + /* Check flag for creation of noise and interference report */ + if(report_config->cc_report_type[i].cc_report_flags & PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE) { + // TODO: Fill in the actual noise and interference report for this cell + Protocol__FlexNoiseInterferenceReport *ni_report; + ni_report = malloc(sizeof(Protocol__FlexNoiseInterferenceReport)); + if(ni_report == NULL) + goto error; + protocol__flex_noise_interference_report__init(ni_report); + // Current frame and subframe number + ni_report->sfn_sf = flexran_get_sfn_sf(enb_id); + ni_report->has_sfn_sf = 1; + //TODO:Received interference power in dbm + ni_report->rip = 0; + ni_report->has_rip = 1; + //TODO:Thermal noise power in dbm + ni_report->tnp = 0; + ni_report->has_tnp = 1; + + ni_report->p0_nominal_pucch = flexran_get_p0_nominal_pucch(enb_id, 0); + ni_report->has_p0_nominal_pucch = 1; + cell_report[i]->noise_inter_report = ni_report; + } + } + + + + } - *msg = malloc(sizeof(Protocol__FlexranMessage)); - if(*msg == NULL) - goto error; - protocol__flexran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG; - (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; - (*msg)->stats_reply_msg = stats_reply_msg; return 0; error: - // TODO: Need to make proper error handling - if (header != NULL) - free(header); - if (stats_reply_msg != NULL) - free(stats_reply_msg); - if(*msg != NULL) - free(*msg); - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + + if (cell_report != NULL) + free(cell_report); + if (ue_report != NULL) + free(ue_report); + return -1; } @@ -1346,58 +1164,7 @@ void flexran_agent_send_sf_trigger(mid_t mod_id) { LOG_D(FLEXRAN_AGENT, "Could not send sf trigger message\n"); } -void flexran_agent_send_update_mac_stats(mid_t mod_id) { - Protocol__FlexranMessage *current_report = NULL; - void *data; - int size; - err_code_t err_code; - int priority = 0; - - if (pthread_mutex_lock(mac_stats_context[mod_id].mutex)) { - goto error; - } - - if (mac_stats_context[mod_id].cont_update == 1) { - - /*Create a fresh report with the required flags*/ - err_code = flexran_agent_mac_handle_stats(mod_id, (void *) mac_stats_context[mod_id].stats_req, ¤t_report); - if (err_code < 0) { - goto error; - } - } - /* /\*TODO:Check if a previous reports exists and if yes, generate a report */ - /* *that is the diff between the old and the new report, */ - /* *respecting the thresholds. Otherwise send the new report*\/ */ - /* if (mac_stats_context[mod_id].prev_stats_reply != NULL) { */ - - /* msg = flexran_agent_generate_diff_mac_stats_report(current_report, mac_stats_context[mod_id].prev_stats_reply); */ - - /* /\*Destroy the old stats*\/ */ - /* flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); */ - /* } */ - /* /\*Use the current report for future comparissons*\/ */ - /* mac_stats_context[mod_id].prev_stats_reply = current_report; */ - - - if (pthread_mutex_unlock(mac_stats_context[mod_id].mutex)) { - goto error; - } - - if (current_report != NULL){ - data=flexran_agent_pack_message(current_report, &size); - /*Send any stats updates using the MAC channel of the eNB*/ - if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_MAC, data, size, priority)) { - err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; - goto error; - } - - LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); - return; - } - error: - LOG_D(FLEXRAN_AGENT, "Could not send sf trigger message\n"); -} int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { if (mac_agent_registered[mod_id]) { @@ -1408,11 +1175,10 @@ int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { //xface->agent_ctxt = &shared_ctxt[mod_id]; xface->flexran_agent_send_sr_info = flexran_agent_send_sr_info; xface->flexran_agent_send_sf_trigger = flexran_agent_send_sf_trigger; - xface->flexran_agent_send_update_mac_stats = flexran_agent_send_update_mac_stats; + //xface->flexran_agent_send_update_mac_stats = flexran_agent_send_update_mac_stats; xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_default; //xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_remote; xface->flexran_agent_get_pending_dl_mac_config = flexran_agent_get_pending_dl_mac_config; - xface->flexran_agent_notify_ue_state_change = flexran_agent_ue_state_change; xface->dl_scheduler_loaded_lib = NULL; @@ -1427,10 +1193,10 @@ int flexran_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { //xface->agent_ctxt = NULL; xface->flexran_agent_send_sr_info = NULL; xface->flexran_agent_send_sf_trigger = NULL; - xface->flexran_agent_send_update_mac_stats = NULL; + //xface->flexran_agent_send_update_mac_stats = NULL; xface->flexran_agent_schedule_ue_spec = NULL; xface->flexran_agent_get_pending_dl_mac_config = NULL; - xface->flexran_agent_notify_ue_state_change = NULL; + xface->dl_scheduler_loaded_lib = NULL; @@ -1441,89 +1207,7 @@ int flexran_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { } -/****************************************************** - *Implementations of flexran_agent_mac_internal.h functions - ******************************************************/ - -err_code_t flexran_agent_init_cont_mac_stats_update(mid_t mod_id) { - - /*Initialize the Mac stats update structure*/ - /*Initially the continuous update is set to false*/ - mac_stats_context[mod_id].cont_update = 0; - mac_stats_context[mod_id].is_initialized = 1; - mac_stats_context[mod_id].stats_req = NULL; - mac_stats_context[mod_id].prev_stats_reply = NULL; - mac_stats_context[mod_id].mutex = calloc(1, sizeof(pthread_mutex_t)); - if (mac_stats_context[mod_id].mutex == NULL) - goto error; - if (pthread_mutex_init(mac_stats_context[mod_id].mutex, NULL)) - goto error;; - - return 0; - - error: - return -1; -} - -err_code_t flexran_agent_destroy_cont_mac_stats_update(mid_t mod_id) { - /*Disable the continuous updates for the MAC*/ - mac_stats_context[mod_id].cont_update = 0; - mac_stats_context[mod_id].is_initialized = 0; - flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].stats_req); - flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); - free(mac_stats_context[mod_id].mutex); - - mac_agent_registered[mod_id] = 0; - return 1; -} -err_code_t flexran_agent_enable_cont_mac_stats_update(mid_t mod_id, - xid_t xid, stats_request_config_t *stats_req) { - /*Enable the continuous updates for the MAC*/ - if (pthread_mutex_lock(mac_stats_context[mod_id].mutex)) { - goto error; - } - Protocol__FlexranMessage *req_msg; - flexran_agent_mac_stats_request(mod_id, xid, stats_req, &req_msg); - mac_stats_context[mod_id].stats_req = req_msg; - mac_stats_context[mod_id].prev_stats_reply = NULL; - - mac_stats_context[mod_id].cont_update = 1; - mac_stats_context[mod_id].xid = xid; - - if (pthread_mutex_unlock(mac_stats_context[mod_id].mutex)) { - goto error; - } - return 0; - - error: - LOG_E(FLEXRAN_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); - return -1; -} - -err_code_t flexran_agent_disable_cont_mac_stats_update(mid_t mod_id) { - /*Disable the continuous updates for the MAC*/ - if (pthread_mutex_lock(mac_stats_context[mod_id].mutex)) { - goto error; - } - mac_stats_context[mod_id].cont_update = 0; - mac_stats_context[mod_id].xid = 0; - if (mac_stats_context[mod_id].stats_req != NULL) { - flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].stats_req); - } - if (mac_stats_context[mod_id].prev_stats_reply != NULL) { - flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); - } - if (pthread_mutex_unlock(mac_stats_context[mod_id].mutex)) { - goto error; - } - return 0; - - error: - LOG_E(FLEXRAN_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); - return -1; - -} diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h index e2378e9311..d2db860ce4 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h @@ -37,50 +37,10 @@ #include "flexran_agent_common.h" #include "flexran_agent_extern.h" -/* These types will be used to give - instructions for the type of stats reports - we need to create */ -typedef struct { - uint16_t ue_rnti; - uint32_t ue_report_flags; /* Indicates the report elements - required for this UE id. See - FlexRAN specification 1.2.4.2 */ -} ue_report_type_t; - -typedef struct { - uint16_t cc_id; - uint32_t cc_report_flags; /* Indicates the report elements - required for this CC index. See - FlexRAN specification 1.2.4.3 */ -} cc_report_type_t; - -typedef struct { - int nr_ue; - ue_report_type_t *ue_report_type; - int nr_cc; - cc_report_type_t *cc_report_type; -} report_config_t; - -typedef struct stats_request_config_s{ - uint8_t report_type; - uint8_t report_frequency; - uint16_t period; /*In number of subframes*/ - report_config_t *config; -} stats_request_config_t; /* Initialization function for the agent structures etc */ void flexran_agent_init_mac_agent(mid_t mod_id); -int flexran_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); - -/* Statistics request protocol message constructor and destructor */ -int flexran_agent_mac_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); -int flexran_agent_mac_destroy_stats_request(Protocol__FlexranMessage *msg); - -/* Statistics reply protocol message constructor and destructor */ -int flexran_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg); -int flexran_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg); - /* Scheduling request information protocol message constructor and estructor */ int flexran_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int flexran_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg); @@ -89,6 +49,10 @@ int flexran_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg); int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int flexran_agent_mac_destroy_sf_trigger(Protocol__FlexranMessage *msg); +/* Statistics reply protocol message constructor and destructor */ +int flexran_agent_mac_stats_reply(mid_t mod_id, const report_config_t *report_config, Protocol__FlexUeStatsReport **ue_report, Protocol__FlexCellStatsReport **cell_report); +int flexran_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg); + /* DL MAC scheduling decision protocol message constructor (empty command) and destructor */ int flexran_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage **msg); int flexran_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg); diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h index 9ec8594f88..8354223123 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h @@ -48,7 +48,7 @@ typedef struct { /// Send to the controller all the mac stat updates that occured during this subframe /// based on the stats request configuration - void (*flexran_agent_send_update_mac_stats)(mid_t mod_id); + // void (*flexran_agent_send_update_mac_stats)(mid_t mod_id); /// Provide to the scheduler a pending dl_mac_config message void (*flexran_agent_get_pending_dl_mac_config)(mid_t mod_id, @@ -63,8 +63,8 @@ typedef struct { /// Notify the controller for a state change of a particular UE, by sending the proper /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) - int (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, - uint8_t state_change); + // int (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, + // uint8_t state_change); void *dl_scheduler_loaded_lib; diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c index 1fa9852487..66efafae55 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c @@ -180,10 +180,12 @@ Protocol__FlexUeStatsReport * copy_ue_stats_report(Protocol__FlexUeStatsReport * } } - if (copy->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PRH) { - copy->has_phr = original->has_phr; - copy->phr = original->phr; - } + + + if (copy->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PHR) { + copy->has_phr = original->has_phr; + copy->phr = original->phr; + } if (copy->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RLC_BS) { copy->n_rlc_report = original->n_rlc_report; diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c new file mode 100644 index 0000000000..d48d12d670 --- /dev/null +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.c @@ -0,0 +1,662 @@ +/* + * 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 flexran_agent_mac.c + * \brief FlexRAN agent Control Module RRC + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +#include "flexran_agent_rrc.h" + + +#include "liblfds700.h" + +#include "log.h" + + +/*Flags showing if a rrc agent has already been registered*/ +unsigned int rrc_agent_registered[NUM_MAX_ENB]; + +/*Array containing the Agent-RRC interfaces*/ +AGENT_RRC_xface *agent_rrc_xface[NUM_MAX_ENB]; + +/* Ringbuffer related structs used for maintaining the dl rrc config messages */ +//message_queue_t *rrc_dl_config_queue; +struct lfds700_misc_prng_state rrc_ps[NUM_MAX_ENB]; +struct lfds700_ringbuffer_element *rrc_dl_config_array[NUM_MAX_ENB]; +struct lfds700_ringbuffer_state rrc_ringbuffer_state[NUM_MAX_ENB]; + + + +void flexran_agent_init_rrc_agent(mid_t mod_id) { + lfds700_misc_library_init_valid_on_current_logical_core(); + lfds700_misc_prng_init(&rrc_ps[mod_id]); + int num_elements = RINGBUFFER_SIZE + 1; + //Allow RINGBUFFER_SIZE messages to be stored in the ringbuffer at any time + rrc_dl_config_array[mod_id] = malloc( sizeof(struct lfds700_ringbuffer_element) * num_elements); + lfds700_ringbuffer_init_valid_on_current_logical_core( &rrc_ringbuffer_state[mod_id], rrc_dl_config_array[mod_id], num_elements, &rrc_ps[mod_id], NULL ); +} + + + + + +void flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { + int size; + Protocol__FlexranMessage *msg; + Protocol__FlexHeader *header; + void *data; + int priority = 0; + err_code_t err_code; + + int xid = 0; + + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UE_STATE_CHANGE, &header) != 0) + goto error; + + Protocol__FlexUeStateChange *ue_state_change_msg; + ue_state_change_msg = malloc(sizeof(Protocol__FlexUeStateChange)); + if(ue_state_change_msg == NULL) { + goto error; + } + protocol__flex_ue_state_change__init(ue_state_change_msg); + ue_state_change_msg->has_type = 1; + ue_state_change_msg->type = state_change; + + Protocol__FlexUeConfig *config; + config = malloc(sizeof(Protocol__FlexUeConfig)); + if (config == NULL) { + goto error; + } + protocol__flex_ue_config__init(config); + if (state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED) { + // Simply set the rnti of the UE + config->has_rnti = 1; + config->rnti = rnti; + } else if (state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_UPDATED + || state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED) { + int i = find_UE_id(mod_id, rnti); + config->has_rnti = 1; + config->rnti = rnti; + if(flexran_get_time_alignment_timer(mod_id,i) != -1) { + config->time_alignment_timer = flexran_get_time_alignment_timer(mod_id,i); + config->has_time_alignment_timer = 1; + } + if(flexran_get_meas_gap_config(mod_id,i) != -1){ + config->meas_gap_config_pattern = flexran_get_meas_gap_config(mod_id,i); + config->has_meas_gap_config_pattern = 1; + } + if(config->has_meas_gap_config_pattern == 1 && + config->meas_gap_config_pattern != PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF) { + config->meas_gap_config_sf_offset = flexran_get_meas_gap_config_offset(mod_id,i); + config->has_meas_gap_config_sf_offset = 1; + } + //TODO: Set the SPS configuration (Optional) + //Not supported for now, so we do not set it + + //TODO: Set the SR configuration (Optional) + //We do not set it for now + + //TODO: Set the CQI configuration (Optional) + //We do not set it for now + + if(flexran_get_ue_transmission_mode(mod_id,i) != -1) { + config->transmission_mode = flexran_get_ue_transmission_mode(mod_id,i); + config->has_transmission_mode = 1; + } + + config->ue_aggregated_max_bitrate_ul = flexran_get_ue_aggregated_max_bitrate_ul(mod_id,i); + config->has_ue_aggregated_max_bitrate_ul = 1; + + config->ue_aggregated_max_bitrate_dl = flexran_get_ue_aggregated_max_bitrate_dl(mod_id,i); + config->has_ue_aggregated_max_bitrate_dl = 1; + + //TODO: Set the UE capabilities + Protocol__FlexUeCapabilities *c_capabilities; + c_capabilities = malloc(sizeof(Protocol__FlexUeCapabilities)); + protocol__flex_ue_capabilities__init(c_capabilities); + //TODO: Set half duplex (FDD operation) + c_capabilities->has_half_duplex = 0; + c_capabilities->half_duplex = 1;//flexran_get_half_duplex(i); + //TODO: Set intra-frame hopping flag + c_capabilities->has_intra_sf_hopping = 0; + c_capabilities->intra_sf_hopping = 1;//flexran_get_intra_sf_hopping(i); + //TODO: Set support for type 2 hopping with n_sb > 1 + c_capabilities->has_type2_sb_1 = 0; + c_capabilities->type2_sb_1 = 1;//flexran_get_type2_sb_1(i); + //TODO: Set ue category + c_capabilities->has_ue_category = 0; + c_capabilities->ue_category = 1;//flexran_get_ue_category(i); + //TODO: Set UE support for resource allocation type 1 + c_capabilities->has_res_alloc_type1 = 0; + c_capabilities->res_alloc_type1 = 1;//flexran_get_res_alloc_type1(i); + //Set the capabilites to the message + config->capabilities = c_capabilities; + + if(flexran_get_ue_transmission_antenna(mod_id,i) != -1) { + config->has_ue_transmission_antenna = 1; + config->ue_transmission_antenna = flexran_get_ue_transmission_antenna(mod_id,i); + } + + if(flexran_get_tti_bundling(mod_id,i) != -1) { + config->has_tti_bundling = 1; + config->tti_bundling = flexran_get_tti_bundling(mod_id,i); + } + + if(flexran_get_maxHARQ_TX(mod_id,i) != -1){ + config->has_max_harq_tx = 1; + config->max_harq_tx = flexran_get_maxHARQ_TX(mod_id,i); + } + + if(flexran_get_beta_offset_ack_index(mod_id,i) != -1) { + config->has_beta_offset_ack_index = 1; + config->beta_offset_ack_index = flexran_get_beta_offset_ack_index(mod_id,i); + } + + if(flexran_get_beta_offset_ri_index(mod_id,i) != -1) { + config->has_beta_offset_ri_index = 1; + config->beta_offset_ri_index = flexran_get_beta_offset_ri_index(mod_id,i); + } + + if(flexran_get_beta_offset_cqi_index(mod_id,i) != -1) { + config->has_beta_offset_cqi_index = 1; + config->beta_offset_cqi_index = flexran_get_beta_offset_cqi_index(mod_id,i); + } + + if(flexran_get_ack_nack_simultaneous_trans(mod_id,i) != -1) { + config->has_ack_nack_simultaneous_trans = 1; + config->ack_nack_simultaneous_trans = flexran_get_ack_nack_simultaneous_trans(mod_id,i); + } + + if(flexran_get_simultaneous_ack_nack_cqi(mod_id,i) != -1) { + config->has_simultaneous_ack_nack_cqi = 1; + config->simultaneous_ack_nack_cqi = flexran_get_simultaneous_ack_nack_cqi(mod_id,i); + } + + if(flexran_get_aperiodic_cqi_rep_mode(mod_id,i) != -1) { + config->has_aperiodic_cqi_rep_mode = 1; + int mode = flexran_get_aperiodic_cqi_rep_mode(mod_id,i); + if (mode > 4) { + config->aperiodic_cqi_rep_mode = PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_NONE; + } else { + config->aperiodic_cqi_rep_mode = mode; + } + } + + if(flexran_get_tdd_ack_nack_feedback(mod_id, i) != -1) { + config->has_tdd_ack_nack_feedback = 1; + config->tdd_ack_nack_feedback = flexran_get_tdd_ack_nack_feedback(mod_id,i); + } + + if(flexran_get_ack_nack_repetition_factor(mod_id, i) != -1) { + config->has_ack_nack_repetition_factor = 1; + config->ack_nack_repetition_factor = flexran_get_ack_nack_repetition_factor(mod_id,i); + } + + if(flexran_get_extended_bsr_size(mod_id, i) != -1) { + config->has_extended_bsr_size = 1; + config->extended_bsr_size = flexran_get_extended_bsr_size(mod_id,i); + } + + config->has_pcell_carrier_index = 1; + config->pcell_carrier_index = UE_PCCID(mod_id, i); + //TODO: Set carrier aggregation support (boolean) + config->has_ca_support = 0; + config->ca_support = 0; + if(config->has_ca_support){ + //TODO: Set cross carrier scheduling support (boolean) + config->has_cross_carrier_sched_support = 1; + config->cross_carrier_sched_support = 0; + //TODO: Set secondary cells configuration + // We do not set it for now. No carrier aggregation support + + //TODO: Set deactivation timer for secondary cell + config->has_scell_deactivation_timer = 0; + config->scell_deactivation_timer = 0; + } + } else if (state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_MOVED) { + // TODO: Not supported for now. Leave blank + } + + ue_state_change_msg->config = config; + msg = malloc(sizeof(Protocol__FlexranMessage)); + if (msg == NULL) { + goto error; + } + protocol__flexran_message__init(msg); + msg->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG; + msg->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; + msg->ue_state_change_msg = ue_state_change_msg; + + data = flexran_agent_pack_message(msg, &size); + /*Send sr info using the MAC channel of the eNB*/ + if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) { + err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; + goto error; + } + + LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); + return; + error: + LOG_E(FLEXRAN_AGENT, "Could not send UE state message becasue of %d \n",err_code); +} + + + +int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg) { + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG) + goto error; + free(msg->ue_state_change_msg->header); + //TODO: Free the contents of the UE config structure + free(msg->ue_state_change_msg); + free(msg); + return 0; + + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +/* this is called by RRC as a part of rrc xface . The controller previously requested this*/ +void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t* measResults) { + + // int i, m, k; + int priority = 0; // Warning Preventing + void *data; + int size; + err_code_t err_code; + Protocol__FlexUeStatsReport **ue_report; + Protocol__FlexCellStatsReport **cell_report; + Protocol__FlexStatsReply *stats_reply_msg; + Protocol__FlexranMessage *msg; + + Protocol__FlexHeader *header; + int xid = 0; + int i; + + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) + goto error; + + + + stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply)); + + if (stats_reply_msg == NULL) + goto error; + + protocol__flex_stats_reply__init(stats_reply_msg); + stats_reply_msg->header = header; + stats_reply_msg->n_ue_report = 1; + stats_reply_msg->n_cell_report = 1; + +/****** LOCK ******************************************************************/ + // pthread_spin_lock(&rrc_meas_t_lock); + + // struct rrc_meas_trigg *ctxt; + // ctxt = rrc_meas_get_trigg(p->rnti, p->meas->measId); + + // pthread_spin_unlock(&rrc_meas_t_lock); +/****** UNLOCK ****************************************************************/ + + // if (ctxt == NULL) { + + // flexran_RRC_meas_reconf(p->rnti, -1, p->meas->measId, NULL, NULL); + // Free the measurement report received from UE. + // ASN_STRUCT_FREE(asn_DEF_MeasResults, p->meas); + // /* Free the params. */ + // free(p); + // return 0; + // } + + + /* Check here whether trigger is registered in agent and then proceed. + */ + // if (em_has_trigger(mod_id, ctxt->t_id, RRC_MEAS_TRIGGER) == 0) { + + // flexran_RRC_meas_reconf(p->rnti, -1, p->meas->measId, NULL, NULL); + // /* Trigger does not exist in agent so remove from wrapper as well. */ + // if (rrc_meas_rem_trigg(ctxt) < 0) { + // goto error; + // } + // } + + + + + /* Set the RNTI of the UE. */ + // repl->rnti = p->rnti; + /* Set the request status. */ + // if (p->reconfig_success == 0) { + // repl->status = STATS_REQ_STATUS__SREQS_FAILURE; + // goto error; + // } + /* Successful outcome. */ + // repl->status = STATS_REQ_STATUS__SREQS_SUCCESS; + /* Set the measurement ID of measurement. */ + // repl->has_measid = 1; + // repl->measid = measResults->measId; + /* Fill the Primary Cell RSRP and RSRQ. */ + // repl->has_pcell_rsrp = 1; + // repl->has_pcell_rsrq = 1; + // #ifdef Rel10 + // repl->has_pcell_rsrp = 1; + // repl->has_pcell_rsrq = 1; + // repl->pcell_rsrp = measResults2->measResultPCell.rsrpResult - 140; + // repl->pcell_rsrq = (measResults2->measResultPCell.rsrqResult)/2 - 20; + + ue_report = malloc(sizeof(Protocol__FlexUeStatsReport *) * 1); + if (ue_report == NULL) + goto error; + + for (i = 0; i < 1; i++) { + + ue_report[i] = malloc(sizeof(Protocol__FlexUeStatsReport)); + if(ue_report[i] == NULL) + goto error; + protocol__flex_ue_stats_report__init(ue_report[i]); + ue_report[i]->rnti = flexran_get_ue_crnti(mod_id, 0); + ue_report[i]->has_rnti = 1; + ue_report[i]->flags = 65536; + ue_report[i]->has_flags = 1; + + } + + cell_report = malloc(sizeof(Protocol__FlexCellStatsReport *) * 1); + if (cell_report == NULL) + goto error; + + for (i = 0; i < 1; i++) { + + cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport)); + if(cell_report[i] == NULL) + goto error; + + protocol__flex_cell_stats_report__init(cell_report[i]); + cell_report[i]->carrier_index = 0; //report_config->cc_report_type[i].cc_id; + cell_report[i]->has_carrier_index = 1; + cell_report[i]->flags = 0; // report_config->cc_report_type[i].cc_report_flags; + cell_report[i]->has_flags = 1; + } + + + Protocol__FlexRrcMeasurements *rrc_measurements; + rrc_measurements = malloc(sizeof(Protocol__FlexRrcMeasurements)); + if (rrc_measurements == NULL) + goto error; + protocol__flex_rrc_measurements__init(rrc_measurements); + + rrc_measurements->measid = measResults->measId; + rrc_measurements->has_measid = 1; + + rrc_measurements->pcell_rsrp = measResults->measResultPCell.rsrpResult - 140; + rrc_measurements->has_pcell_rsrp = 1; + + rrc_measurements->pcell_rsrq = (measResults->measResultPCell.rsrqResult)/2 - 20; + rrc_measurements->has_pcell_rsrq = 1 ; + + ue_report[0]->rrc_measurements = rrc_measurements; + + + + + + // #else + // repl->has_pcell_rsrp = 1; + // repl->has_pcell_rsrq = 1; + // repl->pcell_rsrp = RSRP_meas_mapping[meas-> + // measResultServCell.rsrpResult]; + // repl->pcell_rsrq = RSRQ_meas_mapping[meas-> + // measResultServCell.rsrqResult]; + // #endif + + // repl->neigh_meas = NULL; + + // if (meas->measResultNeighCells != NULL) { + // /* + // * Neighboring cells measurements performed by UE. + // */ + // NeighCellsMeasurements *neigh_meas; + // neigh_meas = malloc(sizeof(NeighCellsMeasurements)); + // if (neigh_meas == NULL) + // goto error; + // neigh_cells_measurements__init(neigh_meas); + + // /* EUTRAN RRC Measurements. */ + // if (meas->measResultNeighCells->present == + // MeasResults__measResultNeighCells_PR_measResultListEUTRA) { + + // MeasResultListEUTRA_t meas_list = meas->measResultNeighCells-> + // choice.measResultListEUTRA; + // /* Set the number of EUTRAN measurements present in report. */ + // neigh_meas->n_eutra_meas = meas_list.list.count; + // if (neigh_meas->n_eutra_meas > 0) { + // /* Initialize EUTRAN measurements. */ + // EUTRAMeasurements **eutra_meas; + // eutra_meas = malloc(sizeof(EUTRAMeasurements *) * + // neigh_meas->n_eutra_meas); + // for (i = 0; i < neigh_meas->n_eutra_meas; i++) { + // eutra_meas[i] = malloc(sizeof(EUTRAMeasurements)); + // eutra_measurements__init(eutra_meas[i]); + // /* Fill in the physical cell identifier. */ + // eutra_meas[i]->has_phys_cell_id = 1; + // eutra_meas[i]->phys_cell_id = meas_list.list.array[i]-> + // physCellId; + // // log_i(agent,"PCI of Target %d", eutra_meas[i]->phys_cell_id); + // /* Check for Reference signal measurements. */ + // if (&(meas_list.list.array[i]->measResult)) { + // /* Initialize Ref. signal measurements. */ + // EUTRARefSignalMeas *meas_result; + // meas_result = malloc(sizeof(EUTRARefSignalMeas)); + // eutra_ref_signal_meas__init(meas_result); + + // if (meas_list.list.array[i]->measResult.rsrpResult) { + // meas_result->has_rsrp = 1; + // meas_result->rsrp = RSRP_meas_mapping[*(meas_list. + // list.array[i]->measResult.rsrpResult)]; + // // log_i(agent,"RSRP of Target %d", meas_result->rsrp); + // } + + // if (meas_list.list.array[i]->measResult.rsrqResult) { + // meas_result->has_rsrq = 1; + // meas_result->rsrq = RSRQ_meas_mapping[*(meas_list. + // list.array[i]->measResult.rsrqResult)]; + // // log_i(agent,"RSRQ of Target %d", meas_result->rsrq); + // } + // eutra_meas[i]->meas_result = meas_result; + // } + // /* Check for CGI measurements. */ + // if (meas_list.list.array[i]->cgi_Info) { + // /* Initialize CGI measurements. */ + // EUTRACgiMeasurements *cgi_meas; + // cgi_meas = malloc(sizeof(EUTRACgiMeasurements)); + // eutra_cgi_measurements__init(cgi_meas); + + // /* EUTRA Cell Global Identity (CGI). */ + // CellGlobalIdEUTRA *cgi; + // cgi = malloc(sizeof(CellGlobalIdEUTRA)); + // cell_global_id__eutra__init(cgi); + + // cgi->has_cell_id = 1; + // CellIdentity_t cId = meas_list.list.array[i]-> + // cgi_Info->cellGlobalId.cellIdentity; + // cgi->cell_id = (cId.buf[0] << 20) + (cId.buf[1] << 12) + + // (cId.buf[2] << 4) + (cId.buf[3] >> 4); + + // /* Public land mobile network identifier of neighbor + // * cell. + // */ + // PlmnIdentity *plmn_id; + // plmn_id = malloc(sizeof(PlmnIdentity)); + // plmn_identity__init(plmn_id); + + // MNC_t mnc = meas_list.list.array[i]-> + // cgi_Info->cellGlobalId.plmn_Identity.mnc; + + // plmn_id->has_mnc = 1; + // plmn_id->mnc = 0; + // for (m = 0; m < mnc.list.count; m++) { + // plmn_id->mnc += *mnc.list.array[m] * + // ((uint32_t) pow(10, mnc.list.count - m - 1)); + // } + + // MCC_t *mcc = meas_list.list.array[i]-> + // cgi_Info->cellGlobalId.plmn_Identity.mcc; + + // plmn_id->has_mcc = 1; + // plmn_id->mcc = 0; + // for (m = 0; m < mcc->list.count; m++) { + // plmn_id->mcc += *mcc->list.array[m] * + // ((uint32_t) pow(10, mcc->list.count - m - 1)); + // } + + // TrackingAreaCode_t tac = meas_list.list.array[i]-> + // cgi_Info->trackingAreaCode; + + // cgi_meas->has_tracking_area_code = 1; + // cgi_meas->tracking_area_code = (tac.buf[0] << 8) + + // (tac.buf[1]); + + // PLMN_IdentityList2_t *plmn_l = meas_list.list.array[i]-> + // cgi_Info->plmn_IdentityList; + + // cgi_meas->n_plmn_id = plmn_l->list.count; + // /* Set the PLMN ID list in CGI measurements. */ + // PlmnIdentity **plmn_id_l; + // plmn_id_l = malloc(sizeof(PlmnIdentity *) * + // cgi_meas->n_plmn_id); + + // MNC_t mnc2; + // MCC_t *mcc2; + // for (m = 0; m < cgi_meas->n_plmn_id; m++) { + // plmn_id_l[m] = malloc(sizeof(PlmnIdentity)); + // plmn_identity__init(plmn_id_l[m]); + + // mnc2 = plmn_l->list.array[m]->mnc; + // plmn_id_l[m]->has_mnc = 1; + // plmn_id_l[m]->mnc = 0; + // for (k = 0; k < mnc2.list.count; k++) { + // plmn_id_l[m]->mnc += *mnc2.list.array[k] * + // ((uint32_t) pow(10, mnc2.list.count - k - 1)); + // } + + // mcc2 = plmn_l->list.array[m]->mcc; + // plmn_id_l[m]->has_mcc = 1; + // plmn_id_l[m]->mcc = 0; + // for (k = 0; k < mcc2->list.count; k++) { + // plmn_id_l[m]->mcc += *mcc2->list.array[k] * + // ((uint32_t) pow(10, mcc2->list.count - k - 1)); + // } + // } + // cgi_meas->plmn_id = plmn_id_l; + // eutra_meas[i]->cgi_meas = cgi_meas; + // } + // } + // neigh_meas->eutra_meas = eutra_meas; + // } + // } + // repl->neigh_meas = neigh_meas; + // } + /* Attach the RRC measurement reply message to RRC measurements message. */ + // mrrc_meas->repl = repl; + /* Attach RRC measurement message to triggered event message. */ + // te->mrrc_meas = mrrc_meas; + // te->has_action = 0; + /* Attach the triggered event message to main message. */ + // reply->te = te; + + /* Send the report to controller. */ + // if (flexran_agent_msg_send(b_id, reply) < 0) { + // goto error; + // } + + /* Free the measurement report received from UE. */ + // ASN_STRUCT_FREE(asn_DEF_MeasResults, p->meas); + /* Free the params. */ + // free(p); + + + stats_reply_msg->cell_report = cell_report; + + stats_reply_msg->ue_report = ue_report; + + msg = malloc(sizeof(Protocol__FlexranMessage)); + if(msg == NULL) + goto error; + protocol__flexran_message__init(msg); + msg->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG; + msg->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; + msg->stats_reply_msg = stats_reply_msg; + + data = flexran_agent_pack_message(msg, &size); + + + if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) { + + err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; + goto error; + } + + LOG_I(FLEXRAN_AGENT,"RRC Trigger is done \n"); + + return; + + error: + + LOG_E(FLEXRAN_AGENT, "Could not send UE state message becasue of %d \n",err_code); + /* Free the measurement report received from UE. */ + // ASN_STRUCT_FREE(asn_DEF_MeasResults, p->meas); + /* Free the params. */ + // free(p); + // return -1; +} + + +int flexran_agent_register_rrc_xface(mid_t mod_id, AGENT_RRC_xface *xface) { + if (rrc_agent_registered[mod_id]) { + LOG_E(RRC, "RRC agent for eNB %d is already registered\n", mod_id); + return -1; + } + +// xface->flexran_agent_send_update_rrc_stats = flexran_agent_send_update_rrc_stats; + + xface->flexran_agent_notify_ue_state_change = flexran_agent_ue_state_change; + xface->flexran_trigger_rrc_measurements = flexran_trigger_rrc_measurements; + + rrc_agent_registered[mod_id] = 1; + agent_rrc_xface[mod_id] = xface; + + return 0; +} + +int flexran_agent_unregister_rrc_xface(mid_t mod_id, AGENT_RRC_xface *xface) { + + //xface->agent_ctxt = NULL; +// xface->flexran_agent_send_update_rrc_stats = NULL; + + xface->flexran_agent_notify_ue_state_change = NULL; + xface->flexran_trigger_rrc_measurements = NULL; + rrc_agent_registered[mod_id] = 0; + agent_rrc_xface[mod_id] = NULL; + + return 0; +} diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h new file mode 100644 index 0000000000..aa210f9d41 --- /dev/null +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc.h @@ -0,0 +1,74 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2014 Eurecom + + OpenAirInterface is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + + OpenAirInterface is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OpenAirInterface.The full GNU General Public License is + included in this distribution in the file called "COPYING". If not, + see . + + Contact Information + OpenAirInterface Admin: openair_admin@eurecom.fr + OpenAirInterface Tech : openair_tech@eurecom.fr + OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr + + Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. + + *******************************************************************************/ + +/*! \file flexran_agent_rrc.h + * \brief FlexRAN agent Control Module RRC header + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +#ifndef FLEXRAN_AGENT_RRC_H_ +#define FLEXRAN_AGENT_RRC_H_ + +#include "header.pb-c.h" +#include "flexran.pb-c.h" +#include "stats_messages.pb-c.h" +#include "stats_common.pb-c.h" + + +#include "flexran_agent_common.h" +#include "flexran_agent_rrc_defs.h" + + +/* Initialization function for the agent structures etc */ +void flexran_agent_init_rrc_agent(mid_t mod_id); + +/* UE state change message constructor and destructor */ +void flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change); +int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg); + + +/********************************** + * FlexRAN agent - technology RRC API + **********************************/ + +/* Send to the controller all the rrc stat updates that occured during this subframe*/ +// void flexran_agent_send_update_rrc_stats(mid_t mod_id); + +/* this is called by RRC as a part of rrc xface . The controller previously requested this*/ +void flexran_trigger_rrc_measurements (mid_t mod_id, MeasResults_t *); + +/*Register technology specific interface callbacks*/ +int flexran_agent_register_rrc_xface(mid_t mod_id, AGENT_RRC_xface *xface); + +/*Unregister technology specific callbacks*/ +int flexran_agent_unregister_rrc_xface(mid_t mod_id, AGENT_RRC_xface*xface); + +#endif diff --git a/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h new file mode 100644 index 0000000000..ad1375171e --- /dev/null +++ b/openair2/ENB_APP/CONTROL_MODULES/RRC/flexran_agent_rrc_defs.h @@ -0,0 +1,64 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2016 Eurecom + + OpenAirInterface is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + + OpenAirInterface is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OpenAirInterface.The full GNU General Public License is + included in this distribution in the file called "COPYING". If not, + see . + + Contact Information + OpenAirInterface Admin: openair_admin@eurecom.fr + OpenAirInterface Tech : openair_tech@eurecom.fr + OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr + + Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. + + *******************************************************************************/ + +/*! \file flexran_agent_rrc_defs.h + * \brief FlexRAN agent - RRC interface primitives + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + * \mail + */ + +#ifndef __FLEXRAN_AGENT_RRC_PRIMITIVES_H__ +#define __FLEXRAN_AGENT_RRC_PRIMITIVES_H__ + +#include "PHY/extern.h" +#include "flexran_agent_defs.h" +#include "flexran.pb-c.h" +#include "header.pb-c.h" +#include "MeasResults.h" + +#define RINGBUFFER_SIZE 100 + +/* FLEXRAN AGENT-RRC Interface */ +typedef struct { + + /// Inform the controller about the scheduling requests received during the subframe + //void (*flexran_agent_send_update_rrc_stats)(mid_t mod_id); + + /// Notify the controller for a state change of a particular UE, by sending the proper + /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) + void (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, + uint8_t state_change); + + void (*flexran_trigger_rrc_measurements)(mid_t mod_id, MeasResults_t* measResults); + +} AGENT_RRC_xface; + +#endif diff --git a/openair2/ENB_APP/MESSAGES/V2/flexran.proto b/openair2/ENB_APP/MESSAGES/V2/flexran.proto index f49b69f4ad..caee626a73 100644 --- a/openair2/ENB_APP/MESSAGES/V2/flexran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/flexran.proto @@ -25,10 +25,11 @@ message flexran_message { flex_lc_config_request lc_config_request_msg = 12; flex_lc_config_reply lc_config_reply_msg = 13; flex_dl_mac_config dl_mac_config_msg = 14; - flex_ul_mac_config ul_mac_config_msg = 18; + flex_ul_mac_config ul_mac_config_msg = 19; flex_ue_state_change ue_state_change_msg = 15; flex_control_delegation control_delegation_msg = 16; flex_agent_reconfiguration agent_reconfiguration_msg = 17; + flex_rrc_triggering rrc_triggering = 18; } } @@ -164,12 +165,22 @@ message flex_dl_mac_config { repeated flex_pdcch_ofdm_sym_count ofdm_sym = 6; // OFDM symbol count for each CC } + message flex_ul_mac_config { optional flex_header header = 1; optional uint32 sfn_sf = 2; repeated flex_ul_data ul_ue_data = 3; } + +message flex_rrc_triggering { + + optional flex_header header = 1; + optional string rrc_trigger = 2; +} + + + // // UE state change message // diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index dfd5ea6c99..468dcd201e 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -39,5 +39,7 @@ enum flex_type { // Control delegation messages FLPT_DELEGATE_CONTROL = 15; FLPT_RECONFIGURE_AGENT = 16; + FLPT_RRC_TRIGGERING = 17; + } diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto index 080883ea97..cce36df00a 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto @@ -181,3 +181,63 @@ message flex_noise_interference_report { optional int32 p0_nominal_pucch = 4; } +// +// RRC Primitives +// +message flex_rrc_measurements { + // Measurement identifier. + optional int32 measid = 1; + // Primary Cell Reference Signal Received Power (RSRP). + optional int32 pcell_rsrp = 2; + // Primary Cell Reference Signal Received Quality (RSRQ). + optional int32 pcell_rsrq = 3; + // Neighboring cells measurements performed by UE. + optional flex_neigh_cells_measurements neigh_meas = 4; +} + +message flex_neigh_cells_measurements { + // Neighboring EUTRA cells measurements. + repeated flex_eutra_measurements eutra_meas = 1; +} + +message flex_eutra_measurements { + // Physical Cell identifier. + optional int32 phys_cell_id = 1; + // EUTRA Cell Global Identity (CGI) measurement. + optional flex_eutra_cgi_measurements cgi_meas = 2; + // EUTRA nearby cell reference signal measurement. + optional flex_eutra_ref_signal_meas meas_result = 3; +} + +message flex_eutra_cgi_measurements { + // EUTRA Cell Global Identity (CGI). + optional flex_cell_global_eutra_id cgi = 1; + // Tracking area code of the neighbor cell. + optional uint32 tracking_area_code = 2; + // Public land mobile network identifiers of neighbor cell. + repeated flex_plmn_identity plmn_id = 3; +} + +message flex_cell_global_eutra_id { + // Public land mobile network identifier of neighbor cell. + optional flex_plmn_identity plmn_id = 1; + // Cell identifier of neighbor cell. + optional uint32 cell_id = 2; +} + +message flex_plmn_identity { + // Mobile Network Code (MNC). + repeated uint32 mnc = 1; + // Mobile Country Code (MCC). + repeated uint32 mcc = 2; + // tracking area code + repeated uint32 tac = 3; +} + +message flex_eutra_ref_signal_meas { + // Neighboring Cell Reference Signal Received Power (RSRP). + optional int32 rsrp = 1; + // Neighboring Cell Reference Signal Received Quality (RSRQ). + optional int32 rsrq = 2; + +} diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto index 1b1567dda1..48360f6f68 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto @@ -46,6 +46,7 @@ message flex_ue_stats_report { optional flex_dl_cqi_report dl_cqi_report = 7; optional flex_paging_buffer_report pbr = 8; optional flex_ul_cqi_report ul_cqi_report = 9; + optional flex_rrc_measurements rrc_measurements = 10; } // @@ -76,11 +77,12 @@ enum flex_cell_stats_type { // Flags for UE-related statistics enum flex_ue_stats_type { FLUST_BSR = 1; - FLUST_PRH = 2; + FLUST_PHR = 2; FLUST_RLC_BS = 4; FLUST_MAC_CE_BS = 8; FLUST_DL_CQI = 16; FLUST_PBS = 32; FLUST_UL_CQI = 64; // To be extended with more types of stats -} \ No newline at end of file + FLUST_RRC_MEASUREMENTS = 65536; +} diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index 153c89b3e2..09d7495a69 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -98,6 +98,8 @@ #define ENB_CONFIG_STRING_EUTRA_BAND "eutra_band" #define ENB_CONFIG_STRING_DOWNLINK_FREQUENCY "downlink_frequency" #define ENB_CONFIG_STRING_UPLINK_FREQUENCY_OFFSET "uplink_frequency_offset" +#define ENB_CONFIG_STRING_RRC_REPORT_CONFIG_AMOUNT "report_amount" +#define ENB_CONFIG_STRING_RRC_REPORT_CONFIG_INTERVAL "report_interval" #define ENB_CONFIG_STRING_NID_CELL "Nid_cell" #define ENB_CONFIG_STRING_N_RB_DL "N_RB_DL" @@ -165,7 +167,7 @@ #define ENB_CONFIG_STRING_UETIMERS_N310 "ue_TimersAndConstants_n310" #define ENB_CONFIG_STRING_UETIMERS_N311 "ue_TimersAndConstants_n311" #define ENB_CONFIG_STRING_UE_TRANSMISSION_MODE "ue_TransmissionMode" - +#define ENB_CONFIG_STRING_RRC_CONFIG "rrc_config" #define ENB_CONFIG_STRING_SRB1 "srb1_parameters" #define ENB_CONFIG_STRING_SRB1_TIMER_POLL_RETRANSMIT "timer_poll_retransmit" #define ENB_CONFIG_STRING_SRB1_TIMER_REORDERING "timer_reordering" @@ -456,6 +458,10 @@ void enb_config_display(void) printf( "\tue_TransmissionMode for CC %d:\t%ld:\n",j,enb_properties.properties[i]->ue_TransmissionMode[j]); + printf( "\n\tRRC Report Config: \n"); + printf( "\n\t Report interval \t%ld: ", enb_properties.properties[i]->rrc_report_interval); + printf( "\n\t Report amount \t%ld: \n", enb_properties.properties[i]->rrc_report_amount); + } for (j=0; j < enb_properties.properties[i]->num_otg_elements; j++) { @@ -545,6 +551,7 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) config_setting_t *setting_enb = NULL; config_setting_t *setting_otg = NULL; config_setting_t *subsetting_otg = NULL; + config_setting_t *setting_rrc = NULL; int parse_errors = 0; int num_enb_properties = 0; int enb_properties_index = 0; @@ -651,7 +658,8 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) libconfig_int srb1_max_retx_threshold = 0; libconfig_int my_int; - + const char* rrc_report_amount = NULL; + const char* rrc_report_interval = NULL; char* if_name = NULL; char* ipv4 = NULL; @@ -1968,6 +1976,75 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) } } + + setting_rrc = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_RRC_CONFIG); + if (setting_rrc != NULL) { + + if (!(config_setting_lookup_string(setting_rrc, ENB_CONFIG_STRING_RRC_REPORT_CONFIG_AMOUNT, &rrc_report_amount) + && config_setting_lookup_string(setting_rrc, ENB_CONFIG_STRING_RRC_REPORT_CONFIG_INTERVAL, &rrc_report_interval))) + AssertFatal (0, + "Failed to parse eNB configuration file %s, enb %d, rrc_report_amount and rrc_reporyt_interval !\n", + lib_config_file_name_pP, i); + + if (strcmp(rrc_report_amount, "r1") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r1; + } else if (strcmp(rrc_report_amount, "r2") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r2; + }else if (strcmp(rrc_report_amount, "r4") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r4; + }else if (strcmp(rrc_report_amount, "r8") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r8; + }else if (strcmp(rrc_report_amount, "r16") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r16; + }else if (strcmp(rrc_report_amount, "r32") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r32; + }else if (strcmp(rrc_report_amount, "r64") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r64; + }else if (strcmp(rrc_report_amount, "infinity") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_infinity; + }else{ + AssertFatal (0, + "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for report_amount choice: r1, r2, r4, r8, r16, r32, r64, infinity !\n", + lib_config_file_name_pP, i,rrc_report_amount); + } + + if (strcmp(rrc_report_interval, "120ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms120; + } else if (strcmp(rrc_report_interval, "240ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms240; + }else if (strcmp(rrc_report_interval, "480ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms480; + }else if (strcmp(rrc_report_interval, "640ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms640; + }else if (strcmp(rrc_report_interval, "1024ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms1024; + }else if (strcmp(rrc_report_interval, "2048ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms2048; + }else if (strcmp(rrc_report_interval, "5120ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms5120; + }else if (strcmp(rrc_report_interval, "10240ms") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms10240; + }else if (strcmp(rrc_report_interval, "1min") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_min1; + }else if (strcmp(rrc_report_interval, "6min") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_min6; + }else if (strcmp(rrc_report_interval, "12min") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_min12; + }else if (strcmp(rrc_report_interval, "30min") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_min30; + } else if (strcmp(rrc_report_interval, "60min") == 0) { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_min60; + } else { + AssertFatal (0, + "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for report_interval choice: 120ms, 240ms, 480ms, 640ms, 1024ms, 2048ms, 5120ms, 10240ms, 1min, 6min, 12", + lib_config_file_name_pP, i,rrc_report_interval); + } + + } else { + enb_properties.properties[enb_properties_index]->rrc_report_interval = ReportInterval_ms120; + enb_properties.properties[enb_properties_index]->rrc_report_amount = ReportConfigEUTRA__reportAmount_r1; + } + setting_srb1 = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_SRB1); if (setting_srb1 != NULL) { diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h index a508a82e1f..094360749b 100644 --- a/openair2/ENB_APP/enb_config.h +++ b/openair2/ENB_APP/enb_config.h @@ -214,6 +214,10 @@ typedef struct Enb_properties_s { long srb1_poll_pdu; long srb1_poll_byte; long srb1_max_retx_threshold; + + long rrc_report_amount; + long rrc_report_interval; + /* Nb of MME to connect to */ uint8_t nb_mme; /* List of MME to connect to */ diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index 0dcacd4b81..ec984cfa8b 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -21,27 +21,16 @@ /*! \file flexran_agent.h * \brief top level flexran agent receive thread and itti task - * \author Xenofon Foukas and Navid Nikaein - * \date 2016 + * \author Xenofon Foukas and Navid Nikaein and shahab SHARIAT BAGHERI + * \date 2017 * \version 0.1 */ -#include "flexran_agent_common.h" -#include "log.h" #include "flexran_agent.h" -#include "flexran_agent_mac_defs.h" -#include "flexran_agent_mac.h" -#include "flexran_agent_mac_internal.h" - -#include "flexran_agent_extern.h" - -#include "assertions.h" - -#include "flexran_agent_net_comm.h" -#include "flexran_agent_async.h" #include + //#define TEST_TIMER flexran_agent_instance_t flexran_agent[NUM_MAX_ENB]; @@ -264,8 +253,8 @@ int flexran_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properti *flexran_agent_register_channel(mod_id, channel, FLEXRAN_AGENT_MAC); */ - /*Initialize the continuous MAC stats update mechanism*/ - flexran_agent_init_cont_mac_stats_update(mod_id); + /*Initialize the continuous stats update mechanism*/ + flexran_agent_init_cont_stats_update(mod_id); new_thread(receive_thread, &flexran_agent[mod_id]); @@ -275,6 +264,9 @@ int flexran_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properti AGENT_MAC_xface *mac_agent_xface = (AGENT_MAC_xface *) malloc(sizeof(AGENT_MAC_xface)); flexran_agent_register_mac_xface(mod_id, mac_agent_xface); + AGENT_RRC_xface *rrc_agent_xface = (AGENT_RRC_xface *) malloc(sizeof(AGENT_RRC_xface)); + flexran_agent_register_rrc_xface(mod_id, rrc_agent_xface); + /* * initilize a timer */ diff --git a/openair2/ENB_APP/flexran_agent.h b/openair2/ENB_APP/flexran_agent.h index 21ea21aafc..0ef48e2105 100644 --- a/openair2/ENB_APP/flexran_agent.h +++ b/openair2/ENB_APP/flexran_agent.h @@ -22,15 +22,26 @@ /*! \file flexran_agent.h * \brief top level flexran agent * \author Navid Nikaein and Xenofon Foukas - * \date 2016 + * \date 2017 * \version 0.1 */ #ifndef FLEXRAN_AGENT_H_ #define FLEXRAN_AGENT_H_ -#include "enb_config.h" // for enb properties #include "flexran_agent_common.h" +#include "flexran_agent_async.h" +#include "flexran_agent_extern.h" +#include "flexran_agent_timer.h" +#include "flexran_agent_defs.h" +#include "flexran_agent_net_comm.h" +#include "flexran_agent_ran_api.h" +#include "flexran_agent_mac.h" +#include "flexran_agent_rrc.h" +#include "log.h" +#include "assertions.h" + +#include "enb_config.h" // for enb properties /* Initiation and termination of the eNodeB agent */ diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index f2d00145a0..78d3a75ec7 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -21,8 +21,8 @@ /*! \file flexran_agent_common.c * \brief common primitives for all agents - * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein - * \date 2016 + * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein, shahab SHARIAT BAGHERI + * \date 2017 * \version 0.1 */ @@ -33,6 +33,7 @@ #include "flexran_agent_common_internal.h" #include "flexran_agent_extern.h" #include "flexran_agent_net_comm.h" +#include "flexran_agent_ran_api.h" #include "PHY/extern.h" #include "log.h" @@ -41,10 +42,6 @@ #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" #include "rrc_eNB_UE_context.h" -void * enb[NUM_MAX_ENB]; -void * enb_ue[NUM_MAX_ENB]; -void * enb_rrc[NUM_MAX_ENB]; - /* * message primitives */ @@ -344,19 +341,6 @@ int flexran_agent_destroy_lc_config_reply(Protocol__FlexranMessage *msg) { return -1; } -int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg) { - if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG) - goto error; - free(msg->ue_state_change_msg->header); - //TODO: Free the contents of the UE config structure - free(msg->ue_state_change_msg); - free(msg); - return 0; - - error: - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - return -1; -} int flexran_agent_destroy_enb_config_request(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG) @@ -442,1083 +426,6 @@ int flexran_agent_destroy_agent_reconfiguration(Protocol__FlexranMessage *msg) { } -/* - * get generic info from RAN - */ - -void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran){ - - switch (ran){ - case RAN_LTE_OAI : - enb[mod_id] = (void *)&eNB_mac_inst[mod_id]; - enb_ue[mod_id] = (void *)&eNB_mac_inst[mod_id].UE_list; - enb_rrc[mod_id] = (void *)&eNB_rrc_inst[mod_id]; - break; - default : - goto error; - } - - return; - - error: - LOG_E(FLEXRAN_AGENT, "unknown RAN name %d\n", ran); -} - -int flexran_get_current_time_ms (mid_t mod_id, int subframe_flag){ - - if (subframe_flag == 1){ - return ((eNB_MAC_INST *)enb[mod_id])->frame*10 + ((eNB_MAC_INST *)enb[mod_id])->subframe; - }else { - return ((eNB_MAC_INST *)enb[mod_id])->frame*10; - } - -} - -unsigned int flexran_get_current_frame (mid_t mod_id) { - - // #warning "SFN will not be in [0-1023] when oaisim is used" - return ((eNB_MAC_INST *)enb[mod_id])->frame; - -} - -unsigned int flexran_get_current_system_frame_num(mid_t mod_id) { - return (flexran_get_current_frame(mod_id) %1024); -} - -unsigned int flexran_get_current_subframe (mid_t mod_id) { - - return ((eNB_MAC_INST *)enb[mod_id])->subframe; - -} - -uint16_t flexran_get_sfn_sf (mid_t mod_id) { - - frame_t frame; - sub_frame_t subframe; - uint16_t sfn_sf, frame_mask, sf_mask; - - frame = (frame_t) flexran_get_current_system_frame_num(mod_id); - subframe = (sub_frame_t) flexran_get_current_subframe(mod_id); - frame_mask = ((1<<12) - 1); - sf_mask = ((1<<4) - 1); - sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4); - - return sfn_sf; -} - -uint16_t flexran_get_future_sfn_sf (mid_t mod_id, int ahead_of_time) { - - frame_t frame; - sub_frame_t subframe; - uint16_t sfn_sf, frame_mask, sf_mask; - - frame = (frame_t) flexran_get_current_system_frame_num(mod_id); - subframe = (sub_frame_t) flexran_get_current_subframe(mod_id); - - subframe = ((subframe + ahead_of_time) % 10); - - if (subframe < flexran_get_current_subframe(mod_id)) { - frame = (frame + 1) % 1024; - } - - int additional_frames = ahead_of_time / 10; - frame = (frame + additional_frames) % 1024; - - frame_mask = ((1<<12) - 1); - sf_mask = ((1<<4) - 1); - sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4); - - return sfn_sf; -} - -int flexran_get_num_ues (mid_t mod_id){ - - return ((UE_list_t *)enb_ue[mod_id])->num_UEs; -} - -int flexran_get_ue_crnti (mid_t mod_id, mid_t ue_id) { - - return UE_RNTI(mod_id, ue_id); -} - -int flexran_get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid) { - - return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].bsr_info[lcid]; -} - -int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id) { - - return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].phr_info; -} - -int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, 0, UE_RNTI(mod_id, ue_id)); - return eNB_UE_stats->DL_cqi[0]; - - // return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].dl_cqi; -} - -int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); - mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id,frame,ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0); - return rlc_status.bytes_in_buffer; -} - -int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); - mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, ENB_FLAG_YES, MBMS_FLAG_NO, channel_id, 0); - return rlc_status.head_sdu_creation_time; -} - -short flexran_get_TA(mid_t mod_id, mid_t ue_id, int CC_id) { - - UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list; - int rnti; - - rnti = flexran_get_ue_crnti(mod_id, ue_id); - - LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - //ue_sched_ctl->ta_timer = 20; // wait 20 subframes before taking TA measurement from PHY - switch (PHY_vars_eNB_g[mod_id][CC_id]->frame_parms.N_RB_DL) { - case 6: - return eNB_UE_stats->timing_advance_update; - case 15: - return eNB_UE_stats->timing_advance_update/2; - case 25: - return eNB_UE_stats->timing_advance_update/4; - case 50: - return eNB_UE_stats->timing_advance_update/8; - case 75: - return eNB_UE_stats->timing_advance_update/12; - case 100: - if (PHY_vars_eNB_g[mod_id][CC_id]->frame_parms.threequarter_fs == 0) { - return eNB_UE_stats->timing_advance_update/16; - } else { - return eNB_UE_stats->timing_advance_update/12; - } - default: - return 0; - } -} - -void flexran_update_TA(mid_t mod_id, mid_t ue_id, int CC_id) { - - UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list; - UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[ue_id]; - - if (ue_sched_ctl->ta_timer == 0) { - - // WE SHOULD PROTECT the eNB_UE_stats with a mutex here ... - // LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - //ue_sched_ctl->ta_timer = 20; // wait 20 subframes before taking TA measurement from PHY - ue_sched_ctl->ta_update = flexran_get_TA(mod_id, ue_id, CC_id); - - // clear the update in case PHY does not have a new measurement after timer expiry - // eNB_UE_stats->timing_advance_update = 0; - } else { - ue_sched_ctl->ta_timer--; - ue_sched_ctl->ta_update = 0; // don't trigger a timing advance command - } -} - -int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) { - - UE_list_t *UE_list = &eNB_mac_inst[mod_id].UE_list; - - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); - - if (eNB_UE_stats == NULL) { - return 0; - } - - if (flexran_get_TA(mod_id, ue_id, CC_id) != 0) { - return PROTOCOL__FLEX_CE_TYPE__FLPCET_TA; - } else { - return 0; - } - -} - -int flexran_get_active_CC(mid_t mod_id, mid_t ue_id) { - return ((UE_list_t *)enb_ue[mod_id])->numactiveCCs[ue_id]; -} - -int flexran_get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); - - if (eNB_UE_stats == NULL) { - return 0; - } - - return eNB_UE_stats[CC_id].rank; -} - -int flexran_get_tpc(mid_t mod_id, mid_t ue_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - int32_t normalized_rx_power, target_rx_power; - int tpc = 1; - - int pCCid = UE_PCCID(mod_id,ue_id); - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, pCCid, rnti); - - target_rx_power = mac_xface->get_target_pusch_rx_power(mod_id,pCCid); - - if (eNB_UE_stats == NULL) { - normalized_rx_power = target_rx_power; - } else if (eNB_UE_stats->UL_rssi != NULL) { - normalized_rx_power = eNB_UE_stats->UL_rssi[0]; - } else { - normalized_rx_power = target_rx_power; - } - - if (normalized_rx_power>(target_rx_power+1)) { - tpc = 0; //-1 - } else if (normalized_rx_power<(target_rx_power-1)) { - tpc = 2; //+1 - } else { - tpc = 1; //0 - } - return tpc; -} - -int flexran_get_harq(const mid_t mod_id, - const uint8_t CC_id, - const mid_t ue_id, - const int frame, - const uint8_t subframe, - uint8_t *id, - uint8_t *round) { //flag_id_status = 0 then id, else status - /*TODO: Add int TB in function parameters to get the status of the second TB. This can be done to by editing in - * get_ue_active_harq_pid function in line 272 file: phy_procedures_lte_eNB.c to add - * DLSCH_ptr = PHY_vars_eNB_g[Mod_id][CC_id]->dlsch_eNB[(uint32_t)UE_id][1];*/ - - uint8_t harq_pid; - uint8_t harq_round; - - - uint16_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&harq_round,openair_harq_DL); - - *id = harq_pid; - *round = harq_round; - /* if (round > 0) { */ - /* *status = 1; */ - /* } else { */ - /* *status = 0; */ - /* } */ - - /* return 0; */ - return *round; -} - -int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - - if (eNB_UE_stats == NULL) { - return -1; - } - - // if(eNB_UE_stats->Po_PUCCH_update == 1) { - return eNB_UE_stats->Po_PUCCH_dBm; - //} - //else - // return -1; -} - -int flexran_get_p0_nominal_pucch(mid_t mod_id, int CC_id) { - int32_t pucch_rx_received = mac_xface->get_target_pucch_rx_power(mod_id, CC_id); - return pucch_rx_received; -} - -int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - return eNB_UE_stats->Po_PUCCH_update; -} - -int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id) { - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); - - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - eNB_UE_stats->Po_PUCCH_update = 0; - - return 0; -} - - -/* - * ************************************ - * Get Messages for eNB Configuration Reply - * ************************************ - */ - -int flexran_get_hopping_offset(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pusch_config_common.pusch_HoppingOffset; -} - -int flexran_get_hopping_mode(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pusch_config_common.hoppingMode; -} - -int flexran_get_n_SB(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pusch_config_common.n_SB; -} - -int flexran_get_enable64QAM(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pusch_config_common.enable64QAM; -} - -int flexran_get_phich_duration(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->phich_config_common.phich_duration; -} - -int flexran_get_phich_resource(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - if(frame_parms->phich_config_common.phich_resource == oneSixth) - return 0; - else if(frame_parms->phich_config_common.phich_resource == half) - return 1; - else if(frame_parms->phich_config_common.phich_resource == one) - return 2; - else if(frame_parms->phich_config_common.phich_resource == two) - return 3; - - return -1; -} - -int flexran_get_n1pucch_an(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pucch_config_common.n1PUCCH_AN; -} - -int flexran_get_nRB_CQI(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pucch_config_common.nRB_CQI; -} - -int flexran_get_deltaPUCCH_Shift(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->pucch_config_common.deltaPUCCH_Shift; -} - -int flexran_get_prach_ConfigIndex(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex; -} - -int flexran_get_prach_FreqOffset(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset; -} - -int flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->maxHARQ_Msg3Tx; -} - -int flexran_get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->Ncp_UL; -} - -int flexran_get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->Ncp; -} - -int flexran_get_cell_id(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->Nid_cell; -} - -int flexran_get_srs_BandwidthConfig(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->soundingrs_ul_config_common.srs_BandwidthConfig; -} - -int flexran_get_srs_SubframeConfig(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->soundingrs_ul_config_common.srs_SubframeConfig; -} - -int flexran_get_srs_MaxUpPts(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->soundingrs_ul_config_common.srs_MaxUpPts; -} - -int flexran_get_N_RB_DL(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->N_RB_DL; -} - -int flexran_get_N_RB_UL(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->N_RB_UL; -} - -int flexran_get_N_RBG(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->N_RBG; -} - -int flexran_get_subframe_assignment(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->tdd_config; -} - -int flexran_get_special_subframe_assignment(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - return frame_parms->tdd_config_S; -} - -int flexran_get_ra_ResponseWindowSize(mid_t mod_id, int CC_id) { - return enb_config_get()->properties[mod_id]->rach_raResponseWindowSize[CC_id]; -} - -int flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id) { - return enb_config_get()->properties[mod_id]->rach_macContentionResolutionTimer[CC_id]; -} - -int flexran_get_duplex_mode(mid_t mod_id, int CC_id) { - LTE_DL_FRAME_PARMS *frame_parms; - - frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); - if(frame_parms->frame_type == TDD) - return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD; - else if (frame_parms->frame_type == FDD) - return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_FDD; - - return -1; -} - -long flexran_get_si_window_length(mid_t mod_id, int CC_id) { - return ((eNB_RRC_INST *)enb_rrc[mod_id])->carrier[CC_id].sib1->si_WindowLength; -} - -int flexran_get_sib1_length(mid_t mod_id, int CC_id) { - return ((eNB_RRC_INST *)enb_rrc[mod_id])->carrier[CC_id].sizeof_SIB1; -} - -int flexran_get_num_pdcch_symb(mid_t mod_id, int CC_id) { - /* TODO: This should return the number of PDCCH symbols initially used by the cell CC_id */ - return 0; - //(PHY_vars_UE_g[mod_id][CC_id]->lte_ue_pdcch_vars[mod_id]->num_pdcch_symbols); -} - - - -/* - * ************************************ - * Get Messages for UE Configuration Reply - * ************************************ - */ - - -int flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.mac_MainConfig != NULL) { - return ue_context_p->ue_context.mac_MainConfig->timeAlignmentTimerDedicated; - } else { - return -1; - } - } else { - return -1; - } -} - -int flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.measGapConfig != NULL) { - if(ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_setup) { - if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp0) { - return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP1; - } else if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp1) { - return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP2; - } else { - return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF; - } - } - } - } - return -1; -} - - -int flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.measGapConfig != NULL){ - if(ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_setup) { - if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp0) { - return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp0; - } else if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp1) { - return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp0; - } - } - } - } - return -1; -} - -int flexran_get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id) { - return ((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateDL; -} - -int flexran_get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id) { - return ((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateUL; -} - -int flexran_get_half_duplex(mid_t ue_id) { - // TODO - //int halfduplex = 0; - //int bands_to_scan = ((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.count; - //for (int i =0; i < bands_to_scan; i++){ - //if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.array[i]->halfDuplex > 0) - // halfduplex = 1; - //} - //return halfduplex; - return 0; -} - -int flexran_get_intra_sf_hopping(mid_t ue_id) { - //TODO:Get proper value - //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); - //return (0 & ( 1 << (31))); - return 0; -} - -int flexran_get_type2_sb_1(mid_t ue_id) { - //TODO:Get proper value - //uint8_t temp = 0; - //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); - //return (temp & ( 1 << (11))); - return 0; -} - -int flexran_get_ue_category(mid_t ue_id) { - //TODO:Get proper value - //return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->ue_Category); - return 0; -} - -int flexran_get_res_alloc_type1(mid_t ue_id) { - //TODO:Get proper value - //uint8_t temp = 0; - //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); - //return (temp & ( 1 << (30))); - return 0; -} - -int flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode; - } else { - return -1; - } - } else { - return -1; - } -} - -int flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.mac_MainConfig != NULL){ - return ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->ttiBundling; - } else { - return -1; - } - } - else { - return -1; - } -} - -int flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.mac_MainConfig != NULL){ - return *ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->maxHARQ_Tx; - } - } - return -1; -} - -int flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_ACK_Index; - } else { - return -1; - } - } else { - return -1; - } -} - -int flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index; - } else { - return -1; - } - } else { - return -1; - } -} - -int flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index; - } else { - return -1; - } - } - else { - return -1; - } -} - -int flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - if (ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic != NULL) { - return ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.simultaneousAckNackAndCQI; - } - } - } - return -1; -} - -int flexran_get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id) { - return (&eNB_rrc_inst[mod_id])->carrier[0].sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; -} - -int flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return *ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic; - } - } - return -1; -} - -int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) { - // TODO: This needs fixing - return -1; - - /* struct rrc_eNB_ue_context_s* ue_context_p = NULL; */ - /* uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); */ - - /* ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); */ - - /* if(ue_context_p != NULL) { */ - /* if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ */ - /* return ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode; */ - /* } else { */ - /* return -1; */ - /* } */ - /* } else { */ - /* return -1; */ - /* } */ -} - -int flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - return ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->ackNackRepetition.choice.setup.repetitionFactor; - } else { - return -1; - } - } else { - return -1; - } -} - -int flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id) { - //TODO: need to double check - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.mac_MainConfig != NULL){ - if(ue_context_p->ue_context.mac_MainConfig->ext2 != NULL){ - long val = (*(ue_context_p->ue_context.mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10)); - if (val > 0) { - return 1; - } - } - } - } - return -1; -} - -int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) { - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); - - ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); - - if(ue_context_p != NULL) { - if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ - if(ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_closedLoop) { - return 2; - } else if(ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_openLoop) { - return 1; - } else { - return 0; - } - } else { - return -1; - } - } else { - return -1; - } -} - -int flexran_get_lcg(mid_t ue_id, mid_t lc_id) { - if (UE_mac_inst == NULL) { - return -1; - } - if(UE_mac_inst[ue_id].logicalChannelConfig[lc_id] != NULL) { - return *UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters->logicalChannelGroup; - } else { - return -1; - } -} - -int flexran_get_direction(mid_t ue_id, mid_t lc_id) { - /*TODO: fill with the value for the rest of LCID*/ - if(lc_id == DCCH || lc_id == DCCH1) { - return 2; - } else if(lc_id == DTCH) { - return 1; - } else { - return -1; - } -} - -int flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { - int size; - Protocol__FlexranMessage *msg; - Protocol__FlexHeader *header; - void *data; - int priority = 0; - - int xid = 0; - - if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UE_STATE_CHANGE, &header) != 0) - goto error; - - Protocol__FlexUeStateChange *ue_state_change_msg; - ue_state_change_msg = malloc(sizeof(Protocol__FlexUeStateChange)); - if(ue_state_change_msg == NULL) { - goto error; - } - protocol__flex_ue_state_change__init(ue_state_change_msg); - ue_state_change_msg->has_type = 1; - ue_state_change_msg->type = state_change; - - Protocol__FlexUeConfig *config; - config = malloc(sizeof(Protocol__FlexUeConfig)); - if (config == NULL) { - goto error; - } - protocol__flex_ue_config__init(config); - if (state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED) { - // Simply set the rnti of the UE - config->has_rnti = 1; - config->rnti = rnti; - } else if (state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_UPDATED - || state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED) { - int i = find_UE_id(mod_id, rnti); - config->has_rnti = 1; - config->rnti = rnti; - if(flexran_get_time_alignment_timer(mod_id,i) != -1) { - config->time_alignment_timer = flexran_get_time_alignment_timer(mod_id,i); - config->has_time_alignment_timer = 1; - } - if(flexran_get_meas_gap_config(mod_id,i) != -1){ - config->meas_gap_config_pattern = flexran_get_meas_gap_config(mod_id,i); - config->has_meas_gap_config_pattern = 1; - } - if(config->has_meas_gap_config_pattern == 1 && - config->meas_gap_config_pattern != PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF) { - config->meas_gap_config_sf_offset = flexran_get_meas_gap_config_offset(mod_id,i); - config->has_meas_gap_config_sf_offset = 1; - } - //TODO: Set the SPS configuration (Optional) - //Not supported for now, so we do not set it - - //TODO: Set the SR configuration (Optional) - //We do not set it for now - - //TODO: Set the CQI configuration (Optional) - //We do not set it for now - - if(flexran_get_ue_transmission_mode(mod_id,i) != -1) { - config->transmission_mode = flexran_get_ue_transmission_mode(mod_id,i); - config->has_transmission_mode = 1; - } - - config->ue_aggregated_max_bitrate_ul = flexran_get_ue_aggregated_max_bitrate_ul(mod_id,i); - config->has_ue_aggregated_max_bitrate_ul = 1; - - config->ue_aggregated_max_bitrate_dl = flexran_get_ue_aggregated_max_bitrate_dl(mod_id,i); - config->has_ue_aggregated_max_bitrate_dl = 1; - - //TODO: Set the UE capabilities - Protocol__FlexUeCapabilities *c_capabilities; - c_capabilities = malloc(sizeof(Protocol__FlexUeCapabilities)); - protocol__flex_ue_capabilities__init(c_capabilities); - //TODO: Set half duplex (FDD operation) - c_capabilities->has_half_duplex = 0; - c_capabilities->half_duplex = 1;//flexran_get_half_duplex(i); - //TODO: Set intra-frame hopping flag - c_capabilities->has_intra_sf_hopping = 0; - c_capabilities->intra_sf_hopping = 1;//flexran_get_intra_sf_hopping(i); - //TODO: Set support for type 2 hopping with n_sb > 1 - c_capabilities->has_type2_sb_1 = 0; - c_capabilities->type2_sb_1 = 1;//flexran_get_type2_sb_1(i); - //TODO: Set ue category - c_capabilities->has_ue_category = 0; - c_capabilities->ue_category = 1;//flexran_get_ue_category(i); - //TODO: Set UE support for resource allocation type 1 - c_capabilities->has_res_alloc_type1 = 0; - c_capabilities->res_alloc_type1 = 1;//flexran_get_res_alloc_type1(i); - //Set the capabilites to the message - config->capabilities = c_capabilities; - - if(flexran_get_ue_transmission_antenna(mod_id,i) != -1) { - config->has_ue_transmission_antenna = 1; - config->ue_transmission_antenna = flexran_get_ue_transmission_antenna(mod_id,i); - } - - if(flexran_get_tti_bundling(mod_id,i) != -1) { - config->has_tti_bundling = 1; - config->tti_bundling = flexran_get_tti_bundling(mod_id,i); - } - - if(flexran_get_maxHARQ_TX(mod_id,i) != -1){ - config->has_max_harq_tx = 1; - config->max_harq_tx = flexran_get_maxHARQ_TX(mod_id,i); - } - - if(flexran_get_beta_offset_ack_index(mod_id,i) != -1) { - config->has_beta_offset_ack_index = 1; - config->beta_offset_ack_index = flexran_get_beta_offset_ack_index(mod_id,i); - } - - if(flexran_get_beta_offset_ri_index(mod_id,i) != -1) { - config->has_beta_offset_ri_index = 1; - config->beta_offset_ri_index = flexran_get_beta_offset_ri_index(mod_id,i); - } - - if(flexran_get_beta_offset_cqi_index(mod_id,i) != -1) { - config->has_beta_offset_cqi_index = 1; - config->beta_offset_cqi_index = flexran_get_beta_offset_cqi_index(mod_id,i); - } - - if(flexran_get_ack_nack_simultaneous_trans(mod_id,i) != -1) { - config->has_ack_nack_simultaneous_trans = 1; - config->ack_nack_simultaneous_trans = flexran_get_ack_nack_simultaneous_trans(mod_id,i); - } - - if(flexran_get_simultaneous_ack_nack_cqi(mod_id,i) != -1) { - config->has_simultaneous_ack_nack_cqi = 1; - config->simultaneous_ack_nack_cqi = flexran_get_simultaneous_ack_nack_cqi(mod_id,i); - } - - if(flexran_get_aperiodic_cqi_rep_mode(mod_id,i) != -1) { - config->has_aperiodic_cqi_rep_mode = 1; - int mode = flexran_get_aperiodic_cqi_rep_mode(mod_id,i); - if (mode > 4) { - config->aperiodic_cqi_rep_mode = PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_NONE; - } else { - config->aperiodic_cqi_rep_mode = mode; - } - } - - if(flexran_get_tdd_ack_nack_feedback(mod_id, i) != -1) { - config->has_tdd_ack_nack_feedback = 1; - config->tdd_ack_nack_feedback = flexran_get_tdd_ack_nack_feedback(mod_id,i); - } - - if(flexran_get_ack_nack_repetition_factor(mod_id, i) != -1) { - config->has_ack_nack_repetition_factor = 1; - config->ack_nack_repetition_factor = flexran_get_ack_nack_repetition_factor(mod_id,i); - } - - if(flexran_get_extended_bsr_size(mod_id, i) != -1) { - config->has_extended_bsr_size = 1; - config->extended_bsr_size = flexran_get_extended_bsr_size(mod_id,i); - } - - config->has_pcell_carrier_index = 1; - config->pcell_carrier_index = UE_PCCID(mod_id, i); - //TODO: Set carrier aggregation support (boolean) - config->has_ca_support = 0; - config->ca_support = 0; - if(config->has_ca_support){ - //TODO: Set cross carrier scheduling support (boolean) - config->has_cross_carrier_sched_support = 1; - config->cross_carrier_sched_support = 0; - //TODO: Set secondary cells configuration - // We do not set it for now. No carrier aggregation support - - //TODO: Set deactivation timer for secondary cell - config->has_scell_deactivation_timer = 0; - config->scell_deactivation_timer = 0; - } - } else if (state_change == PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_MOVED) { - // TODO: Not supported for now. Leave blank - } - - ue_state_change_msg->config = config; - msg = malloc(sizeof(Protocol__FlexranMessage)); - if (msg == NULL) { - goto error; - } - protocol__flexran_message__init(msg); - msg->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG; - msg->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; - msg->ue_state_change_msg = ue_state_change_msg; - - data = flexran_agent_pack_message(msg, &size); - /*Send sr info using the MAC channel of the eNB*/ - if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) { - goto error; - } - - LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); - return 0; - error: - LOG_D(FLEXRAN_AGENT, "Could not send UE state message\n"); - return -1; -} - - - int flexran_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { xid_t xid; @@ -2138,191 +1045,39 @@ int flexran_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__F } +int flexran_agent_rrc_measurement(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { -/* - * timer primitives - */ + protocol_ctxt_t ctxt; -//struct flexran_agent_map agent_map; -flexran_agent_timer_instance_t timer_instance; -int agent_timer_init = 0; -err_code_t flexran_agent_init_timer(void){ + Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; + Protocol__FlexRrcTriggering *triggering = input->rrc_triggering; + + agent_reconf_rrc *reconf_param = malloc(sizeof(agent_reconf_rrc)); - LOG_I(FLEXRAN_AGENT, "init RB tree\n"); - if (!agent_timer_init) { - RB_INIT(&timer_instance.flexran_agent_head); - agent_timer_init = 1; + + reconf_param->trigger_policy = triggering->rrc_trigger; + + struct rrc_eNB_ue_context_s *ue_context_p = NULL; + + RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(eNB_rrc_inst[mod_id].rrc_ue_head)){ + + + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, mod_id, ENB_FLAG_YES, ue_context_p->ue_context.rnti, flexran_get_current_frame(mod_id), flexran_get_current_subframe (mod_id), mod_id); + + flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(&ctxt, ue_context_p, 0, reconf_param); + } - - return PROTOCOL__FLEXRAN_ERR__NO_ERR; -} - -RB_GENERATE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer); - -/* The timer_id might not be the best choice for the comparison */ -int flexran_agent_compare_timer(struct flexran_agent_timer_element_s *a, struct flexran_agent_timer_element_s *b){ - - if (a->timer_id < b->timer_id) return -1; - if (a->timer_id > b->timer_id) return 1; - - // equal timers + + + *msg = NULL; return 0; } -err_code_t flexran_agent_create_timer(uint32_t interval_sec, - uint32_t interval_usec, - agent_id_t agent_id, - instance_t instance, - uint32_t timer_type, - xid_t xid, - flexran_agent_timer_callback_t cb, - void* timer_args, - long *timer_id){ - - struct flexran_agent_timer_element_s *e = calloc(1, sizeof(*e)); - DevAssert(e != NULL); - -//uint32_t timer_id; - int ret=-1; - - if ((interval_sec == 0) && (interval_usec == 0 )) - return TIMER_NULL; - - if (timer_type >= FLEXRAN_AGENT_TIMER_TYPE_MAX) - return TIMER_TYPE_INVALIDE; - - if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_ONESHOT){ - ret = timer_setup(interval_sec, - interval_usec, - TASK_FLEXRAN_AGENT, - instance, - TIMER_ONE_SHOT, - timer_args, - timer_id); - - e->type = TIMER_ONE_SHOT; - } - else if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_PERIODIC ){ - ret = timer_setup(interval_sec, - interval_usec, - TASK_FLEXRAN_AGENT, - instance, - TIMER_PERIODIC, - timer_args, - timer_id); - - e->type = TIMER_PERIODIC; - } - - if (ret < 0 ) { - return TIMER_SETUP_FAILED; - } - e->agent_id = agent_id; - e->instance = instance; - e->state = FLEXRAN_AGENT_TIMER_STATE_ACTIVE; - e->timer_id = *timer_id; - e->xid = xid; - e->timer_args = timer_args; - e->cb = cb; - /*element should be a real pointer*/ - RB_INSERT(flexran_agent_map, &timer_instance.flexran_agent_head, e); - - LOG_I(FLEXRAN_AGENT,"Created a new timer with id 0x%lx for agent %d, instance %d \n", - e->timer_id, e->agent_id, e->instance); - - return 0; -} - -err_code_t flexran_agent_destroy_timer(long timer_id){ - - struct flexran_agent_timer_element_s *e = get_timer_entry(timer_id); - - if (e != NULL ) { - RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); - flexran_agent_destroy_flexran_message(e->timer_args->msg); - free(e); - } - - if (timer_remove(timer_id) < 0 ) - goto error; - - return 0; - - error: - LOG_E(FLEXRAN_AGENT, "timer can't be removed\n"); - return TIMER_REMOVED_FAILED ; -} - -err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid) { - struct flexran_agent_timer_element_s *e = NULL; - long timer_id; - RB_FOREACH(e, flexran_agent_map, &timer_instance.flexran_agent_head) { - if (e->xid == xid) { - timer_id = e->timer_id; - RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); - flexran_agent_destroy_flexran_message(e->timer_args->msg); - free(e); - if (timer_remove(timer_id) < 0 ) { - goto error; - } - } - } - return 0; - - error: - LOG_E(FLEXRAN_AGENT, "timer can't be removed\n"); - return TIMER_REMOVED_FAILED ; -} - -err_code_t flexran_agent_destroy_timers(void){ - - struct flexran_agent_timer_element_s *e = NULL; - - RB_FOREACH(e, flexran_agent_map, &timer_instance.flexran_agent_head) { - RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); - timer_remove(e->timer_id); - flexran_agent_destroy_flexran_message(e->timer_args->msg); - free(e); - } - - return 0; - -} - -void flexran_agent_sleep_until(struct timespec *ts, int delay) { - ts->tv_nsec += delay; - if(ts->tv_nsec >= 1000*1000*1000){ - ts->tv_nsec -= 1000*1000*1000; - ts->tv_sec++; - } - clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts, NULL); -} - - -err_code_t flexran_agent_stop_timer(long timer_id){ - - struct flexran_agent_timer_element_s *e=NULL; - struct flexran_agent_timer_element_s search; - memset(&search, 0, sizeof(struct flexran_agent_timer_element_s)); - search.timer_id = timer_id; - - e = RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search); - - if (e != NULL ) { - e->state = FLEXRAN_AGENT_TIMER_STATE_STOPPED; - } - - timer_remove(timer_id); - +int flexran_agent_destroy_rrc_measurement(Protocol__FlexranMessage *msg){ + // TODO return 0; } -struct flexran_agent_timer_element_s * get_timer_entry(long timer_id) { - - struct flexran_agent_timer_element_s search; - memset(&search, 0, sizeof(struct flexran_agent_timer_element_s)); - search.timer_id = timer_id; - return RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search); -} + diff --git a/openair2/ENB_APP/flexran_agent_common.h b/openair2/ENB_APP/flexran_agent_common.h index abe5a05b44..8fd62a0524 100644 --- a/openair2/ENB_APP/flexran_agent_common.h +++ b/openair2/ENB_APP/flexran_agent_common.h @@ -21,8 +21,8 @@ /*! \file flexran_agent_common.h * \brief common message primitves and utilities - * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein - * \date 2016 + * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein and shahab SHARIAT BAGHERI + * \date 2017 * \version 0.1 */ @@ -37,7 +37,8 @@ #include "flexran.pb-c.h" #include "stats_messages.pb-c.h" #include "stats_common.pb-c.h" - +#include "flexran_agent_ran_api.h" +#include "flexran_agent_net_comm.h" #include "flexran_agent_defs.h" #include "enb_config.h" @@ -60,6 +61,19 @@ typedef int (*flexran_agent_message_destruction_callback)( Protocol__FlexranMessage *msg ); +typedef struct { + + uint8_t is_initialized; + volatile uint8_t cont_update; + xid_t xid; + Protocol__FlexranMessage *stats_req; + Protocol__FlexranMessage *prev_stats_reply; + + pthread_mutex_t *mutex; +} stats_updates_context_t; + +stats_updates_context_t stats_context[NUM_MAX_ENB]; + /********************************** * FlexRAN protocol messages helper * functions and generic handlers @@ -116,10 +130,6 @@ int flexran_agent_destroy_ue_config_request(Protocol__FlexranMessage *msg); /* TODO: Need to define and implement destructor */ int flexran_agent_destroy_lc_config_request(Protocol__FlexranMessage *msg); -/* UE state change message constructor and destructor */ -int flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change); -int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg); - /* Control delegation message constructor and destructor */ int flexran_agent_control_delegation(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int flexran_agent_destroy_control_delegation(Protocol__FlexranMessage *msg); @@ -128,6 +138,11 @@ int flexran_agent_destroy_control_delegation(Protocol__FlexranMessage *msg); int flexran_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int flexran_agent_destroy_agent_reconfiguration(Protocol__FlexranMessage *msg); +/* rrc triggering measurement message constructor and destructor */ +int flexran_agent_rrc_measurement(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int flexran_agent_destroy_rrc_measurement(Protocol__FlexranMessage *msg); + + /* FlexRAN protocol message dispatcher function */ Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id, uint8_t *data, @@ -136,367 +151,21 @@ Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id, /* Function to be used to send a message to a dispatcher once the appropriate event is triggered. */ Protocol__FlexranMessage *flexran_agent_handle_timed_task(void *args); +/*Top level Statistics hanlder*/ +int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +/* Function to be used to handle reply message . */ +int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg); +/* Top level Statistics request protocol message constructor and destructor */ +int flexran_agent_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); +int flexran_agent_destroy_stats_request(Protocol__FlexranMessage *msg); -/**************************** - * get generic info from RAN - ****************************/ +err_code_t flexran_agent_init_cont_stats_update(mid_t mod_id); -void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran); - -int flexran_get_current_time_ms (mid_t mod_id, int subframe_flag); - -/*Return the current frame number - *Could be using implementation specific numbering of frames - */ -unsigned int flexran_get_current_frame(mid_t mod_id); - -/*Return the current SFN (0-1023)*/ -unsigned int flexran_get_current_system_frame_num(mid_t mod_id); - -unsigned int flexran_get_current_subframe(mid_t mod_id); - -/*Return the frame and subframe number in compact 16-bit format. - Bits 0-3 subframe, rest for frame. Required by FlexRAN protocol*/ -uint16_t flexran_get_sfn_sf (mid_t mod_id); - -/* Return a future frame and subframe number that is ahead_of_time - subframes later in compact 16-bit format. Bits 0-3 subframe, - rest for frame */ -uint16_t flexran_get_future_sfn_sf(mid_t mod_id, int ahead_of_time); - -/* Return the number of attached UEs */ -int flexran_get_num_ues(mid_t mod_id); - -/* Get the rnti of a UE with id ue_id */ -int flexran_get_ue_crnti (mid_t mod_id, mid_t ue_id); - -/* Get the RLC buffer status report of a ue for a designated - logical channel id */ -int flexran_get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid); - -/* Get power headroom of UE with id ue_id */ -int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id); - -/* Get the UE wideband CQI */ -int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id); - -/* Get the transmission queue size for a UE with a channel_id logical channel id */ -int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); - -/* Get the head of line delay for a UE with a channel_id logical channel id */ -int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); - -/* Check the status of the timing advance for a UE */ -short flexran_get_TA(mid_t mod_id, mid_t ue_id, int CC_id); - -/* Update the timing advance status (find out whether a timing advance command is required) */ -void flexran_update_TA(mid_t mod_id, mid_t ue_id, int CC_id); - -/* Return timing advance MAC control element for a designated cell and UE */ -int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, int CC_id); - -/* Get the number of active component carriers for a specific UE */ -int flexran_get_active_CC(mid_t mod_id, mid_t ue_id); - -/* Get the rank indicator for a designated cell and UE */ -int flexran_get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id); - -/* See TS 36.213, section 10.1 */ -int flexran_get_n1pucch_an(mid_t mod_id, int CC_id); - -/* See TS 36.211, section 5.4 */ -int flexran_get_nRB_CQI(mid_t mod_id, int CC_id); - -/* See TS 36.211, section 5.4 */ -int flexran_get_deltaPUCCH_Shift(mid_t mod_id, int CC_id); - -/* See TS 36.211, section 5.7.1 */ -int flexran_get_prach_ConfigIndex(mid_t mod_id, int CC_id); - -/* See TS 36.211, section 5.7.1 */ -int flexran_get_prach_FreqOffset(mid_t mod_id, int CC_id); - -/* See TS 36.321 */ -int flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id); - -/* Get the length of the UL cyclic prefix */ -int flexran_get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id); - -/* Get the length of the DL cyclic prefix */ -int flexran_get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id); - -/* Get the physical cell id of a cell */ -int flexran_get_cell_id(mid_t mod_id, int CC_id); - -/* See TS 36.211, section 5.5.3.2 */ -int flexran_get_srs_BandwidthConfig(mid_t mod_id, int CC_id); - -/* See TS 36.211, table 5.5.3.3-1 and 2 */ -int flexran_get_srs_SubframeConfig(mid_t mod_id, int CC_id); - -/* Boolean value. See TS 36.211, - section 5.5.3.2. TDD only */ -int flexran_get_srs_MaxUpPts(mid_t mod_id, int CC_id); - -/* Get number of DL resource blocks */ -int flexran_get_N_RB_DL(mid_t mod_id, int CC_id); - -/* Get number of UL resource blocks */ -int flexran_get_N_RB_UL(mid_t mod_id, int CC_id); - -/* Get number of resource block groups */ -int flexran_get_N_RBG(mid_t mod_id, int CC_id); - -/* Get DL/UL subframe assignment. TDD only */ -int flexran_get_subframe_assignment(mid_t mod_id, int CC_id); - -/* TDD only. See TS 36.211, table 4.2.1 */ -int flexran_get_special_subframe_assignment(mid_t mod_id, int CC_id); - -/* Get the duration of the random access response window in subframes */ -int flexran_get_ra_ResponseWindowSize(mid_t mod_id, int CC_id); - -/* Get timer used for random access */ -int flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id); - -/* Get type of duplex mode (FDD/TDD) */ -int flexran_get_duplex_mode(mid_t mod_id, int CC_id); - -/* Get the SI window length */ -long flexran_get_si_window_length(mid_t mod_id, int CC_id); - -/* Get the number of PDCCH symbols configured for the cell */ -int flexran_get_num_pdcch_symb(mid_t mod_id, int CC_id); - -/* See TS 36.213, sec 5.1.1.1 */ -int flexran_get_tpc(mid_t mod_id, mid_t ue_id); - -/* Get the first available HARQ process for a specific cell and UE during - a designated frame and subframe. Returns 0 for success. The id and the - status of the HARQ process are stored in id and status respectively */ -int flexran_get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, - const int frame, const uint8_t subframe, unsigned char *id, unsigned char *round); - -/* Uplink power control management*/ -int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id); - -int flexran_get_p0_nominal_pucch(mid_t mod_id, int CC_id); - -int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id); - -int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id); - - -/* - * ************************************ - * Get Messages for UE Configuration Reply - * ************************************ - */ - -/* Get timer in subframes. Controls the synchronization - status of the UE, not the actual timing - advance procedure. See TS 36.321 */ -int flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id); - -/* Get measurement gap configuration. See TS 36.133 */ -int flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id); - -/* Get measurement gap configuration offset if applicable */ -int flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id); - -/* DL aggregated bit-rate of non-gbr bearer - per UE. See TS 36.413 */ -int flexran_get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id); - -/* UL aggregated bit-rate of non-gbr bearer - per UE. See TS 36.413 */ -int flexran_get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id); - -/* Only half-duplex support. FDD - operation. Boolean value */ -int flexran_get_half_duplex(mid_t ue_id); - -/* Support of intra-subframe hopping. - Boolean value */ -int flexran_get_intra_sf_hopping(mid_t ue_id); - -/* UE support for type 2 hopping with - n_sb>1 */ -int flexran_get_type2_sb_1(mid_t ue_id); - -/* Get the UE category */ -int flexran_get_ue_category(mid_t ue_id); - -/* UE support for resource allocation - type 1 */ -int flexran_get_res_alloc_type1(mid_t ue_id); - -/* Get UE transmission mode */ -int flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id); - -/* Boolean value. See TS 36.321 */ -int flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id); - -/* The max HARQ retransmission for UL. - See TS 36.321 */ -int flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id); - -/* See TS 36.213 */ -int flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id); - -/* See TS 36.213 */ -int flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id); - -/* See TS 36.213 */ -int flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id); - -/* Boolean. See TS36.213, Section 10.1 */ -int flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id); - -/* Boolean. See TS 36.213, Section 8.2 */ -int flexran_get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id); - -/* Get aperiodic CQI report mode */ -int flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id); - -/* Get ACK/NACK feedback mode. TDD only */ -int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id); - -/* See TS36.213, section 10.1 */ -int flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id); - -/* Boolean. Extended buffer status report size */ -int flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id); - -/* Get number of UE transmission antennas */ -int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id); - -/* Get logical channel group of a channel with id lc_id */ -int flexran_get_lcg(mid_t ue_id, mid_t lc_id); - -/* Get direction of logical channel with id lc_id */ -int flexran_get_direction(mid_t ue_id, mid_t lc_id); - -/******************* - * timer primitves - *******************/ - -#define TIMER_NULL -1 -#define TIMER_TYPE_INVALIDE -2 -#define TIMER_SETUP_FAILED -3 -#define TIMER_REMOVED_FAILED -4 -#define TIMER_ELEMENT_NOT_FOUND -5 - - -/* Type of the callback executed when the timer expired */ -typedef Protocol__FlexranMessage *(*flexran_agent_timer_callback_t)(void*); - -typedef enum { - /* oneshot timer: */ - FLEXRAN_AGENT_TIMER_TYPE_ONESHOT = 0x0, - - /* periodic timer */ - FLEXRAN_AGENT_TIMER_TYPE_PERIODIC = 0x1, - - /* Inactive state: initial state for any timer. */ - FLEXRAN_AGENT_TIMER_TYPE_EVENT_DRIVEN = 0x2, - - /* Max number of states available */ - FLEXRAN_AGENT_TIMER_TYPE_MAX, -} flexran_agent_timer_type_t; - -typedef enum { - /* Inactive state: initial state for any timer. */ - FLEXRAN_AGENT_TIMER_STATE_INACTIVE = 0x0, - - /* Inactive state: initial state for any timer. */ - FLEXRAN_AGENT_TIMER_STATE_ACTIVE = 0x1, - - /* Inactive state: initial state for any timer. */ - FLEXRAN_AGENT_TIMER_STATE_STOPPED = 0x2, - - /* Max number of states available */ - FLEXRAN_AGENT_TIMER_STATE_MAX, -} flexran_agent_timer_state_t; - -typedef struct flexran_agent_timer_args_s{ - mid_t mod_id; - Protocol__FlexranMessage *msg; -} flexran_agent_timer_args_t; - - - -typedef struct flexran_agent_timer_element_s{ - RB_ENTRY(flexran_agent_timer_element_s) entry; - - agent_id_t agent_id; - instance_t instance; - - flexran_agent_timer_type_t type; - flexran_agent_timer_state_t state; - - uint32_t interval_sec; - uint32_t interval_usec; - - long timer_id; /* Timer id returned by the timer API*/ - xid_t xid; /*The id of the task as received by the controller - message*/ - - flexran_agent_timer_callback_t cb; - flexran_agent_timer_args_t *timer_args; - -} flexran_agent_timer_element_t; - -typedef struct flexran_agent_timer_instance_s{ - RB_HEAD(flexran_agent_map, flexran_agent_timer_element_s) flexran_agent_head; -}flexran_agent_timer_instance_t; - - -err_code_t flexran_agent_init_timer(void); - -/* Create a timer for some agent related event with id xid. Will store the id - of the generated timer in timer_id */ -err_code_t flexran_agent_create_timer(uint32_t interval_sec, - uint32_t interval_usec, - agent_id_t agent_id, - instance_t instance, - uint32_t timer_type, - xid_t xid, - flexran_agent_timer_callback_t cb, - void* timer_args, - long *timer_id); - -/* Destroy all existing timers */ -err_code_t flexran_agent_destroy_timers(void); - -/* Destroy the timer with the given timer_id */ -err_code_t flexran_agent_destroy_timer(long timer_id); - -/* Destroy the timer for task with id xid */ -err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid); - -/* Stop a timer */ -err_code_t flexran_agent_stop_timer(long timer_id); - -/* Restart the given timer */ -err_code_t flexran_agent_restart_timer(long *timer_id); - -/* Find the timer with the given timer_id */ -struct flexran_agent_timer_element_s * get_timer_entry(long timer_id); - -/* Obtain the protocol message stored in the given expired timer */ -Protocol__FlexranMessage * flexran_agent_process_timeout(long timer_id, void* timer_args); - -/* Comparator function comparing two timers. Decides the ordering of the timers */ -int flexran_agent_compare_timer(struct flexran_agent_timer_element_s *a, struct flexran_agent_timer_element_s *b); - -/*Specify a delay in nanoseconds to timespec and sleep until then*/ -void flexran_agent_sleep_until(struct timespec *ts, int delay); - -/* RB_PROTOTYPE is for .h files */ -RB_PROTOTYPE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer); +void flexran_agent_send_update_stats(mid_t mod_id); +err_code_t flexran_agent_enable_cont_stats_update(mid_t mod_id, xid_t xid, stats_request_config_t *stats_req) ; +err_code_t flexran_agent_disable_cont_stats_update(mid_t mod_id); #endif diff --git a/openair2/ENB_APP/flexran_agent_defs.h b/openair2/ENB_APP/flexran_agent_defs.h index d60510b0c7..0b8822a949 100644 --- a/openair2/ENB_APP/flexran_agent_defs.h +++ b/openair2/ENB_APP/flexran_agent_defs.h @@ -21,8 +21,8 @@ /*! \file flexran_agent_defs.h * \brief FlexRAN agent common definitions - * \author Navid Nikaein and Xenofon Foukas - * \date 2016 + * \author Navid Nikaein and Xenofon Foukas and shahab SHARIAT BAGHERI + * \date 2017 * \version 0.1 */ #ifndef FLEXRAN_AGENT_DEFS_H_ @@ -102,6 +102,38 @@ typedef uint8_t lcid_t; typedef int32_t err_code_t; +/*---------Timer Enums --------- */ + +typedef enum { + /* oneshot timer: */ + FLEXRAN_AGENT_TIMER_TYPE_ONESHOT = 0, + + /* periodic timer */ + FLEXRAN_AGENT_TIMER_TYPE_PERIODIC = 1, + + /* Inactive state: initial state for any timer. */ + FLEXRAN_AGENT_TIMER_TYPE_EVENT_DRIVEN = 2, + + /* Max number of states available */ + FLEXRAN_AGENT_TIMER_TYPE_MAX, +} flexran_agent_timer_type_t; + + +typedef enum { + /* Inactive state: initial state for any timer. */ + FLEXRAN_AGENT_TIMER_STATE_INACTIVE = 0x0, + + /* Inactive state: initial state for any timer. */ + FLEXRAN_AGENT_TIMER_STATE_ACTIVE = 0x1, + + /* Inactive state: initial state for any timer. */ + FLEXRAN_AGENT_TIMER_STATE_STOPPED = 0x2, + + /* Max number of states available */ + FLEXRAN_AGENT_TIMER_STATE_MAX, +} flexran_agent_timer_state_t; + + typedef struct { /* general info */ @@ -116,6 +148,53 @@ typedef struct { } flexran_agent_info_t; + +/* +rrc triggering + */ + + +typedef struct { + char * trigger_policy; + uint32_t report_interval; + uint32_t report_amount; + +} agent_reconf_rrc; + + +/* These structs will be used to give + instructions for the type of stats reports + we need to create */ + + +typedef struct { + uint16_t ue_rnti; + uint32_t ue_report_flags; /* Indicates the report elements + required for this UE id. See + FlexRAN specification 1.2.4.2 */ +} ue_report_type_t; + +typedef struct { + uint16_t cc_id; + uint32_t cc_report_flags; /* Indicates the report elements + required for this CC index. See + FlexRAN specification 1.2.4.3 */ +} cc_report_type_t; + +typedef struct { + int nr_ue; + ue_report_type_t *ue_report_type; + int nr_cc; + cc_report_type_t *cc_report_type; +} report_config_t; + +typedef struct stats_request_config_s{ + uint8_t report_type; + uint8_t report_frequency; + uint16_t period; /*In number of subframes*/ + report_config_t *config; +} stats_request_config_t; + typedef struct { mid_t enb_id; flexran_agent_info_t agent_info; diff --git a/openair2/ENB_APP/flexran_agent_extern.h b/openair2/ENB_APP/flexran_agent_extern.h index 4a04d5d3a6..4df984e1a0 100644 --- a/openair2/ENB_APP/flexran_agent_extern.h +++ b/openair2/ENB_APP/flexran_agent_extern.h @@ -20,9 +20,9 @@ */ /*! \file ENB_APP/extern.h - * \brief FlexRAN agent - mac interface primitives - * \author Xenofon Foukas - * \date 2016 + * \brief FlexRAN agent - Extern VSF xfaces + * \author Xenofon Foukas and shahab SHARIAT BAGHERI + * \date 2017 * \version 0.1 * \mail x.foukas@sms.ed.ac.uk */ @@ -30,9 +30,9 @@ #ifndef __FLEXRAN_AGENT_EXTERN_H__ #define __FLEXRAN_AGENT_EXTERN_H__ -#include "flexran_agent_defs.h" +// #include "flexran_agent_defs.h" #include "flexran_agent_mac_defs.h" - +#include "flexran_agent_rrc_defs.h" //extern msg_context_t shared_ctxt[NUM_MAX_ENB][FLEXRAN_AGENT_MAX]; @@ -45,6 +45,12 @@ extern AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB]; /* Flag indicating whether the VSFs for the MAC control module have been registered */ extern unsigned int mac_agent_registered[NUM_MAX_ENB]; +/* Control module interface for the communication of the RRC Control Module with the agent */ +extern AGENT_RRC_xface *agent_rrc_xface[NUM_MAX_ENB]; + +/* Flag indicating whether the VSFs for the RRC control module have been registered */ +extern unsigned int rrc_agent_registered[NUM_MAX_ENB]; + /* Requried to know which UEs had a harq updated over some subframe */ extern int harq_pid_updated[NUMBER_OF_UE_MAX][8]; extern int harq_pid_round[NUMBER_OF_UE_MAX][8]; diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c index 29a1c1000c..fc2ed135c8 100644 --- a/openair2/ENB_APP/flexran_agent_handler.c +++ b/openair2/ENB_APP/flexran_agent_handler.c @@ -21,14 +21,17 @@ /*! \file flexran_agent_handler.c * \brief FlexRAN agent tx and rx message handler - * \author Xenofon Foukas and Navid Nikaein - * \date 2016 + * \author Xenofon Foukas and Navid Nikaein and shahab SHARIAT BAGHERI + * \date 2017 * \version 0.1 */ - +#include "flexran_agent_defs.h" #include "flexran_agent_common.h" #include "flexran_agent_mac.h" +#include "flexran_agent_rrc.h" +#include "flexran_agent_timer.h" +#include "flexran_agent_ran_api.h" #include "log.h" #include "assertions.h" @@ -37,7 +40,7 @@ flexran_agent_message_decoded_callback agent_messages_callback[][3] = { {flexran_agent_hello, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_HELLO_MSG*/ {flexran_agent_echo_reply, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_ECHO_REQUEST_MSG*/ {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_ECHO_REPLY_MSG*/ //Must add handler when receiving echo reply - {flexran_agent_mac_handle_stats, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG*/ + {flexran_agent_handle_stats, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG*/ {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG*/ {0, 0, 0}, /*PROTOCOK__FLEXRAN_MESSAGE__MSG_SF_TRIGGER_MSG*/ {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_UL_SR_INFO_MSG*/ @@ -51,13 +54,14 @@ flexran_agent_message_decoded_callback agent_messages_callback[][3] = { {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG*/ {flexran_agent_control_delegation, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_CONTROL_DELEGATION_MSG*/ {flexran_agent_reconfiguration, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_AGENT_RECONFIGURATION_MSG*/ + {flexran_agent_rrc_measurement, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_RRC_TRIGGERING_MSG*/ }; flexran_agent_message_destruction_callback message_destruction_callback[] = { flexran_agent_destroy_hello, flexran_agent_destroy_echo_request, flexran_agent_destroy_echo_reply, - flexran_agent_mac_destroy_stats_request, + flexran_agent_destroy_stats_request, flexran_agent_mac_destroy_stats_reply, flexran_agent_mac_destroy_sf_trigger, flexran_agent_mac_destroy_sr_info, @@ -93,7 +97,7 @@ Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id, err_code= PROTOCOL__FLEXRAN_ERR__MSG_DECODING; goto error; } - + // printf("==================> %d %d \n", decoded_message->msg_case, decoded_message->msg_dir); if ((decoded_message->msg_case > sizeof(agent_messages_callback) / (3 * sizeof(flexran_agent_message_decoded_callback))) || (decoded_message->msg_dir > PROTOCOL__FLEXRAN_DIRECTION__UNSUCCESSFUL_OUTCOME)){ err_code= PROTOCOL__FLEXRAN_ERR__MSG_NOT_HANDLED; @@ -187,3 +191,568 @@ Protocol__FlexranMessage* flexran_agent_process_timeout(long timer_id, void* tim err_code_t flexran_agent_destroy_flexran_message(Protocol__FlexranMessage *msg) { return ((*message_destruction_callback[msg->msg_case-1])(msg)); } + + +/* + Top Level Statistics Report + + */ + + + +int flexran_agent_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg){ + + // TODO: Must deal with sanitization of input + // TODO: Must check if RNTIs and cell ids of the request actually exist + // TODO: Must resolve conflicts among stats requests + + int i; + err_code_t err_code; + xid_t xid; + uint32_t usec_interval, sec_interval; + + //TODO: We do not deal with multiple CCs at the moment and eNB id is 0 + int enb_id = mod_id; + + //eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; + //UE_list_t *eNB_UE_list= &eNB->UE_list; + + report_config_t report_config; + + uint32_t ue_flags = 0; + uint32_t c_flags = 0; + + Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; + + Protocol__FlexStatsRequest *stats_req = input->stats_request_msg; + xid = (stats_req->header)->xid; + + // Check the type of request that is made + switch(stats_req->body_case) { + case PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ; + Protocol__FlexCompleteStatsRequest *comp_req = stats_req->complete_stats_request; + if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_OFF) { + /*Disable both periodic and continuous updates*/ + // flexran_agent_disable_cont_stats_update(mod_id); + flexran_agent_destroy_timer_by_task_id(xid); + *msg = NULL; + return 0; + } else { //One-off, periodical or continuous reporting + //Set the proper flags + ue_flags = comp_req->ue_report_flags; + c_flags = comp_req->cell_report_flags; + //Create a list of all eNB RNTIs and cells + + //Set the number of UEs and create list with their RNTIs stats configs + report_config.nr_ue = flexran_get_num_ues(mod_id); //eNB_UE_list->num_UEs + report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t) * report_config.nr_ue); + if (report_config.ue_report_type == NULL) { + // TODO: Add appropriate error code + err_code = -100; + goto error; + } + for (i = 0; i < report_config.nr_ue; i++) { + report_config.ue_report_type[i].ue_rnti = flexran_get_ue_crnti(enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].crnti; + report_config.ue_report_type[i].ue_report_flags = ue_flags; + } + //Set the number of CCs and create a list with the cell stats configs + report_config.nr_cc = MAX_NUM_CCs; + report_config.cc_report_type = (cc_report_type_t *) malloc(sizeof(cc_report_type_t) * report_config.nr_cc); + if (report_config.cc_report_type == NULL) { + // TODO: Add appropriate error code + err_code = -100; + goto error; + } + for (i = 0; i < report_config.nr_cc; i++) { + //TODO: Must fill in the proper cell ids + report_config.cc_report_type[i].cc_id = i; + report_config.cc_report_type[i].cc_report_flags = c_flags; + } + /* Check if request was periodical */ + if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_PERIODICAL) { + /* Create a one off flexran message as an argument for the periodical task */ + Protocol__FlexranMessage *timer_msg; + stats_request_config_t request_config; + request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS; + request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE; + request_config.period = 0; + /* Need to make sure that the ue flags are saved (Bug) */ + if (report_config.nr_ue == 0) { + report_config.nr_ue = 1; + report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t)); + if (report_config.ue_report_type == NULL) { + // TODO: Add appropriate error code + err_code = -100; + goto error; + } + report_config.ue_report_type[0].ue_rnti = 0; // Dummy value + report_config.ue_report_type[0].ue_report_flags = ue_flags; + } + request_config.config = &report_config; + flexran_agent_stats_request(enb_id, xid, &request_config, &timer_msg); + /* Create a timer */ + long timer_id = 0; + flexran_agent_timer_args_t *timer_args; + timer_args = malloc(sizeof(flexran_agent_timer_args_t)); + memset (timer_args, 0, sizeof(flexran_agent_timer_args_t)); + timer_args->mod_id = enb_id; + timer_args->msg = timer_msg; + /*Convert subframes to usec time*/ + usec_interval = 1000*comp_req->sf; + sec_interval = 0; + /*add seconds if required*/ + if (usec_interval >= 1000*1000) { + sec_interval = usec_interval/(1000*1000); + usec_interval = usec_interval%(1000*1000); + } + flexran_agent_create_timer(sec_interval, usec_interval, FLEXRAN_AGENT_DEFAULT, enb_id, FLEXRAN_AGENT_TIMER_TYPE_PERIODIC, xid, flexran_agent_handle_timed_task,(void*) timer_args, &timer_id); + } else if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_CONTINUOUS) { + /*If request was for continuous updates, disable the previous configuration and + set up a new one*/ + flexran_agent_disable_cont_stats_update(mod_id); + stats_request_config_t request_config; + request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS; + request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE; + request_config.period = 0; + /* Need to make sure that the ue flags are saved (Bug) */ + if (report_config.nr_ue == 0) { + report_config.nr_ue = 1; + report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t)); + if (report_config.ue_report_type == NULL) { + // TODO: Add appropriate error code + err_code = -100; + goto error; + } + report_config.ue_report_type[0].ue_rnti = 0; // Dummy value + report_config.ue_report_type[0].ue_report_flags = ue_flags; + } + request_config.config = &report_config; + flexran_agent_enable_cont_stats_update(enb_id, xid, &request_config); + } + } + break; + case PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST:; + Protocol__FlexCellStatsRequest *cell_req = stats_req->cell_stats_request; + // UE report config will be blank + report_config.nr_ue = 0; + report_config.ue_report_type = NULL; + report_config.nr_cc = cell_req->n_cell; + report_config.cc_report_type = (cc_report_type_t *) malloc(sizeof(cc_report_type_t) * report_config.nr_cc); + if (report_config.cc_report_type == NULL) { + // TODO: Add appropriate error code + err_code = -100; + goto error; + } + for (i = 0; i < report_config.nr_cc; i++) { + //TODO: Must fill in the proper cell ids + report_config.cc_report_type[i].cc_id = cell_req->cell[i]; + report_config.cc_report_type[i].cc_report_flags = cell_req->flags; + } + break; + case PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST:; + Protocol__FlexUeStatsRequest *ue_req = stats_req->ue_stats_request; + // Cell report config will be blank + report_config.nr_cc = 0; + report_config.cc_report_type = NULL; + report_config.nr_ue = ue_req->n_rnti; + report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t) * report_config.nr_ue); + if (report_config.ue_report_type == NULL) { + // TODO: Add appropriate error code + err_code = -100; + goto error; + } + for (i = 0; i < report_config.nr_ue; i++) { + report_config.ue_report_type[i].ue_rnti = ue_req->rnti[i]; + report_config.ue_report_type[i].ue_report_flags = ue_req->flags; + } + break; + default: + //TODO: Add appropriate error code + err_code = -100; + goto error; + } + + if (flexran_agent_stats_reply(enb_id, xid, &report_config, msg )){ + err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; + goto error; + } + + free(report_config.ue_report_type); + free(report_config.cc_report_type); + + return 0; + + error : + LOG_E(FLEXRAN_AGENT, "errno %d occured\n", err_code); + return err_code; +} + +/* + Top level reply + */ + +int flexran_agent_stats_reply(mid_t enb_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg){ + + Protocol__FlexHeader *header; + err_code_t err_code; + int i; + + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) + goto error; + + + Protocol__FlexStatsReply *stats_reply_msg; + + stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply)); + + if (stats_reply_msg == NULL) + goto error; + + protocol__flex_stats_reply__init(stats_reply_msg); + stats_reply_msg->header = header; + + stats_reply_msg->n_ue_report = report_config->nr_ue; + stats_reply_msg->n_cell_report = report_config->nr_cc; + + // UE report + + Protocol__FlexUeStatsReport **ue_report; + + + ue_report = malloc(sizeof(Protocol__FlexUeStatsReport *) * report_config->nr_ue); + if (ue_report == NULL) + goto error; + + for (i = 0; i < report_config->nr_ue; i++) { + + ue_report[i] = malloc(sizeof(Protocol__FlexUeStatsReport)); + protocol__flex_ue_stats_report__init(ue_report[i]); + ue_report[i]->rnti = report_config->ue_report_type[i].ue_rnti; + ue_report[i]->has_rnti = 1; + ue_report[i]->flags = report_config->ue_report_type[i].ue_report_flags; + ue_report[i]->has_flags = 1; + + } + + // cell rpoert + + Protocol__FlexCellStatsReport **cell_report; + + + cell_report = malloc(sizeof(Protocol__FlexCellStatsReport *) * report_config->nr_cc); + if (cell_report == NULL) + goto error; + + for (i = 0; i < report_config->nr_cc; i++) { + + cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport)); + if(cell_report[i] == NULL) + goto error; + + protocol__flex_cell_stats_report__init(cell_report[i]); + cell_report[i]->carrier_index = report_config->cc_report_type[i].cc_id; + cell_report[i]->has_carrier_index = 1; + cell_report[i]->flags = report_config->cc_report_type[i].cc_report_flags; + cell_report[i]->has_flags = 1; + + } + + /* + MAC reply split + */ + + + if (flexran_agent_mac_stats_reply(enb_id, report_config, ue_report, cell_report) < 0 ) { + err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; + goto error; + } + + + stats_reply_msg->cell_report = cell_report; + stats_reply_msg->ue_report = ue_report; + + *msg = malloc(sizeof(Protocol__FlexranMessage)); + if(*msg == NULL) + goto error; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; + (*msg)->stats_reply_msg = stats_reply_msg; + + return 0; + +error : + LOG_E(FLEXRAN_AGENT, "errno %d occured\n", err_code); + return err_code; + +} + +/* + Top Level Request + */ + +int flexran_agent_stats_request(mid_t mod_id, + xid_t xid, + const stats_request_config_t *report_config, + Protocol__FlexranMessage **msg) { + Protocol__FlexHeader *header; + int i; + + Protocol__FlexStatsRequest *stats_request_msg; + stats_request_msg = malloc(sizeof(Protocol__FlexStatsRequest)); + if(stats_request_msg == NULL) + goto error; + protocol__flex_stats_request__init(stats_request_msg); + + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REQUEST, &header) != 0) + goto error; + + stats_request_msg->header = header; + + stats_request_msg->type = report_config->report_type; + stats_request_msg->has_type = 1; + + switch (report_config->report_type) { + case PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS: + stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST; + Protocol__FlexCompleteStatsRequest *complete_stats; + complete_stats = malloc(sizeof(Protocol__FlexCompleteStatsRequest)); + if(complete_stats == NULL) + goto error; + protocol__flex_complete_stats_request__init(complete_stats); + complete_stats->report_frequency = report_config->report_frequency; + complete_stats->has_report_frequency = 1; + complete_stats->sf = report_config->period; + complete_stats->has_sf = 1; + complete_stats->has_cell_report_flags = 1; + complete_stats->has_ue_report_flags = 1; + if (report_config->config->nr_cc > 0) { + complete_stats->cell_report_flags = report_config->config->cc_report_type[0].cc_report_flags; + } + if (report_config->config->nr_ue > 0) { + complete_stats->ue_report_flags = report_config->config->ue_report_type[0].ue_report_flags; + } + stats_request_msg->complete_stats_request = complete_stats; + break; + case PROTOCOL__FLEX_STATS_TYPE__FLST_CELL_STATS: + stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST; + Protocol__FlexCellStatsRequest *cell_stats; + cell_stats = malloc(sizeof(Protocol__FlexCellStatsRequest)); + if(cell_stats == NULL) + goto error; + protocol__flex_cell_stats_request__init(cell_stats); + cell_stats->n_cell = report_config->config->nr_cc; + cell_stats->has_flags = 1; + if (cell_stats->n_cell > 0) { + uint32_t *cells; + cells = (uint32_t *) malloc(sizeof(uint32_t)*cell_stats->n_cell); + for (i = 0; i < cell_stats->n_cell; i++) { + cells[i] = report_config->config->cc_report_type[i].cc_id; + } + cell_stats->cell = cells; + cell_stats->flags = report_config->config->cc_report_type[i].cc_report_flags; + } + stats_request_msg->cell_stats_request = cell_stats; + break; + case PROTOCOL__FLEX_STATS_TYPE__FLST_UE_STATS: + stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST; + Protocol__FlexUeStatsRequest *ue_stats; + ue_stats = malloc(sizeof(Protocol__FlexUeStatsRequest)); + if(ue_stats == NULL) + goto error; + protocol__flex_ue_stats_request__init(ue_stats); + ue_stats->n_rnti = report_config->config->nr_ue; + ue_stats->has_flags = 1; + if (ue_stats->n_rnti > 0) { + uint32_t *ues; + ues = (uint32_t *) malloc(sizeof(uint32_t)*ue_stats->n_rnti); + for (i = 0; i < ue_stats->n_rnti; i++) { + ues[i] = report_config->config->ue_report_type[i].ue_rnti; + } + ue_stats->rnti = ues; + ue_stats->flags = report_config->config->ue_report_type[i].ue_report_flags; + } + stats_request_msg->ue_stats_request = ue_stats; + break; + default: + goto error; + } + *msg = malloc(sizeof(Protocol__FlexranMessage)); + if(*msg == NULL) + goto error; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; + (*msg)->stats_request_msg = stats_request_msg; + return 0; + + error: + // TODO: Need to make proper error handling + if (header != NULL) + free(header); + if (stats_request_msg != NULL) + free(stats_request_msg); + if(*msg != NULL) + free(*msg); + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +int flexran_agent_destroy_stats_request(Protocol__FlexranMessage *msg) { + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG) + goto error; + free(msg->stats_request_msg->header); + if (msg->stats_request_msg->body_case == PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST) { + free(msg->stats_request_msg->cell_stats_request->cell); + } + if (msg->stats_request_msg->body_case == PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST) { + free(msg->stats_request_msg->ue_stats_request->rnti); + } + free(msg->stats_request_msg); + free(msg); + return 0; + + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +/* + Top Level Update + */ + +void flexran_agent_send_update_stats(mid_t mod_id) { + + Protocol__FlexranMessage *current_report = NULL; + void *data; + int size; + err_code_t err_code; + int priority = 0; + + if (pthread_mutex_lock(stats_context[mod_id].mutex)) { + goto error; + } + + if (stats_context[mod_id].cont_update == 1) { + + /*Create a fresh report with the required flags*/ + err_code = flexran_agent_handle_stats(mod_id, (void *) stats_context[mod_id].stats_req, ¤t_report); + if (err_code < 0) { + goto error; + } + } + /* /\*TODO:Check if a previous reports exists and if yes, generate a report */ + /* *that is the diff between the old and the new report, */ + /* *respecting the thresholds. Otherwise send the new report*\/ */ + /* if (stats_context[mod_id].prev_stats_reply != NULL) { */ + + /* msg = flexran_agent_generate_diff_mac_stats_report(current_report, stats_context[mod_id].prev_stats_reply); */ + + /* /\*Destroy the old stats*\/ */ + /* flexran_agent_destroy_flexran_message(stats_context[mod_id].prev_stats_reply); */ + /* } */ + /* /\*Use the current report for future comparissons*\/ */ + /* stats_context[mod_id].prev_stats_reply = current_report; */ + + + if (pthread_mutex_unlock(stats_context[mod_id].mutex)) { + goto error; + } + + if (current_report != NULL){ + data=flexran_agent_pack_message(current_report, &size); + /*Send any stats updates using the MAC channel of the eNB*/ + if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_MAC, data, size, priority)) { + err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; + goto error; + } + + LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); + return; + } + error: + LOG_D(FLEXRAN_AGENT, "Could not send sf trigger message\n"); +} + +err_code_t flexran_agent_disable_cont_stats_update(mid_t mod_id) { + /*Disable the continuous updates for the MAC*/ + if (pthread_mutex_lock(stats_context[mod_id].mutex)) { + goto error; + } + stats_context[mod_id].cont_update = 0; + stats_context[mod_id].xid = 0; + if (stats_context[mod_id].stats_req != NULL) { + flexran_agent_destroy_flexran_message(stats_context[mod_id].stats_req); + } + if (stats_context[mod_id].prev_stats_reply != NULL) { + flexran_agent_destroy_flexran_message(stats_context[mod_id].prev_stats_reply); + } + if (pthread_mutex_unlock(stats_context[mod_id].mutex)) { + goto error; + } + return 0; + + error: + LOG_E(FLEXRAN_AGENT, "stats_context for eNB %d is not initialized\n", mod_id); + return -1; + +} + +err_code_t flexran_agent_enable_cont_stats_update(mid_t mod_id, + xid_t xid, stats_request_config_t *stats_req) { + + if (pthread_mutex_lock(stats_context[mod_id].mutex)) { + goto error; + } + + Protocol__FlexranMessage *req_msg; + + flexran_agent_stats_request(mod_id, xid, stats_req, &req_msg); + stats_context[mod_id].stats_req = req_msg; + stats_context[mod_id].prev_stats_reply = NULL; + + stats_context[mod_id].cont_update = 1; + stats_context[mod_id].xid = xid; + + if (pthread_mutex_unlock(stats_context[mod_id].mutex)) { + goto error; + } + return 0; + + error: + LOG_E(FLEXRAN_AGENT, "stats_context for eNB %d is not initialized\n", mod_id); + return -1; +} + + +err_code_t flexran_agent_init_cont_stats_update(mid_t mod_id) { + + + /*Initially the continuous update is set to false*/ + stats_context[mod_id].cont_update = 0; + stats_context[mod_id].is_initialized = 1; + stats_context[mod_id].stats_req = NULL; + stats_context[mod_id].prev_stats_reply = NULL; + stats_context[mod_id].mutex = calloc(1, sizeof(pthread_mutex_t)); + if (stats_context[mod_id].mutex == NULL) + goto error; + if (pthread_mutex_init(stats_context[mod_id].mutex, NULL)) + goto error;; + + return 0; + + error: + return -1; +} + +err_code_t flexran_agent_destroy_cont_stats_update(mid_t mod_id) { + + stats_context[mod_id].cont_update = 0; + stats_context[mod_id].is_initialized = 0; + flexran_agent_destroy_flexran_message(stats_context[mod_id].stats_req); + flexran_agent_destroy_flexran_message(stats_context[mod_id].prev_stats_reply); + free(stats_context[mod_id].mutex); + + // mac_agent_registered[mod_id] = 0; + return 1; +} diff --git a/openair2/ENB_APP/flexran_agent_ran_api.c b/openair2/ENB_APP/flexran_agent_ran_api.c new file mode 100644 index 0000000000..9602b041c3 --- /dev/null +++ b/openair2/ENB_APP/flexran_agent_ran_api.c @@ -0,0 +1,931 @@ +/* + * 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 flexran_agent_ran_api.c + * \brief FlexRAN RAN API abstraction + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +#include "flexran_agent_ran_api.h" + + +/* + * get generic info from RAN + */ + + + +void * enb[NUM_MAX_ENB]; +void * enb_ue[NUM_MAX_ENB]; +void * enb_rrc[NUM_MAX_ENB]; + +void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran){ + + switch (ran){ + case RAN_LTE_OAI : + enb[mod_id] = (void *)&eNB_mac_inst[mod_id]; + enb_ue[mod_id] = (void *)&eNB_mac_inst[mod_id].UE_list; + enb_rrc[mod_id] = (void *)&eNB_rrc_inst[mod_id]; + break; + default : + goto error; + } + + return; + + error: + LOG_E(FLEXRAN_AGENT, "unknown RAN name %d\n", ran); +} + +int flexran_get_current_time_ms (mid_t mod_id, int subframe_flag){ + + if (subframe_flag == 1){ + return ((eNB_MAC_INST *)enb[mod_id])->frame*10 + ((eNB_MAC_INST *)enb[mod_id])->subframe; + }else { + return ((eNB_MAC_INST *)enb[mod_id])->frame*10; + } + +} + +unsigned int flexran_get_current_frame (mid_t mod_id) { + + // #warning "SFN will not be in [0-1023] when oaisim is used" + return ((eNB_MAC_INST *)enb[mod_id])->frame; + +} + +unsigned int flexran_get_current_system_frame_num(mid_t mod_id) { + return (flexran_get_current_frame(mod_id) %1024); +} + +unsigned int flexran_get_current_subframe (mid_t mod_id) { + + return ((eNB_MAC_INST *)enb[mod_id])->subframe; + +} + +uint16_t flexran_get_sfn_sf (mid_t mod_id) { + + frame_t frame; + sub_frame_t subframe; + uint16_t sfn_sf, frame_mask, sf_mask; + + frame = (frame_t) flexran_get_current_system_frame_num(mod_id); + subframe = (sub_frame_t) flexran_get_current_subframe(mod_id); + frame_mask = ((1<<12) - 1); + sf_mask = ((1<<4) - 1); + sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4); + + return sfn_sf; +} + +uint16_t flexran_get_future_sfn_sf (mid_t mod_id, int ahead_of_time) { + + frame_t frame; + sub_frame_t subframe; + uint16_t sfn_sf, frame_mask, sf_mask; + + frame = (frame_t) flexran_get_current_system_frame_num(mod_id); + subframe = (sub_frame_t) flexran_get_current_subframe(mod_id); + + subframe = ((subframe + ahead_of_time) % 10); + + if (subframe < flexran_get_current_subframe(mod_id)) { + frame = (frame + 1) % 1024; + } + + int additional_frames = ahead_of_time / 10; + frame = (frame + additional_frames) % 1024; + + frame_mask = ((1<<12) - 1); + sf_mask = ((1<<4) - 1); + sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4); + + return sfn_sf; +} + +int flexran_get_num_ues (mid_t mod_id){ + + return ((UE_list_t *)enb_ue[mod_id])->num_UEs; +} + +int flexran_get_ue_crnti (mid_t mod_id, mid_t ue_id) { + + return UE_RNTI(mod_id, ue_id); +} + +int flexran_get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid) { + + return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].bsr_info[lcid]; +} + +int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id) { + + return ((UE_list_t *)enb_ue[mod_id])->UE_template[UE_PCCID(mod_id,ue_id)][ue_id].phr_info; +} + +int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id) { + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, 0, UE_RNTI(mod_id, ue_id)); + return eNB_UE_stats->DL_cqi[0]; + + // return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].dl_cqi; +} + +int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); + uint16_t subframe = (uint16_t) flexran_get_current_subframe(mod_id); + mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id, frame, subframe, ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0); + return rlc_status.bytes_in_buffer; +} + +int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); + uint16_t subframe = (uint16_t) flexran_get_current_subframe(mod_id); + mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, subframe, ENB_FLAG_YES, MBMS_FLAG_NO, channel_id, 0); + return rlc_status.head_sdu_creation_time; +} + +short flexran_get_TA(mid_t mod_id, mid_t ue_id, int CC_id) { + + // UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list; + int rnti; + + rnti = flexran_get_ue_crnti(mod_id, ue_id); + + LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + //ue_sched_ctl->ta_timer = 20; // wait 20 subframes before taking TA measurement from PHY + switch (PHY_vars_eNB_g[mod_id][CC_id]->frame_parms.N_RB_DL) { + case 6: + return eNB_UE_stats->timing_advance_update; + case 15: + return eNB_UE_stats->timing_advance_update/2; + case 25: + return eNB_UE_stats->timing_advance_update/4; + case 50: + return eNB_UE_stats->timing_advance_update/8; + case 75: + return eNB_UE_stats->timing_advance_update/12; + case 100: + if (PHY_vars_eNB_g[mod_id][CC_id]->frame_parms.threequarter_fs == 0) { + return eNB_UE_stats->timing_advance_update/16; + } else { + return eNB_UE_stats->timing_advance_update/12; + } + default: + return 0; + } +} + +int flexran_get_ue_pmi(mid_t mod_id){ + + /*Xenofon to check this*/ + + return 0; +} + + +void flexran_update_TA(mid_t mod_id, mid_t ue_id, int CC_id) { + + UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list; + UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[ue_id]; + + if (ue_sched_ctl->ta_timer == 0) { + + // WE SHOULD PROTECT the eNB_UE_stats with a mutex here ... + // LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + //ue_sched_ctl->ta_timer = 20; // wait 20 subframes before taking TA measurement from PHY + ue_sched_ctl->ta_update = flexran_get_TA(mod_id, ue_id, CC_id); + + // clear the update in case PHY does not have a new measurement after timer expiry + // eNB_UE_stats->timing_advance_update = 0; + } else { + ue_sched_ctl->ta_timer--; + ue_sched_ctl->ta_update = 0; // don't trigger a timing advance command + } +} + +int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) { + + // UE_list_t *UE_list = &eNB_mac_inst[mod_id].UE_list; + + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); + + if (eNB_UE_stats == NULL) { + return 0; + } + + if (flexran_get_TA(mod_id, ue_id, CC_id) != 0) { + return PROTOCOL__FLEX_CE_TYPE__FLPCET_TA; + } else { + return 0; + } + +} + +int flexran_get_active_CC(mid_t mod_id, mid_t ue_id) { + return ((UE_list_t *)enb_ue[mod_id])->numactiveCCs[ue_id]; +} + +int flexran_get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) { + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); + + if (eNB_UE_stats == NULL) { + return 0; + } + + return eNB_UE_stats[CC_id].rank; +} + +int flexran_get_tpc(mid_t mod_id, mid_t ue_id) { + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + int32_t normalized_rx_power, target_rx_power; + int tpc = 1; + + int pCCid = UE_PCCID(mod_id,ue_id); + rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, pCCid, rnti); + + target_rx_power = mac_xface->get_target_pusch_rx_power(mod_id,pCCid); + + if (eNB_UE_stats == NULL) { + normalized_rx_power = target_rx_power; + } else if (eNB_UE_stats->UL_rssi != NULL) { + normalized_rx_power = eNB_UE_stats->UL_rssi[0]; + } else { + normalized_rx_power = target_rx_power; + } + + if (normalized_rx_power>(target_rx_power+1)) { + tpc = 0; //-1 + } else if (normalized_rx_power<(target_rx_power-1)) { + tpc = 2; //+1 + } else { + tpc = 1; //0 + } + return tpc; +} + +int flexran_get_harq(const mid_t mod_id, + const uint8_t CC_id, + const mid_t ue_id, + const int frame, + const uint8_t subframe, + uint8_t *id, + uint8_t *round) { //flag_id_status = 0 then id, else status + /*TODO: Add int TB in function parameters to get the status of the second TB. This can be done to by editing in + * get_ue_active_harq_pid function in line 272 file: phy_procedures_lte_eNB.c to add + * DLSCH_ptr = PHY_vars_eNB_g[Mod_id][CC_id]->dlsch_eNB[(uint32_t)UE_id][1];*/ + + uint8_t harq_pid; + uint8_t harq_round; + + + uint16_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + + mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&harq_round,openair_harq_DL); + + *id = harq_pid; + *round = harq_round; + /* if (round > 0) { */ + /* *status = 1; */ + /* } else { */ + /* *status = 0; */ + /* } */ + + /* return 0; */ + return *round; +} + +int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id) { + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + + if (eNB_UE_stats == NULL) { + return -1; + } + + // if(eNB_UE_stats->Po_PUCCH_update == 1) { + return eNB_UE_stats->Po_PUCCH_dBm; + //} + //else + // return -1; +} + +int flexran_get_p0_nominal_pucch(mid_t mod_id, int CC_id) { + int32_t pucch_rx_received = mac_xface->get_target_pucch_rx_power(mod_id, CC_id); + return pucch_rx_received; +} + +int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id) { + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + return eNB_UE_stats->Po_PUCCH_update; +} + +int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id) { + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + uint32_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + eNB_UE_stats->Po_PUCCH_update = 0; + + return 0; +} + + +/* + * ************************************ + * Get Messages for eNB Configuration Reply + * ************************************ + */ + +int flexran_get_hopping_offset(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pusch_config_common.pusch_HoppingOffset; +} + +int flexran_get_hopping_mode(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pusch_config_common.hoppingMode; +} + +int flexran_get_n_SB(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pusch_config_common.n_SB; +} + +int flexran_get_enable64QAM(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pusch_config_common.enable64QAM; +} + +int flexran_get_phich_duration(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->phich_config_common.phich_duration; +} + +int flexran_get_phich_resource(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + if(frame_parms->phich_config_common.phich_resource == oneSixth) + return 0; + else if(frame_parms->phich_config_common.phich_resource == half) + return 1; + else if(frame_parms->phich_config_common.phich_resource == one) + return 2; + else if(frame_parms->phich_config_common.phich_resource == two) + return 3; + + return -1; +} + +int flexran_get_n1pucch_an(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pucch_config_common.n1PUCCH_AN; +} + +int flexran_get_nRB_CQI(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pucch_config_common.nRB_CQI; +} + +int flexran_get_deltaPUCCH_Shift(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->pucch_config_common.deltaPUCCH_Shift; +} + +int flexran_get_prach_ConfigIndex(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex; +} + +int flexran_get_prach_FreqOffset(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset; +} + +int flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->maxHARQ_Msg3Tx; +} + +int flexran_get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->Ncp_UL; +} + +int flexran_get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->Ncp; +} + +int flexran_get_cell_id(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->Nid_cell; +} + +int flexran_get_srs_BandwidthConfig(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->soundingrs_ul_config_common.srs_BandwidthConfig; +} + +int flexran_get_srs_SubframeConfig(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->soundingrs_ul_config_common.srs_SubframeConfig; +} + +int flexran_get_srs_MaxUpPts(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->soundingrs_ul_config_common.srs_MaxUpPts; +} + +int flexran_get_N_RB_DL(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->N_RB_DL; +} + +int flexran_get_N_RB_UL(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->N_RB_UL; +} + +int flexran_get_N_RBG(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->N_RBG; +} + +int flexran_get_subframe_assignment(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->tdd_config; +} + +int flexran_get_special_subframe_assignment(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->tdd_config_S; +} + +int flexran_get_ra_ResponseWindowSize(mid_t mod_id, int CC_id) { + return enb_config_get()->properties[mod_id]->rach_raResponseWindowSize[CC_id]; +} + +int flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id) { + return enb_config_get()->properties[mod_id]->rach_macContentionResolutionTimer[CC_id]; +} + +int flexran_get_duplex_mode(mid_t mod_id, int CC_id) { + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + if(frame_parms->frame_type == TDD) + return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD; + else if (frame_parms->frame_type == FDD) + return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_FDD; + + return -1; +} + +long flexran_get_si_window_length(mid_t mod_id, int CC_id) { + return ((eNB_RRC_INST *)enb_rrc[mod_id])->carrier[CC_id].sib1->si_WindowLength; +} + +int flexran_get_sib1_length(mid_t mod_id, int CC_id) { + return ((eNB_RRC_INST *)enb_rrc[mod_id])->carrier[CC_id].sizeof_SIB1; +} + +int flexran_get_num_pdcch_symb(mid_t mod_id, int CC_id) { + /* TODO: This should return the number of PDCCH symbols initially used by the cell CC_id */ + return 0; + //(PHY_vars_UE_g[mod_id][CC_id]->lte_ue_pdcch_vars[mod_id]->num_pdcch_symbols); +} + + + +/* + * ************************************ + * Get Messages for UE Configuration Reply + * ************************************ + */ + + +int flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.mac_MainConfig != NULL) { + return ue_context_p->ue_context.mac_MainConfig->timeAlignmentTimerDedicated; + } else { + return -1; + } + } else { + return -1; + } +} + +int flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.measGapConfig != NULL) { + if(ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_setup) { + if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp0) { + return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP1; + } else if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp1) { + return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP2; + } else { + return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF; + } + } + } + } + return -1; +} + + +int flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.measGapConfig != NULL){ + if(ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_setup) { + if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp0) { + return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp0; + } else if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp1) { + return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp0; + } + } + } + } + return -1; +} + +int flexran_get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id) { + return ((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateDL; +} + +int flexran_get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id) { + return ((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateUL; +} + +int flexran_get_half_duplex(mid_t ue_id) { + // TODO + //int halfduplex = 0; + //int bands_to_scan = ((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.count; + //for (int i =0; i < bands_to_scan; i++){ + //if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.array[i]->halfDuplex > 0) + // halfduplex = 1; + //} + //return halfduplex; + return 0; +} + +int flexran_get_intra_sf_hopping(mid_t ue_id) { + //TODO:Get proper value + //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); + //return (0 & ( 1 << (31))); + return 0; +} + +int flexran_get_type2_sb_1(mid_t ue_id) { + //TODO:Get proper value + //uint8_t temp = 0; + //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); + //return (temp & ( 1 << (11))); + return 0; +} + +int flexran_get_ue_category(mid_t ue_id) { + //TODO:Get proper value + //return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->ue_Category); + return 0; +} + +int flexran_get_res_alloc_type1(mid_t ue_id) { + //TODO:Get proper value + //uint8_t temp = 0; + //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); + //return (temp & ( 1 << (30))); + return 0; +} + +int flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + return ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode; + } else { + return -1; + } + } else { + return -1; + } +} + +int flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.mac_MainConfig != NULL){ + return ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->ttiBundling; + } else { + return -1; + } + } + else { + return -1; + } +} + +int flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.mac_MainConfig != NULL){ + return *ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->maxHARQ_Tx; + } + } + return -1; +} + +int flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_ACK_Index; + } else { + return -1; + } + } else { + return -1; + } +} + +int flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index; + } else { + return -1; + } + } else { + return -1; + } +} + +int flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index; + } else { + return -1; + } + } + else { + return -1; + } +} + +int flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + if (ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic != NULL) { + return ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.simultaneousAckNackAndCQI; + } + } + } + return -1; +} + +int flexran_get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id) { + return (&eNB_rrc_inst[mod_id])->carrier[0].sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; +} + +int flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + return *ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic; + } + } + return -1; +} + +int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) { + // TODO: This needs fixing + return -1; + + /* struct rrc_eNB_ue_context_s* ue_context_p = NULL; */ + /* uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); */ + + /* ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); */ + + /* if(ue_context_p != NULL) { */ + /* if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ */ + /* return ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode; */ + /* } else { */ + /* return -1; */ + /* } */ + /* } else { */ + /* return -1; */ + /* } */ +} + +int flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + return ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->ackNackRepetition.choice.setup.repetitionFactor; + } else { + return -1; + } + } else { + return -1; + } +} + +int flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id) { + //TODO: need to double check + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.mac_MainConfig != NULL){ + if(ue_context_p->ue_context.mac_MainConfig->ext2 != NULL){ + long val = (*(ue_context_p->ue_context.mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10)); + if (val > 0) { + return 1; + } + } + } + } + return -1; +} + +int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = flexran_get_ue_crnti(mod_id,ue_id); + + ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); + + if(ue_context_p != NULL) { + if(ue_context_p->ue_context.physicalConfigDedicated != NULL){ + if(ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_closedLoop) { + return 2; + } else if(ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_openLoop) { + return 1; + } else { + return 0; + } + } else { + return -1; + } + } else { + return -1; + } +} + +int flexran_get_lcg(mid_t ue_id, mid_t lc_id) { + if (UE_mac_inst == NULL) { + return -1; + } + if(UE_mac_inst[ue_id].logicalChannelConfig[lc_id] != NULL) { + return *UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters->logicalChannelGroup; + } else { + return -1; + } +} + +int flexran_get_direction(mid_t ue_id, mid_t lc_id) { + /*TODO: fill with the value for the rest of LCID*/ + if(lc_id == DCCH || lc_id == DCCH1) { + return 2; + } else if(lc_id == DTCH) { + return 1; + } else { + return -1; + } +} + +int flexran_get_antenna_ports(mid_t mod_id, int CC_id){ + + LTE_DL_FRAME_PARMS *frame_parms; + + frame_parms = mac_xface->get_lte_frame_parms(mod_id, CC_id); + return frame_parms->nb_antenna_ports_eNB; + +} diff --git a/openair2/ENB_APP/flexran_agent_ran_api.h b/openair2/ENB_APP/flexran_agent_ran_api.h new file mode 100644 index 0000000000..8a7d6dbaf7 --- /dev/null +++ b/openair2/ENB_APP/flexran_agent_ran_api.h @@ -0,0 +1,301 @@ +/* + * 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 flexran_agent_ran_api.h + * \brief FlexRAN RAN API abstraction header + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +#include +#include + +#include "flexran_agent_common.h" +#include "flexran_agent_common_internal.h" +#include "flexran_agent_extern.h" +#include "flexran_agent_defs.h" + + +#include "enb_config.h" +#include "LAYER2/MAC/extern.h" +#include "LAYER2/RLC/rlc.h" +#include "SCHED/defs.h" +#include "RRC/LITE/extern.h" +#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" +#include "RRC/LITE/rrc_eNB_UE_context.h" +#include "PHY/extern.h" +#include "log.h" + +/**************************** + * get generic info from RAN + ****************************/ + +void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran); + +int flexran_get_current_time_ms (mid_t mod_id, int subframe_flag); + +/*Return the current frame number + *Could be using implementation specific numbering of frames + */ +unsigned int flexran_get_current_frame(mid_t mod_id); + +/*Return the current SFN (0-1023)*/ +unsigned int flexran_get_current_system_frame_num(mid_t mod_id); + +unsigned int flexran_get_current_subframe(mid_t mod_id); + +/*Return the frame and subframe number in compact 16-bit format. + Bits 0-3 subframe, rest for frame. Required by FlexRAN protocol*/ +uint16_t flexran_get_sfn_sf (mid_t mod_id); + +/* Return a future frame and subframe number that is ahead_of_time + subframes later in compact 16-bit format. Bits 0-3 subframe, + rest for frame */ +uint16_t flexran_get_future_sfn_sf(mid_t mod_id, int ahead_of_time); + +/* Return the number of attached UEs */ +int flexran_get_num_ues(mid_t mod_id); + +/* Get the rnti of a UE with id ue_id */ +int flexran_get_ue_crnti (mid_t mod_id, mid_t ue_id); + +/* Get the RLC buffer status report of a ue for a designated + logical channel id */ +int flexran_get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid); + +/* Get power headroom of UE with id ue_id */ +int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id); + +/* Get the UE wideband CQI */ +int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id); + +/* Get the transmission queue size for a UE with a channel_id logical channel id */ +int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); + +/* Get the head of line delay for a UE with a channel_id logical channel id */ +int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); + +/* Check the status of the timing advance for a UE */ +short flexran_get_TA(mid_t mod_id, mid_t ue_id, int CC_id); + +/* Update the timing advance status (find out whether a timing advance command is required) */ +void flexran_update_TA(mid_t mod_id, mid_t ue_id, int CC_id); + +/* Return timing advance MAC control element for a designated cell and UE */ +int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, int CC_id); + +/* Get the number of active component carriers for a specific UE */ +int flexran_get_active_CC(mid_t mod_id, mid_t ue_id); + +/* Get the rank indicator for a designated cell and UE */ +int flexran_get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id); + +/* See TS 36.213, section 10.1 */ +int flexran_get_n1pucch_an(mid_t mod_id, int CC_id); + +/* See TS 36.211, section 5.4 */ +int flexran_get_nRB_CQI(mid_t mod_id, int CC_id); + +/* See TS 36.211, section 5.4 */ +int flexran_get_deltaPUCCH_Shift(mid_t mod_id, int CC_id); + +/* See TS 36.211, section 5.7.1 */ +int flexran_get_prach_ConfigIndex(mid_t mod_id, int CC_id); + +/* See TS 36.211, section 5.7.1 */ +int flexran_get_prach_FreqOffset(mid_t mod_id, int CC_id); + +/* See TS 36.321 */ +int flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id); + +/* Get the length of the UL cyclic prefix */ +int flexran_get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id); + +/* Get the length of the DL cyclic prefix */ +int flexran_get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id); + +/* Get the physical cell id of a cell */ +int flexran_get_cell_id(mid_t mod_id, int CC_id); + +/* See TS 36.211, section 5.5.3.2 */ +int flexran_get_srs_BandwidthConfig(mid_t mod_id, int CC_id); + +/* See TS 36.211, table 5.5.3.3-1 and 2 */ +int flexran_get_srs_SubframeConfig(mid_t mod_id, int CC_id); + +/* Boolean value. See TS 36.211, + section 5.5.3.2. TDD only */ +int flexran_get_srs_MaxUpPts(mid_t mod_id, int CC_id); + +/* Get number of DL resource blocks */ +int flexran_get_N_RB_DL(mid_t mod_id, int CC_id); + +/* Get number of UL resource blocks */ +int flexran_get_N_RB_UL(mid_t mod_id, int CC_id); + +/* Get number of resource block groups */ +int flexran_get_N_RBG(mid_t mod_id, int CC_id); + +/* Get DL/UL subframe assignment. TDD only */ +int flexran_get_subframe_assignment(mid_t mod_id, int CC_id); + +/* TDD only. See TS 36.211, table 4.2.1 */ +int flexran_get_special_subframe_assignment(mid_t mod_id, int CC_id); + +/* Get the duration of the random access response window in subframes */ +int flexran_get_ra_ResponseWindowSize(mid_t mod_id, int CC_id); + +/* Get timer used for random access */ +int flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id); + +/* Get type of duplex mode (FDD/TDD) */ +int flexran_get_duplex_mode(mid_t mod_id, int CC_id); + +/* Get the SI window length */ +long flexran_get_si_window_length(mid_t mod_id, int CC_id); + +/* Get the number of PDCCH symbols configured for the cell */ +int flexran_get_num_pdcch_symb(mid_t mod_id, int CC_id); + +int flexran_get_antenna_ports(mid_t mod_id, int CC_id); + +/* See TS 36.213, sec 5.1.1.1 */ +int flexran_get_tpc(mid_t mod_id, mid_t ue_id); + +int flexran_get_ue_pmi(mid_t mod_id); + +/* Get the first available HARQ process for a specific cell and UE during + a designated frame and subframe. Returns 0 for success. The id and the + status of the HARQ process are stored in id and status respectively */ +int flexran_get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, + const int frame, const uint8_t subframe, unsigned char *id, unsigned char *round); + +/* Uplink power control management*/ +int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id); + +int flexran_get_p0_nominal_pucch(mid_t mod_id, int CC_id); + +int flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, int CC_id); + +int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, int CC_id); + +int flexran_get_hopping_mode(mid_t mod_id, int CC_id); + +int flexran_get_hopping_offset(mid_t mod_id, int CC_id); + +int flexran_get_n_SB(mid_t mod_id, int CC_id); + +int flexran_get_phich_resource(mid_t mod_id, int CC_id); + +int flexran_get_enable64QAM(mid_t mod_id, int CC_id); + +int flexran_get_phich_duration(mid_t mod_id, int CC_id); + +/* + * ************************************ + * Get Messages for UE Configuration Reply + * ************************************ + */ + +/* Get timer in subframes. Controls the synchronization + status of the UE, not the actual timing + advance procedure. See TS 36.321 */ +int flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id); + +/* Get measurement gap configuration. See TS 36.133 */ +int flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id); + +/* Get measurement gap configuration offset if applicable */ +int flexran_get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id); + +/* DL aggregated bit-rate of non-gbr bearer + per UE. See TS 36.413 */ +int flexran_get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id); + +/* UL aggregated bit-rate of non-gbr bearer + per UE. See TS 36.413 */ +int flexran_get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id); + +/* Only half-duplex support. FDD + operation. Boolean value */ +int flexran_get_half_duplex(mid_t ue_id); + +/* Support of intra-subframe hopping. + Boolean value */ +int flexran_get_intra_sf_hopping(mid_t ue_id); + +/* UE support for type 2 hopping with + n_sb>1 */ +int flexran_get_type2_sb_1(mid_t ue_id); + +/* Get the UE category */ +int flexran_get_ue_category(mid_t ue_id); + +/* UE support for resource allocation + type 1 */ +int flexran_get_res_alloc_type1(mid_t ue_id); + +/* Get UE transmission mode */ +int flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id); + +/* Boolean value. See TS 36.321 */ +int flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id); + +/* The max HARQ retransmission for UL. + See TS 36.321 */ +int flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id); + +/* See TS 36.213 */ +int flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id); + +/* See TS 36.213 */ +int flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id); + +/* See TS 36.213 */ +int flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id); + +/* Boolean. See TS36.213, Section 10.1 */ +int flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id); + +/* Boolean. See TS 36.213, Section 8.2 */ +int flexran_get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id); + +/* Get aperiodic CQI report mode */ +int flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id); + +/* Get ACK/NACK feedback mode. TDD only */ +int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id); + +/* See TS36.213, section 10.1 */ +int flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id); + +/* Boolean. Extended buffer status report size */ +int flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id); + +/* Get number of UE transmission antennas */ +int flexran_get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id); + +/* Get logical channel group of a channel with id lc_id */ +int flexran_get_lcg(mid_t ue_id, mid_t lc_id); + +/* Get direction of logical channel with id lc_id */ +int flexran_get_direction(mid_t ue_id, mid_t lc_id); \ No newline at end of file diff --git a/openair2/ENB_APP/flexran_agent_timer.c b/openair2/ENB_APP/flexran_agent_timer.c new file mode 100644 index 0000000000..f5436e4d01 --- /dev/null +++ b/openair2/ENB_APP/flexran_agent_timer.c @@ -0,0 +1,217 @@ +/* + * 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 flexran_agent_timer.c + * \brief FlexRAN Timer + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +/* + * timer primitives + */ + +#include "flexran_agent_timer.h" + +//struct flexran_agent_map agent_map; +flexran_agent_timer_instance_t timer_instance; +int agent_timer_init = 0; +err_code_t flexran_agent_init_timer(void){ + + LOG_I(FLEXRAN_AGENT, "init RB tree\n"); + if (!agent_timer_init) { + RB_INIT(&timer_instance.flexran_agent_head); + agent_timer_init = 1; + } + + return PROTOCOL__FLEXRAN_ERR__NO_ERR; +} + +RB_GENERATE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer); + +/* The timer_id might not be the best choice for the comparison */ +int flexran_agent_compare_timer(struct flexran_agent_timer_element_s *a, struct flexran_agent_timer_element_s *b){ + + if (a->timer_id < b->timer_id) return -1; + if (a->timer_id > b->timer_id) return 1; + + // equal timers + return 0; +} + +err_code_t flexran_agent_create_timer(uint32_t interval_sec, + uint32_t interval_usec, + agent_id_t agent_id, + instance_t instance, + uint32_t timer_type, + xid_t xid, + flexran_agent_timer_callback_t cb, + void* timer_args, + long *timer_id){ + + struct flexran_agent_timer_element_s *e = calloc(1, sizeof(*e)); + DevAssert(e != NULL); + +//uint32_t timer_id; + int ret=-1; + + if ((interval_sec == 0) && (interval_usec == 0 )) + return TIMER_NULL; + + if (timer_type >= FLEXRAN_AGENT_TIMER_TYPE_MAX) + return TIMER_TYPE_INVALIDE; + + if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_ONESHOT){ + ret = timer_setup(interval_sec, + interval_usec, + TASK_FLEXRAN_AGENT, + instance, + TIMER_ONE_SHOT, + timer_args, + timer_id); + + e->type = TIMER_ONE_SHOT; + } + else if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_PERIODIC ){ + ret = timer_setup(interval_sec, + interval_usec, + TASK_FLEXRAN_AGENT, + instance, + TIMER_PERIODIC, + timer_args, + timer_id); + + e->type = TIMER_PERIODIC; + } + + if (ret < 0 ) { + return TIMER_SETUP_FAILED; + } + + e->agent_id = agent_id; + e->instance = instance; + e->state = FLEXRAN_AGENT_TIMER_STATE_ACTIVE; + e->timer_id = *timer_id; + e->xid = xid; + e->timer_args = timer_args; + e->cb = cb; + /*element should be a real pointer*/ + RB_INSERT(flexran_agent_map, &timer_instance.flexran_agent_head, e); + + LOG_I(FLEXRAN_AGENT,"Created a new timer with id 0x%lx for agent %d, instance %d \n", + e->timer_id, e->agent_id, e->instance); + + return 0; +} + +err_code_t flexran_agent_destroy_timer(long timer_id){ + + struct flexran_agent_timer_element_s *e = get_timer_entry(timer_id); + + if (e != NULL ) { + RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); + flexran_agent_destroy_flexran_message(e->timer_args->msg); + free(e); + } + + if (timer_remove(timer_id) < 0 ) + goto error; + + return 0; + + error: + LOG_E(FLEXRAN_AGENT, "timer can't be removed\n"); + return TIMER_REMOVED_FAILED ; +} + +err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid) { + struct flexran_agent_timer_element_s *e = NULL; + long timer_id; + RB_FOREACH(e, flexran_agent_map, &timer_instance.flexran_agent_head) { + if (e->xid == xid) { + timer_id = e->timer_id; + RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); + flexran_agent_destroy_flexran_message(e->timer_args->msg); + free(e); + if (timer_remove(timer_id) < 0 ) { + goto error; + } + } + } + return 0; + + error: + LOG_E(FLEXRAN_AGENT, "timer can't be removed\n"); + return TIMER_REMOVED_FAILED ; +} + +err_code_t flexran_agent_destroy_timers(void){ + + struct flexran_agent_timer_element_s *e = NULL; + + RB_FOREACH(e, flexran_agent_map, &timer_instance.flexran_agent_head) { + RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); + timer_remove(e->timer_id); + flexran_agent_destroy_flexran_message(e->timer_args->msg); + free(e); + } + + return 0; + +} + +void flexran_agent_sleep_until(struct timespec *ts, int delay) { + ts->tv_nsec += delay; + if(ts->tv_nsec >= 1000*1000*1000){ + ts->tv_nsec -= 1000*1000*1000; + ts->tv_sec++; + } + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts, NULL); +} + + +err_code_t flexran_agent_stop_timer(long timer_id){ + + struct flexran_agent_timer_element_s *e=NULL; + struct flexran_agent_timer_element_s search; + memset(&search, 0, sizeof(struct flexran_agent_timer_element_s)); + search.timer_id = timer_id; + + e = RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search); + + if (e != NULL ) { + e->state = FLEXRAN_AGENT_TIMER_STATE_STOPPED; + } + + timer_remove(timer_id); + + return 0; +} + +struct flexran_agent_timer_element_s * get_timer_entry(long timer_id) { + + struct flexran_agent_timer_element_s search; + memset(&search, 0, sizeof(struct flexran_agent_timer_element_s)); + search.timer_id = timer_id; + + return RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search); +} diff --git a/openair2/ENB_APP/flexran_agent_timer.h b/openair2/ENB_APP/flexran_agent_timer.h new file mode 100644 index 0000000000..86e0d07825 --- /dev/null +++ b/openair2/ENB_APP/flexran_agent_timer.h @@ -0,0 +1,133 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.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 flexran_agent_timer.h + * \brief FlexRAN Timer header + * \author shahab SHARIAT BAGHERI + * \date 2017 + * \version 0.1 + */ + +#include +#include + +#include "flexran_agent_common.h" +#include "flexran_agent_common_internal.h" +#include "flexran_agent_extern.h" +#include "flexran_agent_defs.h" + + +# include "tree.h" +# include "intertask_interface.h" +# include "timer.h" + + + +/******************* + * timer primitves + *******************/ + +#define TIMER_NULL -1 +#define TIMER_TYPE_INVALIDE -2 +#define TIMER_SETUP_FAILED -3 +#define TIMER_REMOVED_FAILED -4 +#define TIMER_ELEMENT_NOT_FOUND -5 + + +/* Type of the callback executed when the timer expired */ +typedef Protocol__FlexranMessage *(*flexran_agent_timer_callback_t)(void*); + + +typedef struct flexran_agent_timer_args_s{ + mid_t mod_id; + Protocol__FlexranMessage *msg; +} flexran_agent_timer_args_t; + + +typedef struct flexran_agent_timer_element_s{ + RB_ENTRY(flexran_agent_timer_element_s) entry; + + agent_id_t agent_id; + instance_t instance; + + flexran_agent_timer_type_t type; + flexran_agent_timer_state_t state; + + uint32_t interval_sec; + uint32_t interval_usec; + + long timer_id; /* Timer id returned by the timer API*/ + xid_t xid; /*The id of the task as received by the controller + message*/ + + flexran_agent_timer_callback_t cb; + flexran_agent_timer_args_t *timer_args; + +} flexran_agent_timer_element_t; + +typedef struct flexran_agent_timer_instance_s{ + RB_HEAD(flexran_agent_map, flexran_agent_timer_element_s) flexran_agent_head; +}flexran_agent_timer_instance_t; + + +err_code_t flexran_agent_init_timer(void); + +/* Create a timer for some agent related event with id xid. Will store the id + of the generated timer in timer_id */ +err_code_t flexran_agent_create_timer(uint32_t interval_sec, + uint32_t interval_usec, + agent_id_t agent_id, + instance_t instance, + uint32_t timer_type, + xid_t xid, + flexran_agent_timer_callback_t cb, + void* timer_args, + long *timer_id); + +/* Destroy all existing timers */ +err_code_t flexran_agent_destroy_timers(void); + +/* Destroy the timer with the given timer_id */ +err_code_t flexran_agent_destroy_timer(long timer_id); + +/* Destroy the timer for task with id xid */ +err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid); + +/* Stop a timer */ +err_code_t flexran_agent_stop_timer(long timer_id); + +/* Restart the given timer */ +err_code_t flexran_agent_restart_timer(long *timer_id); + +/* Find the timer with the given timer_id */ +struct flexran_agent_timer_element_s * get_timer_entry(long timer_id); + +/* Obtain the protocol message stored in the given expired timer */ +Protocol__FlexranMessage * flexran_agent_process_timeout(long timer_id, void* timer_args); + +/* Comparator function comparing two timers. Decides the ordering of the timers */ +int flexran_agent_compare_timer(struct flexran_agent_timer_element_s *a, struct flexran_agent_timer_element_s *b); + +/*Specify a delay in nanoseconds to timespec and sleep until then*/ +void flexran_agent_sleep_until(struct timespec *ts, int delay); + +/* RB_PROTOTYPE is for .h files */ +RB_PROTOTYPE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer); diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 12dbeecf16..ecbe0b68ba 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -332,15 +332,17 @@ rrc_mac_config_req( if (eNB_flagP == 0) { if (measObj!= NULL) { if (measObj[0]!= NULL) { - UE_mac_inst[Mod_idP].n_adj_cells = measObj[0]->measObject.choice.measObjectEUTRA.cellsToAddModList->list.count; - LOG_I(MAC,"Number of adjacent cells %d\n",UE_mac_inst[Mod_idP].n_adj_cells); + if (measObj[0]->measObject.choice.measObjectEUTRA.cellsToAddModList != NULL) { + UE_mac_inst[Mod_idP].n_adj_cells = measObj[0]->measObject.choice.measObjectEUTRA.cellsToAddModList->list.count; + LOG_D(MAC,"Number of adjacent cells %d\n",UE_mac_inst[Mod_idP].n_adj_cells); - for (i=0; imeasObject.choice.measObjectEUTRA.cellsToAddModList->list.array[i]->physCellId; - LOG_I(MAC,"Cell %d : Nid_cell %d\n",i,UE_mac_inst[Mod_idP].adj_cell_id[i]); - } + for (i=0; imeasObject.choice.measObjectEUTRA.cellsToAddModList->list.array[i]->physCellId; + LOG_D(MAC,"Cell %d : Nid_cell %d\n",i,UE_mac_inst[Mod_idP].adj_cell_id[i]); + } - mac_xface->phy_config_meas_ue(Mod_idP,0,eNB_index,UE_mac_inst[Mod_idP].n_adj_cells,UE_mac_inst[Mod_idP].adj_cell_id); + mac_xface->phy_config_meas_ue(Mod_idP,0,eNB_index,UE_mac_inst[Mod_idP].n_adj_cells,UE_mac_inst[Mod_idP].adj_cell_id); + } } /* diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 6509471124..2bea6e1f1f 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -158,8 +158,8 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, //mac_remove_ue(module_idP, i, frameP, subframeP); //Inform the controller about the UE deactivation. Should be moved to RRC agent in the future #if defined(FLEXRAN_AGENT_SB_IF) - if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->flexran_agent_notify_ue_state_change(module_idP, + if (rrc_agent_registered[module_idP]) { + agent_rrc_xface[module_idP]->flexran_agent_notify_ue_state_change(module_idP, rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); } @@ -1084,10 +1084,11 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, #if defined(FLEXRAN_AGENT_SB_IF) #ifndef DISABLE_CONT_STATS + flexran_agent_send_update_stats(module_idP); //Send subframe trigger to the controller - if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->flexran_agent_send_update_mac_stats(module_idP); - } + // if (mac_agent_registered[module_idP]) { + // agent_mac_xface[module_idP]->flexran_agent_send_update_mac_stats(module_idP); + // } #endif #endif diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index a15e6bbdae..188eab9c95 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -426,8 +426,8 @@ schedule_ue_spec( int N_RBG[MAX_NUM_CCs]; unsigned char aggregation; mac_rlc_status_resp_t rlc_status; - unsigned char header_len_dcch=0, header_len_dcch_tmp=0; - unsigned char header_len_dtch=0, header_len_dtch_tmp=0, header_len_dtch_last=0; + unsigned char header_len_dcch=0, header_len_dcch_tmp=0; + unsigned char header_len_dtch=0, header_len_dtch_tmp=0, header_len_dtch_last=0; unsigned char ta_len=0; unsigned char sdu_lcids[NB_RB_MAX],lcid,offset,num_sdus=0; uint16_t nb_rb,nb_rb_temp,total_nb_available_rb[MAX_NUM_CCs],nb_available_rb; @@ -472,7 +472,7 @@ schedule_ue_spec( total_nb_available_rb[CC_id] = frame_parms[CC_id]->N_RB_DL; for (i=0;iN_RB_DL;i++) if (eNB->common_channels[CC_id].vrb_map[i]!=0) - total_nb_available_rb[CC_id]--; + total_nb_available_rb[CC_id]--; N_RBG[CC_id] = frame_parms[CC_id]->N_RBG; @@ -574,7 +574,7 @@ schedule_ue_spec( round = ue_sched_ctl->round[CC_id]; UE_list->eNB_UE_stats[CC_id][UE_id].crnti= rnti; UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status=mac_eNB_get_rrc_status(module_idP,rnti); - UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid; + UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid; UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round; sdu_length_total=0; @@ -599,7 +599,7 @@ schedule_ue_spec( LOG_D(MAC,"[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n", module_idP, frameP, UE_id,CC_id,rnti,harq_pid, round,nb_available_rb, eNB_UE_stats->DL_cqi[0], eNB_UE_stats->dlsch_mcs1, - UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); + UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); // Note this code is for a specific DCI format @@ -743,8 +743,8 @@ schedule_ue_spec( } break; - /* - // this code is disabled for now - needs to be done properly + /* + // this code is disabled for now - needs to be done properly case 4: // if (nb_rb>10) { ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->ndi1 = 0; @@ -782,7 +782,7 @@ schedule_ue_spec( ((DCI1E_5MHz_2A_M10PRB_TDD_t*)DLSCH_dci)->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; ((DCI1E_5MHz_2A_M10PRB_TDD_t*)DLSCH_dci)->dl_power_off = 1;//dl_pow_off[UE_id]; break; - */ + */ } add_ue_dlsch_info(module_idP, @@ -819,8 +819,9 @@ schedule_ue_spec( rlc_status = mac_rlc_status_ind( module_idP, rnti, - module_idP, + module_idP, frameP, + subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, @@ -832,14 +833,15 @@ schedule_ue_spec( LOG_D(MAC,"[eNB %d] Frame %d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n", module_idP,frameP,CC_id,TBS-header_len_dcch); sdu_lengths[0] = mac_rlc_data_req( - module_idP, - rnti, - module_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - DCCH, - (char *)&dlsch_buffer[0]); + module_idP, + rnti, + module_idP, + frameP, + ENB_FLAG_YES, + MBMS_FLAG_NO, + DCCH, + TBS, //not used + (char *)&dlsch_buffer[0]); T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(DCCH), T_INT(sdu_lengths[0])); @@ -864,20 +866,21 @@ schedule_ue_spec( sdu_length_total = 0; } } - + // check for DCCH1 and update header information (assume 2 byte sub-header) if (TBS-ta_len-header_len_dcch-sdu_length_total > 0 ) { rlc_status = mac_rlc_status_ind( module_idP, rnti, - module_idP, + module_idP, frameP, + subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH+1, (TBS-ta_len-header_len_dcch-sdu_length_total)); // transport block set size less allocations for timing advance and // DCCH SDU - sdu_lengths[num_sdus] = 0; + sdu_lengths[num_sdus] = 0; if (rlc_status.bytes_in_buffer > 0) { LOG_I(MAC,"[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", @@ -885,11 +888,12 @@ schedule_ue_spec( sdu_lengths[num_sdus] += mac_rlc_data_req( module_idP, rnti, - module_idP, + module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH+1, + TBS, //not used (char *)&dlsch_buffer[sdu_length_total]); T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), @@ -900,7 +904,7 @@ schedule_ue_spec( header_len_dcch += 2; UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH1]+=1; UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1]+=sdu_lengths[num_sdus]; - num_sdus++; + num_sdus++; #ifdef DEBUG_eNB_SCHEDULER LOG_T(MAC,"[eNB %d][DCCH1] CC_id %d Got %d bytes :",module_idP,CC_id,sdu_lengths[num_sdus]); @@ -911,85 +915,87 @@ schedule_ue_spec( LOG_T(MAC,"\n"); #endif - } + } } - // assume the max dtch header size, and adjust it later - header_len_dtch=0; - header_len_dtch_last=0; // the header length of the last mac sdu - // lcid has to be sorted before the actual allocation (similar struct as ue_list). - for (lcid=NB_RB_MAX-1; lcid>=DTCH ; lcid--){ - // TBD: check if the lcid is active + // assume the max dtch header size, and adjust it later + header_len_dtch=0; + header_len_dtch_last=0; // the header length of the last mac sdu + // lcid has to be sorted before the actual allocation (similar struct as ue_list). + for (lcid=NB_RB_MAX-1; lcid>=DTCH ; lcid--){ + // TBD: check if the lcid is active + + header_len_dtch+=3; + header_len_dtch_last=3; + LOG_D(MAC,"[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n", + module_idP,frameP,lcid,TBS, + TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); + + if (TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch > 0 ) { // NN: > 2 ? + rlc_status = mac_rlc_status_ind(module_idP, + rnti, + module_idP, + frameP, + subframeP, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); + - header_len_dtch+=3; - header_len_dtch_last=3; - LOG_D(MAC,"[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n", - module_idP,frameP,lcid,TBS, - TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); - - if (TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch > 0 ) { // NN: > 2 ? - rlc_status = mac_rlc_status_ind(module_idP, - rnti, - module_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); - - - if (rlc_status.bytes_in_buffer > 0) { - - LOG_D(MAC,"[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n", - module_idP,frameP,TBS-header_len_dcch-sdu_length_total-header_len_dtch,lcid, header_len_dtch); - sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, - rnti, - module_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - (char*)&dlsch_buffer[sdu_length_total]); - T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), + if (rlc_status.bytes_in_buffer > 0) { + + LOG_D(MAC,"[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n", + module_idP,frameP,TBS-header_len_dcch-sdu_length_total-header_len_dtch,lcid, header_len_dtch); + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, + rnti, + module_idP, + frameP, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + TBS, //not used + (char*)&dlsch_buffer[sdu_length_total]); + T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(lcid), T_INT(sdu_lengths[num_sdus])); - LOG_D(MAC,"[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n",module_idP,sdu_lengths[num_sdus],lcid); - sdu_lcids[num_sdus] = lcid; - sdu_length_total += sdu_lengths[num_sdus]; - UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid]+=1; - UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[lcid]+=sdu_lengths[num_sdus]; - if (sdu_lengths[num_sdus] < 128) { - header_len_dtch--; - header_len_dtch_last--; - } - num_sdus++; - } // no data for this LCID - else { - header_len_dtch-=3; - } - } // no TBS left - else { - header_len_dtch-=3; - break; - } - } - if (header_len_dtch == 0 ) - header_len_dtch_last= 0; - // there is at least one SDU - // if (num_sdus > 0 ){ - if ((sdu_length_total + header_len_dcch + header_len_dtch )> 0) { - - // Now compute number of required RBs for total sdu length - // Assume RAH format 2 - // adjust header lengths - header_len_dcch_tmp = header_len_dcch; - header_len_dtch_tmp = header_len_dtch; - if (header_len_dtch==0) { - header_len_dcch = (header_len_dcch >0) ? 1 : 0;//header_len_dcch; // remove length field - } else { - header_len_dtch_last-=1; // now use it to find how many bytes has to be removed for the last MAC SDU - header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last :header_len_dtch; // remove length field for the last SDU - } + LOG_D(MAC,"[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n",module_idP,sdu_lengths[num_sdus],lcid); + sdu_lcids[num_sdus] = lcid; + sdu_length_total += sdu_lengths[num_sdus]; + UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid]+=1; + UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[lcid]+=sdu_lengths[num_sdus]; + if (sdu_lengths[num_sdus] < 128) { + header_len_dtch--; + header_len_dtch_last--; + } + num_sdus++; + } // no data for this LCID + else { + header_len_dtch-=3; + } + } // no TBS left + else { + header_len_dtch-=3; + break; + } + } + if (header_len_dtch == 0 ) + header_len_dtch_last= 0; + // there is at least one SDU + // if (num_sdus > 0 ){ + if ((sdu_length_total + header_len_dcch + header_len_dtch )> 0) { + + // Now compute number of required RBs for total sdu length + // Assume RAH format 2 + // adjust header lengths + header_len_dcch_tmp = header_len_dcch; + header_len_dtch_tmp = header_len_dtch; + if (header_len_dtch==0) { + header_len_dcch = (header_len_dcch >0) ? 1 : 0;//header_len_dcch; // remove length field + } else { + header_len_dtch_last-=1; // now use it to find how many bytes has to be removed for the last MAC SDU + header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last :header_len_dtch; // remove length field for the last SDU + } mcs = eNB_UE_stats->dlsch_mcs1; @@ -1103,7 +1109,7 @@ schedule_ue_spec( "[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n", module_idP,frameP, UE_id, CC_id, sdu_length_total,num_sdus,sdu_lengths[0],sdu_lcids[0],offset, ue_sched_ctl->ta_update,padding,post_padding,mcs,TBS,nb_rb,header_len_dcch,header_len_dtch); - } + } //#endif #ifdef DEBUG_eNB_SCHEDULER LOG_T(MAC,"[eNB %d] First 16 bytes of DLSCH : \n"); @@ -1164,44 +1170,44 @@ schedule_ue_spec( update_ul_dci(module_idP,CC_id,rnti,UE_list->UE_template[CC_id][UE_id].DAI); } - // do PUCCH power control + // do PUCCH power control // this is the normalized RX power - eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti); - normalized_rx_power = eNB_UE_stats->Po_PUCCH_dBm; - target_rx_power = mac_xface->get_target_pucch_rx_power(module_idP,CC_id) + 20; - + eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti); + normalized_rx_power = eNB_UE_stats->Po_PUCCH_dBm; + target_rx_power = mac_xface->get_target_pucch_rx_power(module_idP,CC_id) + 20; + // this assumes accumulated tpc - // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out - int32_t framex10psubframe = UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame*10+UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe; + // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out + int32_t framex10psubframe = UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame*10+UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe; if (((framex10psubframe+10)<=(frameP*10+subframeP)) || //normal case - ((framex10psubframe>(frameP*10+subframeP)) && (((10240-framex10psubframe+frameP*10+subframeP)>=10)))) //frame wrap-around - if (eNB_UE_stats->Po_PUCCH_update == 1) { - eNB_UE_stats->Po_PUCCH_update = 0; + ((framex10psubframe>(frameP*10+subframeP)) && (((10240-framex10psubframe+frameP*10+subframeP)>=10)))) //frame wrap-around + if (eNB_UE_stats->Po_PUCCH_update == 1) { + eNB_UE_stats->Po_PUCCH_update = 0; - UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame=frameP; - UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe=subframeP; + UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame=frameP; + UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe=subframeP; + + if (normalized_rx_power>(target_rx_power+1)) { + tpc = 0; //-1 + tpc_accumulated--; + } else if (normalized_rx_power<(target_rx_power-1)) { + tpc = 2; //+1 + tpc_accumulated++; + } else { + tpc = 1; //0 + } + /* + LOG_I(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", + module_idP,frameP, subframeP,harq_pid,tpc, + tpc_accumulated,normalized_rx_power,target_rx_power);*/ - if (normalized_rx_power>(target_rx_power+1)) { - tpc = 0; //-1 - tpc_accumulated--; - } else if (normalized_rx_power<(target_rx_power-1)) { - tpc = 2; //+1 - tpc_accumulated++; - } else { - tpc = 1; //0 - } - /* - LOG_I(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", - module_idP,frameP, subframeP,harq_pid,tpc, - tpc_accumulated,normalized_rx_power,target_rx_power);*/ - - } // Po_PUCCH has been updated - else { - tpc = 1; //0 - } // time to do TPC update - else { - tpc = 1; //0 - } + } // Po_PUCCH has been updated + else { + tpc = 1; //0 + } // time to do TPC update + else { + tpc = 1; //0 + } switch (mac_xface->get_transmission_mode(module_idP,CC_id,rnti)) { case 1: @@ -1324,7 +1330,7 @@ schedule_ue_spec( ((DCI2A_5MHz_2A_TDD_t*)DLSCH_dci)->ndi1 = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; ((DCI2A_5MHz_2A_TDD_t*)DLSCH_dci)->rv1 = 0; ((DCI2A_5MHz_2A_TDD_t*)DLSCH_dci)->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - ((DCI2A_5MHz_2A_TDD_t*)DLSCH_dci)->TPC = tpc; + ((DCI2A_5MHz_2A_TDD_t*)DLSCH_dci)->TPC = tpc; // deactivate TB2 ((DCI2A_5MHz_2A_TDD_t*)DLSCH_dci)->mcs2 = 0; @@ -1339,7 +1345,7 @@ schedule_ue_spec( ((DCI2A_10MHz_2A_TDD_t*)DLSCH_dci)->ndi1 = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; ((DCI2A_10MHz_2A_TDD_t*)DLSCH_dci)->rv1 = 0; ((DCI2A_10MHz_2A_TDD_t*)DLSCH_dci)->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - ((DCI2A_10MHz_2A_TDD_t*)DLSCH_dci)->TPC = tpc; + ((DCI2A_10MHz_2A_TDD_t*)DLSCH_dci)->TPC = tpc; // deactivate TB2 ((DCI2A_10MHz_2A_TDD_t*)DLSCH_dci)->mcs2 = 0; @@ -1352,7 +1358,7 @@ schedule_ue_spec( ((DCI2A_20MHz_2A_TDD_t*)DLSCH_dci)->ndi1 = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; ((DCI2A_20MHz_2A_TDD_t*)DLSCH_dci)->rv1 = 0; ((DCI2A_20MHz_2A_TDD_t*)DLSCH_dci)->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - ((DCI2A_20MHz_2A_TDD_t*)DLSCH_dci)->TPC = tpc; + ((DCI2A_20MHz_2A_TDD_t*)DLSCH_dci)->TPC = tpc; // deactivate TB2 ((DCI2A_20MHz_2A_TDD_t*)DLSCH_dci)->mcs2 = 0; @@ -1365,7 +1371,7 @@ schedule_ue_spec( ((DCI2A_5MHz_2A_TDD_t*)DLSCH_dci)->ndi1 = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; ((DCI2A_5MHz_2A_TDD_t*)DLSCH_dci)->rv1 = 0; ((DCI2A_5MHz_2A_TDD_t*)DLSCH_dci)->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - ((DCI2A_5MHz_2A_TDD_t*)DLSCH_dci)->TPC = tpc; + ((DCI2A_5MHz_2A_TDD_t*)DLSCH_dci)->TPC = tpc; // deactivate TB2 ((DCI2A_5MHz_2A_TDD_t*)DLSCH_dci)->mcs2 = 0; @@ -1379,7 +1385,7 @@ schedule_ue_spec( ((DCI2A_1_5MHz_2A_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; ((DCI2A_1_5MHz_2A_FDD_t*)DLSCH_dci)->ndi1 = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; ((DCI2A_1_5MHz_2A_FDD_t*)DLSCH_dci)->rv1 = 0; - ((DCI2A_1_5MHz_2A_FDD_t*)DLSCH_dci)->TPC = tpc; + ((DCI2A_1_5MHz_2A_FDD_t*)DLSCH_dci)->TPC = tpc; // deactivate TB2 ((DCI2A_1_5MHz_2A_FDD_t*)DLSCH_dci)->mcs2 = 0; @@ -1391,7 +1397,7 @@ schedule_ue_spec( ((DCI2A_5MHz_2A_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; ((DCI2A_5MHz_2A_FDD_t*)DLSCH_dci)->ndi1 = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; ((DCI2A_5MHz_2A_FDD_t*)DLSCH_dci)->rv1 = 0; - ((DCI2A_5MHz_2A_FDD_t*)DLSCH_dci)->TPC = tpc; + ((DCI2A_5MHz_2A_FDD_t*)DLSCH_dci)->TPC = tpc; // deactivate TB2 ((DCI2A_5MHz_2A_FDD_t*)DLSCH_dci)->mcs2 = 0; @@ -1403,7 +1409,7 @@ schedule_ue_spec( ((DCI2A_10MHz_2A_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; ((DCI2A_10MHz_2A_FDD_t*)DLSCH_dci)->ndi1 = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; ((DCI2A_10MHz_2A_FDD_t*)DLSCH_dci)->rv1 = 0; - ((DCI2A_10MHz_2A_FDD_t*)DLSCH_dci)->TPC = tpc; + ((DCI2A_10MHz_2A_FDD_t*)DLSCH_dci)->TPC = tpc; // deactivate TB2 ((DCI2A_10MHz_2A_FDD_t*)DLSCH_dci)->mcs2 = 0; ((DCI2A_10MHz_2A_FDD_t*)DLSCH_dci)->rv2 = 1; @@ -1414,7 +1420,7 @@ schedule_ue_spec( ((DCI2A_20MHz_2A_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; ((DCI2A_20MHz_2A_FDD_t*)DLSCH_dci)->ndi1 = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; ((DCI2A_20MHz_2A_FDD_t*)DLSCH_dci)->rv1 = 0; - ((DCI2A_20MHz_2A_FDD_t*)DLSCH_dci)->TPC = tpc; + ((DCI2A_20MHz_2A_FDD_t*)DLSCH_dci)->TPC = tpc; // deactivate TB2 ((DCI2A_20MHz_2A_FDD_t*)DLSCH_dci)->mcs2 = 0; @@ -1426,7 +1432,7 @@ schedule_ue_spec( ((DCI2A_5MHz_2A_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; ((DCI2A_5MHz_2A_FDD_t*)DLSCH_dci)->ndi1 = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; ((DCI2A_5MHz_2A_FDD_t*)DLSCH_dci)->rv1 = 0; - ((DCI2A_5MHz_2A_FDD_t*)DLSCH_dci)->TPC = tpc; + ((DCI2A_5MHz_2A_FDD_t*)DLSCH_dci)->TPC = tpc; // deactivate TB2 ((DCI2A_5MHz_2A_FDD_t*)DLSCH_dci)->mcs2 = 0; @@ -1437,8 +1443,8 @@ schedule_ue_spec( break; - /* - // disabled for now as this needs to be done properly + /* + // disabled for now as this needs to be done properly case 4: if (frame_parms[CC_id]->frame_type == TDD) { switch (frame_parms[CC_id]->N_RB_DL) { @@ -1460,8 +1466,8 @@ schedule_ue_spec( case 25: ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->tpmi = 0; - ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->mcs1 = mcs; - ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->mcs1 = mcs; + ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->ndi1 = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->rv1 = 0; ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; @@ -1508,8 +1514,8 @@ schedule_ue_spec( ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->ndi1 = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->rv1 = 0; - ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->TPC = tpc; + ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->TPC = tpc; // deactivate TB2 @@ -1530,7 +1536,7 @@ schedule_ue_spec( // deactivate TB2 ((DCI2_1_5MHz_2A_FDD_t*)DLSCH_dci)->mcs2 = 0; ((DCI2_1_5MHz_2A_FDD_t*)DLSCH_dci)->rv2 = 1; - break; + break; case 25: ((DCI2_5MHz_2A_FDD_t*)DLSCH_dci)->tpmi = 0; @@ -1598,7 +1604,7 @@ schedule_ue_spec( ((DCI1E_5MHz_2A_M10PRB_TDD_t*)DLSCH_dci)->ndi = 1; ((DCI1E_5MHz_2A_M10PRB_TDD_t*)DLSCH_dci)->rv = round&3; ((DCI1E_5MHz_2A_M10PRB_TDD_t*)DLSCH_dci)->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - ((DCI1E_5MHz_2A_M10PRB_TDD_t*)DLSCH_dci)->TPC = tpc; + ((DCI1E_5MHz_2A_M10PRB_TDD_t*)DLSCH_dci)->TPC = tpc; if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { ue_sched_ctl->dl_pow_off[CC_id] = 1; @@ -1616,10 +1622,10 @@ schedule_ue_spec( ((DCI1E_5MHz_2A_M10PRB_TDD_t*)DLSCH_dci)->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; ((DCI1E_5MHz_2A_M10PRB_TDD_t*)DLSCH_dci)->dl_power_off = 1; ((DCI1E_5MHz_2A_M10PRB_TDD_t*)DLSCH_dci)->tpmi = 5; - ((DCI1E_5MHz_2A_M10PRB_TDD_t*)DLSCH_dci)->TPC = tpc; + ((DCI1E_5MHz_2A_M10PRB_TDD_t*)DLSCH_dci)->TPC = tpc; break; - */ + */ } // Toggle NDI for next time @@ -1648,11 +1654,11 @@ schedule_ue_spec( //------------------------------------------------------------------------------ void fill_DLSCH_dci( - module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP, - int* mbsfn_flagP - ) + module_id_t module_idP, + frame_t frameP, + sub_frame_t subframeP, + int* mbsfn_flagP + ) //------------------------------------------------------------------------------ { @@ -1687,7 +1693,7 @@ fill_DLSCH_dci( continue; DCI_pdu = &eNB->common_channels[CC_id].DCI_pdu; - + // UE specific DCIs for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { @@ -1698,8 +1704,8 @@ fill_DLSCH_dci( // clear scheduling flag eNB_dlsch_info[module_idP][CC_id][UE_id].status = S_DL_WAITING; rnti = UE_RNTI(module_idP,UE_id); - // mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,0); - harq_pid = UE_list->UE_sched_ctrl[UE_id].harq_pid[CC_id]; + // mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,0); + harq_pid = UE_list->UE_sched_ctrl[UE_id].harq_pid[CC_id]; nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; DLSCH_dci = (void *)UE_list->UE_template[CC_id][UE_id].DLSCH_DCI[harq_pid]; @@ -1906,7 +1912,7 @@ fill_DLSCH_dci( break; - /* + /* case 4: // DCI format 2_2A @@ -1949,7 +1955,7 @@ fill_DLSCH_dci( format1E_2A_M10PRB, 0); break; - */ + */ } } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_mch.c b/openair2/LAYER2/MAC/eNB_scheduler_mch.c index acf28c805f..2d3e96bec3 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_mch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_mch.c @@ -504,7 +504,7 @@ int schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_fra module_idP,CC_id,frameP,MTCH,TBS, TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); - rlc_status = mac_rlc_status_ind(module_idP,0,frameP,module_idP,ENB_FLAG_YES,MBMS_FLAG_YES,MTCH, + rlc_status = mac_rlc_status_ind(module_idP,0,frameP,subframeP,module_idP,ENB_FLAG_YES,MBMS_FLAG_YES,MTCH, TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); LOG_D(MAC,"e-MBMS log channel %u frameP %d, subframeP %d, rlc_status.bytes_in_buffer is %d\n", MTCH,frameP,subframeP, rlc_status.bytes_in_buffer); @@ -521,6 +521,7 @@ int schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_fra ENB_FLAG_YES, MBMS_FLAG_YES, MTCH, + 0, //not used (char*)&mch_buffer[sdu_length_total]); //sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,frameP, MBMS_FLAG_NO, MTCH+(MAX_NUM_RB*(NUMBER_OF_UE_MAX+1)), (char*)&mch_buffer[sdu_length_total]); LOG_I(MAC,"[eNB %d][MBMS USER-PLANE] CC_id %d Got %d bytes for MTCH %d\n",module_idP,CC_id,sdu_lengths[num_sdus],MTCH); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 56ede260e8..01edbb87cf 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -180,6 +180,10 @@ uint8_t find_active_UEs(module_id_t module_idP,int CC_id){ } */ +int UE_BSR (uint8_t mod_id, uint8_t ue_id, uint8_t lcid) { + + return eNB_mac_inst[mod_id].UE_list.UE_template[UE_PCCID(mod_id,ue_id)][ue_id].bsr_info[lcid]; +} // get aggregation (L) form phy for a give UE unsigned char get_aggregation (uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt) @@ -304,6 +308,12 @@ printf("MAC: cannot add new UE for rnti %x\n", rntiP); return(-1); } +int CC_id_rnti_downlink (uint8_t mod_id, int CC_index, uint16_t ue_rnti) { + + return eNB_mac_inst[mod_id].UE_list.ordered_CCids[CC_index][ue_rnti]; +} + + //------------------------------------------------------------------------------ int rrc_mac_remove_ue(module_id_t mod_idP,rnti_t rntiP) //------------------------------------------------------------------------------ diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 585d9c2c1c..6d0044b346 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -885,7 +885,7 @@ abort(); rb_table_index=UE_template->pre_allocated_rb_table_index_ul; } else { mcs=10;//cmin (10, openair_daq_vars.target_ue_ul_mcs); - rb_table_index=13; // for PHR + rb_table_index=5; // for PHR } UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2=mcs; diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c index 9c8b23df07..38f39e50e1 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c @@ -174,6 +174,7 @@ void flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, rnti, mod_id, frame, + subframe, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, @@ -193,6 +194,7 @@ void flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, rnti, mod_id, frame, + subframe, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, @@ -209,6 +211,7 @@ void flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, + rlc_size, //not used (char *)&dlsch_buffer[sdu_length_total]); LOG_D(MAC,"[eNB %d][LCID %d] CC_id %d Got %d bytes from RLC\n",mod_id, lcid, CC_id, sdu_lengths[j]); diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index 00027f04ce..81c18a26c0 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -50,7 +50,7 @@ #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" #include "ENB_APP/flexran_agent_defs.h" - +#include "flexran_agent_ran_api.h" #include "pdcp.h" #include "header.pb-c.h" @@ -160,7 +160,7 @@ void _store_dlsch_buffer (module_id_t Mod_id, for(i=0; i< MAX_NUM_LCID; i++) { // loop over all the logical channels - rlc_status = mac_rlc_status_ind(Mod_id,rnti, Mod_id,frameP,ENB_FLAG_YES,MBMS_FLAG_NO,i,0 ); + rlc_status = mac_rlc_status_ind(Mod_id,rnti, Mod_id,frameP,subframeP,ENB_FLAG_YES,MBMS_FLAG_NO,i,0 ); UE_template->dl_buffer_info[i] = rlc_status.bytes_in_buffer; //storing the dlsch buffer for each logical channel UE_template->dl_pdus_in_buffer[i] = rlc_status.pdus_in_buffer; UE_template->dl_buffer_head_sdu_creation_time[i] = rlc_status.head_sdu_creation_time ; @@ -1241,6 +1241,7 @@ flexran_schedule_ue_spec_common(mid_t mod_id, rnti, mod_id, frame, + subframe, ENB_FLAG_YES, MBMS_FLAG_NO, j, diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c index 7dec8d0c56..bff461acc7 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c @@ -30,7 +30,7 @@ */ #include "flexran_agent_common_internal.h" - +#include "flexran_agent_ran_api.h" #include "flexran_agent_scheduler_dlsch_ue_remote.h" #include "LAYER2/MAC/defs.h" diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 6e73e353f0..74e0a43d7d 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -109,7 +109,7 @@ void store_dlsch_buffer (module_id_t Mod_id, for(i=0; i< MAX_NUM_LCID; i++) { // loop over all the logical channels - rlc_status = mac_rlc_status_ind(Mod_id,rnti, Mod_id,frameP,ENB_FLAG_YES,MBMS_FLAG_NO,i,0 ); + rlc_status = mac_rlc_status_ind(Mod_id,rnti, Mod_id,frameP,subframeP,ENB_FLAG_YES,MBMS_FLAG_NO,i,0 ); UE_template->dl_buffer_info[i] = rlc_status.bytes_in_buffer; //storing the dlsch buffer for each logical channel UE_template->dl_pdus_in_buffer[i] = rlc_status.pdus_in_buffer; UE_template->dl_buffer_head_sdu_creation_time[i] = rlc_status.head_sdu_creation_time ; diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 3343e8821e..16f2d186ea 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -454,6 +454,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP,u @param t_crnti Pointer to PHY variable containing the T_CRNTI @param preamble_index Preamble Index used by PHY to transmit the PRACH. This should match the received RAR to trigger the rest of random-access procedure +@param selected_rar_buffer the output buffer for storing the selected RAR header and RAR payload @returns timing advance or 0xffff if preamble doesn't match */ uint16_t @@ -464,7 +465,8 @@ ue_process_rar( const rnti_t ra_rnti, uint8_t * const dlsch_buffer, rnti_t * const t_crnti, - const uint8_t preamble_index + const uint8_t preamble_index, + uint8_t* selected_rar_buffer ); @@ -537,6 +539,7 @@ void sort_ue_ul (module_id_t module_idP,int frameP, sub_frame_t subframeP); void assign_max_mcs_min_rb(module_id_t module_idP,int frameP, sub_frame_t subframeP,uint16_t *first_rb); void adjust_bsr_info(int buffer_occupancy, uint16_t TBS, UE_TEMPLATE *UE_template); int phy_stats_exist(module_id_t Mod_id, int rnti); +void sort_UEs (module_id_t Mod_idP, int frameP, sub_frame_t subframeP); /*! \fn UE_L2_state_t ue_scheduler(const module_id_t module_idP,const frame_t frameP, const sub_frame_t subframe, const lte_subframe_t direction,const uint8_t eNB_index) \brief UE scheduler where all the ue background tasks are done. This function performs the following: 1) Trigger PDCP every 5ms 2) Call RRC for link status return to PHY3) Perform SR/BSR procedures for scheduling feedback 4) Perform PHR procedures. diff --git a/openair2/LAYER2/MAC/ra_procedures.c b/openair2/LAYER2/MAC/ra_procedures.c index 8264699f43..d2d52383b0 100644 --- a/openair2/LAYER2/MAC/ra_procedures.c +++ b/openair2/LAYER2/MAC/ra_procedures.c @@ -394,7 +394,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP, } else if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] > 0) { // This is for triggering a transmission on DCCH using PRACH (during handover, or sending SR for example) dcch_header_len = 2 + 2; /// SHORT Subheader + C-RNTI control element - rlc_status = mac_rlc_status_ind(module_idP,UE_mac_inst[module_idP].crnti, eNB_indexP,frameP,ENB_FLAG_NO,MBMS_FLAG_NO, + rlc_status = mac_rlc_status_ind(module_idP,UE_mac_inst[module_idP].crnti, eNB_indexP,frameP,subframeP,ENB_FLAG_NO,MBMS_FLAG_NO, DCCH, 6); @@ -409,6 +409,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP, sdu_lengths[0] = mac_rlc_data_req(module_idP, UE_mac_inst[module_idP].crnti, eNB_indexP, frameP,ENB_FLAG_NO, MBMS_FLAG_NO, DCCH, + 6, //not used (char *)&ulsch_buff[0]); LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH\n",module_idP,sdu_lengths[0]); diff --git a/openair2/LAYER2/MAC/rar_tools.c b/openair2/LAYER2/MAC/rar_tools.c index 2de22c067a..51900d8f3a 100644 --- a/openair2/LAYER2/MAC/rar_tools.c +++ b/openair2/LAYER2/MAC/rar_tools.c @@ -136,15 +136,48 @@ ue_process_rar( const rnti_t ra_rnti, uint8_t* const dlsch_buffer, rnti_t* const t_crnti, - const uint8_t preamble_index + const uint8_t preamble_index, + uint8_t* selected_rar_buffer // output argument for storing the selected RAR header and RAR payload ) //------------------------------------------------------------------------------ { + uint16_t ret = 0; // return value RA_HEADER_RAPID *rarh = (RA_HEADER_RAPID *)dlsch_buffer; // RAR_PDU *rar = (RAR_PDU *)(dlsch_buffer+1); uint8_t *rar = (uint8_t *)(dlsch_buffer+1); + // get the last RAR payload for working with CMW500 + uint8_t n_rarpy = 0; // number of RAR payloads + uint8_t n_rarh = 0; // number of MAC RAR subheaders + uint8_t best_rx_rapid = -1; // the closest RAPID receive from all RARs + while (1) { + n_rarh++; + if (rarh->T == 1) { + n_rarpy++; + LOG_D(MAC, "RAPID %d\n", rarh->RAPID); + } + + if (rarh->RAPID == preamble_index) { + LOG_D(PHY, "Found RAR with the intended RAPID %d\n", rarh->RAPID); + rar = (uint8_t *)(dlsch_buffer+n_rarh + (n_rarpy-1)*6); + break; + } + + if (abs((int)rarh->RAPID - (int)preamble_index) < abs((int)best_rx_rapid - (int)preamble_index)) { + best_rx_rapid = rarh->RAPID; + rar = (uint8_t *)(dlsch_buffer+n_rarh + (n_rarpy-1)*6); + } + + if (rarh->E == 0) { + LOG_I(PHY, "No RAR found with the intended RAPID. The closest RAPID in all RARs is %d\n", best_rx_rapid); + break; + } else { + rarh++; + } + }; + LOG_D(MAC, "number of RAR subheader %d; number of RAR pyloads %d\n", n_rarh, n_rarpy); + if (CC_id>0) { LOG_W(MAC,"Should not have received RAR on secondary CCs! \n"); return(0xffff); @@ -172,7 +205,7 @@ ue_process_rar( if (opt_enabled) { LOG_D(OPT,"[UE %d][RAPROC] CC_id %d RAR Frame %d trace pdu for ra-RNTI %x\n", module_idP, CC_id, frameP, ra_rnti); - trace_pdu(1, (uint8_t*)rarh, 7, module_idP, 2, ra_rnti, + trace_pdu(1, (uint8_t*)dlsch_buffer, n_rarh + n_rarpy*6, module_idP, 2, ra_rnti, UE_mac_inst[module_idP].rxFrame, UE_mac_inst[module_idP].rxSubframe, 0, 0); } @@ -180,9 +213,16 @@ ue_process_rar( *t_crnti = (uint16_t)rar[5]+(rar[4]<<8);//rar->t_crnti; UE_mac_inst[module_idP].crnti = *t_crnti;//rar->t_crnti; //return(rar->Timing_Advance_Command); - return((((uint16_t)(rar[0]&0x7f))<<4) + (rar[1]>>4)); + ret = ((((uint16_t)(rar[0]&0x7f))<<4) + (rar[1]>>4)); } else { UE_mac_inst[module_idP].crnti=0; - return(0xffff); + ret = (0xffff); } + + // move the selected RAR to the front of the RA_PDSCH buffer + memcpy(selected_rar_buffer+0, (uint8_t*)rarh, 1); + memcpy(selected_rar_buffer+1, (uint8_t*)rar , 6); + + return ret; + } diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index c27c0d524e..f9488ce543 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -353,7 +353,7 @@ ue_send_sdu( if (opt_enabled) { trace_pdu(1, sdu, sdu_len, module_idP, 3, UE_mac_inst[module_idP].crnti, - UE_mac_inst[module_idP].rxFrame, UE_mac_inst[module_idP].rxSubframe, 0, 0); + frameP, subframeP, 0, 0); LOG_D(OPT,"[UE %d][DLSCH] Frame %d trace pdu for rnti %x with size %d\n", module_idP, frameP, UE_mac_inst[module_idP].crnti, sdu_len); } @@ -1265,13 +1265,13 @@ unsigned char generate_ulsch_header(uint8_t *mac_header, void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subframe, uint8_t eNB_index,uint8_t *ulsch_buffer,uint16_t buflen, uint8_t *access_mode) { - mac_rlc_status_resp_t rlc_status; uint8_t total_rlc_pdu_header_len=0, rlc_pdu_header_len_last=0 ; uint16_t buflen_remain = 0; uint8_t bsr_len=0,bsr_ce_len=0,bsr_header_len=0; uint8_t phr_header_len=0, phr_ce_len=0,phr_len=0; uint8_t lcid=0,lcid_rlc_pdu_count=0; boolean_t is_lcid_processed = FALSE; + boolean_t is_all_lcid_processed = FALSE; uint16_t sdu_lengths[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t sdu_lcids[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t payload_offset=0,num_sdus=0; @@ -1291,6 +1291,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf int lcg_id_bsr_trunc = 0; int highest_priority = 16; int num_lcg_id_with_data = 0; + rlc_buffer_occupancy_t lcid_buffer_occupancy_old=0, lcid_buffer_occupancy_new=0; LOG_D(MAC,"[UE %d] MAC PROCESS UL TRANSPORT BLOCK at frame%d subframe %d TBS=%d\n", module_idP, frameP, subframe, buflen); @@ -1400,16 +1401,32 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf // check for UL bandwidth requests and add SR control element // Check for DCCH first -// TO DO: Unrool the loop to do it at least once to avoid the if num_sdu -for (lcid=DCCH; lcid < DTCH ; lcid++) { +// TO DO: Multiplex in the order defined by the logical channel prioritization +for (lcid=DCCH; (lcid < MAX_NUM_LCID) && (is_all_lcid_processed == FALSE) ; lcid++) { if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) { - is_lcid_processed = FALSE; lcid_rlc_pdu_count = 0; + is_lcid_processed = FALSE; + lcid_buffer_occupancy_old = mac_rlc_get_buffer_occupancy_ind(module_idP, + UE_mac_inst[module_idP].crnti, + eNB_index, + frameP, + subframe, + ENB_FLAG_NO, + lcid); + + lcid_buffer_occupancy_new = lcid_buffer_occupancy_old; + + AssertFatal (lcid_buffer_occupancy_new == UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid], "LCID=%d RLC has BO %d bytes but MAC has stored %d bytes\n", + lcid,lcid_buffer_occupancy_new,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]); + + AssertFatal (lcid_buffer_occupancy_new <= UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], "LCID=%d RLC has more BO %d bytes than BSR = %d bytes\n", + lcid,lcid_buffer_occupancy_new,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); + //Multiplex all available DCCH RLC PDUs considering to multiplex the last PDU each time for maximize the data //Adjust at the end of the loop - while ((!is_lcid_processed) && (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + MIN_MAC_HDR_RLC_SIZE <= buflen)) { + while ((!is_lcid_processed) && (lcid_buffer_occupancy_new) && (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + MIN_MAC_HDR_RLC_SIZE <= buflen)) { // Workaround for issue in OAI eNB or EPC which are not able to process SRB2 message multiplexed with SRB1 on the same MAC PDU if ((usim_test == 0) && (lcid == DCCH1) && (lcid_rlc_pdu_count == 0) && (num_sdus)) { @@ -1420,253 +1437,103 @@ for (lcid=DCCH; lcid < DTCH ; lcid++) { buflen_remain = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); - rlc_status = mac_rlc_status_ind(module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, // eNB_index - lcid, - buflen_remain); - // Workaround for BO issue in RLC AM ReTx : RLC BO can not be bigger than stored MAC BO - if (UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] < rlc_status.bytes_in_buffer) { - - LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Inconsistent BO! for LCID=%d MAC=%d RLC=%d RLC PDU nb=%d\n", - module_idP,frameP,subframe, - lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],rlc_status.bytes_in_buffer,lcid_rlc_pdu_count); - - // Skip multiplexing for the LCID - break; - } - - /* - AssertFatal ( UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] >= rlc_status.bytes_in_buffer, "Inconsistent BO! for LCID=%d MAC=%d RLC=%d RLC PDU nb=%d Frame %d Subrame %d\n", - lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],rlc_status.bytes_in_buffer,lcid_rlc_pdu_count,frameP,subframe); - */ - - if (rlc_status.bytes_in_buffer > 0) { + LOG_D(MAC, "[UE %d] Frame %d : UL-DXCH -> ULSCH, RLC %d has %d bytes to " + "send (Transport Block size %d BSR size=%d PHR=%d SDU Length Total %d , mac header len %d BSR byte before Tx=%d)\n", + module_idP,frameP, lcid,lcid_buffer_occupancy_new,buflen,bsr_len,phr_len,sdu_length_total,total_rlc_pdu_header_len,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); - LOG_D(MAC, "[UE %d] Frame %d : UL-DCCH -> ULSCH, RLC SRB%d has %d bytes to " - "send (Transport Block size %d BSR size=%d PHR=%d SDU Length Total %d , mac header len %d BSR byte before Tx=%d)\n", - module_idP,frameP, lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],buflen,bsr_len,phr_len,sdu_length_total,total_rlc_pdu_header_len,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, + UE_mac_inst[module_idP].crnti, + eNB_index, + frameP, + ENB_FLAG_NO, + MBMS_FLAG_NO, + lcid, + buflen_remain, + (char *)&ulsch_buff[sdu_length_total]); - sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, - lcid, - (char *)&ulsch_buff[sdu_length_total]); + AssertFatal (buflen_remain >= sdu_lengths[num_sdus], "LCID=%d RLC has segmented %d bytes but MAC has max=%d\n", + lcid,sdu_lengths[num_sdus],buflen_remain); - AssertFatal (UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] >= sdu_lengths[num_sdus], "LCID=%d RLC has segmented %d bytes but MAC has max=%d\n", - lcid,sdu_lengths[num_sdus],UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]); + if (sdu_lengths[num_sdus]) + { + sdu_length_total += sdu_lengths[num_sdus]; + sdu_lcids[num_sdus] = lcid; + LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU TX Got %d bytes for LcId%d\n",module_idP,sdu_lengths[num_sdus],lcid); + if (buflen == (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1)) { + //No more remaining TBS after this PDU + //exit the function + rlc_pdu_header_len_last = 1; + is_lcid_processed = TRUE; + is_all_lcid_processed = TRUE; + } + else { + rlc_pdu_header_len_last = (sdu_lengths[num_sdus] > 128 ) ? 3 : 2 ; + //Change to 1 byte if it does not fit in the TBS, ie last PDU + if (buflen <= (bsr_len + phr_len + total_rlc_pdu_header_len + rlc_pdu_header_len_last + sdu_length_total)) { + rlc_pdu_header_len_last = 1; + is_lcid_processed = TRUE; + is_all_lcid_processed = TRUE; + } + } - sdu_length_total += sdu_lengths[num_sdus]; - sdu_lcids[num_sdus] = lcid; - LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU TX Got %d bytes for SRB%d\n",module_idP,sdu_lengths[num_sdus],lcid); - //header_len +=2; - // update LCID remain buffer - UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] -= sdu_lengths[num_sdus]; - /* Update BSR : substract transmitted data */ - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] >= sdu_lengths[num_sdus]){ - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] -= sdu_lengths[num_sdus] ; - } - else { - LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data transmitted=%d for LCID%d\n", - module_idP,frameP,subframe, - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], - UE_mac_inst[module_idP].scheduling_info.LCGID[lcid], - sdu_lengths[num_sdus],lcid); - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] = 0; - } + //Update number of SDU + num_sdus ++; - //Update the number of LCGID with data as BSR shall reflect status after BSR transmission - if ((num_lcg_id_with_data > 1) && (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] == 0)) - { - num_lcg_id_with_data --; - // Change BSR size to BSR SHORT if num_lcg_id_with_data becomes to 1 - if ((bsr_len) && (num_lcg_id_with_data == 1)) - { - bsr_ce_len = sizeof(BSR_SHORT); - bsr_len = bsr_ce_len + bsr_header_len; - } + //Update total MAC Header size for RLC PDUs and save last one + total_rlc_pdu_header_len += rlc_pdu_header_len_last; - } + lcid_rlc_pdu_count ++; + } + else + { + /* avoid infinite loop ... */ + is_lcid_processed = TRUE; + } - if (buflen == (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1)) { - //No more remaining TBS after this PDU - //exit the function - rlc_pdu_header_len_last = 1; - is_lcid_processed = TRUE; - } - else { - rlc_pdu_header_len_last = (sdu_lengths[num_sdus] > 128 ) ? 3 : 2 ; + /* Get updated BO after multiplexing this PDU */ + lcid_buffer_occupancy_new = mac_rlc_get_buffer_occupancy_ind(module_idP, + UE_mac_inst[module_idP].crnti, + eNB_index, + frameP, + subframe, + ENB_FLAG_NO, + lcid); - //Change to 1 byte if it does not fit in the TBS, ie last PDU - if (buflen <= (bsr_len + phr_len + total_rlc_pdu_header_len + rlc_pdu_header_len_last + sdu_length_total)) { - rlc_pdu_header_len_last = 1; - is_lcid_processed = TRUE; - } - } - - //Update number of SDU - num_sdus ++; - - //Update total MAC Header size for RLC PDUs and save last one - total_rlc_pdu_header_len += rlc_pdu_header_len_last; - - } //end if (rlc_status.bytes_in_buffer > 0) - else { - // Switch to next LCID or exit the whole loop - is_lcid_processed = TRUE; - } - lcid_rlc_pdu_count ++; + is_lcid_processed = (is_lcid_processed) || (lcid_buffer_occupancy_new <= 0); } + //Update Buffer remain and BSR bytes after transmission + + AssertFatal (lcid_buffer_occupancy_new <= lcid_buffer_occupancy_old, "MAC UE Tx error : Buffer Occupancy After Tx=%d greater than before=%d BO! for LCID=%d RLC PDU nb=%d Frame %d Subrame %d\n", + lcid_buffer_occupancy_new,lcid_buffer_occupancy_old,lcid,lcid_rlc_pdu_count,frameP,subframe); + + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] = lcid_buffer_occupancy_new; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] += (lcid_buffer_occupancy_new - lcid_buffer_occupancy_old); + + //Update the number of LCGID with data as BSR shall reflect status after BSR transmission + if ((num_lcg_id_with_data > 1) && (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] == 0)) + { + num_lcg_id_with_data --; + // Change BSR size to BSR SHORT if num_lcg_id_with_data becomes to 1 + if ((bsr_len) && (num_lcg_id_with_data == 1)) + { + bsr_ce_len = sizeof(BSR_SHORT); + bsr_len = bsr_ce_len + bsr_header_len; + } + } + + UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_EMPTY; } -} - - -// Now Check for DTCH first -// TO DO: do it according to Logical Channel Prioritization if at least 2 DTCH -for (lcid=DTCH; lcid < MAX_NUM_LCID ; lcid++) { -if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) { - - is_lcid_processed = FALSE; - lcid_rlc_pdu_count = 0; - - //Multiplex all available DTCH RLC PDUs considering to multiplex the last PDU each time for maximize the data - //Adjust at the end of the loop - while ((!is_lcid_processed) && (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + MIN_MAC_HDR_RLC_SIZE <= buflen)) { - - buflen_remain = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); - - rlc_status = mac_rlc_status_ind(module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, // eNB_index - lcid, - buflen_remain); - - // Workaround for BO issue in RLC AM ReTx : RLC BO can not be bigger than stored MAC BO - if (UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] < rlc_status.bytes_in_buffer) { - - LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Inconsistent BO! for LCID=%d MAC=%d RLC=%d RLC PDU nb=%d\n", - module_idP,frameP,subframe, - lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],rlc_status.bytes_in_buffer,lcid_rlc_pdu_count); - - // Skip multiplexing for the LCID - break; - } - - /* - AssertFatal ( UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] >= rlc_status.bytes_in_buffer, "Inconsistent BO! for LCID=%d MAC=%d RLC=%d RLC PDU nb=%d Frame %d Subrame %d\n", - lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],rlc_status.bytes_in_buffer,lcid_rlc_pdu_count,frameP,subframe); - */ - - if (rlc_status.bytes_in_buffer > 0) { - - - LOG_D(MAC, "[UE %d] Frame %d : UL-DTCH -> ULSCH, RLC LCID%d has %d bytes to " - "send (Transport Block size %d BSR size=%d PHR=%d SDU Length Total %d , mac header len %d BSR byte before Tx=%d)\n", - module_idP,frameP, lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],buflen,bsr_len,phr_len,sdu_length_total,total_rlc_pdu_header_len,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); - - - sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, - lcid, - (char *)&ulsch_buff[sdu_length_total]); - - AssertFatal (sdu_lengths[num_sdus] < MAX_ULSCH_PAYLOAD_BYTES, "LCID=%d RLC PDU size = %d is too big\n", - lcid,sdu_lengths[num_sdus]); - - - AssertFatal (UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] >= sdu_lengths[num_sdus], "LCID=%d RLC has segmented %d bytes but MAC has max=%d\n", - lcid,sdu_lengths[num_sdus],UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]); - - - - sdu_length_total += sdu_lengths[num_sdus]; - sdu_lcids[num_sdus] = lcid; - LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU TX Got %d bytes for LCID%d\n",module_idP,sdu_lengths[num_sdus],lcid); - //header_len +=2; - // update LCID remain buffer - UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] -= sdu_lengths[num_sdus]; - /* Update BSR : substract transmitted data */ - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] >= sdu_lengths[num_sdus]){ - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] -= sdu_lengths[num_sdus] ; - } - else { - LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data transmitted=%d for LCID%d\n", - module_idP,frameP,subframe, - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], - UE_mac_inst[module_idP].scheduling_info.LCGID[lcid], - sdu_lengths[num_sdus],lcid); - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] = 0; - } - - //Update the number of LCGID with data as BSR shall reflect status after BSR transmission - if ((num_lcg_id_with_data > 1) && (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] == 0)) - { - num_lcg_id_with_data --; - // Change BSR size to BSR SHORT if num_lcg_id_with_data becomes to 1 - if ((bsr_len) && (num_lcg_id_with_data == 1)) - { - bsr_ce_len = sizeof(BSR_SHORT); - bsr_len = bsr_ce_len + bsr_header_len; - } - - } - - if (buflen == (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1)) { - //No more remaining TBS after this PDU - //exit the function - rlc_pdu_header_len_last = 1; - is_lcid_processed = TRUE; - } - else { - rlc_pdu_header_len_last = (sdu_lengths[num_sdus] > 128 ) ? 3 : 2 ; - - //Change to 1 byte if it does not fit in the TBS, ie last PDU - if (buflen <= (bsr_len + phr_len + total_rlc_pdu_header_len + rlc_pdu_header_len_last + sdu_length_total)) { - rlc_pdu_header_len_last = 1; - is_lcid_processed = TRUE; - } - } - - //Update number of SDU - num_sdus ++; - - //Update total MAC Header size for RLC PDUs and save last one - total_rlc_pdu_header_len += rlc_pdu_header_len_last; - - } //end if (rlc_status.bytes_in_buffer > 0) - else { - // Switch to next LCID or exit the whole loop - is_lcid_processed = TRUE; - } - lcid_rlc_pdu_count ++; } - UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_EMPTY; - } -} - //lcgid= get_bsr_lcgid(module_idP); // Compute BSR Values and update Nb LCGID with data after multiplexing num_lcg_id_with_data = 0; @@ -1923,7 +1790,7 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) if (opt_enabled) { trace_pdu(0, ulsch_buffer, buflen, module_idP, 3, UE_mac_inst[module_idP].crnti, UE_mac_inst[module_idP].txFrame, UE_mac_inst[module_idP].txSubframe, 0, 0); LOG_D(OPT,"[UE %d][ULSCH] Frame %d subframe %d trace pdu for rnti %x with size %d\n", - module_idP, UE_mac_inst[module_idP].txFrame, UE_mac_inst[module_idP].txSubframe, UE_mac_inst[module_idP].crnti, buflen); + module_idP, frameP, subframe, UE_mac_inst[module_idP].crnti, buflen); } } @@ -2104,7 +1971,7 @@ ue_scheduler( /* if (lcid == DCCH) { LOG_D(MAC,"[UE %d][SR] Frame %d subframe %d Pending data for SRB1=%d for LCGID %d \n", - module_idP, frameP,subframeP,UE_mac_inst[module_idP].scheduling_info.BSR[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], + module_idP, txFrameP,txSubframeP,UE_mac_inst[module_idP].scheduling_info.BSR[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], // UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); } */ @@ -2396,9 +2263,9 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subfra lcgid_buffer_remain[lcgid] += UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]; } - rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,eNB_index,frameP,ENB_FLAG_NO,MBMS_FLAG_NO, + rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,eNB_index,frameP,subframeP,ENB_FLAG_NO,MBMS_FLAG_NO, lcid, - 0); + 0xFFFF); //TBS is not used in RLC at this step, set a special value for debug lcid_bytes_in_buffer[lcid] = rlc_status.bytes_in_buffer; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index 726b52be53..03fabf47b3 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -43,61 +43,148 @@ #include "DL-AM-RLC.h" +//----------------------------------------------------------------------------- +uint32_t +rlc_am_get_status_pdu_buffer_occupancy( + rlc_am_entity_t * const rlc_pP){ + + //Compute Max Status PDU size according to what has been received and not received in the window [vrR vrMS[ + + // minimum header size in bits to be transmitted: D/C + CPT + ACK_SN + E1 + uint32_t nb_bits_to_transmit = RLC_AM_PDU_D_C_BITS + RLC_AM_STATUS_PDU_CPT_LENGTH + RLC_AM_SN_BITS + RLC_AM_PDU_E_BITS; + mem_block_t *cursor_p = rlc_pP->receiver_buffer.head; + rlc_am_pdu_info_t *pdu_info_cursor_p = NULL; + int waited_so = 0; + + rlc_sn_t sn_cursor = rlc_pP->vr_r; + rlc_sn_t sn_prev = rlc_pP->vr_r; + rlc_sn_t sn_end = rlc_pP->vr_ms; + boolean_t segment_loop_end = false; + + + if (sn_prev != sn_end) + { + while ((RLC_AM_DIFF_SN(sn_prev,rlc_pP->vr_r) < RLC_AM_DIFF_SN(sn_end,rlc_pP->vr_r)) && (cursor_p != NULL)) + { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + sn_cursor = pdu_info_cursor_p->sn; + + // Add holes between sn_prev and sn_cursor + while ((sn_prev != sn_cursor) && (sn_prev != sn_end)) + { + /* Add 1 NACK_SN + E1 + E2 */ + nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1)); + sn_prev = RLC_AM_NEXT_SN(sn_prev); + } //end while (sn_prev != sn_cursor) + + /* Handle case sn_cursor is partially received */ + /* Each gap will add NACK_SN + E1 + E2 + SOStart + SOEnd */ + if ((((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received == 0) && (RLC_AM_DIFF_SN(sn_cursor,rlc_pP->vr_r) < RLC_AM_DIFF_SN(sn_end,rlc_pP->vr_r))) + { + /* Check lsf */ + segment_loop_end = (pdu_info_cursor_p->lsf == 1); + + /* Fill for [0 SO[ if SO not null */ + if (pdu_info_cursor_p->so) { + nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); + waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size; + } + else { + waited_so = pdu_info_cursor_p->payload_size; + } + + /* Go to next segment */ + cursor_p = cursor_p->next; + if (cursor_p != NULL) + { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + + /* Fill following gaps if any */ + while (!segment_loop_end) + { + if ((cursor_p != NULL) && (pdu_info_cursor_p->sn == sn_cursor)) + { + /* Check lsf */ + segment_loop_end = (pdu_info_cursor_p->lsf == 1); + + if (waited_so < pdu_info_cursor_p->so) { + nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); + } + else { + /* contiguous segment: only update waited_so */ + /* Assuming so and payload_size updated according to duplication removal done at reception ... */ + waited_so += pdu_info_cursor_p->payload_size; + } + + /* Go to next received PDU or PDU Segment */ + cursor_p = cursor_p->next; + if (cursor_p != NULL) + { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + else + { + /* Fill last gap assuming LSF is not received */ + nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); + segment_loop_end = true; + } + } // end while (!segment_loop_end) + } // end if segments + else + { + /* Go to next received PDU or PDU segment with different SN */ + do + { + cursor_p = cursor_p->next; + } while ((cursor_p != NULL) && (((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info.sn == sn_cursor)); + } + + sn_prev = RLC_AM_NEXT_SN(sn_cursor); + } + } // end if (sn_prev != sn_end) + + // round up to the greatest byte + return ((nb_bits_to_transmit + 7) >> 3); + +} + //----------------------------------------------------------------------------- uint32_t rlc_am_get_buffer_occupancy_in_bytes ( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlc_pP) { - uint32_t max_li_overhead; - uint32_t header_overhead; - // priority of control trafic rlc_pP->status_buffer_occupancy = 0; - if (rlc_pP->status_requested) { - if (rlc_pP->t_status_prohibit.running == 0) { + if ((rlc_pP->status_requested) && !(rlc_pP->status_requested & RLC_AM_STATUS_NO_TX_MASK)) { + rlc_pP->status_buffer_occupancy = rlc_am_get_status_pdu_buffer_occupancy(rlc_pP); #if TRACE_RLC_AM_BO - if (((15 + rlc_pP->num_nack_sn*(10+1) + rlc_pP->num_nack_so*(15+15+1) + 7) >> 3) > 0) { LOG_D(RLC, PROTOCOL_CTXT_FMT RB_AM_FMT" BO : CONTROL PDU %d bytes \n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - ((15 + rlc_pP->num_nack_sn*(10+1) + rlc_pP->num_nack_so*(15+15+1) + 7) >> 3)); - } + rlc_pP->status_buffer_occupancy); #endif - rlc_pP->status_buffer_occupancy = ((15 + rlc_pP->num_nack_sn*(10+1) + rlc_pP->num_nack_so*(15+15+1) + 7) >> 3); - } - } - - // data traffic - if (rlc_pP->nb_sdu_no_segmented <= 1) { - max_li_overhead = 0; - } else { - max_li_overhead = (((rlc_pP->nb_sdu_no_segmented - 1) * 3) / 2) + ((rlc_pP->nb_sdu_no_segmented - 1) % 2); - } - - if (rlc_pP->sdu_buffer_occupancy == 0) { - header_overhead = 0; - } else { - header_overhead = 2; } #if TRACE_RLC_AM_BO - if ((rlc_pP->status_buffer_occupancy + rlc_pP->retransmission_buffer_occupancy + rlc_pP->sdu_buffer_occupancy + max_li_overhead + header_overhead) > 0) { + if ((rlc_pP->status_buffer_occupancy + rlc_pP->retrans_num_bytes_to_retransmit + rlc_pP->sdu_buffer_occupancy + max_li_overhead + header_overhead) > 0) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" BO : STATUS BUFFER %d bytes \n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->status_buffer_occupancy); - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" BO : RETRANS BUFFER %d bytes \n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->retransmission_buffer_occupancy); + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" BO : RETRANS BUFFER %d bytes \n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->retrans_num_bytes_to_retransmit); LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" BO : SDU BUFFER %d bytes + li_overhead %d bytes header_overhead %d bytes (nb sdu not segmented %d)\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->sdu_buffer_occupancy, - max_li_overhead, - header_overhead, + 0, + 0, rlc_pP->nb_sdu_no_segmented); } #endif - return rlc_pP->status_buffer_occupancy + rlc_pP->retrans_num_bytes_to_retransmit + rlc_pP->sdu_buffer_occupancy + max_li_overhead + header_overhead; + return rlc_pP->status_buffer_occupancy + rlc_pP->retrans_num_bytes_to_retransmit + rlc_pP->sdu_buffer_occupancy; } //----------------------------------------------------------------------------- void @@ -150,9 +237,9 @@ config_req_rlc_am ( PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p)); } } -uint32_t pollPDU_tab[PollPDU_pInfinity+1]= {4,8,16,32,64,128,256,1024}; // What is PollPDU_pInfinity??? 1024 for now +uint16_t pollPDU_tab[PollPDU_pInfinity+1]= {4,8,16,32,64,128,256,RLC_AM_POLL_PDU_INFINITE}; //PollPDU_pInfinity is chosen to 0xFFFF for now uint32_t maxRetxThreshold_tab[UL_AM_RLC__maxRetxThreshold_t32+1]= {1,2,3,4,6,8,16,32}; -uint32_t pollByte_tab[PollByte_spare1]= {25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,10000}; // What is PollByte_kBinfinity??? 10000 for now +uint32_t pollByte_tab[PollByte_spare1]= {25000,50000,75000,100000,125000,250000,375000,500000,750000,1000000,1250000,1500000,2000000,3000000,RLC_AM_POLL_BYTE_INFINITE}; // PollByte_kBinfinity is chosen to 0xFFFFFFFF for now #if defined(Rel14) uint32_t PollRetransmit_tab[T_PollRetransmit_spare5]= {5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,180,185,190,195,200,205,210,215,220,225,230,235,240,245,250,300,350,400,450,500,800,1000,2000,4000}; uint32_t am_t_Reordering_tab[32]= {0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,110,120,130,140,150,160,170,180,190,200,1600}; @@ -318,7 +405,7 @@ rlc_am_get_pdus ( rlc_am_entity_t * const rlc_pP ) { - int display_flag = 0; + //int display_flag = 0; // 5.1.3.1 Transmit operations // 5.1.3.1.1 // General @@ -335,7 +422,8 @@ rlc_am_get_pdus ( case RLC_DATA_TRANSFER_READY_STATE: // TRY TO SEND CONTROL PDU FIRST - if ((rlc_pP->nb_bytes_requested_by_mac > 2) && (rlc_pP->status_requested)) { + if ((rlc_pP->nb_bytes_requested_by_mac >= 2) && + ((rlc_pP->status_requested) && !(rlc_pP->status_requested & RLC_AM_STATUS_NO_TX_MASK))) { // When STATUS reporting has been triggered, the receiving side of an AM RLC entity shall: // - if t-StatusProhibit is not running: // - at the first transmission opportunity indicated by lower layer, construct a STATUS PDU and deliver it to lower layer; @@ -346,140 +434,39 @@ rlc_am_get_pdus ( // // When a STATUS PDU has been delivered to lower layer, the receiving side of an AM RLC entity shall: // - start t-StatusProhibit. - if (rlc_pP->t_status_prohibit.running == 0) { + rlc_am_send_status_pdu(ctxt_pP, rlc_pP); mem_block_t* pdu = list_remove_head(&rlc_pP->control_pdu_list); if (pdu) { list_add_tail_eurecom (pdu, &rlc_pP->pdus_to_mac_layer); - rlc_pP->status_requested = 0; + RLC_AM_CLEAR_ALL_STATUS(rlc_pP->status_requested); rlc_pP->status_buffer_occupancy = 0; rlc_am_start_timer_status_prohibit(ctxt_pP, rlc_pP); return; } - } else { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" DELAYED SENT STATUS PDU BECAUSE T-STATUS-PROHIBIT RUNNING (TIME-OUT %u)\n", + } + else { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" DELAYED SENT STATUS PDU (Available MAC Data %u)(T-PROHIBIT %u) (DELAY FLAG %u)\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->t_status_prohibit.ms_time_out); - } + rlc_pP->nb_bytes_requested_by_mac,rlc_pP->t_status_prohibit.ms_time_out,(rlc_pP->status_requested & RLC_AM_STATUS_TRIGGERED_DELAYED)); } - /*while ((rlc_pP->nb_bytes_requested_by_mac > 0) && (stay_on_this_list)) { - mem_block_t* pdu = list_get_head(&rlc_pP->control_pdu_list); - if (pdu != NULL { - if ( ((rlc_am_tx_control_pdu_management_t*)(pdu->data))->size <= rlc_pP->nb_bytes_requested_by_mac) { - pdu = list_remove_head(&rlc_pP->control_pdu_list); - #if TRACE_RLC_AM_TX - msg ("[FRAME %5u][%s][RLC_AM][MOD %u/%u][RB %u] SEND CONTROL PDU\n", ((rlc_am_entity_t *) rlc_pP)->module_id,((rlc_am_entity_t *) rlc_pP)->rb_id, ctxt_pP->frame); - #endif - list_add_tail_eurecom (pdu, &rlc_pP->pdus_to_mac_layer); - rlc_pP->nb_bytes_requested_by_mac = rlc_pP->nb_bytes_requested_by_mac - ((rlc_am_tx_control_pdu_management_t*)(pdu->data))->size; - } else { - stay_on_this_list = 0; - } - } else { - stay_on_this_list = 0; - } - }*/ // THEN TRY TO SEND RETRANS PDU - if (rlc_pP->first_retrans_pdu_sn >= 0) { - rlc_am_tx_data_pdu_management_t* tx_data_pdu_management; + if ((rlc_pP->retrans_num_bytes_to_retransmit) && (rlc_pP->nb_bytes_requested_by_mac > 2)) { - // tx min 3 bytes because of the size of the RLC header - while ((rlc_pP->nb_bytes_requested_by_mac > 2) && - (rlc_pP->first_retrans_pdu_sn >= 0) && - (rlc_pP->first_retrans_pdu_sn != rlc_pP->vt_s)) { + /* Get 1 AM data PDU or PDU segment to retransmit */ + mem_block_t* pdu_retx = rlc_am_get_pdu_to_retransmit(ctxt_pP, rlc_pP); - tx_data_pdu_management = &rlc_pP->pdu_retrans_buffer[rlc_pP->first_retrans_pdu_sn]; + if (pdu_retx != NULL) { + list_add_tail_eurecom (pdu_retx, &rlc_pP->pdus_to_mac_layer); - if ((tx_data_pdu_management->header_and_payload_size <= rlc_pP->nb_bytes_requested_by_mac) && (tx_data_pdu_management->retx_count >= 0) - && (tx_data_pdu_management->nack_so_start == 0) && (tx_data_pdu_management->nack_so_stop == 0x7FFF)) { - mem_block_t* copy = rlc_am_retransmit_get_copy(ctxt_pP, rlc_pP, rlc_pP->first_retrans_pdu_sn); - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RE-SEND DATA PDU SN %04d %d BYTES\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn, - tx_data_pdu_management->header_and_payload_size); - rlc_pP->stat_tx_data_pdu += 1; - rlc_pP->stat_tx_retransmit_pdu += 1; - rlc_pP->stat_tx_retransmit_pdu_by_status += 1; - rlc_pP->stat_tx_data_bytes += tx_data_pdu_management->header_and_payload_size; - rlc_pP->stat_tx_retransmit_bytes += tx_data_pdu_management->header_and_payload_size; - rlc_pP->stat_tx_retransmit_bytes_by_status += tx_data_pdu_management->header_and_payload_size; - - list_add_tail_eurecom (copy, &rlc_pP->pdus_to_mac_layer); - rlc_pP->nb_bytes_requested_by_mac = rlc_pP->nb_bytes_requested_by_mac - tx_data_pdu_management->header_and_payload_size; - - tx_data_pdu_management->retx_count += 1; return; - } else if ((tx_data_pdu_management->retx_count >= 0) && (rlc_pP->nb_bytes_requested_by_mac >= RLC_AM_MIN_SEGMENT_SIZE_REQUEST)) { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" SEND SEGMENT OF DATA PDU SN %04d MAC BYTES %d SIZE %d RTX COUNT %d nack_so_start %d nack_so_stop %04X(hex)\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn, - rlc_pP->nb_bytes_requested_by_mac, - tx_data_pdu_management->header_and_payload_size, - tx_data_pdu_management->retx_count, - tx_data_pdu_management->nack_so_start, - tx_data_pdu_management->nack_so_stop); - - mem_block_t* copy = rlc_am_retransmit_get_subsegment( - ctxt_pP, - rlc_pP, - rlc_pP->first_retrans_pdu_sn, - &rlc_pP->nb_bytes_requested_by_mac); - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" SEND SEGMENT OF DATA PDU SN %04d (NEW SO %05d)\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn, - tx_data_pdu_management->nack_so_start); - - rlc_pP->stat_tx_data_pdu += 1; - rlc_pP->stat_tx_retransmit_pdu += 1; - rlc_pP->stat_tx_retransmit_pdu_by_status += 1; - rlc_pP->stat_tx_data_bytes += (((struct mac_tb_req*)(copy->data))->tb_size); - rlc_pP->stat_tx_retransmit_bytes += (((struct mac_tb_req*)(copy->data))->tb_size); - rlc_pP->stat_tx_retransmit_bytes_by_status += (((struct mac_tb_req*)(copy->data))->tb_size); - list_add_tail_eurecom (copy, &rlc_pP->pdus_to_mac_layer); - } else { - break; + } } - // update first_retrans_pdu_sn - while ((rlc_pP->first_retrans_pdu_sn != rlc_pP->vt_s) && - (!(rlc_pP->pdu_retrans_buffer[rlc_pP->first_retrans_pdu_sn].flags.retransmit))) { - rlc_pP->first_retrans_pdu_sn = (rlc_pP->first_retrans_pdu_sn+1) & RLC_AM_SN_MASK; - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" UPDATED first_retrans_pdu_sn SN %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn); - }; - - display_flag = 1; - - if (rlc_pP->first_retrans_pdu_sn == rlc_pP->vt_s) { - // no more pdu to be retransmited - rlc_pP->first_retrans_pdu_sn = -1; - display_flag = 0; - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" CLEAR first_retrans_pdu_sn\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); - } - - if (display_flag > 0) { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" UPDATED first_retrans_pdu_sn %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn); - } - - return; - - /* ONLY ONE TB PER TTI - if ((tx_data_pdu_management->retx_count >= 0) && (rlc_pP->nb_bytes_requested_by_mac < RLC_AM_MIN_SEGMENT_SIZE_REQUEST)) { - #if TRACE_RLC_AM_TX - msg ("[FRAME %5u][%s][RLC_AM][MOD %u/%u][RB %u] BREAK LOOP ON RETRANSMISSION BECAUSE ONLY %d BYTES ALLOWED TO TRANSMIT BY MAC\n",ctxt_pP->frame, ((rlc_am_entity_t *) rlc_pP)->module_id,((rlc_am_entity_t *) rlc_pP)->rb_id, rlc_pP->nb_bytes_requested_by_mac); - #endif - break; - }*/ - } - } - - if ((rlc_pP->nb_bytes_requested_by_mac > 2) && (rlc_pP->vt_s != rlc_pP->vt_ms)) { + // THEN TRY TO SEND NEW DATA PDU + if ((rlc_pP->nb_bytes_requested_by_mac > 2) && (rlc_pP->sdu_buffer_occupancy) && (rlc_pP->vt_s != rlc_pP->vt_ms)) { rlc_am_segment_10(ctxt_pP, rlc_pP); list_add_list (&rlc_pP->segmentation_pdu_list, &rlc_pP->pdus_to_mac_layer); @@ -490,29 +477,6 @@ rlc_am_get_pdus ( } } - if ((rlc_pP->pdus_to_mac_layer.head == NULL) && - (rlc_am_is_timer_poll_retransmit_timed_out(ctxt_pP, rlc_pP)) && - (rlc_pP->nb_bytes_requested_by_mac > 2)) { - rlc_am_retransmit_any_pdu(ctxt_pP, rlc_pP); - return; - } else { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" COULD NOT RETRANSMIT ANY PDU BECAUSE ", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); - - if (rlc_pP->pdus_to_mac_layer.head != NULL) { - LOG_D(RLC, "THERE ARE SOME PDUS READY TO TRANSMIT "); - } - - if (!(rlc_am_is_timer_poll_retransmit_timed_out(ctxt_pP, rlc_pP))) { - LOG_D(RLC, "TIMER POLL DID NOT TIMED OUT (RUNNING = %d NUM PDUS TO RETRANS = %d NUM BYTES TO RETRANS = %d) ", rlc_pP->t_poll_retransmit.running, - rlc_pP->retrans_num_pdus, rlc_pP->retrans_num_bytes_to_retransmit); - } - - if (rlc_pP->nb_bytes_requested_by_mac <= 2) { - LOG_D(RLC, "NUM BYTES REQUESTED BY MAC = %d", rlc_pP->nb_bytes_requested_by_mac); - } - LOG_D(RLC, "\n"); - } break; @@ -554,7 +518,8 @@ rlc_am_mac_status_indication ( const protocol_ctxt_t* const ctxt_pP, void * const rlc_pP, const uint16_t tb_sizeP, - struct mac_status_ind tx_statusP) + struct mac_status_ind tx_statusP, + const eNB_flag_t enb_flagP) { struct mac_status_resp status_resp; uint16_t sdu_size = 0; @@ -578,18 +543,38 @@ rlc_am_mac_status_indication ( */ if (rlc->input_sdus == NULL) return status_resp; - if (rlc->last_frame_status_indication != ctxt_pP->frame) { + if (rlc->last_absolute_subframe_status_indication != (PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP))) { rlc_am_check_timer_poll_retransmit(ctxt_pP, rlc); rlc_am_check_timer_reordering(ctxt_pP, rlc); rlc_am_check_timer_status_prohibit(ctxt_pP, rlc); } - rlc->last_frame_status_indication = ctxt_pP->frame; + rlc->last_absolute_subframe_status_indication = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP); rlc->nb_bytes_requested_by_mac = tb_sizeP; status_resp.buffer_occupancy_in_bytes = rlc_am_get_buffer_occupancy_in_bytes(ctxt_pP, rlc); + // For eNB scheduler : Add Max RLC header size for new PDU + // For UE : do not add RLC header part to be compliant with BSR definition in 36.321 + if (enb_flagP == ENB_FLAG_YES) { + uint32_t max_li_overhead = 0; + uint32_t header_overhead = 0; + + if (rlc->nb_sdu_no_segmented > 1) { + /* This computation assumes there is no SDU with size greater than 2047 bytes, otherwise a new PDU must be built except for LI15 configuration from Rel12*/ + uint32_t num_li = rlc->nb_sdu_no_segmented - 1; + max_li_overhead = num_li + (num_li >> 1) + (num_li & 1); + } + + if (rlc->sdu_buffer_occupancy > 0) { + header_overhead = 2; + } + + status_resp.buffer_occupancy_in_bytes += (header_overhead + max_li_overhead); + } + + if ((rlc->input_sdus[rlc->current_sdu_index].mem_block != NULL) && (status_resp.buffer_occupancy_in_bytes)) { //status_resp.buffer_occupancy_in_bytes += ((rlc_am_entity_t *) rlc)->tx_header_min_length_in_bytes; @@ -610,32 +595,16 @@ rlc_am_mac_status_indication ( } } else { - if (rlc_am_is_timer_poll_retransmit_timed_out(ctxt_pP, rlc)) { - if ((status_resp.buffer_occupancy_in_bytes == 0) && (rlc->input_sdus[rlc->current_sdu_index].mem_block == NULL) && (rlc->nb_sdu > 0)) { - // force BO to be > 0 - rlc_sn_t sn = (rlc->vt_s - 1) & RLC_AM_SN_MASK; - rlc_sn_t sn_end = (rlc->vt_a - 1) & RLC_AM_SN_MASK; - int found_pdu = 0; - rlc_sn_t found_pdu_sn = 0; // avoid warning - (void)found_pdu_sn; /* avoid gcc warning "set but not used" */ - - - while (sn != sn_end) { - if (rlc->pdu_retrans_buffer[sn].mem_block != NULL) { - if (!found_pdu) { - found_pdu = 1; - found_pdu_sn = sn; - } - status_resp.buffer_occupancy_in_bytes = rlc->pdu_retrans_buffer[sn].header_and_payload_size; - status_resp.buffer_occupancy_in_pdus = rlc->nb_sdu; - status_resp.head_sdu_remaining_size_to_send = status_resp.buffer_occupancy_in_bytes; - // TODO head_sdu_is_segmented - break; + /* Not so many possibilities ... */ + /* either buffer_occupancy_in_bytes = 0 and that's it */ + /* or we have segmented all received SDUs and buffer occupancy is then made of retransmissions and/or status pdu pending */ + /* then consider only retransmission buffer for the specific BO values used by eNB scheduler (not used up to now...) */ + if (rlc->retrans_num_bytes_to_retransmit) { + status_resp.buffer_occupancy_in_pdus = rlc->retrans_num_pdus; + status_resp.head_sdu_remaining_size_to_send = rlc->retrans_num_bytes_to_retransmit; + status_resp.head_sdu_is_segmented = 1; } } - } - } - } #if MESSAGE_CHART_GENERATOR_RLC_MAC MSC_LOG_RX_MESSAGE( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE, @@ -678,11 +647,23 @@ rlc_am_mac_status_indication ( #endif return status_resp; } + +//----------------------------------------------------------------------------- +void +rlc_am_set_nb_bytes_requested_by_mac ( + void * const rlc_pP, + const tb_size_t tb_sizeP +) +{ + ((rlc_am_entity_t *) rlc_pP)->nb_bytes_requested_by_mac = tb_sizeP; +} + //----------------------------------------------------------------------------- struct mac_data_req rlc_am_mac_data_request ( const protocol_ctxt_t* const ctxt_pP, - void * const rlc_pP + void * const rlc_pP, + const eNB_flag_t enb_flagP ) { struct mac_data_req data_req; @@ -720,7 +701,10 @@ rlc_am_mac_data_request ( data_req.data.nb_elements); } + if (enb_flagP) { + // redundant in UE MAC Tx processing and not used in eNB ... data_req.buffer_occupancy_in_bytes = rlc_am_get_buffer_occupancy_in_bytes(ctxt_pP, l_rlc_p); + } data_req.rlc_info.rlc_protocol_state = l_rlc_p->protocol_state; #if TRACE_RLC_AM_PDU || MESSAGE_CHART_GENERATOR @@ -1267,14 +1251,19 @@ rlc_am_data_req ( l_rlc_p->input_sdus[l_rlc_p->next_sdu_index].flags.no_new_sdu_segmented_in_last_pdu = 0; //l_rlc_p->input_sdus[l_rlc_p->next_sdu_index].li_index_for_discard = -1; l_rlc_p->next_sdu_index = (l_rlc_p->next_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE; - LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RLC_AM_DATA_REQ size %d Bytes, NB SDU %d current_sdu_index=%d next_sdu_index=%d conf %d mui %d\n", + if (l_rlc_p->channel_id <3) + { + LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RLC_AM_DATA_REQ size %d Bytes, NB SDU %d current_sdu_index=%d next_sdu_index=%d conf %d mui %d vtA %d vtS %d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p), data_size, l_rlc_p->nb_sdu, l_rlc_p->current_sdu_index, l_rlc_p->next_sdu_index, conf, - mui); + mui, + l_rlc_p->vt_a, + l_rlc_p->vt_s); + } } else { #if MESSAGE_CHART_GENERATOR mui = ((struct rlc_am_data_req*) (sdu_pP->data))->mui; @@ -1291,12 +1280,14 @@ rlc_am_data_req ( data_size, mui); #endif - LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RLC_AM_DATA_REQ BUFFER FULL, NB SDU %d current_sdu_index=%d next_sdu_index=%d size_input_sdus_buffer=%d\n", + LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RLC_AM_DATA_REQ BUFFER FULL, NB SDU %d current_sdu_index=%d next_sdu_index=%d size_input_sdus_buffer=%d vtA=%d vtS=%d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p), l_rlc_p->nb_sdu, l_rlc_p->current_sdu_index, l_rlc_p->next_sdu_index, - RLC_AM_SDU_CONTROL_BUFFER_SIZE); + RLC_AM_SDU_CONTROL_BUFFER_SIZE, + l_rlc_p->vt_a, + l_rlc_p->vt_s); LOG_W(RLC, " input_sdus[].mem_block=%p next input_sdus[].flags.segmented=%d\n", l_rlc_p->input_sdus[l_rlc_p->next_sdu_index].mem_block, l_rlc_p->input_sdus[l_rlc_p->next_sdu_index].flags.segmented); l_rlc_p->stat_tx_pdcp_sdu_discarded += 1; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h index 61c6a043cc..4619a07315 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h @@ -267,23 +267,32 @@ private_rlc_am( void rlc_am_get_pdus (const protocol_ctxt_t* const ctxtP,v */ protected_rlc_am( void rlc_am_rx (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, struct mac_data_ind);) -/*! \fn struct mac_status_resp rlc_am_mac_status_indication (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP) +/*! \fn struct mac_status_resp rlc_am_mac_status_indication (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP,const eNB_flag_t enb_flagP) * \brief Request the maximum number of bytes that can be served by RLC instance to MAC and fix the amount of bytes requested by MAC for next RLC transmission. * \param[in] ctxt_pP Running context. * \param[in] rlc_pP RLC AM protocol instance pointer. * \param[in] tbs_sizeP Number of bytes requested by MAC for next transmission. * \param[in] tx_statusP Transmission status given by MAC on previous MAC transmission of the PDU. +* \param[in] enb_flagP eNB or UE flag indication. * \return The maximum number of bytes that can be served by RLC instance to MAC. */ -public_rlc_am( struct mac_status_resp rlc_am_mac_status_indication (const protocol_ctxt_t* const ctxtP, void * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP);) +public_rlc_am( struct mac_status_resp rlc_am_mac_status_indication (const protocol_ctxt_t* const ctxtP, void * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP,const eNB_flag_t enb_flagP);) -/*! \fn struct mac_data_req rlc_am_mac_data_request (const protocol_ctxt_t* const ctxtP,void * const rlc_pP) +/*! \fn void rlc_am_set_nb_bytes_requested_by_mac (void * const rlc_pP,const tb_size_t tb_sizeP) +* \brief Set available TBS for RLC Tx just before am_mac_data_request. Used for UE only. +* \param[in] rlc_pP RLC AM protocol instance pointer. +* \param[in] tb_sizeP Available Tx Transport Block size in bytes. +*/ +public_rlc_am( void rlc_am_set_nb_bytes_requested_by_mac (void * const rlc_pP,const tb_size_t tb_sizeP);) + +/*! \fn struct mac_data_req rlc_am_mac_data_request (const protocol_ctxt_t* const ctxtP,void * const rlc_pP,const eNB_flag_t enb_flagP) * \brief Gives PDUs to lower layer MAC. * \param[in] ctxt_pP Running context. * \param[in] rlc_pP RLC AM protocol instance pointer. +* \param[in] enb_flagP eNB or UE flag * \return A PDU of the previously requested number of bytes, and the updated maximum number of bytes that can be served by RLC instance to MAC for next RLC transmission. */ -public_rlc_am( struct mac_data_req rlc_am_mac_data_request (const protocol_ctxt_t* const ctxtP,void * const rlc_pP);) +public_rlc_am( struct mac_data_req rlc_am_mac_data_request (const protocol_ctxt_t* const ctxtP,void * const rlc_pP,const eNB_flag_t enb_flagP);) /*! \fn void rlc_am_mac_data_indication (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, struct mac_data_ind data_indP) * \brief Receive PDUs from lower layer MAC. @@ -293,6 +302,13 @@ public_rlc_am( struct mac_data_req rlc_am_mac_data_request (const protocol_ct */ public_rlc_am( void rlc_am_mac_data_indication (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, struct mac_data_ind data_indP);) +/*! \fn uint32_t rlc_am_get_buffer_occupancy_in_bytes (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlc_pP) +* \brief Get Tx Buffer Occupancy. +* \param[in] ctxt_pP Running context. +* \param[in] rlc_pP RLC AM protocol instance pointer. +*/ +public_rlc_am( uint32_t rlc_am_get_buffer_occupancy_in_bytes (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlc_pP);) + /*! \fn void rlc_am_data_req (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, mem_block_t *sduP) * \brief Interface with higher layers, buffer higher layer SDUS for transmission. * \param[in] ctxt_pP Running context. diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h index dcc5f2de8f..69429b84b8 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h @@ -48,14 +48,17 @@ # define RLC_AM_SDU_DATA_BUFFER_SIZE 64*1024 /** Max number of incoming SDUs from upper layer that can be buffered in a RLC AM protocol instance. */ -# define RLC_AM_SDU_CONTROL_BUFFER_SIZE 128 +# define RLC_AM_SDU_CONTROL_BUFFER_SIZE 1024 /** Size of the retransmission buffer (number of PDUs). */ -# define RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE RLC_AM_SN_MODULO +# define RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE RLC_AM_WINDOW_SIZE /** PDU minimal header size in bytes. */ # define RLC_AM_HEADER_MIN_SIZE 2 +/** PDU Segment minimal header size in bytes = PDU header + SOStart + SOEnd. */ +# define RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE 4 + /** If we want to send a segment of a PDU, then the min transport block size requested by MAC should be this amount. */ # define RLC_AM_MIN_SEGMENT_SIZE_REQUEST 8 @@ -69,6 +72,99 @@ # define RLC_AM_MAX_NACK_IN_STATUS_PDU 1023 /** Max holes created by NACK_SN with segment offsets for a PDU in the retransmission buffer. */ -# define RLC_AM_MAX_HOLES_REPORT_PER_PDU 32 +# define RLC_AM_MAX_HOLES_REPORT_PER_PDU 16 /** @} */ -# endif + +#define RLC_AM_POLL_PDU_INFINITE 0xFFFF +#define RLC_AM_POLL_BYTE_INFINITE 0xFFFFFFFF + +/* MACRO DEFINITIONS */ + +#define RLC_AM_NEXT_SN(sn) (((sn)+1) & (RLC_AM_SN_MASK)) +#define RLC_AM_PREV_SN(sn) (((sn)+(RLC_AM_SN_MODULO)-1) & (RLC_AM_SN_MASK)) + +#define RLC_DIFF_SN(sn,snref,modulus) ((sn+(modulus)-snref) & ((modulus)-1)) +#define RLC_SN_IN_WINDOW(sn,snref,modulus) ((RLC_DIFF_SN(sn,snref,modulus)) < ((modulus) >> 1)) + +#define RLC_AM_DIFF_SN(sn,snref) (RLC_DIFF_SN(sn,snref,RLC_AM_SN_MODULO)) +#define RLC_AM_SN_IN_WINDOW(sn,snref) (RLC_SN_IN_WINDOW(sn,snref,RLC_AM_SN_MODULO)) + +#define RLC_SET_BIT(x,offset) ((x) |= (1 << (offset))) +#define RLC_GET_BIT(x,offset) (((x) & (1 << (offset))) >> (offset)) +#define RLC_CLEAR_BIT(x,offset) ((x) &= ~(1 << (offset))) + +#define RLC_SET_EVENT(x,event) ((x) |= (event)) +#define RLC_GET_EVENT(x,event) ((x) & (event)) +#define RLC_CLEAR_EVENT(x,event) ((x) &= (~(event))) + +/* Common to Data and Status PDU */ +#define RLC_AM_SN_BITS 10 +#define RLC_AM_PDU_D_C_BITS 1 +#define RLC_AM_PDU_E_BITS 1 +#define RLC_AM_PDU_FI_BITS 2 +#define RLC_AM_PDU_POLL_BITS 1 +#define RLC_AM_PDU_RF_BITS 1 + + +#define RLC_AM_LI_BITS 11 +#define RLC_AM_LI_MASK 0x7FF + + +/* AM Data PDU */ +#define RLC_AM_PDU_E_OFFSET 2 +#define RLC_AM_PDU_FI_OFFSET (RLC_AM_PDU_E_OFFSET + RLC_AM_PDU_E_BITS) +#define RLC_AM_PDU_POLL_OFFSET (RLC_AM_PDU_FI_OFFSET + RLC_AM_PDU_FI_BITS) +#define RLC_AM_PDU_RF_OFFSET (RLC_AM_PDU_POLL_OFFSET + RLC_AM_PDU_POLL_BITS) +#define RLC_AM_PDU_D_C_OFFSET (RLC_AM_PDU_RF_OFFSET + RLC_AM_PDU_RF_BITS) + +#define RLC_AM_PDU_GET_FI_START(px) (RLC_GET_BIT((px),RLC_AM_PDU_FI_OFFSET + 1)) +#define RLC_AM_PDU_GET_FI_END(px) (RLC_GET_BIT((px),RLC_AM_PDU_FI_OFFSET)) + +#define RLC_AM_PDU_GET_LI(x,offset) (((x) >> (offset)) & RLC_AM_LI_MASK) +#define RLC_AM_PDU_SET_LI(x,li,offset) ((x) |= (((li) & RLC_AM_LI_MASK) << (offset))) + +#define RLC_AM_PDU_SET_E(px) (RLC_SET_BIT((px),RLC_AM_PDU_E_OFFSET)) +#define RLC_AM_PDU_SET_D_C(px) (RLC_SET_BIT((px),RLC_AM_PDU_D_C_OFFSET)) +#define RLC_AM_PDU_SET_RF(px) (RLC_SET_BIT((px),RLC_AM_PDU_RF_OFFSET)) +#define RLC_AM_PDU_SET_POLL(px) (RLC_SET_BIT((px),RLC_AM_PDU_POLL_OFFSET)) +#define RLC_AM_PDU_CLEAR_POLL(px) (RLC_CLEAR_BIT((px),RLC_AM_PDU_POLL_OFFSET)) + +#define RLC_AM_PDU_SEGMENT_SO_LENGTH 15 +#define RLC_AM_PDU_SEGMENT_SO_BYTES 2 +#define RLC_AM_PDU_SEGMENT_SO_OFFSET 0 +#define RLC_AM_PDU_LSF_OFFSET (RLC_AM_PDU_SEGMENT_SO_OFFSET + RLC_AM_PDU_SEGMENT_SO_LENGTH) + +#define RLC_AM_PDU_SET_LSF(px) (RLC_SET_BIT((px),RLC_AM_PDU_LSF_OFFSET)) + +#define RLC_AM_HEADER_LI_LENGTH(li) ((li) + ((li)>>1) + ((li)&1)) +#define RLC_AM_PDU_SEGMENT_HEADER_SIZE(numLis) (RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE + RLC_AM_HEADER_LI_LENGTH(numLis)) + +/* STATUS PDU */ +#define RLC_AM_STATUS_PDU_CPT_STATUS 0 + +#define RLC_AM_STATUS_PDU_CPT_OFFSET 4 +#define RLC_AM_STATUS_PDU_CPT_LENGTH 3 + +#define RLC_AM_STATUS_PDU_ACK_SN_OFFSET 2 + +#define RLC_AM_STATUS_PDU_SO_LENGTH 15 + +#define RLC_AM_STATUS_PDU_SO_END_ALL_BYTES 0x7FFF + + +/* Uplink STATUS PDU trigger events */ +#define RLC_AM_STATUS_NOT_TRIGGERED 0 +#define RLC_AM_STATUS_TRIGGERED_POLL 0x01 /* Status Report is triggered by a received poll */ +#define RLC_AM_STATUS_TRIGGERED_T_REORDERING 0x02 /* Status Report is triggered by Timer Reordering Expiry */ +#define RLC_AM_STATUS_TRIGGERED_DELAYED 0x10 /* Status is delayed until SN(receivedPoll) < VR(MS) */ +#define RLC_AM_STATUS_PROHIBIT 0x20 /* TimerStatusProhibit still running */ +#define RLC_AM_STATUS_NO_TX_MASK (RLC_AM_STATUS_PROHIBIT | RLC_AM_STATUS_TRIGGERED_DELAYED) + +/* Status triggered (bit 5-7) will be concatenated with Poll triggered (bit 0-4) for RLCdec. RLC_AM_STATUS_TRIGGERED_DELAYED is not recorded. */ +#define RLC_AM_SET_STATUS(x,event) (RLC_SET_EVENT(x,event)) +#define RLC_AM_GET_STATUS(x,event) (RLC_GET_EVENT(x,event)) +#define RLC_AM_CLEAR_STATUS(x,event) (RLC_CLEAR_EVENT(x,event)) +#define RLC_AM_CLEAR_ALL_STATUS(x) ((x) = (RLC_AM_STATUS_NOT_TRIGGERED)) + + +#endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h index 42114d4269..602e8e98c2 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h @@ -57,7 +57,6 @@ typedef struct rlc_am_entity_s { boolean_t is_data_plane; /*!< \brief To know if the RLC belongs to a data radio bearer or a signalling radio bearer, for statistics and trace purpose. */ rlc_buffer_occupancy_t sdu_buffer_occupancy; /*!< \brief Number of bytes of unsegmented SDUs. */ - rlc_buffer_occupancy_t retransmission_buffer_occupancy; /*!< \brief Number of bytes of PDUs in retransmission buffer waiting for a ACK. */ rlc_buffer_occupancy_t status_buffer_occupancy; /*!< \brief Number of bytes of control PDUs waiting for transmission. */ rlc_am_control_pdu_info_t control_pdu_info; @@ -69,17 +68,14 @@ typedef struct rlc_am_entity_s { pthread_mutex_t lock_input_sdus; rlc_am_tx_sdu_management_t *input_sdus; /*!< \brief Input SDU buffer (for SDUs coming from upper layers). */ signed int nb_sdu; /*!< \brief Total number of valid rlc_am_tx_sdu_management_t in input_sdus[]. */ - signed int nb_sdu_no_segmented; /*!< \brief Total number of SDUs not segmented and partially segmented. */ + signed int nb_sdu_no_segmented; /*!< \brief Total number of SDUs not segmented and partially segmented. nb_sdu_no_segmented = next_sdu_index - current_sdu_index */ signed int next_sdu_index; /*!< \brief Next SDU index in input_sdus array where for a new incoming SDU. */ - signed int current_sdu_index; /*!< \brief Current SDU index in input_sdus array to be segmented. */ + signed int current_sdu_index; /*!< \brief Current SDU index in input_sdus array to be segmented which is not segmented or partially segmented. */ - rlc_am_tx_data_pdu_management_t *pdu_retrans_buffer; /*!< \brief Retransmission buffer. */ + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer; /*!< \brief Transmission PDU data buffer. Used also for retransmissions */ signed int retrans_num_pdus; /*!< \brief Number of PDUs in the retransmission buffer. */ - signed int retrans_num_bytes; /*!< \brief Number of bytes in the retransmission buffer. */ - signed int retrans_num_bytes_to_retransmit; /*!< \brief Number of bytes in the retransmission buffer to be retransmitted. */ - unsigned int num_nack_so; /*!< \brief Number of segment offsets asked to be retransmitted by peer RLC entity. */ - unsigned int num_nack_sn; /*!< \brief Number of segment asked to be retransmitted by peer RLC entity. */ + signed int retrans_num_bytes_to_retransmit; /*!< \brief Number of bytes in the retransmission buffer to be retransmitted. Only payload is taken into account */ boolean_t force_poll; /*!< \brief force poll due to t_poll_retransmit time-out. */ //--------------------------------------------------------------------- @@ -137,7 +133,7 @@ typedef struct rlc_am_entity_s { //----------------------------- uint16_t max_retx_threshold; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to limit the number of retransmissions of an AMD PDU. */ uint16_t poll_pdu; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to trigger a poll for every pollPDU PDUs. */ - uint16_t poll_byte; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to trigger a poll for every pollByte bytes. */ + uint32_t poll_byte; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to trigger a poll for every pollByte bytes. */ //--------------------------------------------------------------------- // STATISTICS @@ -176,14 +172,14 @@ typedef struct rlc_am_entity_s { //--------------------------------------------------------------------- // OUTPUTS //--------------------------------------------------------------------- - sdu_size_t nb_bytes_requested_by_mac; /*!< \brief Number of bytes requested by lower layer for next transmission. */ + sdu_size_t nb_bytes_requested_by_mac; /*!< \brief Number of remaining bytes available for transmission of any RLC PDU indicated by lower layer */ list_t pdus_to_mac_layer; /*!< \brief PDUs buffered for transmission to MAC layer. */ list_t control_pdu_list; /*!< \brief Control PDUs buffered for transmission to MAC layer. */ - rlc_sn_t first_retrans_pdu_sn; /*!< \brief Lowest sequence number of PDU to be retransmitted. */ list_t segmentation_pdu_list; /*!< \brief List of "freshly" segmented PDUs. */ - boolean_t status_requested; /*!< \brief Status requested by peer. */ - frame_t last_frame_status_indication; /*!< \brief The last frame number a MAC status indication has been received by RLC. */ + uint8_t status_requested; /*!< \brief Status bitmap requested by peer. */ + rlc_sn_t sn_status_triggered_delayed; /*!< \brief SN of the last received poll for which Status is delayed until SN is out of Rx Window. */ + uint32_t last_absolute_subframe_status_indication; /*!< \brief The last absolute subframe number a MAC status indication has been received by RLC. */ //----------------------------- // buffer occupancy measurements sent to MAC //----------------------------- diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c index 0f0b0e75e1..4b5c173d4b 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c @@ -41,21 +41,28 @@ void rlc_am_free_in_sdu( const unsigned int index_in_bufferP) { if (index_in_bufferP <= RLC_AM_SDU_CONTROL_BUFFER_SIZE) { + /* BugFix: SDU shall have been already freed during initial PDU segmentation or concatenation !! */ + AssertFatal(rlcP->input_sdus[index_in_bufferP].mem_block == NULL, "RLC AM Tx SDU Conf: Data Part is not empty index=%d LcId=%d\n", + index_in_bufferP,rlcP->channel_id); + /* if (rlcP->input_sdus[index_in_bufferP].mem_block != NULL) { free_mem_block(rlcP->input_sdus[index_in_bufferP].mem_block, __func__); rlcP->input_sdus[index_in_bufferP].mem_block = NULL; rlcP->nb_sdu_no_segmented -= 1; rlcP->input_sdus[index_in_bufferP].sdu_remaining_size = 0; } + */ rlcP->nb_sdu -= 1; memset(&rlcP->input_sdus[index_in_bufferP], 0, sizeof(rlc_am_tx_sdu_management_t)); rlcP->input_sdus[index_in_bufferP].flags.transmitted_successfully = 1; + // case when either one SDU needs to be removed from segmentation or SDU buffer is full if (rlcP->current_sdu_index == index_in_bufferP) { rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE; } + // wrapping and reset current_sdu_index to next_sdu_index when all transmitted SDUs have been acknowledged while ((rlcP->current_sdu_index != rlcP->next_sdu_index) && (rlcP->input_sdus[rlcP->current_sdu_index].flags.transmitted_successfully == 1)) { rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE; @@ -100,3 +107,41 @@ rlc_am_in_sdu_is_empty( return 0; } + +// called when PDU is ACKED +//----------------------------------------------------------------------------- +void +rlc_am_pdu_sdu_data_cnf( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t* const rlc_pP, + const rlc_sn_t snP) +{ + int pdu_sdu_index; + int sdu_index; + + for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE].nb_sdus; pdu_sdu_index++) { + sdu_index = rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE].sdus_index[pdu_sdu_index]; + assert(sdu_index >= 0); + assert(sdu_index < RLC_AM_SDU_CONTROL_BUFFER_SIZE); + rlc_pP->input_sdus[sdu_index].nb_pdus_ack += 1; + + if ((rlc_pP->input_sdus[sdu_index].nb_pdus_ack == rlc_pP->input_sdus[sdu_index].nb_pdus) && + (rlc_pP->input_sdus[sdu_index].sdu_remaining_size == 0)) { + #if TEST_RLC_AM + rlc_am_v9_3_0_test_data_conf ( + rlc_pP->module_id, + rlc_pP->rb_id, + rlc_pP->input_sdus[sdu_index].mui, + RLC_SDU_CONFIRM_YES); + #else + rlc_data_conf( + ctxt_pP, + rlc_pP->rb_id, + rlc_pP->input_sdus[sdu_index].mui, + RLC_SDU_CONFIRM_YES, + rlc_pP->is_data_plane); + #endif + rlc_am_free_in_sdu(ctxt_pP, rlc_pP, sdu_index); + } + } +} diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h index 3201dfc941..c596bc671a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h @@ -77,5 +77,13 @@ protected_rlc_am_in_sdu(void rlc_am_free_in_sdu_data (const protocol_ctxt_t* con * \return 1 if the buffer is empty, else 0. */ protected_rlc_am_in_sdu(signed int rlc_am_in_sdu_is_empty(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *rlcP);) + +/*! \fn void rlc_am_pdu_sdu_data_cnf(const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t* const rlc_pP,const rlc_sn_t snP) +* \brief Process SDU cnf of a ACKED PDU for all SDUs concatenated in this PDU. +* \param[in] ctxtP Running context. +* \param[in] rlcP RLC AM protocol instance pointer. +* \param[in] snP Sequence number of the PDU. +*/ +protected_rlc_am_in_sdu(void rlc_am_pdu_sdu_data_cnf(const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t* const rlc_pP,const rlc_sn_t snP);) /** @} */ # endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c index cb03e28c4b..129d4ffb0f 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c @@ -51,16 +51,16 @@ rlc_am_init( pthread_mutex_init(&rlc_pP->lock_input_sdus, NULL); rlc_pP->input_sdus = calloc(1, RLC_AM_SDU_CONTROL_BUFFER_SIZE*sizeof(rlc_am_tx_sdu_management_t)); //#warning "cast the rlc retrans buffer to uint32" - // rlc_pP->pdu_retrans_buffer = calloc(1, (uint16_t)((unsigned int)RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE*(unsigned int)sizeof(rlc_am_tx_data_pdu_management_t))); - rlc_pP->pdu_retrans_buffer = calloc(1, (uint32_t)((unsigned int)RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE*(unsigned int)sizeof( + // rlc_pP->tx_data_pdu_buffer = calloc(1, (uint16_t)((unsigned int)RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE*(unsigned int)sizeof(rlc_am_tx_data_pdu_management_t))); + rlc_pP->tx_data_pdu_buffer = calloc(1, (uint32_t)((unsigned int)RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE*(unsigned int)sizeof( rlc_am_tx_data_pdu_management_t))); LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[AM INIT] input_sdus[] = %p element size=%zu\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->input_sdus, sizeof(rlc_am_tx_sdu_management_t)); - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[AM INIT] pdu_retrans_buffer[] = %p element size=%zu\n", + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[AM INIT] tx_data_pdu_buffer[] = %p element size=%zu\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->pdu_retrans_buffer, + rlc_pP->tx_data_pdu_buffer, sizeof(rlc_am_tx_data_pdu_management_t)); // TX state variables @@ -74,12 +74,12 @@ rlc_am_init( // RX state variables //rlc_pP->vr_r = 0; rlc_pP->vr_mr = rlc_pP->vr_r + RLC_AM_WINDOW_SIZE; - //rlc_pP->vr_x = 0; + rlc_pP->vr_x = RLC_SN_UNDEFINED; //rlc_pP->vr_ms = 0; //rlc_pP->vr_h = 0; + rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; - rlc_pP->last_frame_status_indication = 123456; // any value > 1 - rlc_pP->first_retrans_pdu_sn = -1; + rlc_pP->last_absolute_subframe_status_indication = 0xFFFFFFFF; // any value > 1 rlc_pP->initialized = TRUE; } @@ -128,12 +128,13 @@ rlc_am_reestablish( // RX state variables rlc_pP->vr_r = 0; rlc_pP->vr_mr = rlc_pP->vr_r + RLC_AM_WINDOW_SIZE; - rlc_pP->vr_x = 0; + rlc_pP->vr_x = RLC_SN_UNDEFINED; rlc_pP->vr_ms = 0; rlc_pP->vr_h = 0; + rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; + rlc_pP->status_requested = RLC_AM_STATUS_NOT_TRIGGERED; - rlc_pP->last_frame_status_indication = 123456; // any value > 1 - rlc_pP->first_retrans_pdu_sn = -1; + rlc_pP->last_absolute_subframe_status_indication = 0xFFFFFFFF; // any value > 1 rlc_pP->initialized = TRUE; @@ -172,16 +173,16 @@ rlc_am_cleanup( pthread_mutex_destroy(&rlc_pP->lock_input_sdus); - if (rlc_pP->pdu_retrans_buffer != NULL) { + if (rlc_pP->tx_data_pdu_buffer != NULL) { for (i=0; i < RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE; i++) { - if (rlc_pP->pdu_retrans_buffer[i].mem_block != NULL) { - free_mem_block(rlc_pP->pdu_retrans_buffer[i].mem_block, __func__); - rlc_pP->pdu_retrans_buffer[i].mem_block = NULL; + if (rlc_pP->tx_data_pdu_buffer[i % RLC_AM_WINDOW_SIZE].mem_block != NULL) { + free_mem_block(rlc_pP->tx_data_pdu_buffer[i % RLC_AM_WINDOW_SIZE].mem_block, __func__); + rlc_pP->tx_data_pdu_buffer[i % RLC_AM_WINDOW_SIZE].mem_block = NULL; } } - free(rlc_pP->pdu_retrans_buffer); - rlc_pP->pdu_retrans_buffer = NULL; + free(rlc_pP->tx_data_pdu_buffer); + rlc_pP->tx_data_pdu_buffer = NULL; } memset(rlc_pP, 0, sizeof(rlc_am_entity_t)); diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c index 873e51fbfe..4202443a5a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c @@ -91,7 +91,7 @@ rlc_am_send_sdu ( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlc_pP) { -# if TRACE_RLC_UM_PDU +# if TRACE_RLC_AM_PDU char message_string[7000]; size_t message_string_size = 0; #if ENABLE_ITTI @@ -212,7 +212,8 @@ void rlc_am_reassemble_pdu( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlc_pP, - mem_block_t * const tb_pP) + mem_block_t * const tb_pP, + boolean_t free_rlc_pdu) { int i,j; @@ -397,5 +398,7 @@ rlc_am_reassemble_pdu( } } - free_mem_block(tb_pP, __func__); + if (free_rlc_pdu) { + free_mem_block(tb_pP, __func__); + } } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h index fece9ae570..4b780ce441 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h @@ -72,13 +72,14 @@ private_rlc_am_reassembly( void rlc_am_reassembly (const protocol_ctxt_t* co */ private_rlc_am_reassembly( void rlc_am_send_sdu (const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP);) -/*! \fn void rlc_am_reassemble_pdu(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, const mem_block_t* const tb_pP) +/*! \fn void rlc_am_reassemble_pdu(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, const mem_block_t* const tb_pP,boolean_t free_rlc_pdu) * \brief Reassembly a RLC AM PDU, depending of the content of this PDU, data will be reassemblied to the current output SDU, the current will be sent to higher layers or not, after or before the reassembly, or no send of SDU will be triggered, depending on FI field in PDU header. * \param[in] ctxtP Running context. * \param[in] rlc_pP RLC AM protocol instance pointer. * \param[in] tb_pP RLC AM PDU embedded in a mem_block_t. +* \param[in] free_rlc_pdu Flag for freeing RLC AM PDU after reassembly. */ -protected_rlc_am_reassembly( void rlc_am_reassemble_pdu(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, mem_block_t* const tb_pP);) +protected_rlc_am_reassembly( void rlc_am_reassemble_pdu(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, mem_block_t* const tb_pP,boolean_t free_rlc_pdu);) /** @} */ #endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c index d783684893..d2a5cc985e 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c @@ -31,6 +31,7 @@ #include "LAYER2/MAC/extern.h" #include "UTIL/LOG/log.h" + //----------------------------------------------------------------------------- signed int rlc_am_get_data_pdu_infos( @@ -40,14 +41,15 @@ rlc_am_get_data_pdu_infos( int16_t total_sizeP, rlc_am_pdu_info_t* pdu_info_pP) { - memset(pdu_info_pP, 0, sizeof (rlc_am_pdu_info_t)); + memset(pdu_info_pP, 0, sizeof (rlc_am_pdu_info_t)); - int16_t sum_li = 0; - pdu_info_pP->d_c = header_pP->b1 >> 7; - pdu_info_pP->num_li = 0; + int16_t sum_li = 0; + pdu_info_pP->d_c = header_pP->b1 >> 7; + pdu_info_pP->num_li = 0; - if (pdu_info_pP->d_c) { + AssertFatal (pdu_info_pP->d_c != 0, "RLC AM Rx PDU Data D/C Header Error LcId=%d\n", rlc_pP->channel_id); + pdu_info_pP->rf = (header_pP->b1 >> 6) & 0x01; pdu_info_pP->p = (header_pP->b1 >> 5) & 0x01; pdu_info_pP->fi = (header_pP->b1 >> 3) & 0x03; @@ -117,12 +119,6 @@ rlc_am_get_data_pdu_infos( } return 0; - } else { - LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[GET DATA PDU INFO] SN %04d ERROR CONTROL PDU ", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - pdu_info_pP->sn); - return -1; - } } //----------------------------------------------------------------------------- void @@ -181,26 +177,22 @@ rlc_am_rx_update_vr_ms( do { pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; - if (((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received == 0) { + if ((((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received == 0) || + (rlc_pP->vr_ms != pdu_info_cursor_p->sn)) { + #if TRACE_RLC_AM_RX LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[UPDATE VR(MS)] UPDATED VR(MS) %04d -> %04d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->vr_ms, pdu_info_cursor_p->sn); #endif - rlc_pP->vr_ms = pdu_info_cursor_p->sn; + return; } + rlc_pP->vr_ms = RLC_AM_NEXT_SN(pdu_info_cursor_p->sn); cursor_p = cursor_p->next; - } while (cursor_p != NULL); + } while ((cursor_p != NULL) && (rlc_pP->vr_ms != rlc_pP->vr_h)); -#if TRACE_RLC_AM_RX - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[UPDATE VR(MS)] UPDATED VR(MS) %04d -> %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->vr_ms, - (pdu_info_cursor_p->sn + 1) & RLC_AM_SN_MASK); -#endif - rlc_pP->vr_ms = (pdu_info_cursor_p->sn + 1) & RLC_AM_SN_MASK; } } // assumed the sn of the tb_p is equal to VR(R) @@ -322,34 +314,30 @@ rlc_am_receive_process_data_pdu ( // - discard the duplicate byte segments. rlc_am_pdu_info_t* pdu_info_p = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info; rlc_am_pdu_sn_10_t* rlc_am_pdu_sn_10_p = (rlc_am_pdu_sn_10_t*)first_byte_pP; + rlc_am_rx_pdu_status_t pdu_status = RLC_AM_DATA_PDU_STATUS_OK; + boolean_t reassemble = false; if (rlc_am_get_data_pdu_infos(ctxt_pP,rlc_pP, rlc_am_pdu_sn_10_p, tb_size_in_bytesP, pdu_info_p) >= 0) { ((rlc_am_rx_pdu_management_t*)(tb_pP->data))->all_segments_received = 0; - if (rlc_am_in_rx_window(ctxt_pP, rlc_pP, pdu_info_p->sn)) { + if (RLC_AM_SN_IN_WINDOW(pdu_info_p->sn, rlc_pP->vr_r)) { - if (pdu_info_p->p) { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] POLL BIT SET, STATUS REQUESTED:\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); - rlc_pP->status_requested = 1; - } - - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] VR(R) %04d VR(H) %04d VR(MR) %04d VR(MS) %04d VR(X) %04d\n", + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SN=%04d] VR(R) %04d VR(H) %04d VR(MR) %04d VR(MS) %04d VR(X) %04d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + pdu_info_p->sn, rlc_pP->vr_r, rlc_pP->vr_h, rlc_pP->vr_mr, rlc_pP->vr_ms, rlc_pP->vr_x); - if (rlc_am_rx_list_insert_pdu(ctxt_pP, rlc_pP,tb_pP) < 0) { + pdu_status = rlc_am_rx_list_check_duplicate_insert_pdu(ctxt_pP, rlc_pP,tb_pP); + if (pdu_status != RLC_AM_DATA_PDU_STATUS_OK) { rlc_pP->stat_rx_data_pdu_dropped += 1; rlc_pP->stat_rx_data_bytes_dropped += tb_size_in_bytesP; - free_mem_block (tb_pP, __func__); - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU DISCARDED, STATUS REQUESTED:\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); - rlc_pP->status_requested = 1; + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU DISCARDED CAUSE=%d SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_status,pdu_info_p->sn); #if RLC_STOP_ON_LOST_PDU AssertFatal( 0 == 1, PROTOCOL_RLC_AM_CTXT_FMT" LOST PDU DETECTED\n", @@ -394,12 +382,15 @@ rlc_am_receive_process_data_pdu ( rlc_am_rx_list_display(rlc_pP, "rlc_am_receive_process_data_pdu AFTER INSERTION "); #endif - if (rlc_am_sn_gte_vr_h(ctxt_pP, rlc_pP, pdu_info_p->sn) > 0) { - rlc_pP->vr_h = (pdu_info_p->sn + 1) & RLC_AM_SN_MASK; + /* 1) Update vrH if sn >= vrH */ + if (RLC_AM_DIFF_SN(pdu_info_p->sn,rlc_pP->vr_r) >= RLC_AM_DIFF_SN(rlc_pP->vr_h,rlc_pP->vr_r)) + { + rlc_pP->vr_h = RLC_AM_NEXT_SN(pdu_info_p->sn); } rlc_am_rx_check_all_byte_segments(ctxt_pP, rlc_pP, tb_pP); + /* 2) Reordering Window Processing: Update vr_ms if sn = vr_ms and all bytes received for sn */ if ((pdu_info_p->sn == rlc_pP->vr_ms) && (((rlc_am_rx_pdu_management_t*)(tb_pP->data))->all_segments_received)) { rlc_am_rx_update_vr_ms(ctxt_pP, rlc_pP, tb_pP); } @@ -410,39 +401,114 @@ rlc_am_receive_process_data_pdu ( rlc_pP->vr_mr = (rlc_pP->vr_r + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK; } - rlc_am_rx_list_reassemble_rlc_sdus(ctxt_pP, rlc_pP); + reassemble = rlc_am_rx_check_vr_reassemble(ctxt_pP, rlc_pP); + //TODO : optimization : check whether a reassembly is needed by looking at LI, FI, SO, etc... + } //FNA: fix check VrX out of receiving window - if (rlc_pP->t_reordering.running) { - if ((rlc_pP->vr_x == rlc_pP->vr_r) || ((rlc_am_in_rx_window(ctxt_pP, rlc_pP, rlc_pP->vr_x) == 0) && (rlc_pP->vr_x != rlc_pP->vr_mr))) { + if ((rlc_pP->t_reordering.running) || ((rlc_pP->t_reordering.ms_duration == 0) && (rlc_pP->vr_x != RLC_SN_UNDEFINED))) { + if ((rlc_pP->vr_x == rlc_pP->vr_r) || (!(RLC_AM_SN_IN_WINDOW(rlc_pP->vr_x, rlc_pP->vr_r)) && (rlc_pP->vr_x != rlc_pP->vr_mr))) { rlc_am_stop_and_reset_timer_reordering(ctxt_pP, rlc_pP); + rlc_pP->vr_x = RLC_SN_UNDEFINED; } } if (!(rlc_pP->t_reordering.running)) { if (rlc_pP->vr_h != rlc_pP->vr_r) { // - if VR (H) > VR(R) translated to - if VR (H) != VR(R) - rlc_am_start_timer_reordering(ctxt_pP, rlc_pP); rlc_pP->vr_x = rlc_pP->vr_h; + if (rlc_pP->t_reordering.ms_duration != 0) { + rlc_am_start_timer_reordering(ctxt_pP, rlc_pP); + } + else { + /* specific case for no timer reordering configured */ + /* reordering window directly advances with vrH */ + rlc_pP->vr_ms = rlc_pP->vr_h; + + /* Trigger a Status and clear any existing Delay Flag */ + RLC_AM_SET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_T_REORDERING); + RLC_AM_CLEAR_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED); + rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; + } } } } - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] VR(R) %04d VR(H) %04d VR(MS) %04d VR(MR) %04d\n", + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SN=%04d] NEW VR(R) %04d VR(H) %04d VR(MS) %04d VR(MR) %04d VR(X) %04d reassemble=%d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + pdu_info_p->sn, rlc_pP->vr_r, rlc_pP->vr_h, rlc_pP->vr_ms, - rlc_pP->vr_mr); + rlc_pP->vr_mr, + rlc_pP->vr_x, + reassemble); } else { rlc_pP->stat_rx_data_pdu_out_of_window += 1; rlc_pP->stat_rx_data_bytes_out_of_window += tb_size_in_bytesP; - free_mem_block (tb_pP, __func__); - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU OUT OF RX WINDOW, DISCARDED, STATUS REQUESTED:\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); - rlc_pP->status_requested = 1; + pdu_status = RLC_AM_DATA_PDU_STATUS_SN_OUTSIDE_WINDOW; + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU OUT OF RX WINDOW, DISCARDED, SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_info_p->sn); } + + /* 3) Check for triggering a Tx Status PDU if a poll is received or if a pending status was delayed */ + if ((pdu_info_p->p) && (pdu_status < RLC_AM_DATA_PDU_STATUS_BUFFER_FULL)) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] POLL BIT SET, STATUS REQUESTED:\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); + + /* Polling Info Saving for In and Out of Window PDU */ + /* avoid multi status trigger */ + if ((RLC_AM_GET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED)) || + !(RLC_AM_GET_STATUS(rlc_pP->status_requested,(RLC_AM_STATUS_TRIGGERED_POLL | RLC_AM_STATUS_TRIGGERED_T_REORDERING)))) + { + RLC_AM_SET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_POLL); + + if ((pdu_status != RLC_AM_DATA_PDU_STATUS_OK) || ((pdu_status == RLC_AM_DATA_PDU_STATUS_OK) && + (!(RLC_AM_SN_IN_WINDOW(pdu_info_p->sn,rlc_pP->vr_r)) || + (RLC_AM_DIFF_SN(pdu_info_p->sn,rlc_pP->vr_r) < RLC_AM_DIFF_SN(rlc_pP->vr_ms,rlc_pP->vr_r))) + ) + ) + { + /* Conditions are met for sending a Status Report */ + /* Then clear Delay Flag and reset its corresponding sn */ + RLC_AM_CLEAR_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED); + rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; + } + else if (rlc_pP->sn_status_triggered_delayed == RLC_SN_UNDEFINED) + { + /* Delay status trigger if pdustatus OK and sn>= vr_ms */ + /* Note: vr_r and vr_ms have been updated */ + RLC_AM_SET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED); + rlc_pP->sn_status_triggered_delayed = pdu_info_p->sn; + } + } + } + + /* ReEnable a previously delayed Status Trigger if PDU discarded or */ + /* sn no more in RxWindow due to RxWindow advance or sn < vr_ms */ + if ((RLC_AM_GET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED)) && + (pdu_status == RLC_AM_DATA_PDU_STATUS_OK) && + (!(RLC_AM_SN_IN_WINDOW(rlc_pP->sn_status_triggered_delayed,rlc_pP->vr_r)) || + (RLC_AM_DIFF_SN(rlc_pP->sn_status_triggered_delayed,rlc_pP->vr_r) < RLC_AM_DIFF_SN(rlc_pP->vr_ms,rlc_pP->vr_r))) + ) + { + RLC_AM_CLEAR_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED); + rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; + } + + } else { - free_mem_block (tb_pP, __func__); + pdu_status = RLC_AM_DATA_PDU_STATUS_HEADER_ERROR; + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU DISCARDED BAD HEADER FORMAT SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_info_p->sn); + } + + if (pdu_status != RLC_AM_DATA_PDU_STATUS_OK) { + /* Discard received block if out of window, duplicate or header error */ + free_mem_block (tb_pP, __func__); + } + else if (reassemble) { + /* Reassemble SDUs */ + rlc_am_rx_list_reassemble_rlc_sdus(ctxt_pP, rlc_pP); } } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index 7fb801b33d..f80a46695d 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -30,12 +30,13 @@ #include "UTIL/LOG/log.h" #include "msc.h" //----------------------------------------------------------------------------- -void rlc_am_nack_pdu ( +boolean_t rlc_am_nack_pdu ( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlc_pP, const rlc_sn_t snP, - const sdu_size_t so_startP, - const sdu_size_t so_endP) + const rlc_sn_t prev_nack_snP, + sdu_size_t so_startP, + sdu_size_t so_endP) { // 5.2.1 Retransmission // ... @@ -50,55 +51,124 @@ void rlc_am_nack_pdu ( // - indicate to upper layers that max retransmission has been reached. - mem_block_t* mb_p = rlc_pP->pdu_retrans_buffer[snP].mem_block; - int pdu_sdu_index; - int sdu_index; + mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE].mem_block; + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE]; + //int pdu_sdu_index; + //int sdu_index; + boolean_t status = TRUE; + boolean_t retx_count_increment = FALSE; + sdu_size_t pdu_data_to_retx = 0; if (mb_p != NULL) { - rlc_pP->num_nack_sn += 1; assert(so_startP <= so_endP); - //----------------------------------------- - // allow holes in reports - // it is assumed that hole reports are done in byte offset - // increasing order among calls refering to only one status PDU - // and among time - //----------------------------------------- - if (rlc_pP->pdu_retrans_buffer[snP].last_nack_time != ctxt_pP->frame) { - rlc_pP->pdu_retrans_buffer[snP].last_nack_time = ctxt_pP->frame; - rlc_am_clear_holes(ctxt_pP, rlc_pP, snP); + // Handle full PDU NACK first + if ((so_startP == 0) && (so_endP == 0x7FFF)) { + if ((prev_nack_snP != snP) && (tx_data_pdu_buffer_p->flags.ack == 0) && (tx_data_pdu_buffer_p->flags.max_retransmit == 0)) { + pdu_data_to_retx = tx_data_pdu_buffer_p->payload_size; + /* Increment VtReTxNext if this is the first NACK or if some segments have already been transmitted */ + if ((tx_data_pdu_buffer_p->flags.retransmit == 0) || (tx_data_pdu_buffer_p->nack_so_start)) + { + retx_count_increment = TRUE; + } + + tx_data_pdu_buffer_p->nack_so_start = 0; + tx_data_pdu_buffer_p->num_holes = 0; + tx_data_pdu_buffer_p->retx_hole_index = 0; + tx_data_pdu_buffer_p->nack_so_stop = tx_data_pdu_buffer_p->payload_size - 1; + #if TRACE_RLC_AM_HOLE + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] SN %04d GLOBAL NACK 0->%05d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + snP, + so_stopP); + #endif + assert(tx_data_pdu_buffer_p->nack_so_start < tx_data_pdu_buffer_p->payload_size); + } + else { + status = FALSE; + } + } + else if (tx_data_pdu_buffer_p->flags.max_retransmit == 0) { + // Handle Segment offset + if (so_endP == 0x7FFF) { + so_endP = tx_data_pdu_buffer_p->payload_size - 1; + } + + // Check consistency + if ((so_startP <= so_endP) && (so_endP < tx_data_pdu_buffer_p->payload_size)) { + if (prev_nack_snP != snP) { + /* New NACK_SN with SO */ + /* check whether a new segment is to be placed in Retransmission Buffer, then increment vrReTx */ + if ((tx_data_pdu_buffer_p->flags.retransmit == 0) || (so_startP < tx_data_pdu_buffer_p->nack_so_start)) { + retx_count_increment = TRUE; + } + + tx_data_pdu_buffer_p->num_holes = 1; + tx_data_pdu_buffer_p->retx_hole_index = 0; + tx_data_pdu_buffer_p->hole_so_start[0] = so_startP; + tx_data_pdu_buffer_p->hole_so_stop[0] = so_endP; + tx_data_pdu_buffer_p->nack_so_start = so_startP; + tx_data_pdu_buffer_p->nack_so_stop = so_endP; + pdu_data_to_retx = so_endP - so_startP + 1; + + } + else if ((tx_data_pdu_buffer_p->num_holes) && (tx_data_pdu_buffer_p->num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU)) { + /* New SOStart/SOEnd for the same NACK_SN than before */ + /* check discontinuity */ + if (so_startP > tx_data_pdu_buffer_p->hole_so_stop[tx_data_pdu_buffer_p->num_holes - 1]) { + tx_data_pdu_buffer_p->hole_so_start[tx_data_pdu_buffer_p->num_holes] = so_startP; + tx_data_pdu_buffer_p->hole_so_stop[tx_data_pdu_buffer_p->num_holes] = so_endP; + tx_data_pdu_buffer_p->nack_so_stop = so_endP; + tx_data_pdu_buffer_p->num_holes ++; + pdu_data_to_retx = so_endP - so_startP + 1; + } + else { + status = FALSE; + } + } + else { + status = FALSE; + } + } + else { + status = FALSE; + } + } + else { + status = FALSE; } - if (!((so_startP == 0) && (so_endP == 0x7FFF))) { - rlc_pP->num_nack_so += 1; + if (status) { + tx_data_pdu_buffer_p->flags.nack = 1; + if ((retx_count_increment) && (tx_data_pdu_buffer_p->retx_count == tx_data_pdu_buffer_p->retx_count_next)) { + tx_data_pdu_buffer_p->retx_count_next ++; + } + if (tx_data_pdu_buffer_p->flags.retransmit == 1) { + if (prev_nack_snP != snP) { + /* if first process of this NACK_SN and data already pending for retx */ + rlc_pP->retrans_num_bytes_to_retransmit += (pdu_data_to_retx - tx_data_pdu_buffer_p->retx_payload_size); + tx_data_pdu_buffer_p->retx_payload_size = pdu_data_to_retx; + } + else if (tx_data_pdu_buffer_p->num_holes > 1) { + /* Segment case : SOStart and SOEnd already received for same NACK_SN */ + /* filter case where a NACK_SN is received twice with SO first time and no SO second time */ + rlc_pP->retrans_num_bytes_to_retransmit += pdu_data_to_retx; + tx_data_pdu_buffer_p->retx_payload_size += pdu_data_to_retx; + } + } + else { + tx_data_pdu_buffer_p->flags.retransmit = 1; + rlc_pP->retrans_num_bytes_to_retransmit += pdu_data_to_retx; + tx_data_pdu_buffer_p->retx_payload_size = pdu_data_to_retx; + rlc_pP->retrans_num_pdus ++; + } } - rlc_am_add_hole(ctxt_pP, rlc_pP, snP, so_startP, so_endP); - - if (rlc_pP->first_retrans_pdu_sn < 0) { - rlc_pP->first_retrans_pdu_sn = snP; - } else if (rlc_am_tx_sn1_gt_sn2(ctxt_pP, rlc_pP, rlc_pP->first_retrans_pdu_sn, snP)) { - rlc_pP->first_retrans_pdu_sn = snP; - } - - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[NACK-PDU] NACK PDU SN %04d previous retx_count %d 1ST_RETRANS_PDU %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - snP, - rlc_pP->pdu_retrans_buffer[snP].retx_count, - rlc_pP->first_retrans_pdu_sn); - - rlc_pP->pdu_retrans_buffer[snP].flags.retransmit = 1; - - if (rlc_pP->pdu_retrans_buffer[snP].retx_count == -1) { - rlc_pP->pdu_retrans_buffer[snP].retx_count = 0; - rlc_pP->retrans_num_bytes_to_retransmit += rlc_pP->pdu_retrans_buffer[snP].header_and_payload_size; - } else { - rlc_pP->pdu_retrans_buffer[snP].retx_count += 1; - } - - if (rlc_pP->pdu_retrans_buffer[snP].retx_count >= rlc_pP->max_retx_threshold) { - for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->pdu_retrans_buffer[snP].nb_sdus; pdu_sdu_index++) { - sdu_index = rlc_pP->pdu_retrans_buffer[snP].sdus_index[pdu_sdu_index]; + /* TODO: Move this part in UL SCH processing */ +#if 0 + if (rlc_pP->tx_data_pdu_buffer[snP].retx_count >= rlc_pP->max_retx_threshold) { + for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->tx_data_pdu_buffer[snP].nb_sdus; pdu_sdu_index++) { + sdu_index = rlc_pP->tx_data_pdu_buffer[snP].sdus_index[pdu_sdu_index]; assert(pdu_sdu_index < RLC_AM_MAX_SDU_IN_PDU); assert(sdu_index < RLC_AM_SDU_CONTROL_BUFFER_SIZE); rlc_pP->input_sdus[sdu_index].nb_pdus_ack += 1; @@ -122,12 +192,15 @@ void rlc_am_nack_pdu ( } } } +#endif } else { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[NACK-PDU] ERROR NACK MISSING PDU SN %05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP); - //assert(2==3); + status = FALSE; } + + return status; } //----------------------------------------------------------------------------- void rlc_am_ack_pdu ( @@ -135,100 +208,27 @@ void rlc_am_ack_pdu ( rlc_am_entity_t *const rlc_pP, const rlc_sn_t snP) { - mem_block_t* mb_p = rlc_pP->pdu_retrans_buffer[snP].mem_block; - int pdu_sdu_index; - int sdu_index; + mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE].mem_block; + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE]; - rlc_pP->pdu_retrans_buffer[snP].flags.retransmit = 0; + tx_data_pdu_buffer->flags.retransmit = 0; - if ((rlc_pP->pdu_retrans_buffer[snP].flags.ack == 0) && (mb_p != NULL)) { + if ((tx_data_pdu_buffer->flags.ack == 0) && (mb_p != NULL)) { //if (mb_pP != NULL) { free_mem_block(mb_p, __func__); - rlc_pP->pdu_retrans_buffer[snP].mem_block = NULL; + tx_data_pdu_buffer->mem_block = NULL; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] ACK PDU SN %05d previous retx_count %d \n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, - rlc_pP->pdu_retrans_buffer[snP].retx_count); - rlc_pP->retrans_num_pdus -= 1; - rlc_pP->retrans_num_bytes -= rlc_pP->pdu_retrans_buffer[snP].header_and_payload_size; + tx_data_pdu_buffer->retx_count); - if (rlc_pP->pdu_retrans_buffer[snP].retx_count >= 0) { - rlc_pP->retrans_num_bytes_to_retransmit -= rlc_pP->pdu_retrans_buffer[snP].header_and_payload_size; + if (tx_data_pdu_buffer->retx_payload_size) { + rlc_pP->retrans_num_bytes_to_retransmit -= tx_data_pdu_buffer->retx_payload_size; + tx_data_pdu_buffer->retx_payload_size = 0; + tx_data_pdu_buffer->num_holes = 0; + rlc_pP->retrans_num_pdus --; } - for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->pdu_retrans_buffer[snP].nb_sdus; pdu_sdu_index++) { - sdu_index = rlc_pP->pdu_retrans_buffer[snP].sdus_index[pdu_sdu_index]; - assert(sdu_index >= 0); - assert(sdu_index < RLC_AM_SDU_CONTROL_BUFFER_SIZE); - rlc_pP->input_sdus[sdu_index].nb_pdus_ack += 1; - - if ((rlc_pP->input_sdus[sdu_index].nb_pdus_ack == rlc_pP->input_sdus[sdu_index].nb_pdus) && - (rlc_pP->input_sdus[sdu_index].sdu_remaining_size == 0)) { -#if TEST_RLC_AM - rlc_am_v9_3_0_test_data_conf ( - rlc_pP->module_id, - rlc_pP->rb_id, - rlc_pP->input_sdus[sdu_index].mui, - RLC_SDU_CONFIRM_YES); -#else - rlc_data_conf( - ctxt_pP, - rlc_pP->rb_id, - rlc_pP->input_sdus[sdu_index].mui, - RLC_SDU_CONFIRM_YES, - rlc_pP->is_data_plane); -#endif - rlc_am_free_in_sdu(ctxt_pP, rlc_pP, sdu_index); - } - } - - // 7.1... - // VT(A) – Acknowledgement state variable - // This state variable holds the value of the SN of the next AMD PDU for which a positive acknowledgment is to be - // received in-sequence, and it serves as the lower edge of the transmitting window. It is initially set to 0, and is updated - // whenever the AM RLC entity receives a positive acknowledgment for an AMD PDU with SN = VT(A). - rlc_pP->pdu_retrans_buffer[snP].flags.ack = 1; - - if (snP == rlc_pP->vt_a) { - //rlc_pP->pdu_retrans_buffer[snP].flags.ack = 1; - do { - memset(&rlc_pP->pdu_retrans_buffer[rlc_pP->vt_a], 0, sizeof(rlc_am_tx_data_pdu_management_t)); - - if (rlc_pP->vt_a == rlc_pP->first_retrans_pdu_sn) { - rlc_pP->first_retrans_pdu_sn = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK; - } - - rlc_pP->vt_a = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK; - } while ((rlc_pP->pdu_retrans_buffer[rlc_pP->vt_a].flags.ack == 1) && (rlc_pP->vt_a != rlc_pP->vt_s)); - - - rlc_pP->vt_ms = (rlc_pP->vt_a + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK; - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED VT(A) %04d VT(MS) %04d VT(S) %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->vt_a, - rlc_pP->vt_ms, - rlc_pP->vt_s); - } - - if (snP == rlc_pP->first_retrans_pdu_sn) { - do { - rlc_pP->first_retrans_pdu_sn = (rlc_pP->first_retrans_pdu_sn + 1) & RLC_AM_SN_MASK; - - if (rlc_pP->pdu_retrans_buffer[rlc_pP->first_retrans_pdu_sn].retx_count >= 0) { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED first_retrans_pdu_sn -> %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn); - break; - } - } while (rlc_pP->first_retrans_pdu_sn != rlc_pP->vt_s); - - if (rlc_pP->vt_s == rlc_pP->first_retrans_pdu_sn) { - rlc_pP->first_retrans_pdu_sn = -1; - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED first_retrans_pdu_sn -> %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn); - } - } } else { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] WARNING ACK PDU SN %05d -> NO PDU TO ACK\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -236,31 +236,13 @@ void rlc_am_ack_pdu ( if (mb_p != NULL) { free_mem_block(mb_p, __func__); - rlc_pP->pdu_retrans_buffer[snP].mem_block = NULL; - } - - if (rlc_pP->pdu_retrans_buffer[snP].flags.ack > 0) { - if (snP == rlc_pP->vt_a) { - //rlc_pP->pdu_retrans_buffer[snP].flags.ack = 1; - do { - memset(&rlc_pP->pdu_retrans_buffer[rlc_pP->vt_a], 0, sizeof(rlc_am_tx_data_pdu_management_t)); - - if (rlc_pP->vt_a == rlc_pP->first_retrans_pdu_sn) { - rlc_pP->first_retrans_pdu_sn = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK; - } - - rlc_pP->vt_a = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK; - } while ((rlc_pP->pdu_retrans_buffer[rlc_pP->vt_a].flags.ack == 1) && (rlc_pP->vt_a != rlc_pP->vt_s)); - - rlc_pP->vt_ms = (rlc_pP->vt_a + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK; - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED VT(A) %04d VT(MS) %04d VT(S) %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->vt_a, - rlc_pP->vt_ms, - rlc_pP->vt_s); - } + tx_data_pdu_buffer->mem_block = NULL; } } + tx_data_pdu_buffer->flags.ack = 1; + tx_data_pdu_buffer->flags.transmitted = 0; + tx_data_pdu_buffer->flags.retransmit = 0; + } //----------------------------------------------------------------------------- mem_block_t* rlc_am_retransmit_get_copy ( @@ -268,27 +250,414 @@ mem_block_t* rlc_am_retransmit_get_copy ( rlc_am_entity_t *const rlc_pP, const rlc_sn_t snP) { - mem_block_t* mb_original_p = rlc_pP->pdu_retrans_buffer[snP].mem_block; + mem_block_t* mb_original_p = rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE].mem_block; - if (mb_original_p != NULL) { + AssertFatal (mb_original_p != NULL, "RLC AM PDU Copy Error: Empty block sn=%d vtA=%d vtS=%d LcId=%d !\n", + snP,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); - rlc_am_tx_data_pdu_management_t *pdu_mngt = &rlc_pP->pdu_retrans_buffer[snP % RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE]; + rlc_am_tx_data_pdu_management_t *pdu_mngt = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE]; - int size = pdu_mngt->header_and_payload_size + sizeof(struct mac_tb_req); - mem_block_t* mb_copy = get_free_mem_block(size, __func__); - memcpy(mb_copy->data, mb_original_p->data, size); + /* We need to allocate a new buffer and copy to it because header content may change for Polling bit */ + int size = pdu_mngt->header_and_payload_size + sizeof(struct mac_tb_req); + mem_block_t* mb_copy = get_free_mem_block(size, __func__); + memcpy(mb_copy->data, mb_original_p->data, size); - rlc_am_pdu_sn_10_t *pdu_p = (rlc_am_pdu_sn_10_t*) (&mb_copy->data[sizeof(struct mac_tb_req)]); - ((struct mac_tb_req*)(mb_copy->data))->data_ptr = (uint8_t*)pdu_p; + rlc_am_pdu_sn_10_t *pdu_p = (rlc_am_pdu_sn_10_t*) (&mb_copy->data[sizeof(struct mac_tb_req)]); + ((struct mac_tb_req*)(mb_copy->data))->data_ptr = (uint8_t*)pdu_p; - pdu_mngt->flags.retransmit = 0; - - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt->payload_size); - return mb_copy; - } else { - return NULL; - } + return mb_copy; } + +//----------------------------------------------------------------------------- +mem_block_t* rlc_am_retransmit_get_am_segment( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t *const rlc_pP, + rlc_am_tx_data_pdu_management_t *const pdu_mngt, + sdu_size_t * const payload_sizeP /* in-out*/) +{ + int16_t sdus_segment_size[RLC_AM_MAX_SDU_IN_PDU]; + mem_block_t* mb_original_p = pdu_mngt->mem_block; + mem_block_t* mem_pdu_segment_p = NULL; + uint8_t *pdu_original_header_p = NULL; + uint8_t *pdu_segment_header_p = NULL; + sdu_size_t retx_so_start,retx_so_stop; //starting and ending SO for retransmission in this PDU + rlc_sn_t sn = pdu_mngt->sn; + uint16_t header_so_part; + boolean_t fi_start, fi_end; + uint8_t sdu_index = 0; + uint8_t sdu_segment_index = 0; + uint8_t num_LIs_pdu_segment = pdu_mngt->nb_sdus - 1; + uint8_t li_bit_offset = 4; /* toggle between 0 and 4 */ + uint8_t li_jump_offset = 1; /* toggle between 1 and 2 */ + + + AssertFatal (mb_original_p != NULL, "RLC AM PDU Segment Error: Empty block sn=%d vtA=%d vtS=%d LcId=%d !\n", + sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + + + AssertFatal (pdu_mngt->payload == mb_original_p->data + sizeof(struct mac_tb_req) + pdu_mngt->header_and_payload_size - pdu_mngt->payload_size, + "RLC AM PDU Segment Error: Inconsistent data pointers p1=%p p2=%p sn = %d total size = %d data size = %d LcId=%d !\n", + pdu_mngt->payload,mb_original_p->data + sizeof(struct mac_tb_req),pdu_mngt->header_and_payload_size,pdu_mngt->payload_size,sn,rlc_pP->channel_id); + + /* Init ReTx Hole list if not configured, ie the whole PDU has to be retransmitted */ + if (pdu_mngt->num_holes == 0) + { + AssertFatal (pdu_mngt->retx_payload_size == pdu_mngt->payload_size,"RLC AM PDU ReTx Segment: Expecting full PDU size ReTxSize=%d DataSize=%d sn=%d vtA=%d vtS=%d LcId=%d !\n", + pdu_mngt->retx_payload_size,pdu_mngt->payload_size,sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + pdu_mngt->retx_hole_index = 0; + pdu_mngt->hole_so_start[0] = 0; + pdu_mngt->hole_so_stop[0] = pdu_mngt->payload_size - 1; + pdu_mngt->num_holes = 1; + } + + /* Init SO Start and SO Stop */ + retx_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index]; + retx_so_stop = pdu_mngt->hole_so_stop[pdu_mngt->retx_hole_index]; + + AssertFatal ((retx_so_start <= retx_so_stop) && (retx_so_stop - retx_so_start + 1 <= pdu_mngt->payload_size), + "RLC AM Tx PDU Segment Data SO Error: retx_so_start=%d retx_so_stop=%d OriginalPDUDataLength=%d sn=%d LcId=%d!\n", + retx_so_start,retx_so_stop,pdu_mngt->payload_size,sn,rlc_pP->channel_id); + + /* Init FI to the same value as original PDU */ + fi_start = (!(RLC_AM_PDU_GET_FI_START(*(pdu_mngt->first_byte)))); + fi_end = (!(RLC_AM_PDU_GET_FI_END(*(pdu_mngt->first_byte)))); + + /* Handle no LI case first */ + if (num_LIs_pdu_segment == 0) + { + /* Bound retx_so_stop to available TBS */ + if (retx_so_stop - retx_so_start + 1 + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE > rlc_pP->nb_bytes_requested_by_mac) + { + retx_so_stop = retx_so_start + rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE - 1; + } + + *payload_sizeP = retx_so_stop - retx_so_start + 1; + + mem_pdu_segment_p = get_free_mem_block((*payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE + sizeof(struct mac_tb_req)), __func__); + pdu_segment_header_p = (uint8_t *)&mem_pdu_segment_p->data[sizeof(struct mac_tb_req)]; + ((struct mac_tb_req*)(mem_pdu_segment_p->data))->data_ptr = pdu_segment_header_p; + ((struct mac_tb_req*)(mem_pdu_segment_p->data))->tb_size = RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE + *payload_sizeP; + + /* clear all PDU segment */ + memset(pdu_segment_header_p, 0, *payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE); + /* copy data part */ + memcpy(pdu_segment_header_p + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE, pdu_mngt->payload + retx_so_start, *payload_sizeP); + + /* Set FI part to false if SO Start and SO End are different from PDU boundaries */ + if (retx_so_start) + { + fi_start = FALSE; + } + if (retx_so_stop < pdu_mngt->payload_size - 1) + { + fi_end = FALSE; + } + + /* Header content is filled at the end */ + } + else + { + /* Step 1 */ + /* Find the SDU index in the original PDU containing retx_so_start */ + sdu_size_t sdu_size = 0; + sdu_size_t data_size = 0; + *payload_sizeP = 0; + sdu_size_t header_segment_length = RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; + pdu_original_header_p = pdu_mngt->first_byte + 2; + li_bit_offset = 4; /* toggle between 0 and 4 */ + li_jump_offset = 1; /* toggle between 1 and 2 */ + uint16_t temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); + + + /* Read first LI */ + sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); + pdu_original_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + data_size += sdu_size; + sdu_index = 1; + + /* Loop on all original LIs */ + while ((data_size < retx_so_start + 1) && (sdu_index < pdu_mngt->nb_sdus)) + { + if (sdu_index < pdu_mngt->nb_sdus - 1) + { + temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); + sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); + pdu_original_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + data_size += sdu_size; + } + else + { + /* if retx_so_start is still not included then set data_size with full original PDU data size */ + /* Set fi_start to FALSE in this case */ + data_size = pdu_mngt->payload_size; + } + sdu_index ++; + } + + if (retx_so_start == data_size) + { + /* Set FI Start if retx_so_start = cumulated data size */ + fi_start = TRUE; + /* there must be at least one SDU more */ + AssertFatal (sdu_index < pdu_mngt->nb_sdus, "RLC AM Tx PDU Segment Error: sdu_index=%d nb_sdus=%d sn=%d LcId=%d !\n", + sdu_index,pdu_mngt->nb_sdus,sn,rlc_pP->channel_id); + if (sdu_index < pdu_mngt->nb_sdus - 1) + { + temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); + sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); + pdu_original_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + data_size += sdu_size; + } + else + { + /* It was the last LI, then set data_size to full original PDU size */ + data_size = pdu_mngt->payload_size; + } + /* Go to next SDU */ + sdu_index ++; + } + else if (retx_so_start != 0) + { + /* in all other cases set fi_start to FALSE if it SO Start is not 0 */ + fi_start = FALSE; + } + + /* Set first SDU portion of the segment */ + sdus_segment_size[0] = data_size - retx_so_start; + + /* Check if so end is in the first SDU portion */ + if (sdus_segment_size[0] >= retx_so_stop - retx_so_start + 1) + { + sdus_segment_size[0] = retx_so_stop - retx_so_start + 1; + *payload_sizeP = sdus_segment_size[0]; + num_LIs_pdu_segment = 0; + } + + /* Bound first SDU segment to available TBS if necessary */ + if (sdus_segment_size[0] + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE >= rlc_pP->nb_bytes_requested_by_mac) + { + sdus_segment_size[0] = rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; + *payload_sizeP = sdus_segment_size[0]; + num_LIs_pdu_segment = 0; + } + + + /* Now look for the end if it was not set previously */ + if (*payload_sizeP == 0) + { + sdu_segment_index ++; + while ((sdu_index < pdu_mngt->nb_sdus) && (data_size < retx_so_stop + 1)) + { + if (sdu_index < pdu_mngt->nb_sdus - 1) + { + temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); + sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); + pdu_original_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + data_size += sdu_size; + } + else + { + sdu_size = pdu_mngt->payload_size - data_size; + data_size = pdu_mngt->payload_size; + } + + sdus_segment_size[sdu_segment_index] = sdu_size; + sdu_index ++; + sdu_segment_index ++; + } + + + if (data_size > retx_so_stop + 1) + { + sdus_segment_size[sdu_segment_index - 1] = retx_so_stop - (data_size - sdu_size) + 1; + } + + /* Set number of LIs in the segment */ + num_LIs_pdu_segment = sdu_segment_index - 1; + + AssertFatal (num_LIs_pdu_segment <= pdu_mngt->nb_sdus - 1, "RLC AM Tx PDU Segment Data Error: nbLISegment=%d nbLIPDU=%d sn=%d LcId=%d !\n", + num_LIs_pdu_segment,pdu_mngt->nb_sdus - 1,sn,rlc_pP->channel_id); + + /* Bound to available TBS taking into account min PDU segment header*/ + sdu_segment_index = 0; + while ((sdu_segment_index < num_LIs_pdu_segment + 1) && (rlc_pP->nb_bytes_requested_by_mac > *payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index))) + { + AssertFatal (sdus_segment_size[sdu_segment_index] > 0, "RLC AM Tx PDU Segment Data Error: EMpty LI index=%d numLISegment=%d numLIPDU=%d PDULength=%d SOStart=%d SOStop=%d sn=%d LcId=%d !\n", + sdu_segment_index,num_LIs_pdu_segment,pdu_mngt->nb_sdus - 1,pdu_mngt->payload_size,retx_so_start,retx_so_stop,sn,rlc_pP->channel_id); + + /* Add next sdu_segment_index to data part */ + if (RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index) + (*payload_sizeP) + sdus_segment_size[sdu_segment_index] <= rlc_pP->nb_bytes_requested_by_mac) + { + (*payload_sizeP) += sdus_segment_size[sdu_segment_index]; + } + else + { + /* bound to available TBS size */ + sdus_segment_size[sdu_segment_index] = rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index) - (*payload_sizeP); + (*payload_sizeP) += sdus_segment_size[sdu_segment_index]; + } + header_segment_length = RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index); + sdu_segment_index ++; + } + + num_LIs_pdu_segment = sdu_segment_index - 1; + } + + + /* update retx_so_stop */ + retx_so_stop = retx_so_start + (*payload_sizeP) - 1; + + AssertFatal ((retx_so_stop <= pdu_mngt->payload_size - 1) && (retx_so_stop - retx_so_start + 1 < pdu_mngt->payload_size), + "RLC AM Tx PDU Segment Data Error: retx_so_stop=%d OriginalPDUDataLength=%d SOStart=%d SegmentLength=%d numLISegment=%d numLIPDU=%d sn=%d LcId=%d !\n", + retx_so_stop,pdu_mngt->payload_size,retx_so_start,*payload_sizeP,num_LIs_pdu_segment,pdu_mngt->nb_sdus - 1,sn,rlc_pP->channel_id); + + /* init FI End to FALSE if retx_so_stop is not end of PDU */ + if (retx_so_stop != pdu_mngt->payload_size - 1) + { + fi_end = FALSE; + } + + /* Check consistency between sdus_segment_size and payload_sizeP */ + /* And Set FI End if retx_so_stop = cumulated data size and this is not last SDU */ + data_size = 0; + for (int i = 0; i < num_LIs_pdu_segment + 1; i++) + { + data_size += sdus_segment_size[i]; + if ((retx_so_stop == data_size - 1) && (i < num_LIs_pdu_segment)) + { + fi_end = TRUE; + } + } + + AssertFatal (data_size == *payload_sizeP, "RLC AM Tx PDU Segment Data Error: SduSum=%d Data=%d sn=%d LcId=%d !\n", + data_size,*payload_sizeP,sn,rlc_pP->channel_id); + + + + /* Allocation */ + AssertFatal (header_segment_length + *payload_sizeP <= pdu_mngt->header_and_payload_size + 2, "RLC AM PDU Segment Error: Hdr=%d Data=%d Original Hdr+Data =%d sn=%d LcId=%d !\n", + header_segment_length,*payload_sizeP,pdu_mngt->header_and_payload_size,sn,rlc_pP->channel_id); + mem_pdu_segment_p = get_free_mem_block((*payload_sizeP + header_segment_length + sizeof(struct mac_tb_req)), __func__); + pdu_segment_header_p = (uint8_t *)&mem_pdu_segment_p->data[sizeof(struct mac_tb_req)]; + ((struct mac_tb_req*)(mem_pdu_segment_p->data))->data_ptr = pdu_segment_header_p; + ((struct mac_tb_req*)(mem_pdu_segment_p->data))->tb_size = header_segment_length + *payload_sizeP; + + /* clear all PDU segment */ + memset(pdu_segment_header_p, 0, *payload_sizeP + header_segment_length); + /* copy data part */ + memcpy(pdu_segment_header_p + header_segment_length, pdu_mngt->payload + retx_so_start, *payload_sizeP); + } + + /* Last step : update contexts and fill PDU Segment Header */ + if (mem_pdu_segment_p != NULL) + { + /* Update PDU Segment contexts */ + if (*payload_sizeP == pdu_mngt->hole_so_stop[pdu_mngt->retx_hole_index] - pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index] + 1) + { + /* All data in the segment are transmitted : switch to next one */ + pdu_mngt->retx_hole_index ++; + if (pdu_mngt->retx_hole_index < pdu_mngt->num_holes) + { + /* Set min SOStart to the value of next hole : assumption is holes are ordered by increasing SOStart */ + pdu_mngt->nack_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index]; + } + else + { + /* no more scheduled Retx: reset values */ + /* Retx size is reset in the calling function */ + pdu_mngt->num_holes = 0; + pdu_mngt->retx_hole_index = 0; + pdu_mngt->nack_so_start = 0; + } + } + else + { + /* not all segment data could be transmitted, just update SoStart */ + pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index] += (*payload_sizeP); + pdu_mngt->nack_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index]; + } + + /* Content is supposed to be init with 0 so with FIStart=FIEnd=TRUE */ + RLC_AM_PDU_SET_D_C(*pdu_segment_header_p); + RLC_AM_PDU_SET_RF(*pdu_segment_header_p); + /* Change FI */ + if (!fi_start) + { + // Set to not starting + (*pdu_segment_header_p) |= (1 << (RLC_AM_PDU_FI_OFFSET + 1)); + } + if (!fi_end) + { + // Set to not starting + (*pdu_segment_header_p) |= (1 << (RLC_AM_PDU_FI_OFFSET)); + } + /* Set SN */ + (*pdu_segment_header_p) |= ((sn >> 8) & 0x3); + (*(pdu_segment_header_p + 1)) |= (sn & 0xFF); + + /* Segment Offset */ + header_so_part = retx_so_start; + + /* Last Segment Flag (LSF) */ + if (retx_so_stop == pdu_mngt->payload_size - 1) + { + RLC_AM_PDU_SET_LSF(header_so_part); + } + + /* Store SO bytes */ + * (pdu_segment_header_p + 2) = (header_so_part >> 8) & 0xFF; + * (pdu_segment_header_p + 3) = header_so_part & 0xFF; + + /* Fill LI part */ + if (num_LIs_pdu_segment) + { + uint16_t index = 0; + uint16_t temp = 0; + /* Set Extension bit in first byte */ + RLC_AM_PDU_SET_E(*pdu_segment_header_p); + + /* loop on nb of LIs */ + pdu_segment_header_p += RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; + li_bit_offset = 4; /* toggle between 0 and 4 */ + li_jump_offset = 1; /* toggle between 1 and 2 */ + + while (index < num_LIs_pdu_segment) + { + /* Set E bit for next LI if present */ + if (index < num_LIs_pdu_segment - 1) + RLC_SET_BIT(temp,li_bit_offset + RLC_AM_LI_BITS); + /* Set LI */ + RLC_AM_PDU_SET_LI(temp,sdus_segment_size[index],li_bit_offset); + *pdu_segment_header_p = temp >> 8; + *(pdu_segment_header_p + 1) = temp & 0xFF; + pdu_segment_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + + temp = ((*pdu_segment_header_p) << 8) | (*(pdu_segment_header_p + 1)); + index ++; + } + } + } + else + { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] OUT OF MEMORY PDU SN %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + sn); + } + + return mem_pdu_segment_p; +} + +#if 0 //----------------------------------------------------------------------------- mem_block_t* rlc_am_retransmit_get_subsegment( const protocol_ctxt_t* const ctxt_pP, @@ -340,7 +709,7 @@ mem_block_t* rlc_am_retransmit_get_subsegment( // - set the header of the new AMD PDU segment in accordance with the description in sub clause 6.; // - set the P field according to sub clause 5.2.2. - mem_block_t* mb_original_p = rlc_pP->pdu_retrans_buffer[snP].mem_block; + mem_block_t* mb_original_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block; if (mb_original_p != NULL) { mem_block_t* mb_sub_segment_p = get_free_mem_block(*sizeP + sizeof(struct mac_tb_req), __func__); @@ -353,10 +722,10 @@ mem_block_t* rlc_am_retransmit_get_subsegment( ((struct mac_tb_req*)(mb_sub_segment_p->data))->data_ptr = (uint8_t*)&(mb_sub_segment_p->data[sizeof(struct mac_tb_req)]); - if (rlc_am_get_data_pdu_infos(ctxt_pP, rlc_pP, pdu_original_p, rlc_pP->pdu_retrans_buffer[snP].header_and_payload_size, &pdu_info) >= 0) { + if (rlc_am_get_data_pdu_infos(ctxt_pP, rlc_pP, pdu_original_p, rlc_pP->tx_data_pdu_buffer[snP].header_and_payload_size, &pdu_info) >= 0) { int li_index = 0; - int start_offset = rlc_pP->pdu_retrans_buffer[snP].nack_so_start; - int stop_offset = rlc_pP->pdu_retrans_buffer[snP].nack_so_stop; + int start_offset = rlc_pP->tx_data_pdu_buffer[snP].nack_so_start; + int stop_offset = rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] ORIGINAL PDU SN %04d:\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -366,8 +735,8 @@ mem_block_t* rlc_am_retransmit_get_subsegment( // all 15 bits set to 1 (indicate that the missing portion of the AMD PDU includes all bytes // to the last byte of the AMD PDU) if (stop_offset == 0x7FFF) { - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = rlc_pP->pdu_retrans_buffer[snP].payload_size - 1; - stop_offset = rlc_pP->pdu_retrans_buffer[snP].nack_so_stop; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = rlc_pP->tx_data_pdu_buffer[snP].payload_size - 1; + stop_offset = rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] UPDATED RETRANS PDU SN %04d nack_so_stop FROM 0x7FFF to %05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, @@ -627,7 +996,7 @@ mem_block_t* rlc_am_retransmit_get_subsegment( PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); test_pdu_copy_size = max_copy_payload_size; - if ((stop_offset == (start_offset + max_copy_payload_size - 1)) && (stop_offset == rlc_pP->pdu_retrans_buffer[snP].payload_size - 1)) { + if ((stop_offset == (start_offset + max_copy_payload_size - 1)) && (stop_offset == rlc_pP->tx_data_pdu_buffer[snP].payload_size - 1)) { not_test_fi = (not_test_fi & 0x2) | (not_fi_original & 0x1); // set b0 idendical to the b0 of the non segmented PDU } else { not_test_fi = not_test_fi & 0x2; // clear b0 because no SDU ending in this PDU @@ -635,7 +1004,7 @@ mem_block_t* rlc_am_retransmit_get_subsegment( } //--------------------------------------------------------------- - /*if (stop_offset == (rlc_pP->pdu_retrans_buffer[snP].payload_size - 1)) { + /*if (stop_offset == (rlc_pP->tx_data_pdu_buffer[snP].payload_size - 1)) { test_fi = (test_fi & 0x02) | (fi_original & 0x01); }*/ //--------------------------------------------------------------- @@ -692,16 +1061,16 @@ mem_block_t* rlc_am_retransmit_get_subsegment( // copy payload to retransmit //--------------------------------------------------------------- memcpy(fill_payload_p, - &rlc_pP->pdu_retrans_buffer[snP].payload[start_offset], + &rlc_pP->tx_data_pdu_buffer[snP].payload[start_offset], test_pdu_copy_size); ((struct mac_tb_req*)(mb_sub_segment_p->data))->tb_size = (tb_size_t)(((uint64_t)fill_payload_p)+ test_pdu_copy_size) - ((uint64_t)(&pdu_sub_segment_p->b1)); // set LSF - if ((test_pdu_copy_size + start_offset) == rlc_pP->pdu_retrans_buffer[snP].payload_size) { + if ((test_pdu_copy_size + start_offset) == rlc_pP->tx_data_pdu_buffer[snP].payload_size) { pdu_sub_segment_p->data[0] = pdu_sub_segment_p->data[0] | 0x80; - rlc_pP->pdu_retrans_buffer[snP].flags.retransmit = 0; + rlc_pP->tx_data_pdu_buffer[snP].flags.retransmit = 0; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] RE-SEND DATA PDU SN %04d SO %d %d BYTES PAYLOAD %d BYTES LSF!\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -728,15 +1097,15 @@ mem_block_t* rlc_am_retransmit_get_subsegment( // update nack_so_start //--------------------------------------------------------------- rlc_am_remove_hole(ctxt_pP, rlc_pP, snP, start_offset, test_pdu_copy_size+start_offset - 1); - //rlc_pP->pdu_retrans_buffer[snP].nack_so_start = rlc_pP->pdu_retrans_buffer[snP].nack_so_start + test_pdu_copy_size; + //rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = rlc_pP->tx_data_pdu_buffer[snP].nack_so_start + test_pdu_copy_size; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] RE-SEND DATA PDU SN %04d NOW nack_so_start %d nack_so_stop %d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, - rlc_pP->pdu_retrans_buffer[snP].nack_so_start, - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop); - /*if (rlc_pP->pdu_retrans_buffer[snP].nack_so_start == rlc_pP->pdu_retrans_buffer[snP].nack_so_stop) { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = 0; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = 0x7FFF; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start, + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop); + /*if (rlc_pP->tx_data_pdu_buffer[snP].nack_so_start == rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop) { + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = 0; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = 0x7FFF; }*/ } else { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] COULD NOT GET INFO FOR DATA PDU SN %04d -> RETURN NULL\n", @@ -744,8 +1113,6 @@ mem_block_t* rlc_am_retransmit_get_subsegment( snP); return NULL; } - - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sub_segment_p, test_pdu_copy_size); return mb_sub_segment_p; } else { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] RE-SEND DATA PDU SN %04d BUT NO PDU AVAILABLE -> RETURN NULL\n", @@ -755,6 +1122,7 @@ mem_block_t* rlc_am_retransmit_get_subsegment( return NULL; } } +#endif //----------------------------------------------------------------------------- void rlc_am_tx_buffer_display ( const protocol_ctxt_t* const ctxt_pP, @@ -763,6 +1131,7 @@ void rlc_am_tx_buffer_display ( { rlc_sn_t sn = rlc_pP->vt_a; int i, loop = 0; + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p; if (message_pP) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" Retransmission buffer %s VT(A)=%04d VT(S)=%04d:", @@ -778,25 +1147,26 @@ void rlc_am_tx_buffer_display ( } while (rlc_pP->vt_s != sn) { - if (rlc_pP->pdu_retrans_buffer[sn].mem_block) { + tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[sn % RLC_AM_WINDOW_SIZE]; + if (tx_data_pdu_buffer_p->mem_block) { if ((loop % 1) == 0) { LOG_D(RLC, "\nTX SN:\t"); } - if (rlc_pP->pdu_retrans_buffer[sn].flags.retransmit) { - LOG_D(RLC, "%04d %d/%d Bytes (NACK RTX:%02d ",sn, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size, rlc_pP->pdu_retrans_buffer[sn].payload_size, - rlc_pP->pdu_retrans_buffer[sn].retx_count); + if (tx_data_pdu_buffer_p->flags.retransmit) { + LOG_D(RLC, "%04d %d/%d Bytes (NACK RTX:%02d ",sn, tx_data_pdu_buffer_p->header_and_payload_size, tx_data_pdu_buffer_p->payload_size, + tx_data_pdu_buffer_p->retx_count); } else { - LOG_D(RLC, "%04d %d/%d Bytes (RTX:%02d ",sn, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size, rlc_pP->pdu_retrans_buffer[sn].payload_size, - rlc_pP->pdu_retrans_buffer[sn].retx_count); + LOG_D(RLC, "%04d %d/%d Bytes (RTX:%02d ",sn, tx_data_pdu_buffer_p->header_and_payload_size, tx_data_pdu_buffer_p->payload_size, + tx_data_pdu_buffer_p->retx_count); } - if (rlc_pP->pdu_retrans_buffer[sn].num_holes == 0) { - LOG_D(RLC, "SO:%04d->%04d)\t", rlc_pP->pdu_retrans_buffer[sn].nack_so_start, rlc_pP->pdu_retrans_buffer[sn].nack_so_stop); + if (tx_data_pdu_buffer_p->num_holes == 0) { + LOG_D(RLC, "SO:%04d->%04d)\t", tx_data_pdu_buffer_p->nack_so_start, tx_data_pdu_buffer_p->nack_so_stop); } else { - for (i=0; ipdu_retrans_buffer[sn].num_holes; i++) { + for (i=0; inum_holes; i++) { assert(i < RLC_AM_MAX_HOLES_REPORT_PER_PDU); - LOG_D(RLC, "SO:%04d->%04d)\t", rlc_pP->pdu_retrans_buffer[sn].hole_so_start[i], rlc_pP->pdu_retrans_buffer[sn].hole_so_stop[i]); + LOG_D(RLC, "SO:%04d->%04d)\t", tx_data_pdu_buffer_p->hole_so_start[i], tx_data_pdu_buffer_p->hole_so_stop[i]); } } @@ -808,6 +1178,132 @@ void rlc_am_tx_buffer_display ( LOG_D(RLC, "\n"); } + +//----------------------------------------------------------------------------- +mem_block_t * rlc_am_get_pdu_to_retransmit( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t* const rlc_pP) +{ + rlc_sn_t sn = rlc_pP->vt_a; + rlc_sn_t sn_end = rlc_pP->vt_s; + mem_block_t* pdu_p = NULL; + rlc_am_tx_data_pdu_management_t* tx_data_pdu_management; + + AssertFatal ((rlc_pP->retrans_num_pdus > 0) && (rlc_pP->vt_a != rlc_pP->vt_s), "RLC AM ReTx start process Error: NbPDUtoRetx=%d vtA=%d vtS=%d LcId=%d !\n", + rlc_pP->retrans_num_pdus,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + + do + { + tx_data_pdu_management = &rlc_pP->tx_data_pdu_buffer[sn % RLC_AM_WINDOW_SIZE]; + if ((tx_data_pdu_management->flags.retransmit) && (tx_data_pdu_management->flags.max_retransmit == 0)) + { + AssertFatal (tx_data_pdu_management->sn == sn, "RLC AM ReTx PDU Error: SN Error pdu_sn=%d sn=%d vtA=%d vtS=%d LcId=%d !\n", + tx_data_pdu_management->sn,sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + AssertFatal (tx_data_pdu_management->flags.transmitted == 1, "RLC AM ReTx PDU Error: State Error sn=%d vtA=%d vtS=%d LcId=%d !\n", + sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + AssertFatal (tx_data_pdu_management->retx_payload_size > 0, "RLC AM ReTx PDU Error: No Data to Retx sn=%d vtA=%d vtS=%d LcId=%d !\n", + sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + + /* Either the whole RLC PDU is to be transmitted and there is enough MAC TBS or there is minimum TBS size for transmitting 1 AM PDU segment */ + if ((tx_data_pdu_management->retx_payload_size == tx_data_pdu_management->payload_size) && (rlc_pP->nb_bytes_requested_by_mac >= tx_data_pdu_management->header_and_payload_size)) + { + /* check maxretx is not hit */ + if (tx_data_pdu_management->retx_count_next <= rlc_pP->max_retx_threshold) + { + pdu_p = rlc_am_retransmit_get_copy(ctxt_pP, rlc_pP, sn); + + if (pdu_p != NULL) + { + rlc_pP->retrans_num_bytes_to_retransmit -= tx_data_pdu_management->retx_payload_size; + rlc_pP->retrans_num_pdus --; + tx_data_pdu_management->retx_payload_size = 0; + tx_data_pdu_management->flags.retransmit = 0; + + // update stats + rlc_pP->stat_tx_data_pdu += 1; + rlc_pP->stat_tx_retransmit_pdu += 1; + rlc_pP->stat_tx_retransmit_pdu_by_status += 1; + rlc_pP->stat_tx_data_bytes += tx_data_pdu_management->payload_size; + rlc_pP->stat_tx_retransmit_bytes += tx_data_pdu_management->payload_size; + rlc_pP->stat_tx_retransmit_bytes_by_status += tx_data_pdu_management->payload_size; + + } + } + else + { + // TO DO : RLC Notification to RRC + ReEstablishment procedure + tx_data_pdu_management->flags.max_retransmit = 1; + LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RLC AM MAX RETX=%d] SN %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + tx_data_pdu_management->retx_count_next, + sn); + } + } + else if (rlc_pP->nb_bytes_requested_by_mac >= 5) + { + /* Resegmentation case */ + /* check maxretx is not hit */ + if (tx_data_pdu_management->retx_count_next <= rlc_pP->max_retx_threshold) + { + sdu_size_t pdu_data_size = 0; + + pdu_p = rlc_am_retransmit_get_am_segment(ctxt_pP, rlc_pP, tx_data_pdu_management,&pdu_data_size); + + if (pdu_p != NULL) + { + AssertFatal ((tx_data_pdu_management->retx_payload_size >= pdu_data_size) && (rlc_pP->retrans_num_bytes_to_retransmit >= pdu_data_size), "RLC AM ReTx PDU Segment Error: DataSize=%d PDUReTxsize=%d TotalReTxsize=%d sn=%d LcId=%d !\n", + pdu_data_size,tx_data_pdu_management->retx_payload_size,rlc_pP->retrans_num_bytes_to_retransmit,sn,rlc_pP->channel_id); + + tx_data_pdu_management->retx_payload_size -= pdu_data_size; + rlc_pP->retrans_num_bytes_to_retransmit -= pdu_data_size; + if (tx_data_pdu_management->retx_payload_size == 0) + { + rlc_pP->retrans_num_pdus --; + tx_data_pdu_management->retx_payload_size = 0; + tx_data_pdu_management->flags.retransmit = 0; + } + + // update stats + rlc_pP->stat_tx_data_pdu += 1; + rlc_pP->stat_tx_retransmit_pdu += 1; + rlc_pP->stat_tx_retransmit_pdu_by_status += 1; + rlc_pP->stat_tx_data_bytes += pdu_data_size; + rlc_pP->stat_tx_retransmit_bytes += pdu_data_size; + rlc_pP->stat_tx_retransmit_bytes_by_status += pdu_data_size; + + } + } + else + { + // TO DO : RLC Notification to RRC + ReEstablishment procedure + tx_data_pdu_management->flags.max_retransmit = 1; + LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RLC AM MAX RETX=%d] SN %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + tx_data_pdu_management->retx_count_next, + sn); + } + } + + if (pdu_p != NULL) + { + /* check polling */ + rlc_am_pdu_sn_10_t* pdu_header_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]); + rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_header_p, tx_data_pdu_management->payload_size,false); + + tx_data_pdu_management->retx_count = tx_data_pdu_management->retx_count_next; + + break; + } + + } + + sn = RLC_AM_NEXT_SN(sn); + } while((sn != sn_end) && (rlc_pP->retrans_num_pdus > 0)); + + return pdu_p; +} + +#if 0 //----------------------------------------------------------------------------- void rlc_am_retransmit_any_pdu( const protocol_ctxt_t* const ctxt_pP, @@ -824,13 +1320,13 @@ void rlc_am_retransmit_any_pdu( PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); while (sn != sn_end) { - if (rlc_pP->pdu_retrans_buffer[sn].mem_block != NULL) { + if (rlc_pP->tx_data_pdu_buffer[sn].mem_block != NULL) { if (!found_pdu) { found_pdu = 1; found_pdu_sn = sn; } - if (rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size <= rlc_pP->nb_bytes_requested_by_mac) { + if (rlc_pP->tx_data_pdu_buffer[sn].header_and_payload_size <= rlc_pP->nb_bytes_requested_by_mac) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[FORCE-TRAFFIC] RE-SEND DATA PDU SN %04d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), sn); @@ -843,12 +1339,13 @@ void rlc_am_retransmit_any_pdu( // no need for update rlc_pP->nb_bytes_requested_by_mac pdu_p = rlc_am_retransmit_get_copy(ctxt_pP, rlc_pP, sn); pdu_sn_10_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]); - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size); - pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20; - rlc_pP->c_pdu_without_poll = 0; - rlc_pP->c_byte_without_poll = 0; + rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->tx_data_pdu_buffer[sn].header_and_payload_size,false); + //BugFix: polling is checked and done in function above ! + //pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20; + //BugFix : pdu_without_poll and byte_without_poll are reset only if a Poll is transmitted + //rlc_pP->c_pdu_without_poll = 0; + //rlc_pP->c_byte_without_poll = 0; //rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK; - rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP); rlc_pP->stat_tx_data_pdu += 1; rlc_pP->stat_tx_retransmit_pdu += 1; rlc_pP->stat_tx_data_bytes += ((struct mac_tb_req*)(pdu_p->data))->tb_size; @@ -877,12 +1374,11 @@ void rlc_am_retransmit_any_pdu( rlc_am_nack_pdu (ctxt_pP, rlc_pP, found_pdu_sn, 0, 0x7FFF); pdu_p = rlc_am_retransmit_get_subsegment(ctxt_pP, rlc_pP, found_pdu_sn, &rlc_pP->nb_bytes_requested_by_mac); pdu_sn_10_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]); - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[found_pdu_sn].header_and_payload_size); + rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->tx_data_pdu_buffer[found_pdu_sn].header_and_payload_size,false); pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20; rlc_pP->c_pdu_without_poll = 0; rlc_pP->c_byte_without_poll = 0; //rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK; - rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP); rlc_pP->stat_tx_data_pdu += 1; rlc_pP->stat_tx_retransmit_pdu += 1; rlc_pP->stat_tx_data_bytes += ((struct mac_tb_req*)(pdu_p->data))->tb_size; @@ -896,3 +1392,4 @@ void rlc_am_retransmit_any_pdu( } } } +#endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h index 99570e5d7f..338bc79196 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h @@ -50,21 +50,24 @@ # define public_rlc_am_retransmit(x) extern x # endif # endif -/*! \fn void rlc_am_nack_pdu (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *rlcP, uint16_t snP, sdu_size_t so_startP, sdu_size_t so_endP) +/*! \fn boolean_t rlc_am_nack_pdu (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *rlcP, int16_t snP, int16_t prev_nack_snP,sdu_size_t so_startP, sdu_size_t so_endP) * \brief The RLC AM PDU which have the sequence number snP is marked NACKed with segment offset fields. * \param[in] ctxtP Running context. * \param[in] rlcP RLC AM protocol instance pointer. * \param[in] snP Sequence number of the PDU that is negative acknowledged. +* \param[in] prev_nack_snP Sequence number of previous PDU that is negative acknowledged. * \param[in] so_startP Start of the segment offset of the PDU that . * \param[in] so_endP Transport blocks received from MAC layer. +* \return OK/KO * \note It may appear a new hole in the retransmission buffer depending on the segment offset informations. Depending on the state of the retransmission buffer, negative confirmation can be sent to higher layers about the drop by the RLC AM instance of a particular SDU. */ -protected_rlc_am_retransmit(void rlc_am_nack_pdu ( +protected_rlc_am_retransmit(boolean_t rlc_am_nack_pdu ( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, const rlc_sn_t snP, - const sdu_size_t so_startP, - const sdu_size_t so_endP);) + const rlc_sn_t prev_nack_snP, + sdu_size_t so_startP, + sdu_size_t so_endP);) /*! \fn void rlc_am_ack_pdu (const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t *rlcP, rlc_sn_t snP) * \brief The RLC AM PDU which have the sequence number snP is marked ACKed. @@ -90,6 +93,7 @@ protected_rlc_am_retransmit(mem_block_t* rlc_am_retransmit_get_copy ( rlc_am_entity_t *const rlcP, const rlc_sn_t snP)); +#if 0 /*! \fn mem_block_t* rlc_am_retransmit_get_subsegment (const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t *rlcP,rlc_sn_t snP, sdu_size_t *sizeP) * \brief The RLC AM PDU which have the sequence number snP is marked ACKed. * \param[in] ctxtP Running context. @@ -103,7 +107,18 @@ protected_rlc_am_retransmit(mem_block_t* rlc_am_retransmit_get_subsegment ( rlc_am_entity_t *const rlcP, const rlc_sn_t snP, sdu_size_t *const sizeP)); +#endif +/*! \fn mem_block_t* rlc_am_get_pdu_to_retransmit(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* rlcP) +* \brief Find a PDU or PDU segment to retransmit. +* \param[in] ctxtP Running context. +* \param[in] rlcP RLC AM protocol instance pointer. +* \return A copy of the retransmitted PDU or PDU segment or NULL if TBS was not big enough +*/ +protected_rlc_am_retransmit(mem_block_t* rlc_am_get_pdu_to_retransmit( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t* const rlcP);) +#if 0 /*! \fn void rlc_am_retransmit_any_pdu(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* rlcP) * \brief Retransmit any PDU in order to unblock peer entity, if no suitable PDU is found (depending on requested MAC size) to be retransmitted, then try to retransmit a subsegment of any PDU. * \param[in] ctxtP Running context. @@ -112,6 +127,7 @@ protected_rlc_am_retransmit(mem_block_t* rlc_am_retransmit_get_subsegment ( protected_rlc_am_retransmit(void rlc_am_retransmit_any_pdu( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* const rlcP);) +#endif /*! \fn void rlc_am_tx_buffer_display (const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t* rlcP, char* message_pP) * \brief Display the dump of the retransmission buffer. diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index a9f0bdbf7e..cad1a776a8 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -31,7 +31,812 @@ #include "UTIL/LOG/log.h" +boolean_t rlc_am_rx_check_vr_reassemble( + const protocol_ctxt_t* const ctxt_pP, + const rlc_am_entity_t* const rlc_pP) +{ + mem_block_t* cursor_p = rlc_pP->receiver_buffer.head; + rlc_am_rx_pdu_management_t * pdu_cursor_mgnt_p = NULL; + sdu_size_t next_waited_so = 0; + boolean_t reassemble = FALSE; + if (cursor_p != NULL) { + + rlc_am_pdu_info_t* pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + rlc_usn_t sn_ref = pdu_info_p->sn; + + if (sn_ref != rlc_pP->vr_r) { + /* Case vrR has advanced from head : most likely case */ + + reassemble = TRUE; + /* Handle first SN if it is made of PDU segments : set them all to be reassembled */ + if (pdu_info_p->rf) { + pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data); + next_waited_so = 0; + AssertFatal(pdu_cursor_mgnt_p->all_segments_received > 0,"AM Rx Check Reassembly head SN=%d with PDU segments != vrR=%d should be fully received LCID=%d\n", + sn_ref,rlc_pP->vr_r,rlc_pP->channel_id); + while ((cursor_p != NULL) && (pdu_info_p->sn == sn_ref) && (pdu_info_p->so == next_waited_so)) { + if (pdu_cursor_mgnt_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO) { + pdu_cursor_mgnt_p->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING; + } + next_waited_so += pdu_info_p->payload_size; + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data); + pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + } + + /* Now jump up to vrR */ + while ((RLC_AM_DIFF_SN(pdu_info_p->sn,sn_ref) < RLC_AM_DIFF_SN(rlc_pP->vr_r,sn_ref)) && (cursor_p != NULL)) { + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + + /* Handle vrR if it is made of incomplete PDU Segments */ + if ((cursor_p != NULL) && (pdu_info_p->sn == rlc_pP->vr_r)) { + pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data); + next_waited_so = 0; + AssertFatal(pdu_cursor_mgnt_p->all_segments_received == 0,"AM Rx Check Reassembly vr=%d should be partly received SNHead=%d LCID=%d\n", + rlc_pP->vr_r,sn_ref,rlc_pP->channel_id); + while ((cursor_p != NULL) && (pdu_info_p->sn == rlc_pP->vr_r) && (pdu_info_p->so == next_waited_so)) { + if (pdu_cursor_mgnt_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO) { + pdu_cursor_mgnt_p->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING; + } + next_waited_so += pdu_info_p->payload_size; + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data); + pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + } + } /* end sn_ref != rlc_pP->vr_r */ + else { + /* case vrR = partially received */ + + pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data); + next_waited_so = 0; + AssertFatal(pdu_cursor_mgnt_p->all_segments_received == 0,"AM Rx Check Reassembly SNHead=vr=%d should be partly received LCID=%d\n", + rlc_pP->vr_r,rlc_pP->channel_id); + while ((cursor_p != NULL) && (pdu_info_p->sn == rlc_pP->vr_r) && (pdu_info_p->so == next_waited_so)) { + if (pdu_cursor_mgnt_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO) { + pdu_cursor_mgnt_p->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING; + reassemble = TRUE; + } + next_waited_so += pdu_info_p->payload_size; + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data); + pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + } /*end sn_ref == rlc_pP->vr_r */ + } + return reassemble; +} + +mem_block_t * create_new_segment_from_pdu( + mem_block_t* const tb_pP, + uint16_t so_offset, /* offset from the data part of the PDU to copy */ + sdu_size_t data_length_to_copy) +{ + rlc_am_pdu_info_t* pdu_rx_info_p = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info; + rlc_am_pdu_info_t* pdu_new_segment_info_p = NULL; + mem_block_t * new_segment_p = NULL; + int16_t new_li_list[RLC_AM_MAX_SDU_IN_PDU]; + int16_t header_size = 0; + uint8_t num_li = 0; + boolean_t fi_start, fi_end, lsf; + + /* Init some PDU Segment header fixed parameters */ + fi_start = !((pdu_rx_info_p->fi & 0x2) >> 1); + fi_end = !(pdu_rx_info_p->fi & 0x1); + lsf = ((pdu_rx_info_p->lsf == 1) || (pdu_rx_info_p->rf == 0)); + + /* Handle NO Li case fist */ + if (pdu_rx_info_p->num_li == 0) { + + header_size = RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; + + if (so_offset) { + fi_start = FALSE; + } + if (so_offset + data_length_to_copy != pdu_rx_info_p->payload_size) { + fi_end = FALSE; + lsf = FALSE; + } + } // end no LI in original segment + else { + + uint8_t li_index = 0; + uint16_t li_sum = 0; + num_li = pdu_rx_info_p->num_li; + + /* set LSF to false if we know that end of the original segment will not be copied */ + if (so_offset + data_length_to_copy != pdu_rx_info_p->payload_size) { + lsf = FALSE; + } + + /* catch the first LI containing so_offset */ + while ((li_index < pdu_rx_info_p->num_li) && (li_sum + pdu_rx_info_p->li_list[li_index] <= so_offset)) { + li_sum += pdu_rx_info_p->li_list[li_index]; + num_li --; + li_index ++; + } + + /* set FI start if so_offset = LI sum and at least one LI have been read */ + if ((li_index) && (so_offset == li_sum)) { + fi_start = TRUE; + } + + /* Fill LI until the end */ + if (num_li) { + sdu_size_t remaining_size = data_length_to_copy; + uint8_t j = 0; + new_li_list[0] = li_sum + pdu_rx_info_p->li_list[li_index] - so_offset; + if (data_length_to_copy <= new_li_list[0]) { + num_li = 0; + } + else { + remaining_size -= new_li_list[0]; + j++; + li_index ++; + while ((li_index < pdu_rx_info_p->num_li) && (remaining_size >= pdu_rx_info_p->li_list[li_index])) { + remaining_size -= pdu_rx_info_p->li_list[li_index]; + new_li_list[j] = pdu_rx_info_p->li_list[li_index]; + j++; + li_index ++; + } + + /* update number of LI in the segment */ + num_li = j; + /* set FI End if remaining size = 0 */ + if (remaining_size == 0) { + fi_end = TRUE; + } + } + } + + /* compute header size */ + header_size = RLC_AM_PDU_SEGMENT_HEADER_SIZE(num_li); + + } // end LIs in original segment + + /* Allocate new buffer */ + new_segment_p = get_free_mem_block(sizeof (mac_rlc_max_rx_header_size_t) + header_size + data_length_to_copy, __func__); + + /* Fill PDU Segment Infos and Header */ + if (new_segment_p != NULL) { + pdu_new_segment_info_p = &((rlc_am_rx_pdu_management_t*)(new_segment_p->data))->pdu_info; + rlc_am_rx_pdu_management_t * pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (new_segment_p->data); + uint8_t *pdu_segment_header_p = (uint8_t *)&(new_segment_p->data[sizeof (mac_rlc_max_rx_header_size_t)]); + + pdu_cursor_mgnt_p->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO; //to be updated after if SN = vrR + + pdu_new_segment_info_p->d_c = pdu_rx_info_p->d_c; + pdu_new_segment_info_p->sn = pdu_rx_info_p->sn; + pdu_new_segment_info_p->p = pdu_rx_info_p->p; + pdu_new_segment_info_p->rf = 1; + pdu_new_segment_info_p->fi = (((fi_start ? 0: 1) << 1) | (fi_end ? 0: 1)); + pdu_new_segment_info_p->num_li = num_li; + pdu_new_segment_info_p->e = (num_li ? 1: 0); + pdu_new_segment_info_p->lsf = (lsf ? 1: 0); + pdu_new_segment_info_p->so = pdu_rx_info_p->so + so_offset; + pdu_new_segment_info_p->payload = pdu_segment_header_p + header_size; + pdu_new_segment_info_p->header_size = header_size; + pdu_new_segment_info_p->payload_size = data_length_to_copy; + pdu_new_segment_info_p->hidden_size = data_length_to_copy; + for (int i=0; i < num_li; i++) { + pdu_new_segment_info_p->li_list[i] = new_li_list[i]; + pdu_new_segment_info_p->hidden_size -= new_li_list[i]; + } + + /* Fill Header part in the buffer */ + /* Content is supposed to be init with 0 so with FIStart=FIEnd=TRUE */ + /* copy first two bytes from original: D/C + RF + FI + E+ SN*/ + memset(pdu_segment_header_p, 0, header_size); + RLC_AM_PDU_SET_D_C(*pdu_segment_header_p); + RLC_AM_PDU_SET_RF(*pdu_segment_header_p); + if (pdu_new_segment_info_p->p) { + RLC_AM_PDU_SET_POLL(*pdu_segment_header_p); + } + /* Change FI */ + if (!fi_start) + { + // Set to not starting + (*pdu_segment_header_p) |= (1 << (RLC_AM_PDU_FI_OFFSET + 1)); + + } + if (!fi_end) + { + // Set to not starting + (*pdu_segment_header_p) |= (1 << (RLC_AM_PDU_FI_OFFSET)); + + } + /* E */ + if (pdu_new_segment_info_p->e) { + RLC_AM_PDU_SET_E(*pdu_segment_header_p); + } + /* SN */ + (*pdu_segment_header_p) |= ((pdu_new_segment_info_p->sn >> 8) & 0x3); + *(pdu_segment_header_p + 1) = (pdu_new_segment_info_p->sn & 0xFF); + + pdu_segment_header_p += 2; + + /* Last Segment Flag (LSF) */ + if (lsf) + { + RLC_AM_PDU_SET_LSF(*pdu_segment_header_p); + } + /* Store SO bytes */ + * (pdu_segment_header_p ) |= ((pdu_new_segment_info_p->so >> 8) & 0x7F); + * (pdu_segment_header_p + 1) = pdu_new_segment_info_p->so & 0xFF; + + if (num_li) { + uint16_t index = 0; + uint16_t temp = 0; + uint8_t li_bit_offset = 4; /* toggle between 0 and 4 */ + uint8_t li_jump_offset = 1; /* toggle between 1 and 2 */ + + /* loop on nb of LIs */ + pdu_segment_header_p += 2; + + while (index < num_li) + { + /* Set E bit for next LI if present */ + if (index < num_li - 1) + RLC_SET_BIT(temp,li_bit_offset + RLC_AM_LI_BITS); + /* Set LI */ + RLC_AM_PDU_SET_LI(temp,new_li_list[index],li_bit_offset); + *pdu_segment_header_p = temp >> 8; + *(pdu_segment_header_p + 1) = temp & 0xFF; + pdu_segment_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + + temp = ((*pdu_segment_header_p) << 8) | (*(pdu_segment_header_p + 1)); + index ++; + } + } + + /* copy data part */ + /* Fill mem_block contexts */ + ((struct mac_tb_ind *) (new_segment_p->data))->first_bit = 0; + ((struct mac_tb_ind *) (new_segment_p->data))->data_ptr = (uint8_t*)&new_segment_p->data[sizeof (mac_rlc_max_rx_header_size_t)]; + ((struct mac_tb_ind *) (new_segment_p->data))->size = data_length_to_copy + header_size; + memcpy(pdu_new_segment_info_p->payload,pdu_rx_info_p->payload + so_offset,data_length_to_copy); + } + + return new_segment_p; +} + +rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t* const rlc_pP, + mem_block_t* const tb_pP) +{ + rlc_am_pdu_info_t* pdu_rx_info_p = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info; + rlc_am_pdu_info_t* pdu_info_cursor_p = NULL; + rlc_am_pdu_info_t* pdu_info_previous_cursor_p = NULL; + mem_block_t* cursor_p = rlc_pP->receiver_buffer.head; + mem_block_t* previous_cursor_p = NULL; + mem_block_t* next_cursor_p = NULL; + uint16_t so_start_min = 0; + uint16_t so_end = 0; + uint16_t so_start_segment = pdu_rx_info_p->so; + uint16_t so_end_segment = pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1; + + /*****************************************************/ + // 1) Find previous cursor to the PDU to insert + /*****************************************************/ + AssertFatal(cursor_p != NULL,"AM Rx PDU Error, received buffer empty LcID=%d\n",rlc_pP->channel_id); + + do { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + + // Stop if Cursor SN >= Received SN + if (RLC_AM_DIFF_SN(pdu_info_cursor_p->sn,rlc_pP->vr_r) >= RLC_AM_DIFF_SN(pdu_rx_info_p->sn,rlc_pP->vr_r)) { + break; + } + + previous_cursor_p = cursor_p; + pdu_info_previous_cursor_p = pdu_info_cursor_p; + cursor_p = cursor_p->next; + } while (cursor_p != NULL); + + /*****************************************************/ + // 2) Store the received Segment + /*****************************************************/ + // First case : cursor_p is NULL or its SN is different from the received one, it means the SN is received for the first time + // Insert PDU after previous_cursor_p + if ((cursor_p == NULL) || (pdu_info_cursor_p->sn != pdu_rx_info_p->sn)) { + if (previous_cursor_p != NULL) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT SN=%d] PDU SEGMENT INSERTED AFTER PDU SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn, + pdu_info_previous_cursor_p->sn); + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + } + else { /* SN of head of Rx PDU list is higher than received PDU SN */ + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT SN=%d] PDU SEGMENT INSERTED BEFORE PDU SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn, + pdu_info_cursor_p->sn); + list2_insert_before_element(tb_pP, cursor_p, &rlc_pP->receiver_buffer); + } + + return RLC_AM_DATA_PDU_STATUS_OK; + } + + /********************************************/ + /* Now handle case cursor->sn = received SN */ + /********************************************/ + + rlc_am_rx_pdu_management_t * pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data); + + // Filter out SN duplicate + if (pdu_cursor_mgnt_p->all_segments_received) { + return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; + } + + // Try to catch a segment duplicate + next_cursor_p = cursor_p; + while ((next_cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn)) { + if ((so_start_segment >= pdu_info_cursor_p->so) && (so_end_segment <= pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size - 1)) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] DISCARD : DUPLICATE SEGMENT SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn); + return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; + } + next_cursor_p = next_cursor_p->next; + if (next_cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info; + } + } + + // Reset pdu_info_cursor_p because of the loop before + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + + // Try to Handle the most likely cases first + if (pdu_info_cursor_p->so == 0) { + + /* Loop on stored segments and find the stored segment containing received SOStart */ + previous_cursor_p = cursor_p; + pdu_info_previous_cursor_p = pdu_info_cursor_p; + while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) + && ((pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size) <= so_start_segment)) { + previous_cursor_p = cursor_p; + pdu_info_previous_cursor_p = pdu_info_cursor_p; + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + + // Most likely case : no duplicate, the segment is put after all stored segments which are contiguous + if ((cursor_p == NULL) || (pdu_info_cursor_p->sn != pdu_rx_info_p->sn) || (pdu_info_cursor_p->so > so_end_segment)) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT SN=%d SOSTART=%d] PDU SEGMENT INSERTED AFTER PDU SEGMENT WITH SOEND=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn,so_start_segment, + pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - 1); + + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + return RLC_AM_DATA_PDU_STATUS_OK; + } + + // Duplicate case : Resume contiguous scan and update previous_cursor_p + so_start_min = pdu_info_previous_cursor_p->so; + so_end = so_start_min + pdu_info_previous_cursor_p->payload_size; + cursor_p = previous_cursor_p->next; + if (cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) + && (pdu_info_cursor_p->so == so_end)) { + previous_cursor_p = cursor_p; + pdu_info_previous_cursor_p = pdu_info_cursor_p; + so_end += pdu_info_cursor_p->payload_size; + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + + /* Now discard the PDU segment if it is within so_start_min and so_end */ + if ((so_start_min <= so_start_segment) && (so_end_segment <= so_end - 1)) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] DISCARD : DUPLICATE SEGMENT SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn); + return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; + } + + // Discard potential embedded segments in the received PDU segment + // The first one is discontigous + next_cursor_p = cursor_p; + while ((next_cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && + (so_end_segment >= pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size - 1)) { + /* Discard the segment */ + cursor_p = next_cursor_p; + next_cursor_p = next_cursor_p->next; + list2_remove_element (cursor_p, &rlc_pP->receiver_buffer); + free_mem_block(cursor_p, __func__); + + if (next_cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info; + } + } + cursor_p = next_cursor_p; + + //Remove duplicate at the begining + if (so_start_segment < pdu_info_previous_cursor_p->so) { + so_start_segment = pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size; + } + else if (so_start_segment < pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size){ + so_start_segment += (pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - so_start_segment); + } + + // Now remove duplicate at the end, only valid if cursor_p SN has the same received SN + if (cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info; + + if ((pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && (so_end_segment >= pdu_info_cursor_p->so)) { + so_end_segment = pdu_info_cursor_p->so - 1; + } + } + + AssertFatal((so_start_segment <= so_end_segment) && (pdu_rx_info_p->so <= so_start_segment) && + (so_end_segment <= pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1), + " AM RX PDU Segment Duplicate elimination error FirstSO=0 OldSOStart=%d OldSOEnd=%d newSOStart=%d newSOEnd =%d SN=%d\n", + pdu_rx_info_p->so,pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1,so_start_segment,so_end_segment,pdu_rx_info_p->sn); + + } // end pdu_info_cursor_p->so == 0 + else { + // Handle most likely case : PDU Segment without duplicate is inserted before first stored PDU segment + if (so_end_segment < pdu_info_cursor_p->so) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT SN=%d SOSTART=%d SOEND=%d] PDU SEGMENT INSERTED BEFORE PDU SEGMENT WITH SOSTART=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn,so_start_segment,so_end_segment, + pdu_info_cursor_p->so); + + list2_insert_before_element(tb_pP, cursor_p, &rlc_pP->receiver_buffer); + return RLC_AM_DATA_PDU_STATUS_OK; + } + + // Handle duplicate case + if (so_start_segment < pdu_info_cursor_p->so) { + // First Case : only duplicate at the end + // Scan for embedded segments to be discarded + next_cursor_p = cursor_p; + while ((next_cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && + (so_end_segment >= pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size - 1)) { + /* Discard the segment */ + cursor_p = next_cursor_p; + next_cursor_p = next_cursor_p->next; + list2_remove_element (cursor_p, &rlc_pP->receiver_buffer); + free_mem_block(cursor_p, __func__); + + if (next_cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info; + } + } + cursor_p = next_cursor_p; + + // Now remove duplicate at the end, only valid if cursor_p SN has the same received SN + if (cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info; + + if ((pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && (so_end_segment >= pdu_info_cursor_p->so)) { + so_end_segment = pdu_info_cursor_p->so - 1; + } + } + + AssertFatal((so_start_segment <= so_end_segment) && + (so_end_segment <= pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1), + " AM RX PDU Segment Duplicate elimination at the end error FirstSO!=0 SOStart=%d OldSOEnd=%d newSOEnd =%d SN=%d\n", + pdu_rx_info_p->so,pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1,so_end_segment,pdu_rx_info_p->sn); + + } + else { + // Second Case: Duplicate at the begining and potentially at the end + /* Loop on stored segments and find the stored segment containing received SOStart */ + + previous_cursor_p = cursor_p; + pdu_info_previous_cursor_p = pdu_info_cursor_p; + while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) + && ((pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size) <= so_start_segment)) { + previous_cursor_p = cursor_p; + pdu_info_previous_cursor_p = pdu_info_cursor_p; + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + + // Most likely case : no duplicate, the segment is put after all stored segments which are contiguous + if ((cursor_p == NULL) || (pdu_info_cursor_p->sn != pdu_rx_info_p->sn) || (pdu_info_cursor_p->so > so_end_segment)) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT SN=%d SOSTART=%d] PDU SEGMENT INSERTED AFTER PDU SEGMENT WITH SOEND=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn,so_start_segment, + pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - 1); + + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + return RLC_AM_DATA_PDU_STATUS_OK; + } + + // Now look for contiguous segments to check whether the received segment is not fully duplicate + so_start_min = pdu_info_previous_cursor_p->so; + so_end = so_start_min + pdu_info_previous_cursor_p->payload_size; + cursor_p = previous_cursor_p->next; + if (cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) + && (pdu_info_cursor_p->so == so_end)) { + previous_cursor_p = cursor_p; + pdu_info_previous_cursor_p = pdu_info_cursor_p; + so_end += pdu_info_cursor_p->payload_size; + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + + /* Now discard the PDU segment if it is within so_start_min and so_end */ + if ((so_start_min <= so_start_segment) && (so_end_segment < so_end)) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] DISCARD : DUPLICATE SEGMENT SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn); + return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; + } + + //Remove duplicate at the begining + if (so_start_segment < pdu_info_previous_cursor_p->so) { + so_start_segment = pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size; + } + else if (so_start_segment < pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size){ + so_start_segment += (pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - so_start_segment); + } + + + // Now Scan for embedded segments to be discarded + next_cursor_p = cursor_p; + while ((next_cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && + (so_end_segment >= pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size - 1)) { + /* Discard the segment */ + cursor_p = next_cursor_p; + next_cursor_p = next_cursor_p->next; + list2_remove_element (cursor_p, &rlc_pP->receiver_buffer); + free_mem_block(cursor_p, __func__); + + if (next_cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info; + } + } + cursor_p = next_cursor_p; + + // Now remove duplicate at the end, only valid if cursor_p SN has the same received SN + if (cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info; + + if ((pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && (so_end_segment >= pdu_info_cursor_p->so)) { + so_end_segment = pdu_info_cursor_p->so - 1; + } + } + + AssertFatal((so_start_segment <= so_end_segment) && (pdu_rx_info_p->so <= so_start_segment) && + (so_end_segment <= pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1), + " AM RX PDU Segment Duplicate elimination error FirstSO!=0 OldSOStart=%d OldSOEnd=%d newSOStart=%d newSOEnd =%d SN=%d\n", + pdu_rx_info_p->so,pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1,so_start_segment,so_end_segment,pdu_rx_info_p->sn); + } + + } // end pdu_info_cursor_p->so != 0 + + + /* Last step : duplicate bytes had been removed, build a new PDU segment */ + AssertFatal((pdu_rx_info_p->so != so_start_segment) || (so_end_segment != pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1), + " AM RX PDU Segment Duplicate elimination error FirstSO!=0 OldSOStart=%d OldSOEnd=%d newSOStart=%d newSOEnd =%d SN=%d\n", + pdu_rx_info_p->so,pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1,so_start_segment,so_end_segment,pdu_rx_info_p->sn); + + mem_block_t* trunc_segment = create_new_segment_from_pdu(tb_pP,so_start_segment - pdu_rx_info_p->so,so_end_segment - so_start_segment + 1); + if (trunc_segment != NULL) { + LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] CREATE SEGMENT FROM SEGMENT OFFSET=%d DATA LENGTH=%d SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),so_start_segment - pdu_rx_info_p->so,so_end_segment - so_start_segment + 1,pdu_rx_info_p->sn); + + if (previous_cursor_p != NULL) { + list2_insert_after_element(trunc_segment, previous_cursor_p, &rlc_pP->receiver_buffer); + } + else { + list2_insert_before_element(trunc_segment, rlc_pP->receiver_buffer.head, &rlc_pP->receiver_buffer); + } + + /* Free original PDU Segment */ + free_mem_block(tb_pP, __func__); + + return RLC_AM_DATA_PDU_STATUS_OK; + } + else { + return RLC_AM_DATA_PDU_STATUS_BUFFER_FULL; + } + +} + +rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t* const rlc_pP, + mem_block_t* const tb_pP) +{ + rlc_am_pdu_info_t* pdu_rx_info_p = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info; + rlc_am_pdu_info_t* pdu_info_cursor_p = NULL; + mem_block_t* cursor_p = rlc_pP->receiver_buffer.head; + mem_block_t* previous_cursor_p = NULL; + rlc_am_rx_pdu_status_t pdu_status = RLC_AM_DATA_PDU_STATUS_OK; + // it is assumed this pdu is in rx window + + + /*****************************************************/ + // 1) Find previous cursor to the PDU to insert + /*****************************************************/ + AssertFatal(cursor_p != NULL,"AM Rx PDU Error, received buffer empty LcID=%d\n",rlc_pP->channel_id); + + do { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + + // Stop if Cursor SN >= Received SN + if (RLC_AM_DIFF_SN(pdu_info_cursor_p->sn,rlc_pP->vr_r) >= RLC_AM_DIFF_SN(pdu_rx_info_p->sn,rlc_pP->vr_r)) { + break; + } + + previous_cursor_p = cursor_p; + cursor_p = cursor_p->next; + } while (cursor_p != NULL); + + /*****************************************************/ + // 2) Insert PDU by removing byte duplicate if required + /*****************************************************/ + // First case : cursor_p is NULL or SN are different, it means the SN is received for the first time + // Insert PDU after previous_cursor_p + if ((cursor_p == NULL) || (pdu_info_cursor_p->sn != pdu_rx_info_p->sn)) { + if (previous_cursor_p != NULL) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SN=%d] PDU INSERTED AFTER PDU SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn, + ((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->pdu_info.sn); + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + } + else { /* SN of head of Rx PDU list is higher than received PDU SN */ + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SN=%d] PDU INSERTED BEFORE PDU SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn, + pdu_info_cursor_p->sn); + list2_insert_before_element(tb_pP, cursor_p, &rlc_pP->receiver_buffer); + } + + return pdu_status; + } + + // Filter out SN duplicate + // SN of received PDU has already data stored + rlc_am_rx_pdu_management_t * pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data); + + if (pdu_cursor_mgnt_p->all_segments_received) { + return RLC_AM_DATA_PDU_STATUS_SN_DUPLICATE; + } + + /* check if the received PDU is equal to vrR */ + if ((pdu_rx_info_p->sn != rlc_pP->vr_r) || (pdu_info_cursor_p->so != 0)) { + /* The full received PDU can replace the allready received PDU Segments. */ + /* clean them and append this PDU */ + mem_block_t* cursor_next_p = cursor_p; + while (cursor_next_p) { + cursor_p = cursor_next_p; + cursor_next_p = cursor_next_p->next; + list2_remove_element (cursor_p, &rlc_pP->receiver_buffer); + free_mem_block(cursor_p, __func__); + if (cursor_next_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_next_p->data))->pdu_info; + if (pdu_info_cursor_p->sn != pdu_rx_info_p->sn) { + break; + } + } + } + + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU REPLACES STORED PDU SEGMENTS SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn); + + if (previous_cursor_p != NULL) { + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + } + else { + list2_insert_before_element(tb_pP, cursor_next_p, &rlc_pP->receiver_buffer); + } + + return pdu_status; + } // End SN != vrR or SO != 0 + else { + /* First update cursor until discontinuity */ + previous_cursor_p = cursor_p; + AssertFatal(pdu_info_cursor_p->rf != 0,"AM Rx PDU Error, stored SN=%d should be a PDU segment\n",pdu_info_cursor_p->sn); + AssertFatal(((rlc_am_rx_pdu_management_t *) (cursor_p->data))->all_segments_received == 0, + "AM Rx PDU Error, stored SN=%d already fully received\n",pdu_info_cursor_p->sn); + sdu_size_t next_waited_so = 0; + while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && (pdu_info_cursor_p->so == next_waited_so)) { + next_waited_so += pdu_info_cursor_p->payload_size; + previous_cursor_p = cursor_p; + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + /* Create a new PDU segment by removing first next_waited_so bytes */ + mem_block_t* trunc_pdu = create_new_segment_from_pdu(tb_pP,next_waited_so,pdu_rx_info_p->payload_size - next_waited_so); + + if (trunc_pdu != NULL) { + /* Insert PDU Segment */ + list2_insert_after_element(trunc_pdu, previous_cursor_p, &rlc_pP->receiver_buffer); + + LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] CREATE PDU SEGMENT FROM PDU OFFSET =%d SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),next_waited_so,pdu_rx_info_p->sn); + + /* clean previous stored segments in duplicate */ + if ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn)) { + mem_block_t* cursor_next_p = cursor_p; + while (cursor_next_p) { + cursor_p = cursor_next_p; + cursor_next_p = cursor_next_p->next; + list2_remove_element (cursor_p, &rlc_pP->receiver_buffer); + free_mem_block(cursor_p, __func__); + if (cursor_next_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_next_p->data))->pdu_info; + if (pdu_info_cursor_p->sn != pdu_rx_info_p->sn) { + break; + } + } + } + } + + /* Free original PDU */ + free_mem_block(tb_pP, __func__); + + return pdu_status; + } + else { + return RLC_AM_DATA_PDU_STATUS_BUFFER_FULL; + } + } +} + +// returns 0 if success +// returns neg value if failure +//----------------------------------------------------------------------------- +rlc_am_rx_pdu_status_t +rlc_am_rx_list_check_duplicate_insert_pdu( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t* const rlc_pP, + mem_block_t* const tb_pP) +{ + rlc_am_pdu_info_t* pdu_rx_info_p = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info; + mem_block_t* cursor_p = NULL; + cursor_p = rlc_pP->receiver_buffer.head; + rlc_am_rx_pdu_status_t pdu_status = RLC_AM_DATA_PDU_STATUS_OK; + // it is assumed this pdu is in rx window + + /* Init Reassembly status */ + ((rlc_am_rx_pdu_management_t*)(tb_pP->data))->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO; + + if (cursor_p == NULL) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[INSERT PDU] LINE %d RX PDU SN %04d (only inserted)\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + pdu_rx_info_p->sn); + list2_add_head(tb_pP, &rlc_pP->receiver_buffer); + return pdu_status; + } + + + if (pdu_rx_info_p->rf == 0) { // Case normal PDU received + pdu_status = rlc_am_rx_list_handle_pdu(ctxt_pP,rlc_pP,tb_pP); + } + else { + pdu_status = rlc_am_rx_list_handle_pdu_segment(ctxt_pP,rlc_pP,tb_pP); + } + + return pdu_status; +} +#if 0 // returns 0 if success // returns neg value if failure //----------------------------------------------------------------------------- @@ -49,6 +854,10 @@ rlc_am_rx_list_insert_pdu( cursor_p = rlc_pP->receiver_buffer.head; // it is assumed this pdu is in rx window + //TODO : check for duplicate + // should be rewrite + /* look for previous SN */ + if (cursor_p) { if (rlc_pP->vr_mr < rlc_pP->vr_r) { if (pdu_info_p->sn >= rlc_pP->vr_r) { @@ -479,6 +1288,8 @@ rlc_am_rx_list_insert_pdu( pdu_info_p->sn); return -1; } +#endif + //----------------------------------------------------------------------------- void rlc_am_rx_check_all_byte_segments( @@ -519,8 +1330,10 @@ rlc_am_rx_check_all_byte_segments( // in case all first segments up to tb_pP are in list // the so field of the first PDU should be 0 //cursor_p = list.head; + //we start from the first stored PDU segment of this SN pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + // if the first segment does not have SO = 0 then no need to continue if (pdu_info_p->so != 0) { return; } @@ -549,13 +1362,15 @@ rlc_am_rx_check_all_byte_segments( next_waited_so = next_waited_so + pdu_info_p->payload_size; //msg("rlc_am_rx_check_all_byte_segments(%d) @6\n",sn); } else { // assumed pdu_info_p->so + pdu_info_p->payload_size > next_waited_so - next_waited_so = (next_waited_so + pdu_info_p->payload_size) - (next_waited_so - pdu_info_p->so); + //next_waited_so = (next_waited_so + pdu_info_p->payload_size) - (next_waited_so - pdu_info_p->so); //msg("rlc_am_rx_check_all_byte_segments(%d) @7\n",sn); + return; } if (pdu_info_p->lsf > 0) { //msg("rlc_am_rx_check_all_byte_segments(%d) @8\n",sn); rlc_am_rx_mark_all_segments_received(ctxt_pP, rlc_pP, first_cursor_p); + return; } } @@ -599,13 +1414,15 @@ rlc_am_rx_mark_all_segments_received( } } //----------------------------------------------------------------------------- +//#define RLC_AM_DEBUG_REASSEMBLY void rlc_am_rx_list_reassemble_rlc_sdus( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* const rlc_pP) { - mem_block_t* cursor_p = NULL; - rlc_am_rx_pdu_management_t* rlc_am_rx_old_pdu_management = NULL; + mem_block_t* cursor_p = NULL; + rlc_am_rx_pdu_management_t* rlc_am_rx_old_pdu_management = NULL; + rlc_am_pdu_info_t* pdu_info_p = NULL; cursor_p = list2_get_head(&rlc_pP->receiver_buffer); @@ -614,20 +1431,79 @@ rlc_am_rx_list_reassemble_rlc_sdus( } rlc_am_rx_pdu_management_t* rlc_am_rx_pdu_management_p = ((rlc_am_rx_pdu_management_t*)(cursor_p->data)); + pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; +#ifdef RLC_AM_DEBUG_REASSEMBLY + rlc_usn_t sn_reass_start = pdu_info_p->sn; +#endif + + /* Specific process for the first SN if all PDU segments had been reassembled but not freed */ + if ((rlc_am_rx_pdu_management_p->all_segments_received > 0) && (pdu_info_p->rf != 0)) { + rlc_sn_t sn = pdu_info_p->sn; + while ((cursor_p != NULL) && (((rlc_am_rx_pdu_management_t*)(cursor_p->data))->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLED) + && ((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info.sn == sn) { + cursor_p = list2_remove_head(&rlc_pP->receiver_buffer); + free_mem_block(cursor_p, __func__); + cursor_p = list2_get_head(&rlc_pP->receiver_buffer); + } + + /* Reset Management pointers */ + if (cursor_p != NULL) { + rlc_am_rx_pdu_management_p = ((rlc_am_rx_pdu_management_t*)(cursor_p->data)); + /* Next SN must be the same or SN+1 */ + if (RLC_AM_DIFF_SN(rlc_am_rx_pdu_management_p->pdu_info.sn,sn) > 1) { + return; + } + } + else { + return; + } + } do { if (rlc_am_rx_pdu_management_p->all_segments_received > 0) { cursor_p = list2_remove_head(&rlc_pP->receiver_buffer); - rlc_am_reassemble_pdu(ctxt_pP, rlc_pP, cursor_p); + rlc_am_reassemble_pdu(ctxt_pP, rlc_pP, cursor_p,TRUE); rlc_am_rx_old_pdu_management = rlc_am_rx_pdu_management_p; cursor_p = list2_get_head(&rlc_pP->receiver_buffer); if (cursor_p == NULL) { +#ifdef RLC_AM_DEBUG_REASSEMBLY + LOG_D(RLC, "RLC AM REASSEMBLY from sn=%d to ALL, vrR=%d vrMS=%d\n", + sn_reass_start,rlc_pP->vr_r,rlc_pP->vr_ms); +#endif return; } rlc_am_rx_pdu_management_p = ((rlc_am_rx_pdu_management_t*)(cursor_p->data)); - } else { + } + else if (rlc_am_rx_pdu_management_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING) { + rlc_am_rx_pdu_management_p->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLED; + + rlc_am_reassemble_pdu(ctxt_pP, rlc_pP, cursor_p,FALSE); + rlc_am_rx_old_pdu_management = rlc_am_rx_pdu_management_p; + cursor_p = cursor_p->next; + + if (cursor_p == NULL) { +#ifdef RLC_AM_DEBUG_REASSEMBLY + LOG_D(RLC, "RLC AM REASSEMBLY from sn=%d to ALL, Last is Segment, vrR=%d vrMS=%d\n", + sn_reass_start,rlc_pP->vr_r,rlc_pP->vr_ms); +#endif + return; + } + + rlc_am_rx_pdu_management_p = ((rlc_am_rx_pdu_management_t*)(cursor_p->data)); + } + else if (rlc_am_rx_pdu_management_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLED) { + rlc_am_rx_old_pdu_management = rlc_am_rx_pdu_management_p; + cursor_p = cursor_p->next; + + if (cursor_p == NULL) { + return; + } + + rlc_am_rx_pdu_management_p = ((rlc_am_rx_pdu_management_t*)(cursor_p->data)); + } + else { #if RLC_STOP_ON_LOST_PDU if (list2_get_head(&rlc_pP->receiver_buffer) != cursor_p) { @@ -636,12 +1512,29 @@ rlc_am_rx_list_reassemble_rlc_sdus( PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); } +#endif +#ifdef RLC_AM_DEBUG_REASSEMBLY + LOG_D(RLC, "RLC AM REASSEMBLY from sn=%d to ALL, vrR=%d vrMS=%d\n", + sn_reass_start,rlc_pP->vr_r,rlc_pP->vr_ms); #endif return; } - } while ((rlc_am_rx_pdu_management_p->pdu_info.sn == ((rlc_am_rx_old_pdu_management->pdu_info.sn + 1) & RLC_AM_SN_MASK)) - || ((rlc_am_rx_pdu_management_p->pdu_info.sn == rlc_am_rx_old_pdu_management->pdu_info.sn) && (rlc_am_rx_pdu_management_p->all_segments_received > 0))); + } while (((RLC_AM_DIFF_SN(rlc_am_rx_pdu_management_p->pdu_info.sn,rlc_am_rx_old_pdu_management->pdu_info.sn) < 2) && (rlc_am_rx_old_pdu_management->all_segments_received > 0)) + || ((rlc_am_rx_pdu_management_p->pdu_info.sn == rlc_am_rx_old_pdu_management->pdu_info.sn) && (rlc_am_rx_pdu_management_p->segment_reassembled != RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO))); + +#ifdef RLC_AM_DEBUG_REASSEMBLY + mem_block_t* cursor_head_p = list2_get_head(&rlc_pP->receiver_buffer); + if (cursor_head_p == NULL) { + return; + } + + rlc_am_pdu_info_t* pdu_info_head_p = &((rlc_am_rx_pdu_management_t*)(cursor_head_p->data))->pdu_info; + + LOG_D(RLC, "RLC AM REASSEMBLY from sn=%d to sn=%d, next_sn=%d head sn=%d vrR=%d vrMS=%d\n", + sn_reass_start,rlc_am_rx_old_pdu_management->pdu_info.sn,rlc_am_rx_pdu_management_p->pdu_info.sn,pdu_info_head_p->sn,rlc_pP->vr_r,rlc_pP->vr_ms); +#endif + } //----------------------------------------------------------------------------- mem_block_t * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h index c75255c4fa..e6e043dd0a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h @@ -59,6 +59,16 @@ #include "PHY/defs.h" //----------------------------------------------------------------------------- +/*! \fn rlc_am_rx_pdu_status_t rlc_am_rx_list_check_duplicate_insert_pdu(const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t* const rlc_pP,mem_block_t* const tb_pP) +* \brief Insert a PDU in the RX buffer after removing byte duplicate (implemented with a list). +* \param[in] ctxt_pP Running context. +* \param[in] rlcP RLC AM protocol instance pointer. +* \param[in] tbP A PDU embedded in a mem_block_t. +* \return Zero if the PDU could be inserted in the RX buffer, a negative value if the PDU could not be inserted. +*/ +protected_rlc_am_rx_list( rlc_am_rx_pdu_status_t rlc_am_rx_list_check_duplicate_insert_pdu(const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t* const rlc_pP,mem_block_t* const tb_pP);) + +#if 0 /*! \fn signed int rlc_am_rx_list_insert_pdu(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* const rlcP , mem_block_t* const tbP) * \brief Insert a PDU in the RX buffer (implemented with a list). * \param[in] ctxt_pP Running context. @@ -67,6 +77,15 @@ * \return Zero if the PDU could be inserted in the RX buffer, a negative value if the PDU could not be inserted. */ protected_rlc_am_rx_list( signed int rlc_am_rx_list_insert_pdu(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* const rlcP, mem_block_t* const tbP);) +#endif + +/*! \fn boolean_t rlc_am_rx_check_vr_reassemble(const protocol_ctxt_t* const ctxt_pP,const rlc_am_entity_t* const rlc_pP) +* \brief Check if reassembly taking into account potential new vrR value +* \param[in] ctxt_pP Running context. +* \param[in] rlcP RLC AM protocol instance pointer. +* \return TRUE if reassembly must be done, FALSE else +*/ +protected_rlc_am_rx_list( boolean_t rlc_am_rx_check_vr_reassemble(const protocol_ctxt_t* const ctxt_pP,const rlc_am_entity_t* const rlc_pP);) /*! \fn void rlc_am_rx_check_all_byte_segments(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* const rlcP, mem_block_t* const tbP) * \brief Check if all sub-segments of a PDU are received, if yes then call rlc_am_rx_mark_all_segments_received() procedure. diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c index 893588d65e..113ee7d048 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c @@ -39,7 +39,8 @@ void rlc_am_pdu_polling ( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlc_pP, rlc_am_pdu_sn_10_t *const pdu_pP, - const int16_t payload_sizeP) + const int16_t payload_sizeP, + boolean_t is_new_pdu) { // 5.2.2 Polling // An AM RLC entity can poll its peer AM RLC entity in order to trigger STATUS reporting at the peer AM RLC entity. @@ -68,49 +69,59 @@ void rlc_am_pdu_polling ( // - start t-PollRetransmit; // - else: // - restart t-PollRetransmit; - rlc_pP->c_pdu_without_poll += 1; - rlc_pP->c_byte_without_poll += payload_sizeP; + + if (is_new_pdu) { + if (rlc_pP->poll_pdu != RLC_AM_POLL_PDU_INFINITE) { + rlc_pP->c_pdu_without_poll += 1; + } + + if (rlc_pP->poll_byte != RLC_AM_POLL_BYTE_INFINITE) { + rlc_pP->c_byte_without_poll += payload_sizeP; + } + } if ( - (rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu) || - (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte) || + ((is_new_pdu) && ((rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu) || + (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte))) || ((rlc_pP->sdu_buffer_occupancy == 0) && (rlc_pP->retrans_num_bytes_to_retransmit == 0)) || (rlc_pP->vt_s == rlc_pP->vt_ms) || - (rlc_pP->force_poll == TRUE) + (rlc_pP->force_poll == true) ) { - rlc_pP->force_poll = FALSE; + rlc_pP->force_poll = false; - if (rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu) { + if ((is_new_pdu) && (rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu)) { LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX NUM PDU THRESHOLD %d HAS BEEN REACHED\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->poll_pdu); - } else - if (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte) { + } + if ((is_new_pdu) && (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte)) { LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX NUM BYTES THRESHOLD %d HAS BEEN REACHED\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->poll_byte); - } else + } if ((rlc_pP->sdu_buffer_occupancy == 0) && (rlc_pP->retrans_num_bytes_to_retransmit == 0)) { LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX BUFFERS ARE EMPTY\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); - } else + } if (rlc_pP->vt_s == rlc_pP->vt_ms) { LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE OF WINDOW STALLING\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); } - pdu_pP->b1 = pdu_pP->b1 | 0x20; + RLC_AM_PDU_SET_POLL(pdu_pP->b1); rlc_pP->c_pdu_without_poll = 0; rlc_pP->c_byte_without_poll = 0; - rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK; + // vt_s shall have been updated before in case of new transmission + rlc_pP->poll_sn = RLC_AM_PREV_SN(rlc_pP->vt_s); //optimisation if (!rlc_pP->t_poll_retransmit.running) { rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP); //optimisation } else { //optimisation rlc_pP->t_poll_retransmit.frame_time_out = ctxt_pP->frame + rlc_pP->t_poll_retransmit.time_out; //optimisation } } else { - pdu_pP->b1 = pdu_pP->b1 & 0xDF; + // Need to clear poll bit as it may be a copy(retransmission case) of the original RLC PDU which was containing a poll + RLC_AM_PDU_CLEAR_POLL(pdu_pP->b1); } } //----------------------------------------------------------------------------- @@ -178,7 +189,9 @@ void rlc_am_segment_10 ( if (rlc_pP->nb_sdu_no_segmented <= 1) { max_li_overhead = 0; } else { - max_li_overhead = (((rlc_pP->nb_sdu_no_segmented - 1) * 3) / 2) + ((rlc_pP->nb_sdu_no_segmented - 1) % 2); + /* This computation assumes there is no SDU with size greater than 2047 bytes, otherwise a new PDU must be built except for LI15 configuration from Rel12*/ + test_num_li = rlc_pP->nb_sdu_no_segmented - 1; + max_li_overhead = test_num_li + (test_num_li >> 1) + (test_num_li & 1); } LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEGMENT] max_li_overhead %d\n", @@ -210,7 +223,7 @@ void rlc_am_segment_10 ( pdu_remaining_size = data_pdu_size - RLC_AM_HEADER_MIN_SIZE; pdu_p = (rlc_am_pdu_sn_10_t*) (&pdu_mem_p->data[sizeof(struct mac_tb_req)]); pdu_tb_req_p = (struct mac_tb_req*) (pdu_mem_p->data); - pdu_mngt_p = &rlc_pP->pdu_retrans_buffer[rlc_pP->vt_s % RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE]; + pdu_mngt_p = &rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_s % RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE]; memset(pdu_mngt_p, 0, sizeof (rlc_am_tx_data_pdu_management_t)); memset (pdu_mem_p->data, 0, sizeof (rlc_am_pdu_sn_10_t)+sizeof(struct mac_tb_req)); @@ -485,11 +498,11 @@ void rlc_am_segment_10 ( fi = fi + 1; } - pdu_p->b1 = pdu_p->b1 | (fi << 3); + pdu_p->b1 = pdu_p->b1 | (fi << RLC_AM_PDU_FI_OFFSET); // set fist e bit if (fill_num_li > 0) { - pdu_p->b1 = pdu_p->b1 | 0x04; + RLC_AM_PDU_SET_E(pdu_p->b1); } LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEGMENT] SEND PDU SN %04d SIZE %d BYTES PAYLOAD SIZE %d BYTES\n", @@ -501,8 +514,9 @@ void rlc_am_segment_10 ( rlc_pP->stat_tx_data_pdu += 1; rlc_pP->stat_tx_data_bytes += (data_pdu_size - pdu_remaining_size); - //pdu_p->sn = rlc_pP->vt_s; - pdu_p->b1 = pdu_p->b1 | 0x80; // DATA/CONTROL field is DATA PDU + // set DATA/CONTROL field is DATA PDU(1) + RLC_AM_PDU_SET_D_C(pdu_p->b1); + // set sn = rlc_pP->vt_s; pdu_p->b1 = pdu_p->b1 | (rlc_pP->vt_s >> 8); pdu_p->b2 = rlc_pP->vt_s & 0xFF; rlc_pP->vt_s = (rlc_pP->vt_s+1) & RLC_AM_SN_MASK; @@ -511,24 +525,28 @@ void rlc_am_segment_10 ( pdu_tb_req_p->tb_size = data_pdu_size - pdu_remaining_size; //#warning "why 3000: changed to RLC_SDU_MAX_SIZE " assert(pdu_tb_req_p->tb_size < RLC_SDU_MAX_SIZE ); - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt_p->payload_size); + rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt_p->payload_size,true); //list_add_tail_eurecom (pdu_mem_p, &rlc_pP->segmentation_pdu_list); pdu_mngt_p->mem_block = pdu_mem_p; pdu_mngt_p->first_byte = (unsigned char*)pdu_p; pdu_mngt_p->header_and_payload_size = data_pdu_size - pdu_remaining_size; - pdu_mngt_p->retx_count = -1; + pdu_mngt_p->retx_count = 0; + pdu_mngt_p->retx_count_next = 0; + pdu_mngt_p->flags.retransmit = 0; + pdu_mngt_p->flags.transmitted = 1; + pdu_mngt_p->sn = RLC_AM_PREV_SN(rlc_pP->vt_s); - rlc_pP->retrans_num_pdus += 1; - rlc_pP->retrans_num_bytes += pdu_mngt_p->header_and_payload_size; + //TBC: What for resetting local pointers at the end ?? pdu_p = NULL; pdu_mem_p = NULL; //nb_bytes_to_transmit = nb_bytes_to_transmit - data_pdu_size; nb_bytes_to_transmit = 0; // 1 PDU only - mem_block_t* copy = rlc_am_retransmit_get_copy (ctxt_pP, rlc_pP, (rlc_pP->vt_s-1) & RLC_AM_SN_MASK); + /* We need to copy the PDU to pass to MAC in order to keep it in the buffer for potential retransmissions */ + mem_block_t* copy = rlc_am_retransmit_get_copy (ctxt_pP, rlc_pP, RLC_AM_PREV_SN(rlc_pP->vt_s)); list_add_tail_eurecom (copy, &rlc_pP->segmentation_pdu_list); } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h index 6b67758b80..b52b3e5aaa 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h @@ -51,14 +51,14 @@ # endif # endif -/*! \fn void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP) +/*! \fn void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP,boolean_t is_new_pdu) * \brief Set or not the poll bit in the PDU header depending on RLC AM protocol variables. * \param[in] ctxt_pP Running context. * \param[in] rlcP RLC AM protocol instance pointer. * \param[in] pduP Pointer on the header of the PDU in order to be able to set the poll bit if necessary. * \param[in] payload_sizeP Size of the payload of the PDU. */ -protected_rlc_am_segment(void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP);) +protected_rlc_am_segment(void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP,boolean_t is_new_pdu);) /*! \fn void rlc_am_segment_10 (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlcP) * \brief Segment a PDU with 10 bits sequence number, based on segmentation information given by MAC (size to transmit). diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c index 37e9b13508..46a656e65a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c @@ -19,6 +19,7 @@ * contact@openairinterface.org */ +#if 0 #define RLC_AM_MODULE 1 #define RLC_AM_SEGMENT_HOLES_C 1 //----------------------------------------------------------------------------- @@ -32,7 +33,7 @@ void rlc_am_clear_holes ( rlc_am_entity_t *const rlc_pP, const rlc_sn_t snP) { - rlc_pP->pdu_retrans_buffer[snP].num_holes = 0; + rlc_pP->tx_data_pdu_buffer[snP].num_holes = 0; } //----------------------------------------------------------------------------- void rlc_am_shift_down_holes ( @@ -43,12 +44,12 @@ void rlc_am_shift_down_holes ( { int i; - for (i=indexP; i < rlc_pP->pdu_retrans_buffer[snP].num_holes - 1; i++) { - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i] = rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i+1]; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i] = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i+1]; + for (i=indexP; i < rlc_pP->tx_data_pdu_buffer[snP].num_holes - 1; i++) { + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i+1]; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i+1]; } - rlc_pP->pdu_retrans_buffer[snP].num_holes = rlc_pP->pdu_retrans_buffer[snP].num_holes - 1; + rlc_pP->tx_data_pdu_buffer[snP].num_holes = rlc_pP->tx_data_pdu_buffer[snP].num_holes - 1; } //----------------------------------------------------------------------------- void rlc_am_shift_up_holes ( @@ -60,13 +61,13 @@ void rlc_am_shift_up_holes ( // shift include indexP int i; - for (i=rlc_pP->pdu_retrans_buffer[snP].num_holes; i > indexP; i--) { - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i] = rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i-1]; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i] = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i-1]; + for (i=rlc_pP->tx_data_pdu_buffer[snP].num_holes; i > indexP; i--) { + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i-1]; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i-1]; } - rlc_pP->pdu_retrans_buffer[snP].num_holes = rlc_pP->pdu_retrans_buffer[snP].num_holes + 1; - assert(rlc_pP->pdu_retrans_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); + rlc_pP->tx_data_pdu_buffer[snP].num_holes = rlc_pP->tx_data_pdu_buffer[snP].num_holes + 1; + assert(rlc_pP->tx_data_pdu_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); } //----------------------------------------------------------------------------- void rlc_am_remove_hole ( @@ -79,81 +80,81 @@ void rlc_am_remove_hole ( int i; #if TRACE_RLC_AM_HOLE LOG_D(RLC, - PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] REMOVE HOLE SN %04d so_startP %05d so_stopP %05d rlc_pP->pdu_retrans_buffer[snP].nack_so_start %05d rlc_pP->pdu_retrans_buffer[snP].nack_so_stop %05d\n", + PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] REMOVE HOLE SN %04d so_startP %05d so_stopP %05d rlc_pP->tx_data_pdu_buffer[snP].nack_so_start %05d rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop %05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, so_startP, so_stopP, - rlc_pP->pdu_retrans_buffer[snP].nack_so_start, - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop); + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start, + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop); #endif assert(so_startP <= so_stopP); - if (rlc_pP->pdu_retrans_buffer[snP].num_holes == 0) { - assert(so_startP == rlc_pP->pdu_retrans_buffer[snP].nack_so_start); - assert(so_stopP <= rlc_pP->pdu_retrans_buffer[snP].nack_so_stop); + if (rlc_pP->tx_data_pdu_buffer[snP].num_holes == 0) { + assert(so_startP == rlc_pP->tx_data_pdu_buffer[snP].nack_so_start); + assert(so_stopP <= rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop); #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] REMOVE HOLE SN %04d MODIFIED nack_so_start %05d->%05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, - rlc_pP->pdu_retrans_buffer[snP].nack_so_start, + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start, so_stopP+1); #endif - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = so_stopP+1; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = so_stopP+1; - if (rlc_pP->pdu_retrans_buffer[snP].nack_so_start >= rlc_pP->pdu_retrans_buffer[snP].nack_so_stop) { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = 0; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = 0x7FFF; + if (rlc_pP->tx_data_pdu_buffer[snP].nack_so_start >= rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop) { + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = 0; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = 0x7FFF; } } else { // normally should be removed in increasing order... - for (i = 0; i < rlc_pP->pdu_retrans_buffer[snP].num_holes; i++) { - if (so_startP <= rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i]) { - if (so_stopP >= rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i]) { + for (i = 0; i < rlc_pP->tx_data_pdu_buffer[snP].num_holes; i++) { + if (so_startP <= rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i]) { + if (so_stopP >= rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i]) { rlc_am_shift_down_holes(ctxt_pP, rlc_pP, snP, i); i = i - 1; } else { - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i] = so_stopP; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i] = so_stopP; - if (rlc_pP->pdu_retrans_buffer[snP].num_holes == 0) { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = 0; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = 0x7FFF; + if (rlc_pP->tx_data_pdu_buffer[snP].num_holes == 0) { + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = 0; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = 0x7FFF; } else { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = rlc_pP->pdu_retrans_buffer[snP].hole_so_start[0]; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[rlc_pP->pdu_retrans_buffer[snP].num_holes - 1]; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[0]; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[rlc_pP->tx_data_pdu_buffer[snP].num_holes - 1]; } #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] REMOVE HOLE SN %04d NOW nack_so_start %05d nack_so_stop %05d num holes %d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, - rlc_pP->pdu_retrans_buffer[snP].nack_so_start, - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop, - rlc_pP->pdu_retrans_buffer[snP].num_holes); + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start, + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop, + rlc_pP->tx_data_pdu_buffer[snP].num_holes); #endif return; } - } else if (so_startP > rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i]) { - if (so_startP <= rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i]) { - if (so_stopP < rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i]) { + } else if (so_startP > rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i]) { + if (so_startP <= rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i]) { + if (so_stopP < rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i]) { // BAD CASE: 1 HOLE IS SPLITTED IN 2 HOLES rlc_am_shift_up_holes(ctxt_pP, rlc_pP, snP, i+1); - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i+1] = so_startP+1; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i+1] = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i]; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i] = so_startP - 1; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i+1] = so_startP+1; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i+1] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i]; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i] = so_startP - 1; } else { - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i] = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i] = so_startP; } } } } - if (rlc_pP->pdu_retrans_buffer[snP].num_holes == 0) { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = 0; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = 0x7FFF; + if (rlc_pP->tx_data_pdu_buffer[snP].num_holes == 0) { + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = 0; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = 0x7FFF; } else { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = rlc_pP->pdu_retrans_buffer[snP].hole_so_start[0]; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[rlc_pP->pdu_retrans_buffer[snP].num_holes - 1]; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[0]; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[rlc_pP->tx_data_pdu_buffer[snP].num_holes - 1]; } } @@ -161,11 +162,11 @@ void rlc_am_remove_hole ( LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] REMOVE HOLE SN %04d NOW nack_so_start %05d nack_so_stop %05d num holes %d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, - rlc_pP->pdu_retrans_buffer[snP].nack_so_start, - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop, - rlc_pP->pdu_retrans_buffer[snP].num_holes); + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start, + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop, + rlc_pP->tx_data_pdu_buffer[snP].num_holes); #endif - assert(rlc_pP->pdu_retrans_buffer[snP].nack_so_start < rlc_pP->pdu_retrans_buffer[snP].payload_size); + assert(rlc_pP->tx_data_pdu_buffer[snP].nack_so_start < rlc_pP->tx_data_pdu_buffer[snP].payload_size); } //----------------------------------------------------------------------------- void rlc_am_get_next_hole ( @@ -175,9 +176,9 @@ void rlc_am_get_next_hole ( sdu_size_t* const so_startP, sdu_size_t* const so_stopP) { - if (rlc_pP->pdu_retrans_buffer[snP].num_holes == 0) { - *so_startP = rlc_pP->pdu_retrans_buffer[snP].nack_so_start; - *so_stopP = rlc_pP->pdu_retrans_buffer[snP].nack_so_stop; + if (rlc_pP->tx_data_pdu_buffer[snP].num_holes == 0) { + *so_startP = rlc_pP->tx_data_pdu_buffer[snP].nack_so_start; + *so_stopP = rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop; #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] rlc_am_get_next_hole(SN %04d) %05d->%05d (NUM HOLES == 0)\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -186,15 +187,15 @@ void rlc_am_get_next_hole ( *so_stopP); #endif } else { - *so_startP = rlc_pP->pdu_retrans_buffer[snP].hole_so_start[0]; - *so_stopP = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[0]; + *so_startP = rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[0]; + *so_stopP = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[0]; #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] rlc_am_get_next_hole(SN %04d) %05d->%05d (NUM HOLES == %d)\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, *so_startP, *so_stopP, - rlc_pP->pdu_retrans_buffer[snP].num_holes); + rlc_pP->tx_data_pdu_buffer[snP].num_holes); #endif } } @@ -214,33 +215,33 @@ void rlc_am_add_hole ( // if global NACK - if ((so_startP == 0) && ((so_stopP == 0x7FFF) || (so_stopP == rlc_pP->pdu_retrans_buffer[snP].payload_size - 1))) { - rlc_pP->pdu_retrans_buffer[snP].num_holes = 0; - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = so_startP; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = so_stopP; + if ((so_startP == 0) && ((so_stopP == 0x7FFF) || (so_stopP == rlc_pP->tx_data_pdu_buffer[snP].payload_size - 1))) { + rlc_pP->tx_data_pdu_buffer[snP].num_holes = 0; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = so_stopP; #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] SN %04d GLOBAL NACK 0->%05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, so_stopP); #endif - assert(rlc_pP->pdu_retrans_buffer[snP].nack_so_start < rlc_pP->pdu_retrans_buffer[snP].payload_size); + assert(rlc_pP->tx_data_pdu_buffer[snP].nack_so_start < rlc_pP->tx_data_pdu_buffer[snP].payload_size); return; } if (so_stopP == 0x7FFF) { - so_stopP = rlc_pP->pdu_retrans_buffer[snP].payload_size - 1; + so_stopP = rlc_pP->tx_data_pdu_buffer[snP].payload_size - 1; } // first hole - if (rlc_pP->pdu_retrans_buffer[snP].num_holes == 0) { - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[0] = so_startP; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop [0] = so_stopP; + if (rlc_pP->tx_data_pdu_buffer[snP].num_holes == 0) { + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[0] = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop [0] = so_stopP; - rlc_pP->pdu_retrans_buffer[snP].num_holes = 1; + rlc_pP->tx_data_pdu_buffer[snP].num_holes = 1; - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = so_startP; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = so_stopP; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = so_stopP; #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] FIRST HOLE SN %04d GLOBAL NACK %05d->%05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -248,44 +249,44 @@ void rlc_am_add_hole ( so_startP, so_stopP); #endif - assert(rlc_pP->pdu_retrans_buffer[snP].nack_so_start < rlc_pP->pdu_retrans_buffer[snP].payload_size); + assert(rlc_pP->tx_data_pdu_buffer[snP].nack_so_start < rlc_pP->tx_data_pdu_buffer[snP].payload_size); return; } hole_index = 0; - while (hole_index < rlc_pP->pdu_retrans_buffer[snP].num_holes) { - if (so_stopP < rlc_pP->pdu_retrans_buffer[snP].hole_so_start[hole_index]) { - assert(rlc_pP->pdu_retrans_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); + while (hole_index < rlc_pP->tx_data_pdu_buffer[snP].num_holes) { + if (so_stopP < rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[hole_index]) { + assert(rlc_pP->tx_data_pdu_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); if (hole_index > 0) { - assert(so_startP > rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[hole_index-1]); + assert(so_startP > rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[hole_index-1]); } - for (i=rlc_pP->pdu_retrans_buffer[snP].num_holes; i >= hole_index; i--) { - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i] = rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i-1]; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i] = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i-1]; + for (i=rlc_pP->tx_data_pdu_buffer[snP].num_holes; i >= hole_index; i--) { + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i-1]; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i-1]; } - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[hole_index] = so_startP; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[hole_index] = so_stopP; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[hole_index] = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[hole_index] = so_stopP; // update nack "window" vars nack_so_start, nack_so_stop if (hole_index == 0) { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = so_startP; } - rlc_pP->pdu_retrans_buffer[snP].num_holes += 1; + rlc_pP->tx_data_pdu_buffer[snP].num_holes += 1; #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] INSERT %d th HOLE SN %04d GLOBAL NACK %05d->%05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->pdu_retrans_buffer[snP].num_holes, + rlc_pP->tx_data_pdu_buffer[snP].num_holes, snP, so_startP, so_stopP); #endif - assert(rlc_pP->pdu_retrans_buffer[snP].nack_so_start < rlc_pP->pdu_retrans_buffer[snP].payload_size); - assert(rlc_pP->pdu_retrans_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); + assert(rlc_pP->tx_data_pdu_buffer[snP].nack_so_start < rlc_pP->tx_data_pdu_buffer[snP].payload_size); + assert(rlc_pP->tx_data_pdu_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); return; } @@ -293,17 +294,17 @@ void rlc_am_add_hole ( } // if here insert to the "tail" - if (so_startP > rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[hole_index - 1]) { - assert(rlc_pP->pdu_retrans_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[hole_index] = so_startP; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[hole_index] = so_stopP; - rlc_pP->pdu_retrans_buffer[snP].num_holes += 1; + if (so_startP > rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[hole_index - 1]) { + assert(rlc_pP->tx_data_pdu_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[hole_index] = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[hole_index] = so_stopP; + rlc_pP->tx_data_pdu_buffer[snP].num_holes += 1; // update nack "window" vars nack_so_start, nack_so_stop - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = so_stopP; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = so_stopP; #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] INSERT THE %d th LAST HOLE SN %04d GLOBAL NACK %05d->%05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->pdu_retrans_buffer[snP].num_holes, + rlc_pP->tx_data_pdu_buffer[snP].num_holes, snP, so_startP, so_stopP); @@ -312,6 +313,7 @@ void rlc_am_add_hole ( assert(1==2); } - assert(rlc_pP->pdu_retrans_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); - assert(rlc_pP->pdu_retrans_buffer[snP].nack_so_start < rlc_pP->pdu_retrans_buffer[snP].payload_size); + assert(rlc_pP->tx_data_pdu_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); + assert(rlc_pP->tx_data_pdu_buffer[snP].nack_so_start < rlc_pP->tx_data_pdu_buffer[snP].payload_size); } +#endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.h index 902bc59306..68200c0f99 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.h @@ -32,7 +32,7 @@ * @ingroup _rlc_am_internal_segment_impl_ * @{ */ - +#if 0 #ifndef __RLC_AM_SEGMENT_HOLES_H__ # define __RLC_AM_SEGMENT_HOLES_H__ //----------------------------------------------------------------------------- @@ -108,3 +108,4 @@ protected_rlc_am_segments_holes(void rlc_am_add_hole ( sdu_size_t so_stopP);) /** @} */ #endif +#endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index d687bf8606..d33dc78e91 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -268,6 +268,14 @@ rlc_am_receive_process_control_pdu( { rlc_am_pdu_sn_10_t *rlc_am_pdu_sn_10_p = (rlc_am_pdu_sn_10_t*)*first_byte_ppP; sdu_size_t initial_pdu_size = *tb_size_in_bytes_pP; + rlc_sn_t ack_sn = RLC_AM_NEXT_SN(rlc_pP->vt_a); + rlc_sn_t sn_cursor = rlc_pP->vt_a; + rlc_sn_t vt_a_new = rlc_pP->vt_a; + rlc_sn_t sn_data_cnf; + rlc_sn_t nack_sn,prev_nack_sn; + sdu_size_t data_cnf_so_stop = 0x7FFF; + unsigned int nack_index; + boolean_t status = TRUE; if (rlc_am_get_control_pdu_infos(rlc_am_pdu_sn_10_p, tb_size_in_bytes_pP, &rlc_pP->control_pdu_info) >= 0) { @@ -280,11 +288,7 @@ rlc_am_receive_process_control_pdu( rlc_pP->control_pdu_info.ack_sn); rlc_am_display_control_pdu_infos(&rlc_pP->control_pdu_info); - rlc_sn_t ack_sn = rlc_pP->control_pdu_info.ack_sn; - rlc_sn_t sn_cursor = rlc_pP->vt_a; - rlc_sn_t nack_sn; - unsigned int nack_index; - + ack_sn = rlc_pP->control_pdu_info.ack_sn; // 5.2.1 Retransmission // // The transmitting side of an AM RLC entity can receive a negative acknowledgement (notification of reception failure @@ -308,64 +312,119 @@ rlc_am_receive_process_control_pdu( assert(ack_sn < RLC_AM_SN_MODULO); assert(rlc_pP->control_pdu_info.num_nack < RLC_AM_MAX_NACK_IN_STATUS_PDU); - if (rlc_am_in_tx_window(ctxt_pP, rlc_pP, ack_sn) > 0) { - rlc_pP->num_nack_so = 0; - rlc_pP->num_nack_sn = 0; - + /* Note : ackSn can be equal to current vtA only in case the status pdu contains a list of nack_sn with same value = vtA with SOStart/SOEnd */ + /* and meaning the report is not complete due to not enough ressources to fill all SOStart/SOEnd of this NACK_SN */ + if (RLC_AM_DIFF_SN(rlc_pP->vt_s,rlc_pP->vt_a) >= RLC_AM_DIFF_SN(ack_sn,rlc_pP->vt_a)) + { if (rlc_pP->control_pdu_info.num_nack == 0) { while (sn_cursor != ack_sn) { - if (sn_cursor == rlc_pP->poll_sn) { - rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP, rlc_pP); - } - rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor); - sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK; + sn_cursor = RLC_AM_NEXT_SN(sn_cursor); } + + vt_a_new = ack_sn; + sn_data_cnf = RLC_AM_PREV_SN(vt_a_new); } else { nack_index = 0; nack_sn = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn; + prev_nack_sn = 0x3FFF; - while (sn_cursor != ack_sn) { - if (sn_cursor == rlc_pP->poll_sn) { - rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP, rlc_pP); - } + while (sn_cursor != nack_sn) { + rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor); + sn_cursor = RLC_AM_NEXT_SN(sn_cursor); + } + vt_a_new = nack_sn; + + // catch DataCfn + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[nack_sn % RLC_AM_WINDOW_SIZE]; + if (tx_data_pdu_buffer_p->retx_payload_size == tx_data_pdu_buffer_p->payload_size) { + sn_data_cnf = RLC_AM_PREV_SN(nack_sn); + } + else if (tx_data_pdu_buffer_p->nack_so_start != 0) { + sn_data_cnf = nack_sn; + data_cnf_so_stop = tx_data_pdu_buffer_p->nack_so_start - 1; + } + else { + sn_data_cnf = RLC_AM_PREV_SN(nack_sn); + } + + + while ((sn_cursor != ack_sn) && (status)) { if (sn_cursor != nack_sn) { rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor); } else { - rlc_am_nack_pdu (ctxt_pP, + status = rlc_am_nack_pdu (ctxt_pP, rlc_pP, - sn_cursor, + nack_sn, + prev_nack_sn, rlc_pP->control_pdu_info.nack_list[nack_index].so_start, rlc_pP->control_pdu_info.nack_list[nack_index].so_end); nack_index = nack_index + 1; + prev_nack_sn = nack_sn; - if (nack_index == rlc_pP->control_pdu_info.num_nack) { - nack_sn = 0xFFFF; // value never reached by sn - } else { - nack_sn = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn; + if (nack_index < rlc_pP->control_pdu_info.num_nack) { + nack_sn = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn; + } + else if (nack_sn != ack_sn) { + /* general case*/ + nack_sn = ack_sn; + } + else { + /*specific case when the sender did not have enough TBS to fill all SOStart SOEnd for this NACK_SN */ + break; } } - - if ((nack_index < rlc_pP->control_pdu_info.num_nack) && (nack_index > 0)) { - if (rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn != rlc_pP->control_pdu_info.nack_list[nack_index-1].nack_sn) { + if (prev_nack_sn != nack_sn) { + /* do not increment sn_cursor in case of several informations for the same nack_sn */ sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK; - } - } else { - sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK; } } } + + } else { - LOG_N(RLC, PROTOCOL_RLC_AM_CTXT_FMT" WARNING CONTROL PDU ACK SN OUT OF WINDOW\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); + LOG_N(RLC, PROTOCOL_RLC_AM_CTXT_FMT" WARNING CONTROL PDU ACK SN %d OUT OF WINDOW vtA=%d vtS=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),ack_sn,rlc_pP->vt_a,rlc_pP->vt_s); + status = FALSE; } } else { LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT" ERROR IN DECODING CONTROL PDU\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); + status = FALSE; + } + + if (status) { + /* Check for Stopping TpollReTx */ + if ((rlc_pP->poll_sn != RLC_SN_UNDEFINED) && + (RLC_AM_DIFF_SN(ack_sn,rlc_pP->vt_a) > RLC_AM_DIFF_SN(rlc_pP->poll_sn,rlc_pP->vt_a))) { + rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP, rlc_pP); + rlc_pP->poll_sn = RLC_SN_UNDEFINED; + } + + //TODO : this part does not cover all cases of Data Cnf and move it at the end of Status PDU processing + sn_cursor = rlc_pP->vt_a; + + /* Handle all acked PDU up to and excluding sn_data_cnf */ + while (sn_cursor != sn_data_cnf) { + rlc_am_pdu_sdu_data_cnf(ctxt_pP,rlc_pP,sn_cursor); + sn_cursor = RLC_AM_NEXT_SN(sn_cursor); + } + + // Handle last SN. TO DO : case of PDU partially ACKED with SDU to be data conf + if (data_cnf_so_stop == 0x7FFF) { + rlc_am_pdu_sdu_data_cnf(ctxt_pP,rlc_pP,sn_data_cnf); + } + + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RECEIVE STATUS PDU ACK_SN=%d NewvtA=%d OldvtA=%d SnDataCnf=%d DataCnfSOStop=%d vtS=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),ack_sn,vt_a_new,rlc_pP->vt_a,sn_data_cnf,data_cnf_so_stop,rlc_pP->vt_s); + + /* Update vtA and vtMS */ + rlc_pP->vt_a = vt_a_new; + rlc_pP->vt_ms = (rlc_pP->vt_a + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK; } *first_byte_ppP = (uint8_t*)((uint64_t)*first_byte_ppP + initial_pdu_size - *tb_size_in_bytes_pP); @@ -449,6 +508,357 @@ rlc_am_send_status_pdu( // - set the ACK_SN to the SN of the next not received RLC Data PDU which is not indicated as missing in the // resulting STATUS PDU. + signed int nb_bits_to_transmit = rlc_pP->nb_bytes_requested_by_mac << 3; + // minimum header size in bits to be transmitted: D/C + CPT + ACK_SN + E1 + signed int nb_bits_transmitted = RLC_AM_PDU_D_C_BITS + RLC_AM_STATUS_PDU_CPT_LENGTH + RLC_AM_SN_BITS + RLC_AM_PDU_E_BITS; + rlc_am_control_pdu_info_t control_pdu_info; + rlc_am_pdu_info_t *pdu_info_cursor_p = NULL; + rlc_sn_t sn_cursor = 0; + rlc_sn_t sn_nack = rlc_pP->vr_r; + mem_block_t *cursor_p = rlc_pP->receiver_buffer.head; + int all_segments_received = 0; + int waited_so = 0; + mem_block_t *tb_p = NULL; + sdu_size_t pdu_size = 0; + boolean_t status_report_completed = false; + boolean_t segment_loop_end = false; + + memset(&control_pdu_info, 0, sizeof(rlc_am_control_pdu_info_t)); + +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] nb_bits_to_transmit %d (15 already allocated for header)\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + nb_bits_to_transmit); + rlc_am_rx_list_display(rlc_pP, " DISPLAY BEFORE CONSTRUCTION OF STATUS REPORT"); +#endif + + /* Handle no NACK first */ + if (rlc_pP->vr_r == rlc_pP->vr_ms) { + + control_pdu_info.ack_sn = rlc_pP->vr_ms; + status_report_completed = true; +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d ALL ACK WITH ACK_SN %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + rlc_pP->vr_ms); +#endif + } + else if ((cursor_p != NULL) && ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1)) <= nb_bits_to_transmit)) { + + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + sn_cursor = pdu_info_cursor_p->sn; + + /* Set E1 bit for the presence of first NACK_SN/E1/E2 */ + control_pdu_info.e1 = 1; + + // 12 bits = size of NACK_SN field + E1, E2 bits + // 42 bits = size of NACK_SN field + SO_START, SO_END fields, E1, E2 bits + while ((!status_report_completed) && (RLC_AM_DIFF_SN(sn_nack,rlc_pP->vr_r) < RLC_AM_DIFF_SN(rlc_pP->vr_ms,rlc_pP->vr_r)) + && (cursor_p != NULL) && (nb_bits_transmitted <= nb_bits_to_transmit)) { + + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + sn_cursor = pdu_info_cursor_p->sn; + all_segments_received = ((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received; + + /* First fill NACK_SN with each missing PDU between current sn_nack and sn_cursor */ + while ((sn_nack != sn_cursor) && (RLC_AM_DIFF_SN(sn_nack,rlc_pP->vr_r) < RLC_AM_DIFF_SN(rlc_pP->vr_ms,rlc_pP->vr_r))) { + if (nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) <= nb_bits_to_transmit) { + /* Fill NACK_SN infos */ + control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_nack; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = 0; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES; + control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 0; + /* Set E1 for next NACK_SN. The last one will be cleared */ + control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1; + control_pdu_info.num_nack += 1; + nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1)); +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + sn_nack); +#endif + sn_nack = RLC_AM_NEXT_SN(sn_nack); + } + else { + /* Not enough UL TBS*/ + /* latest value of sn_nack shall be used as ACK_SN */ + control_pdu_info.ack_sn = sn_nack; + status_report_completed = true; +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d NOT ENOUGH TBS STOP WITH ACK_SN %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + sn_nack); +#endif + break; + } + } + + if (sn_nack == rlc_pP->vr_ms) { + break; + } + + /* Now process all Segments of sn_cursor if PDU not fully received */ + if ((!status_report_completed) && (all_segments_received == 0) && (sn_cursor != rlc_pP->vr_ms)) { + AssertFatal (sn_nack == sn_cursor, "RLC AM Tx Status PDU Data sn_nack=%d and sn_cursor=%d should be equal LcId=%d\n",sn_nack,sn_cursor, rlc_pP->channel_id); + + /* First ensure there is enough TBS for at least 1 SOStart/SOEnd, else break */ + if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { + /* Init loop flags */ + /* Check lsf */ + segment_loop_end = (pdu_info_cursor_p->lsf == 1); + + /* Init first SO Start according to first segment */ + if (pdu_info_cursor_p->so) { + /* Fill the first SO */ + control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = 0; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = pdu_info_cursor_p->so - 1; + control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; + /* Set E1 for next NACK_SN. The last one will be cleared */ + control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1; + control_pdu_info.num_nack += 1; + nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d SO START %05d SO END %05d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + sn_cursor, + 0, + pdu_info_cursor_p->so - 1); +#endif + waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size; + } + else { + waited_so = pdu_info_cursor_p->payload_size; + } + + /* Go to next segment */ + cursor_p = cursor_p->next; + if (cursor_p != NULL) + { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + + /* Find the first discontinuity and then fill SOStart/SOEnd */ + while (!segment_loop_end) { + if ((cursor_p != NULL) && (pdu_info_cursor_p->sn == sn_cursor)) { + + /* PDU segment is for the same SN*/ + /* Check lsf */ + segment_loop_end = (pdu_info_cursor_p->lsf == 1); + + if (waited_so < pdu_info_cursor_p->so) { + /* SO is greater than previous received portion : gap identified to fill */ + if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { + control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = pdu_info_cursor_p->so - 1; + control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; + /* Set E1 for next NACK_SN. The last one will be cleared */ + control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1; + control_pdu_info.num_nack += 1; + nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d SO START %05d SO END %05d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + sn_cursor, + waited_so, + pdu_info_cursor_p->so); +#endif + } + else { + /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */ + control_pdu_info.ack_sn = sn_cursor; + status_report_completed = true; + segment_loop_end = true; + break; + } + } + else { + /* contiguous segment: only update waited_so */ + /* Assuming so and payload_size updated according to duplication removal done at reception ... */ + waited_so += pdu_info_cursor_p->payload_size; + } + + /* Go to next received PDU or PDU Segment */ + cursor_p = cursor_p->next; + if (cursor_p != NULL) + { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + + } //end if (cursor_p != NULL) && (pdu_info_cursor_p->sn == sn_cursor) + else { + /* Previous PDU segment was the last one and did not have lsf indication : fill the latest gap */ + if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { + control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES; + control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; + /* Set E1 for next NACK_SN. The last one will be cleared */ + control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1; + control_pdu_info.num_nack += 1; + nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING LAST NACK %04d SO START %05d SO END %05d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + sn_cursor, + waited_so, + RLC_AM_STATUS_PDU_SO_END_ALL_BYTES); +#endif + } + else { + /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */ + control_pdu_info.ack_sn = sn_cursor; + status_report_completed = true; + } + + segment_loop_end = true; + } + } //end while (!segment_loop_end) + } // end if enough resource for transmitting at least one SOStart/SOEnd + else { + /* Not enough UL TBS to set at least one SOStart/SOEnd */ + /* latest value of sn_nack shall be used as ACK_SN */ + control_pdu_info.ack_sn = sn_nack; + status_report_completed = true; + } + } // end while on all PDU segments of sn_cursor + else { + /* Go to next received PDU or PDU segment with different SN */ + do { + cursor_p = cursor_p->next; + } while ((cursor_p != NULL) && (((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info.sn == sn_cursor)); + } + + /* Increment sn_nack except if sn_cursor = vrMS and if current SN was not fully received */ + if (RLC_AM_DIFF_SN(sn_cursor,rlc_pP->vr_r) < RLC_AM_DIFF_SN(rlc_pP->vr_ms,rlc_pP->vr_r)) { + sn_nack = RLC_AM_NEXT_SN(sn_cursor); + } + else { + sn_nack = rlc_pP->vr_ms; + } + + + } // End main while NACK_SN + + /* Clear E1 of last nack_sn entry */ + AssertFatal ((control_pdu_info.num_nack) || (all_segments_received == 0), "RLC AM Tx Status PDU Data Error no NACK_SN vrR=%d vrMS=%d lastSN_NACK=%d Completed=%d NbBytesAvailable=%d LcId=%d\n", + rlc_pP->vr_r,rlc_pP->vr_ms,sn_nack,status_report_completed,(nb_bits_to_transmit >> 3),rlc_pP->channel_id); + if (control_pdu_info.num_nack) { + control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 0; + } + + + /* Set ACK_SN unless it was set before */ + if (!status_report_completed){ + + control_pdu_info.ack_sn = sn_nack; + } + + } else { + /* reception buffer empty or not enough TBS for filling at least 1 NACK_SN + E1 + E2 */ + control_pdu_info.ack_sn = rlc_pP->vr_r; +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING ACK %04d = VR(R)\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + control_pdu_info.ack_sn); +#endif + } + + + //msg ("[FRAME %5u][%s][RLC_AM][MOD %u/%u][RB %u] nb_bits_to_transmit %d\n", + // rlc_pP->module_id, rlc_pP->rb_id, ctxt_pP->frame,nb_bits_to_transmit); + +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING ACK %04d NUM NACK %d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + control_pdu_info.ack_sn, + control_pdu_info.num_nack); +#endif + + + /* encode the control pdu */ + pdu_size = (nb_bits_transmitted + 7) >> 3; + AssertFatal (pdu_size <= rlc_pP->nb_bytes_requested_by_mac, "RLC AM Tx Status PDU Data size=%d bigger than remaining TBS=%d nb_bits_transmitted=%d LcId=%d\n", + pdu_size,rlc_pP->nb_bytes_requested_by_mac,nb_bits_transmitted, rlc_pP->channel_id); + + +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d forecast pdu_size %d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + pdu_size); +#endif + tb_p = get_free_mem_block(sizeof(struct mac_tb_req) + pdu_size, __func__); + memset(tb_p->data, 0, sizeof(struct mac_tb_req) + pdu_size); + //estimation only ((struct mac_tb_req*)(tb_p->data))->tb_size = pdu_size; + ((struct mac_tb_req*)(tb_p->data))->data_ptr = (uint8_t*)&(tb_p->data[sizeof(struct mac_tb_req)]); + + // warning reuse of pdu_size + // TODO : rlc_am_write_status_pdu should be rewritten as not very tested ... + pdu_size = rlc_am_write_status_pdu(ctxt_pP, rlc_pP,(rlc_am_pdu_sn_10_t*)(((struct mac_tb_req*)(tb_p->data))->data_ptr), &control_pdu_info); + ((struct mac_tb_req*)(tb_p->data))->tb_size = pdu_size; + //assert((((struct mac_tb_req*)(tb_p->data))->tb_size) < 3000); + +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] SEND STATUS PDU SIZE %d, rlc_pP->nb_bytes_requested_by_mac %d, nb_bits_to_transmit>>3 %d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + pdu_size, + rlc_pP->nb_bytes_requested_by_mac, + nb_bits_to_transmit >> 3); +#endif + + AssertFatal (pdu_size == ((nb_bits_transmitted + 7) >> 3), "RLC AM Tx Status PDU Data encoding size=%d different than expected=%d LcId=%d\n", + pdu_size,((nb_bits_transmitted + 7) >> 3), rlc_pP->channel_id); + + // remaining bytes to transmit for RLC (retrans pdus and new data pdus) + rlc_pP->nb_bytes_requested_by_mac = rlc_pP->nb_bytes_requested_by_mac - pdu_size; + // put pdu in trans + list_add_head(tb_p, &rlc_pP->control_pdu_list); + rlc_pP->stat_tx_control_pdu += 1; + rlc_pP->stat_tx_control_bytes += pdu_size; + +} + + +#if 0 +//----------------------------------------------------------------------------- +void +rlc_am_send_status_pdu_backup( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t *const rlc_pP +) +{ + // When STATUS reporting has been triggered, the receiving side of an AM RLC entity shall: + // - if t-StatusProhibit is not running: + // - at the first transmission opportunity indicated by lower layer, construct a STATUS PDU and deliver it to lower layer; + // - else: + // - at the first transmission opportunity indicated by lower layer after t-StatusProhibit expires, construct a single + // STATUS PDU even if status reporting was triggered several times while t-StatusProhibit was running and + // deliver it to lower layer; + // + // When a STATUS PDU has been delivered to lower layer, the receiving side of an AM RLC entity shall: + // - start t-StatusProhibit. + // + // When constructing a STATUS PDU, the AM RLC entity shall: + // - for the AMD PDUs with SN such that VR(R) <= SN < VR(MR) that has not been completely received yet, in + // increasing SN of PDUs and increasing byte segment order within PDUs, starting with SN = VR(R) up to + // the point where the resulting STATUS PDU still fits to the total size of RLC PDU(s) indicated by lower layer: + // - for an AMD PDU for which no byte segments have been received yet:: + // - include in the STATUS PDU a NACK_SN which is set to the SN of the AMD PDU; + // - for a continuous sequence of byte segments of a partly received AMD PDU that have not been received yet: + // - include in the STATUS PDU a set of NACK_SN, SOstart and SOend + // - set the ACK_SN to the SN of the next not received RLC Data PDU which is not indicated as missing in the + // resulting STATUS PDU. + signed int nb_bits_to_transmit = rlc_pP->nb_bytes_requested_by_mac << 3; rlc_am_control_pdu_info_t control_pdu_info; rlc_am_pdu_info_t *pdu_info_cursor_p = NULL; @@ -470,11 +880,12 @@ rlc_am_send_status_pdu( rlc_am_rx_list_display(rlc_pP, " DISPLAY BEFORE CONSTRUCTION OF STATUS REPORT"); #endif + if (cursor_p != NULL) { pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; sn_cursor = pdu_info_cursor_p->sn; - while (rlc_am_in_rx_window(ctxt_pP, rlc_pP, sn_cursor) == 0) { + while (!(RLC_AM_SN_IN_WINDOW(sn_cursor, rlc_pP->vr_r))) { cursor_p = cursor_p->next; previous_sn_cursor = sn_cursor; @@ -757,3 +1168,5 @@ end_push_nack: rlc_pP->stat_tx_control_bytes += pdu_size; } +#endif + diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h index 02112fe736..2b75cb21a7 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h @@ -88,9 +88,12 @@ typedef struct rlc_am_tx_sdu_management { * \brief Structure containing PDU variables related to its retransmission. */ typedef struct pdu_management_flags { + uint8_t transmitted:1; /*!< \brief Boolean telling that this PDU is not empty and has been at least transmitted once. */ uint8_t ack:1; /*!< \brief Boolean telling that this PDU has been acknowledged. */ + uint8_t nack:1; /*!< \brief Boolean telling that this PDU has been acknowledged negatively. */ uint8_t retransmit:1; /*!< \brief Boolean telling a retransmission is scheduled for this PDU. */ - uint8_t dummy:6; /*!< \brief Free bits. */ + uint8_t max_retransmit:1; /*!< \brief Boolean telling max retransmission has been hit for this PDU. */ + uint8_t dummy:3; /*!< \brief Free bits. */ } pdu_management_flags_t; @@ -107,15 +110,17 @@ typedef struct rlc_am_tx_data_pdu_management { sdu_size_t hole_so_start [RLC_AM_MAX_HOLES_REPORT_PER_PDU]; /*!< \brief Array containing the start segment offsets for marking a hole (negative acknowledged area) in the PDU. */ sdu_size_t hole_so_stop [RLC_AM_MAX_HOLES_REPORT_PER_PDU]; /*!< \brief Array containing the stop segment offsets for marking a hole (negative acknowledged area) in the PDU. */ uint8_t num_holes; /*!< \brief Number of registereg holes in hole_so_start[], hole_so_stop[]. */ + uint8_t retx_hole_index; /*!< \brief Next index of registered holes to retransmit. */ sdu_size_t header_and_payload_size; /*!< \brief Size of the PDU in bytes, including header and payload. */ sdu_size_t payload_size; /*!< \brief Size of the PDU payload in bytes. */ + sdu_size_t retx_payload_size; /*!< \brief Size of the PDU payload to be retransmitted in bytes including all Segment portions. */ rlc_sn_t sn; /*!< \brief Sequence number of the PDU. */ sdu_size_t nack_so_start; /*!< \brief Lowest NACK start segment offset, must be set to 0 if global NACK. */ - sdu_size_t nack_so_stop; /*!< \brief Highest NACK stop segment offset, must be set to data_size if global NACK */ + sdu_size_t nack_so_stop; /*!< \brief Highest NACK stop segment offset, must be set to data_size - 1 if global NACK */ int8_t nb_sdus; /*!< \brief Number of sdu having segments in this pdu. */ - int8_t - retx_count; /*!< \brief Counts the number of retransmissions of an AMD PDU (see subclause 5.2.1). There is one RETX_COUNT counter per PDU that needs to be retransmitted. there is one VT(DAT) for each PDU and it is incremented each time the PDU is transmitted. */ + int8_t retx_count; /*!< \brief Counts the number of already occurred retransmissions of an AMD PDU (see subclause 5.2.1). */ + int8_t retx_count_next; /*!< \brief Counts the number of already occurred retransmissions plus the latest pending one. */ pdu_management_flags_t flags; /*!< \brief PDU variables related to its retransmission. */ } rlc_am_tx_data_pdu_management_t; @@ -228,14 +233,48 @@ typedef struct rlc_am_timer { * @{ */ +typedef enum rlc_am_rx_segment_reassemble_info +{ + /** No Reassembly scheduled */ + RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO = 0, + /** Reassembly scheduled */ + RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING = 1, + /** Reassembly done */ + RLC_AM_RX_PDU_SEGMENT_REASSEMBLED = 2 + +} rlc_am_rx_segment_reassemble_info_t; + /*! \struct rlc_am_rx_pdu_management_t * \brief Structure for storing decoded informations from the header of a AMD PDU or AMD PDU segment and information on reassembly. */ typedef struct rlc_am_rx_pdu_management { rlc_am_pdu_info_t pdu_info; /*!< \brief Field for storing decoded informations from the header of a AMD PDU or AMD PDU segment. */ uint8_t all_segments_received; /*!< \brief Is all segments of PDU SN have been received. */ + rlc_am_rx_segment_reassemble_info_t segment_reassembled; /*!< \brief if the segment for SN=vrR is reassembled but not discarded yet. */ } rlc_am_rx_pdu_management_t; /** @} */ + +typedef enum rlc_am_rx_pdu_status +{ + /** PDU okay. */ + RLC_AM_DATA_PDU_STATUS_OK = 0, + /** SN outside RX window */ + RLC_AM_DATA_PDU_STATUS_SN_OUTSIDE_WINDOW = 1, + /** SN already available */ + RLC_AM_DATA_PDU_STATUS_SN_DUPLICATE = 2, + /** SN already available */ + RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE = 3, + /** Buffer full */ + RLC_AM_DATA_PDU_STATUS_BUFFER_FULL = 4, + /** Header Error (LI,SO...) */ + RLC_AM_DATA_PDU_STATUS_HEADER_ERROR = 5, + /** Unknown bearer */ + RLC_AM_DATA_PDU_STATUS_INVALID_BEARER = 6, + /** RLC in wrong state */ + RLC_AM_DATA_PDU_STATUS_WRONG_STATE = 7 + +} rlc_am_rx_pdu_status_t; + /*! \cond PRIVATE */ //----------------------------------------------------------------------------- // interlayers optimizations diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c index aa3fdb909a..2dfa472523 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c @@ -77,10 +77,41 @@ rlc_am_check_timer_poll_retransmit( LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T_POLL_RETRANSMIT] TIME-OUT\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); + /* Check for any retransmittable PDU if Buffer Occupancy empty or window stall */ + if (((rlc_pP->sdu_buffer_occupancy == 0) && (rlc_pP->retrans_num_bytes_to_retransmit == 0)) || + (rlc_pP->vt_s == rlc_pP->vt_ms)) { + // force BO to be > 0 + rlc_sn_t sn = RLC_AM_PREV_SN(rlc_pP->vt_s); + rlc_sn_t sn_end = RLC_AM_PREV_SN(rlc_pP->vt_a); + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p; + + /* Look for the first retransmittable PDU starting from vtS - 1 */ + while (sn != sn_end) { + tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[sn % RLC_AM_WINDOW_SIZE]; + AssertFatal (tx_data_pdu_buffer_p->mem_block != NULL, "RLC AM Tpoll Retx expiry sn=%d is empty vtA=%d vtS=%d LcId=%d\n", + sn, rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + if ((tx_data_pdu_buffer_p->flags.ack == 0) && (tx_data_pdu_buffer_p->flags.max_retransmit == 0)) { + tx_data_pdu_buffer_p->flags.retransmit = 1; + tx_data_pdu_buffer_p->retx_payload_size = tx_data_pdu_buffer_p->payload_size; + if (tx_data_pdu_buffer_p->retx_count == tx_data_pdu_buffer_p->retx_count_next) { + tx_data_pdu_buffer_p->retx_count_next ++; + } + rlc_pP->retrans_num_pdus += 1; + rlc_pP->retrans_num_bytes_to_retransmit += tx_data_pdu_buffer_p->payload_size; + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T_POLL_RETRANSMIT] TIME-OUT PUT SN=%d in ReTx Buffer\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),tx_data_pdu_buffer_p->sn); + break; + } + else + { + sn = RLC_AM_PREV_SN(sn); + } + } + } + rlc_pP->force_poll= TRUE; - //#warning TO DO rlc_am_check_timer_poll_retransmit - rlc_pP->t_poll_retransmit.ms_time_out = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP) + rlc_pP->t_poll_retransmit.ms_duration; + //BugFix : new ms_time_out is computed when next poll is transmitter } } } @@ -119,9 +150,9 @@ rlc_am_start_timer_poll_retransmit( rlc_am_entity_t * const rlc_pP ) { - rlc_pP->t_poll_retransmit.timed_out = 0; + /* Stop timer if it was previously running */ + rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP,rlc_pP); - if (rlc_pP->t_poll_retransmit.running == 0) { if (rlc_pP->t_poll_retransmit.ms_duration > 0) { rlc_pP->t_poll_retransmit.running = 1; rlc_pP->t_poll_retransmit.ms_time_out = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP) + rlc_pP->t_poll_retransmit.ms_duration; @@ -138,14 +169,7 @@ rlc_am_start_timer_poll_retransmit( LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T_POLL_RETRANSMIT] NOT STARTED, CAUSE CONFIGURED 0 ms\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); } - } else { -#if MESSAGE_CHART_GENERATOR_RLC_MAC - MSC_LOG_EVENT((ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,\ - "0 "PROTOCOL_RLC_AM_MSC_FMT" t_poll_retransmit not restarted (TO %u ms)",\ - PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP,rlc_pP), rlc_pP->t_poll_retransmit.ms_time_out); -#endif - } } //----------------------------------------------------------------------------- void diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c index 3bbc2e87ac..cec0dffd1d 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c @@ -70,6 +70,8 @@ rlc_am_check_timer_reordering( PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP,rlc_pP)); #endif + AssertFatal (rlc_pP->vr_x != RLC_SN_UNDEFINED, "RLC AM TReordering Expiry vrX not defined LcId=%d\n", rlc_pP->channel_id); + rlc_pP->t_reordering.running = 0; rlc_pP->t_reordering.timed_out = 1; rlc_pP->stat_timer_reordering_timed_out += 1; @@ -77,38 +79,56 @@ rlc_am_check_timer_reordering( rlc_am_pdu_info_t* pdu_info; mem_block_t* cursor; cursor = rlc_pP->receiver_buffer.head; + rlc_usn_t vr_ms_new = rlc_pP->vr_x; - if (cursor) { - do { - pdu_info = &((rlc_am_rx_pdu_management_t*)(cursor->data))->pdu_info; + AssertFatal (cursor != NULL, "RLC AM TReordering Expiry Rx PDU list empty LcId=%d\n", rlc_pP->channel_id); - // NOT VERY SURE ABOUT THAT, THINK ABOUT IT - rlc_pP->vr_ms = (pdu_info->sn + 1) & RLC_AM_SN_MASK; - - if (rlc_am_sn_gte_vr_x(ctxt_pP, rlc_pP, pdu_info->sn)) { - if (((rlc_am_rx_pdu_management_t*)(cursor->data))->all_segments_received == 0) { - rlc_pP->vr_ms = pdu_info->sn; - break; - } - } - - cursor = cursor->next; - } while (cursor != NULL); - - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T-REORDERING] TIME-OUT UPDATED VR(MS) %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->vr_ms); + /* go to memblock up to vrX*/ + pdu_info = &((rlc_am_rx_pdu_management_t*)(cursor->data))->pdu_info; + while ((cursor != NULL) && (RLC_AM_DIFF_SN(pdu_info->sn,rlc_pP->vr_r) < RLC_AM_DIFF_SN(vr_ms_new,rlc_pP->vr_r))) { + cursor = cursor->next; + if (cursor != NULL) { + pdu_info = &((rlc_am_rx_pdu_management_t*)(cursor->data))->pdu_info; + } } - if (rlc_am_sn_gt_vr_ms(ctxt_pP, rlc_pP, rlc_pP->vr_h)) { + /* Now find a SN for which either no PDU is received or partially received */ + while ((cursor != NULL) && (vr_ms_new != rlc_pP->vr_h) && (pdu_info->sn == vr_ms_new) && (((rlc_am_rx_pdu_management_t*)(cursor->data))->all_segments_received > 0)) { + /* Increment vrMS if the PDU is fully received or if this is the last PDU segment */ + if ((pdu_info->rf == 0) || (pdu_info->lsf == 1)) { + vr_ms_new = RLC_AM_NEXT_SN(vr_ms_new); + } + cursor = cursor->next; + if (cursor != NULL) { + pdu_info = &((rlc_am_rx_pdu_management_t*)(cursor->data))->pdu_info; + } + } + + /* Update vr_ms */ + rlc_pP->vr_ms = vr_ms_new; + + + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T-REORDERING] TIME-OUT UPDATED VR(MS) %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + rlc_pP->vr_ms); + + /* if new vrMS is lower than vrH, update vrX and restart timerReordering */ + if (rlc_pP->vr_ms != rlc_pP->vr_h) { rlc_pP->vr_x = rlc_pP->vr_h; rlc_pP->t_reordering.ms_time_out = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP) + rlc_pP->t_reordering.ms_duration; + + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T-REORDERING] TIME-OUT, RESTARTED T-REORDERING, UPDATED VR(X) to VR(R) %04d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->vr_x); } - rlc_pP->status_requested = 1; + /* Trigger a STATUS report */ + RLC_AM_SET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_T_REORDERING); + // Clear Delay flag if it was setup as it is useless due to Status PDU to be sent for TReordering expiry + RLC_AM_CLEAR_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED); + rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; + } } } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c index b41fa1c17f..65ea056120 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c @@ -70,6 +70,8 @@ rlc_am_check_timer_status_prohibit( PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); //#warning TO DO rlc_am_check_timer_status_prohibit rlc_am_stop_and_reset_timer_status_prohibit(ctxt_pP, rlc_pP); + /* Clear StatusProhibit flag */ + RLC_AM_CLEAR_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_PROHIBIT); //rlc_pP->t_status_prohibit.frame_time_out = ctxt_pP->frame + rlc_pP->t_status_prohibit.time_out; } } @@ -110,6 +112,7 @@ rlc_am_start_timer_status_prohibit( rlc_pP->t_status_prohibit.running = 1; rlc_pP->t_status_prohibit.ms_time_out = rlc_pP->t_status_prohibit.ms_duration + PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP); rlc_pP->t_status_prohibit.ms_start = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP); + RLC_AM_SET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_PROHIBIT); LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T-STATUS-PROHIBIT] STARTED (TIME-OUT = %u ms)\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->t_status_prohibit.ms_time_out); diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c index 51440d0bfa..e3322d9410 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c @@ -434,7 +434,6 @@ rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP int32_t diff_time=0; rlc_um_entity_t *rlc_p = NULL; mem_block_t *mb_p = NULL; - unsigned int max_li_overhead = 0; status_resp.buffer_occupancy_in_pdus = 0; status_resp.buffer_occupancy_in_bytes = 0; @@ -454,20 +453,11 @@ rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP if ((status_resp.buffer_occupancy_in_bytes > 0) && ((mb_p = list_get_head(&rlc_p->input_sdus)) != NULL)) { - //Fix on full Header size - if (enb_flagP == ENB_FLAG_NO) - { - // compute Length Indicator overhead to inform MAC of maximum full RLC PDU size according to stored SDUs - // For UE scheduler - // Could be useful for eNB: to be checked - if (rlc_p->input_sdus.nb_elements <= 1) { - max_li_overhead = 0; - } else { - unsigned int num_li = rlc_p->input_sdus.nb_elements - 1; - max_li_overhead = num_li + (num_li >> 1) + (num_li & 1); - } - } - status_resp.buffer_occupancy_in_bytes += (rlc_p->tx_header_min_length_in_bytes + max_li_overhead); + if (enb_flagP == ENB_FLAG_YES) { + /* For eNB: add minimum RLC UM header size for the scheduler */ + /* For UE : RLC header part is not taken into account for BSR reporting (cf 36.321) */ + status_resp.buffer_occupancy_in_bytes += rlc_p->tx_header_min_length_in_bytes; + } status_resp.buffer_occupancy_in_pdus = rlc_p->input_sdus.nb_elements; diff_time = ctxt_pP->frame - ((struct rlc_um_tx_sdu_management *)mb_p->data)->sdu_creation_time; @@ -520,9 +510,19 @@ rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP return status_resp; } +//----------------------------------------------------------------------------- +void +rlc_um_set_nb_bytes_requested_by_mac ( + void * rlc_pP, + const tb_size_t tb_sizeP +) +{ + ((rlc_um_entity_t *) rlc_pP)->nb_bytes_requested_by_mac = tb_sizeP; +} + //----------------------------------------------------------------------------- struct mac_data_req -rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP) +rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP,const eNB_flag_t enb_flagP) { struct mac_data_req data_req; int16_t tb_size_in_bytes; @@ -544,10 +544,13 @@ rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP) list_add_list (&l_rlc_p->pdus_to_mac_layer, &data_req.data); - data_req.buffer_occupancy_in_bytes = rlc_um_get_buffer_occupancy (l_rlc_p); + if (enb_flagP) { + // redundant in UE MAC Tx processing and not used in eNB scheduler ... + data_req.buffer_occupancy_in_bytes = rlc_um_get_buffer_occupancy (l_rlc_p); - if (data_req.buffer_occupancy_in_bytes > 0) { - data_req.buffer_occupancy_in_bytes += l_rlc_p->tx_header_min_length_in_bytes; + if (data_req.buffer_occupancy_in_bytes > 0) { + data_req.buffer_occupancy_in_bytes += l_rlc_p->tx_header_min_length_in_bytes; + } } data_req.rlc_info.rlc_protocol_state = l_rlc_p->protocol_state; diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h index 5951eaf149..87cf2e2f37 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h @@ -188,13 +188,21 @@ protected_rlc_um( void rlc_um_rx (const protocol_ctxt_t* const ctxt_pP, rlc_ */ public_rlc_um( struct mac_status_resp rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP, const eNB_flag_t enb_flagP);) -/*! \fn struct mac_data_req rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP) +/*! \fn void rlc_um_set_nb_bytes_requested_by_mac (rlc_um_entity_t * const rlc_pP, const tb_size_t tb_sizeP) +* \brief Set available TBS size for MAC Tx. +* \param[in] rlc_pP RLC UM protocol instance pointer. +* \param[in] tb_sizeP remaining TBS in bytes. +*/ +public_rlc_um( void rlc_um_set_nb_bytes_requested_by_mac (rlc_um_entity_t * const rlc_pP, const tb_size_t tb_sizeP);) + +/*! \fn struct mac_data_req rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP,const eNB_flag_t enb_flagP) * \brief Gives PDUs to lower layer MAC. * \param[in] ctxt_pP Running context. * \param[in] rlc_pP RLC UM protocol instance pointer. +* \param[in] enb_flagP eNB or UE flag. * \return A PDU of the previously requested number of bytes, and the updated maximum number of bytes that can be served by RLC instance to MAC for next RLC transmission. */ -public_rlc_um( struct mac_data_req rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP);) +public_rlc_um( struct mac_data_req rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP,const eNB_flag_t enb_flagP);) /*! \fn void rlc_um_mac_data_indication (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP,struct mac_data_ind data_indP) @@ -205,6 +213,11 @@ public_rlc_um( struct mac_data_req rlc_um_mac_data_request (const protocol_ct */ public_rlc_um( void rlc_um_mac_data_indication (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP, struct mac_data_ind data_indP);) +/*! \fn uint32_t rlc_um_get_buffer_occupancy (rlc_um_entity_t *rlc_pP) +* \brief Gets Tx Buffer Occupancy. +* \param[in] rlc_pP RLC UM protocol instance pointer.) +*/ +public_rlc_um( uint32_t rlc_um_get_buffer_occupancy (rlc_um_entity_t *rlc_pP);) /*! \fn void rlc_um_data_req (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP, mem_block_t *sduP) * \brief Interface with higher layers, buffer higher layer SDUS for transmission. diff --git a/openair2/LAYER2/RLC/rlc.h b/openair2/LAYER2/RLC/rlc.h index 465492bec9..3d6be20524 100644 --- a/openair2/LAYER2/RLC/rlc.h +++ b/openair2/LAYER2/RLC/rlc.h @@ -436,10 +436,11 @@ public_rlc_rrc(void rrc_rlc_register_rrc (rrc_data_ind_cb_t rrc_data_indP, rrc_d * \param [in] eNB_flagP Flag to indicate eNB (1) or UE (0) * \param [in] MBMS_flagP Flag to indicate whether this is the MBMS service (1) or not (0) * \param [in] rb_idP Radio bearer identifier. +* \param [in] tb_sizeP Available Tx TBS in bytes. For UE only. * \param [in,out] bufferP Memory area to fill with the bytes requested by MAC. * \return A status about the processing, OK or error code. */ -public_rlc_mac(tbs_size_t mac_rlc_data_req (const module_id_t, const rnti_t, const eNB_index_t, const frame_t, const eNB_flag_t, const MBMS_flag_t, logical_chan_id_t, char*);) +public_rlc_mac(tbs_size_t mac_rlc_data_req (const module_id_t, const rnti_t, const eNB_index_t, const frame_t, const eNB_flag_t, const MBMS_flag_t, logical_chan_id_t, const tb_size_t,char*);) /*! \fn void mac_rlc_data_ind (const module_id_t mod_idP, const rnti_t rntiP, const frame_t frameP, const eNB_flag_t eNB_flagP, const MBMS_flag_t MBMS_flagP, logical_chan_id_t rb_idP, uint32_t frameP, char* bufferP, tb_size_t tb_sizeP, num_tb_t num_tbP, crc_t *crcs) * \brief Interface with MAC layer, deserialize the transport blocks sent by MAC, then map data indication to the RLC instance corresponding to the radio bearer identifier. @@ -457,18 +458,31 @@ public_rlc_mac(tbs_size_t mac_rlc_data_req (const module_id_t, co public_rlc_mac(void mac_rlc_data_ind (const module_id_t, const rnti_t, const eNB_index_t,const frame_t, const eNB_flag_t, const MBMS_flag_t, logical_chan_id_t, char*, tb_size_t, num_tb_t, crc_t* );) -/*! \fn mac_rlc_status_resp_t mac_rlc_status_ind (const module_id_t mod_idP, const rnti_t rntiP, const frame_t frameP, const eNB_flag_t eNB_flagP, const MBMS_flag_t MBMS_flagP, logical_chan_id_t rb_idP, tb_size_t tb_sizeP) +/*! \fn mac_rlc_status_resp_t mac_rlc_status_ind (const module_id_t mod_idP, const rnti_t rntiP, const frame_t frameP, const sub_frame_t subframeP, const eNB_flag_t eNB_flagP, const MBMS_flag_t MBMS_flagP, logical_chan_id_t rb_idP, tb_size_t tb_sizeP) * \brief Interface with MAC layer, request and set the number of bytes scheduled for transmission by the RLC instance corresponding to the radio bearer identifier. * \param[in] mod_idP Virtualized module identifier. * \param[in] rntiP UE identifier. * \param[in] frameP Frame index. +* \param[in] subframeP SubFrame index. * \param[in] eNB_flagP Flag to indicate eNB operation (1 true, 0 false) * \param[in] MBMS_flagP Flag to indicate whether this is the MBMS service (1) or not (0) * \param[in] rb_idP Radio bearer identifier. * \param[in] tb_sizeP Size of a transport block set in bytes. * \return The maximum number of bytes that the RLC instance can send in the next transmission sequence. */ -public_rlc_mac(mac_rlc_status_resp_t mac_rlc_status_ind (const module_id_t, const rnti_t, const eNB_index_t, const frame_t, const eNB_flag_t, const MBMS_flag_t, logical_chan_id_t, tb_size_t );) +public_rlc_mac(mac_rlc_status_resp_t mac_rlc_status_ind (const module_id_t, const rnti_t, const eNB_index_t, const frame_t, const sub_frame_t, const eNB_flag_t, const MBMS_flag_t, logical_chan_id_t, tb_size_t );) + +/*! \fn rlc_buffer_occupancy_t mac_rlc_get_buffer_occupancy_ind(const module_id_t module_idP, const rnti_t rntiP, const eNB_index_t eNB_index, const frame_t frameP, const sub_frame_t subframeP,const eNB_flag_t enb_flagP, const logical_chan_id_t channel_idP) +* \brief Interface with MAC layer, UE only: request and get the number of bytes scheduled for transmission by the RLC instance corresponding to the radio bearer identifier. +* \param[in] mod_idP Virtualized module identifier. +* \param[in] rntiP UE identifier. +* \param[in] frameP Frame index. +* \param[in] subframeP SubFrame index. +* \param[in] eNB_flagP Flag to indicate eNB operation (1 true, 0 false) +* \param[in] channel_idP Logical Channel identifier. +* \return The maximum number of bytes that the RLC instance can send in the next transmission sequence. +*/ +public_rlc_mac(rlc_buffer_occupancy_t mac_rlc_get_buffer_occupancy_ind(const module_id_t, const rnti_t, const eNB_index_t, const frame_t, const sub_frame_t, const eNB_flag_t, const logical_chan_id_t );) //----------------------------------------------------------------------------- // RLC methods //----------------------------------------------------------------------------- diff --git a/openair2/LAYER2/RLC/rlc_def.h b/openair2/LAYER2/RLC/rlc_def.h index 124ba509b5..929d66b70b 100644 --- a/openair2/LAYER2/RLC/rlc_def.h +++ b/openair2/LAYER2/RLC/rlc_def.h @@ -64,6 +64,7 @@ enum RLC_OPERATION_MODE { TRANSMITTER_ONLY = 0x00, // dimensions # define SN_12BITS_MASK 0x0FFF # define RLC_SN_OVERFLOW 0xFFFF +# define RLC_SN_UNDEFINED RLC_SN_OVERFLOW //---------------------------------------------------------- // DISCARD //---------------------------------------------------------- diff --git a/openair2/LAYER2/RLC/rlc_mac.c b/openair2/LAYER2/RLC/rlc_mac.c index d43a90ed6a..b4061ad29f 100644 --- a/openair2/LAYER2/RLC/rlc_mac.c +++ b/openair2/LAYER2/RLC/rlc_mac.c @@ -125,6 +125,7 @@ tbs_size_t mac_rlc_data_req( const eNB_flag_t enb_flagP, const MBMS_flag_t MBMS_flagP, const logical_chan_id_t channel_idP, + const tb_size_t tb_sizeP, char *buffer_pP) { //----------------------------------------------------------------------------- @@ -189,12 +190,14 @@ tbs_size_t mac_rlc_data_req( break; case RLC_MODE_AM: - data_request = rlc_am_mac_data_request(&ctxt, &rlc_union_p->rlc.am); + if (!enb_flagP) rlc_am_set_nb_bytes_requested_by_mac(&rlc_union_p->rlc.am,tb_sizeP); + data_request = rlc_am_mac_data_request(&ctxt, &rlc_union_p->rlc.am,enb_flagP); ret_tb_size =mac_rlc_serialize_tb(buffer_pP, data_request.data); break; case RLC_MODE_UM: - data_request = rlc_um_mac_data_request(&ctxt, &rlc_union_p->rlc.um); + if (!enb_flagP) rlc_um_set_nb_bytes_requested_by_mac(&rlc_union_p->rlc.um,tb_sizeP); + data_request = rlc_um_mac_data_request(&ctxt, &rlc_union_p->rlc.um,enb_flagP); ret_tb_size = mac_rlc_serialize_tb(buffer_pP, data_request.data); break; @@ -320,6 +323,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind( const rnti_t rntiP, const eNB_index_t eNB_index, const frame_t frameP, + const sub_frame_t subframeP, const eNB_flag_t enb_flagP, const MBMS_flag_t MBMS_flagP, const logical_chan_id_t channel_idP, @@ -337,7 +341,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind( srb_flag_t srb_flag = (channel_idP <= 2) ? SRB_FLAG_YES : SRB_FLAG_NO; protocol_ctxt_t ctxt; - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, enb_flagP, rntiP, frameP, 0, eNB_index); + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, enb_flagP, rntiP, frameP, subframeP, eNB_index); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_MAC_RLC_STATUS_IND,VCD_FUNCTION_IN); memset (&mac_rlc_status_resp, 0, sizeof(mac_rlc_status_resp_t)); @@ -397,7 +401,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind( break; case RLC_MODE_AM: - status_resp = rlc_am_mac_status_indication(&ctxt, &rlc_union_p->rlc.am, tb_sizeP, tx_status); + status_resp = rlc_am_mac_status_indication(&ctxt, &rlc_union_p->rlc.am, tb_sizeP, tx_status,enb_flagP); mac_rlc_status_resp.bytes_in_buffer = status_resp.buffer_occupancy_in_bytes; mac_rlc_status_resp.head_sdu_creation_time = status_resp.head_sdu_creation_time; mac_rlc_status_resp.head_sdu_remaining_size_to_send = status_resp.head_sdu_remaining_size_to_send; @@ -430,3 +434,65 @@ mac_rlc_status_resp_t mac_rlc_status_ind( return mac_rlc_status_resp; } +//----------------------------------------------------------------------------- +rlc_buffer_occupancy_t mac_rlc_get_buffer_occupancy_ind( + const module_id_t module_idP, + const rnti_t rntiP, + const eNB_index_t eNB_index, + const frame_t frameP, + const sub_frame_t subframeP, + const eNB_flag_t enb_flagP, + const logical_chan_id_t channel_idP) +{ + //----------------------------------------------------------------------------- + rlc_buffer_occupancy_t mac_rlc_buffer_occupancy_resp = 0; + 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; + srb_flag_t srb_flag = (channel_idP <= 2) ? SRB_FLAG_YES : SRB_FLAG_NO; + protocol_ctxt_t ctxt; + + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, enb_flagP, rntiP, frameP, 0, eNB_index); + + //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_MAC_RLC_GET_BUFFER_OCCUPANCY_IND,VCD_FUNCTION_IN); + + + /* Assumptions : for UE only */ + /* At each TTI, Buffer Occupancy is first computed in mac_rlc_status_ind called by MAC ue_scheduler() function */ + /* Then this function is called during MAC multiplexing ue_get_sdu(), and it may be call several times for the same bearer if it is in AM mode and there are several PDU types to transmit */ + AssertFatal(enb_flagP == FALSE,"RLC Tx mac_rlc_get_buffer_occupancy_ind function is not implemented for eNB LcId=%d\n", channel_idP); + + + key = RLC_COLL_KEY_LCID_VALUE(module_idP, rntiP, enb_flagP, channel_idP, srb_flag); + + + 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; + //LOG_W(RLC , "[%s] RLC not configured rb id %u lcid %u module %u!\n", __FUNCTION__, rb_id, channel_idP, ue_module_idP); + //LOG_D(RLC , "[%s] RLC not configured rb id %u lcid %u module %u!\n", __FUNCTION__, rb_id, channel_idP, ue_module_idP); + } + + switch (rlc_mode) { + case RLC_MODE_AM: + mac_rlc_buffer_occupancy_resp = rlc_am_get_buffer_occupancy_in_bytes(&ctxt, &rlc_union_p->rlc.am); + break; + + case RLC_MODE_UM: + mac_rlc_buffer_occupancy_resp = rlc_um_get_buffer_occupancy(&rlc_union_p->rlc.um); + break; + + default: + mac_rlc_buffer_occupancy_resp = 0 ; + } + + //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_MAC_RLC_GET_BUFFER_OCCUPANCY_IND,VCD_FUNCTION_OUT); + + return mac_rlc_buffer_occupancy_resp; +} + + diff --git a/openair2/PHY_INTERFACE/defs.h b/openair2/PHY_INTERFACE/defs.h index 5769d94a37..effc4c7877 100644 --- a/openair2/PHY_INTERFACE/defs.h +++ b/openair2/PHY_INTERFACE/defs.h @@ -170,7 +170,7 @@ typedef struct { PRACH_RESOURCES_t* (*ue_get_rach)(module_id_t Mod_id,int CC_id,frame_t frameP,uint8_t Msg3_flag,sub_frame_t subframe); /// Process Random-Access Response - uint16_t (*ue_process_rar)(module_id_t Mod_id,int CC_id,frame_t frameP, uint16_t ra_rnti, uint8_t *dlsch_buffer, uint16_t *t_crnti,uint8_t preamble_index); + uint16_t (*ue_process_rar)(module_id_t Mod_id,int CC_id,frame_t frameP, uint16_t ra_rnti, uint8_t *dlsch_buffer, uint16_t *t_crnti,uint8_t preamble_index, uint8_t* selected_rar_buffer); /// Get SR payload (0,1) from UE MAC uint32_t (*ue_get_SR)(module_id_t Mod_id,int CC_id,frame_t frameP,uint8_t eNB_id,rnti_t rnti,sub_frame_t subframe); diff --git a/openair2/RRC/LITE/L2_interface.c b/openair2/RRC/LITE/L2_interface.c index 64734cac9a..6a64d7811e 100644 --- a/openair2/RRC/LITE/L2_interface.c +++ b/openair2/RRC/LITE/L2_interface.c @@ -52,6 +52,10 @@ extern UE_MAC_INST *UE_mac_inst; # include "intertask_interface.h" #endif +#if defined(FLEXRAN_AGENT_SB_IF) +#include "flexran_agent_extern.h" +#endif + //#define RRC_DATA_REQ_DEBUG #define DEBUG_RRC 1 @@ -734,6 +738,13 @@ void mac_eNB_rrc_ul_failure(const module_id_t Mod_instP, else { LOG_W(RRC,"Frame %d, Subframe %d: UL failure: UE %x unknown \n",frameP,subframeP,rntiP); } +#if defined(FLEXRAN_AGENT_SB_IF) + if (rrc_agent_registered[Mod_instP]) { + agent_rrc_xface[Mod_instP]->flexran_agent_notify_ue_state_change(Mod_instP, + rntiP, + PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); + } +#endif rrc_mac_remove_ue(Mod_instP,rntiP); } diff --git a/openair2/RRC/LITE/proto.h b/openair2/RRC/LITE/proto.h index 8433980be4..20bc99ab79 100644 --- a/openair2/RRC/LITE/proto.h +++ b/openair2/RRC/LITE/proto.h @@ -33,6 +33,10 @@ #include "RRC/LITE/defs.h" +#if defined(FLEXRAN_AGENT_SB_IF) +#include "flexran_agent_extern.h" +#endif + //main.c int rrc_init_global_param(void); int L3_xface_init(void); @@ -254,6 +258,19 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration( const uint8_t ho_state ); + +#if defined(FLEXRAN_AGENT_SB_IF) + +void +flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + const uint8_t ho_state, + agent_reconf_rrc * trig_param + ); + +#endif + void rrc_eNB_generate_dedeicatedRRCConnectionReconfiguration( const protocol_ctxt_t* const ctxt_pP, diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index cedf5a11f5..84d9e802dd 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -975,6 +975,8 @@ rrc_ue_update_radioResourceConfigDedicated(RadioResourceConfigDedicated_t* radio physicalConfigDedicated2->pusch_ConfigDedicated = CALLOC(1,sizeof(*physicalConfigDedicated2->pusch_ConfigDedicated)); physicalConfigDedicated2->pucch_ConfigDedicated = CALLOC(1,sizeof(*physicalConfigDedicated2->pucch_ConfigDedicated)); physicalConfigDedicated2->cqi_ReportConfig = CALLOC(1,sizeof(*physicalConfigDedicated2->cqi_ReportConfig)); + physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic + = CALLOC(1,sizeof(*physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic)); physicalConfigDedicated2->soundingRS_UL_ConfigDedicated = CALLOC(1,sizeof(*physicalConfigDedicated2->soundingRS_UL_ConfigDedicated)); physicalConfigDedicated2->schedulingRequestConfig = CALLOC(1,sizeof(*physicalConfigDedicated2->schedulingRequestConfig)); physicalConfigDedicated2->antennaInfo = CALLOC(1,sizeof(*physicalConfigDedicated2->antennaInfo)); @@ -1036,14 +1038,25 @@ rrc_ue_update_radioResourceConfigDedicated(RadioResourceConfigDedicated_t* radio // Update cqi_ReportConfig if(radioResourceConfigDedicated->physicalConfigDedicated->cqi_ReportConfig != NULL) { - LOG_I(RRC,"Update cqi_ReportConfig config \n"); + LOG_I(RRC,"Update cqi_ReportConfig config (size=%d,%d)\n", sizeof(*physicalConfigDedicated2->cqi_ReportConfig), sizeof(CQI_ReportConfig_t)); if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->cqi_ReportConfig == NULL) UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->cqi_ReportConfig = CALLOC(1,sizeof(CQI_ReportConfig_t)); memcpy((char*)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->cqi_ReportConfig, (char*)radioResourceConfigDedicated->physicalConfigDedicated->cqi_ReportConfig, - sizeof(physicalConfigDedicated2->cqi_ReportConfig)); + sizeof(*physicalConfigDedicated2->cqi_ReportConfig)); + + if (radioResourceConfigDedicated->physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic != NULL) { + LOG_I(RRC,"Update cqi_ReportPeriodic config (size=%d,%d)\n", sizeof(*physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic), sizeof(CQI_ReportPeriodic_t)); + + if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->cqi_ReportConfig->cqi_ReportPeriodic == NULL) + UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->cqi_ReportConfig->cqi_ReportPeriodic = CALLOC(1,sizeof(CQI_ReportPeriodic_t)); + + memcpy((char*)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->cqi_ReportConfig->cqi_ReportPeriodic, + (char*)radioResourceConfigDedicated->physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic, + sizeof(*physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic)); + } } else { diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index da9d93c19a..6fbdd645ed 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -93,9 +93,6 @@ #include "SIMULATION/TOOLS/defs.h" // for taus -#if defined(FLEXRAN_AGENT_SB_IF) -#include "flexran_agent_extern.h" -#endif //#define XER_PRINT #ifdef PHY_EMUL @@ -832,6 +829,15 @@ rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s* #endif #endif +#if defined(FLEXRAN_AGENT_SB_IF) + if (rrc_agent_registered[enb_mod_idP]) { + agent_rrc_xface[enb_mod_idP]->flexran_agent_notify_ue_state_change(enb_mod_idP, + rnti, + PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); + } +#endif + + rrc_mac_remove_ue(enb_mod_idP,rnti); rrc_rlc_remove_ue(&ctxt); pdcp_remove_UE(&ctxt); @@ -1899,7 +1905,7 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* cons ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A1); - + if (ho_state == 1 /*HO_MEASURMENT */ ) { LOG_I(RRC, "[eNB %d] frame %d: requesting A2, A3, A4, A5, and A6 event reporting\n", ctxt_pP->module_id, ctxt_pP->frame); @@ -2158,6 +2164,599 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* cons PDCP_TRANSMISSION_MODE_CONTROL); } +#if defined(FLEXRAN_AGENT_SB_IF) + +//----------------------------------------------------------------------------- +void +flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + const uint8_t ho_state, + agent_reconf_rrc * trig_param + ) +//----------------------------------------------------------------------------- +{ + uint8_t buffer[RRC_BUF_SIZE]; + uint16_t size; + int i; + + // configure SRB1/SRB2, PhysicalConfigDedicated, MAC_MainConfig for UE + eNB_RRC_INST* rrc_inst = &eNB_rrc_inst[ctxt_pP->module_id]; + struct PhysicalConfigDedicated** physicalConfigDedicated = &ue_context_pP->ue_context.physicalConfigDedicated; + + struct SRB_ToAddMod *SRB2_config = NULL; + struct SRB_ToAddMod__rlc_Config *SRB2_rlc_config = NULL; + struct SRB_ToAddMod__logicalChannelConfig *SRB2_lchan_config = NULL; + struct LogicalChannelConfig__ul_SpecificParameters + *SRB2_ul_SpecificParameters = NULL; + SRB_ToAddModList_t* SRB_configList = ue_context_pP->ue_context.SRB_configList; + SRB_ToAddModList_t **SRB_configList2 = NULL; + + struct DRB_ToAddMod *DRB_config = NULL; + struct RLC_Config *DRB_rlc_config = NULL; + struct PDCP_Config *DRB_pdcp_config = NULL; + struct PDCP_Config__rlc_AM *PDCP_rlc_AM = NULL; + struct PDCP_Config__rlc_UM *PDCP_rlc_UM = NULL; + struct LogicalChannelConfig *DRB_lchan_config = NULL; + struct LogicalChannelConfig__ul_SpecificParameters + *DRB_ul_SpecificParameters = NULL; + DRB_ToAddModList_t** DRB_configList = &ue_context_pP->ue_context.DRB_configList; + DRB_ToAddModList_t** DRB_configList2 = NULL; + MAC_MainConfig_t *mac_MainConfig = NULL; + MeasObjectToAddModList_t *MeasObj_list = NULL; + MeasObjectToAddMod_t *MeasObj = NULL; + ReportConfigToAddModList_t *ReportConfig_list = NULL; + ReportConfigToAddMod_t *ReportConfig_per;//, *ReportConfig_A1, + // *ReportConfig_A2, *ReportConfig_A3, *ReportConfig_A4, *ReportConfig_A5; + MeasIdToAddModList_t *MeasId_list = NULL; + MeasIdToAddMod_t *MeasId0; //, *MeasId1, *MeasId2, *MeasId3, *MeasId4, *MeasId5; +#if Rel10 + long *sr_ProhibitTimer_r9 = NULL; + // uint8_t sCellIndexToAdd = rrc_find_free_SCell_index(enb_mod_idP, ue_mod_idP, 1); + //uint8_t sCellIndexToAdd = 0; +#endif + + long *logicalchannelgroup, *logicalchannelgroup_drb; + long *maxHARQ_Tx, *periodicBSR_Timer; + + RSRP_Range_t *rsrp = NULL; + struct MeasConfig__speedStatePars *Sparams = NULL; + QuantityConfig_t *quantityConfig = NULL; + CellsToAddMod_t *CellToAdd = NULL; + CellsToAddModList_t *CellsToAddModList = NULL; + struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList *dedicatedInfoNASList = NULL; + DedicatedInfoNAS_t *dedicatedInfoNas = NULL; + /* for no gcc warnings */ + (void)dedicatedInfoNas; + + C_RNTI_t *cba_RNTI = NULL; + + uint8_t xid = rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id); //Transaction_id, + +#ifdef CBA + //struct PUSCH_CBAConfigDedicated_vlola *pusch_CBAConfigDedicated_vlola; + uint8_t *cba_RNTI_buf; + cba_RNTI = CALLOC(1, sizeof(C_RNTI_t)); + cba_RNTI_buf = CALLOC(1, 2 * sizeof(uint8_t)); + cba_RNTI->buf = cba_RNTI_buf; + cba_RNTI->size = 2; + cba_RNTI->bits_unused = 0; + + // associate UEs to the CBa groups as a function of their UE id + if (rrc_inst->num_active_cba_groups) { + cba_RNTI->buf[0] = rrc_inst->cba_rnti[ue_mod_idP % rrc_inst->num_active_cba_groups] & 0xff; + cba_RNTI->buf[1] = 0xff; + LOG_D(RRC, + "[eNB %d] Frame %d: cba_RNTI = %x in group %d is attribued to UE %d\n", + enb_mod_idP, frameP, + rrc_inst->cba_rnti[ue_mod_idP % rrc_inst->num_active_cba_groups], + ue_mod_idP % rrc_inst->num_active_cba_groups, ue_mod_idP); + } else { + cba_RNTI->buf[0] = 0x0; + cba_RNTI->buf[1] = 0x0; + LOG_D(RRC, "[eNB %d] Frame %d: no cba_RNTI is configured for UE %d\n", enb_mod_idP, frameP, ue_mod_idP); + } + +#endif + + T(T_ENB_RRC_CONNECTION_RECONFIGURATION, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + // Configure SRB2 + /// SRB2 + SRB_configList2=&ue_context_pP->ue_context.SRB_configList2[xid]; + if (*SRB_configList2) { + free(*SRB_configList2); + } + *SRB_configList2 = CALLOC(1, sizeof(**SRB_configList2)); + memset(*SRB_configList2, 0, sizeof(**SRB_configList2)); + SRB2_config = CALLOC(1, sizeof(*SRB2_config)); + + SRB2_config->srb_Identity = 2; + SRB2_rlc_config = CALLOC(1, sizeof(*SRB2_rlc_config)); + SRB2_config->rlc_Config = SRB2_rlc_config; + + SRB2_rlc_config->present = SRB_ToAddMod__rlc_Config_PR_explicitValue; + SRB2_rlc_config->choice.explicitValue.present = RLC_Config_PR_am; + SRB2_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.t_PollRetransmit = T_PollRetransmit_ms15; + SRB2_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollPDU = PollPDU_p8; + SRB2_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollByte = PollByte_kB1000; + SRB2_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.maxRetxThreshold = UL_AM_RLC__maxRetxThreshold_t32; + SRB2_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_Reordering = T_Reordering_ms35; + SRB2_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_StatusProhibit = T_StatusProhibit_ms10; + + SRB2_lchan_config = CALLOC(1, sizeof(*SRB2_lchan_config)); + SRB2_config->logicalChannelConfig = SRB2_lchan_config; + + SRB2_lchan_config->present = SRB_ToAddMod__logicalChannelConfig_PR_explicitValue; + + SRB2_ul_SpecificParameters = CALLOC(1, sizeof(*SRB2_ul_SpecificParameters)); + + SRB2_ul_SpecificParameters->priority = 3; // let some priority for SRB1 and dedicated DRBs + SRB2_ul_SpecificParameters->prioritisedBitRate = + LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity; + SRB2_ul_SpecificParameters->bucketSizeDuration = + LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50; + + // LCG for CCCH and DCCH is 0 as defined in 36331 + logicalchannelgroup = CALLOC(1, sizeof(long)); + *logicalchannelgroup = 0; + + SRB2_ul_SpecificParameters->logicalChannelGroup = logicalchannelgroup; + + SRB2_lchan_config->choice.explicitValue.ul_SpecificParameters = SRB2_ul_SpecificParameters; + // this list has the configuration for SRB1 and SRB2 + ASN_SEQUENCE_ADD(&SRB_configList->list, SRB2_config); + // this list has only the configuration for SRB2 + ASN_SEQUENCE_ADD(&(*SRB_configList2)->list, SRB2_config); + + // Configure DRB + //*DRB_configList = CALLOC(1, sizeof(*DRB_configList)); + // list for all the configured DRB + if (*DRB_configList) { + free(*DRB_configList); + } + *DRB_configList = CALLOC(1, sizeof(**DRB_configList)); + memset(*DRB_configList, 0, sizeof(**DRB_configList)); + + // list for the configured DRB for a this xid + DRB_configList2=&ue_context_pP->ue_context.DRB_configList2[xid]; + if (*DRB_configList2) { + free(*DRB_configList2); + } + *DRB_configList2 = CALLOC(1, sizeof(**DRB_configList2)); + memset(*DRB_configList2, 0, sizeof(**DRB_configList2)); + + + /// DRB + DRB_config = CALLOC(1, sizeof(*DRB_config)); + + DRB_config->eps_BearerIdentity = CALLOC(1, sizeof(long)); + *(DRB_config->eps_BearerIdentity) = 5L; // LW set to first value, allowed value 5..15, value : x+4 + // DRB_config->drb_Identity = (DRB_Identity_t) 1; //allowed values 1..32 + // NN: this is the 1st DRB for this ue, so set it to 1 + DRB_config->drb_Identity = (DRB_Identity_t) 1; // (ue_mod_idP+1); //allowed values 1..32, value: x + DRB_config->logicalChannelIdentity = CALLOC(1, sizeof(long)); + *(DRB_config->logicalChannelIdentity) = (long)3; // value : x+2 + DRB_rlc_config = CALLOC(1, sizeof(*DRB_rlc_config)); + DRB_config->rlc_Config = DRB_rlc_config; + +#ifdef RRC_DEFAULT_RAB_IS_AM + DRB_rlc_config->present = RLC_Config_PR_am; + DRB_rlc_config->choice.am.ul_AM_RLC.t_PollRetransmit = T_PollRetransmit_ms50; + DRB_rlc_config->choice.am.ul_AM_RLC.pollPDU = PollPDU_p16; + DRB_rlc_config->choice.am.ul_AM_RLC.pollByte = PollByte_kBinfinity; + DRB_rlc_config->choice.am.ul_AM_RLC.maxRetxThreshold = UL_AM_RLC__maxRetxThreshold_t8; + DRB_rlc_config->choice.am.dl_AM_RLC.t_Reordering = T_Reordering_ms35; + DRB_rlc_config->choice.am.dl_AM_RLC.t_StatusProhibit = T_StatusProhibit_ms25; +#else + DRB_rlc_config->present = RLC_Config_PR_um_Bi_Directional; + DRB_rlc_config->choice.um_Bi_Directional.ul_UM_RLC.sn_FieldLength = SN_FieldLength_size10; + DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.sn_FieldLength = SN_FieldLength_size10; +#ifdef CBA + DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.t_Reordering = T_Reordering_ms5;//T_Reordering_ms25; +#else + DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.t_Reordering = T_Reordering_ms35; +#endif +#endif + + DRB_pdcp_config = CALLOC(1, sizeof(*DRB_pdcp_config)); + DRB_config->pdcp_Config = DRB_pdcp_config; + DRB_pdcp_config->discardTimer = CALLOC(1, sizeof(long)); + *DRB_pdcp_config->discardTimer = PDCP_Config__discardTimer_infinity; + DRB_pdcp_config->rlc_AM = NULL; + DRB_pdcp_config->rlc_UM = NULL; + + /* avoid gcc warnings */ + (void)PDCP_rlc_AM; + (void)PDCP_rlc_UM; + +#ifdef RRC_DEFAULT_RAB_IS_AM // EXMIMO_IOT + PDCP_rlc_AM = CALLOC(1, sizeof(*PDCP_rlc_AM)); + DRB_pdcp_config->rlc_AM = PDCP_rlc_AM; + PDCP_rlc_AM->statusReportRequired = FALSE; +#else + PDCP_rlc_UM = CALLOC(1, sizeof(*PDCP_rlc_UM)); + DRB_pdcp_config->rlc_UM = PDCP_rlc_UM; + PDCP_rlc_UM->pdcp_SN_Size = PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits; +#endif + DRB_pdcp_config->headerCompression.present = PDCP_Config__headerCompression_PR_notUsed; + + DRB_lchan_config = CALLOC(1, sizeof(*DRB_lchan_config)); + DRB_config->logicalChannelConfig = DRB_lchan_config; + DRB_ul_SpecificParameters = CALLOC(1, sizeof(*DRB_ul_SpecificParameters)); + DRB_lchan_config->ul_SpecificParameters = DRB_ul_SpecificParameters; + + DRB_ul_SpecificParameters->priority = 12; // lower priority than srb1, srb2 and other dedicated bearer + DRB_ul_SpecificParameters->prioritisedBitRate =LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8 ; + //LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity; + DRB_ul_SpecificParameters->bucketSizeDuration = + LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50; + + // LCG for DTCH can take the value from 1 to 3 as defined in 36331: normally controlled by upper layers (like RRM) + logicalchannelgroup_drb = CALLOC(1, sizeof(long)); + *logicalchannelgroup_drb = 1; + DRB_ul_SpecificParameters->logicalChannelGroup = logicalchannelgroup_drb; + + ASN_SEQUENCE_ADD(&(*DRB_configList)->list, DRB_config); + ASN_SEQUENCE_ADD(&(*DRB_configList2)->list, DRB_config); + + //ue_context_pP->ue_context.DRB_configList2[0] = &(*DRB_configList); + + mac_MainConfig = CALLOC(1, sizeof(*mac_MainConfig)); + // ue_context_pP->ue_context.mac_MainConfig = mac_MainConfig; + + mac_MainConfig->ul_SCH_Config = CALLOC(1, sizeof(*mac_MainConfig->ul_SCH_Config)); + + maxHARQ_Tx = CALLOC(1, sizeof(long)); + *maxHARQ_Tx = MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; + mac_MainConfig->ul_SCH_Config->maxHARQ_Tx = maxHARQ_Tx; + periodicBSR_Timer = CALLOC(1, sizeof(long)); + *periodicBSR_Timer = PeriodicBSR_Timer_r12_sf64; + mac_MainConfig->ul_SCH_Config->periodicBSR_Timer = periodicBSR_Timer; + mac_MainConfig->ul_SCH_Config->retxBSR_Timer = RetxBSR_Timer_r12_sf320; + mac_MainConfig->ul_SCH_Config->ttiBundling = 0; // FALSE + + mac_MainConfig->timeAlignmentTimerDedicated = TimeAlignmentTimer_infinity; + + mac_MainConfig->drx_Config = NULL; + + mac_MainConfig->phr_Config = CALLOC(1, sizeof(*mac_MainConfig->phr_Config)); + + mac_MainConfig->phr_Config->present = MAC_MainConfig__phr_Config_PR_setup; + mac_MainConfig->phr_Config->choice.setup.periodicPHR_Timer = MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; // sf20 = 20 subframes + + mac_MainConfig->phr_Config->choice.setup.prohibitPHR_Timer = MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; // sf20 = 20 subframes + + mac_MainConfig->phr_Config->choice.setup.dl_PathlossChange = MAC_MainConfig__phr_Config__setup__dl_PathlossChange_dB1; // Value dB1 =1 dB, dB3 = 3 dB + +#ifdef Rel10 + sr_ProhibitTimer_r9 = CALLOC(1, sizeof(long)); + *sr_ProhibitTimer_r9 = 0; // SR tx on PUCCH, Value in number of SR period(s). Value 0 = no timer for SR, Value 2= 2*SR + mac_MainConfig->ext1 = CALLOC(1, sizeof(struct MAC_MainConfig__ext1)); + mac_MainConfig->ext1->sr_ProhibitTimer_r9 = sr_ProhibitTimer_r9; + //sps_RA_ConfigList_rlola = NULL; +#endif + + //change the transmission mode for the primary component carrier + //TODO: add codebook subset restriction here + //TODO: change TM for secondary CC in SCelltoaddmodlist + if (*physicalConfigDedicated) { + if ((*physicalConfigDedicated)->antennaInfo) { + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.transmissionMode = rrc_inst->configuration.ue_TransmissionMode[0]; + LOG_D(RRC,"Setting transmission mode to %ld+1\n",rrc_inst->configuration.ue_TransmissionMode[0]); + if (rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm3) { + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction= + CALLOC(1,sizeof(AntennaInfoDedicated__codebookSubsetRestriction_PR)); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->present = + AntennaInfoDedicated__codebookSubsetRestriction_PR_n2TxAntenna_tm3; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm3.buf= MALLOC(1); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm3.buf[0] = 0xc0; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm3.size=1; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm3.bits_unused=6; + } + else if (rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm4) { + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction= + CALLOC(1,sizeof(AntennaInfoDedicated__codebookSubsetRestriction_PR)); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->present = + AntennaInfoDedicated__codebookSubsetRestriction_PR_n2TxAntenna_tm4; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm4.buf= MALLOC(1); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm4.buf[0] = 0xfc; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm4.size=1; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm4.bits_unused=2; + + } + else if (rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm5) { + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction= + CALLOC(1,sizeof(AntennaInfoDedicated__codebookSubsetRestriction_PR)); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->present = + AntennaInfoDedicated__codebookSubsetRestriction_PR_n2TxAntenna_tm5; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm5.buf= MALLOC(1); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm5.buf[0] = 0xf0; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm5.size=1; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm5.bits_unused=4; + } + else if (rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm6) { + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction= + CALLOC(1,sizeof(AntennaInfoDedicated__codebookSubsetRestriction_PR)); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->present = + AntennaInfoDedicated__codebookSubsetRestriction_PR_n2TxAntenna_tm6; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm6.buf= MALLOC(1); + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm6.buf[0] = 0xf0; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm6.size=1; + (*physicalConfigDedicated)->antennaInfo->choice.explicitValue.codebookSubsetRestriction->choice.n2TxAntenna_tm6.bits_unused=4; + } + } + else { + LOG_E(RRC,"antenna_info not present in physical_config_dedicated. Not reconfiguring!\n"); + } + if ((*physicalConfigDedicated)->cqi_ReportConfig) { + if ((rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm4) || + (rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm5) || + (rrc_inst->configuration.ue_TransmissionMode[0]==AntennaInfoDedicated__transmissionMode_tm6)) { + //feedback mode needs to be set as well + //TODO: I think this is taken into account in the PHY automatically based on the transmission mode variable + printf("setting cqi reporting mode to rm31\n"); +#if defined(Rel10) || defined(Rel14) + *((*physicalConfigDedicated)->cqi_ReportConfig->cqi_ReportModeAperiodic)=CQI_ReportModeAperiodic_rm31; +#else + *((*physicalConfigDedicated)->cqi_ReportConfig->cqi_ReportModeAperiodic)=CQI_ReportConfig__cqi_ReportModeAperiodic_rm31; // HLC CQI, no PMI +#endif + } + } + else { + LOG_E(RRC,"cqi_ReportConfig not present in physical_config_dedicated. Not reconfiguring!\n"); + } + } + else { + LOG_E(RRC,"physical_config_dedicated not present in RRCConnectionReconfiguration. Not reconfiguring!\n"); + } + + // Measurement ID list + MeasId_list = CALLOC(1, sizeof(*MeasId_list)); + memset((void *)MeasId_list, 0, sizeof(*MeasId_list)); + + MeasId0 = CALLOC(1, sizeof(*MeasId0)); + MeasId0->measId = 1; + MeasId0->measObjectId = 1; + MeasId0->reportConfigId = 1; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId0); + + /* + * Add one EUTRA Measurement Object + */ + + MeasObj_list = CALLOC(1, sizeof(*MeasObj_list)); + memset((void *)MeasObj_list, 0, sizeof(*MeasObj_list)); + + // Configure MeasObject + + MeasObj = CALLOC(1, sizeof(*MeasObj)); + memset((void *)MeasObj, 0, sizeof(*MeasObj)); + + MeasObj->measObjectId = 1; + MeasObj->measObject.present = MeasObjectToAddMod__measObject_PR_measObjectEUTRA; + MeasObj->measObject.choice.measObjectEUTRA.carrierFreq = 3350; //band 7, 2.68GHz + //MeasObj->measObject.choice.measObjectEUTRA.carrierFreq = 36090; //band 33, 1.909GHz + MeasObj->measObject.choice.measObjectEUTRA.allowedMeasBandwidth = AllowedMeasBandwidth_mbw25; + MeasObj->measObject.choice.measObjectEUTRA.presenceAntennaPort1 = 1; + MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.buf = CALLOC(1, sizeof(uint8_t)); + MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.buf[0] = 0; + MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.size = 1; + MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.bits_unused = 6; + MeasObj->measObject.choice.measObjectEUTRA.offsetFreq = NULL; // Default is 15 or 0dB + + MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList = + (CellsToAddModList_t *) CALLOC(1, sizeof(*CellsToAddModList)); + + CellsToAddModList = MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList; + + // Add adjacent cell lists (6 per eNB) + for (i = 0; i < 6; i++) { + CellToAdd = (CellsToAddMod_t *) CALLOC(1, sizeof(*CellToAdd)); + CellToAdd->cellIndex = i + 1; + CellToAdd->physCellId = get_adjacent_cell_id(ctxt_pP->module_id, i); + CellToAdd->cellIndividualOffset = Q_OffsetRange_dB0; + + ASN_SEQUENCE_ADD(&CellsToAddModList->list, CellToAdd); + } + + ASN_SEQUENCE_ADD(&MeasObj_list->list, MeasObj); + // rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measObjectToAddModList = MeasObj_list; + + // Report Configurations for periodical, A1-A5 events + + /* RRC Strategy Measurement */ + + + if (strcmp("one_shot", trig_param->trigger_policy) == 0){ + + trig_param->report_interval = 0; + trig_param->report_amount = 0; + + } + + else if (strcmp("event_driven", trig_param->trigger_policy) == 0){ + + trig_param->report_interval = 6; + trig_param->report_amount = 2; + + } + + else if (strcmp("periodical", trig_param->trigger_policy) == 0){ + + trig_param->report_interval = 1; + trig_param->report_amount = 7; + + } + + else { + + LOG_E(FLEXRAN_AGENT, "There is something wrong on RRC agent!"); + } + + + + ReportConfig_list = CALLOC(1, sizeof(*ReportConfig_list)); + + ReportConfig_per = CALLOC(1, sizeof(*ReportConfig_per)); + + // Periodical Measurement Report + + ReportConfig_per->reportConfigId = 1; + ReportConfig_per->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_periodical; + + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.choice.periodical.purpose = + ReportConfigEUTRA__triggerType__periodical__purpose_reportStrongestCells; + + // ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.timeToTrigger = TimeToTrigger_ms40; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.triggerQuantity = ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportInterval = trig_param->report_interval ;//ReportInterval_ms2048; // RRC counter frame- ms1024 is 1ms + + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportAmount = trig_param->report_amount; //ReportConfigEUTRA__reportAmount_r2; // put r1 to see once, r2 for 2 times and ... + + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_per); + + + + quantityConfig = CALLOC(1, sizeof(*quantityConfig)); + memset((void *)quantityConfig, 0, sizeof(*quantityConfig)); + quantityConfig->quantityConfigEUTRA = CALLOC(1, sizeof(struct QuantityConfigEUTRA)); + memset((void *)quantityConfig->quantityConfigEUTRA, 0, sizeof(*quantityConfig->quantityConfigEUTRA)); + quantityConfig->quantityConfigCDMA2000 = NULL; + quantityConfig->quantityConfigGERAN = NULL; + quantityConfig->quantityConfigUTRA = NULL; + quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP = + CALLOC(1, sizeof(*(quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP))); + quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ = + CALLOC(1, sizeof(*(quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ))); + *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP = FilterCoefficient_fc4; + *quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ = FilterCoefficient_fc4; + + +#if defined(ENABLE_ITTI) + /* Initialize NAS list */ + dedicatedInfoNASList = CALLOC(1, sizeof(struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList)); + + /* Add all NAS PDUs to the list */ + for (i = 0; i < ue_context_pP->ue_context.nb_of_e_rabs; i++) { + if (ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer != NULL) { + dedicatedInfoNas = CALLOC(1, sizeof(DedicatedInfoNAS_t)); + memset(dedicatedInfoNas, 0, sizeof(OCTET_STRING_t)); + OCTET_STRING_fromBuf(dedicatedInfoNas, + (char*)ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer, + ue_context_pP->ue_context.e_rab[i].param.nas_pdu.length); + ASN_SEQUENCE_ADD(&dedicatedInfoNASList->list, dedicatedInfoNas); + } + + /* TODO parameters yet to process ... */ + // { + // ue_context_pP->ue_context.e_rab[i].param.qos; + // ue_context_pP->ue_context.e_rab[i].param.sgw_addr; + // ue_context_pP->ue_context.e_rab[i].param.gtp_teid; + // } + + /* TODO should test if e RAB are Ok before! */ + ue_context_pP->ue_context.e_rab[i].status = E_RAB_STATUS_DONE; + LOG_D(RRC, "setting the status for the default DRB (index %d) to (%d,%s)\n", + i, ue_context_pP->ue_context.e_rab[i].status, "E_RAB_STATUS_DONE"); + } + + /* If list is empty free the list and reset the address */ + if (dedicatedInfoNASList->list.count == 0) { + free(dedicatedInfoNASList); + dedicatedInfoNASList = NULL; + } + +#endif + + memset(buffer, 0, RRC_BUF_SIZE); + + size = do_RRCConnectionReconfiguration(ctxt_pP, + buffer, + xid, //Transaction_id, + (SRB_ToAddModList_t*)NULL, // SRB_configList + (DRB_ToAddModList_t*)NULL, + (DRB_ToReleaseList_t*)NULL, // DRB2_list, + (struct SPS_Config*)NULL, // *sps_Config, + (struct PhysicalConfigDedicated*)*physicalConfigDedicated, +// #ifdef EXMIMO_IOT +// NULL, NULL, NULL,NULL, +// #else + (MeasObjectToAddModList_t*)MeasObj_list, + (ReportConfigToAddModList_t*)ReportConfig_list, + (QuantityConfig_t*)quantityConfig, + (MeasIdToAddModList_t*)MeasId_list, +// #endif + (MAC_MainConfig_t*)mac_MainConfig, + (MeasGapConfig_t*)NULL, + (MobilityControlInfo_t*)NULL, + (struct MeasConfig__speedStatePars*)Sparams, + (RSRP_Range_t*)rsrp, + (C_RNTI_t*)cba_RNTI, + (struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList*)dedicatedInfoNASList +#if defined(Rel10) || defined(Rel14) + , (SCellToAddMod_r10_t*)NULL +#endif + ); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC Connection Reconfiguration\n"); + for (i = 0; i < size; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)buffer)[i]); + } + LOG_F(RRC,"\n"); + //////////////////////////////////////// +#endif + +#if defined(ENABLE_ITTI) + + /* Free all NAS PDUs */ + for (i = 0; i < ue_context_pP->ue_context.nb_of_e_rabs; i++) { + if (ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer != NULL) { + /* Free the NAS PDU buffer and invalidate it */ + free(ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer); + ue_context_pP->ue_context.e_rab[i].param.nas_pdu.buffer = NULL; + } + } + +#endif + + LOG_I(RRC, + "[eNB %d] Frame %d, Logical Channel DL-DCCH, Generate RRCConnectionReconfiguration (bytes %d, UE id %x)\n", + ctxt_pP->module_id, ctxt_pP->frame, size, ue_context_pP->ue_context.rnti); + + LOG_D(RRC, + "[FRAME %05d][RRC_eNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcConnectionReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n", + ctxt_pP->frame, ctxt_pP->module_id, size, ue_context_pP->ue_context.rnti, rrc_eNB_mui, ctxt_pP->module_id, DCCH); + + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + buffer, + size, + MSC_AS_TIME_FMT" rrcConnectionReconfiguration UE %x MUI %d size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_pP->ue_context.rnti, + rrc_eNB_mui, + size); + + rrc_data_req( + ctxt_pP, + DCCH, + rrc_eNB_mui++, + SDU_CONFIRM_NO, + size, + buffer, + PDCP_TRANSMISSION_MODE_CONTROL); +} + +#endif //----------------------------------------------------------------------------- @@ -2246,41 +2845,41 @@ rrc_eNB_process_MeasurementReport( ) //----------------------------------------------------------------------------- { - T(T_ENB_RRC_MEASUREMENT_REPORT, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), - T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + // T(T_ENB_RRC_MEASUREMENT_REPORT, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + // T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); - LOG_I(RRC, "[eNB %d] Frame %d: Process Measurement Report From UE %x (Measurement Id %d)\n", - ctxt_pP->module_id, ctxt_pP->frame, ctxt_pP->rnti, (int)measResults2->measId); + // LOG_I(RRC, "[eNB %d] Frame %d: Process Measurement Report From UE %x (Measurement Id %d)\n", + // ctxt_pP->module_id, ctxt_pP->frame, ctxt_pP->rnti, (int)measResults2->measId); - if (measResults2->measResultNeighCells->choice.measResultListEUTRA.list.count > 0) { - LOG_I(RRC, "Physical Cell Id %d\n", - (int)measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]->physCellId); - LOG_I(RRC, "RSRP of Target %d\n", - (int)*(measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]-> - measResult.rsrpResult)); - LOG_I(RRC, "RSRQ of Target %d\n", - (int)*(measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]-> - measResult.rsrqResult)); - } + // if (measResults2->measResultNeighCells->choice.measResultListEUTRA.list.count > 0) { + // LOG_I(RRC, "Physical Cell Id %d\n", + // (int)measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]->physCellId); + // LOG_I(RRC, "RSRP of Target %d\n", + // (int)*(measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]-> + // measResult.rsrpResult)); + // LOG_I(RRC, "RSRQ of Target %d\n", + // (int)*(measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]-> + // measResult.rsrqResult)); + // } -#if defined(Rel10) || defined(Rel14) +// #if defined(Rel10) || defined(Rel14) LOG_I(RRC, "RSRP of Source %ld\n", measResults2->measResultPCell.rsrpResult); LOG_I(RRC, "RSRQ of Source %ld\n", measResults2->measResultPCell.rsrqResult); -#else - LOG_I(RRC, "RSRP of Source %d\n", measResults2->measResultServCell.rsrpResult); - LOG_I(RRC, "RSRQ of Source %d\n", measResults2->measResultServCell.rsrqResult); -#endif +// #else + // LOG_I(RRC, "RSRP of Source %d\n", measResults2->measResultServCell.rsrpResult); + // LOG_I(RRC, "RSRQ of Source %d\n", measResults2->measResultServCell.rsrqResult); +// #endif - if (ue_context_pP->ue_context.handover_info->ho_prepare != 0xF0) { - rrc_eNB_generate_HandoverPreparationInformation(ctxt_pP, - ue_context_pP, - measResults2->measResultNeighCells->choice. - measResultListEUTRA.list.array[0]->physCellId); - } else { - LOG_D(RRC, "[eNB %d] Frame %d: Ignoring MeasReport from UE %x as Handover is in progress... \n", ctxt_pP->module_id, ctxt_pP->frame, - ctxt_pP->rnti); - } + // if (ue_context_pP->ue_context.handover_info->ho_prepare != 0xF0) { + // rrc_eNB_generate_HandoverPreparationInformation(ctxt_pP, + // ue_context_pP, + // measResults2->measResultNeighCells->choice. + // measResultListEUTRA.list.array[0]->physCellId); + // } else { + // LOG_D(RRC, "[eNB %d] Frame %d: Ignoring MeasReport from UE %x as Handover is in progress... \n", ctxt_pP->module_id, ctxt_pP->frame, + // ctxt_pP->rnti); + // } //Look for IP address of the target eNB //Send Handover Request -> target eNB @@ -4295,6 +4894,13 @@ rrc_eNB_decode_ccch( } else { // no context available +#if defined(FLEXRAN_AGENT_SB_IF) + if (rrc_agent_registered[ctxt_pP->module_id]) { + agent_rrc_xface[ctxt_pP->module_id]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, + ctxt_pP->rnti, + PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); + } +#endif 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); @@ -4501,6 +5107,13 @@ rrc_eNB_decode_dcch( ue_context_p, &ul_dcch_msg->message.choice.c1.choice.measurementReport. criticalExtensions.choice.c1.choice.measurementReport_r8.measResults); + #if defined(FLEXRAN_AGENT_SB_IF) + + if (rrc_agent_registered[ctxt_pP->module_id]) { + agent_rrc_xface[ctxt_pP->eNB_index]->flexran_trigger_rrc_measurements (ctxt_pP->module_id, &ul_dcch_msg->message.choice.c1.choice.measurementReport.criticalExtensions.choice.c1.choice.measurementReport_r8.measResults); + } +#endif + break; case UL_DCCH_MessageType__c1_PR_rrcConnectionReconfigurationComplete: @@ -4553,8 +5166,8 @@ rrc_eNB_decode_dcch( #if defined(FLEXRAN_AGENT_SB_IF) //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future - if (mac_agent_registered[ctxt_pP->module_id]) { - agent_mac_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, + if (rrc_agent_registered[ctxt_pP->module_id]) { + agent_rrc_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, ue_context_p->ue_id_rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_UPDATED); } @@ -4657,8 +5270,8 @@ rrc_eNB_decode_dcch( #if defined(FLEXRAN_AGENT_SB_IF) //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future - if (mac_agent_registered[ctxt_pP->module_id]) { - agent_mac_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, + if (rrc_agent_registered[ctxt_pP->module_id]) { + agent_rrc_xface[ctxt_pP->eNB_index]->flexran_agent_notify_ue_state_change(ctxt_pP->module_id, ue_context_p->ue_id_rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED); } diff --git a/openair2/UTIL/LISTS/list2.c b/openair2/UTIL/LISTS/list2.c index abd9d2aacc..8daa19bfa4 100644 --- a/openair2/UTIL/LISTS/list2.c +++ b/openair2/UTIL/LISTS/list2.c @@ -233,6 +233,8 @@ list2_add_head (mem_block_t * elementP, list2_t * listP) // almost one element if (head == NULL) { + elementP->previous = NULL; + elementP->next = NULL; listP->head = elementP; listP->tail = elementP; } else { diff --git a/openair2/UTIL/LOG/log.c b/openair2/UTIL/LOG/log.c index 9a2d6a96ef..9c28c4b68d 100644 --- a/openair2/UTIL/LOG/log.c +++ b/openair2/UTIL/LOG/log.c @@ -28,6 +28,7 @@ */ +#define _GNU_SOURCE /* required for pthread_getname_np */ //#define LOG_TEST 1 #define COMPONENT_LOG @@ -1032,6 +1033,19 @@ void logRecord_mt(const char *file, const char *func, int line, int comp, if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; } + if ( (g_log->flag & FLAG_THREAD) || (c->flag & FLAG_THREAD) ) { +# define THREAD_NAME_LEN 128 + char threadname[THREAD_NAME_LEN]; + if (pthread_getname_np(pthread_self(), threadname, THREAD_NAME_LEN) != 0) + { + perror("pthread_getname_np : "); + } else { + len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s]", threadname); + if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL; + } +# undef THREAD_NAME_LEN + } + if ( (g_log->flag & FLAG_FUNCT) || (c->flag & FLAG_FUNCT) ) { len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s] ", func); @@ -1287,11 +1301,15 @@ int set_comp_log(int component, int level, int verbosity, int interval) LOG_EMERG); DevCheck((interval > 0) && (interval <= 0xFF), interval, 0, 0xFF); +#if 0 if ((verbosity == LOG_NONE) || (verbosity == LOG_LOW) || (verbosity == LOG_MED) || (verbosity == LOG_FULL) || (verbosity == LOG_HIGH)) { g_log->log_component[component].flag = verbosity; } +#else + g_log->log_component[component].flag = verbosity; +#endif g_log->log_component[component].level = level; g_log->log_component[component].interval = interval; diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp index f2d2af55c7..2dec4ff22d 100644 --- a/targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp +++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp @@ -45,6 +45,14 @@ lms_device_t* lms_device; lms_stream_t rx_stream; lms_stream_t tx_stream; +/* We have a strange behavior when we just start reading + * from the device (inconsistent values of the timestamp). + * A quick solution is to discard the very first read packet + * after a "start". + * The following global variable "first_rx" serves that purpose. + */ +static int first_rx = 0; + #define RXDCLENGTH 4096 #define NUMBUFF 32 @@ -94,6 +102,10 @@ int trx_lms_read(openair0_device *device, openair0_timestamp *ptimestamp, void * meta.flushPartialPacket = false; int ret; + if (first_rx == 1) { + first_rx = 0; + ret = LMS_RecvStream(&rx_stream,buff[0],nsamps,&meta,50); + } ret = LMS_RecvStream(&rx_stream,buff[0],nsamps,&meta,50); *ptimestamp = meta.timestamp; return ret; @@ -223,6 +235,8 @@ int trx_lms_start(openair0_device *device){ } + first_rx = 1; + rx_stream.channel = 0; rx_stream.fifoSize = 256*1024; rx_stream.throughputVsLatency = 0.1; @@ -355,7 +369,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg){ break; case 15360000: openair0_cfg[0].samples_per_packet = 2048; - openair0_cfg[0].tx_sample_advance = 450; + openair0_cfg[0].tx_sample_advance = 50; /* TODO: to be refined */ openair0_cfg[0].tx_bw = 15.36e6; openair0_cfg[0].rx_bw = 15.36e6; break; diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 2ad68765e3..68fcbc49d5 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -329,6 +329,7 @@ void help (void) { 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"); @@ -1386,6 +1387,7 @@ int main( int argc, char **argv ) { 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 @@ -1417,7 +1419,7 @@ int main( int argc, char **argv ) { 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, 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); @@ -1517,6 +1519,12 @@ int main( int argc, char **argv ) { 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_idUE_scan_carrier ); - if (UE->UE_scan_carrier == 1) { - UE->UE_scan_carrier = 0; + // rerun with new cell parameters and frequency-offset for (i=0; irf_map.card].rx_num_channels; i++) { openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET; + if (UE->UE_scan_carrier == 1) { if (freq_offset >= 0) openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] += abs(UE->common_vars.freq_offset); else @@ -337,6 +337,7 @@ static void *UE_thread_synch(void *arg) { downlink_frequency[CC_id][i] = openair0_cfg[CC_id].rx_freq[i]; freq_offset=0; } + } // reconfigure for potentially different bandwidth switch(UE->frame_parms.N_RB_DL) { @@ -375,6 +376,10 @@ static void *UE_thread_synch(void *arg) { LOG_E(HW,"Could not start the device\n"); oai_exit=1; }*/ + + if (UE->UE_scan_carrier == 1) { + + UE->UE_scan_carrier = 0; } else { AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), ""); UE->is_synchronized = 1; diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index c783ebe075..b60e73e37c 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -243,7 +243,7 @@ help (void) printf ("-L [0-1] 0 to disable new link adaptation, 1 to enable new link adapatation\n"); printf ("-m Gives a fixed DL mcs for eNB scheduler\n"); printf ("-M Set the machine ID for Ethernet-based emulation\n"); - printf ("-n Set the number of frames for the simulation\n"); + printf ("-n Set the number of frames for the simulation. 0 for no limit\n"); printf ("-O [enb_conf_file] eNB configuration file name\n"); printf ("-p Set the total number of machine in emulation - valid if M is set\n"); printf ("-P [trace type] Enable protocol analyzer. Possible values for OPT:\n");