From 5adc20ca0623f7d5341cbfadc2f785b4fa6f3012 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 18 Aug 2015 17:17:46 +0200 Subject: [PATCH 001/413] patch difference of TM7 dev with svn r7530 to git branch --- cmake_targets/CMakeLists.txt | 1 + common/utils/Makefile.inc | 2 +- openair1/PHY/INIT/lte_init.c | 42 +- .../LTE_ESTIMATION/bf_freq_domain_filters.m | 59 + openair1/PHY/LTE_ESTIMATION/defs.h | 7 + openair1/PHY/LTE_ESTIMATION/filt12_32.h | 72 + .../lte_dl_bf_channel_estimation.c | 96 ++ openair1/PHY/LTE_REFSIG/defs.h | 11 +- openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c | 393 +++++ openair1/PHY/LTE_REFSIG/lte_dl_uespec.c | 362 ----- openair1/PHY/LTE_REFSIG/lte_gold.c | 42 + openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 9 +- .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 795 +++++++++- .../PHY/LTE_TRANSPORT/dlsch_llr_computation.c | 12 +- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 1370 +++++++++-------- openair1/PHY/LTE_TRANSPORT/lte_mcs.c | 15 +- openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c | 217 +++ openair1/PHY/LTE_TRANSPORT/pmch.c | 5 +- openair1/PHY/LTE_TRANSPORT/proto.h | 49 +- openair1/PHY/MODULATION/slot_fep.c | 9 + openair1/PHY/Makefile.inc | 6 +- openair1/PHY/defs.h | 9 +- openair1/PHY/impl_defs_lte.h | 17 +- openair1/SCHED/phy_procedures_lte_eNb.c | 46 +- openair1/SCHED/phy_procedures_lte_ue.c | 27 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 321 +++- openair1/SIMULATION/LTE_PHY/mbmssim.c | 2 +- targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m | 18 +- 28 files changed, 2884 insertions(+), 1130 deletions(-) create mode 100644 openair1/PHY/LTE_ESTIMATION/bf_freq_domain_filters.m create mode 100644 openair1/PHY/LTE_ESTIMATION/filt12_32.h create mode 100644 openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c create mode 100644 openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c create mode 100644 openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 9bb062ba20..e3d2bed6f4 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -754,6 +754,7 @@ set(PHY_SRC ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_timefreq.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_adjust_sync.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_dl_mbsfn_channel_estimation.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_est_freq_offset.c diff --git a/common/utils/Makefile.inc b/common/utils/Makefile.inc index b7a1c82379..8c4ebbe31e 100644 --- a/common/utils/Makefile.inc +++ b/common/utils/Makefile.inc @@ -5,7 +5,7 @@ linux := $(shell if [ `uname` = "Linux" ] ; then echo "1" ; else echo "0" ; fi) CFLAGS += -std=gnu99 -#CFLAGS += -Wall -g -ggdb -Wstrict-prototypes -fno-strict-aliasing +CFLAGS += -Wall -g -ggdb -Wstrict-prototypes -fno-strict-aliasing # Need to force this option because default kernel module builder is wrong CFLAGS += $(call cc-option,-mpreferred-stack-boundary=4) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 9adbe31916..51c4939c56 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -923,14 +923,17 @@ void phy_init_lte_ue__PDSCH( LTE_UE_PDSCH* const pdsch, const LTE_DL_FRAME_PARMS pdsch->llr128_2ndstream = (int16_t**)malloc16_clear( sizeof(int16_t*) ); // FIXME! no further allocation for (int16_t*)pdsch->llr128 !!! expect SIGSEGV - pdsch->rxdataF_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pdsch->rxdataF_comp0 = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pdsch->rho = (int32_t**)malloc16_clear( frame_parms->nb_antennas_rx*sizeof(int32_t*) ); - pdsch->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pdsch->dl_ch_rho_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pdsch->dl_ch_rho2_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pdsch->dl_ch_mag0 = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); - pdsch->dl_ch_magb0 = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->rxdataF_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->rxdataF_uespec_pilots = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->rxdataF_comp0 = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->rho = (int32_t**)malloc16_clear( frame_parms->nb_antennas_rx*sizeof(int32_t*) ); + pdsch->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->dl_bf_ch_estimates = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->dl_bf_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->dl_ch_rho_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->dl_ch_rho2_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->dl_ch_mag0 = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); + pdsch->dl_ch_magb0 = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); // the allocated memory size is fixed: AssertFatal( frame_parms->nb_antennas_rx <= 2, "nb_antennas_rx > 2" ); @@ -941,13 +944,16 @@ void phy_init_lte_ue__PDSCH( LTE_UE_PDSCH* const pdsch, const LTE_DL_FRAME_PARMS for (int j=0; j<4; j++) { //frame_parms->nb_antennas_tx; j++) const int idx = (j<<1)+i; const size_t num = 7*2*frame_parms->N_RB_DL*12; - pdsch->rxdataF_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - pdsch->rxdataF_comp0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - pdsch->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - pdsch->dl_ch_rho_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - pdsch->dl_ch_rho2_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - pdsch->dl_ch_mag0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - pdsch->dl_ch_magb0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + pdsch->rxdataF_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + pdsch->rxdataF_uespec_pilots[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * frame_parms->N_RB_DL*12); + pdsch->rxdataF_comp0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + pdsch->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + pdsch->dl_bf_ch_estimates[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + pdsch->dl_bf_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t)*frame_parms->symbols_per_tti*(frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH) ); + pdsch->dl_ch_rho_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + pdsch->dl_ch_rho2_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + pdsch->dl_ch_mag0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); + pdsch->dl_ch_magb0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); } } } @@ -1268,10 +1274,10 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, if (abstraction_flag==0) { // TX vars - eNB_common_vars->txdata[eNB_id] = (int32_t**)malloc16( frame_parms->nb_antennas_tx*sizeof(int32_t*) ); - eNB_common_vars->txdataF[eNB_id] = (mod_sym_t **)malloc16( frame_parms->nb_antennas_tx*sizeof(mod_sym_t*) ); + eNB_common_vars->txdata[eNB_id] = (int32_t**)malloc16(phy_vars_eNB->nb_antennas_tx_phy*sizeof(int32_t*) ); + eNB_common_vars->txdataF[eNB_id] = (mod_sym_t **)malloc16(phy_vars_eNB->nb_antennas_tx_phy*sizeof(mod_sym_t*) ); - for (i=0; inb_antennas_tx; i++) { + for (i=0; inb_antennas_tx_phy; i++) { #ifdef USER_MODE eNB_common_vars->txdata[eNB_id][i] = (int32_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(int32_t) ); eNB_common_vars->txdataF[eNB_id][i] = (mod_sym_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t) ); diff --git a/openair1/PHY/LTE_ESTIMATION/bf_freq_domain_filters.m b/openair1/PHY/LTE_ESTIMATION/bf_freq_domain_filters.m new file mode 100644 index 0000000000..557c54dddd --- /dev/null +++ b/openair1/PHY/LTE_ESTIMATION/bf_freq_domain_filters.m @@ -0,0 +1,59 @@ +filter_length = 12; + +F = -3/4:1/4:7/4; +F_l = zeros(8,12); +F_r = zeros(8,12); +F_m = zeros(8,12); + +F2 =-3/5:1/5:8/5; + +for i=0:3 + F_l(i+1,:) = floor(16384*[F(8+i:-1:4) zeros(1,7-i)]); + F_r(i+1,:) = floor(16384*[zeros(1,4+i) F(4:end-i)]); + F_m(i+1,:) = floor(16384*[F(4-i:8) F(7:-1:1+i)]); +end + +for i=0:1 + F_l(i+5,:) = floor(16384*[F(8:-1:4-i) zeros(1,7-i)]); + F_r(i+5,:) = floor(16384*[zeros(1,5+i) F2(5+i) F2(7:end-i)]); + F_m(i+5,:) = floor(16384*[F(4-i:8) F2(8-i) F2(6:-1:1+i)]); +end + +for i=2:3 + F_l(i+5,:) = floor(16384*[F2(end:-1:7) F2(8-i) zeros(1,5)]); + F_r(i+5,:) = floor(16384*[zeros(1,4+i) F(4:end-i)]); + F_m(i+5,:) = floor(16384*[F2(4-i:6) F2(4+i) F(8:-1:1+i)]); +end + + +fd = fopen("filt12_32.h","w"); + +for i=0:3 + fprintf(fd,"short filt12_l%d[12] = {\n",i); + fprintf(fd,"%d,",F_l(i+1,1:end-1)); + fprintf(fd,"%d};\n\n",F_l(i+1,end)); + + fprintf(fd,"short filt12_r%d[12] = {\n",i); + fprintf(fd,"%d,",F_r(i+1,1:end-1)); + fprintf(fd,"%d};\n\n",F_r(i+1,end)); + + fprintf(fd,"short filt12_m%d[12] = {\n",i); + fprintf(fd,"%d,",F_m(i+1,1:end-1)); + fprintf(fd,"%d};\n\n",F_m(i+1,end)); +end + +for i=0:3 + fprintf(fd,"short filt12_l%d_dc[12] = {\n",i); + fprintf(fd,"%d,",F_l(i+5,1:end-1)); + fprintf(fd,"%d};\n\n",F_l(i+5,end)); + + fprintf(fd,"short filt12_r%d_dc[12] = {\n",i); + fprintf(fd,"%d,",F_r(i+5,1:end-1)); + fprintf(fd,"%d};\n\n",F_r(i+5,end)); + + fprintf(fd,"short filt12_m%d_dc[12] = {\n",i); + fprintf(fd,"%d,",F_m(i+5,1:end-1)); + fprintf(fd,"%d};\n\n",F_m(i+5,end)); +end + +fclose(fd); diff --git a/openair1/PHY/LTE_ESTIMATION/defs.h b/openair1/PHY/LTE_ESTIMATION/defs.h index ee8d9d8c6f..4763602525 100644 --- a/openair1/PHY/LTE_ESTIMATION/defs.h +++ b/openair1/PHY/LTE_ESTIMATION/defs.h @@ -124,6 +124,13 @@ int lte_dl_channel_estimation(PHY_VARS_UE *phy_vars_ue, uint8_t symbol); +int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, + module_id_t eNB_id, + uint8_t eNB_offset, + uint8_t Ns, + uint8_t p, + uint8_t symbol); + int lte_dl_msbfn_channel_estimation(PHY_VARS_UE *phy_vars_ue, module_id_t eNB_id, uint8_t eNB_offset, diff --git a/openair1/PHY/LTE_ESTIMATION/filt12_32.h b/openair1/PHY/LTE_ESTIMATION/filt12_32.h new file mode 100644 index 0000000000..602f7c2c3f --- /dev/null +++ b/openair1/PHY/LTE_ESTIMATION/filt12_32.h @@ -0,0 +1,72 @@ +short filt12_l0[12] = { +16384,12288,8192,4096,0,0,0,0,0,0,0,0}; + +short filt12_r0[12] = { +0,0,0,0,0,4096,8192,12288,16384,20480,24576,28672}; + +short filt12_m0[12] = { +0,4096,8192,12288,16384,12288,8192,4096,0,-4096,-8192,-12288}; + +short filt12_l1[12] = { +20480,16384,12288,8192,4096,0,0,0,0,0,0,0}; + +short filt12_r1[12] = { +0,0,0,0,0,0,4096,8192,12288,16384,20480,24576}; + +short filt12_m1[12] = { +-4096,0,4096,8192,12288,16384,12288,8192,4096,0,-4096,-8192}; + +short filt12_l2[12] = { +24576,20480,16384,12288,8192,4096,0,0,0,0,0,0}; + +short filt12_r2[12] = { +0,0,0,0,0,0,0,4096,8192,12288,16384,20480}; + +short filt12_m2[12] = { +-8192,-4096,0,4096,8192,12288,16384,12288,8192,4096,0,-4096}; + +short filt12_l3[12] = { +28672,24576,20480,16384,12288,8192,4096,0,0,0,0,0}; + +short filt12_r3[12] = { +0,0,0,0,0,0,0,0,4096,8192,12288,16384}; + +short filt12_m3[12] = { +-12288,-8192,-4096,0,4096,8192,12288,16384,12288,8192,4096,0}; + +short filt12_l0_dc[12] = { +16384,12288,8192,4096,0,0,0,0,0,0,0,0}; + +short filt12_r0_dc[12] = { +0,0,0,0,0,3276,9830,13107,16384,19660,22937,26214}; + +short filt12_m0_dc[12] = { +0,4096,8192,12288,16384,13107,6553,3276,0,-3277,-6554,-9831}; + +short filt12_l1_dc[12] = { +16384,12288,8192,4096,0,-4096,0,0,0,0,0,0}; + +short filt12_r1_dc[12] = { +0,0,0,0,0,0,6553,9830,13107,16384,19660,22937}; + +short filt12_m1_dc[12] = { +-4096,0,4096,8192,12288,16384,9830,6553,3276,0,-3277,-6554}; + +short filt12_l2_dc[12] = { +26214,22937,19660,16384,13107,9830,6553,0,0,0,0,0}; + +short filt12_r2_dc[12] = { +0,0,0,0,0,0,0,4096,8192,12288,16384,20480}; + +short filt12_m2_dc[12] = { +-6554,-3277,0,3276,6553,6553,16384,12288,8192,4096,0,-4096}; + +short filt12_l3_dc[12] = { +26214,22937,19660,16384,13107,9830,3276,0,0,0,0,0}; + +short filt12_r3_dc[12] = { +0,0,0,0,0,0,0,0,4096,8192,12288,16384}; + +short filt12_m3_dc[12] = { +-9831,-6554,-3277,0,3276,6553,9830,16384,12288,8192,4096,0}; + diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c new file mode 100644 index 0000000000..9707b15b35 --- /dev/null +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c @@ -0,0 +1,96 @@ +/******************************************************************************* + 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + + *******************************************************************************/ +#ifdef USER_MODE +#include +#endif +#include "defs.h" +#include "PHY/defs.h" +#include "filt12_32.h" +//#define DEBUG_CH + +/*To be accomplished*/ +int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, + uint8_t eNB_id, + uint8_t eNB_offset, + unsigned char Ns, + unsigned char p, + unsigned char symbol) +{ + + unsigned char aarx; + int uespec_pilot[9][200]; + short *pil, *rxF; + + //LTE_UE_PDSCH *lte_ue_pdsch_vars = phy_vars_ue->lte_ue_pdsch_vars[eNB_id]; + int **rxdataF = phy_vars_ue->lte_ue_common_vars.rxdataF; + int32_t **dl_bf_ch_estimates = phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates; + + int beamforming_mode = phy_vars_ue->transmission_mode>7?phy_vars_ue->transmission_mode : 0; + + // define interpolation filters + //.... + + //ch_offset = phy_vars_ue->lte_frame_parms.ofdm_symbol_size*symbol; + + //generate ue specific pilots + if(beamforming_mode==7) + lte_dl_ue_spec_rx(phy_vars_ue,&uespec_pilot[p-5][0],Ns,p,0); + else if (beamforming_mode>7) + lte_dl_ue_spec_rx(phy_vars_ue,&uespec_pilot[p-6][0],Ns,p,0); + else if (beamforming_mode==0) + msg("No beamforming is performed.\n"); + else + msg("Beamforming mode not supported yet.\n"); + + + if(beamforming_mode==7) { + + for (aarx=0; aarxlte_frame_parms.nb_antennas_rx;aarx++) { + + /* pil = (short *)&uespec_pilot[0][0]; + rxF = (short *)&rxdataF_uespec[aarx][(symbol-1)/3*frame_parms->N_RB_DL*(3+frame_parms->Ncp)]; + dl_ch = (short *)&dl_bf_ch_estimates[aarx][ch_offset]; + + memset(dl_ch,0,4*(phy_vars_ue->lte_frame_parms.ofdm_symbol_size)); + //estimation and interpolation */ + } + + } else if (beamforming_mode==0){ + msg("No beamforming is performed.\n"); + return(-1); + } else { + msg("Beamforming mode is not supported yet.\n"); + return(-1); + } + + //temporal interpolation + + return(0); + +} diff --git a/openair1/PHY/LTE_REFSIG/defs.h b/openair1/PHY/LTE_REFSIG/defs.h index 2127380565..e9482060a7 100644 --- a/openair1/PHY/LTE_REFSIG/defs.h +++ b/openair1/PHY/LTE_REFSIG/defs.h @@ -52,12 +52,13 @@ unsigned int lte_gold_generic(unsigned int *x1, unsigned int *x2, unsigned char void lte_gold(LTE_DL_FRAME_PARMS *frame_parms,uint32_t lte_gold_table[20][2][14],uint16_t Nid_cell); +void lte_gold_ue_spec(LTE_DL_FRAME_PARMS *frame_parms,uint32_t lte_gold_uespec_table[2][20][2][21],uint16_t Nid_cell, uint16_t *n_idDMRS); + /*!\brief This function generates the LTE Gold sequence (36-211, Sec 7.2), specifically for DL UE-specific reference signals for antenna ports 7..14. @param frame_parms LTE DL Frame parameters @param lte_gold_uespec_table pointer to table where sequences are stored @param Nid_cell Cell Id (to compute sequences for local and adjacent cells) @param n_idDMRS Scrambling identity for TM10*/ -void lte_gold_ue_spec(LTE_DL_FRAME_PARMS *frame_parms,uint32_t lte_gold_uespec_table[2][20][2][21],uint16_t Nid_cell, uint16_t *n_idDMRS); void lte_gold_mbsfn(LTE_DL_FRAME_PARMS *frame_parms,uint32_t lte_gold_mbsfn_table[10][3][42],uint16_t Nid_MBSFN); @@ -84,6 +85,7 @@ int lte_dl_cell_spec(PHY_VARS_eNB *phy_vars_eNB, @param output Output vector for OFDM symbol (Frequency Domain) @param amp Q15 amplitude @param Ns Slot number (0..19) +@param lprime symbol (0,1) @param p antenna index @param SS_flag Flag to indicate special subframe */ @@ -92,6 +94,7 @@ int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, mod_sym_t *output, short amp, uint8_t Ns, + uint8_t lprime, uint8_t p, int SS_flag ); @@ -123,6 +126,12 @@ int lte_dl_cell_spec_rx(PHY_VARS_UE *phy_vars_ue, unsigned char l, unsigned char p); +int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, + mod_sym_t *output, + unsigned char Ns, + unsigned char p, + int SS_flag); + int lte_dl_mbsfn_rx(PHY_VARS_UE *phy_vars_ue, int *output, int subframe, diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c b/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c new file mode 100644 index 0000000000..64c4e8782e --- /dev/null +++ b/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c @@ -0,0 +1,393 @@ +/******************************************************************************* + 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + + *******************************************************************************/ + +/*! \file PHY/LTE_REFSIG/lte_dl_ue_spec.c +* \brief Top-level routines for generating UE-specific Reference signals from 36-211, V11.3.0 2013-06 +* \author R. Knopp X. Jiang +* \date 2015 +* \version 0.1 +* \company Eurecom +* \email: knopp@eurecom.fr xiwen.jiang@eurecom.fr +* \note +* \warning +*/ + +#ifdef USER_MODE +#include +#include +#endif + +#include "defs.h" +#include "PHY/defs.h" +#include "log.h" + +//extern unsigned int lte_gold_table[3][20][2][14]; +//#define DEBUG_DL_CELL_SPEC + +int Wbar_NCP[8][4] = {{1,1,1,1},{1,-1,1,-1},{1,1,1,1},{1,-1,1,-1},{1,1,-1,-1},{-1,-1,1,1},{1,-1,-1,1},{-1,1,1,-1}}; + +int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, + uint8_t UE_id, + mod_sym_t *output, + short amp, + uint8_t Ns, + uint8_t lprime, + uint8_t p, + int SS_flag ) +{ + + mod_sym_t qpsk[4],nqpsk[4]; + int16_t k=0,a; + int mprime,mprime_dword,mprime_qpsk_symb; + unsigned nushift,kprime; + // LTE_eNB_DLSCH_t *dlsch = phy_vars_eNB->dlsch_eNB[UE_id][0]; + + a = (amp*ONE_OVER_SQRT2_Q15)>>15; + ((short *)&qpsk[0])[0] = a; + ((short *)&qpsk[0])[1] = a; + ((short *)&qpsk[1])[0] = -a; + ((short *)&qpsk[1])[1] = a; + ((short *)&qpsk[2])[0] = a; + ((short *)&qpsk[2])[1] = -a; + ((short *)&qpsk[3])[0] = -a; + ((short *)&qpsk[3])[1] = -a; + + ((short *)&nqpsk[0])[0] = -a; + ((short *)&nqpsk[0])[1] = -a; + ((short *)&nqpsk[1])[0] = a; + ((short *)&nqpsk[1])[1] = -a; + ((short *)&nqpsk[2])[0] = -a; + ((short *)&nqpsk[2])[1] = a; + ((short *)&nqpsk[3])[0] = a; + ((short *)&nqpsk[3])[1] = a; + + if (p==5) { + if (SS_flag==0) { + if (phy_vars_eNB->lte_frame_parms.Ncp == NORMAL) { + // this is 3GPP 36-211 6.10.3.2, NORMAL CP, p=5 + + nushift = phy_vars_eNB->lte_frame_parms.Nid_cell%3; + + if(lprime==0){ + kprime=nushift; + }else{ + kprime=(nushift+2*lprime)%4; + } + + k = kprime+phy_vars_eNB->lte_frame_parms.first_carrier_offset; + printf("lte_dl_ue_spec:k=%d\n",k); + + for (mprime=0;mprime<3*phy_vars_eNB->lte_frame_parms.N_RB_DL-1;mprime++) { + mprime_dword = mprime>>4; + mprime_qpsk_symb = mprime&0xf; + + //output[k] = qpsk[(phy_vars_eNB->lte_gold_uespec_port5_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + output[k] = 0xffffffff; + + k += 4; + if (k >= phy_vars_eNB->lte_frame_parms.ofdm_symbol_size) { + k++; // skip DC carrier + k-=phy_vars_eNB->lte_frame_parms.ofdm_symbol_size; + } + + } + } + } + } else if (p>=7) { + printf("lte_dl_ue_spec:antenna ports >=7 not supported yet!\n"); + } else { + LOG_E(PHY,"Illegal p %d UE specific pilots\n",p); + } + + return(0); +} + + +int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, + mod_sym_t *output, + unsigned char Ns, + unsigned char p, + int SS_flag) +{ + mod_sym_t qpsk[4],nqpsk[4],*qpsk_p,*output_p; + int16_t a; + int w,lprime,mprime,ind,l,ind_dword,ind_qpsk_symb,nPRB; + short pamp; + + // Compute the correct pilot amplitude, sqrt_rho_b = Q3.13 + pamp = ONE_OVER_SQRT2_Q15; + + // This includes complex conjugate for channel estimation + ((short *)&qpsk[0])[0] = pamp; + ((short *)&qpsk[0])[1] = -pamp; + ((short *)&qpsk[1])[0] = -pamp; + ((short *)&qpsk[1])[1] = -pamp; + ((short *)&qpsk[2])[0] = pamp; + ((short *)&qpsk[2])[1] = pamp; + ((short *)&qpsk[3])[0] = -pamp; + ((short *)&qpsk[3])[1] = pamp; + + ((short *)&nqpsk[0])[0] = -pamp; + ((short *)&nqpsk[0])[1] = pamp; + ((short *)&nqpsk[1])[0] = pamp; + ((short *)&nqpsk[1])[1] = pamp; + ((short *)&nqpsk[2])[0] = -pamp; + ((short *)&nqpsk[2])[1] = -pamp; + ((short *)&nqpsk[3])[0] = pamp; + ((short *)&nqpsk[3])[1] = -pamp; + + if (p>=7) { + if (SS_flag==0) { + if (phy_vars_ue->lte_frame_parms.Ncp == NORMAL) { + // this is 3GPP 36-211 6.10.3.2, NORMAL CP, p>=7 + + output_p = output; + + for (lprime=0; lprime<2; lprime++) { + + ind = 3*lprime*phy_vars_ue->lte_frame_parms.N_RB_DL; + l = lprime + ((Ns&1)<<1); + + // loop over pairs of PRBs, this is the periodicity of the W_bar_NCP sequence + // unroll the computations for the 6 pilots, select qpsk or nqpsk as function of W_bar_NCP + for (nPRB=0; nPRBlte_frame_parms.N_RB_DL; nPRB+=2) { + + // First pilot + w = Wbar_NCP[p-7][l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + + + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + + +#ifdef DEBUG_DL_UESPEC + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); +#endif + + output_p++; + ind++; + + w = Wbar_NCP[p-7][3-l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + + // Second pilot + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + +#ifdef DEBUG_DL_UESPEC + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); +#endif + + output_p++; + ind++; + + w = Wbar_NCP[p-7][l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + // Third pilot + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + +#ifdef DEBUG_DL_UESPEC + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); +#endif + + output_p++; + ind++; + + // Fourth pilot + w = Wbar_NCP[p-7][3-l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + + + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + + +#ifdef DEBUG_DL_UESPEC + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); +#endif + + output_p++; + ind++; + + w = Wbar_NCP[p-7][l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + + // Fifth pilot + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + +#ifdef DEBUG_DL_UESPEC + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); +#endif + + output_p++; + ind++; + + w = Wbar_NCP[p-7][3-l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + // Sixth pilot + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + +#ifdef DEBUG_DL_UESPEC + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); +#endif + + output_p++; + ind++; + } + } + } else { + LOG_E(PHY,"Special subframe not supported for UE specific pilots yet\n"); + } + } + } else if (p==5) { + if (SS_flag==0) { + if (phy_vars_ue->lte_frame_parms.Ncp == NORMAL) { + + for (lprime=0;lprime<2;lprime++) { + ind = 3*lprime*phy_vars_ue->lte_frame_parms.N_RB_DL; + + for (mprime=0;mprime<3*phy_vars_ue->lte_frame_parms.N_RB_DL-1;mprime++) { + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_port5_table[Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + *output_p++; + } + } + } + } + } else { + LOG_E(PHY,"Illegal p %d UE specific pilots\n",p); + } + + return(0); +} + + + +#ifdef LTE_DL_CELL_SPEC_MAIN + + + +//extern int write_output(const char *,const char *,void *,int,int,char); +// flag change eren +extern int write_output(const char *,const char *,void *,int,int,char); +main() +{ + + unsigned short Nid_cell=0; + unsigned int Ncp = 0; + int output00[1024]; + int output01[1024]; + int output10[1024]; + int output11[1024]; + + memset(output00,0,1024*sizeof(int)); + memset(output01,0,1024*sizeof(int)); + memset(output10,0,1024*sizeof(int)); + memset(output11,0,1024*sizeof(int)); + + lte_gold(Nid_cell,Ncp); + + lte_dl_ue_spec(output00, + ONE_OVER_SQRT2_Q15, + 50, + Nid_cell, + Ncp, + 0, + 0, + 0, + 0); + + lte_dl_ue_spec(output10, + ONE_OVER_SQRT2_Q15, + 50, + Nid_cell, + Ncp, + 0, + 1, + 0, + 0); + + lte_dl_ue_spec(output01, + ONE_OVER_SQRT2_Q15, + 50, + Nid_cell, + Ncp, + 0, + 0, + 1, + 0); + + lte_dl_ue_spec(output11, + ONE_OVER_SQRT2_Q15, + 50, + Nid_cell, + Ncp, + 0, + 1, + 1, + 0); + + + write_output("dl_ue_spec00.m","dl_cs00",output00,1024,1,1); + write_output("dl_ue_spec01.m","dl_cs01",output01,1024,1,1); + write_output("dl_ue_spec10.m","dl_cs10",output10,1024,1,1); + write_output("dl_ue_spec11.m","dl_cs11",output11,1024,1,1); +} + + +#endif diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c b/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c index b40f6ddfda..e69de29bb2 100644 --- a/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c +++ b/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c @@ -1,362 +0,0 @@ -/******************************************************************************* - 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@eurecom.fr - - Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - - *******************************************************************************/ - -/*! \file PHY/LTE_REFSIG/lte_dl_uespec.c -* \brief Top-level routines for generating UE-specific Reference signals from 36-211, V11.3.0 2013-06 -* \author R. Knopp -* \date 2014 -* \version 0.1 -* \company Eurecom -* \email: knopp@eurecom.fr -* \note -* \warning -*/ - -#ifdef USER_MODE -#include -#include -#endif - -#include "defs.h" -#include "PHY/defs.h" -#include "log.h" - -//extern unsigned int lte_gold_table[3][20][2][14]; -//#define DEBUG_DL_CELL_SPEC - -int Wbar_NCP[8][4] = {{1,1,1,1},{1,-1,1,-1},{1,1,1,1},{1,-1,1,-1},{1,1,-1,-1},{-1,-1,1,1},{1,-1,-1,1},{-1,1,1,-1}}; - -int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, - uint8_t UE_id, - mod_sym_t *output, - short amp, - uint8_t Ns, - uint8_t p, - int SS_flag ) -{ - - mod_sym_t qpsk[4],nqpsk[4],*qpsk_p,*output_p; - int16_t a; - int w,lprime,ind,l,ind_dword,ind_qpsk_symb,nPRB; - // LTE_eNB_DLSCH_t *dlsch = phy_vars_eNB->dlsch_eNB[UE_id][0]; - - a = (amp*ONE_OVER_SQRT2_Q15)>>15; - ((short *)&qpsk[0])[0] = a; - ((short *)&qpsk[0])[1] = a; - ((short *)&qpsk[1])[0] = -a; - ((short *)&qpsk[1])[1] = a; - ((short *)&qpsk[2])[0] = a; - ((short *)&qpsk[2])[1] = -a; - ((short *)&qpsk[3])[0] = -a; - ((short *)&qpsk[3])[1] = -a; - - ((short *)&nqpsk[0])[0] = -a; - ((short *)&nqpsk[0])[1] = -a; - ((short *)&nqpsk[1])[0] = a; - ((short *)&nqpsk[1])[1] = -a; - ((short *)&nqpsk[2])[0] = -a; - ((short *)&nqpsk[2])[1] = a; - ((short *)&nqpsk[3])[0] = a; - ((short *)&nqpsk[3])[1] = a; - - if (p>=7) { - if (SS_flag==0) { - if (phy_vars_eNB->lte_frame_parms.Ncp == NORMAL) { - // this is 3GPP 36-211 6.10.3.2, NORMAL CP, p>=7 - - - - // position output pointer to 5th symbol in slot - output_p = output+(60*phy_vars_eNB->lte_frame_parms.N_RB_DL); - - // shift to 2nd RE in PRB for p=7,8,11,13 - if ((p==7) || (p==8) || (p==11) || (p==13)) output_p++; - - - for (lprime=0; lprime<2; lprime++) { - - ind = 3*lprime*phy_vars_eNB->lte_frame_parms.N_RB_DL; - l = lprime + ((Ns&1)<<1); - - // loop over pairs of PRBs, this is the periodicity of the W_bar_NCP sequence - // unroll the computations for the 6 pilots, select qpsk or nqpsk as function of W_bar_NCP - for (nPRB=0; nPRBlte_frame_parms.N_RB_DL; nPRB+=2) { - - // First pilot - w = Wbar_NCP[p-7][l]; - qpsk_p = (w==1) ? qpsk : nqpsk; - - - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; - - *output_p = qpsk_p[(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; - - -#ifdef DEBUG_DL_UESPEC - LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", - Ns,l,m,mprime_dword,mprime_qpsk_symb); - LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); -#endif - - output_p+=5; - ind++; - - w = Wbar_NCP[p-7][3-l]; - qpsk_p = (w==1) ? qpsk : nqpsk; - - // Second pilot - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; - - *output_p = qpsk_p[(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; - -#ifdef DEBUG_DL_UESPEC - LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", - Ns,l,m,mprime_dword,mprime_qpsk_symb); - LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); -#endif - - output_p+=5; - ind++; - - w = Wbar_NCP[p-7][l]; - qpsk_p = (w==1) ? qpsk : nqpsk; - // Third pilot - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; - - *output_p = qpsk_p[(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; - -#ifdef DEBUG_DL_UESPEC - LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", - Ns,l,m,mprime_dword,mprime_qpsk_symb); - LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); -#endif - - output_p+=2; - ind++; - - // Fourth pilot - w = Wbar_NCP[p-7][3-l]; - qpsk_p = (w==1) ? qpsk : nqpsk; - - - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; - - *output_p = qpsk_p[(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; - - -#ifdef DEBUG_DL_UESPEC - LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", - Ns,l,m,mprime_dword,mprime_qpsk_symb); - LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); -#endif - - output_p+=5; - ind++; - - w = Wbar_NCP[p-7][l]; - qpsk_p = (w==1) ? qpsk : nqpsk; - - // Fifth pilot - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; - - *output_p = qpsk_p[(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; - -#ifdef DEBUG_DL_UESPEC - LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", - Ns,l,m,mprime_dword,mprime_qpsk_symb); - LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); -#endif - - output_p+=5; - ind++; - - w = Wbar_NCP[p-7][3-l]; - qpsk_p = (w==1) ? qpsk : nqpsk; - // Sixth pilot - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; - - *output_p = qpsk_p[(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; - -#ifdef DEBUG_DL_UESPEC - LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", - Ns,l,m,mprime_dword,mprime_qpsk_symb); - LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); -#endif - - output_p+=2; - ind++; - } - } - } else { - LOG_E(PHY,"Special subframe not supported for UE specific pilots yet\n"); - } - } - } else if (p==5) { - LOG_E(PHY,"p=5 not supported for UE specific pilots yet\n"); - } else { - LOG_E(PHY,"Illegal p %d UE specific pilots\n",p); - } - - return(0); -} - -/* -int lte_dl_cell_spec_rx(PHY_VARS_UE *phy_vars_ue, - uint8_t eNB_offset, - int *output, - unsigned char Ns, - unsigned char l, - unsigned char p) { - - - unsigned char mprime,mprime_dword,mprime_qpsk_symb,m; - unsigned short k=0; - unsigned int qpsk[4]; - short pamp; - - // Compute the correct pilot amplitude, sqrt_rho_b = Q3.13 - pamp = ONE_OVER_SQRT2_Q15; - - // This includes complex conjugate for channel estimation - - ((short *)&qpsk[0])[0] = pamp; - ((short *)&qpsk[0])[1] = -pamp; - ((short *)&qpsk[1])[0] = -pamp; - ((short *)&qpsk[1])[1] = -pamp; - ((short *)&qpsk[2])[0] = pamp; - ((short *)&qpsk[2])[1] = pamp; - ((short *)&qpsk[3])[0] = -pamp; - ((short *)&qpsk[3])[1] = pamp; - - mprime = 110 - phy_vars_ue->lte_frame_parms.N_RB_DL; - - for (m=0;mlte_frame_parms.N_RB_DL<<1;m++) { - - mprime_dword = mprime>>4; - mprime_qpsk_symb = mprime&0xf; - - // this is r_mprime from 3GPP 36-211 6.10.1.2 - output[k] = qpsk[(phy_vars_ue->lte_gold_table[eNB_offset][Ns][l][mprime_dword]>>(2*mprime_qpsk_symb))&3]; -#ifdef DEBUG_DL_CELL_SPEC - printf("Ns %d, l %d, m %d,mprime_dword %d, mprime_qpsk_symbol %d\n", - Ns,l,m,mprime_dword,mprime_qpsk_symb); - printf("index = %d (k %d)\n",(phy_vars_ue->lte_gold_table[eNB_offset][Ns][l][mprime_dword]>>(2*mprime_qpsk_symb))&3,k); -#endif - - mprime++; -#ifdef DEBUG_DL_CELL_SPEC - if (m<4) - printf("Ns %d l %d output[%d] = (%d,%d)\n",Ns,l,k,((short *)&output[k])[0],((short *)&output[k])[1]); -#endif - k++; - } - return(0); -} - -*/ - -#ifdef LTE_DL_CELL_SPEC_MAIN - - - -//extern int write_output(const char *,const char *,void *,int,int,char); -// flag change eren -extern int write_output(const char *,const char *,void *,int,int,char); -main() -{ - - unsigned short Nid_cell=0; - unsigned int Ncp = 0; - int output00[1024]; - int output01[1024]; - int output10[1024]; - int output11[1024]; - - memset(output00,0,1024*sizeof(int)); - memset(output01,0,1024*sizeof(int)); - memset(output10,0,1024*sizeof(int)); - memset(output11,0,1024*sizeof(int)); - - lte_gold(Nid_cell,Ncp); - - lte_dl_cell_spec(output00, - ONE_OVER_SQRT2_Q15, - 50, - Nid_cell, - Ncp, - 0, - 0, - 0, - 0); - - lte_dl_cell_spec(output10, - ONE_OVER_SQRT2_Q15, - 50, - Nid_cell, - Ncp, - 0, - 1, - 0, - 0); - - lte_dl_cell_spec(output01, - ONE_OVER_SQRT2_Q15, - 50, - Nid_cell, - Ncp, - 0, - 0, - 1, - 0); - - lte_dl_cell_spec(output11, - ONE_OVER_SQRT2_Q15, - 50, - Nid_cell, - Ncp, - 0, - 1, - 1, - 0); - - - write_output("dl_cell_spec00.m","dl_cs00",output00,1024,1,1); - write_output("dl_cell_spec01.m","dl_cs01",output01,1024,1,1); - write_output("dl_cell_spec10.m","dl_cs10",output10,1024,1,1); - write_output("dl_cell_spec11.m","dl_cs11",output11,1024,1,1); -} - - -#endif diff --git a/openair1/PHY/LTE_REFSIG/lte_gold.c b/openair1/PHY/LTE_REFSIG/lte_gold.c index 2463d73b79..456a2b17d1 100644 --- a/openair1/PHY/LTE_REFSIG/lte_gold.c +++ b/openair1/PHY/LTE_REFSIG/lte_gold.c @@ -142,6 +142,48 @@ void lte_gold_ue_spec(LTE_DL_FRAME_PARMS *frame_parms,uint32_t lte_gold_uespec_t } } +void lte_gold_ue_spec_port5(uint32_t lte_gold_uespec_port5_table[20][2][21],uint16_t Nid_cell, uint16_t n_rnti) +{ + + unsigned char ns,l; + unsigned int n,x1,x2; + + + for (ns=0; ns<20; ns++) { + + for (l=0; l<2; l++) { + + + x2 = ((((ns>>1)+1)*((Nid_cell<<1)+1))<<16) + n_rnti; + //x2 = frame_parms->Ncp + (Nid_cell<<1) + (1+(Nid_cell<<1))*(1 + (3*l) + (7*(1+ns))); //cinit + //n = 0 + // printf("cinit (ns %d, l %d) => %d\n",ns,l,x2); + x1 = 1+ (1<<31); + x2=x2 ^ ((x2 ^ (x2>>1) ^ (x2>>2) ^ (x2>>3))<<31); + + // skip first 50 double words (1600 bits) + //printf("n=0 : x1 %x, x2 %x\n",x1,x2); + for (n=1; n<50; n++) { + x1 = (x1>>1) ^ (x1>>4); + x1 = x1 ^ (x1<<31) ^ (x1<<28); + x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4); + x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28); + // printf("x1 : %x, x2 : %x\n",x1,x2); + } + + for (n=0; n<14; n++) { + x1 = (x1>>1) ^ (x1>>4); + x1 = x1 ^ (x1<<31) ^ (x1<<28); + x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4); + x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28); + lte_gold_uespec_port5_table[ns][l][n] = x1^x2; + // printf("n=%d : c %x\n",n,x1^x2); + } + + } + } +} + /*! \brief gold sequenquence generator \param x1 \param x2 this should be set to c_init if reset=1 diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index 5dd2f9b5f9..db95c2362c 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -259,6 +259,7 @@ int dlsch_encoding(unsigned char *a, unsigned char mod_order; unsigned int Kr=0,Kr_bytes,r,r_offset=0; unsigned short m=dlsch->harq_processes[harq_pid]->mcs; + uint8_t transmission_mode_7to9=0; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_IN); @@ -266,7 +267,13 @@ int dlsch_encoding(unsigned char *a, // printf("Encoder: A: %d\n",A); mod_order = get_Qm(dlsch->harq_processes[harq_pid]->mcs); - G = get_G(frame_parms,nb_rb,dlsch->harq_processes[harq_pid]->rb_alloc,mod_order,dlsch->harq_processes[harq_pid]->Nl,num_pdcch_symbols,frame,subframe); + if(dlsch->harq_processes[harq_pid]->mimo_mode == TM7) + transmission_mode_7to9 = 7; + else if(dlsch->harq_processes[harq_pid]->mimo_mode == TM8) + transmission_mode_7to9 = 8; + else if(dlsch->harq_processes[harq_pid]->mimo_mode == TM9_10) + transmission_mode_7to9 = 9; + G = get_G(frame_parms,nb_rb,dlsch->harq_processes[harq_pid]->rb_alloc,mod_order,dlsch->harq_processes[harq_pid]->Nl,num_pdcch_symbols,frame,subframe,transmission_mode_7to9); // if (dlsch->harq_processes[harq_pid]->Ndi == 1) { // this is a new packet diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index a1f1173ede..3aa3f72312 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -1,4 +1,4 @@ -/******************************************************************************* +/****************************************************************************** OpenAirInterface Copyright(c) 1999 - 2014 Eurecom @@ -74,7 +74,6 @@ unsigned char offset_mumimo_llr_drange[29][3]={{7, 8, 7},{6, 6, 7},{6, 6, 7},{6, */ unsigned char offset_mumimo_llr_drange[29][3]= {{0, 6, 5},{0, 4, 5},{0, 4, 5},{0, 5, 4},{0, 5, 6},{0, 5, 3},{0, 4, 4},{0, 4, 4},{0, 3, 3},{0, 1, 2},{1, 1, 0},{1, 3, 2},{3, 4, 1},{2, 0, 0},{2, 2, 2},{1, 1, 1},{2, 1, 0},{2, 1, 1},{1, 0, 1},{1, 0, 1},{0, 0, 0},{1, 0, 0},{0, 0, 0},{0, 1, 0},{1, 0, 0},{0, 0, 0},{0, 0, 0},{0, 0, 0},{0, 0, 0}}; - extern void print_shorts(char *s,__m128i *x); int rx_pdsch(PHY_VARS_UE *phy_vars_ue, @@ -99,6 +98,8 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, unsigned short nb_rb; int avgs, rb; LTE_DL_UE_HARQ_t *dlsch0_harq,*dlsch1_harq = 0; + + uint8_t beamforming_mode = phy_vars_ue->transmission_mode[eNB_id]<7?0:phy_vars_ue->transmission_mode[eNB_id]; switch (type) { case SI_PDSCH: @@ -162,7 +163,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, pilots=0; */ - if (frame_parms->nb_antennas_tx_eNB>1) { + if (frame_parms->nb_antennas_tx_eNB>1 && beamforming_mode==0) { #ifdef DEBUG_DLSCH_MOD LOG_I(PHY,"dlsch: using pmi %x (%p), rb_alloc %x\n",pmi2hex_2Ar1(dlsch0_harq->pmi_alloc),dlsch_ue[0],dlsch0_harq->rb_alloc[0]); #endif @@ -204,8 +205,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, phy_vars_ue->high_speed_flag, frame_parms); } - } // if n_tx>1 - else { + } else if (beamforming_mode==0) {// if n_tx>1 nb_rb = dlsch_extract_rbs_single(lte_ue_common_vars->rxdataF, lte_ue_common_vars->dl_ch_estimates[eNB_id], lte_ue_pdsch_vars[eNB_id]->rxdataF_ext, @@ -244,7 +244,21 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, phy_vars_ue->high_speed_flag, frame_parms); } - } //else n_tx>1 + } else if (beamforming_mode==7) { //else n_tx>1 + nb_rb = dlsch_extract_rbs_TM7(lte_ue_common_vars->rxdataF, + lte_ue_common_vars->dl_ch_estimates[eNB_id], + lte_ue_pdsch_vars[eNB_id]->rxdataF_ext, + lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext, + dlsch0_harq->rb_alloc, + symbol, + subframe, + phy_vars_ue->high_speed_flag, + frame_parms); + + + } else if(beamforming_mode>7) { + LOG_W(PHY,"dlsch_demodulation:beamforming mode not supported yet.\n"); + } // printf("nb_rb = %d, eNB_id %d\n",nb_rb,eNB_id); if (nb_rb==0) { @@ -418,7 +432,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, } } else if (dlsch0_harq->mimo_moden_connected_eNB)) { // TM5 two-user // Scale the channel estimates for interfering stream @@ -531,6 +545,21 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, lte_ue_pdsch_vars[eNB_id]->log2_maxh, 1); } + } else if (dlsch0_harq->mimo_mode==TM7) { //TM7 + + dlsch_channel_compensation(lte_ue_pdsch_vars[eNB_id]->rxdataF_ext, + lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext, + lte_ue_pdsch_vars[eNB_id]->dl_ch_mag0, + lte_ue_pdsch_vars[eNB_id]->dl_ch_magb0, + lte_ue_pdsch_vars[eNB_id]->rxdataF_comp0, + (aatx>1) ? lte_ue_pdsch_vars[eNB_id]->rho : NULL, + frame_parms, + symbol, + first_symbol_flag, + get_Qm(dlsch0_harq->mcs), + nb_rb, + lte_ue_pdsch_vars[eNB_id]->log2_maxh, + phy_measurements); // log2_maxh+I0_shift } // printf("MRC\n"); @@ -570,8 +599,8 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, // printf("Combining"); if ((dlsch0_harq->mimo_mode == SISO) || ((dlsch0_harq->mimo_mode >= UNIFORM_PRECODING11) && - (dlsch0_harq->mimo_mode <= PUSCH_PRECODING0))) { - + (dlsch0_harq->mimo_mode <= PUSCH_PRECODING0)) || + (dlsch0_harq->mimo_mode == TM7)) { /* dlsch_siso(frame_parms, lte_ue_pdsch_vars[eNB_id]->rxdataF_comp, @@ -608,7 +637,8 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, lte_ue_pdsch_vars[eNB_id]->llr[0], symbol,first_symbol_flag,nb_rb, adjust_G2(frame_parms,dlsch0_harq->rb_alloc,2,subframe,symbol), - lte_ue_pdsch_vars[eNB_id]->llr128); + lte_ue_pdsch_vars[eNB_id]->llr128, + beamforming_mode); else if (i_mod == 2) { dlsch_qpsk_qpsk_llr(frame_parms, lte_ue_pdsch_vars[eNB_id]->rxdataF_comp0, @@ -4178,8 +4208,745 @@ unsigned short dlsch_extract_rbs_dual(int **rxdataF, return(nb_rb/frame_parms->nb_antennas_rx); } -//============================================================================================== -// Auxiliary functions +unsigned short dlsch_extract_rbs_TM7(int **rxdataF, + int **dl_ch_estimates, + int **rxdataF_ext, + int **dl_ch_estimates_ext, + unsigned int *rb_alloc, + unsigned char symbol, + unsigned char subframe, + uint32_t high_speed_flag, + LTE_DL_FRAME_PARMS *frame_parms) +{ + + unsigned short rb,nb_rb=0; + unsigned char rb_alloc_ind; + unsigned char i,aarx,l,nsymb,skip_half=0,sss_symb,pss_symb=0; + int *dl_ch0,*dl_ch0_ext,*rxF,*rxF_ext,*rxF_uespec; + + unsigned char symbol_mod,pilots=0,uespec_pilots=0,j=0,k=0,poffset=0,uespec_poffset=0; + int8_t uespec_nushift = frame_parms->Nid_cell%3; + + symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol; + pilots = ((symbol_mod==0)||(symbol_mod==(4-frame_parms->Ncp))) ? 1 : 0; + l=symbol; + nsymb = (frame_parms->Ncp==NORMAL) ? 14:12; + + if (frame_parms->Ncp==0){ + if (symbol==3 || symbol==6 || symbol==9 || symbol==12) + uespec_pilots = 1; + } else{ + if (symbol==4 || symbol==7 || symbol==10) + uespec_pilots = 1; + } + + if (frame_parms->frame_type == TDD) { // TDD + sss_symb = nsymb-1; + pss_symb = 2; + } else { + sss_symb = (nsymb>>1)-2; + pss_symb = (nsymb>>1)-1; + } + + if (symbol_mod==(4-frame_parms->Ncp)) + poffset=3; + + if ((frame_parms->Ncp==0 && (symbol==6 ||symbol ==12)) || (frame_parms->Ncp==1 && symbol==7)) + uespec_poffset=2; + + for (aarx=0; aarxnb_antennas_rx; aarx++) { + + if (high_speed_flag == 1) + dl_ch0 = &dl_ch_estimates[aarx][5+(symbol*(frame_parms->ofdm_symbol_size))]; + else + dl_ch0 = &dl_ch_estimates[aarx][5]; + + dl_ch0_ext = &dl_ch_estimates_ext[aarx][symbol*(frame_parms->N_RB_DL*12)]; + + rxF_ext = &rxdataF_ext[aarx][symbol*(frame_parms->N_RB_DL*12)]; + rxF = &rxdataF[aarx][(frame_parms->first_carrier_offset + (symbol*(frame_parms->ofdm_symbol_size)))]; + printf("symbol:%d, (symbol-1)/3:%d\n",symbol,(symbol-1)/3); + //rxF_uespec = &rxdataF_uespec_pilots[aarx][(symbol-1)/3*frame_parms->N_RB_DL*(3+frame_parms->Ncp)]; + //printf("symbol, rxF_uespec offset:%d\n",symbol,(symbol-1)/3*frame_parms->N_RB_DL*(3+frame_parms->Ncp)); + + if ((frame_parms->N_RB_DL&1) == 0) // even number of RBs + for (rb=0; rbN_RB_DL; rb++) { + + if (rb < 32) + rb_alloc_ind = (rb_alloc[0]>>rb) & 1; + else if (rb < 64) + rb_alloc_ind = (rb_alloc[1]>>(rb-32)) & 1; + else if (rb < 96) + rb_alloc_ind = (rb_alloc[2]>>(rb-64)) & 1; + else if (rb < 100) + rb_alloc_ind = (rb_alloc[3]>>(rb-96)) & 1; + else + rb_alloc_ind = 0; + + // For second half of RBs skip DC carrier + if (rb==(frame_parms->N_RB_DL>>1)) { + rxF = &rxdataF[aarx][(1 + (symbol*(frame_parms->ofdm_symbol_size)))]; + //dl_ch0++; + } + + if (rb_alloc_ind==1) { + //*pmi_ext = (pmi>>((rb>>2)<<1))&3; + memcpy(dl_ch0_ext,dl_ch0,12*sizeof(int)); + + /* + printf("rb %d\n",rb); + for (i=0;i<12;i++) + printf("(%d %d)",((short *)dl_ch0)[i<<1],((short*)dl_ch0)[1+(i<<1)]); + printf("\n"); + */ + if (pilots==0 && uespec_pilots==0) { + for (i=0; i<12; i++) { + rxF_ext[i]=rxF[i]; + /* + printf("%d : (%d,%d)\n",(rxF+i-&rxdataF[aarx][( (symbol*(frame_parms->ofdm_symbol_size)))]), + ((short*)&rxF[i])[0],((short*)&rxF[i])[1]);*/ + } + + dl_ch0_ext+=12; + rxF_ext+=12; + } else if(pilots==1 && uespec_pilots==0) { + j=0; + + for (i=0; i<12; i++) { + if ((i!=(frame_parms->nushift+poffset)) && + (i!=((frame_parms->nushift+poffset+6)%12))) { + rxF_ext[j]=rxF[i]; + // printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); + dl_ch0_ext[j++]=dl_ch0[i]; + + } + } + + dl_ch0_ext+=10; + rxF_ext+=10; + + } else if (pilots==0 && uespec_pilots==1) { + j=0; + k=0; + + for (i=0; i<12; i++){ + if (frame_parms->Ncp==0){ + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ + rxF_ext[j] = rxF[i]; + dl_ch0_ext[j++]=dl_ch0[i]; + } + } else{ + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ + rxF_ext[j] = rxF[i]; + dl_ch0_ext[j++]=dl_ch0[i]; + } + } + + } + + dl_ch0_ext+=9-frame_parms->Ncp; + rxF_ext+=9-frame_parms->Ncp; + + } else { + msg("dlsch_extract_rbs_TM7(dl_demodulation.c):pilot or ue spec pilot detection error\n"); + exit(-1); + } + + nb_rb++; + } + + dl_ch0+=12; + rxF+=12; + + } + else { // Odd number of RBs + for (rb=0; rbN_RB_DL>>1; rb++) { + // printf("dlch_ext %d\n",dl_ch0_ext-&dl_ch_estimates_ext[aarx][0]); + skip_half=0; + + if (rb < 32) + rb_alloc_ind = (rb_alloc[0]>>rb) & 1; + else if (rb < 64) + rb_alloc_ind = (rb_alloc[1]>>(rb-32)) & 1; + else if (rb < 96) + rb_alloc_ind = (rb_alloc[2]>>(rb-64)) & 1; + else if (rb < 100) + rb_alloc_ind = (rb_alloc[3]>>(rb-96)) & 1; + else + rb_alloc_ind = 0; + + + // PBCH + if ((subframe==0) && (rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) { + rb_alloc_ind = 0; + } + + //PBCH subframe 0, symbols nsymb>>1 ... nsymb>>1 + 3 + if ((subframe==0) && (rb==((frame_parms->N_RB_DL>>1)-3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) + skip_half=1; + else if ((subframe==0) && (rb==((frame_parms->N_RB_DL>>1)+3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) + skip_half=2; + + //SSS + + if (((subframe==0)||(subframe==5)) && + (rb>((frame_parms->N_RB_DL>>1)-3)) && + (rb<((frame_parms->N_RB_DL>>1)+3)) && + (l==sss_symb) ) { + rb_alloc_ind = 0; + } + + //SSS + if (((subframe==0)||(subframe==5)) && + (rb==((frame_parms->N_RB_DL>>1)-3)) && + (l==sss_symb)) + skip_half=1; + else if (((subframe==0)||(subframe==5)) && + (rb==((frame_parms->N_RB_DL>>1)+3)) && + (l==sss_symb)) + skip_half=2; + + //PSS in subframe 0/5 if FDD + if (frame_parms->frame_type == FDD) { //FDD + if (((subframe==0)||(subframe==5)) && (rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + + if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)-3)) && (l==pss_symb)) + skip_half=1; + else if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb)) + skip_half=2; + } + + if ((frame_parms->frame_type == TDD) && + (subframe==6)) { //TDD Subframe 6 + if ((rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + + if ((rb==((frame_parms->N_RB_DL>>1)-3)) && (l==pss_symb)) + skip_half=1; + else if ((rb==((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb)) + skip_half=2; + } + + + if (rb_alloc_ind==1) { + // printf("rb %d/symbol %d (skip_half %d)\n",rb,l,skip_half); + + if (pilots==0 && uespec_pilots==0) { + // printf("Extracting w/o pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half); + + if (skip_half==1) { + memcpy(dl_ch0_ext,dl_ch0,6*sizeof(int)); + + for (i=0; i<6; i++) + rxF_ext[i]=rxF[i]; + + dl_ch0_ext+=6; + rxF_ext+=6; + } else if (skip_half==2) { + memcpy(dl_ch0_ext,dl_ch0+6,6*sizeof(int)); + + for (i=0; i<6; i++) + rxF_ext[i]=rxF[(i+6)]; + + dl_ch0_ext+=6; + rxF_ext+=6; + } else { + memcpy(dl_ch0_ext,dl_ch0,12*sizeof(int)); + + for (i=0; i<12; i++) + rxF_ext[i]=rxF[i]; + + dl_ch0_ext+=12; + rxF_ext+=12; + } + } else if (pilots==1 && uespec_pilots==0){ + // printf("Extracting with pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half); + j=0; + + if (skip_half==1) { + for (i=0; i<6; i++) { + if (i!=((frame_parms->nushift+poffset)%6)) { + rxF_ext[j]=rxF[i]; + // printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); + dl_ch0_ext[j++]=dl_ch0[i]; + } + } + + dl_ch0_ext+=5; + rxF_ext+=5; + } else if (skip_half==2) { + for (i=0; i<6; i++) { + if (i!=((frame_parms->nushift+poffset)%6)) { + rxF_ext[j]=rxF[(i+6)]; + // printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); + dl_ch0_ext[j++]=dl_ch0[i+6]; + } + } + + dl_ch0_ext+=5; + rxF_ext+=5; + } else { + for (i=0; i<12; i++) { + if ((i!=(frame_parms->nushift+poffset)) && + (i!=((frame_parms->nushift+poffset+6)%12))) { + rxF_ext[j]=rxF[i]; + // printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); + dl_ch0_ext[j++]=dl_ch0[i]; + + } + } + + dl_ch0_ext+=10; + rxF_ext+=10; + } + } else if(pilots==0 && uespec_pilots==1){ + //printf("Extracting with uespec pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half); + j=0; + k=0; + + if (skip_half==1) { + if (frame_parms->Ncp==0){ + for (i=0; i<6; i++) { + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ + rxF_ext[j]=rxF[i]; + dl_ch0_ext[j++]=dl_ch0[i]; + } + } + dl_ch0_ext+=6-(uespec_nushift+uespec_poffset<6)-(uespec_nushift+uespec_poffset+4<6)-((uespec_nushift+uespec_poffset+8)%12<6); + rxF_ext+=6-(uespec_nushift+uespec_poffset<6)-(uespec_nushift+uespec_poffset+4<6)-((uespec_nushift+uespec_poffset+8)%12<6); + + } else{ + for (i=0; i<6; i++) { + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ + rxF_ext[j]=rxF[i]; + dl_ch0_ext[j++]=dl_ch0[i]; + } + } + dl_ch0_ext+=4; + rxF_ext+=4; + } + + } else if (skip_half==2) { + if(frame_parms->Ncp==0){ + for (i=0; i<6; i++) { + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ + rxF_ext[j]=rxF[(i+6)]; + dl_ch0_ext[j++]=dl_ch0[i+6]; + } + } + dl_ch0_ext+=6-(uespec_nushift+uespec_poffset>6)-(uespec_nushift+uespec_poffset+4>6)-((uespec_nushift+uespec_poffset+8)%12>6); + rxF_ext+=6-(uespec_nushift+uespec_poffset>6)-(uespec_nushift+uespec_poffset+4>6)-((uespec_nushift+uespec_poffset+8)%12>6); + + } else { + for (i=0; i<6; i++) { + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ + rxF_ext[j]=rxF[(i+6)]; + dl_ch0_ext[j++]=dl_ch0[i+6]; + } + } + dl_ch0_ext+=4; + rxF_ext+=4; + } + + } else { + + for (i=0; i<12; i++){ + if (frame_parms->Ncp==0){ + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ + rxF_ext[j] = rxF[i]; + dl_ch0_ext[j++] = dl_ch0[i]; + } + } else{ + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ + rxF_ext[j] = rxF[i]; + dl_ch0_ext[j++]=dl_ch0[i]; + } + } + + } + + dl_ch0_ext+=9-frame_parms->Ncp; + rxF_ext+=9-frame_parms->Ncp; + } + + } else { + msg("dlsch_extract_rbs_TM7(dl_demodulation.c):pilot or ue spec pilot detection error\n"); + exit(-1); + + } + + nb_rb++; + } + + dl_ch0+=12; + rxF+=12; + } // first half loop + + + // Do middle RB (around DC) + if (rb < 32) + rb_alloc_ind = (rb_alloc[0]>>rb) & 1; + else if (rb < 64) + rb_alloc_ind = (rb_alloc[1]>>(rb-32)) & 1; + else if (rb < 96) + rb_alloc_ind = (rb_alloc[2]>>(rb-64)) & 1; + else if (rb < 100) + rb_alloc_ind = (rb_alloc[3]>>(rb-96)) & 1; + else + rb_alloc_ind = 0; + + + + // PBCH + if ((subframe==0) && (rb>=((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) { + rb_alloc_ind = 0; + } + + //SSS + if (((subframe==0)||(subframe==5)) && (rb>=((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==sss_symb) ) { + rb_alloc_ind = 0; + } + + if (frame_parms->frame_type == FDD) { + //PSS + if (((subframe==0)||(subframe==5)) && (rb>=((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + } + + if ((frame_parms->frame_type == TDD) && + (subframe==6)) { + //PSS + if ((rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + } + + //printf("dlch_ext %d\n",dl_ch0_ext-&dl_ch_estimates_ext[aarx][0]); + //printf("DC rb %d (%p)\n",rb,rxF); + if (rb_alloc_ind==1) { + //printf("rb %d/symbol %d (skip_half %d)\n",rb,l,skip_half); + if (pilots==0 && uespec_pilots==0) { + for (i=0; i<6; i++) { + dl_ch0_ext[i]=dl_ch0[i]; + rxF_ext[i]=rxF[i]; + } + + rxF = &rxdataF[aarx][((symbol*(frame_parms->ofdm_symbol_size)))]; + + for (; i<12; i++) { + dl_ch0_ext[i]=dl_ch0[i]; + rxF_ext[i]=rxF[(1+i-6)]; + } + + dl_ch0_ext+=12; + rxF_ext+=12; + } else if(pilots==1 && uespec_pilots==0){ // pilots==1 + j=0; + + for (i=0; i<6; i++) { + if (i!=((frame_parms->nushift+poffset)%6)) { + dl_ch0_ext[j]=dl_ch0[i]; + rxF_ext[j++]=rxF[i]; + // printf("**extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); + } + } + + rxF = &rxdataF[aarx][((symbol*(frame_parms->ofdm_symbol_size)))]; + + for (; i<12; i++) { + if (i!=((frame_parms->nushift+6+poffset)%12)) { + dl_ch0_ext[j]=dl_ch0[i]; + rxF_ext[j++]=rxF[(1+i-6)]; + //printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); + } + } + + dl_ch0_ext+=10; + rxF_ext+=10; + } else if(pilots==0 && uespec_pilots==1) { + j=0; + k=0; + + for (i=0; i<6; i++) { + if (frame_parms->Ncp==0){ + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ + dl_ch0_ext[j]=dl_ch0[i]; + rxF_ext[j++] = rxF[i]; + //printf("**extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); + } + } else { + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ + dl_ch0_ext[j]=dl_ch0[i]; + rxF_ext[j++] = rxF[i]; + // printf("**extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); + } + } + } + + rxF = &rxdataF[aarx][((symbol*(frame_parms->ofdm_symbol_size)))]; + + for (; i<12; i++) { + if (frame_parms->Ncp==0){ + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ + dl_ch0_ext[j]=dl_ch0[i]; + rxF_ext[j++]=rxF[(1+i-6)]; + // printf("**extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); + } + } else { + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ + dl_ch0_ext[j]=dl_ch0[i]; + rxF_ext[j++] = rxF[(1+i-6)]; + } + } + } + + dl_ch0_ext+=9-frame_parms->Ncp; + rxF_ext+=9-frame_parms->Ncp; + + }// symbol_mod==0 + + nb_rb++; + } // rballoc==1 + else { + rxF = &rxdataF[aarx][((symbol*(frame_parms->ofdm_symbol_size)))]; + } + + dl_ch0+=12; + rxF+=7; + rb++; + + for (; rbN_RB_DL; rb++) { + // printf("dlch_ext %d\n",dl_ch0_ext-&dl_ch_estimates_ext[aarx][0]); + // printf("rb %d (%p)\n",rb,rxF); + skip_half=0; + + if (rb < 32) + rb_alloc_ind = (rb_alloc[0]>>rb) & 1; + else if (rb < 64) + rb_alloc_ind = (rb_alloc[1]>>(rb-32)) & 1; + else if (rb < 96) + rb_alloc_ind = (rb_alloc[2]>>(rb-64)) & 1; + else if (rb < 100) + rb_alloc_ind = (rb_alloc[3]>>(rb-96)) & 1; + else + rb_alloc_ind = 0; + + + + // PBCH + if ((subframe==0) && (rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l>=nsymb>>1) && (l<((nsymb>>1) + 4))) { + rb_alloc_ind = 0; + } + + //PBCH subframe 0, symbols nsymb>>1 ... nsymb>>1 + 3 + if ((subframe==0) && (rb==((frame_parms->N_RB_DL>>1)-3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) + skip_half=1; + else if ((subframe==0) && (rb==((frame_parms->N_RB_DL>>1)+3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) + skip_half=2; + + //SSS + if (((subframe==0)||(subframe==5)) && (rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==sss_symb) ) { + rb_alloc_ind = 0; + } + + //SSS + if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)-3)) && (l==sss_symb)) + skip_half=1; + else if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)+3)) && (l==sss_symb)) + skip_half=2; + + if (frame_parms->frame_type == FDD) { + //PSS + if (((subframe==0)||(subframe==5)) && (rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + + //PSS + if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)-3)) && (l==pss_symb)) + skip_half=1; + else if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb)) + skip_half=2; + } + + if ((frame_parms->frame_type == TDD) && + (subframe==6)) { //TDD Subframe 6 + if ((rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + + if ((rb==((frame_parms->N_RB_DL>>1)-3)) && (l==pss_symb)) + skip_half=1; + else if ((rb==((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb)) + skip_half=2; + } + + if (rb_alloc_ind==1) { + // printf("rb %d/symbol %d (skip_half %d)\n",rb,l,skip_half); + /* + printf("rb %d\n",rb); + for (i=0;i<12;i++) + printf("(%d %d)",((short *)dl_ch0)[i<<1],((short*)dl_ch0)[1+(i<<1)]); + printf("\n"); + */ + if (pilots==0 && uespec_pilots==0) { + //printf("Extracting w/o pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half); + if (skip_half==1) { + memcpy(dl_ch0_ext,dl_ch0,6*sizeof(int)); + + for (i=0; i<6; i++) + rxF_ext[i]=rxF[i]; + + dl_ch0_ext+=6; + rxF_ext+=6; + + } else if (skip_half==2) { + memcpy(dl_ch0_ext,dl_ch0+6,6*sizeof(int)); + + for (i=0; i<6; i++) + rxF_ext[i]=rxF[(i+6)]; + + dl_ch0_ext+=6; + rxF_ext+=6; + + } else { + memcpy(dl_ch0_ext,dl_ch0,12*sizeof(int)); + + for (i=0; i<12; i++) + rxF_ext[i]=rxF[i]; + + dl_ch0_ext+=12; + rxF_ext+=12; + } + } else if (pilots==1 && uespec_pilots==0){ + //printf("Extracting with pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half); + j=0; + + if (skip_half==1) { + for (i=0; i<6; i++) { + if (i!=((frame_parms->nushift+poffset)%6)) { + rxF_ext[j]=rxF[i]; + //printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); + dl_ch0_ext[j++]=dl_ch0[i]; + } + } + + dl_ch0_ext+=5; + rxF_ext+=5; + } else if (skip_half==2) { + for (i=0; i<6; i++) { + if (i!=((frame_parms->nushift+poffset)%6)) { + rxF_ext[j]=rxF[(i+6)]; + //printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); + dl_ch0_ext[j++]=dl_ch0[i+6]; + } + } + + dl_ch0_ext+=5; + rxF_ext+=5; + } else { + for (i=0; i<12; i++) { + if ((i!=(frame_parms->nushift+poffset)) && + (i!=((frame_parms->nushift+poffset+6)%12))) { + rxF_ext[j]=rxF[i]; + //printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); + dl_ch0_ext[j++]=dl_ch0[i]; + } + } + + dl_ch0_ext+=10; + rxF_ext+=10; + } + } else if(pilots==0 && uespec_pilots==1) { + j=0; + k=0; + + if (skip_half==1) { + if (frame_parms->Ncp==0){ + for (i=0; i<6; i++) { + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ + rxF_ext[j]=rxF[i]; + dl_ch0_ext[j++]=dl_ch0[i]; + } + } + dl_ch0_ext+=6-(uespec_nushift+uespec_poffset<6)-(uespec_nushift+uespec_poffset+4<6)-((uespec_nushift+uespec_poffset+8)%12<6); + rxF_ext+=6-(uespec_nushift+uespec_poffset<6)-(uespec_nushift+uespec_poffset+4<6)-((uespec_nushift+uespec_poffset+8)%12<6); + + } else{ + for (i=0; i<6; i++) { + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ + rxF_ext[j]=rxF[i]; + dl_ch0_ext[j++]=dl_ch0[i]; + } + } + dl_ch0_ext+=4; + rxF_ext+=4; + } + + } else if (skip_half==2) { + if(frame_parms->Ncp==0){ + for (i=0; i<6; i++) { + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ + rxF_ext[j]=rxF[(i+6)]; + dl_ch0_ext[j++]=dl_ch0[i+6]; + } + } + dl_ch0_ext+=6-(uespec_nushift+uespec_poffset>6)-(uespec_nushift+uespec_poffset+4>6)-((uespec_nushift+uespec_poffset+8)%12>6); + rxF_ext+=6-(uespec_nushift+uespec_poffset>6)-(uespec_nushift+uespec_poffset+4>6)-((uespec_nushift+uespec_poffset+8)%12>6); + + } else { + for (i=0; i<6; i++) { + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ + rxF_ext[j]=rxF[(i+6)]; + dl_ch0_ext[j++]=dl_ch0[i+6]; + } + } + dl_ch0_ext+=4; + rxF_ext+=4; + } + + } else { + for (i=0; i<12; i++){ + if (frame_parms->Ncp==0){ + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ + rxF_ext[j] = rxF[i]; + dl_ch0_ext[j++]=dl_ch0[i]; + } + } else{ + if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ + rxF_ext[j] = rxF[i]; + dl_ch0_ext[j++]=dl_ch0[i]; + } + } + } + + dl_ch0_ext+=9-frame_parms->Ncp; + rxF_ext+=9-frame_parms->Ncp; + + } + + }// pilots=0 + + nb_rb++; + } + + dl_ch0+=12; + rxF+=12; + } + } + } + + _mm_empty(); + _m_empty(); + + return(nb_rb/frame_parms->nb_antennas_rx); +} + + + //============================================================================================== #ifdef USER_MODE @@ -4223,6 +4990,10 @@ void dump_dlsch2(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint16_t coded_bits_per } } + sprintf(fname,"dlsch%d_rxF_r%d_uespec0.m",eNB_id,round); + sprintf(vname,"dl%d_rxF_r%d_uespec0",eNB_id,round); + write_output(fname,vname,phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->rxdataF_uespec_pilots[0],12*N_RB_DL,1,1); + /* write_output("dlsch%d_ch_ext01.m","dl01_ch0_ext",lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext[1],12*N_RB_DL*nsymb,1,1); write_output("dlsch%d_ch_ext10.m","dl10_ch0_ext",lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext[2],12*N_RB_DL*nsymb,1,1); diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c index 4990e94cf5..951e4afcd0 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c @@ -640,7 +640,8 @@ int dlsch_qpsk_llr(LTE_DL_FRAME_PARMS *frame_parms, uint8_t first_symbol_flag, uint16_t nb_rb, uint16_t pbch_pss_sss_adjust, - short **llr32p) + short **llr32p, + uint8_t beamforming_mode) { uint32_t *rxF = (uint32_t*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)]; @@ -661,11 +662,16 @@ int dlsch_qpsk_llr(LTE_DL_FRAME_PARMS *frame_parms, if ((symbol_mod==0) || (symbol_mod==(4-frame_parms->Ncp))) { - if (frame_parms->mode1_flag==0) + if (frame_parms->mode1_flag==0 && beamforming_mode!=7) len = (nb_rb*8);// - (2*pbch_pss_sss_adjust/3); else len = (nb_rb*10);// - (5*pbch_pss_sss_adjust/6); - } else { + } else if((beamforming_mode==7) && (frame_parms->Ncp==0) && (symbol==3 || symbol==6 || symbol==9 || symbol==12)){ + len = (nb_rb*9); + } else if((beamforming_mode==7) && (frame_parms->Ncp==1) && (symbol==4 || symbol==7 || symbol==10)){ + len = (nb_rb*8); + } + else { len = (nb_rb*12);// - pbch_pss_sss_adjust; } diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index c4b0247d75..d14c26c13d 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -1,42 +1,42 @@ /******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2014 Eurecom + 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 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. + 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 . + 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@eurecom.fr - Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE +Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE *******************************************************************************/ /*! \file PHY/LTE_TRANSPORT/dlsch_modulation.c -* \brief Top-level routines for generating the PDSCH physical channel from 36-211, V8.6 2009-03 -* \author R. Knopp, F. Kaltenberger -* \date 2011 -* \version 0.1 -* \company Eurecom -* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr -* \note -* \warning -*/ + * \brief Top-level routines for generating the PDSCH physical channel from 36-211, V8.6 2009-03 + * \author R. Knopp, F. Kaltenberger + * \date 2011 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr + * \note + * \warning + */ #include "PHY/defs.h" #include "PHY/extern.h" #include "PHY/CODING/defs.h" @@ -70,10 +70,33 @@ uint8_t is_not_pilot(uint8_t pilots, uint8_t re, uint8_t nushift, uint8_t use2nd return(0); } -uint8_t is_not_UEspecRS(int first_layer,int re) +//uint8_t is_not_UEspecRS(int first_layer,int re) +uint8_t is_not_UEspecRS(uint8_t lprime, uint8_t re, uint8_t nushift, uint8_t Ncp, uint8_t beamforming_mode) { + uint8_t offset = (lprime==2)?2:0; + if(lprime==0) + return(1); - return(1); + switch(beamforming_mode){ + case 7: + if (Ncp == NORMAL){ + if ((re!=nushift+offset) && (re!=((nushift+4+offset)%12)) && (re!=((nushift+8+offset)%12))) + return(1); + /*else{ + printf("(is_no_UEspec_RS):lprime=%d, re=%d, nushift=%d, offset=%d\n",lprime, re,nushift,offset); + }*/ + } else { + if ((re!=nushift+offset) && (re!=((nushift+3+offset)%12)) && (re!=((nushift+6+offset)%12)) && (re!=((nushift+9+offset)%12))) + return(1); + } + break; + + default: + msg("is_not_UEspecRS() [dlsch_modulation.c] : ERROR, unknown beamforming_mode %d\n",beamforming_mode); + return(-1); + } + + return(0); } void generate_64qam_table(void) @@ -110,33 +133,33 @@ void layer1prec2A(int32_t *antenna0_sample, int32_t *antenna1_sample, uint8_t pr switch (precoding_index) { - case 0: // 1 1 - *antenna1_sample=*antenna0_sample; - break; + case 0: // 1 1 + *antenna1_sample=*antenna0_sample; + break; - case 1: // 1 -1 - ((int16_t *)antenna1_sample)[0] = -((int16_t *)antenna0_sample)[0]; - ((int16_t *)antenna1_sample)[1] = -((int16_t *)antenna0_sample)[1]; - break; + case 1: // 1 -1 + ((int16_t *)antenna1_sample)[0] = -((int16_t *)antenna0_sample)[0]; + ((int16_t *)antenna1_sample)[1] = -((int16_t *)antenna0_sample)[1]; + break; - case 2: // 1 j - ((int16_t *)antenna1_sample)[0] = -((int16_t *)antenna0_sample)[1]; - ((int16_t *)antenna1_sample)[1] = ((int16_t *)antenna0_sample)[0]; - break; + case 2: // 1 j + ((int16_t *)antenna1_sample)[0] = -((int16_t *)antenna0_sample)[1]; + ((int16_t *)antenna1_sample)[1] = ((int16_t *)antenna0_sample)[0]; + break; - case 3: // 1 -j - ((int16_t *)antenna1_sample)[0] = ((int16_t *)antenna0_sample)[1]; - ((int16_t *)antenna1_sample)[1] = -((int16_t *)antenna0_sample)[0]; - break; + case 3: // 1 -j + ((int16_t *)antenna1_sample)[0] = ((int16_t *)antenna0_sample)[1]; + ((int16_t *)antenna1_sample)[1] = -((int16_t *)antenna0_sample)[0]; + break; } // normalize /* ((int16_t *)antenna0_sample)[0] = (int16_t)((((int16_t *)antenna0_sample)[0]*ONE_OVER_SQRT2_Q15)>>15); - ((int16_t *)antenna0_sample)[1] = (int16_t)((((int16_t *)antenna0_sample)[1]*ONE_OVER_SQRT2_Q15)>>15); ((int16_t *)antenna1_sample)[0] = (int16_t)((((int16_t *)antenna1_sample)[0]*ONE_OVER_SQRT2_Q15)>>15); - ((int16_t *)antenna1_sample)[1] = (int16_t)((((int16_t *)antenna1_sample)[1]*ONE_OVER_SQRT2_Q15)>>15); */ + ((int16_t *)antenna0_sample)[1] = (int16_t)((((int16_t *)antenna0_sample)[1]*ONE_OVER_SQRT2_Q15)>>15); ((int16_t *)antenna1_sample)[0] = (int16_t)((((int16_t *)antenna1_sample)[0]*ONE_OVER_SQRT2_Q15)>>15); + ((int16_t *)antenna1_sample)[1] = (int16_t)((((int16_t *)antenna1_sample)[1]*ONE_OVER_SQRT2_Q15)>>15); */ } -int allocate_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, +int allocate_REs_in_RB(PHY_VARS_eNB *phy_vars_eNB, mod_sym_t **txdataF, uint32_t *jj, uint32_t *jj2, @@ -151,10 +174,14 @@ int allocate_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, int16_t *qam_table_s1, uint32_t *re_allocated, uint8_t skip_dc, - uint8_t skip_half) + uint8_t skip_half, + uint8_t lprime, + uint8_t mprime, + uint8_t Ns, + int32_t **beamforming_weights) { - + LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_eNB->lte_frame_parms; uint8_t *x0 = dlsch0_harq->e; MIMO_mode_t mimo_mode = dlsch0_harq->mimo_mode; @@ -165,11 +192,11 @@ int allocate_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, uint8_t *x1=NULL; uint8_t mod_order1=2; + uint8_t nb_antennas_tx_phy = phy_vars_eNB->nb_antennas_tx_phy; + // Fill these in later for TM8-10 // int Nlayers1; // int first_layer1; - - int use2ndpilots = (frame_parms->mode1_flag==1)?1:0; uint32_t tti_offset,aa; @@ -195,10 +222,23 @@ int allocate_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, uint8_t first_re,last_re; int32_t tmp_sample1,tmp_sample2; int16_t tmp_amp=amp; + uint8_t layer; int s=1; + + uint8_t mprime2 = mprime,mprime_dword,mprime_qpsk_symb; + mod_sym_t qpsk[4]; gain_lin_QPSK = (int16_t)((amp*ONE_OVER_SQRT2_Q15)>>15); // if (mimo_mode == LARGE_CDD) gain_lin_QPSK>>=1; + ((int16_t *)&qpsk[0])[0] = gain_lin_QPSK; + ((int16_t *)&qpsk[0])[1] = gain_lin_QPSK; + ((int16_t *)&qpsk[1])[0] = -gain_lin_QPSK; + ((int16_t *)&qpsk[1])[1] = gain_lin_QPSK;; + ((int16_t *)&qpsk[2])[0] = gain_lin_QPSK;; + ((int16_t *)&qpsk[2])[1] = -gain_lin_QPSK;; + ((int16_t *)&qpsk[3])[0] = -gain_lin_QPSK;; + ((int16_t *)&qpsk[3])[1] = -gain_lin_QPSK; + if (dlsch1_harq) { x1 = dlsch1_harq->e; @@ -210,151 +250,151 @@ int allocate_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, } /* - switch (mod_order) { - case 2: - // QPSK single stream + switch (mod_order) { + case 2: +// QPSK single stream - break; - case 4: - //16QAM Single stream - gain_lin_16QAM1 = (int16_t)(((int32_t)amp*QAM16_n1)>>15); - gain_lin_16QAM2 = (int16_t)(((int32_t)amp*QAM16_n2)>>15); +break; +case 4: +//16QAM Single stream +gain_lin_16QAM1 = (int16_t)(((int32_t)amp*QAM16_n1)>>15); +gain_lin_16QAM2 = (int16_t)(((int32_t)amp*QAM16_n2)>>15); - break; +break; - case 6: - //64QAM Single stream - break; - default: - break; - } - */ +case 6: +//64QAM Single stream +break; +default: +break; +} + */ -#ifdef DEBUG_DLSCH_MODULATION - printf("allocate_re (mod %d): symbol_offset %d re_offset %d (%d,%d), jj %d -> %d,%d\n",mod_order0,symbol_offset,re_offset,skip_dc,skip_half,*jj, x0[*jj], x0[1+*jj]); -#endif +//#ifdef DEBUG_DLSCH_MODULATION +// printf("allocate_re (mod %d): symbol_offset %d re_offset %d (%d,%d), jj %d -> %d,%d\n",mod_order0,symbol_offset,re_offset,skip_dc,skip_half,*jj, x0[*jj], x0[1+*jj]); +//#endif first_re=0; last_re=12; - + if (skip_half==1) last_re=6; else if (skip_half==2) first_re=6; - - for (re=first_re; reofdm_symbol_size+1; - tti_offset = symbol_offset + re_off + re; + tti_offset = symbol_offset + re_off + re; + // printf("tti_offset = %d\n", tti_offset); // check that RE is not from Cell-specific RS if (is_not_pilot(pilots,re,frame_parms->nushift,use2ndpilots)==1) { - // printf("re %d (jj %d)\n",re,*jj); + // printf("re %d (jj %d)\n",re,*jj); if (mimo_mode == SISO) { //SISO mapping *re_allocated = *re_allocated + 1; switch (mod_order0) { - case 2: //QPSK + case 2: //QPSK - //printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t*)&txdataF[aa][tti_offset])[0] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i - } + //printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + for (aa=0; aanb_antennas_tx; aa++) { + ((int16_t*)&txdataF[aa][tti_offset])[0] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i + } - *jj = *jj + 1; + *jj = *jj + 1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t*)&txdataF[aa][tti_offset])[1] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} - } + for (aa=0; aanb_antennas_tx; aa++) { + ((int16_t*)&txdataF[aa][tti_offset])[1] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} + } - *jj = *jj + 1; + *jj = *jj + 1; - // printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - break; + //printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + break; - case 4: //16QAM + case 4: //16QAM - qam16_table_offset_re = 0; - qam16_table_offset_im = 0; + qam16_table_offset_re = 0; + qam16_table_offset_im = 0; - if (x0[*jj] == 1) - qam16_table_offset_re+=2; + if (x0[*jj] == 1) + qam16_table_offset_re+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_im+=2; + if (x0[*jj] == 1) + qam16_table_offset_im+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_re+=1; + if (x0[*jj] == 1) + qam16_table_offset_re+=1; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_im+=1; + if (x0[*jj] == 1) + qam16_table_offset_im+=1; - *jj=*jj+1; + *jj=*jj+1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s0[qam16_table_offset_re]; - ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s0[qam16_table_offset_im]; - // ((int16_t *)&txdataF[aa][tti_offset])[0]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); - // ((int16_t *)&txdataF[aa][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); - } + for (aa=0; aanb_antennas_tx; aa++) { + ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s0[qam16_table_offset_re]; + ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s0[qam16_table_offset_im]; + // ((int16_t *)&txdataF[aa][tti_offset])[0]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); + // ((int16_t *)&txdataF[aa][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); + } - break; + break; - case 6: //64QAM + case 6: //64QAM - qam64_table_offset_re = 0; - qam64_table_offset_im = 0; + qam64_table_offset_re = 0; + qam64_table_offset_im = 0; - if (x0[*jj] == 1) - qam64_table_offset_re+=4; + if (x0[*jj] == 1) + qam64_table_offset_re+=4; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im+=4; + if (x0[*jj] == 1) + qam64_table_offset_im+=4; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_re+=2; + if (x0[*jj] == 1) + qam64_table_offset_re+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im+=2; + if (x0[*jj] == 1) + qam64_table_offset_im+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_re+=1; + if (x0[*jj] == 1) + qam64_table_offset_re+=1; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im+=1; + if (x0[*jj] == 1) + qam64_table_offset_im+=1; - *jj=*jj+1; + *jj=*jj+1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s0[qam64_table_offset_re];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); - ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s0[qam64_table_offset_im];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); - } + for (aa=0; aanb_antennas_tx; aa++) { + ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s0[qam64_table_offset_re];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); + ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s0[qam64_table_offset_im];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); + } - break; + break; } } @@ -365,171 +405,171 @@ int allocate_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, amp = (int16_t)(((int32_t)tmp_amp*ONE_OVER_SQRT2_Q15)>>15); switch (mod_order0) { - case 2: //QPSK + case 2: //QPSK - // first antenna position n -> x0 + // first antenna position n -> x0 - ((int16_t*)&tmp_sample1)[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; - *jj=*jj+1; - ((int16_t*)&tmp_sample1)[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; - *jj=*jj+1; + ((int16_t*)&tmp_sample1)[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + *jj=*jj+1; + ((int16_t*)&tmp_sample1)[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + *jj=*jj+1; - // second antenna position n -> -x1* + // second antenna position n -> -x1* - ((int16_t*)&tmp_sample2)[0] = (x0[*jj]==1) ? (gain_lin_QPSK) : -gain_lin_QPSK; - *jj=*jj+1; - ((int16_t*)&tmp_sample2)[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; - *jj=*jj+1; + ((int16_t*)&tmp_sample2)[0] = (x0[*jj]==1) ? (gain_lin_QPSK) : -gain_lin_QPSK; + *jj=*jj+1; + ((int16_t*)&tmp_sample2)[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + *jj=*jj+1; - // normalization for 2 tx antennas - ((int16_t*)&txdataF[0][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*ONE_OVER_SQRT2_Q15)>>15); - ((int16_t*)&txdataF[0][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*ONE_OVER_SQRT2_Q15)>>15); - ((int16_t*)&txdataF[1][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample2)[0]*ONE_OVER_SQRT2_Q15)>>15); - ((int16_t*)&txdataF[1][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample2)[1]*ONE_OVER_SQRT2_Q15)>>15); + // normalization for 2 tx antennas + ((int16_t*)&txdataF[0][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*ONE_OVER_SQRT2_Q15)>>15); + ((int16_t*)&txdataF[0][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*ONE_OVER_SQRT2_Q15)>>15); + ((int16_t*)&txdataF[1][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample2)[0]*ONE_OVER_SQRT2_Q15)>>15); + ((int16_t*)&txdataF[1][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample2)[1]*ONE_OVER_SQRT2_Q15)>>15); - break; + break; - case 4: //16QAM + case 4: //16QAM - // Antenna 0 position n + // Antenna 0 position n - qam16_table_offset_re = 0; - qam16_table_offset_im = 0; + qam16_table_offset_re = 0; + qam16_table_offset_im = 0; - if (x0[*jj] == 1) - qam16_table_offset_re+=2; + if (x0[*jj] == 1) + qam16_table_offset_re+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_im+=2; + if (x0[*jj] == 1) + qam16_table_offset_im+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_re+=1; + if (x0[*jj] == 1) + qam16_table_offset_re+=1; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_im+=1; + if (x0[*jj] == 1) + qam16_table_offset_im+=1; - *jj=*jj+1; + *jj=*jj+1; - ((int16_t *)&txdataF[0][tti_offset])[0]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); - ((int16_t *)&txdataF[0][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); + ((int16_t *)&txdataF[0][tti_offset])[0]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); + ((int16_t *)&txdataF[0][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); - // Antenna 1 position n Real part -> -x1* + // Antenna 1 position n Real part -> -x1* - qam16_table_offset_re = 0; - qam16_table_offset_im = 0; + qam16_table_offset_re = 0; + qam16_table_offset_im = 0; - if (x0[*jj] == 1) - qam16_table_offset_re+=2; + if (x0[*jj] == 1) + qam16_table_offset_re+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_im+=2; + if (x0[*jj] == 1) + qam16_table_offset_im+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_re+=1; + if (x0[*jj] == 1) + qam16_table_offset_re+=1; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_im+=1; + if (x0[*jj] == 1) + qam16_table_offset_im+=1; - *jj=*jj+1; + *jj=*jj+1; - ((int16_t *)&txdataF[1][tti_offset])[0]+=-(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); - ((int16_t *)&txdataF[1][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); + ((int16_t *)&txdataF[1][tti_offset])[0]+=-(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); + ((int16_t *)&txdataF[1][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); - break; + break; - case 6: // 64-QAM + case 6: // 64-QAM - // Antenna 0 - qam64_table_offset_re = 0; - qam64_table_offset_im = 0; + // Antenna 0 + qam64_table_offset_re = 0; + qam64_table_offset_im = 0; - if (x0[*jj] == 1) - qam64_table_offset_re+=4; + if (x0[*jj] == 1) + qam64_table_offset_re+=4; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im+=4; + if (x0[*jj] == 1) + qam64_table_offset_im+=4; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_re+=2; + if (x0[*jj] == 1) + qam64_table_offset_re+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im+=2; + if (x0[*jj] == 1) + qam64_table_offset_im+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_re+=1; + if (x0[*jj] == 1) + qam64_table_offset_re+=1; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im+=1; + if (x0[*jj] == 1) + qam64_table_offset_im+=1; - *jj=*jj+1; + *jj=*jj+1; - ((int16_t *)&txdataF[0][tti_offset])[0]+=(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); - ((int16_t *)&txdataF[0][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); + ((int16_t *)&txdataF[0][tti_offset])[0]+=(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); + ((int16_t *)&txdataF[0][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); - // Antenna 1 => -x1* - qam64_table_offset_re = 0; - qam64_table_offset_im = 0; + // Antenna 1 => -x1* + qam64_table_offset_re = 0; + qam64_table_offset_im = 0; - if (x0[*jj] == 1) - qam64_table_offset_re+=4; + if (x0[*jj] == 1) + qam64_table_offset_re+=4; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im+=4; + if (x0[*jj] == 1) + qam64_table_offset_im+=4; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_re+=2; + if (x0[*jj] == 1) + qam64_table_offset_re+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im+=2; + if (x0[*jj] == 1) + qam64_table_offset_im+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_re+=1; + if (x0[*jj] == 1) + qam64_table_offset_re+=1; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im+=1; + if (x0[*jj] == 1) + qam64_table_offset_im+=1; - *jj=*jj+1; + *jj=*jj+1; - ((int16_t *)&txdataF[1][tti_offset])[0]+=-(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); - ((int16_t *)&txdataF[1][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); + ((int16_t *)&txdataF[1][tti_offset])[0]+=-(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); + ((int16_t *)&txdataF[1][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); - break; + break; } // fill in the rest of the ALAMOUTI precoding @@ -550,182 +590,182 @@ int allocate_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, if (frame_parms->nb_antennas_tx == 2) { switch (mod_order0) { - default: - LOG_E(PHY,"Unknown mod_order0 %d\n",mod_order0); - xx0_re=xx0_im=0; - break; + default: + LOG_E(PHY,"Unknown mod_order0 %d\n",mod_order0); + xx0_re=xx0_im=0; + break; - case 2: //QPSK - // printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - xx0_re = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; - *jj = *jj + 1; - xx0_im = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; - *jj = *jj + 1; + case 2: //QPSK + // printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + xx0_re = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + *jj = *jj + 1; + xx0_im = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + *jj = *jj + 1; - // printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - break; + // printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + break; - case 4: //16QAM + case 4: //16QAM - qam16_table_offset_re0 = 0; - qam16_table_offset_im0 = 0; + qam16_table_offset_re0 = 0; + qam16_table_offset_im0 = 0; - if (x0[*jj] == 1) - qam16_table_offset_re0+=2; + if (x0[*jj] == 1) + qam16_table_offset_re0+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_im0+=2; + if (x0[*jj] == 1) + qam16_table_offset_im0+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_re0+=1; + if (x0[*jj] == 1) + qam16_table_offset_re0+=1; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_im0+=1; + if (x0[*jj] == 1) + qam16_table_offset_im0+=1; - *jj=*jj+1; + *jj=*jj+1; - xx0_re = qam_table_s0[qam16_table_offset_re0]; - xx0_im = qam_table_s0[qam16_table_offset_im0]; + xx0_re = qam_table_s0[qam16_table_offset_re0]; + xx0_im = qam_table_s0[qam16_table_offset_im0]; - break; + break; - case 6: //64QAM + case 6: //64QAM - qam64_table_offset_re0 = 0; - qam64_table_offset_im0 = 0; + qam64_table_offset_re0 = 0; + qam64_table_offset_im0 = 0; - if (x0[*jj] == 1) - qam64_table_offset_re0+=4; + if (x0[*jj] == 1) + qam64_table_offset_re0+=4; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im0+=4; + if (x0[*jj] == 1) + qam64_table_offset_im0+=4; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_re0+=2; + if (x0[*jj] == 1) + qam64_table_offset_re0+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im0+=2; + if (x0[*jj] == 1) + qam64_table_offset_im0+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_re0+=1; + if (x0[*jj] == 1) + qam64_table_offset_re0+=1; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im0+=1; + if (x0[*jj] == 1) + qam64_table_offset_im0+=1; - *jj=*jj+1; + *jj=*jj+1; - xx0_re = qam_table_s0[qam64_table_offset_re0]; - xx0_im = qam_table_s0[qam64_table_offset_im0]; + xx0_re = qam_table_s0[qam64_table_offset_re0]; + xx0_im = qam_table_s0[qam64_table_offset_im0]; - break; + break; } switch (mod_order1) { - default: - LOG_E(PHY,"Unknown mod_order1 %d\n",mod_order1); - xx1_re=xx1_im=0; - break; + default: + LOG_E(PHY,"Unknown mod_order1 %d\n",mod_order1); + xx1_re=xx1_im=0; + break; - case 2: //QPSK - // printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - xx1_re = (x1[*jj2]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; - *jj2 = *jj2 + 1; - xx1_im = (x1[*jj2]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; - *jj2 = *jj2 + 1; - // printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - break; + case 2: //QPSK + // printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + xx1_re = (x1[*jj2]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + *jj2 = *jj2 + 1; + xx1_im = (x1[*jj2]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + *jj2 = *jj2 + 1; + // printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + break; - case 4: //16QAM + case 4: //16QAM - qam16_table_offset_re1 = 0; - qam16_table_offset_im1 = 0; + qam16_table_offset_re1 = 0; + qam16_table_offset_im1 = 0; - if (x1[*jj2] == 1) - qam16_table_offset_re1+=2; + if (x1[*jj2] == 1) + qam16_table_offset_re1+=2; - *jj2 = *jj2 + 1; + *jj2 = *jj2 + 1; - if (x1[*jj2] == 1) - qam16_table_offset_im1+=2; + if (x1[*jj2] == 1) + qam16_table_offset_im1+=2; - *jj2 = *jj2 + 1; + *jj2 = *jj2 + 1; - if (x1[*jj2] == 1) - qam16_table_offset_re1+=1; + if (x1[*jj2] == 1) + qam16_table_offset_re1+=1; - *jj2 = *jj2 + 1; + *jj2 = *jj2 + 1; - if (x1[*jj2] == 1) - qam16_table_offset_im1+=1; + if (x1[*jj2] == 1) + qam16_table_offset_im1+=1; - *jj2 = *jj2 + 1; + *jj2 = *jj2 + 1; - xx1_re = qam_table_s1[qam16_table_offset_re1]; - xx1_im = qam_table_s1[qam16_table_offset_im1]; + xx1_re = qam_table_s1[qam16_table_offset_re1]; + xx1_im = qam_table_s1[qam16_table_offset_im1]; - break; + break; - case 6: //64QAM + case 6: //64QAM - qam64_table_offset_re1 = 0; - qam64_table_offset_im1 = 0; + qam64_table_offset_re1 = 0; + qam64_table_offset_im1 = 0; - if (x1[*jj2] == 1) - qam64_table_offset_re1+=4; + if (x1[*jj2] == 1) + qam64_table_offset_re1+=4; - *jj2 = *jj2 + 1; + *jj2 = *jj2 + 1; - if (x1[*jj2] == 1) - qam64_table_offset_im1+=4; + if (x1[*jj2] == 1) + qam64_table_offset_im1+=4; - *jj2 = *jj2 + 1; + *jj2 = *jj2 + 1; - if (x1[*jj2] == 1) - qam64_table_offset_re1+=2; + if (x1[*jj2] == 1) + qam64_table_offset_re1+=2; - *jj2 = *jj2 + 1; + *jj2 = *jj2 + 1; - if (x1[*jj2] == 1) - qam64_table_offset_im1+=2; + if (x1[*jj2] == 1) + qam64_table_offset_im1+=2; - *jj2 = *jj2 + 1; + *jj2 = *jj2 + 1; - if (x1[*jj2] == 1) - qam64_table_offset_re1+=1; + if (x1[*jj2] == 1) + qam64_table_offset_re1+=1; - *jj2 = *jj2 + 1; + *jj2 = *jj2 + 1; - if (x1[*jj2] == 1) - qam64_table_offset_im1+=1; + if (x1[*jj2] == 1) + qam64_table_offset_im1+=1; - *jj2 = *jj2 + 1; + *jj2 = *jj2 + 1; - xx1_re = qam_table_s1[qam64_table_offset_re1]; - xx1_im = qam_table_s1[qam64_table_offset_im1]; + xx1_re = qam_table_s1[qam64_table_offset_re1]; + xx1_im = qam_table_s1[qam64_table_offset_im1]; - break; + break; } @@ -740,10 +780,10 @@ int allocate_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, ((int16_t *)&txdataF[0][tti_offset])[1]+=((xx0_im+xx1_im)>>1); ((int16_t *)&txdataF[1][tti_offset])[1]+=(s*((xx0_im-xx1_im)>>1)); /* - printf("CDD: xx0 (%d,%d), xx1(%d,%d), s(%d), txF[0] (%d,%d), txF[1] (%d,%d)\n", - xx0_re,xx0_im,xx1_re,xx1_im, s, ((int16_t *)&txdataF[0][tti_offset])[0],((int16_t *)&txdataF[0][tti_offset])[1], - ((int16_t *)&txdataF[1][tti_offset])[0],((int16_t *)&txdataF[1][tti_offset])[1]); - */ + printf("CDD: xx0 (%d,%d), xx1(%d,%d), s(%d), txF[0] (%d,%d), txF[1] (%d,%d)\n", + xx0_re,xx0_im,xx1_re,xx1_im, s, ((int16_t *)&txdataF[0][tti_offset])[0],((int16_t *)&txdataF[0][tti_offset])[1], + ((int16_t *)&txdataF[1][tti_offset])[0],((int16_t *)&txdataF[1][tti_offset])[1]); + */ // s alternates +1/-1 for each RE s = -s; } @@ -753,173 +793,61 @@ int allocate_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, amp = (int16_t)(((int32_t)tmp_amp*ONE_OVER_SQRT2_Q15)>>15); switch (mod_order0) { - case 2: //QPSK - - ((int16_t*)&tmp_sample1)[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; - *jj = *jj + 1; - ((int16_t*)&tmp_sample1)[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; - *jj = *jj + 1; - - // normalization for 2 tx antennas - ((int16_t*)&txdataF[0][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*ONE_OVER_SQRT2_Q15)>>15); - ((int16_t*)&txdataF[0][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*ONE_OVER_SQRT2_Q15)>>15); - - if (frame_parms->nb_antennas_tx == 2) { - layer1prec2A(&tmp_sample1,&tmp_sample2,precoder_index); - ((int16_t*)&txdataF[1][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample2)[0]*ONE_OVER_SQRT2_Q15)>>15); - ((int16_t*)&txdataF[1][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample2)[1]*ONE_OVER_SQRT2_Q15)>>15); - } - - break; - - case 4: //16QAM - - qam16_table_offset_re = 0; - qam16_table_offset_im = 0; - - if (x0[*jj] == 1) - qam16_table_offset_re+=2; - - *jj=*jj+1; - - if (x0[*jj] == 1) - qam16_table_offset_im+=2; - - *jj=*jj+1; - - - if (x0[*jj] == 1) - qam16_table_offset_re+=1; - - *jj=*jj+1; - - if (x0[*jj] == 1) - qam16_table_offset_im+=1; - - *jj=*jj+1; - - ((int16_t*)&tmp_sample1)[0] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); - ((int16_t*)&tmp_sample1)[1] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); - - ((int16_t *)&txdataF[0][tti_offset])[0] += ((int16_t*)&tmp_sample1)[0]; - ((int16_t *)&txdataF[0][tti_offset])[1] += ((int16_t*)&tmp_sample1)[1]; - - if (frame_parms->nb_antennas_tx == 2) { - layer1prec2A(&tmp_sample1,&tmp_sample2,precoder_index); - ((int16_t*)&txdataF[1][tti_offset])[0] += ((int16_t*)&tmp_sample2)[0]; - ((int16_t*)&txdataF[1][tti_offset])[1] += ((int16_t*)&tmp_sample2)[1]; - } - - break; - - case 6: //64QAM - - - qam64_table_offset_re = 0; - qam64_table_offset_im = 0; - - if (x0[*jj] == 1) - qam64_table_offset_re+=4; - - *jj=*jj+1; - - if (x0[*jj] == 1) - qam64_table_offset_im+=4; - - *jj=*jj+1; - - if (x0[*jj] == 1) - qam64_table_offset_re+=2; - - *jj=*jj+1; - - if (x0[*jj] == 1) - qam64_table_offset_im+=2; - - *jj=*jj+1; - - if (x0[*jj] == 1) - qam64_table_offset_re+=1; - - *jj=*jj+1; - - if (x0[*jj] == 1) - qam64_table_offset_im+=1; - - *jj=*jj+1; - - ((int16_t*)&tmp_sample1)[0] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); - ((int16_t*)&tmp_sample1)[1] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); - - ((int16_t *)&txdataF[0][tti_offset])[0] += ((int16_t*)&tmp_sample1)[0]; - ((int16_t *)&txdataF[0][tti_offset])[1] += ((int16_t*)&tmp_sample1)[1]; - - if (frame_parms->nb_antennas_tx == 2) { - layer1prec2A(&tmp_sample1,&tmp_sample2,precoder_index); - ((int16_t*)&txdataF[1][tti_offset])[0] += ((int16_t*)&tmp_sample2)[0]; - ((int16_t*)&txdataF[1][tti_offset])[1] += ((int16_t*)&tmp_sample2)[1]; - } - - break; - - } - } - - if (mimo_mode == ALAMOUTI) { - re++; // adjacent carriers are taken care of by precoding - *re_allocated = *re_allocated + 1; - - if (is_not_pilot(pilots,re,frame_parms->nushift,use2ndpilots)==0) { - re++; - *re_allocated = *re_allocated + 1; - } - } - - if (mimo_mode >= TM8) { //TM8,TM9,TM10 - - if (is_not_UEspecRS(first_layer0,re)) { - switch (mod_order0) { case 2: //QPSK - // printf("%d : %d,%d => ",tti_offset,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - for (int layer=first_layer0; layer<=(first_layer0+Nlayers0); layer++) { - ((int16_t*)&txdataF[layer][tti_offset])[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i - *jj = *jj + 1; - ((int16_t*)&txdataF[layer][tti_offset])[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} - *jj = *jj + 1; + ((int16_t*)&tmp_sample1)[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + *jj = *jj + 1; + ((int16_t*)&tmp_sample1)[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + *jj = *jj + 1; + + // normalization for 2 tx antennas + ((int16_t*)&txdataF[0][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*ONE_OVER_SQRT2_Q15)>>15); + ((int16_t*)&txdataF[0][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*ONE_OVER_SQRT2_Q15)>>15); + + if (frame_parms->nb_antennas_tx == 2) { + layer1prec2A(&tmp_sample1,&tmp_sample2,precoder_index); + ((int16_t*)&txdataF[1][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample2)[0]*ONE_OVER_SQRT2_Q15)>>15); + ((int16_t*)&txdataF[1][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample2)[1]*ONE_OVER_SQRT2_Q15)>>15); } break; case 4: //16QAM - if (is_not_UEspecRS(0/*layer (FIXME uninitialized!)*/,re)) { - qam16_table_offset_re = 0; - qam16_table_offset_im = 0; - if (x0[*jj] == 1) - qam16_table_offset_re+=2; + qam16_table_offset_re = 0; + qam16_table_offset_im = 0; - *jj = *jj + 1; + if (x0[*jj] == 1) + qam16_table_offset_re+=2; - if (x0[*jj] == 1) - qam16_table_offset_im+=2; + *jj=*jj+1; - *jj = *jj + 1; + if (x0[*jj] == 1) + qam16_table_offset_im+=2; - if (x0[*jj] == 1) - qam16_table_offset_re+=1; + *jj=*jj+1; - *jj = *jj + 1; - if (x0[*jj] == 1) - qam16_table_offset_im+=1; + if (x0[*jj] == 1) + qam16_table_offset_re+=1; - *jj = *jj + 1; + *jj=*jj+1; - for (int layer=first_layer0; layer<=(first_layer0+Nlayers0); layer++) { - ((int16_t*)&txdataF[layer][tti_offset])[0] = qam_table_s0[qam16_table_offset_re]; - ((int16_t*)&txdataF[layer][tti_offset])[1] = qam_table_s0[qam16_table_offset_im]; - } + if (x0[*jj] == 1) + qam16_table_offset_im+=1; + + *jj=*jj+1; + + ((int16_t*)&tmp_sample1)[0] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); + ((int16_t*)&tmp_sample1)[1] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); + + ((int16_t *)&txdataF[0][tti_offset])[0] += ((int16_t*)&tmp_sample1)[0]; + ((int16_t *)&txdataF[0][tti_offset])[1] += ((int16_t*)&tmp_sample1)[1]; + + if (frame_parms->nb_antennas_tx == 2) { + layer1prec2A(&tmp_sample1,&tmp_sample2,precoder_index); + ((int16_t*)&txdataF[1][tti_offset])[0] += ((int16_t*)&tmp_sample2)[0]; + ((int16_t*)&txdataF[1][tti_offset])[1] += ((int16_t*)&tmp_sample2)[1]; } break; @@ -933,66 +861,221 @@ int allocate_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, if (x0[*jj] == 1) qam64_table_offset_re+=4; - *jj = *jj + 1; + *jj=*jj+1; if (x0[*jj] == 1) qam64_table_offset_im+=4; - *jj = *jj + 1; + *jj=*jj+1; if (x0[*jj] == 1) qam64_table_offset_re+=2; - *jj = *jj + 1; + *jj=*jj+1; if (x0[*jj] == 1) qam64_table_offset_im+=2; - *jj = *jj + 1; + *jj=*jj+1; if (x0[*jj] == 1) qam64_table_offset_re+=1; - *jj = *jj + 1; + *jj=*jj+1; if (x0[*jj] == 1) qam64_table_offset_im+=1; - *jj = *jj + 1; + *jj=*jj+1; - for (int layer=first_layer0; layer<=(first_layer0+Nlayers0); layer++) { - ((int16_t*)&txdataF[layer][tti_offset])[0] = qam_table_s0[qam64_table_offset_re]; - ((int16_t*)&txdataF[layer][tti_offset])[1] = qam_table_s0[qam64_table_offset_im]; + ((int16_t*)&tmp_sample1)[0] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); + ((int16_t*)&tmp_sample1)[1] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); + + ((int16_t *)&txdataF[0][tti_offset])[0] += ((int16_t*)&tmp_sample1)[0]; + ((int16_t *)&txdataF[0][tti_offset])[1] += ((int16_t*)&tmp_sample1)[1]; + + if (frame_parms->nb_antennas_tx == 2) { + layer1prec2A(&tmp_sample1,&tmp_sample2,precoder_index); + ((int16_t*)&txdataF[1][tti_offset])[0] += ((int16_t*)&tmp_sample2)[0]; + ((int16_t*)&txdataF[1][tti_offset])[1] += ((int16_t*)&tmp_sample2)[1]; } break; - } } - } else if (mimo_mode>=TM9_10) { + } else if(mimo_mode == TM7){ + *re_allocated = *re_allocated + 1; + + if (is_not_UEspecRS(lprime,re,frame_parms->Nid_cell%3,frame_parms->Ncp,7)) { + + switch (mod_order0){ + case 2: //QPSK + + ((int16_t*)&tmp_sample1)[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + *jj = *jj + 1; + ((int16_t*)&tmp_sample1)[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + *jj = *jj + 1; + + //printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + //printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); + for (aa=0; aa>15); + ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((uint16_t*)&beamforming_weights[re][aa])[1])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((uint16_t*)&beamforming_weights[re][aa])[1])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*((uint16_t*)&beamforming_weights[re][aa])[0])>>15); + /* ((int16_t*)&txdataF[aa][tti_offset])[0] = ((int16_t*)&tmp_sample1)[0]; + ((int16_t*)&txdataF[aa][tti_offset])[1] = ((int16_t*)&tmp_sample1)[1]; */ + } + + //printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + break; + + case 4: //16QAM + + qam16_table_offset_re = 0; + qam16_table_offset_im = 0; + + if (x0[*jj] == 1) + qam16_table_offset_re+=2; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam16_table_offset_im+=2; + + *jj=*jj+1; + + + if (x0[*jj] == 1) + qam16_table_offset_re+=1; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam16_table_offset_im+=1; + + *jj=*jj+1; + + ((int16_t*)&tmp_sample1)[0] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); + ((int16_t*)&tmp_sample1)[1] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); + + for (aa=0; aa>15); + ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); + } + + break; + + case 6: //64QAM + + + qam64_table_offset_re = 0; + qam64_table_offset_im = 0; + + if (x0[*jj] == 1) + qam64_table_offset_re+=4; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam64_table_offset_im+=4; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam64_table_offset_re+=2; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam64_table_offset_im+=2; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam64_table_offset_re+=1; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam64_table_offset_im+=1; + + *jj=*jj+1; + + ((int16_t*)&tmp_sample1)[0] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); + ((int16_t*)&tmp_sample1)[1] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); + + for (aa=0; aa>15); + ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); + } + + break; + + } + } else{ + //precoding UE spec RS + //printf("precoding UE spec RS\n"); + + for (aa=0; aa>4; + mprime_qpsk_symb = mprime2&0xf; + + tmp_sample1 = qpsk[(phy_vars_eNB->lte_gold_uespec_port5_table[0][Ns][lprime][mprime_dword]>>(2*mprime_qpsk_symb))&3]; + //printf("tmp_sample1=%d+i%d\n",((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); + //printf("beamforing_weights[%d][%d]=%d+i%d\n",re,aa,((int16_t*)&beamforming_weights[re][aa])[0],((int16_t*)&beamforming_weights[re][aa])[1]); + + ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((uint16_t*)&beamforming_weights[re][aa])[0])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((uint16_t*)&beamforming_weights[re][aa])[1])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((uint16_t*)&beamforming_weights[re][aa])[1])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*((uint16_t*)&beamforming_weights[re][aa])[0])>>15); + + // ((int16_t*)&txdataF[aa][tti_offset])[0] = 0xffff; + // ((int16_t*)&txdataF[aa][tti_offset])[1] = 0xffff; + + mprime2 = mprime2++; + //printf("**txdataF[%d][%d]= %d+i%d\n ",aa,tti_offset,((int16_t*)&txdataF[aa][tti_offset])[0],((int16_t*)&txdataF[aa][tti_offset])[1]); + } + + } + } else if (mimo_mode == TM8) { //TM8 msg("allocate_REs_in_RB() [dlsch.c] : ERROR, unknown mimo_mode %d\n",mimo_mode); return(-1); } + if (mimo_mode == ALAMOUTI) { + re++; // adjacent carriers are taken care of by precoding + *re_allocated = *re_allocated + 1; + + if (is_not_pilot(pilots,re,frame_parms->nushift,use2ndpilots)==0) { + re++; + *re_allocated = *re_allocated + 1; + } + } + } } - return(0); +return(0); } int allocate_REs_in_RB_MCH(mod_sym_t **txdataF, uint32_t *jj, - uint16_t re_offset, - uint32_t symbol_offset, - uint8_t *x0, - uint8_t l, - uint8_t mod_order, - int16_t amp, - int16_t *qam_table_s, - uint32_t *re_allocated, - uint8_t skip_dc, - LTE_DL_FRAME_PARMS *frame_parms) + uint16_t re_offset, + uint32_t symbol_offset, + uint8_t *x0, + uint8_t l, + uint8_t mod_order, + int16_t amp, + int16_t *qam_table_s, + uint32_t *re_allocated, + uint8_t skip_dc, + LTE_DL_FRAME_PARMS *frame_parms) { uint32_t tti_offset,aa; @@ -1033,99 +1116,99 @@ int allocate_REs_in_RB_MCH(mod_sym_t **txdataF, switch (mod_order) { - case 2: //QPSK + case 2: //QPSK - // printf("%d : %d,%d => ",tti_offset,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - for (aa=0; aanb_antennas_tx; aa++) - ((int16_t*)&txdataF[aa][tti_offset])[0] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i + // printf("%d : %d,%d => ",tti_offset,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + for (aa=0; aanb_antennas_tx; aa++) + ((int16_t*)&txdataF[aa][tti_offset])[0] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i - *jj = *jj + 1; + *jj = *jj + 1; - for (aa=0; aanb_antennas_tx; aa++) - ((int16_t*)&txdataF[aa][tti_offset])[1] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} + for (aa=0; aanb_antennas_tx; aa++) + ((int16_t*)&txdataF[aa][tti_offset])[1] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} - *jj = *jj + 1; + *jj = *jj + 1; - // printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - break; + // printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + break; - case 4: //16QAM + case 4: //16QAM - qam16_table_offset_re = 0; - qam16_table_offset_im = 0; + qam16_table_offset_re = 0; + qam16_table_offset_im = 0; - if (x0[*jj] == 1) - qam16_table_offset_re+=2; + if (x0[*jj] == 1) + qam16_table_offset_re+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_im+=2; + if (x0[*jj] == 1) + qam16_table_offset_im+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_re+=1; + if (x0[*jj] == 1) + qam16_table_offset_re+=1; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam16_table_offset_im+=1; + if (x0[*jj] == 1) + qam16_table_offset_im+=1; - *jj=*jj+1; + *jj=*jj+1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s[qam16_table_offset_re]; - ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s[qam16_table_offset_im]; - // ((int16_t *)&txdataF[aa][tti_offset])[0]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); - // ((int16_t *)&txdataF[aa][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); - } + for (aa=0; aanb_antennas_tx; aa++) { + ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s[qam16_table_offset_re]; + ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s[qam16_table_offset_im]; + // ((int16_t *)&txdataF[aa][tti_offset])[0]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); + // ((int16_t *)&txdataF[aa][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); + } - break; + break; - case 6: //64QAM + case 6: //64QAM - qam64_table_offset_re = 0; - qam64_table_offset_im = 0; + qam64_table_offset_re = 0; + qam64_table_offset_im = 0; - if (x0[*jj] == 1) - qam64_table_offset_re+=4; + if (x0[*jj] == 1) + qam64_table_offset_re+=4; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im+=4; + if (x0[*jj] == 1) + qam64_table_offset_im+=4; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_re+=2; + if (x0[*jj] == 1) + qam64_table_offset_re+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im+=2; + if (x0[*jj] == 1) + qam64_table_offset_im+=2; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_re+=1; + if (x0[*jj] == 1) + qam64_table_offset_re+=1; - *jj=*jj+1; + *jj=*jj+1; - if (x0[*jj] == 1) - qam64_table_offset_im+=1; + if (x0[*jj] == 1) + qam64_table_offset_im+=1; - *jj=*jj+1; + *jj=*jj+1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s[qam64_table_offset_re];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); - ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s[qam64_table_offset_im];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); - } + for (aa=0; aanb_antennas_tx; aa++) { + ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s[qam64_table_offset_re];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); + ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s[qam64_table_offset_im];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); + } - break; + break; } } @@ -1142,50 +1225,52 @@ uint8_t get_pmi(uint8_t N_RB_DL,LTE_DL_eNB_HARQ_t *dlsch_harq,uint16_t rb) // printf("Getting pmi for RB %d => %d\n",rb,(pmi_alloc>>((rb>>2)<<1))&3); switch (N_RB_DL) { - case 6: // 1 PRB per subband - if (mode <= PUSCH_PRECODING1) - return((pmi_alloc>>(rb<<1))&3); - else - return((pmi_alloc>>rb)&1); + case 6: // 1 PRB per subband + if (mode <= PUSCH_PRECODING1) + return((pmi_alloc>>(rb<<1))&3); + else + return((pmi_alloc>>rb)&1); - break; + break; - default: - case 25: // 4 PRBs per subband - if (mode <= PUSCH_PRECODING1) - return((pmi_alloc>>((rb>>2)<<1))&3); - else - return((pmi_alloc>>(rb>>2))&1); + default: + case 25: // 4 PRBs per subband + if (mode <= PUSCH_PRECODING1) + return((pmi_alloc>>((rb>>2)<<1))&3); + else + return((pmi_alloc>>(rb>>2))&1); - break; + break; - case 50: // 6 PRBs per subband - if (mode <= PUSCH_PRECODING1) - return((pmi_alloc>>((rb/6)<<1))&3); - else - return((pmi_alloc>>(rb/6))&1); + case 50: // 6 PRBs per subband + if (mode <= PUSCH_PRECODING1) + return((pmi_alloc>>((rb/6)<<1))&3); + else + return((pmi_alloc>>(rb/6))&1); - break; + break; - case 100: // 8 PRBs per subband - if (mode <= PUSCH_PRECODING1) - return((pmi_alloc>>((rb>>3)<<1))&3); - else - return((pmi_alloc>>(rb>>3))&1); + case 100: // 8 PRBs per subband + if (mode <= PUSCH_PRECODING1) + return((pmi_alloc>>((rb>>3)<<1))&3); + else + return((pmi_alloc>>(rb>>3))&1); - break; + break; } } -int dlsch_modulation(mod_sym_t **txdataF, +int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, + mod_sym_t **txdataF, int16_t amp, uint32_t subframe_offset, - LTE_DL_FRAME_PARMS *frame_parms, uint8_t num_pdcch_symbols, LTE_eNB_DLSCH_t *dlsch0, - LTE_eNB_DLSCH_t *dlsch1) + LTE_eNB_DLSCH_t *dlsch1, + int32_t **beamforming_weights) { + LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_eNB->lte_frame_parms; uint8_t nsymb; uint8_t harq_pid = dlsch0->current_harq_pid; @@ -1195,7 +1280,7 @@ int dlsch_modulation(mod_sym_t **txdataF, uint16_t l,rb,re_offset; uint32_t rb_alloc_ind; uint32_t *rb_alloc = dlsch0_harq->rb_alloc; - uint8_t pilots=0; + uint8_t pilots=0,ue_spec_rs=0; uint8_t skip_dc,skip_half; uint8_t mod_order0 = get_Qm(dlsch0_harq->mcs); uint8_t mod_order1 = 0; @@ -1203,6 +1288,11 @@ int dlsch_modulation(mod_sym_t **txdataF, int16_t qam16_table_a0[4],qam64_table_a0[8],qam16_table_b0[4],qam64_table_b0[8]; int16_t qam16_table_a1[4],qam64_table_a1[8],qam16_table_b1[4],qam64_table_b1[8]; int16_t *qam_table_s0,*qam_table_s1; + MIMO_mode_t mimo_mode = dlsch0_harq->mimo_mode; + uint8_t beamforming_mode = 0; + int32_t **beamforming_weights_RB = beamforming_weights; + uint8_t lprime, mprime=0,Ns; + #ifdef DEBUG_DLSCH_MODULATION uint8_t Nl0 = dlsch0_harq->Nl; uint8_t Nl1; @@ -1224,7 +1314,7 @@ int dlsch_modulation(mod_sym_t **txdataF, amp_rho_b = (int16_t)(((int32_t)amp*dlsch0->sqrt_rho_b)>>13); if (mod_order0 == 4) - for (i=0; i<4; i++) { + for (i=0;i<4; i++) { qam16_table_a0[i] = (int16_t)(((int32_t)qam16_table[i]*amp_rho_a)>>15); qam16_table_b0[i] = (int16_t)(((int32_t)qam16_table[i]*amp_rho_b)>>15); } @@ -1281,6 +1371,35 @@ int dlsch_modulation(mod_sym_t **txdataF, pilots=0; } + if(mimo_mode==TM7){ //36.211 V8.6.0 2009-03 + beamforming_mode = 7; + mprime = 0; + if (frame_parms->Ncp==0) { // normal prefix + if ((l==6)||(l==12)) + lprime=2; // pilots in nushift+3, nushift+9 + else if ((l==3)||(l==9)) + lprime=1; // pilots in nushift, nushift+6 + else + lprime=0; + } else { + if ((l==7)) + lprime=2; + else if ((l==4)||(l==10)) + lprime=1; + else + lprime=0; + } + }else if(mimo_mode==TM8){ + beamforming_mode = 8; + }else if(mimo_mode==TM9_10){ + beamforming_mode = 9; + } + + if(l<=(nsymb>>2)) + Ns=0; + else + Ns=1; + re_offset = frame_parms->first_carrier_offset; symbol_offset = (uint32_t)frame_parms->ofdm_symbol_size*(l+(subframe_offset*nsymb)); @@ -1392,7 +1511,7 @@ int dlsch_modulation(mod_sym_t **txdataF, if (frame_parms->frame_type == TDD) { // TDD //SSS if (((subframe_offset==0)|| - (subframe_offset==5)) && + (subframe_offset==5)) && (rb>=((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==nsymb-1) ) { @@ -1401,7 +1520,7 @@ int dlsch_modulation(mod_sym_t **txdataF, //PSS if (((subframe_offset==1)|| - (subframe_offset==6)) && + (subframe_offset==6)) && (rb>=((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==2) ) { @@ -1448,7 +1567,7 @@ int dlsch_modulation(mod_sym_t **txdataF, if (rb_alloc_ind > 0) { // printf("Allocated rb %d/symbol %d, skip_half %d, subframe_offset %d, symbol_offset %d, re_offset %d, jj %d\n",rb,l,skip_half,subframe_offset,symbol_offset,re_offset,jj); - allocate_REs_in_RB(frame_parms, + allocate_REs_in_RB(phy_vars_eNB, txdataF, &jj, &jj2, @@ -1463,23 +1582,36 @@ int dlsch_modulation(mod_sym_t **txdataF, qam_table_s1, &re_allocated, skip_dc, - skip_half); + skip_half, + lprime, + mprime, + Ns, + beamforming_weights_RB); + + if(mimo_mode==TM7){ + if(frame_parms->Ncp==0&&(l==3||l==6||l==9||l==12)) + mprime +=3; + else if(frame_parms->Ncp==1&&(l==4||l==7||l==10)) + mprime +=4; + } } re_offset+=12; // go to next RB + beamforming_weights_RB +=12; // check if we crossed the symbol boundary and skip DC if (re_offset >= frame_parms->ofdm_symbol_size) { - if (skip_dc == 0) //even number of RBs (doesn't straddle DC) - re_offset=1; - else - re_offset=7; // odd number of RBs - } - } + if (skip_dc == 0) //even number of RBs (doesn't straddle DC) + re_offset=1; + else + re_offset=7; // odd number of RBs + } + beamforming_weights_RB = beamforming_weights; + } - } + } diff --git a/openair1/PHY/LTE_TRANSPORT/lte_mcs.c b/openair1/PHY/LTE_TRANSPORT/lte_mcs.c index 6e253c3b63..0c846f3aa7 100644 --- a/openair1/PHY/LTE_TRANSPORT/lte_mcs.c +++ b/openair1/PHY/LTE_TRANSPORT/lte_mcs.c @@ -333,11 +333,8 @@ int adjust_G(LTE_DL_FRAME_PARMS *frame_parms,uint32_t *rb_alloc,uint8_t mod_orde return(0); } -int get_G(LTE_DL_FRAME_PARMS *frame_parms,uint16_t nb_rb,uint32_t *rb_alloc,uint8_t mod_order,uint8_t Nl,uint8_t num_pdcch_symbols,int frame,uint8_t subframe) +int get_G(LTE_DL_FRAME_PARMS *frame_parms,uint16_t nb_rb,uint32_t *rb_alloc,uint8_t mod_order,uint8_t Nl,uint8_t num_pdcch_symbols,int frame,uint8_t subframe,uint8_t beamforming_mode) { - - - int G_adj; if (is_pmch_subframe(frame,subframe,frame_parms) == 0) { @@ -348,9 +345,11 @@ int get_G(LTE_DL_FRAME_PARMS *frame_parms,uint16_t nb_rb,uint32_t *rb_alloc,uint // PDDDPDD PDDDPDD - 13 PDSCH symbols, 10 full, 3 w/ pilots = 10*12 + 3*8 // PCDDPDD PDDDPDD - 12 PDSCH symbols, 9 full, 3 w/ pilots = 9*12 + 3*8 // PCCDPDD PDDDPDD - 11 PDSCH symbols, 8 full, 3 w/pilots = 8*12 + 3*8 - if (frame_parms->mode1_flag==0) // SISO + if (beamforming_mode==0 && frame_parms->mode1_flag==0) return((((int)nb_rb * mod_order * ((11-num_pdcch_symbols)*12 + 3*8)) - G_adj)*Nl); - else + else if(beamforming_mode==7) + return(((int)nb_rb * mod_order * ((7-num_pdcch_symbols)*12 + 3*10 + 4*9)) - G_adj); + else //SISO return(((int)nb_rb * mod_order * ((11-num_pdcch_symbols)*12 + 3*10)) - G_adj); } else { // PDDPDD PDDPDD - 11 PDSCH symbols, 8 full, 3 w/ pilots = 8*12 + 3*8 @@ -358,7 +357,9 @@ int get_G(LTE_DL_FRAME_PARMS *frame_parms,uint16_t nb_rb,uint32_t *rb_alloc,uint // PCCPDD PDDPDD - 9 PDSCH symbols, 6 full, 3 w/pilots = 6*12 + 3*8 if (frame_parms->mode1_flag==0) return((((int)nb_rb * mod_order * ((9-num_pdcch_symbols)*12 + 3*8)) - G_adj)*Nl); - else + else if(beamforming_mode==7) + return(((int)nb_rb * mod_order * ((5-num_pdcch_symbols)*12 + 3*8 + 4*9)) - G_adj); + else //SISO return(((int)nb_rb * mod_order * ((9-num_pdcch_symbols)*12 + 3*10)) - G_adj); } } else { // This is an MBSFN subframe diff --git a/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c b/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c new file mode 100644 index 0000000000..310204eea9 --- /dev/null +++ b/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c @@ -0,0 +1,217 @@ +/******************************************************************************* + 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + + *******************************************************************************/ + +/*! \file PHY/LTE_TRANSPORT/uespec_pilots.c +* \brief Top-level routines for generating DL ue-specific reference signals V12.5 2015-03 +* \author X.JIANG +* \date 2011 +* \version 0.1 +* \company Eurecom +* \email: xiwen.jiangeurecom.fr +* \note +* \warning +*/ +//#include "defs.h" +#include "PHY/defs.h" + +void generate_ue_spec_pilots(PHY_VARS_eNB *phy_vars_eNB, + uint8_t UE_id, + mod_sym_t **txdataF, + int16_t amp, + uint16_t Ntti, + uint8_t beamforming_mode) +{ + + LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_eNB->lte_frame_parms; + + uint32_t tti,tti_offset,slot_offset,Nsymb,samples_per_symbol; + uint8_t second_pilot,aa; + + // printf("Doing TX pilots Nsymb %d, second_pilot %d\n",Nsymb,second_pilot); + + switch(beamforming_mode){ + case 7: + for (tti=0; ttiofdm_symbol_size*Nsymb; + samples_per_symbol = frame_parms->ofdm_symbol_size; + slot_offset = (tti*2)%20; + + // printf("tti %d : offset %d (slot %d)\n",tti,tti_offset,slot_offset); + //Generate UE specific Pilots + printf("generate_dl_ue_spec:tti_offset=%d\n",tti_offset); + + if(frame_parms->Ncp==0) { + for(aa=0;aanb_antennas_tx_phy;aa++){ + //antenna port 5 symbol 0 slot 0 + lte_dl_ue_spec(phy_vars_eNB, + UE_id, + &txdataF[aa][tti_offset+3*samples_per_symbol], + amp, + slot_offset, + 1, + 5, + 0); + + //antenna port 5 symbol 1 slot 0 + lte_dl_ue_spec(phy_vars_eNB, + UE_id, + &txdataF[aa][tti_offset+6*samples_per_symbol], + amp, + slot_offset, + 1, + 5, + 0); + + //antenna port 5 symbol 0 slot 1 + lte_dl_ue_spec(phy_vars_eNB, + UE_id, + &txdataF[aa][tti_offset+9*samples_per_symbol], + amp, + slot_offset+1, + 0, + 5, + 0); + + //antenna port 5 symbol 1 slot 1 + lte_dl_ue_spec(phy_vars_eNB, + UE_id, + &txdataF[aa][tti_offset+12*samples_per_symbol], + amp, + slot_offset+1, + 1, + 5, + 0); + } + } else{ + msg("generate_ue_soec_pilots:Extented Cyclic Prefix for TM7 is not supported yet.\n"); + } + + + } + break; + + case 8: + case 9: + case 10: + default: + msg("[generate_ue_spec_pilots(in uespec_pilots.c)]ERROR:beamforming mode %d is not supported\n",beamforming_mode); + + } +} + +/*int generate_ue_spec_pilots_slot(PHY_VARS_eNB *phy_vars_eNB, + mod_sym_t **txdataF, + int16_t amp, + uint16_t slot, + int first_pilot_only) +{ + + LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_eNB->lte_frame_parms; + uint32_t slot_offset,Nsymb,samples_per_symbol; + uint8_t second_pilot; + + if (slot<0 || slot>= 20) { + msg("generate_pilots_slot: slot not in range (%d)\n",slot); + return(-1); + } + + Nsymb = (frame_parms->Ncp==0)?7:6; + second_pilot = (frame_parms->Ncp==0)?4:3; + + + slot_offset = slot*frame_parms->ofdm_symbol_size*Nsymb; + samples_per_symbol = frame_parms->ofdm_symbol_size; + + // printf("tti %d : offset %d (slot %d)\n",tti,tti_offset,slot_offset); + //Generate Pilots + + //antenna 0 symbol 0 slot 0 + lte_dl_cell_spec(phy_vars_eNB, + &txdataF[0][slot_offset], + amp, + slot, + 0, + 0); + + + if (first_pilot_only==0) { + //antenna 0 symbol 3 slot 0 + lte_dl_cell_spec(phy_vars_eNB, + &txdataF[0][slot_offset+(second_pilot*samples_per_symbol)], + amp, + slot, + 1, + 0); + } + + if (frame_parms->nb_antennas_tx > 1) { + if (frame_parms->mode1_flag) { + // antenna 1 symbol 0 slot 0 + lte_dl_cell_spec(phy_vars_eNB, + &txdataF[1][slot_offset], + amp, + slot, + 0, + 0); + + if (first_pilot_only==0) { + // antenna 1 symbol 3 slot 0 + lte_dl_cell_spec(phy_vars_eNB, + &txdataF[1][slot_offset+(second_pilot*samples_per_symbol)], + amp, + slot, + 1, + 0); + } + } else { + + // antenna 1 symbol 0 slot 0 + lte_dl_cell_spec(phy_vars_eNB, + &txdataF[1][slot_offset], + amp, + slot, + 0, + 1); + + if (first_pilot_only == 0) { + // antenna 1 symbol 3 slot 0 + lte_dl_cell_spec(phy_vars_eNB, + &txdataF[1][slot_offset+(second_pilot*samples_per_symbol)], + amp, + slot, + 1, + 1); + } + } + } + + return(0); +}*/ + diff --git a/openair1/PHY/LTE_TRANSPORT/pmch.c b/openair1/PHY/LTE_TRANSPORT/pmch.c index 3082bff917..422f607464 100644 --- a/openair1/PHY/LTE_TRANSPORT/pmch.c +++ b/openair1/PHY/LTE_TRANSPORT/pmch.c @@ -304,7 +304,7 @@ void generate_mch(PHY_VARS_eNB *phy_vars_eNB,int sched_subframe,uint8_t *a,int a phy_vars_eNB->lte_frame_parms.N_RB_DL, phy_vars_eNB->dlsch_eNB_MCH->harq_processes[0]->rb_alloc, get_Qm(phy_vars_eNB->dlsch_eNB_MCH->harq_processes[0]->mcs),1, - 2,phy_vars_eNB->proc[sched_subframe].frame_tx,subframe); + 2,phy_vars_eNB->proc[sched_subframe].frame_tx,subframe,0); generate_mbsfn_pilot(phy_vars_eNB, phy_vars_eNB->lte_eNB_common_vars.txdataF[0], @@ -319,8 +319,7 @@ void generate_mch(PHY_VARS_eNB *phy_vars_eNB,int sched_subframe,uint8_t *a,int a subframe, &phy_vars_eNB->dlsch_rate_matching_stats, &phy_vars_eNB->dlsch_turbo_encoding_stats, - &phy_vars_eNB->dlsch_interleaving_stats - )<0) + &phy_vars_eNB->dlsch_interleaving_stats)<0) mac_xface->macphy_exit("problem in dlsch_encoding"); dlsch_scrambling(&phy_vars_eNB->lte_frame_parms,1,phy_vars_eNB->dlsch_eNB_MCH,G,0,subframe<<1); diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 5fe7518004..58a1177a37 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -1,4 +1,4 @@ -/******************************************************************************* +/****************************************************************************** OpenAirInterface Copyright(c) 1999 - 2014 Eurecom @@ -157,11 +157,14 @@ void dlsch_encoding_emul(PHY_VARS_eNB *phy_vars_eNB, \param re_allocated pointer to allocation counter \param skip_dc offset for positive RBs \param skip_half indicate that first or second half of RB must be skipped for PBCH/PSS/SSS + \param ue_spec_rs UE specific RS indicator + \param nb_antennas_tx_phy Physical antenna elements which can be different with antenna port number, especially in beamforming case + \param beamforming_weights_rb Beamforming weights applied on each antenna element and each carrier in case of TM7-10 \param use2ndpilots Set to use the pilots from antenna port 1 for PDSCH \param frame_parms Frame parameter descriptor */ -int32_t allocate_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, +int32_t allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, mod_sym_t **txdataF, uint32_t *jj, uint32_t *jj2, @@ -176,8 +179,11 @@ int32_t allocate_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, int16_t *qam_table_s1, uint32_t *re_allocated, uint8_t skip_dc, - uint8_t skip_half); - + uint8_t skip_half, + uint8_t lprime, + uint8_t mprime, + uint8_t Ns, + int32_t **beamforming_weights); /** \fn int32_t dlsch_modulation(mod_sym_t **txdataF, int16_t amp, @@ -194,15 +200,17 @@ int32_t allocate_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, @param num_pdcch_symbols Number of PDCCH symbols in this subframe @param dlsch0 Pointer to Transport Block 0 DLSCH descriptor for this allocation @param dlsch1 Pointer to Transport Block 0 DLSCH descriptor for this allocation - + @param nb_antennas_tx_phy Physical antenna elements which can be different with antenna port number, especially in beamforming case + @param beamforming_weights Beamforming weights applied on each antenna element and each carrier in case of TM7-10 */ -int32_t dlsch_modulation(mod_sym_t **txdataF, +int32_t dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, + mod_sym_t **txdataF, int16_t amp, uint32_t sub_frame_offset, - LTE_DL_FRAME_PARMS *frame_parms, uint8_t num_pdcch_symbols, LTE_eNB_DLSCH_t *dlsch0, - LTE_eNB_DLSCH_t *dlsch1); + LTE_eNB_DLSCH_t *dlsch1, + int32_t **beamforming_weights); /* \brief This function is the top-level routine for generation of the sub-frame signal (frequency-domain) for MCH. @param txdataF Table of pointers for frequency-domain TX signals @@ -295,6 +303,13 @@ int32_t generate_mbsfn_pilot(PHY_VARS_eNB *phy_vars_eNB, int16_t amp, uint16_t subframe); +void generate_ue_spec_pilots(PHY_VARS_eNB *phy_vars_eNB, + uint8_t UE_id, + mod_sym_t **txdataF, + int16_t amp, + uint16_t Ntti, + uint8_t beamforming_mode); + int32_t generate_pss(mod_sym_t **txdataF, int16_t amp, LTE_DL_FRAME_PARMS *frame_parms, @@ -680,6 +695,7 @@ int dlsch_64qam_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms, @param nb_rb number of RBs for this allocation @param pbch_pss_sss_adj Number of channel bits taken by PBCH/PSS/SSS @param llr128p pointer to pointer to symbol in dlsch_llr + @param beamforming_mode beamforming mode */ int32_t dlsch_qpsk_llr(LTE_DL_FRAME_PARMS *frame_parms, int32_t **rxdataF_comp, @@ -688,7 +704,8 @@ int32_t dlsch_qpsk_llr(LTE_DL_FRAME_PARMS *frame_parms, uint8_t first_symbol_flag, uint16_t nb_rb, uint16_t pbch_pss_sss_adj, - int16_t **llr128p); + int16_t **llr128p, + uint8_t beamforming_mode); /** \brief This function generates log-likelihood ratios (decoder input) for single-stream 16QAM received waveforms @@ -904,6 +921,16 @@ uint16_t dlsch_extract_rbs_dual(int32_t **rxdataF, uint32_t high_speed_flag, LTE_DL_FRAME_PARMS *frame_parms); +uint16_t dlsch_extract_rbs_TM7(int32_t **rxdataF, + int32_t **dl_bf_ch_estimates, + int32_t **rxdataF_ext, + int32_t **dl_bf_ch_estimates_ext, + uint32_t *rb_alloc, + uint8_t symbol, + uint8_t subframe, + uint32_t high_speed_flag, + LTE_DL_FRAME_PARMS *frame_parms); + /** \brief This function performs channel compensation (matched filtering) on the received RBs for this allocation. In addition, it computes the squared-magnitude of the channel with weightings for 16QAM/64QAM detection as well as dual-stream detection (cross-correlation) @param rxdataF_ext Frequency-domain received signal in RBs to be demodulated @param dl_ch_estimates_ext Frequency-domain channel estimates in RBs to be demodulated @@ -1249,7 +1276,7 @@ uint8_t get_transmission_mode(module_id_t Mod_id, uint8_t CC_id, rnti_t rnti); */ uint32_t conv_nprb(uint8_t ra_header,uint32_t rb_alloc,int N_RB_DL); -int get_G(LTE_DL_FRAME_PARMS *frame_parms,uint16_t nb_rb,uint32_t *rb_alloc,uint8_t mod_order,uint8_t Nl,uint8_t num_pdcch_symbols,int frame,uint8_t subframe); +int get_G(LTE_DL_FRAME_PARMS *frame_parms,uint16_t nb_rb,uint32_t *rb_alloc,uint8_t mod_order,uint8_t Nl,uint8_t num_pdcch_symbols,int frame,uint8_t subframe, uint8_t beamforming_mode); int adjust_G(LTE_DL_FRAME_PARMS *frame_parms,uint32_t *rb_alloc,uint8_t mod_order,uint8_t subframe); int adjust_G2(LTE_DL_FRAME_PARMS *frame_parms,uint32_t *rb_alloc,uint8_t mod_order,uint8_t subframe,uint8_t symbol); @@ -1551,7 +1578,7 @@ uint8_t phich_subframe2_pusch_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t s @param subframe Subframe of received/transmitted PHICH @returns frame of PUSCH transmission */ -uint8_t phich_frame2_pusch_frame(LTE_DL_FRAME_PARMS *frame_parms,frame_t frame,uint8_t subframe);; +uint8_t phich_frame2_pusch_frame(LTE_DL_FRAME_PARMS *frame_parms,frame_t frame,uint8_t subframe); void print_CQI(void *o,UCI_format_t uci_format,uint8_t eNB_id,int N_RB_DL); diff --git a/openair1/PHY/MODULATION/slot_fep.c b/openair1/PHY/MODULATION/slot_fep.c index 670a852b67..5bbea87c88 100644 --- a/openair1/PHY/MODULATION/slot_fep.c +++ b/openair1/PHY/MODULATION/slot_fep.c @@ -241,6 +241,15 @@ int slot_fep(PHY_VARS_UE *phy_vars_ue, } } + // printf("slot_fep:transmission_mode[%d] = %d\n", eNB_id, phy_vars_ue->transmission_mode[eNB_id]); + if(phy_vars_ue->transmission_mode[eNB_id] == 7) + if(frame_parms->Ncp==0 && (symbol==3) || (symbol==6) || (symbol==9) || (symbol==12)) + lte_dl_bf_channel_estimation(phy_vars_ue,eNB_id,0,Ns,5,symbol); + else if(frame_parms->Ncp==1 && (symbol==4) || (symbol==7) || (symbol==10)) + msg("slot_fep(slot_fep.c):channel estimation not supported yet for TM7 extented CP.\n"); + else if(phy_vars_ue->transmission_mode[eNB_id] > 7) + msg("slot_fep(slot_fep.c):transmission mode not supported yet.\n"); + } #ifdef DEBUG_FEP diff --git a/openair1/PHY/Makefile.inc b/openair1/PHY/Makefile.inc index 2105e1209d..1586f353c0 100644 --- a/openair1/PHY/Makefile.inc +++ b/openair1/PHY/Makefile.inc @@ -1,6 +1,7 @@ PHY_OBJS = $(TOP_DIR)/PHY/LTE_TRANSPORT/pss.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_TRANSPORT/sss.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_TRANSPORT/pilots.o +PHY_OBJS += $(TOP_DIR)/PHY/LTE_TRANSPORT/pilots_ue_spec.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_TRANSPORT/pilots_mbsfn.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_TRANSPORT/dlsch_coding.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_TRANSPORT/dlsch_modulation.o @@ -40,6 +41,7 @@ PHY_OBJS += $(TOP_DIR)/PHY/LTE_ESTIMATION/lte_sync_time.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_ESTIMATION/lte_sync_timefreq.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_ESTIMATION/lte_adjust_sync.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.o +PHY_OBJS += $(TOP_DIR)/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_ESTIMATION/lte_dl_mbsfn_channel_estimation.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_ESTIMATION/lte_est_freq_offset.o @@ -47,7 +49,7 @@ PHY_OBJS += $(TOP_DIR)/PHY/LTE_ESTIMATION/lte_ue_measurements.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_ESTIMATION/lte_eNB_measurements.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_ESTIMATION/adjust_gain.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_REFSIG/lte_dl_cell_spec.o -PHY_OBJS += $(TOP_DIR)/PHY/LTE_REFSIG/lte_dl_uespec.o +PHY_OBJS += $(TOP_DIR)/PHY/LTE_REFSIG/lte_dl_ue_spec.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_REFSIG/lte_gold.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_REFSIG/lte_gold_mbsfn.o PHY_OBJS += $(TOP_DIR)/PHY/LTE_REFSIG/lte_dl_mbsfn.o @@ -69,7 +71,7 @@ PHY_OBJS += $(TOP_DIR)/PHY/INIT/lte_init.o PHY_OBJS += $(TOP_DIR)/PHY/INIT/lte_parms.o PHY_OBJS += $(TOP_DIR)/PHY/INIT/init_top.o PHY_OBJS += $(TOP_DIR)/PHY/TOOLS/file_output.o -PHY_OBJS += $(TOP_DIR)/PHY/TOOLS/fft.o +#PHY_OBJS += $(TOP_DIR)/PHY/TOOLS/fft.o PHY_OBJS += $(TOP_DIR)/PHY/TOOLS/lte_dfts.o PHY_OBJS += $(TOP_DIR)/PHY/TOOLS/log2_approx.o PHY_OBJS += $(TOP_DIR)/PHY/TOOLS/cmult_sv.o diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 7a46d9c444..80c6b4ef01 100755 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -220,6 +220,7 @@ typedef struct PHY_VARS_eNB_s { eNB_proc_t proc[NUM_ENB_THREADS]; uint8_t local_flag; uint32_t rx_total_gain_eNB_dB; + uint8_t nb_antennas_tx_phy; LTE_DL_FRAME_PARMS lte_frame_parms; PHY_MEASUREMENTS_eNB PHY_measurements_eNB[NUMBER_OF_eNB_SECTORS_MAX]; /// Measurement variables LTE_eNB_COMMON lte_eNB_common_vars; @@ -241,6 +242,9 @@ typedef struct PHY_VARS_eNB_s { /// cell-specific reference symbols uint32_t lte_gold_table[20][2][14]; + /// UE-specific reference symbols (p=5), TM 7 + uint32_t lte_gold_uespec_port5_table[NUMBER_OF_UE_MAX][20][2][21]; + /// UE-specific reference symbols (p=7...14), TM 8/9/10 uint32_t lte_gold_uespec_table[2][20][2][21]; @@ -505,8 +509,11 @@ typedef struct { /// cell-specific reference symbols uint32_t lte_gold_table[7][20][2][14]; + /// UE-specific reference symbols (p=5), TM 7 + uint32_t lte_gold_uespec_port5_table[20][2][21]; + /// ue-specific reference symbols - uint32_t lte_gold_uespec_table[2][20][2][21]; + uint32_t lte_gold_uespec_table[2][20][2][21]; /// mbsfn reference symbols uint32_t lte_gold_mbsfn_table[10][3][42]; diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h index 47c32d87c8..a7574575a3 100644 --- a/openair1/PHY/impl_defs_lte.h +++ b/openair1/PHY/impl_defs_lte.h @@ -587,8 +587,9 @@ typedef enum { DUALSTREAM_UNIFORM_PRECODING1=9, DUALSTREAM_UNIFORM_PRECODINGj=10, DUALSTREAM_PUSCH_PRECODING=11, - TM8=12, - TM9_10=13 + TM7=12, + TM8=13, + TM9_10=14 } MIMO_mode_t; typedef struct { @@ -784,6 +785,10 @@ typedef struct { /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx /// - second index: ? [0..168*N_RB_DL[ int32_t **rxdataF_ext; + /// \brief Received frequency-domain ue specific pilots. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..12*N_RB_DL[ + int32_t **rxdataF_uespec_pilots; /// \brief Received frequency-domain signal after extraction and channel compensation. /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx /// - second index: ? [0..168*N_RB_DL[ @@ -797,6 +802,14 @@ typedef struct { /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx /// - second index: ? [0..168*N_RB_DL[ int32_t **dl_ch_estimates_ext; + /// \brief Downlink beamforming channel estimates in frequency domain. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: samples? [0..symbols_per_tti*(ofdm_symbol_size+LTE_CE_FILTER_LENGTH)[ + int32_t **dl_bf_ch_estimates; + /// \brief Downlink beamforming channel estimates. + /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx + /// - second index: ? [0..168*N_RB_DL[ + int32_t **dl_bf_ch_estimates_ext; /// \brief Downlink cross-correlation of MIMO channel estimates (unquantized PMI) extracted in PRBS. /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx /// - second index: ? [0..168*N_RB_DL[ diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 3828a9be72..32ff858996 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -2203,7 +2203,9 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e phy_vars_eNB->dlsch_eNB_SI->harq_processes[0]->rb_alloc, get_Qm(phy_vars_eNB->dlsch_eNB_SI->harq_processes[0]->mcs), 1, - num_pdcch_symbols,phy_vars_eNB->proc[sched_subframe].frame_tx,subframe), + num_pdcch_symbols,phy_vars_eNB->proc[sched_subframe].frame_tx, + subframe, + (phy_vars_eNB->transmission_mode[(uint8_t)UE_id]<7?0:phy_vars_eNB->transmission_mode[(uint8_t)UE_id])), 0, subframe<<1); @@ -2211,13 +2213,14 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e start_meas(&phy_vars_eNB->dlsch_modulation_stats); // for (sect_id=0;sect_idlte_eNB_common_vars.txdataF[0], + re_allocated = dlsch_modulation(&phy_vars_eNB, + phy_vars_eNB->lte_eNB_common_vars.txdataF[0], AMP, subframe, - &phy_vars_eNB->lte_frame_parms, num_pdcch_symbols, phy_vars_eNB->dlsch_eNB_SI, - (LTE_eNB_DLSCH_t *)NULL); + (LTE_eNB_DLSCH_t *)NULL, + (int32_t **)NULL); stop_meas(&phy_vars_eNB->dlsch_modulation_stats); } @@ -2338,17 +2341,22 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e phy_vars_eNB->dlsch_eNB_ra->harq_processes[0]->rb_alloc, get_Qm(phy_vars_eNB->dlsch_eNB_ra->harq_processes[0]->mcs), 1, - num_pdcch_symbols,phy_vars_eNB->proc[sched_subframe].frame_tx,subframe), + num_pdcch_symbols, + phy_vars_eNB->proc[sched_subframe].frame_tx, + subframe, + (phy_vars_eNB->transmission_mode[(uint8_t)UE_id]<7?0:phy_vars_eNB->transmission_mode[(uint8_t)UE_id]<7)), 0, subframe<<1); // for (sect_id=0;sect_idlte_eNB_common_vars.txdataF[0], + re_allocated = dlsch_modulation(phy_vars_eNB, + phy_vars_eNB->lte_eNB_common_vars.txdataF[0], AMP, subframe, - &phy_vars_eNB->lte_frame_parms, num_pdcch_symbols, phy_vars_eNB->dlsch_eNB_ra, - (LTE_eNB_DLSCH_t *)NULL); + (LTE_eNB_DLSCH_t *)NULL, + (int32_t **)NULL); + } #ifdef PHY_ABSTRACTION @@ -2394,7 +2402,10 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->rb_alloc, get_Qm(phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->mcs), phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->Nl, - num_pdcch_symbols,phy_vars_eNB->proc[sched_subframe].frame_tx,subframe), + num_pdcch_symbols, + phy_vars_eNB->proc[sched_subframe].frame_tx, + subframe, + (phy_vars_eNB->transmission_mode[(uint8_t)UE_id]<7?0:phy_vars_eNB->transmission_mode[(uint8_t)UE_id])), phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->nb_rb, phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->mcs, pmi2hex_2Ar1(phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->pmi_alloc), @@ -2413,7 +2424,10 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->rb_alloc, get_Qm(phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->mcs), phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->Nl, - num_pdcch_symbols,phy_vars_eNB->proc[sched_subframe].frame_tx,subframe), + num_pdcch_symbols, + phy_vars_eNB->proc[sched_subframe].frame_tx, + subframe, + (phy_vars_eNB->transmission_mode[(uint8_t)UE_id]<7?0:phy_vars_eNB->transmission_mode[(uint8_t)UE_id]<7)), phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->nb_rb, phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->mcs, pmi2hex_2Ar1(phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->pmi_alloc), @@ -2495,7 +2509,10 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->rb_alloc, get_Qm(phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->mcs), phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->Nl, - num_pdcch_symbols,phy_vars_eNB->proc[sched_subframe].frame_tx,subframe), + num_pdcch_symbols, + phy_vars_eNB->proc[sched_subframe].frame_tx, + subframe, + phy_vars_eNB->transmission_mode[(uint8_t)UE_id]), 0, subframe<<1); stop_meas(&phy_vars_eNB->dlsch_scrambling_stats); @@ -2510,13 +2527,14 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e // if (UE_id == 1) // LOG_I(PHY,"[MYEMOS] MCS_i %d\n", phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->harq_processes[harq_pid]->mcs); - re_allocated = dlsch_modulation(phy_vars_eNB->lte_eNB_common_vars.txdataF[0], + re_allocated = dlsch_modulation(phy_vars_eNB, + phy_vars_eNB->lte_eNB_common_vars.txdataF[0], AMP, subframe, - &phy_vars_eNB->lte_frame_parms, num_pdcch_symbols, phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0], - phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][1]); + phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][1], + (int32_t **)NULL); stop_meas(&phy_vars_eNB->dlsch_modulation_stats); } diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 6394c7dff6..7efee84b84 100755 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -138,7 +138,9 @@ void dump_dlsch(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t subframe,uint8_t get_Qm(phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->mcs), phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->Nl, phy_vars_ue->lte_ue_pdcch_vars[eNB_id]->num_pdcch_symbols, - phy_vars_ue->frame_rx,subframe); + phy_vars_ue->frame_rx, + subframe, + phy_vars_ue->transmission_mode[eNB_id]); write_output("rxsigF0.m","rxsF0", phy_vars_ue->lte_ue_common_vars.rxdataF[0],2*nsymb*phy_vars_ue->lte_frame_parms.ofdm_symbol_size,2,1); write_output("rxsigF0_ext.m","rxsF0_ext", phy_vars_ue->lte_ue_pdsch_vars[0]->rxdataF_ext[0],2*nsymb*phy_vars_ue->lte_frame_parms.ofdm_symbol_size,1,1); @@ -167,7 +169,9 @@ void dump_dlsch_SI(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t subframe) get_Qm(phy_vars_ue->dlsch_ue_SI[eNB_id]->harq_processes[0]->mcs), 1, phy_vars_ue->lte_ue_pdcch_vars[eNB_id]->num_pdcch_symbols, - phy_vars_ue->frame_rx,subframe); + phy_vars_ue->frame_rx, + subframe, + phy_vars_ue->transmission_mode[eNB_id]); LOG_D(PHY,"[UE %d] Dumping dlsch_SI : nb_rb %d, mcs %d, nb_rb %d, num_pdcch_symbols %d,G %d\n", phy_vars_ue->Mod_id, phy_vars_ue->dlsch_ue_SI[eNB_id]->harq_processes[0]->nb_rb, @@ -221,7 +225,9 @@ void dump_dlsch_ra(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t subframe) get_Qm(phy_vars_ue->dlsch_ue_ra[eNB_id]->harq_processes[0]->mcs), 1, phy_vars_ue->lte_ue_pdcch_vars[eNB_id]->num_pdcch_symbols, - phy_vars_ue->frame_rx,subframe); + phy_vars_ue->frame_rx, + subframe, + phy_vars_ue->transmission_mode[eNB_id]); LOG_D(PHY,"[UE %d] Dumping dlsch_ra : nb_rb %d, mcs %d, nb_rb %d, num_pdcch_symbols %d,G %d\n", phy_vars_ue->Mod_id, phy_vars_ue->dlsch_ue_ra[eNB_id]->harq_processes[0]->nb_rb, @@ -2625,7 +2631,9 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac get_Qm(phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->mcs), phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->Nl, phy_vars_ue->lte_ue_pdcch_vars[eNB_id]->num_pdcch_symbols, - frame_rx,subframe_prev); + frame_rx, + subframe_prev, + phy_vars_ue->transmission_mode[eNB_id]); start_meas(&phy_vars_ue->dlsch_unscrambling_stats); dlsch_unscrambling(&phy_vars_ue->lte_frame_parms, 0, @@ -2782,7 +2790,9 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac phy_vars_ue->dlsch_ue_SI[eNB_id]->harq_processes[0]->rb_alloc, get_Qm(phy_vars_ue->dlsch_ue_SI[eNB_id]->harq_processes[0]->mcs),1, phy_vars_ue->lte_ue_pdcch_vars[eNB_id]->num_pdcch_symbols, - frame_rx,subframe_prev); + frame_rx, + subframe_prev, + phy_vars_ue->transmission_mode[eNB_id]); #ifdef DEBUG_PHY_PROC LOG_D(PHY,"Decoding DLSCH_SI : rb_alloc %x : nb_rb %d G %d TBS %d, num_pdcch_sym %d\n",phy_vars_ue->dlsch_ue_SI[eNB_id]->harq_processes[0]->rb_alloc[0], @@ -2926,7 +2936,8 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac get_Qm(phy_vars_ue->dlsch_ue_ra[eNB_id]->harq_processes[0]->mcs),1, phy_vars_ue->lte_ue_pdcch_vars[eNB_id]->num_pdcch_symbols, frame_rx, - subframe_prev); + subframe_prev, + phy_vars_ue->transmission_mode[eNB_id]); #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[UE] decoding RA (subframe %d): G %d,rnti %x\n" ,subframe_prev, @@ -3301,7 +3312,9 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac get_Qm(phy_vars_ue->dlsch_ue_MCH[0]->harq_processes[0]->mcs), 1, 2, - (subframe_rx==9?-1:0)+frame_rx,subframe_rx); + (subframe_rx==9?-1:0)+frame_rx, + subframe_rx, + phy_vars_ue->transmission_mode[eNB_id]); dlsch_unscrambling(&phy_vars_ue->lte_frame_parms,1,phy_vars_ue->dlsch_ue_MCH[0], phy_vars_ue->dlsch_ue_MCH[0]->harq_processes[0]->G, diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 969e485b23..7a3b3bba1d 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -1,5 +1,5 @@ -/******************************************************************************* - OpenAirInterface +/****************************************************************************** + ipenAirInterface Copyright(c) 1999 - 2014 Eurecom OpenAirInterface is free software: you can redistribute it and/or modify @@ -107,8 +107,7 @@ void handler(int sig) exit(1); } -void lte_param_init(unsigned char N_tx, unsigned char N_rx,unsigned char transmission_mode,uint8_t extended_prefix_flag,uint8_t fdd_flag, uint16_t Nid_cell,uint8_t tdd_config,uint8_t N_RB_DL, - uint8_t osf,uint32_t perfect_ce) +void lte_param_init(unsigned char N_tx, unsigned char N_tx_phy, unsigned char N_rx,unsigned char transmission_mode,uint8_t extended_prefix_flag,uint8_t fdd_flag, uint16_t Nid_cell,uint8_t tdd_config,uint8_t N_RB_DL, uint8_t osf,uint32_t perfect_ce) { LTE_DL_FRAME_PARMS *lte_frame_parms; @@ -123,7 +122,8 @@ void lte_param_init(unsigned char N_tx, unsigned char N_rx,unsigned char transmi srand(0); randominit(0); - set_taus_seed(0); + //set_taus_seed(0); + set_taus_seed(1234); lte_frame_parms = &(PHY_vars_eNB->lte_frame_parms); @@ -142,7 +142,8 @@ void lte_param_init(unsigned char N_tx, unsigned char N_rx,unsigned char transmi // lte_frame_parms->Bsrs = 0; // lte_frame_parms->kTC = 0;44 // lte_frame_parms->n_RRC = 0; - lte_frame_parms->mode1_flag = (transmission_mode == 1)? 1 : 0; + //lte_frame_parms->mode1_flag = (transmission_mode == 1)? 1 : 0; + lte_frame_parms->mode1_flag = (transmission_mode == 1 || transmission_mode ==7)? 1 : 0; init_frame_parms(lte_frame_parms,osf); @@ -154,6 +155,11 @@ void lte_param_init(unsigned char N_tx, unsigned char N_rx,unsigned char transmi PHY_vars_UE->lte_frame_parms = *lte_frame_parms; PHY_vars_eNB->lte_frame_parms = *lte_frame_parms; + PHY_vars_eNB->transmission_mode[0] = transmission_mode; + PHY_vars_UE->transmission_mode[0] = transmission_mode; + //printf("lte_param_init: transmission mode = %d\n",PHY_vars_eNB->transmission_mode[0]); + PHY_vars_eNB->nb_antennas_tx_phy = N_tx_phy; + phy_init_lte_top(lte_frame_parms); dump_frame_parms(lte_frame_parms); @@ -166,12 +172,14 @@ void lte_param_init(unsigned char N_tx, unsigned char N_rx,unsigned char transmi phy_init_lte_ue(PHY_vars_UE,1,0); phy_init_lte_eNB(PHY_vars_eNB,0,0,0); + generate_pcfich_reg_mapping(&PHY_vars_UE->lte_frame_parms); generate_phich_reg_mapping(&PHY_vars_UE->lte_frame_parms); // DL power control init - if (transmission_mode == 1) { + //if (transmission_mode == 1) { + if (transmission_mode == 1 || transmission_mode ==7) { PHY_vars_eNB->pdsch_config_dedicated->p_a = dB0; // 4 = 0dB ((PHY_vars_eNB->lte_frame_parms).pdsch_config_common).p_b = 0; PHY_vars_UE->pdsch_config_dedicated->p_a = dB0; // 4 = 0dB @@ -200,7 +208,7 @@ uint64_t DLSCH_alloc_pdu_1[2]; #define CCCH_RB_ALLOC computeRIV(PHY_vars_eNB->lte_frame_parms.N_RB_UL,0,2) //#define DLSCH_RB_ALLOC 0x1fbf // igore DC component,RB13 //#define DLSCH_RB_ALLOC 0x0001 -void do_OFDM_mod_l(mod_sym_t **txdataF, int32_t **txdata, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms) +void do_OFDM_mod_l(mod_sym_t **txdataF, int32_t **txdata, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms, uint8_t nb_antennas_tx_phy) { int aa, slot_offset, slot_offset_F; @@ -208,7 +216,7 @@ void do_OFDM_mod_l(mod_sym_t **txdataF, int32_t **txdata, uint16_t next_slot, LT slot_offset_F = (next_slot)*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); slot_offset = (next_slot)*(frame_parms->samples_per_tti>>1); - for (aa=0; aanb_antennas_tx; aa++) { + for (aa=0; aaNcp == 1) @@ -234,7 +242,7 @@ int main(int argc, char **argv) { char c; - int k,i,aa,aarx,aatx; + int k,i,aa,aarx,aatx,re; int s,Kr,Kr_bytes; @@ -246,8 +254,9 @@ int main(int argc, char **argv) double forgetting_factor=0.0; //in [0,1] 0 means a new channel every time, 1 means keep the same channel double iqim=0.0; - uint8_t extended_prefix_flag=0,transmission_mode=1,n_tx=1,n_rx=2; + uint8_t extended_prefix_flag=0,transmission_mode=1,n_tx=1,n_rx=2,n_tx_phy=1; uint16_t Nid_cell=0; + int32_t **beamforming_weights; int eNB_id = 0, eNB_id_i = 1; unsigned char mcs1=0,mcs2=0,mcs_i=0,dual_stream_UE = 0,awgn_flag=0,round,dci_flag=0; @@ -285,7 +294,7 @@ int main(int argc, char **argv) char input_trch_val[16]; double channelx,channely; - // unsigned char pbch_pdu[6]; + unsigned char pbch_pdu[6]; DCI_ALLOC_t dci_alloc[8],dci_alloc_rx[8]; int num_common_dci=0,num_ue_spec_dci=0,num_dci=0; @@ -525,13 +534,20 @@ int main(int argc, char **argv) (transmission_mode!=2) && (transmission_mode!=3) && (transmission_mode!=5) && - (transmission_mode!=6)) { + (transmission_mode!=6) && + (transmission_mode!=7)) { msg("Unsupported transmission mode %d\n",transmission_mode); exit(-1); } - if (transmission_mode>1) { + if (transmission_mode>1 && transmission_mode<7) { n_tx = 2; + n_tx_phy = n_tx; + } + if (transmission_mode>=7){ + n_tx = 1; + n_tx_phy = 1; + n_rx = 1; } break; @@ -539,9 +555,13 @@ int main(int argc, char **argv) case 'y': n_tx=atoi(optarg); - if ((n_tx==0) || (n_tx>2)) { - msg("Unsupported number of tx antennas %d\n",n_tx); - exit(-1); + if (transmission_mode<7){ + n_tx_phy = n_tx; + + if ((n_tx==0) || ((n_tx>2))) { + msg("Unsupported number of tx antennas %d\n",n_tx); + exit(-1); + } } break; @@ -633,7 +653,7 @@ int main(int argc, char **argv) case 'h': default: - printf("%s -h(elp) -a(wgn on) -d(ci decoding on) -p(extended prefix on) -m mcs1 -M mcs2 -n n_frames -s snr0 -x transmission mode (1,2,5,6) -y TXant -z RXant -I trch_file\n",argv[0]); + printf("%s -h(elp) -a(wgn on) -d(ci decoding on) -p(extended prefix on) -m mcs1 -M mcs2 -n n_frames -s snr0 -x transmission mode (1,2,5,6,7) -y TXant -z RXant -I trch_file\n",argv[0]); printf("-h This message\n"); printf("-a Use AWGN channel and not multipath\n"); printf("-c Number of PDCCH symbols\n"); @@ -648,7 +668,7 @@ int main(int argc, char **argv) printf("-r ressource block allocation (see section 7.1.6.3 in 36.213\n"); printf("-g [A:M] Use 3GPP 25.814 SCM-A/B/C/D('A','B','C','D') or 36-101 EPA('E'), EVA ('F'),ETU('G') models (ignores delay spread and Ricean factor), Rayghleigh8 ('H'), Rayleigh1('I'), Rayleigh1_corr('J'), Rayleigh1_anticorr ('K'), Rice8('L'), Rice1('M')\n"); printf("-F forgetting factor (0 new channel every trial, 1 channel constant\n"); - printf("-x Transmission mode (1,2,6 for the moment)\n"); + printf("-x Transmission mode (1,2,6,7 for the moment)\n"); printf("-y Number of TX antennas used in eNB\n"); printf("-z Number of RX antennas used in UE\n"); printf("-t MCS of interfering UE\n"); @@ -697,8 +717,8 @@ int main(int argc, char **argv) NB_RB=conv_nprb(0,DLSCH_RB_ALLOC,N_RB_DL); - if ((transmission_mode > 1) && (n_tx != 2)) - printf("n_tx must be >1 for transmission_mode %d\n",transmission_mode); + if ((transmission_mode > 1) && (n_tx_phy == 1)) + printf("n_tx_phy must be >1 for transmission_mode %d\n",transmission_mode); #ifdef XFORMS fl_initialize (&argc, argv, NULL, 0, 0); @@ -720,7 +740,19 @@ int main(int argc, char **argv) printf("dual_stream_UE=%d\n", dual_stream_UE); } - lte_param_init(n_tx,n_rx,transmission_mode,extended_prefix_flag,fdd_flag,Nid_cell,tdd_config,N_RB_DL,osf,perfect_ce); + + lte_param_init(n_tx,n_tx_phy,n_rx,transmission_mode,extended_prefix_flag,fdd_flag,Nid_cell,tdd_config,N_RB_DL,osf,perfect_ce); + + if (transmission_mode==7){ + lte_gold_ue_spec_port5(PHY_vars_eNB->lte_gold_uespec_port5_table[0],Nid_cell,n_rnti); + lte_gold_ue_spec_port5(PHY_vars_UE->lte_gold_uespec_port5_table,Nid_cell,n_rnti); + beamforming_weights = (int32_t **)malloc(12*N_RB_DL*sizeof(int32_t*)); + for(re=0;re<12*N_RB_DL;re++){ + beamforming_weights[re]=(int32_t *)malloc(n_tx_phy*sizeof(int32_t)); + for(aa=0;aan_connected_eNB; @@ -728,7 +760,7 @@ int main(int argc, char **argv) printf("Setting mcs2 = %d\n",mcs2); printf("NPRB = %d\n",NB_RB); printf("n_frames = %d\n",n_frames); - printf("Transmission mode %d with %dx%d antenna configuration, Extended Prefix %d\n",transmission_mode,n_tx,n_rx,extended_prefix_flag); + printf("Transmission mode %d with %dx%d antenna configuration, Extended Prefix %d\n",transmission_mode,n_tx_phy,n_rx,extended_prefix_flag); snr1 = snr0+snr_int; printf("SNR0 %f, SNR1 %f\n",snr0,snr1); @@ -745,8 +777,8 @@ int main(int argc, char **argv) frame_parms = &PHY_vars_eNB->lte_frame_parms; - s_re = malloc(2*sizeof(double*)); - s_im = malloc(2*sizeof(double*)); + s_re = malloc(n_tx_phy*sizeof(double*)); + s_im = malloc(n_tx_phy*sizeof(double*)); r_re = malloc(2*sizeof(double*)); r_im = malloc(2*sizeof(double*)); // r_re0 = malloc(2*sizeof(double*)); @@ -883,9 +915,12 @@ int main(int argc, char **argv) } */ - for (i=0; i<2; i++) { + for (i=0; ilte_frame_parms.frame_type == TDD) { @@ -1157,6 +1193,9 @@ int main(int argc, char **argv) P_RNTI, PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single); + if(transmission_mode==7) + PHY_vars_eNB->dlsch_eNB[0][0]->harq_processes[0]->mimo_mode = TM7; //Xiwen: to check about harq_pid + num_dci++; num_ue_spec_dci++; } else { @@ -1300,7 +1339,7 @@ int main(int argc, char **argv) num_dci++; } - + break; case 3: @@ -2027,13 +2066,15 @@ int main(int argc, char **argv) get_Qm(PHY_vars_eNB->dlsch_eNB[0][0]->harq_processes[0]->mcs), PHY_vars_eNB->dlsch_eNB[0][0]->harq_processes[0]->Nl, num_pdcch_symbols, - 0,subframe); + 0, + subframe, + (transmission_mode<7?0:transmission_mode)); uncoded_ber_bit = (short*) malloc(sizeof(short)*coded_bits_per_codeword); printf("uncoded_ber_bit=%p\n",uncoded_ber_bit); snr_step = input_snr_step; - PHY_vars_UE->high_speed_flag = 1; + PHY_vars_UE->high_speed_flag = 0; //1 PHY_vars_UE->ch_est_alpha=0; for (ch_realization=0; ch_realizationdlsch_ue[0][0]->max_turbo_iterations+1; while ((round < num_rounds) && (ret > PHY_vars_UE->dlsch_ue[0][0]->max_turbo_iterations)) { - // printf("Trial %d, round %d\n",trials,round); + printf("Trial %d, round %d\n",trials,round); round_trials[round]++; - if(transmission_mode>=5) + if(transmission_mode>=5&&transmission_mode<7) pmi_feedback=1; else pmi_feedback=0; @@ -2136,7 +2177,7 @@ int main(int argc, char **argv) PMI_FEEDBACK: - // printf("Trial %d : Round %d, pmi_feedback %d \n",trials,round,pmi_feedback); + printf("Trial %d : Round %d, pmi_feedback %d \n",trials,round,pmi_feedback); for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { memset(&PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id][aa][0],0,FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t)); } @@ -2158,6 +2199,7 @@ PMI_FEEDBACK: switch (transmission_mode) { case 1: case 2: + case 7: switch (PHY_vars_eNB->lte_frame_parms.N_RB_DL) { case 6: ((DCI1_1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[0])->ndi = trials&1; @@ -2228,11 +2270,13 @@ PMI_FEEDBACK: DLSCH_alloc_pdu2_1E[0].rv = 0; memcpy(&dci_alloc[0].dci_pdu[0],&DLSCH_alloc_pdu2_1E[0],sizeof(DCI1E_5MHz_2A_M10PRB_TDD_t)); break; + } } else { // FDD switch (transmission_mode) { case 1: case 2: + case 7: switch (PHY_vars_eNB->lte_frame_parms.N_RB_DL) { case 6: ((DCI1_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[0])->ndi = trials&1; @@ -2260,7 +2304,6 @@ PMI_FEEDBACK: } break; - case 3: switch (PHY_vars_eNB->lte_frame_parms.N_RB_DL) { case 6: @@ -2315,6 +2358,7 @@ PMI_FEEDBACK: switch (transmission_mode) { case 1: case 2: + case 7: switch (PHY_vars_eNB->lte_frame_parms.N_RB_DL) { case 6: ((DCI1_1_5MHz_TDD_t *)&DLSCH_alloc_pdu_1[0])->ndi = trials&1; @@ -2422,6 +2466,7 @@ PMI_FEEDBACK: switch (transmission_mode) { case 1: case 2: + case 7: switch (PHY_vars_eNB->lte_frame_parms.N_RB_DL) { case 6: ((DCI1_1_5MHz_FDD_t *)&DLSCH_alloc_pdu_1[0])->ndi = trials&1; @@ -2551,7 +2596,9 @@ PMI_FEEDBACK: get_Qm(PHY_vars_eNB->dlsch_eNB[k][cw]->harq_processes[0]->mcs), PHY_vars_eNB->dlsch_eNB[k][cw]->harq_processes[0]->Nl, num_pdcch_symbols, - 0,subframe); + 0, + subframe, + (transmission_mode<7?0:transmission_mode)); #ifdef TBS_FIX // This is for MESH operation!!! tbs = (double)3*TBStable[get_I_TBS(PHY_vars_eNB->dlsch_eNB[k][cw]->harq_processes[0]->mcs)][PHY_vars_eNB->dlsch_eNB[k][cw]->nb_rb-1]/4; @@ -2596,8 +2643,7 @@ PMI_FEEDBACK: 0,subframe, &PHY_vars_eNB->dlsch_rate_matching_stats, &PHY_vars_eNB->dlsch_turbo_encoding_stats, - &PHY_vars_eNB->dlsch_interleaving_stats - )<0) + &PHY_vars_eNB->dlsch_interleaving_stats)<0) exit(-1); /* @@ -2640,15 +2686,16 @@ PMI_FEEDBACK: } } } - + start_meas(&PHY_vars_eNB->dlsch_modulation_stats); - re_allocated = dlsch_modulation(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], + re_allocated = dlsch_modulation(PHY_vars_eNB, + PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], AMP, subframe, - &PHY_vars_eNB->lte_frame_parms, num_pdcch_symbols, PHY_vars_eNB->dlsch_eNB[k][0], - PHY_vars_eNB->dlsch_eNB[k][1]); + PHY_vars_eNB->dlsch_eNB[k][1], + beamforming_weights); stop_meas(&PHY_vars_eNB->dlsch_modulation_stats); /* if (trials==0 && round==0) @@ -2661,18 +2708,149 @@ PMI_FEEDBACK: PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], AMP, LTE_NUMBER_OF_SUBFRAMES_PER_FRAME); +/* + //PSS/SSS + if (PHY_vars_eNB->lte_frame_parms.frame_type == FDD) { + generate_pss(PHY_vars_eNB->lte_eNB_common_vars.txdataF[0], + AMP, + &PHY_vars_eNB->lte_frame_parms, + (PHY_vars_eNB->lte_frame_parms.Ncp==NORMAL) ? 6 : 5, + 0); + generate_sss(PHY_vars_eNB->lte_eNB_common_vars.txdataF[0], + AMP, + &PHY_vars_eNB->lte_frame_parms, + (PHY_vars_eNB->lte_frame_parms.Ncp==NORMAL) ? 5 : 4, + 0); + generate_pss(PHY_vars_eNB->lte_eNB_common_vars.txdataF[0], + AMP, + &PHY_vars_eNB->lte_frame_parms, + (PHY_vars_eNB->lte_frame_parms.Ncp==NORMAL) ? 6 : 5, + 10); + generate_sss(PHY_vars_eNB->lte_eNB_common_vars.txdataF[0], + AMP, + &PHY_vars_eNB->lte_frame_parms, + (PHY_vars_eNB->lte_frame_parms.Ncp==NORMAL) ? 5 : 4, + 10); + } + else if (PHY_vars_eNB->lte_frame_parms.frame_type == TDD) { + generate_sss(PHY_vars_eNB->lte_eNB_common_vars.txdataF[0], + AMP, + &PHY_vars_eNB->lte_frame_parms, + (PHY_vars_eNB->lte_frame_parms.Ncp==NORMAL) ? 6 : 5, + 1); + generate_pss(PHY_vars_eNB->lte_eNB_common_vars.txdataF[0], + AMP, + &PHY_vars_eNB->lte_frame_parms, + 2, + 2); + generate_sss(PHY_vars_eNB->lte_eNB_common_vars.txdataF[0], + AMP, + &PHY_vars_eNB->lte_frame_parms, + (PHY_vars_eNB->lte_frame_parms.Ncp==NORMAL) ? 6 : 5, + 11); + generate_pss(PHY_vars_eNB->lte_eNB_common_vars.txdataF[0], + AMP, + &PHY_vars_eNB->lte_frame_parms, + 2, + 12); + } + + //PBCH + pbch_pdu[2] = 0; + + // FIXME setting pbch_pdu[2] to zero makes the switch statement easier: remove all the or-operators + switch (PHY_vars_eNB->lte_frame_parms.N_RB_DL) { + case 6: + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (0<<5); + break; + + case 15: + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (1<<5); + break; + + case 25: + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (2<<5); + break; + + case 50: + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (3<<5); + break; + + case 75: + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (4<<5); + break; + + case 100: + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (5<<5); + break; + + default: + // FIXME if we get here, this should be flagged as an error, right? + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (2<<5); + break; + } + + pbch_pdu[2] = (pbch_pdu[2]&0xef) | + ((PHY_vars_eNB->lte_frame_parms.phich_config_common.phich_duration << 4)&0x10); + + switch (PHY_vars_eNB->lte_frame_parms.phich_config_common.phich_resource) { + case oneSixth: + pbch_pdu[2] = (pbch_pdu[2]&0xf3) | (0<<2); + break; + + case half: + pbch_pdu[2] = (pbch_pdu[2]&0xf3) | (1<<2); + break; + + case one: + pbch_pdu[2] = (pbch_pdu[2]&0xf3) | (2<<2); + break; + + case two: + pbch_pdu[2] = (pbch_pdu[2]&0xf3) | (3<<2); + break; + + default: + // unreachable + break; + + + pbch_pdu[2] = (pbch_pdu[2]&0xfc) | ((0>>8)&0x3); + pbch_pdu[1] = 0&0xfc; + pbch_pdu[0] = 0; + } + + generate_pbch(&PHY_vars_eNB->lte_eNB_pbch, + PHY_vars_eNB->lte_eNB_common_vars.txdataF[0], + AMP, + &PHY_vars_eNB->lte_frame_parms, + pbch_pdu, + 0&3); +*/ start_meas(&PHY_vars_eNB->ofdm_mod_stats); +/* + for(i=0;i<20;i++){ + + do_OFDM_mod_l(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], + PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id], + i, + &PHY_vars_eNB->lte_frame_parms, + PHY_vars_eNB->nb_antennas_tx_phy); + } +*/ do_OFDM_mod_l(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id], (subframe*2), - &PHY_vars_eNB->lte_frame_parms); + &PHY_vars_eNB->lte_frame_parms, + PHY_vars_eNB->nb_antennas_tx_phy); do_OFDM_mod_l(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id], (subframe*2)+1, - &PHY_vars_eNB->lte_frame_parms); + &PHY_vars_eNB->lte_frame_parms, + PHY_vars_eNB->nb_antennas_tx_phy); stop_meas(&PHY_vars_eNB->ofdm_mod_stats); stop_meas(&PHY_vars_eNB->phy_proc_tx); @@ -2680,20 +2858,21 @@ PMI_FEEDBACK: do_OFDM_mod_l(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id], (subframe*2)+2, - &PHY_vars_eNB->lte_frame_parms); + &PHY_vars_eNB->lte_frame_parms, + PHY_vars_eNB->nb_antennas_tx_phy); if (n_frames==1) { write_output("txsigF0.m","txsF0", &PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id][0][subframe*nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size], nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size,1,1); - if (PHY_vars_eNB->lte_frame_parms.nb_antennas_tx>1) + if (PHY_vars_eNB->nb_antennas_tx_phy>1)// to be updated write_output("txsigF1.m","txsF1", &PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id][1][subframe*nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size], nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size,1,1); - } + } tx_lev = 0; - for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { + for (aa=0; aanb_antennas_tx_phy; aa++) { tx_lev += signal_energy(&PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa] [subframe*PHY_vars_eNB->lte_frame_parms.samples_per_tti], PHY_vars_eNB->lte_frame_parms.samples_per_tti); @@ -2703,9 +2882,8 @@ PMI_FEEDBACK: if (n_frames==1) { printf("tx_lev = %d (%d dB)\n",tx_lev,tx_lev_dB); - write_output("txsig0.m","txs0", &PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][0][subframe* PHY_vars_eNB->lte_frame_parms.samples_per_tti], - - PHY_vars_eNB->lte_frame_parms.samples_per_tti,1,1); + write_output("txsig0.m","txs0", &PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][0][subframe*PHY_vars_eNB->lte_frame_parms.samples_per_tti],PHY_vars_eNB->lte_frame_parms.samples_per_tti,1,1); + // write_output("txsig0.m","txs0",&PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][0][0*PHY_vars_eNB->lte_frame_parms.samples_per_tti],PHY_vars_eNB->lte_frame_parms.samples_per_tti*10,1,1); } } @@ -2736,7 +2914,7 @@ PMI_FEEDBACK: // printf("Copying tx ..., nsymb %d (n_tx %d), awgn %d\n",nsymb,PHY_vars_eNB->lte_frame_parms.nb_antennas_tx,awgn_flag); for (i=0; i<2*frame_parms->samples_per_tti; i++) { - for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { + for (aa=0; aanb_antennas_tx_phy; aa++) { if (awgn_flag == 0) { s_re[aa][i] = ((double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) + (i<<1)]); s_im[aa][i] = ((double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)+1]); @@ -2745,6 +2923,7 @@ PMI_FEEDBACK: if (aa==0) { r_re[aarx][i] = ((double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)]); r_im[aarx][i] = ((double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)+1]); + //printf("r[%d][%d]=> %f, %f\n",aarx,i,r_re[aarx][i],r_im[aarx][i]); } else { r_re[aarx][i] += ((double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)]); r_im[aarx][i] += ((double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)+1]); @@ -2837,14 +3016,18 @@ PMI_FEEDBACK: for (i=0; i<2*frame_parms->samples_per_tti; i++) { for (aa=0; aalte_frame_parms.nb_antennas_rx; aa++) { - //printf("s_re[0][%d]=> %f , r_re[0][%d]=> %f\n",i,s_re[aa][i],i,r_re[aa][i]); - ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i] = + // printf("s_re[0][%d]=> %f , r_re[0][%d]=> %f\n",i,s_re[aa][i],i,r_re[aa][i]); + /*((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i] = (short) (r_re[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i+1] = - (short) (r_im[aa][i] + (iqim*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); + (short) (r_im[aa][i] + (iqim*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0));*/ + ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i] = (short) (r_re[aa][i]); + ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i+1] = (short) (r_im[aa][i] + (iqim*r_re[aa][i])); + //printf("rxdata[%d][%d]=> %d, %d\n",aa,subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti+i,r_re[aa][i],r_im[aa][i]); } } + // lte_sync_time_init(PHY_vars_eNB->lte_frame_parms,lte_ue_common_vars); // lte_sync_time(lte_ue_common_vars->rxdata, PHY_vars_eNB->lte_frame_parms); // lte_sync_time_free(); @@ -2888,7 +3071,7 @@ PMI_FEEDBACK: for (Ns=(2*subframe); Ns<((2*subframe)+3); Ns++) { for (l=0; lofdm_demod_stats); + //write_output("rxsigF0.m","rxsF0", &PHY_vars_UE->lte_ue_common_vars.rxdataF[0][0],PHY_vars_UE->lte_frame_parms.ofdm_symbol_size*nsymb,1,1); if (PHY_vars_UE->perfect_ce==1) { if (awgn_flag==0) { @@ -3045,7 +3229,12 @@ PMI_FEEDBACK: get_Qm(PHY_vars_UE->dlsch_ue[0][0]->harq_processes[PHY_vars_UE->dlsch_ue[0][0]->current_harq_pid]->mcs), PHY_vars_UE->dlsch_ue[0][0]->harq_processes[PHY_vars_UE->dlsch_ue[0][0]->current_harq_pid]->Nl, PHY_vars_UE->lte_ue_pdcch_vars[0]->num_pdcch_symbols, - 0,subframe); + 0, + subframe, + (transmission_mode<7?0:transmission_mode)); + if (transmission_mode==7 && common_flag==0) + PHY_vars_UE->dlsch_ue[0][0]->harq_processes[0]->mimo_mode = TM7; + /* rate = (double)dlsch_tbs25[get_I_TBS(PHY_vars_UE->dlsch_ue[0][0]->harq_processes[PHY_vars_UE->dlsch_ue[0][0]->current_harq_pid]->mcs)][PHY_vars_UE->dlsch_ue[0][0]->nb_rb-1]/(coded_bits_per_codeword); rate*=get_Qm(PHY_vars_UE->dlsch_ue[0][0]->harq_processes[PHY_vars_UE->dlsch_ue[0][0]->current_harq_pid]->mcs); @@ -3084,6 +3273,7 @@ PMI_FEEDBACK: switch (transmission_mode) { case 1: case 2: + case 7: generate_ue_dlsch_params_from_dci(0, &DLSCH_alloc_pdu_1[0], (common_flag==0)? C_RNTI : SI_RNTI, @@ -3094,6 +3284,8 @@ PMI_FEEDBACK: SI_RNTI, 0, P_RNTI); + if(transmission_mode==7 && common_flag==0) + PHY_vars_UE->dlsch_ue[0][0]->harq_processes[0]->mimo_mode = TM7; break; case 3: @@ -3210,6 +3402,7 @@ PMI_FEEDBACK: for (m=pilot3; mlte_frame_parms.symbols_per_tti; m++) { + //printf("m=%d\n",m); if (rx_pdsch(PHY_vars_UE, PDSCH, eNB_id, @@ -3228,6 +3421,7 @@ PMI_FEEDBACK: stop_meas(&PHY_vars_UE->dlsch_llr_stats); } + if (test_perf ==0 ) { if ((n_frames==1) && (Ns==(2+(2*subframe))) && (l==0)) { write_output("ch0.m","ch0",eNB2UE[0]->ch[0],eNB2UE[0]->channel_length,1,8); @@ -3236,7 +3430,9 @@ PMI_FEEDBACK: write_output("ch1.m","ch1",eNB2UE[0]->ch[PHY_vars_eNB->lte_frame_parms.nb_antennas_rx],eNB2UE[0]->channel_length,1,8); //common vars - write_output("rxsig0.m","rxs0", &PHY_vars_UE->lte_ue_common_vars.rxdata[0][0],10*PHY_vars_UE->lte_frame_parms.samples_per_tti,1,1); + //write_output("rxsig0.m","rxs0", &PHY_vars_UE->lte_ue_common_vars.rxdata[0][0],10*PHY_vars_UE->lte_frame_parms.samples_per_tti,1,1); + write_output("rxsig0.m","rxs0", &PHY_vars_UE->lte_ue_common_vars.rxdata[0][subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti],PHY_vars_UE->lte_frame_parms.samples_per_tti,1,1); + //write_output("rxsigF0.m","rxsF0", &PHY_vars_UE->lte_ue_common_vars.rxdataF[0][subframe*nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size],PHY_vars_UE->lte_frame_parms.ofdm_symbol_size*nsymb,1,1); write_output("rxsigF0.m","rxsF0", &PHY_vars_UE->lte_ue_common_vars.rxdataF[0][0],PHY_vars_UE->lte_frame_parms.ofdm_symbol_size*nsymb,1,1); if (PHY_vars_UE->lte_frame_parms.nb_antennas_rx>1) { @@ -3284,7 +3480,7 @@ PMI_FEEDBACK: //saving PMI in case of Transmission Mode > 5 if(abstx) { - if (trials==0 && round==0 && transmission_mode>=5) { + if (trials==0 && round==0 && transmission_mode>=5 && transmission_mode<7) { for (iii=0; iiilte_ue_pdsch_vars[eNB_id]->pmi_ext[iii]),(PHY_vars_UE->lte_ue_pdsch_vars[eNB_id_i]->pmi_ext[iii])); fprintf(csv_fd,"%x,%x,",(PHY_vars_UE->lte_ue_pdsch_vars[eNB_id]->pmi_ext[iii]),(PHY_vars_UE->lte_ue_pdsch_vars[eNB_id]->pmi_ext[iii])); @@ -3301,7 +3497,9 @@ PMI_FEEDBACK: get_Qm(PHY_vars_eNB->dlsch_eNB[0][cw]->harq_processes[0]->mcs), PHY_vars_eNB->dlsch_eNB[0][cw]->harq_processes[0]->Nl, num_pdcch_symbols, - 0,subframe); + 0, + subframe, + (transmission_mode<7?0:transmission_mode)); PHY_vars_UE->dlsch_ue[0][cw]->harq_processes[PHY_vars_UE->dlsch_ue[0][cw]->current_harq_pid]->G = coded_bits_per_codeword; @@ -3415,7 +3613,7 @@ PMI_FEEDBACK: iter_trials++; if (n_frames==1) { - //if ((n_frames==1) || (SNR>=30)) { + //if ((n_frames==1) || (SNR>=30)) printf("DLSCH errors found (round %d), uncoded ber %f\n",round,uncoded_ber); for (s=0; sdlsch_ue[0][0]->harq_processes[0]->C; s++) { @@ -4054,9 +4252,12 @@ PMI_FEEDBACK: printf("Freeing channel I/O\n"); - for (i=0; i<2; i++) { + for (i=0; idlsch_ue_MCH[0]->harq_processes[0]->rb_alloc, get_Qm(PHY_vars_UE->dlsch_ue_MCH[0]->harq_processes[0]->mcs), 1,2, - PHY_vars_UE->frame_tx,subframe); + PHY_vars_UE->frame_tx,subframe,0); dlsch_unscrambling(&PHY_vars_UE->lte_frame_parms,1,PHY_vars_UE->dlsch_ue_MCH[0], PHY_vars_UE->dlsch_ue_MCH[0]->harq_processes[0]->G, PHY_vars_UE->lte_ue_pdsch_vars_MCH[0]->llr[0],0,subframe<<1); diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m index ad33d26123..0ebf4a0a87 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m @@ -6,7 +6,7 @@ rxgain=0; txgain=0; eNB_flag = 0; card = 0; -active_rf = [1 1 1 1]; +active_rf = [1 0 0 0]; autocal = [1 1 1 1]; resampling_factor = [2 2 2 2]; limeparms; @@ -38,14 +38,14 @@ rffe_band = B19G_TDD*[1 1 1 1]; oarf_config_exmimo(card, freq_rx,freq_tx,tdd_config,syncmode,rxgain,txgain,eNB_flag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor); %oarf_config_exmimo(1, freq_rx,freq_tx,tdd_config,syncmode,rxgain,txgain,eNB_flag,rf_mode,rf_rxdc,rf_local,rf_vcocal,rffe_rxg_low,rffe_rxg_final,rffe_band,autocal,resampling_factor); -amp = pow2(14)-1; +amp = pow2(10)-1; n_bit = 16; length = 307200/pow2(resampling_factor(1)); s = zeros(length,4); -select = 1; +select = 7; switch(select) @@ -73,7 +73,8 @@ case 3 case 4 pss0_f0=[0,0,0,0,0,0,0,0,0,0,32767,0,-26120,-19785,11971,-30502,-24020,-22288,32117,6492,31311,9658,-16384,-28378,25100,-21063,-7292,-31946,20429,25618,14948,29158,11971,-30502,31311,9658,25100,-21063,-16384,28377,-24020,22287,32117,6492,-7292,31945,20429,25618,-26120,-19785,-16384,-28378,-16384,28377,-26120,-19785,-32402,4883,31311,-9659,32117,6492,-7292,-31946,32767,-1,25100,-21063,-24020,22287,-32402,4883,-32402,4883,-24020,22287,25100,-21063,32767,-1,-7292,-31946,32117,6492,31311,-9659,-32402,4883,-26120,-19785,-16384,28377,-16384,-28378,-26120,-19785,20429,25618,-7292,31945,32117,6492,-24020,22287,-16384,28377,25100,-21063,31311,9658,11971,-30502,14948,29158,20429,25618,-7292,-31946,25100,-21063,-16384,-28378,31311,9658,32117,6492,-24020,-22288,11971,-30502,-26120,-19785,32767,0,0,0,0,0,0,0,0,0,0,0]; - pss0_f = pss0_f0(1:2:length(pss0_f0)) + sqrt(-1)*pss0_f0(2:2:length(pss0_f0)); + %pss0_f = pss0_f0(1:2:length(pss0_f0)) + sqrt(-1)*pss0_f0(2:2:length(pss0_f0)); + pss0_f = pss0_f0(1:2:size(pss0_f0,2)) + sqrt(-1)*pss0_f0(2:2:size(pss0_f0,2)); pss0_f = [0 pss0_f(37:72) zeros(1,512-73) pss0_f(1:36)]; pss0_t = ifft(pss0_f); @@ -84,10 +85,15 @@ case 4 pss0_t_fp_re = floor(real(8192*pss0_t/pss0_max)); pss0_t_fp_im = floor(imag(8192*pss0_t/pss0_max)); + %keyboard; s(38400+(1:length(pss0_t_fp_re)),1) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im); s(38400+(1:length(pss0_t_fp_re)),2) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im); s(38400+(1:length(pss0_t_fp_re)),3) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im); s(38400+(1:length(pss0_t_fp_re)),4) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im); + %s(38400+(1:size(pss0_t_fp_re,2)),1) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im); + %s(38400+(1:size(pss0_t_fp_re,2)),2) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im); + %s(38400+(1:size(pss0_t_fp_re,2)),3) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im); + %s(38400+(1:size(pss0_t_fp_re,2)),4) = 2*floor(pss0_t_fp_re) + 2*sqrt(-1)*floor(pss0_t_fp_im); case 5 x=1:length; @@ -108,7 +114,9 @@ case 6 s(:,1) = OFDM_TX_FRAME(num_carriers,num_zeros,prefix_length,num_symbols_frame,preamble_length); s(:,1) = floor(amp*(s(:,1)./max([real(s(:,1)); imag(s(:,1))]))); - + +case 7 + s(:,1) = floor(txs0); otherwise error('unknown case') From cf4a005e320c0a6e140d9a24d04b47f76a5f44e4 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Wed, 9 Sep 2015 09:53:59 +0200 Subject: [PATCH 002/413] Beamforming channel estimation based on UE specific reference signal --- openair1/PHY/INIT/lte_init.c | 4 +- .../LTE_ESTIMATION/bf_freq_domain_filters.m | 40 +- openair1/PHY/LTE_ESTIMATION/defs.h | 1 - openair1/PHY/LTE_ESTIMATION/filt12_32.h | 14 + .../lte_dl_bf_channel_estimation.c | 688 +++++++++++++++++- openair1/PHY/LTE_REFSIG/defs.h | 8 +- openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c | 125 ++-- openair1/PHY/LTE_REFSIG/lte_dl_uespec.c | 0 openair1/PHY/LTE_REFSIG/lte_gold.c | 54 +- .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 83 ++- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 66 +- openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c | 4 +- openair1/PHY/LTE_TRANSPORT/proto.h | 2 + openair1/PHY/MODULATION/slot_fep.c | 24 +- openair1/PHY/defs.h | 4 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 26 +- 16 files changed, 918 insertions(+), 225 deletions(-) delete mode 100644 openair1/PHY/LTE_REFSIG/lte_dl_uespec.c diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 51c4939c56..512b5192c0 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -948,8 +948,8 @@ void phy_init_lte_ue__PDSCH( LTE_UE_PDSCH* const pdsch, const LTE_DL_FRAME_PARMS pdsch->rxdataF_uespec_pilots[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * frame_parms->N_RB_DL*12); pdsch->rxdataF_comp0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); pdsch->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - pdsch->dl_bf_ch_estimates[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); - pdsch->dl_bf_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t)*frame_parms->symbols_per_tti*(frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH) ); + pdsch->dl_bf_ch_estimates[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * frame_parms->ofdm_symbol_size*7*2); + pdsch->dl_bf_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); pdsch->dl_ch_rho_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); pdsch->dl_ch_rho2_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); pdsch->dl_ch_mag0[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); diff --git a/openair1/PHY/LTE_ESTIMATION/bf_freq_domain_filters.m b/openair1/PHY/LTE_ESTIMATION/bf_freq_domain_filters.m index 557c54dddd..e0c0a0f18f 100644 --- a/openair1/PHY/LTE_ESTIMATION/bf_freq_domain_filters.m +++ b/openair1/PHY/LTE_ESTIMATION/bf_freq_domain_filters.m @@ -1,57 +1,57 @@ -filter_length = 12; +filt_len = 16; F = -3/4:1/4:7/4; -F_l = zeros(8,12); -F_r = zeros(8,12); -F_m = zeros(8,12); +F_l = zeros(8,filt_len); +F_r = zeros(8,filt_len); +F_m = zeros(8,filt_len); F2 =-3/5:1/5:8/5; for i=0:3 - F_l(i+1,:) = floor(16384*[F(8+i:-1:4) zeros(1,7-i)]); - F_r(i+1,:) = floor(16384*[zeros(1,4+i) F(4:end-i)]); - F_m(i+1,:) = floor(16384*[F(4-i:8) F(7:-1:1+i)]); + F_l(i+1,:) = floor(16384*[F(8+i:-1:4) zeros(1,7-i) zeros(1,4)]); + F_r(i+1,:) = floor(16384*[zeros(1,4+i) F(4:end-i) zeros(1,4)]); + F_m(i+1,:) = floor(16384*[F(4-i:8) F(7:-1:1+i) zeros(1,4)]); end for i=0:1 - F_l(i+5,:) = floor(16384*[F(8:-1:4-i) zeros(1,7-i)]); - F_r(i+5,:) = floor(16384*[zeros(1,5+i) F2(5+i) F2(7:end-i)]); - F_m(i+5,:) = floor(16384*[F(4-i:8) F2(8-i) F2(6:-1:1+i)]); + F_l(i+5,:) = floor(16384*[F(8:-1:4-i) zeros(1,7-i) zeros(1,4)]); + F_r(i+5,:) = floor(16384*[zeros(1,5+i) F2(5+i) F2(7:end-i) zeros(1,4)]); + F_m(i+5,:) = floor(16384*[F(4-i:8) F2(8-i) F2(6:-1:1+i) zeros(1,4)]); end for i=2:3 - F_l(i+5,:) = floor(16384*[F2(end:-1:7) F2(8-i) zeros(1,5)]); - F_r(i+5,:) = floor(16384*[zeros(1,4+i) F(4:end-i)]); - F_m(i+5,:) = floor(16384*[F2(4-i:6) F2(4+i) F(8:-1:1+i)]); + F_l(i+5,:) = floor(16384*[F2(end:-1:7) F2(8-i) zeros(1,5) zeros(1,4)]); + F_r(i+5,:) = floor(16384*[zeros(1,4+i) F(4:end-i) zeros(1,4)]); + F_m(i+5,:) = floor(16384*[F2(4-i:6) F2(4+i) F(8:-1:1+i) zeros(1,4)]); end -fd = fopen("filt12_32.h","w"); +fd = fopen("filt16_32.h","w"); for i=0:3 - fprintf(fd,"short filt12_l%d[12] = {\n",i); + fprintf(fd,"short filt%d_l%d[%d] = {\n",filt_len,i,filt_len); fprintf(fd,"%d,",F_l(i+1,1:end-1)); fprintf(fd,"%d};\n\n",F_l(i+1,end)); - fprintf(fd,"short filt12_r%d[12] = {\n",i); + fprintf(fd,"short filt%d_r%d[%d] = {\n",filt_len,i,filt_len); fprintf(fd,"%d,",F_r(i+1,1:end-1)); fprintf(fd,"%d};\n\n",F_r(i+1,end)); - fprintf(fd,"short filt12_m%d[12] = {\n",i); + fprintf(fd,"short filt%d_m%d[%d] = {\n",filt_len,i,filt_len); fprintf(fd,"%d,",F_m(i+1,1:end-1)); fprintf(fd,"%d};\n\n",F_m(i+1,end)); end for i=0:3 - fprintf(fd,"short filt12_l%d_dc[12] = {\n",i); + fprintf(fd,"short filt%d_l%d_dc[%d] = {\n",filt_len,i,filt_len); fprintf(fd,"%d,",F_l(i+5,1:end-1)); fprintf(fd,"%d};\n\n",F_l(i+5,end)); - fprintf(fd,"short filt12_r%d_dc[12] = {\n",i); + fprintf(fd,"short filt%d_r%d_dc[%d] = {\n",filt_len,i,filt_len); fprintf(fd,"%d,",F_r(i+5,1:end-1)); fprintf(fd,"%d};\n\n",F_r(i+5,end)); - fprintf(fd,"short filt12_m%d_dc[12] = {\n",i); + fprintf(fd,"short filt%d_m%d_dc[%d] = {\n",filt_len,i,filt_len); fprintf(fd,"%d,",F_m(i+5,1:end-1)); fprintf(fd,"%d};\n\n",F_m(i+5,end)); end diff --git a/openair1/PHY/LTE_ESTIMATION/defs.h b/openair1/PHY/LTE_ESTIMATION/defs.h index 4763602525..1a747c1cc8 100644 --- a/openair1/PHY/LTE_ESTIMATION/defs.h +++ b/openair1/PHY/LTE_ESTIMATION/defs.h @@ -123,7 +123,6 @@ int lte_dl_channel_estimation(PHY_VARS_UE *phy_vars_ue, uint8_t l, uint8_t symbol); - int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, module_id_t eNB_id, uint8_t eNB_offset, diff --git a/openair1/PHY/LTE_ESTIMATION/filt12_32.h b/openair1/PHY/LTE_ESTIMATION/filt12_32.h index 602f7c2c3f..a5dfdb0365 100644 --- a/openair1/PHY/LTE_ESTIMATION/filt12_32.h +++ b/openair1/PHY/LTE_ESTIMATION/filt12_32.h @@ -70,3 +70,17 @@ short filt12_r3_dc[12] = { short filt12_m3_dc[12] = { -9831,-6554,-3277,0,3276,6553,9830,16384,12288,8192,4096,0}; +short filt12_1[12] = { +16384,16384,16384,16384,16384,16384,16384,16384,16384,16384,16384,16384}; + +short filt12_2l0[12] = { +16384,12288,8192,4096,-4096,0,0,0,0,0,0,0}; + +short filt12_2r0[12] = { +0,4096,8192,12288,16384,20480,0,0,0,0,0,0}; + +short filt12_2l1[12] = { +20480,16384,12288,8192,4096,0,0,0,0,0,0,0}; + +short filt12_2r1[12] = { +-4096,0,4096,8192,12288,16384,0,0,0,0,0,0}; diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c index 9707b15b35..457aaeed56 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c @@ -31,10 +31,9 @@ #endif #include "defs.h" #include "PHY/defs.h" -#include "filt12_32.h" +#include "filt16_32.h" //#define DEBUG_CH -/*To be accomplished*/ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, uint8_t eNB_id, uint8_t eNB_offset, @@ -43,53 +42,670 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, unsigned char symbol) { - unsigned char aarx; - int uespec_pilot[9][200]; - short *pil, *rxF; + unsigned short rb,nb_rb=0; + unsigned char aarx,l,lprime,nsymb,skip_half=0,sss_symb,pss_symb=0,rb_alloc_ind,harq_pid,uespec_pilots=0; + int beamforming_mode, ch_offset; + uint8_t subframe; + int8_t uespec_nushift, uespec_poffset=0, pil_offset; + uint8_t pilot0,pilot1,pilot2,pilot3; - //LTE_UE_PDSCH *lte_ue_pdsch_vars = phy_vars_ue->lte_ue_pdsch_vars[eNB_id]; - int **rxdataF = phy_vars_ue->lte_ue_common_vars.rxdataF; - int32_t **dl_bf_ch_estimates = phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates; + short ch[2], *pil, *rxF, *dl_bf_ch, *dl_bf_ch_prev; + short *fl, *fm, *fr, *fl_dc, *fm_dc, *fr_dc, *f1, *f2l, *f2r; - int beamforming_mode = phy_vars_ue->transmission_mode>7?phy_vars_ue->transmission_mode : 0; - - // define interpolation filters - //.... + unsigned int *rb_alloc; + int **rxdataF; + int32_t **dl_bf_ch_estimates; + int uespec_pilot[300]; - //ch_offset = phy_vars_ue->lte_frame_parms.ofdm_symbol_size*symbol; + LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_ue->lte_frame_parms; + LTE_UE_DLSCH_t **dlsch_ue = phy_vars_ue->dlsch_ue[eNB_id]; + LTE_DL_UE_HARQ_t *dlsch0_harq; - //generate ue specific pilots - if(beamforming_mode==7) - lte_dl_ue_spec_rx(phy_vars_ue,&uespec_pilot[p-5][0],Ns,p,0); - else if (beamforming_mode>7) - lte_dl_ue_spec_rx(phy_vars_ue,&uespec_pilot[p-6][0],Ns,p,0); - else if (beamforming_mode==0) - msg("No beamforming is performed.\n"); + harq_pid = dlsch_ue[0]->current_harq_pid; + dlsch0_harq = dlsch_ue[0]->harq_processes[harq_pid]; + + rb_alloc = dlsch0_harq->rb_alloc; + + rxdataF = phy_vars_ue->lte_ue_common_vars.rxdataF; + + dl_bf_ch_estimates = phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates; + beamforming_mode = phy_vars_ue->transmission_mode[eNB_id]>6 ? phy_vars_ue->transmission_mode[eNB_id] : 0; + + if (phy_vars_ue->high_speed_flag == 0) // use second channel estimate position for temporary storage + ch_offset = frame_parms->ofdm_symbol_size; else - msg("Beamforming mode not supported yet.\n"); + ch_offset = frame_parms->ofdm_symbol_size*symbol; + + uespec_nushift = frame_parms->Nid_cell%3; + subframe = Ns>>1; + - if(beamforming_mode==7) { + if (beamforming_mode==7) { + //generate ue specific pilots + lprime = symbol/3-1; + lte_dl_ue_spec_rx(phy_vars_ue,uespec_pilot,Ns,5,lprime,0,dlsch0_harq->nb_rb); + write_output("uespec_pilot_rx.m","uespec_pilot",uespec_pilot,300,1,1); + + if (frame_parms->Ncp==0){ + if (symbol==3 || symbol==6 || symbol==9 || symbol==12) + uespec_pilots = 1; + } else{ + if (symbol==4 || symbol==7 || symbol==10) + uespec_pilots = 1; + } - for (aarx=0; aarxlte_frame_parms.nb_antennas_rx;aarx++) { + if ((frame_parms->Ncp==0 && (symbol==6 ||symbol ==12)) || (frame_parms->Ncp==1 && symbol==7)) + uespec_poffset = 2; - /* pil = (short *)&uespec_pilot[0][0]; - rxF = (short *)&rxdataF_uespec[aarx][(symbol-1)/3*frame_parms->N_RB_DL*(3+frame_parms->Ncp)]; - dl_ch = (short *)&dl_bf_ch_estimates[aarx][ch_offset]; - - memset(dl_ch,0,4*(phy_vars_ue->lte_frame_parms.ofdm_symbol_size)); - //estimation and interpolation */ + if (phy_vars_ue->lte_frame_parms.Ncp == 0) { // normal prefix + pilot0 = 3; + pilot1 = 6; + pilot2 = 9; + pilot3 = 12; + } else { // extended prefix + pilot0 = 4; + pilot1 = 7; + pilot2 = 10; } - } else if (beamforming_mode==0){ - msg("No beamforming is performed.\n"); - return(-1); - } else { - msg("Beamforming mode is not supported yet.\n"); - return(-1); + //define the filter + pil_offset = (uespec_nushift+uespec_poffset)%3; + // printf("symbol=%d,pil_offset=%d\n",symbol,pil_offset); + switch (pil_offset) { + case 0: + fl = filt16_l0; + fm = filt16_m0; + fr = filt16_r0; + fl_dc = filt16_l0; + fm_dc = filt16_m0; + fr_dc = filt16_r0; + f1 = filt16_1; + f2l = filt16_2l0; + f2r = filt16_2r0; + break; + + case 1: + fl = filt16_l1; + fm = filt16_m1; + fr = filt16_r1; + fl_dc = filt16_l1; + fm_dc = filt16_m1; + fr_dc = filt16_r1; + f1 = filt16_1; + f2l = filt16_2l1; + f2r = filt16_2r1; + break; + + case 2: + fl = filt16_l2; + fm = filt16_m2; + fr = filt16_r2; + fl_dc = filt16_l2; + fm_dc = filt16_m2; + fr_dc = filt16_r2; + f1 = filt16_1; + f2l = filt16_2l0; + f2r = filt16_2r0; + break; + + case 3: + fl = filt16_l3; + fm = filt16_m3; + fr = filt16_r3; + fl_dc = filt16_l3; + fm_dc = filt16_m3; + fr_dc = filt16_r3; + f1 = filt16_1; + f2l = filt16_2l1; + f2r = filt16_2r1; + break; + } } + else if (beamforming_mode==0) + msg("lte_dl_bf_channel_estimation:No beamforming is performed.\n"); + else + msg("lte_dl_bf_channel_estimation:Beamforming mode not supported yet.\n"); - //temporal interpolation + + l=symbol; + nsymb = (frame_parms->Ncp==NORMAL) ? 14:12; + + if (frame_parms->frame_type == TDD) { //TDD + sss_symb = nsymb-1; + pss_symb = 2; + } else { + sss_symb = (nsymb>>1)-2; + pss_symb = (nsymb>>1)-1; + } + + + for (aarx=0; aarxnb_antennas_rx; aarx++) { + + rxF = (short *)&rxdataF[aarx][pil_offset + frame_parms->first_carrier_offset + symbol*frame_parms->ofdm_symbol_size]; + pil = (short*)uespec_pilot; + dl_bf_ch = (short *)&dl_bf_ch_estimates[aarx][ch_offset]; + + memset(dl_bf_ch,0,4*(frame_parms->ofdm_symbol_size)); + //memset(dl_bf_ch,0,2*(frame_parms->ofdm_symbol_size)); + + if (phy_vars_ue->high_speed_flag==0) // multiply previous channel estimate by ch_est_alpha + if (frame_parms->Ncp==0) + multadd_complex_vector_real_scalar(dl_bf_ch-(frame_parms->ofdm_symbol_size<<1), + phy_vars_ue->ch_est_alpha,dl_bf_ch-(frame_parms->ofdm_symbol_size<<1), + 1,frame_parms->ofdm_symbol_size); + else + msg("lte_dl_bf_channel_estimation: beamforming channel estimation not supported for TM7 Extended CP.\n"); // phy_vars_ue->ch_est_beta should be defined equaling 1/3 + + //estimation and interpolation + + if ((frame_parms->N_RB_DL&1) == 0) // even number of RBs + for (rb=0; rbN_RB_DL; rb++) { + + if (rb < 32) + rb_alloc_ind = (rb_alloc[0]>>rb) & 1; + else if (rb < 64) + rb_alloc_ind = (rb_alloc[1]>>(rb-32)) & 1; + else if (rb < 96) + rb_alloc_ind = (rb_alloc[2]>>(rb-64)) & 1; + else if (rb < 100) + rb_alloc_ind = (rb_alloc[3]>>(rb-96)) & 1; + else + rb_alloc_ind = 0; + + // For second half of RBs skip DC carrier + if (rb==(frame_parms->N_RB_DL>>1)) { + rxF = &rxdataF[aarx][(1 + (symbol*(frame_parms->ofdm_symbol_size)))]; + } + + if (rb_alloc_ind==1) { + if (uespec_pilots==1) { + if (beamforming_mode==7) { + if (frame_parms->Ncp==0) { + + ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); + ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); + multadd_real_vector_complex_scalar(fl,ch,dl_bf_ch,16); + //printf("rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); + + ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); + ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); + multadd_real_vector_complex_scalar(fm,ch,dl_bf_ch,16); + + ch[0] = (short)(((int)pil[0]*rxF[16] - (int)pil[1]*rxF[17])>>15); + ch[1] = (short)(((int)pil[0]*rxF[17] + (int)pil[1]*rxF[16])>>15); + multadd_real_vector_complex_scalar(fr,ch,dl_bf_ch,16); + } + } else { + msg("lte_dl_bf_channel_estimation(lte_dl_bf_channel_estimation.c):TM7 beamgforming channel estimation not supported for extented CP\n"); + exit(-1); + } + + } else { + msg("lte_dl_bf_channel_estimation(lte_dl_bf_channel_estimation.c): transmission mode not supported.\n"); + } + nb_rb++; + } + + rxF+=24; + dl_bf_ch+=24; + } + else { // Odd number of RBs + for (rb=0; rbN_RB_DL>>1; rb++) { + skip_half=0; + + if (rb < 32) + rb_alloc_ind = (rb_alloc[0]>>rb) & 1; + else if (rb < 64) + rb_alloc_ind = (rb_alloc[1]>>(rb-32)) & 1; + else if (rb < 96) + rb_alloc_ind = (rb_alloc[2]>>(rb-64)) & 1; + else if (rb < 100) + rb_alloc_ind = (rb_alloc[3]>>(rb-96)) & 1; + else + rb_alloc_ind = 0; + + // PBCH + if ((subframe==0) && (rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) { + rb_alloc_ind = 0; + } + + //PBCH subframe 0, symbols nsymb>>1 ... nsymb>>1 + 3 + if ((subframe==0) && (rb==((frame_parms->N_RB_DL>>1)-3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) + skip_half=1; + else if ((subframe==0) && (rb==((frame_parms->N_RB_DL>>1)+3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) + skip_half=2; + + //SSS + if (((subframe==0)||(subframe==5)) && + (rb>((frame_parms->N_RB_DL>>1)-3)) && + (rb<((frame_parms->N_RB_DL>>1)+3)) && + (l==sss_symb) ) { + rb_alloc_ind = 0; + } + + //SSS + if (((subframe==0)||(subframe==5)) && + (rb==((frame_parms->N_RB_DL>>1)-3)) && + (l==sss_symb)) + skip_half=1; + else if (((subframe==0)||(subframe==5)) && + (rb==((frame_parms->N_RB_DL>>1)+3)) && + (l==sss_symb)) + skip_half=2; + + //PSS in subframe 0/5 if FDD + if (frame_parms->frame_type == FDD) { //FDD + if (((subframe==0)||(subframe==5)) && (rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + + if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)-3)) && (l==pss_symb)) + skip_half=1; + else if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb)) + skip_half=2; + } + + if ((frame_parms->frame_type == TDD) && + (subframe==6)) { //TDD Subframe 6 + if ((rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + + if ((rb==((frame_parms->N_RB_DL>>1)-3)) && (l==pss_symb)) + skip_half=1; + else if ((rb==((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb)) + skip_half=2; + } + + //printf("symbol=%d,pil_offset=%d\ni,rb_alloc_ind=%d,uespec_pilots=%d,beamforming_mode=%d,Ncp=%d,skip_half=%d\n",symbol,pil_offset,rb_alloc_ind,uespec_pilots,beamforming_mode,frame_parms->Ncp,skip_half); + if (rb_alloc_ind==1) { + if (uespec_pilots==1) { + if (beamforming_mode==7) { + if (frame_parms->Ncp==0) { + if (skip_half==1) { + if (pil_offset<2) { + + ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); + ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); + multadd_real_vector_complex_scalar(f2l,ch,dl_bf_ch,16); + pil+=2; + + ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); + ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); + multadd_real_vector_complex_scalar(f2r,ch,dl_bf_ch,16); + pil+=2; + + } else { + + ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); + ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); + multadd_real_vector_complex_scalar(f1,ch,dl_bf_ch,16); + pil+=2; + } + } else if (skip_half==2) { + if (pil_offset<2) { + + ch[0] = (short)(((int)pil[0]*rxF[16] - (int)pil[1]*rxF[17])>>15); + ch[1] = (short)(((int)pil[0]*rxF[17] + (int)pil[1]*rxF[16])>>15); + multadd_real_vector_complex_scalar(f1,ch,dl_bf_ch,16); + pil+=2; + + } else { + + ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); + ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); + multadd_real_vector_complex_scalar(f2l,ch,dl_bf_ch,16); + pil+=2; + + ch[0] = (short)(((int)pil[0]*rxF[16] - (int)pil[1]*rxF[17])>>15); + ch[1] = (short)(((int)pil[0]*rxF[17] + (int)pil[1]*rxF[16])>>15); + multadd_real_vector_complex_scalar(f2r,ch,dl_bf_ch,16); + pil+=2; + + } + } else { + + ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); + ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); + multadd_real_vector_complex_scalar(fl,ch,dl_bf_ch,16); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); + pil+=2; + + ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); + ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); + multadd_real_vector_complex_scalar(fm,ch,dl_bf_ch,16); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); + pil+=2; + + ch[0] = (short)(((int)pil[0]*rxF[16] - (int)pil[1]*rxF[17])>>15); + ch[1] = (short)(((int)pil[0]*rxF[17] + (int)pil[1]*rxF[16])>>15); + multadd_real_vector_complex_scalar(fr,ch,dl_bf_ch,16); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); + pil+=2; + + } + } else { + msg("lte_dl_bf_channel_estimation(lte_dl_bf_channel_estimation.c):TM7 beamgforming channel estimation not supported for extented CP\n"); + exit(-1); + } + + } else { + msg("lte_dl_bf_channel_estimation(lte_dl_bf_channel_estimation.c):transmission mode not supported.\n"); + } + } + nb_rb++; + } + + rxF+=24; + dl_bf_ch+=24; + } // first half loop + + // Do middle RB (around DC) + if (rb < 32) + rb_alloc_ind = (rb_alloc[0]>>rb) & 1; + else if (rb < 64) + rb_alloc_ind = (rb_alloc[1]>>(rb-32)) & 1; + else if (rb < 96) + rb_alloc_ind = (rb_alloc[2]>>(rb-64)) & 1; + else if (rb < 100) + rb_alloc_ind = (rb_alloc[3]>>(rb-96)) & 1; + else + rb_alloc_ind = 0; + + // PBCH + if ((subframe==0) && (rb>=((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) { + rb_alloc_ind = 0; + } + + //SSS + if (((subframe==0)||(subframe==5)) && (rb>=((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==sss_symb) ) { + rb_alloc_ind = 0; + } + + if (frame_parms->frame_type == FDD) { + //PSS + if (((subframe==0)||(subframe==5)) && (rb>=((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + } + + if ((frame_parms->frame_type == TDD) && (subframe==6)) { + //PSS + if ((rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + } + + //printf("DC rb %d (%p)\n",rb,rxF); + if (rb_alloc_ind==1) { + if (pil_offset<2) { + ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); + ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); + multadd_real_vector_complex_scalar(fl_dc,ch,dl_bf_ch,16); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); + pil+=2;; + + ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); + ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); + multadd_real_vector_complex_scalar(fm_dc,ch,dl_bf_ch,16); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[8],rxF[9],pil[0],pil[1],ch[0],ch[1]); + pil+=2;; + + rxF = (short *)&rxdataF[aarx][symbol*(frame_parms->ofdm_symbol_size)]; + + ch[0] = (short)(((int)pil[0]*rxF[6] - (int)pil[1]*rxF[7])>>15); + ch[1] = (short)(((int)pil[0]*rxF[7] + (int)pil[1]*rxF[6])>>15); + multadd_real_vector_complex_scalar(fr_dc,ch,dl_bf_ch,16); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[6],rxF[7],pil[0],pil[1],ch[0],ch[1]); + pil+=2;; + } else { + ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); + ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); + multadd_real_vector_complex_scalar(fl_dc,ch,dl_bf_ch,16); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); + pil+=2;; + + rxF = (short *)&rxdataF[aarx][symbol*(frame_parms->ofdm_symbol_size)]; + + ch[0] = (short)(((int)pil[0]*rxF[2] - (int)pil[1]*rxF[3])>>15); + ch[1] = (short)(((int)pil[0]*rxF[3] + (int)pil[1]*rxF[2])>>15); + multadd_real_vector_complex_scalar(fm_dc,ch,dl_bf_ch,16); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[2],rxF[3],pil[0],pil[1],ch[0],ch[1]); + pil+=2;; + + ch[0] = (short)(((int)pil[0]*rxF[10] - (int)pil[1]*rxF[11])>>15); + ch[1] = (short)(((int)pil[0]*rxF[11] + (int)pil[1]*rxF[10])>>15); + multadd_real_vector_complex_scalar(fr_dc,ch,dl_bf_ch,16); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[10],rxF[11],pil[0],pil[1],ch[0],ch[1]); + pil+=2;; + } + } // rballoc==1 + else { + rxF = (short *)&rxdataF[aarx][pil_offset+((symbol*(frame_parms->ofdm_symbol_size)))]; + } + + rxF+=14+2*pil_offset; + dl_bf_ch+=24; + rb++; + + for (; rbN_RB_DL; rb++) { + skip_half=0; + + if (rb < 32) + rb_alloc_ind = (rb_alloc[0]>>rb) & 1; + else if (rb < 64) + rb_alloc_ind = (rb_alloc[1]>>(rb-32)) & 1; + else if (rb < 96) + rb_alloc_ind = (rb_alloc[2]>>(rb-64)) & 1; + else if (rb < 100) + rb_alloc_ind = (rb_alloc[3]>>(rb-96)) & 1; + else + rb_alloc_ind = 0; + + // PBCH + if ((subframe==0) && (rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l>=nsymb>>1) && (l<((nsymb>>1) + 4))) { + rb_alloc_ind = 0; + } + + //PBCH subframe 0, symbols nsymb>>1 ... nsymb>>1 + 3 + if ((subframe==0) && (rb==((frame_parms->N_RB_DL>>1)-3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) + skip_half=1; + else if ((subframe==0) && (rb==((frame_parms->N_RB_DL>>1)+3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) + skip_half=2; + + //SSS + if (((subframe==0)||(subframe==5)) && (rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==sss_symb) ) { + rb_alloc_ind = 0; + } + + //SSS + if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)-3)) && (l==sss_symb)) + skip_half=1; + else if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)+3)) && (l==sss_symb)) + skip_half=2; + + if (frame_parms->frame_type == FDD) { + //PSS + if (((subframe==0)||(subframe==5)) && (rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + + //PSS + if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)-3)) && (l==pss_symb)) + skip_half=1; + else if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb)) + skip_half=2; + } + + if ((frame_parms->frame_type == TDD) && + (subframe==6)) { //TDD Subframe 6 + if ((rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + + if ((rb==((frame_parms->N_RB_DL>>1)-3)) && (l==pss_symb)) + skip_half=1; + else if ((rb==((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb)) + skip_half=2; + } + + if (rb_alloc_ind==1) { + if (uespec_pilots==1) { + if (beamforming_mode==7) { + if (frame_parms->Ncp==0) { + if (skip_half==1) { + if (pil_offset<2) { + + ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); + ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); + multadd_real_vector_complex_scalar(f2l,ch,dl_bf_ch,16); + pil+=2; + + ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); + ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); + multadd_real_vector_complex_scalar(f2r,ch,dl_bf_ch,16); + pil+=2; + + + } else { + + ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); + ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); + multadd_real_vector_complex_scalar(f1,ch,dl_bf_ch,16); + pil+=2; + } + } else if (skip_half==2) { + if (pil_offset<2) { + + ch[0] = (short)(((int)pil[0]*rxF[16] - (int)pil[1]*rxF[17])>>15); + ch[1] = (short)(((int)pil[0]*rxF[17] + (int)pil[1]*rxF[16])>>15); + multadd_real_vector_complex_scalar(f1,ch,dl_bf_ch,16); + pil+=2; + + } else { + + ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); + ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); + multadd_real_vector_complex_scalar(f2l,ch,dl_bf_ch,16); + pil+=2; + + ch[0] = (short)(((int)pil[0]*rxF[16] - (int)pil[1]*rxF[17])>>15); + ch[1] = (short)(((int)pil[0]*rxF[17] + (int)pil[1]*rxF[16])>>15); + multadd_real_vector_complex_scalar(f2r,ch,dl_bf_ch,16); + pil+=2; + + } + } else { + + ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); + ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); + multadd_real_vector_complex_scalar(fl,ch,dl_bf_ch,16); + // printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); + pil+=2; + + ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); + ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); + multadd_real_vector_complex_scalar(fm,ch,dl_bf_ch,16); + // printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[8],rxF[9],pil[0],pil[1],ch[0],ch[1]); + pil+=2; + + ch[0] = (short)(((int)pil[0]*rxF[16] - (int)pil[1]*rxF[17])>>15); + ch[1] = (short)(((int)pil[0]*rxF[17] + (int)pil[1]*rxF[16])>>15); + multadd_real_vector_complex_scalar(fr,ch,dl_bf_ch,16); + // printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[16],rxF[17],pil[0],pil[1],ch[0],ch[1]); + pil+=2; + + } + } else { + msg("lte_dl_bf_channel_estimation(lte_dl_bf_channel_estimation.c):TM7 beamgforming channel estimation not supported for extented CP\n"); + exit(-1); + } + + } else { + msg("lte_dl_bf_channel_estimation(lte_dl_bf_channel_estimation.c):transmission mode not supported.\n"); + } + } + nb_rb++; + } + + rxF+=24; + dl_bf_ch+=24; + } // second half of RBs + } // odd number of RBs + + // Temporal Interpolation + if (phy_vars_ue->perfect_ce == 0) { + + dl_bf_ch = (short *)&dl_bf_ch_estimates[aarx][ch_offset]; + printf("dlsch_bf_ch_est.c:symbol %d, dl_bf_ch (%d,%d)\n",symbol,dl_bf_ch[0],dl_bf_ch[1]); + + if (phy_vars_ue->high_speed_flag == 0) { + multadd_complex_vector_real_scalar(dl_bf_ch, + 32767-phy_vars_ue->ch_est_alpha, + dl_bf_ch-(frame_parms->ofdm_symbol_size<<1),0,frame_parms->ofdm_symbol_size); + printf("dlsch_bf_ch_est.c:symbol %d,dl_bf_ch (%d,%d)\n",symbol,*(dl_bf_ch-512*2),*(dl_bf_ch-512*2+1)); + } else { // high_speed_flag == 1 + if (beamforming_mode==7) { + if (frame_parms->Ncp==0) { + if (symbol == pilot0) { + // printf("Interpolating %d->0\n",4-phy_vars_ue->lte_frame_parms.Ncp); + // dl_bf_ch_prev = (short *)&dl_bf_ch_estimates[aarx][(4-phy_vars_ue->lte_frame_parms.Ncp)*(frame_parms->ofdm_symbol_size)]; + dl_bf_ch_prev = (short *)&dl_bf_ch_estimates[aarx][pilot3*(frame_parms->ofdm_symbol_size)]; + + // pilot spacing 5 symbols (1/5,2/5,3/5,4/5 combination) + multadd_complex_vector_real_scalar(dl_bf_ch_prev,26214,dl_bf_ch_prev+(2*(frame_parms->ofdm_symbol_size)),1,frame_parms->ofdm_symbol_size); + multadd_complex_vector_real_scalar(dl_bf_ch,6554,dl_bf_ch_prev+(2*(frame_parms->ofdm_symbol_size)),0,frame_parms->ofdm_symbol_size); + + multadd_complex_vector_real_scalar(dl_bf_ch_prev,19661,dl_bf_ch-(3*2*(frame_parms->ofdm_symbol_size)),1,frame_parms->ofdm_symbol_size); + multadd_complex_vector_real_scalar(dl_bf_ch,13107,dl_bf_ch-(3*2*(frame_parms->ofdm_symbol_size)),0,frame_parms->ofdm_symbol_size); + + multadd_complex_vector_real_scalar(dl_bf_ch_prev,13107,dl_bf_ch-(2*((frame_parms->ofdm_symbol_size)<<1)),1,frame_parms->ofdm_symbol_size); + multadd_complex_vector_real_scalar(dl_bf_ch,19661,dl_bf_ch-(2*((frame_parms->ofdm_symbol_size)<<1)),0,frame_parms->ofdm_symbol_size); + + multadd_complex_vector_real_scalar(dl_bf_ch_prev,6554,dl_bf_ch-(2*(frame_parms->ofdm_symbol_size)),1,frame_parms->ofdm_symbol_size); + multadd_complex_vector_real_scalar(dl_bf_ch,26214,dl_bf_ch-(2*(frame_parms->ofdm_symbol_size)),0,frame_parms->ofdm_symbol_size); + } else if (symbol == pilot1) { + dl_bf_ch_prev = (short *)&dl_bf_ch_estimates[aarx][pilot0*(frame_parms->ofdm_symbol_size)]; + + // pilot spacing 3 symbols (1/3,2/3 combination) + multadd_complex_vector_real_scalar(dl_bf_ch_prev,21845,dl_bf_ch_prev+(2*(frame_parms->ofdm_symbol_size)),1,frame_parms->ofdm_symbol_size); + multadd_complex_vector_real_scalar(dl_bf_ch,10923,dl_bf_ch_prev+(2*(frame_parms->ofdm_symbol_size)),0,frame_parms->ofdm_symbol_size); + + multadd_complex_vector_real_scalar(dl_bf_ch_prev,10923,dl_bf_ch_prev+(2*((frame_parms->ofdm_symbol_size)<<1)),1,frame_parms->ofdm_symbol_size); + multadd_complex_vector_real_scalar(dl_bf_ch,21845,dl_bf_ch_prev+(2*((frame_parms->ofdm_symbol_size)<<1)),0,frame_parms->ofdm_symbol_size); + + } else if (symbol == pilot2) { + dl_bf_ch_prev = (short *)&dl_bf_ch_estimates[aarx][pilot1*(frame_parms->ofdm_symbol_size)]; + + multadd_complex_vector_real_scalar(dl_bf_ch_prev,21845,dl_bf_ch_prev+(2*(frame_parms->ofdm_symbol_size)),1,frame_parms->ofdm_symbol_size); + multadd_complex_vector_real_scalar(dl_bf_ch,10923,dl_bf_ch_prev+(2*(frame_parms->ofdm_symbol_size)),0,frame_parms->ofdm_symbol_size); + + multadd_complex_vector_real_scalar(dl_bf_ch_prev,10923,dl_bf_ch_prev+(2*((frame_parms->ofdm_symbol_size)<<1)),1,frame_parms->ofdm_symbol_size); + multadd_complex_vector_real_scalar(dl_bf_ch,21845,dl_bf_ch_prev+(2*((frame_parms->ofdm_symbol_size)<<1)),0,frame_parms->ofdm_symbol_size); + } else { // symbol == pilot3 + // printf("Interpolating 0->%d\n",4-phy_vars_ue->lte_frame_parms.Ncp); + dl_bf_ch_prev = (short *)&dl_bf_ch_estimates[aarx][pilot2*(frame_parms->ofdm_symbol_size)]; + + // pilot spacing 3 symbols (1/3,2/3 combination) + multadd_complex_vector_real_scalar(dl_bf_ch_prev,21845,dl_bf_ch_prev+(2*(frame_parms->ofdm_symbol_size)),1,frame_parms->ofdm_symbol_size); + multadd_complex_vector_real_scalar(dl_bf_ch,10923,dl_bf_ch_prev+(2*(frame_parms->ofdm_symbol_size)),0,frame_parms->ofdm_symbol_size); + + multadd_complex_vector_real_scalar(dl_bf_ch_prev,10923,dl_bf_ch_prev+(2*((frame_parms->ofdm_symbol_size)<<1)),1,frame_parms->ofdm_symbol_size); + multadd_complex_vector_real_scalar(dl_bf_ch,21845,dl_bf_ch_prev+(2*((frame_parms->ofdm_symbol_size)<<1)),0,frame_parms->ofdm_symbol_size); + } + + } else { + msg("lte_dl_bf_channel_estimation:temporal interpolation not supported for TM7 extented CP.\n"); + } + } else { + msg("lte_dl_bf_channel_estimation:temporal interpolation not supported for this beamforming mode.\n"); + } + } + } + } //aarx + + //printf("[dlsch bf ch est]: dl_bf_estimates[0][600] %d, %d \n",*(short *)&dl_bf_ch_estimates[0][600],*(short*)&phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates[0][600]); return(0); diff --git a/openair1/PHY/LTE_REFSIG/defs.h b/openair1/PHY/LTE_REFSIG/defs.h index e9482060a7..6d52d4a5f7 100644 --- a/openair1/PHY/LTE_REFSIG/defs.h +++ b/openair1/PHY/LTE_REFSIG/defs.h @@ -54,6 +54,8 @@ void lte_gold(LTE_DL_FRAME_PARMS *frame_parms,uint32_t lte_gold_table[20][2][14] void lte_gold_ue_spec(LTE_DL_FRAME_PARMS *frame_parms,uint32_t lte_gold_uespec_table[2][20][2][21],uint16_t Nid_cell, uint16_t *n_idDMRS); +void lte_gold_ue_spec_port5(uint32_t lte_gold_uespec_port5_table[20][38],uint16_t Nid_cell, uint16_t n_rnti); + /*!\brief This function generates the LTE Gold sequence (36-211, Sec 7.2), specifically for DL UE-specific reference signals for antenna ports 7..14. @param frame_parms LTE DL Frame parameters @param lte_gold_uespec_table pointer to table where sequences are stored @@ -96,7 +98,7 @@ int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, uint8_t Ns, uint8_t lprime, uint8_t p, - int SS_flag ); + int SS_flag); /*! \brief This function generates the MBSFN reference signal sequence (36-211, Sec 6.10.1.2) @param phy_vars_eNB Pointer to eNB variables @@ -130,7 +132,9 @@ int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, mod_sym_t *output, unsigned char Ns, unsigned char p, - int SS_flag); + int lprime, + int SS_flag, + uint16_t nRB_PDSCH); int lte_dl_mbsfn_rx(PHY_VARS_UE *phy_vars_ue, int *output, diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c b/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c index 64c4e8782e..505a6e19cd 100644 --- a/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c +++ b/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c @@ -59,12 +59,12 @@ int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, uint8_t Ns, uint8_t lprime, uint8_t p, - int SS_flag ) + int SS_flag) { - mod_sym_t qpsk[4],nqpsk[4]; + /* mod_sym_t qpsk[4],nqpsk[4]; int16_t k=0,a; - int mprime,mprime_dword,mprime_qpsk_symb; + int mprime,ind,ind_dword,ind_qpsk_symb; unsigned nushift,kprime; // LTE_eNB_DLSCH_t *dlsch = phy_vars_eNB->dlsch_eNB[UE_id][0]; @@ -103,12 +103,13 @@ int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, k = kprime+phy_vars_eNB->lte_frame_parms.first_carrier_offset; printf("lte_dl_ue_spec:k=%d\n",k); - for (mprime=0;mprime<3*phy_vars_eNB->lte_frame_parms.N_RB_DL-1;mprime++) { - mprime_dword = mprime>>4; - mprime_qpsk_symb = mprime&0xf; + for (mprime=0;mprime<3*nRB_PDSCH-1;mprime++) { + ind = 3*lprime*nRB_PDSCH+mprime; + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; - //output[k] = qpsk[(phy_vars_eNB->lte_gold_uespec_port5_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; - output[k] = 0xffffffff; + output[k] = qpsk[(phy_vars_UE->lte_gold_uespec_port5_table[Ns][ind_dword]>>(2*ind_qpsk_symb))&3]; + //output[k] = 0xffffffff; k += 4; if (k >= phy_vars_eNB->lte_frame_parms.ofdm_symbol_size) { @@ -125,19 +126,21 @@ int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, LOG_E(PHY,"Illegal p %d UE specific pilots\n",p); } - return(0); + return(0);*/ } int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, - mod_sym_t *output, - unsigned char Ns, - unsigned char p, - int SS_flag) + mod_sym_t *output, + unsigned char Ns, + unsigned char p, + int lprime, + int SS_flag, + uint16_t nRB_PDSCH) { mod_sym_t qpsk[4],nqpsk[4],*qpsk_p,*output_p; int16_t a; - int w,lprime,mprime,ind,l,ind_dword,ind_qpsk_symb,nPRB; + int w,mprime,ind,l,ind_dword,ind_qpsk_symb,nPRB; short pamp; // Compute the correct pilot amplitude, sqrt_rho_b = Q3.13 @@ -169,7 +172,7 @@ int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, output_p = output; - for (lprime=0; lprime<2; lprime++) { + //for (lprime=0; lprime<2; lprime++) { ind = 3*lprime*phy_vars_ue->lte_frame_parms.N_RB_DL; l = lprime + ((Ns&1)<<1); @@ -288,25 +291,29 @@ int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, output_p++; ind++; } - } + // } } else { LOG_E(PHY,"Special subframe not supported for UE specific pilots yet\n"); } } } else if (p==5) { if (SS_flag==0) { - if (phy_vars_ue->lte_frame_parms.Ncp == NORMAL) { - - for (lprime=0;lprime<2;lprime++) { - ind = 3*lprime*phy_vars_ue->lte_frame_parms.N_RB_DL; - - for (mprime=0;mprime<3*phy_vars_ue->lte_frame_parms.N_RB_DL-1;mprime++) { - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; - *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_port5_table[Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; - *output_p++; - } + output_p = output; + + if (phy_vars_ue->lte_frame_parms.Ncp == NORMAL) { + //for (lprime=0;lprime<4;lprime++) { + for (mprime=0;mprime<3*nRB_PDSCH;mprime++) { + + ind = 3*lprime*nRB_PDSCH+mprime; + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk[(phy_vars_ue->lte_gold_uespec_port5_table[Ns][ind_dword]>>(2*ind_qpsk_symb))&3]; + //printf("lprime=%d,ind=%d,Ns=%d,output_p=(%d,%d)\n",lprime,ind,Ns,((short *)&output_p[0])[0],((short *)&output_p[0])[1]); + *output_p++; + } + // } } } } else { @@ -343,44 +350,44 @@ main() lte_gold(Nid_cell,Ncp); lte_dl_ue_spec(output00, - ONE_OVER_SQRT2_Q15, - 50, - Nid_cell, - Ncp, - 0, - 0, - 0, - 0); + ONE_OVER_SQRT2_Q15, + 50, + Nid_cell, + Ncp, + 0, + 0, + 0, + 0); lte_dl_ue_spec(output10, - ONE_OVER_SQRT2_Q15, - 50, - Nid_cell, - Ncp, - 0, - 1, - 0, - 0); + ONE_OVER_SQRT2_Q15, + 50, + Nid_cell, + Ncp, + 0, + 1, + 0, + 0); lte_dl_ue_spec(output01, - ONE_OVER_SQRT2_Q15, - 50, - Nid_cell, - Ncp, - 0, - 0, - 1, - 0); + ONE_OVER_SQRT2_Q15, + 50, + Nid_cell, + Ncp, + 0, + 0, + 1, + 0); lte_dl_ue_spec(output11, - ONE_OVER_SQRT2_Q15, - 50, - Nid_cell, - Ncp, - 0, - 1, - 1, - 0); + ONE_OVER_SQRT2_Q15, + 50, + Nid_cell, + Ncp, + 0, + 1, + 1, + 0); write_output("dl_ue_spec00.m","dl_cs00",output00,1024,1,1); diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c b/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/openair1/PHY/LTE_REFSIG/lte_gold.c b/openair1/PHY/LTE_REFSIG/lte_gold.c index 456a2b17d1..cdf78b6844 100644 --- a/openair1/PHY/LTE_REFSIG/lte_gold.c +++ b/openair1/PHY/LTE_REFSIG/lte_gold.c @@ -142,7 +142,7 @@ void lte_gold_ue_spec(LTE_DL_FRAME_PARMS *frame_parms,uint32_t lte_gold_uespec_t } } -void lte_gold_ue_spec_port5(uint32_t lte_gold_uespec_port5_table[20][2][21],uint16_t Nid_cell, uint16_t n_rnti) +void lte_gold_ue_spec_port5(uint32_t lte_gold_uespec_port5_table[20][38],uint16_t Nid_cell, uint16_t n_rnti) { unsigned char ns,l; @@ -151,36 +151,36 @@ void lte_gold_ue_spec_port5(uint32_t lte_gold_uespec_port5_table[20][2][21],uint for (ns=0; ns<20; ns++) { - for (l=0; l<2; l++) { + //for (l=0; l<2; l++) { - x2 = ((((ns>>1)+1)*((Nid_cell<<1)+1))<<16) + n_rnti; - //x2 = frame_parms->Ncp + (Nid_cell<<1) + (1+(Nid_cell<<1))*(1 + (3*l) + (7*(1+ns))); //cinit - //n = 0 - // printf("cinit (ns %d, l %d) => %d\n",ns,l,x2); - x1 = 1+ (1<<31); - x2=x2 ^ ((x2 ^ (x2>>1) ^ (x2>>2) ^ (x2>>3))<<31); - - // skip first 50 double words (1600 bits) - //printf("n=0 : x1 %x, x2 %x\n",x1,x2); - for (n=1; n<50; n++) { - x1 = (x1>>1) ^ (x1>>4); - x1 = x1 ^ (x1<<31) ^ (x1<<28); - x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4); - x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28); - // printf("x1 : %x, x2 : %x\n",x1,x2); - } - - for (n=0; n<14; n++) { - x1 = (x1>>1) ^ (x1>>4); - x1 = x1 ^ (x1<<31) ^ (x1<<28); - x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4); - x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28); - lte_gold_uespec_port5_table[ns][l][n] = x1^x2; - // printf("n=%d : c %x\n",n,x1^x2); - } + x2 = ((((ns>>1)+1)*((Nid_cell<<1)+1))<<16) + n_rnti; + //x2 = frame_parms->Ncp + (Nid_cell<<1) + (1+(Nid_cell<<1))*(1 + (3*l) + (7*(1+ns))); //cinit + //n = 0 + // printf("cinit (ns %d, l %d) => %d\n",ns,l,x2); + x1 = 1+ (1<<31); + x2=x2 ^ ((x2 ^ (x2>>1) ^ (x2>>2) ^ (x2>>3))<<31); + // skip first 50 double words (1600 bits) + //printf("n=0 : x1 %x, x2 %x\n",x1,x2); + for (n=1; n<50; n++) { + x1 = (x1>>1) ^ (x1>>4); + x1 = x1 ^ (x1<<31) ^ (x1<<28); + x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4); + x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28); + // printf("x1 : %x, x2 : %x\n",x1,x2); } + + for (n=0; n<38; n++) { + x1 = (x1>>1) ^ (x1>>4); + x1 = x1 ^ (x1<<31) ^ (x1<<28); + x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4); + x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28); + lte_gold_uespec_port5_table[ns][n] = x1^x2; + // printf("n=%d : c %x\n",n,x1^x2); + } + + // } } } diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index 3aa3f72312..89dadbbd1c 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -246,15 +246,16 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, } } else if (beamforming_mode==7) { //else n_tx>1 nb_rb = dlsch_extract_rbs_TM7(lte_ue_common_vars->rxdataF, - lte_ue_common_vars->dl_ch_estimates[eNB_id], + lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates, lte_ue_pdsch_vars[eNB_id]->rxdataF_ext, - lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext, + lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext, dlsch0_harq->rb_alloc, symbol, subframe, phy_vars_ue->high_speed_flag, frame_parms); + printf("dlsch extract: symbol %d, dl_bf_estimates_ext[0][300] %d \n",symbol, lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext[0][300]); } else if(beamforming_mode>7) { LOG_W(PHY,"dlsch_demodulation:beamforming mode not supported yet.\n"); @@ -275,11 +276,19 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, nb_rb); */ if (first_symbol_flag==1) { - dlsch_channel_level(lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext, - frame_parms, - avg, - symbol, - nb_rb); + if (beamforming_mode==0) + dlsch_channel_level(lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext, + frame_parms, + avg, + symbol, + nb_rb); + else + dlsch_channel_level(lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext, + frame_parms, + avg, + symbol, + nb_rb); + #ifdef DEBUG_PHY LOG_D(PHY,"[DLSCH] avg[0] %d\n",avg[0]); #endif @@ -329,6 +338,8 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, aarx = frame_parms->nb_antennas_rx; if (dlsch0_harq->mimo_modedl_ch_estimates_ext[0][300]); + printf("dlsch compensation: symbol %d, dl_estimates_ext[0][2400] %d \n",symbol, lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext[0][2400]); dlsch_channel_compensation(lte_ue_pdsch_vars[eNB_id]->rxdataF_ext, lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext, @@ -546,9 +557,11 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, 1); } } else if (dlsch0_harq->mimo_mode==TM7) { //TM7 + printf("dlsch compensation: symbol %d, dl_bf_estimates_ext[0][300] %d \n",symbol, *(short*)<e_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext[0][300]); + printf("dlsch compensation: symbol %d, dl_bf_estimates_ext[0][2400] %d \n",symbol, lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext[0][2400]); dlsch_channel_compensation(lte_ue_pdsch_vars[eNB_id]->rxdataF_ext, - lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext, + lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext, lte_ue_pdsch_vars[eNB_id]->dl_ch_mag0, lte_ue_pdsch_vars[eNB_id]->dl_ch_magb0, lte_ue_pdsch_vars[eNB_id]->rxdataF_comp0, @@ -558,6 +571,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, first_symbol_flag, get_Qm(dlsch0_harq->mcs), nb_rb, + //9, lte_ue_pdsch_vars[eNB_id]->log2_maxh, phy_measurements); // log2_maxh+I0_shift } @@ -4209,9 +4223,9 @@ unsigned short dlsch_extract_rbs_dual(int **rxdataF, } unsigned short dlsch_extract_rbs_TM7(int **rxdataF, - int **dl_ch_estimates, + int **dl_bf_ch_estimates, int **rxdataF_ext, - int **dl_ch_estimates_ext, + int **dl_bf_ch_estimates_ext, unsigned int *rb_alloc, unsigned char symbol, unsigned char subframe, @@ -4240,7 +4254,7 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, uespec_pilots = 1; } - if (frame_parms->frame_type == TDD) { // TDD + if (frame_parms->frame_type == TDD) {// TDD sss_symb = nsymb-1; pss_symb = 2; } else { @@ -4257,15 +4271,17 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, for (aarx=0; aarxnb_antennas_rx; aarx++) { if (high_speed_flag == 1) - dl_ch0 = &dl_ch_estimates[aarx][5+(symbol*(frame_parms->ofdm_symbol_size))]; + //dl_ch0 = &dl_bf_ch_estimates[aarx][5+(symbol*(frame_parms->ofdm_symbol_size))]; + dl_ch0 = &dl_bf_ch_estimates[aarx][symbol*(frame_parms->ofdm_symbol_size)]; else - dl_ch0 = &dl_ch_estimates[aarx][5]; + //dl_ch0 = &dl_bf_ch_estimates[aarx][5]; + dl_ch0 = &dl_bf_ch_estimates[aarx][0]; - dl_ch0_ext = &dl_ch_estimates_ext[aarx][symbol*(frame_parms->N_RB_DL*12)]; + dl_ch0_ext = &dl_bf_ch_estimates_ext[aarx][symbol*(frame_parms->N_RB_DL*12)]; rxF_ext = &rxdataF_ext[aarx][symbol*(frame_parms->N_RB_DL*12)]; rxF = &rxdataF[aarx][(frame_parms->first_carrier_offset + (symbol*(frame_parms->ofdm_symbol_size)))]; - printf("symbol:%d, (symbol-1)/3:%d\n",symbol,(symbol-1)/3); + //printf("symbol:%d, (symbol-1)/3:%d\n",symbol,(symbol-1)/3); //rxF_uespec = &rxdataF_uespec_pilots[aarx][(symbol-1)/3*frame_parms->N_RB_DL*(3+frame_parms->Ncp)]; //printf("symbol, rxF_uespec offset:%d\n",symbol,(symbol-1)/3*frame_parms->N_RB_DL*(3+frame_parms->Ncp)); @@ -4291,7 +4307,7 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (rb_alloc_ind==1) { //*pmi_ext = (pmi>>((rb>>2)<<1))&3; - memcpy(dl_ch0_ext,dl_ch0,12*sizeof(int)); + //memcpy(dl_ch0_ext,dl_ch0,12*sizeof(int)); /* printf("rb %d\n",rb); @@ -4300,11 +4316,10 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, printf("\n"); */ if (pilots==0 && uespec_pilots==0) { + memcpy(dl_ch0_ext,dl_ch0,12*sizeof(int)); + for (i=0; i<12; i++) { rxF_ext[i]=rxF[i]; - /* - printf("%d : (%d,%d)\n",(rxF+i-&rxdataF[aarx][( (symbol*(frame_parms->ofdm_symbol_size)))]), - ((short*)&rxF[i])[0],((short*)&rxF[i])[1]);*/ } dl_ch0_ext+=12; @@ -4316,9 +4331,7 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if ((i!=(frame_parms->nushift+poffset)) && (i!=((frame_parms->nushift+poffset+6)%12))) { rxF_ext[j]=rxF[i]; - // printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); dl_ch0_ext[j++]=dl_ch0[i]; - } } @@ -4432,7 +4445,7 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (rb_alloc_ind==1) { - // printf("rb %d/symbol %d (skip_half %d)\n",rb,l,skip_half); + //printf("rb %d/symbol %d pilots %d, uespec_pilots %d, (skip_half %d)\n",rb,l,pilots,uespec_pilots,skip_half); if (pilots==0 && uespec_pilots==0) { // printf("Extracting w/o pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half); @@ -4493,8 +4506,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if ((i!=(frame_parms->nushift+poffset)) && (i!=((frame_parms->nushift+poffset+6)%12))) { rxF_ext[j]=rxF[i]; - // printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); + //printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); dl_ch0_ext[j++]=dl_ch0[i]; + //printf("symbol %d, extract rb %d => (%d,%d)\n",symbol,rb,*(short *)&dl_ch0[i],*(1+(short*)&dl_ch0[i])); } } @@ -4558,6 +4572,8 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ rxF_ext[j] = rxF[i]; dl_ch0_ext[j++] = dl_ch0[i]; + //printf("symbol %d, extract rb %d, re %d => (%d,%d)\n",symbol,rb,i,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); + //printf("symbol %d, extract rb %d, re %d, j %d => (%d,%d)\n",symbol,rb,i,j-1,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); } } else{ if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ @@ -4676,13 +4692,13 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ dl_ch0_ext[j]=dl_ch0[i]; rxF_ext[j++] = rxF[i]; - //printf("**extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); + //printf("symbol %d, extract rb %d, re %d, j %d => (%d,%d)\n",symbol,rb,i,j-1,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); + //printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); } } else { if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ dl_ch0_ext[j]=dl_ch0[i]; rxF_ext[j++] = rxF[i]; - // printf("**extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); } } } @@ -4694,7 +4710,8 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ dl_ch0_ext[j]=dl_ch0[i]; rxF_ext[j++]=rxF[(1+i-6)]; - // printf("**extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); + // printf("symbol %d, extract rb %d, re %d, j %d => (%d,%d)\n",symbol,rb,i,j-1,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); + // printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); } } else { if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ @@ -4814,6 +4831,7 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, } else { memcpy(dl_ch0_ext,dl_ch0,12*sizeof(int)); + //printf("symbol %d, extract rb %d, => (%d,%d)\n",symbol,rb,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); for (i=0; i<12; i++) rxF_ext[i]=rxF[i]; @@ -4854,6 +4872,7 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, rxF_ext[j]=rxF[i]; //printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); dl_ch0_ext[j++]=dl_ch0[i]; + //printf("symbol %d, extract rb %d => (%d,%d)\n",symbol,rb,*(short *)&dl_ch0[i],*(1+(short*)&dl_ch0[i])); } } @@ -4914,6 +4933,7 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ rxF_ext[j] = rxF[i]; dl_ch0_ext[j++]=dl_ch0[i]; + // printf("symbol %d, extract rb %d, re %d, j %d => (%d,%d)\n",symbol,rb,i,j-1,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); } } else{ if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ @@ -4972,6 +4992,17 @@ void dump_dlsch2(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint16_t coded_bits_per sprintf(vname,"dl%d_ch_r%d_ext00",eNB_id,round); write_output(fname,vname,phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext[0],12*N_RB_DL*nsymb,1,1); + if (phy_vars_ue->transmission_mode[eNB_id]==7){ + sprintf(fname,"dlsch%d_bf_ch_r%d.m",eNB_id,round); + sprintf(vname,"dl%d_bf_ch_r%d",eNB_id,round); + write_output(fname,vname,phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates[0],512*nsymb,1,1); + //write_output(fname,vname,phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates[0],512,1,1); + + sprintf(fname,"dlsch%d_bf_ch_r%d_ext00.m",eNB_id,round); + sprintf(vname,"dl%d_bf_ch_r%d_ext00",eNB_id,round); + write_output(fname,vname,phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext[0],12*N_RB_DL*nsymb,1,1); + } + if (phy_vars_ue->lte_frame_parms.nb_antennas_rx == 2) { sprintf(fname,"dlsch%d_ch_r%d_ext01.m",eNB_id,round); sprintf(vname,"dl%d_ch_r%d_ext01",eNB_id,round); diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index d14c26c13d..2d769a6ccf 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -71,13 +71,13 @@ uint8_t is_not_pilot(uint8_t pilots, uint8_t re, uint8_t nushift, uint8_t use2nd } //uint8_t is_not_UEspecRS(int first_layer,int re) -uint8_t is_not_UEspecRS(uint8_t lprime, uint8_t re, uint8_t nushift, uint8_t Ncp, uint8_t beamforming_mode) +uint8_t is_not_UEspecRS(int8_t lprime, uint8_t re, uint8_t nushift, uint8_t Ncp, uint8_t beamforming_mode) { - uint8_t offset = (lprime==2)?2:0; - if(lprime==0) + uint8_t offset = (lprime==1||lprime==3)?2:0; + if (lprime==-1) return(1); - switch(beamforming_mode){ + switch (beamforming_mode) { case 7: if (Ncp == NORMAL){ if ((re!=nushift+offset) && (re!=((nushift+4+offset)%12)) && (re!=((nushift+8+offset)%12))) @@ -225,7 +225,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB *phy_vars_eNB, uint8_t layer; int s=1; - uint8_t mprime2 = mprime,mprime_dword,mprime_qpsk_symb; + int mprime2 = mprime,ind,ind_dword,ind_qpsk_symb; mod_sym_t qpsk[4]; gain_lin_QPSK = (int16_t)((amp*ONE_OVER_SQRT2_Q15)>>15); @@ -1022,12 +1022,13 @@ break; //printf("precoding UE spec RS\n"); for (aa=0; aa>4; - mprime_qpsk_symb = mprime2&0xf; + + ind = 3*lprime*dlsch0_harq->nb_rb+mprime2; + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; - tmp_sample1 = qpsk[(phy_vars_eNB->lte_gold_uespec_port5_table[0][Ns][lprime][mprime_dword]>>(2*mprime_qpsk_symb))&3]; - //printf("tmp_sample1=%d+i%d\n",((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); - //printf("beamforing_weights[%d][%d]=%d+i%d\n",re,aa,((int16_t*)&beamforming_weights[re][aa])[0],((int16_t*)&beamforming_weights[re][aa])[1]); + tmp_sample1 = qpsk[(phy_vars_eNB->lte_gold_uespec_port5_table[0][Ns][ind_dword]>>(2*ind_qpsk_symb))&3]; + //printf("lprime=%d,nb_rb=%d,mprime2=%d,ind=%d,Ns=%d,tmp_sample1=(%d,%d)\n",lprime,dlsch0_harq->nb_rb,mprime2,ind,Ns,((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((uint16_t*)&beamforming_weights[re][aa])[0])>>15); ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((uint16_t*)&beamforming_weights[re][aa])[1])>>15); @@ -1037,8 +1038,11 @@ break; // ((int16_t*)&txdataF[aa][tti_offset])[0] = 0xffff; // ((int16_t*)&txdataF[aa][tti_offset])[1] = 0xffff; + //printf("tmp_sample1=%d+i%d\n",((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); + //printf("beamforing_weights[%d][%d]=%d+i%d\n",re,aa,((int16_t*)&beamforming_weights[re][aa])[0],((int16_t*)&beamforming_weights[re][aa])[1]); + //printf("txdataF[%d][%d]= %d+i%d\n ",aa,tti_offset,((int16_t*)&txdataF[aa][tti_offset])[0],((int16_t*)&txdataF[aa][tti_offset])[1]); + mprime2 = mprime2++; - //printf("**txdataF[%d][%d]= %d+i%d\n ",aa,tti_offset,((int16_t*)&txdataF[aa][tti_offset])[0],((int16_t*)&txdataF[aa][tti_offset])[1]); } } @@ -1291,7 +1295,8 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, MIMO_mode_t mimo_mode = dlsch0_harq->mimo_mode; uint8_t beamforming_mode = 0; int32_t **beamforming_weights_RB = beamforming_weights; - uint8_t lprime, mprime=0,Ns; + uint8_t mprime=0,Ns; + int8_t lprime=-1; #ifdef DEBUG_DLSCH_MODULATION uint8_t Nl0 = dlsch0_harq->Nl; @@ -1375,19 +1380,25 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, beamforming_mode = 7; mprime = 0; if (frame_parms->Ncp==0) { // normal prefix - if ((l==6)||(l==12)) - lprime=2; // pilots in nushift+3, nushift+9 - else if ((l==3)||(l==9)) - lprime=1; // pilots in nushift, nushift+6 + if (l==12) + lprime=3; // pilots in nushift+3, nushift+9 + else if (l==9) + lprime=2; // pilots in nushift, nushift+6 + else if (l==6) + lprime=1; // pilots in nushift+3, nushift+9 + else if (l==3) + lprime=0; // pilots in nushift, nushift+6 else - lprime=0; + lprime=-1; } else { - if ((l==7)) + if (l==10) lprime=2; - else if ((l==4)||(l==10)) + else if (l==7) lprime=1; - else + else if (l==4) lprime=0; + else + lprime=-1; } }else if(mimo_mode==TM8){ beamforming_mode = 8; @@ -1395,10 +1406,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, beamforming_mode = 9; } - if(l<=(nsymb>>2)) - Ns=0; - else - Ns=1; + Ns = 2*subframe_offset+(l>=(nsymb>>1)); re_offset = frame_parms->first_carrier_offset; symbol_offset = (uint32_t)frame_parms->ofdm_symbol_size*(l+(subframe_offset*nsymb)); @@ -1566,7 +1574,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, qam_table_s1 = NULL; if (rb_alloc_ind > 0) { - // printf("Allocated rb %d/symbol %d, skip_half %d, subframe_offset %d, symbol_offset %d, re_offset %d, jj %d\n",rb,l,skip_half,subframe_offset,symbol_offset,re_offset,jj); + // printf("Allocated rb %d/symbol %d, skip_half %d, subframe_offset %d, symbol_offset %d, re_offset %d, jj %d\n",rb,l,skip_half,subframe_offset,symbol_offset,re_offset,jj); allocate_REs_in_RB(phy_vars_eNB, txdataF, &jj, @@ -1588,12 +1596,8 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, Ns, beamforming_weights_RB); - if(mimo_mode==TM7){ - if(frame_parms->Ncp==0&&(l==3||l==6||l==9||l==12)) - mprime +=3; - else if(frame_parms->Ncp==1&&(l==4||l==7||l==10)) - mprime +=4; - } + if(mimo_mode==TM7 && lprime>=0) + mprime +=3+frame_parms->Ncp; } diff --git a/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c b/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c index 310204eea9..2287c44a5f 100644 --- a/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c +++ b/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c @@ -48,7 +48,7 @@ void generate_ue_spec_pilots(PHY_VARS_eNB *phy_vars_eNB, uint8_t beamforming_mode) { - LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_eNB->lte_frame_parms; + /*LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_eNB->lte_frame_parms; uint32_t tti,tti_offset,slot_offset,Nsymb,samples_per_symbol; uint8_t second_pilot,aa; @@ -123,7 +123,7 @@ void generate_ue_spec_pilots(PHY_VARS_eNB *phy_vars_eNB, default: msg("[generate_ue_spec_pilots(in uespec_pilots.c)]ERROR:beamforming mode %d is not supported\n",beamforming_mode); - } + }*/ } /*int generate_ue_spec_pilots_slot(PHY_VARS_eNB *phy_vars_eNB, diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 58a1177a37..5c3db65afc 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -1756,6 +1756,8 @@ int is_pmch_subframe(frame_t frame, int subframe, LTE_DL_FRAME_PARMS *frame_parm uint8_t is_not_pilot(uint8_t pilots, uint8_t re, uint8_t nushift, uint8_t use2ndpilots); +uint8_t is_not_UEspecRS(int8_t lprime, uint8_t re, uint8_t nushift, uint8_t Ncp, uint8_t beamforming_mode); + uint32_t dlsch_decoding_abstraction(double *dlsch_MIPB, LTE_DL_FRAME_PARMS *lte_frame_parms, LTE_UE_DLSCH_t *dlsch, diff --git a/openair1/PHY/MODULATION/slot_fep.c b/openair1/PHY/MODULATION/slot_fep.c index 5bbea87c88..a7639d9291 100644 --- a/openair1/PHY/MODULATION/slot_fep.c +++ b/openair1/PHY/MODULATION/slot_fep.c @@ -64,6 +64,11 @@ int slot_fep(PHY_VARS_UE *phy_vars_ue, unsigned int frame_length_samples = frame_parms->samples_per_tti * 10; unsigned int rx_offset; + /*LTE_UE_DLSCH_t **dlsch_ue = phy_vars_ue->dlsch_ue[eNB_id]; + unsigned char harq_pid = dlsch_ue[0]->current_harq_pid; + LTE_DL_UE_HARQ_t *dlsch0_harq = dlsch_ue[0]->harq_processes[harq_pid]; + int uespec_pilot[9][1200];*/ + void (*dft)(int16_t *,int16_t *, int); int tmp_dft_in[256]; // This is for misalignment issues for 6 and 15 PRBs @@ -241,15 +246,18 @@ int slot_fep(PHY_VARS_UE *phy_vars_ue, } } - // printf("slot_fep:transmission_mode[%d] = %d\n", eNB_id, phy_vars_ue->transmission_mode[eNB_id]); - if(phy_vars_ue->transmission_mode[eNB_id] == 7) - if(frame_parms->Ncp==0 && (symbol==3) || (symbol==6) || (symbol==9) || (symbol==12)) - lte_dl_bf_channel_estimation(phy_vars_ue,eNB_id,0,Ns,5,symbol); - else if(frame_parms->Ncp==1 && (symbol==4) || (symbol==7) || (symbol==10)) - msg("slot_fep(slot_fep.c):channel estimation not supported yet for TM7 extented CP.\n"); - else if(phy_vars_ue->transmission_mode[eNB_id] > 7) - msg("slot_fep(slot_fep.c):transmission mode not supported yet.\n"); + if(phy_vars_ue->transmission_mode[eNB_id] == 7) { + + if(frame_parms->Ncp==0 && ((symbol==3) || (symbol==6) || (symbol==9) || (symbol==12))) + lte_dl_bf_channel_estimation(phy_vars_ue,eNB_id,0,Ns,5,symbol); + + else if(frame_parms->Ncp==1 && ((symbol==4) || (symbol==7) || (symbol==10))) + msg("slot_fep(slot_fep.c):channel estimation not supported yet for TM7 extented CP.\n"); + + } else if(phy_vars_ue->transmission_mode[eNB_id] > 7) { + msg("slot_fep(slot_fep.c):transmission mode not supported yet.\n"); + } } #ifdef DEBUG_FEP diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 80c6b4ef01..7cce9d3cd1 100755 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -243,7 +243,7 @@ typedef struct PHY_VARS_eNB_s { uint32_t lte_gold_table[20][2][14]; /// UE-specific reference symbols (p=5), TM 7 - uint32_t lte_gold_uespec_port5_table[NUMBER_OF_UE_MAX][20][2][21]; + uint32_t lte_gold_uespec_port5_table[NUMBER_OF_UE_MAX][20][38]; /// UE-specific reference symbols (p=7...14), TM 8/9/10 uint32_t lte_gold_uespec_table[2][20][2][21]; @@ -510,7 +510,7 @@ typedef struct { uint32_t lte_gold_table[7][20][2][14]; /// UE-specific reference symbols (p=5), TM 7 - uint32_t lte_gold_uespec_port5_table[20][2][21]; + uint32_t lte_gold_uespec_port5_table[20][38]; /// ue-specific reference symbols uint32_t lte_gold_uespec_table[2][20][2][21]; diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 7a3b3bba1d..4d382c64ca 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -172,7 +172,6 @@ void lte_param_init(unsigned char N_tx, unsigned char N_tx_phy, unsigned char N_ phy_init_lte_ue(PHY_vars_UE,1,0); phy_init_lte_eNB(PHY_vars_eNB,0,0,0); - generate_pcfich_reg_mapping(&PHY_vars_UE->lte_frame_parms); generate_phich_reg_mapping(&PHY_vars_UE->lte_frame_parms); @@ -746,6 +745,7 @@ int main(int argc, char **argv) if (transmission_mode==7){ lte_gold_ue_spec_port5(PHY_vars_eNB->lte_gold_uespec_port5_table[0],Nid_cell,n_rnti); lte_gold_ue_spec_port5(PHY_vars_UE->lte_gold_uespec_port5_table,Nid_cell,n_rnti); + beamforming_weights = (int32_t **)malloc(12*N_RB_DL*sizeof(int32_t*)); for(re=0;re<12*N_RB_DL;re++){ beamforming_weights[re]=(int32_t *)malloc(n_tx_phy*sizeof(int32_t)); @@ -3064,10 +3064,12 @@ PMI_FEEDBACK: pilot2 = 6; pilot3 = 9; } + start_meas(&PHY_vars_UE->phy_proc_rx); // Inner receiver scheduling for 3 slots + for (Ns=(2*subframe); Ns<((2*subframe)+3); Ns++) { for (l=0; lofdm_demod_stats); - slot_fep(PHY_vars_UE, - l, - Ns%20, - 0, - 0); - stop_meas(&PHY_vars_UE->ofdm_demod_stats); + if(Ns==(2*subframe) || Ns==(2*subframe+1)) { + start_meas(&PHY_vars_UE->ofdm_demod_stats); + slot_fep(PHY_vars_UE, + l, + Ns%20, + 0, + 0); + stop_meas(&PHY_vars_UE->ofdm_demod_stats); + } //write_output("rxsigF0.m","rxsF0", &PHY_vars_UE->lte_ue_common_vars.rxdataF[0][0],PHY_vars_UE->lte_frame_parms.ofdm_symbol_size*nsymb,1,1); if (PHY_vars_UE->perfect_ce==1) { @@ -3120,6 +3123,11 @@ PMI_FEEDBACK: for (i=0; iN_RB_DL*12; i++) { ((int16_t *) PHY_vars_UE->lte_ue_common_vars.dl_ch_estimates[0][(aa<<1)+aarx])[2*i+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=(short)(AMP); ((int16_t *) PHY_vars_UE->lte_ue_common_vars.dl_ch_estimates[0][(aa<<1)+aarx])[2*i+1+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=0/2; + if (transmission_mode == 7){ + ((int16_t *) PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size)*2]=(short)(AMP); + ((int16_t *) PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+1+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size)*2]=0/2; + + } } } } From f905243047e2e302aa5367db10b88fe1e2746164 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Wed, 9 Sep 2015 09:58:23 +0200 Subject: [PATCH 003/413] update beamforming channel estimation frequency interpolation filter head file --- openair1/PHY/LTE_ESTIMATION/filt12_32.h | 86 ------------------------- openair1/PHY/LTE_ESTIMATION/filt16_32.h | 86 +++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 86 deletions(-) delete mode 100644 openair1/PHY/LTE_ESTIMATION/filt12_32.h create mode 100644 openair1/PHY/LTE_ESTIMATION/filt16_32.h diff --git a/openair1/PHY/LTE_ESTIMATION/filt12_32.h b/openair1/PHY/LTE_ESTIMATION/filt12_32.h deleted file mode 100644 index a5dfdb0365..0000000000 --- a/openair1/PHY/LTE_ESTIMATION/filt12_32.h +++ /dev/null @@ -1,86 +0,0 @@ -short filt12_l0[12] = { -16384,12288,8192,4096,0,0,0,0,0,0,0,0}; - -short filt12_r0[12] = { -0,0,0,0,0,4096,8192,12288,16384,20480,24576,28672}; - -short filt12_m0[12] = { -0,4096,8192,12288,16384,12288,8192,4096,0,-4096,-8192,-12288}; - -short filt12_l1[12] = { -20480,16384,12288,8192,4096,0,0,0,0,0,0,0}; - -short filt12_r1[12] = { -0,0,0,0,0,0,4096,8192,12288,16384,20480,24576}; - -short filt12_m1[12] = { --4096,0,4096,8192,12288,16384,12288,8192,4096,0,-4096,-8192}; - -short filt12_l2[12] = { -24576,20480,16384,12288,8192,4096,0,0,0,0,0,0}; - -short filt12_r2[12] = { -0,0,0,0,0,0,0,4096,8192,12288,16384,20480}; - -short filt12_m2[12] = { --8192,-4096,0,4096,8192,12288,16384,12288,8192,4096,0,-4096}; - -short filt12_l3[12] = { -28672,24576,20480,16384,12288,8192,4096,0,0,0,0,0}; - -short filt12_r3[12] = { -0,0,0,0,0,0,0,0,4096,8192,12288,16384}; - -short filt12_m3[12] = { --12288,-8192,-4096,0,4096,8192,12288,16384,12288,8192,4096,0}; - -short filt12_l0_dc[12] = { -16384,12288,8192,4096,0,0,0,0,0,0,0,0}; - -short filt12_r0_dc[12] = { -0,0,0,0,0,3276,9830,13107,16384,19660,22937,26214}; - -short filt12_m0_dc[12] = { -0,4096,8192,12288,16384,13107,6553,3276,0,-3277,-6554,-9831}; - -short filt12_l1_dc[12] = { -16384,12288,8192,4096,0,-4096,0,0,0,0,0,0}; - -short filt12_r1_dc[12] = { -0,0,0,0,0,0,6553,9830,13107,16384,19660,22937}; - -short filt12_m1_dc[12] = { --4096,0,4096,8192,12288,16384,9830,6553,3276,0,-3277,-6554}; - -short filt12_l2_dc[12] = { -26214,22937,19660,16384,13107,9830,6553,0,0,0,0,0}; - -short filt12_r2_dc[12] = { -0,0,0,0,0,0,0,4096,8192,12288,16384,20480}; - -short filt12_m2_dc[12] = { --6554,-3277,0,3276,6553,6553,16384,12288,8192,4096,0,-4096}; - -short filt12_l3_dc[12] = { -26214,22937,19660,16384,13107,9830,3276,0,0,0,0,0}; - -short filt12_r3_dc[12] = { -0,0,0,0,0,0,0,0,4096,8192,12288,16384}; - -short filt12_m3_dc[12] = { --9831,-6554,-3277,0,3276,6553,9830,16384,12288,8192,4096,0}; - -short filt12_1[12] = { -16384,16384,16384,16384,16384,16384,16384,16384,16384,16384,16384,16384}; - -short filt12_2l0[12] = { -16384,12288,8192,4096,-4096,0,0,0,0,0,0,0}; - -short filt12_2r0[12] = { -0,4096,8192,12288,16384,20480,0,0,0,0,0,0}; - -short filt12_2l1[12] = { -20480,16384,12288,8192,4096,0,0,0,0,0,0,0}; - -short filt12_2r1[12] = { --4096,0,4096,8192,12288,16384,0,0,0,0,0,0}; diff --git a/openair1/PHY/LTE_ESTIMATION/filt16_32.h b/openair1/PHY/LTE_ESTIMATION/filt16_32.h new file mode 100644 index 0000000000..3487fd3466 --- /dev/null +++ b/openair1/PHY/LTE_ESTIMATION/filt16_32.h @@ -0,0 +1,86 @@ +short filt16_l0[16] = { +16384,12288,8192,4096,0,0,0,0,0,0,0,0,0,0,0,0}; + +short filt16_r0[16] = { +0,0,0,0,0,4096,8192,12288,16384,20480,24576,28672,0,0,0,0}; + +short filt16_m0[16] = { +0,4096,8192,12288,16384,12288,8192,4096,0,-4096,-8192,-12288,0,0,0,0}; + +short filt16_l1[16] = { +20480,16384,12288,8192,4096,0,0,0,0,0,0,0,0,0,0,0}; + +short filt16_r1[16] = { +0,0,0,0,0,0,4096,8192,12288,16384,20480,24576,0,0,0,0}; + +short filt16_m1[16] = { +-4096,0,4096,8192,12288,16384,12288,8192,4096,0,-4096,-8192,0,0,0,0}; + +short filt16_l2[16] = { +24576,20480,16384,12288,8192,4096,0,0,0,0,0,0,0,0,0,0}; + +short filt16_r2[16] = { +0,0,0,0,0,0,0,4096,8192,12288,16384,20480,0,0,0,0}; + +short filt16_m2[16] = { +-8192,-4096,0,4096,8192,12288,16384,12288,8192,4096,0,-4096,0,0,0,0}; + +short filt16_l3[16] = { +28672,24576,20480,16384,12288,8192,4096,0,0,0,0,0,0,0,0,0}; + +short filt16_r3[16] = { +0,0,0,0,0,0,0,0,4096,8192,12288,16384,0,0,0,0}; + +short filt16_m3[16] = { +-12288,-8192,-4096,0,4096,8192,12288,16384,12288,8192,4096,0,0,0,0,0}; + +short filt16_l0_dc[16] = { +16384,12288,8192,4096,0,0,0,0,0,0,0,0,0,0,0,0}; + +short filt16_r0_dc[16] = { +0,0,0,0,0,3276,9830,13107,16384,19660,22937,26214,0,0,0,0}; + +short filt16_m0_dc[16] = { +0,4096,8192,12288,16384,13107,6553,3276,0,-3277,-6554,-9831,0,0,0,0}; + +short filt16_l1_dc[16] = { +16384,12288,8192,4096,0,-4096,0,0,0,0,0,0,0,0,0,0}; + +short filt16_r1_dc[16] = { +0,0,0,0,0,0,6553,9830,13107,16384,19660,22937,0,0,0,0}; + +short filt16_m1_dc[16] = { +-4096,0,4096,8192,12288,16384,9830,6553,3276,0,-3277,-6554,0,0,0,0}; + +short filt16_l2_dc[16] = { +26214,22937,19660,16384,13107,9830,6553,0,0,0,0,0,0,0,0,0}; + +short filt16_r2_dc[16] = { +0,0,0,0,0,0,0,4096,8192,12288,16384,20480,0,0,0,0}; + +short filt16_m2_dc[16] = { +-6554,-3277,0,3276,6553,6553,16384,12288,8192,4096,0,-4096,0,0,0,0}; + +short filt16_l3_dc[16] = { +26214,22937,19660,16384,13107,9830,3276,0,0,0,0,0,0,0,0,0}; + +short filt16_r3_dc[16] = { +0,0,0,0,0,0,0,0,4096,8192,12288,16384,0,0,0,0}; + +short filt16_m3_dc[16] = { +-9831,-6554,-3277,0,3276,6553,9830,16384,12288,8192,4096,0,0,0,0,0}; + +short filt16_1[16] = { +16384,16384,16384,16384,16384,16384,16384,16384,16384,16384,16384,16384}; + +short filt16_2l0[16] = { +16384,12288,8192,4096,-4096,0,0,0,0,0,0,0,0,0,0,0}; + +short filt16_2r0[16] = { +0,4096,8192,12288,16384,20480,0,0,0,0,0,0,0,0,0,0}; + +short filt16_2l1[16] = { +20480,16384,12288,8192,4096,0,0,0,0,0,0,0,0,0,0,0}; + +short filt16_2r1[16] = { +-4096,0,4096,8192,12288,16384,0,0,0,0,0,0,0,0,0,0}; From 3a5eda8cae87a53a5d4d1110d4614fb56acbdc8a Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Wed, 9 Sep 2015 11:37:24 +0200 Subject: [PATCH 004/413] cleanness and comments --- .../lte_dl_bf_channel_estimation.c | 23 +-- openair1/PHY/LTE_REFSIG/defs.h | 14 +- openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c | 158 +++++++++--------- openair1/PHY/LTE_REFSIG/lte_gold.c | 14 +- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 10 +- .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 13 +- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 22 +-- openair1/PHY/LTE_TRANSPORT/proto.h | 21 +++ 8 files changed, 142 insertions(+), 133 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c index 457aaeed56..5feb1aaeda 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c @@ -46,7 +46,7 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, unsigned char aarx,l,lprime,nsymb,skip_half=0,sss_symb,pss_symb=0,rb_alloc_ind,harq_pid,uespec_pilots=0; int beamforming_mode, ch_offset; uint8_t subframe; - int8_t uespec_nushift, uespec_poffset=0, pil_offset; + int8_t uespec_nushift, uespec_poffset=0, pil_offset=0; uint8_t pilot0,pilot1,pilot2,pilot3; short ch[2], *pil, *rxF, *dl_bf_ch, *dl_bf_ch_prev; @@ -81,7 +81,7 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, subframe = Ns>>1; - if (beamforming_mode==7) { + // if (beamforming_mode==7) { //generate ue specific pilots lprime = symbol/3-1; lte_dl_ue_spec_rx(phy_vars_ue,uespec_pilot,Ns,5,lprime,0,dlsch0_harq->nb_rb); @@ -161,11 +161,12 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, f2r = filt16_2r1; break; } - } + // beamforming mode extension + /* } else if (beamforming_mode==0) msg("lte_dl_bf_channel_estimation:No beamforming is performed.\n"); else - msg("lte_dl_bf_channel_estimation:Beamforming mode not supported yet.\n"); + msg("lte_dl_bf_channel_estimation:Beamforming mode not supported yet.\n");*/ l=symbol; @@ -183,20 +184,22 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, for (aarx=0; aarxnb_antennas_rx; aarx++) { rxF = (short *)&rxdataF[aarx][pil_offset + frame_parms->first_carrier_offset + symbol*frame_parms->ofdm_symbol_size]; - pil = (short*)uespec_pilot; + pil = (short *)uespec_pilot; dl_bf_ch = (short *)&dl_bf_ch_estimates[aarx][ch_offset]; memset(dl_bf_ch,0,4*(frame_parms->ofdm_symbol_size)); //memset(dl_bf_ch,0,2*(frame_parms->ofdm_symbol_size)); - if (phy_vars_ue->high_speed_flag==0) // multiply previous channel estimate by ch_est_alpha - if (frame_parms->Ncp==0) + if (phy_vars_ue->high_speed_flag==0) { + // multiply previous channel estimate by ch_est_alpha + if (frame_parms->Ncp==0){ multadd_complex_vector_real_scalar(dl_bf_ch-(frame_parms->ofdm_symbol_size<<1), phy_vars_ue->ch_est_alpha,dl_bf_ch-(frame_parms->ofdm_symbol_size<<1), 1,frame_parms->ofdm_symbol_size); - else + } else { msg("lte_dl_bf_channel_estimation: beamforming channel estimation not supported for TM7 Extended CP.\n"); // phy_vars_ue->ch_est_beta should be defined equaling 1/3 - + } + } //estimation and interpolation if ((frame_parms->N_RB_DL&1) == 0) // even number of RBs @@ -215,7 +218,7 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, // For second half of RBs skip DC carrier if (rb==(frame_parms->N_RB_DL>>1)) { - rxF = &rxdataF[aarx][(1 + (symbol*(frame_parms->ofdm_symbol_size)))]; + rxF = (short *)&rxdataF[aarx][(1 + (symbol*(frame_parms->ofdm_symbol_size)))]; } if (rb_alloc_ind==1) { diff --git a/openair1/PHY/LTE_REFSIG/defs.h b/openair1/PHY/LTE_REFSIG/defs.h index 6d52d4a5f7..1ced7f52e8 100644 --- a/openair1/PHY/LTE_REFSIG/defs.h +++ b/openair1/PHY/LTE_REFSIG/defs.h @@ -91,14 +91,14 @@ int lte_dl_cell_spec(PHY_VARS_eNB *phy_vars_eNB, @param p antenna index @param SS_flag Flag to indicate special subframe */ -int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, +/*int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, uint8_t UE_id, mod_sym_t *output, short amp, uint8_t Ns, uint8_t lprime, uint8_t p, - int SS_flag); + int SS_flag);*/ /*! \brief This function generates the MBSFN reference signal sequence (36-211, Sec 6.10.1.2) @param phy_vars_eNB Pointer to eNB variables @@ -128,6 +128,16 @@ int lte_dl_cell_spec_rx(PHY_VARS_UE *phy_vars_ue, unsigned char l, unsigned char p); +/*!\brief This function generates the ue-specific reference signal + * sequence (36-211, Sec 6.10.3.1) for beamforming channel estimation upon reception +@param phy_vars_ue Pointer to UE variables +@param output Output vector for OFDM symbol (Frequency Domain) +@param Ns Slot number (0..19) +@param p antenna port intex +@param lprime symbol (0,1) +@param SS_flag Flag to indicate special subframe +@param nRB_PDSCH number of allocated PDSCH RBs +*/ int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, mod_sym_t *output, unsigned char Ns, diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c b/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c index 505a6e19cd..d029f959ed 100644 --- a/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c +++ b/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c @@ -52,6 +52,7 @@ int Wbar_NCP[8][4] = {{1,1,1,1},{1,-1,1,-1},{1,1,1,1},{1,-1,1,-1},{1,1,-1,-1},{-1,-1,1,1},{1,-1,-1,1},{-1,1,1,-1}}; +/* int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, uint8_t UE_id, mod_sym_t *output, @@ -62,7 +63,7 @@ int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, int SS_flag) { - /* mod_sym_t qpsk[4],nqpsk[4]; + mod_sym_t qpsk[4],nqpsk[4]; int16_t k=0,a; int mprime,ind,ind_dword,ind_qpsk_symb; unsigned nushift,kprime; @@ -126,8 +127,9 @@ int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, LOG_E(PHY,"Illegal p %d UE specific pilots\n",p); } - return(0);*/ + return(0); } +*/ int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, @@ -139,7 +141,6 @@ int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, uint16_t nRB_PDSCH) { mod_sym_t qpsk[4],nqpsk[4],*qpsk_p,*output_p; - int16_t a; int w,mprime,ind,l,ind_dword,ind_qpsk_symb,nPRB; short pamp; @@ -172,126 +173,123 @@ int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, output_p = output; - //for (lprime=0; lprime<2; lprime++) { + ind = 3*lprime*phy_vars_ue->lte_frame_parms.N_RB_DL; + l = lprime + ((Ns&1)<<1); - ind = 3*lprime*phy_vars_ue->lte_frame_parms.N_RB_DL; - l = lprime + ((Ns&1)<<1); + // loop over pairs of PRBs, this is the periodicity of the W_bar_NCP sequence + // unroll the computations for the 6 pilots, select qpsk or nqpsk as function of W_bar_NCP + for (nPRB=0; nPRBlte_frame_parms.N_RB_DL; nPRB+=2) { - // loop over pairs of PRBs, this is the periodicity of the W_bar_NCP sequence - // unroll the computations for the 6 pilots, select qpsk or nqpsk as function of W_bar_NCP - for (nPRB=0; nPRBlte_frame_parms.N_RB_DL; nPRB+=2) { - - // First pilot - w = Wbar_NCP[p-7][l]; - qpsk_p = (w==1) ? qpsk : nqpsk; + // First pilot + w = Wbar_NCP[p-7][l]; + qpsk_p = (w==1) ? qpsk : nqpsk; - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; - *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; #ifdef DEBUG_DL_UESPEC - LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", - Ns,l,m,ind_dword,ind_qpsk_symb); - LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); #endif - output_p++; - ind++; + output_p++; + ind++; - w = Wbar_NCP[p-7][3-l]; - qpsk_p = (w==1) ? qpsk : nqpsk; + w = Wbar_NCP[p-7][3-l]; + qpsk_p = (w==1) ? qpsk : nqpsk; - // Second pilot - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; + // Second pilot + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; - *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; #ifdef DEBUG_DL_UESPEC - LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", - Ns,l,m,ind_dword,ind_qpsk_symb); - LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); #endif - output_p++; - ind++; + output_p++; + ind++; - w = Wbar_NCP[p-7][l]; - qpsk_p = (w==1) ? qpsk : nqpsk; - // Third pilot - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; + w = Wbar_NCP[p-7][l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + // Third pilot + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; - *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; #ifdef DEBUG_DL_UESPEC - LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", - Ns,l,m,ind_dword,ind_qpsk_symb); - LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); #endif - output_p++; - ind++; + output_p++; + ind++; - // Fourth pilot - w = Wbar_NCP[p-7][3-l]; - qpsk_p = (w==1) ? qpsk : nqpsk; + // Fourth pilot + w = Wbar_NCP[p-7][3-l]; + qpsk_p = (w==1) ? qpsk : nqpsk; - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; - *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; #ifdef DEBUG_DL_UESPEC - LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", - Ns,l,m,ind_dword,ind_qpsk_symb); - LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); #endif - output_p++; - ind++; + output_p++; + ind++; - w = Wbar_NCP[p-7][l]; - qpsk_p = (w==1) ? qpsk : nqpsk; + w = Wbar_NCP[p-7][l]; + qpsk_p = (w==1) ? qpsk : nqpsk; - // Fifth pilot - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; + // Fifth pilot + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; - *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; #ifdef DEBUG_DL_UESPEC - LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", - Ns,l,m,ind_dword,ind_qpsk_symb); - LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); #endif - output_p++; - ind++; + output_p++; + ind++; - w = Wbar_NCP[p-7][3-l]; - qpsk_p = (w==1) ? qpsk : nqpsk; - // Sixth pilot - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; + w = Wbar_NCP[p-7][3-l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + // Sixth pilot + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; - *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; #ifdef DEBUG_DL_UESPEC - LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", - Ns,l,m,ind_dword,ind_qpsk_symb); - LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); #endif - output_p++; - ind++; - } - // } + output_p++; + ind++; + } } else { LOG_E(PHY,"Special subframe not supported for UE specific pilots yet\n"); } @@ -301,7 +299,6 @@ int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, output_p = output; if (phy_vars_ue->lte_frame_parms.Ncp == NORMAL) { - //for (lprime=0;lprime<4;lprime++) { for (mprime=0;mprime<3*nRB_PDSCH;mprime++) { ind = 3*lprime*nRB_PDSCH+mprime; @@ -310,10 +307,9 @@ int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, *output_p = qpsk[(phy_vars_ue->lte_gold_uespec_port5_table[Ns][ind_dword]>>(2*ind_qpsk_symb))&3]; //printf("lprime=%d,ind=%d,Ns=%d,output_p=(%d,%d)\n",lprime,ind,Ns,((short *)&output_p[0])[0],((short *)&output_p[0])[1]); - *output_p++; + output_p++; } - // } } } } else { diff --git a/openair1/PHY/LTE_REFSIG/lte_gold.c b/openair1/PHY/LTE_REFSIG/lte_gold.c index cdf78b6844..5861e314ff 100644 --- a/openair1/PHY/LTE_REFSIG/lte_gold.c +++ b/openair1/PHY/LTE_REFSIG/lte_gold.c @@ -145,30 +145,27 @@ void lte_gold_ue_spec(LTE_DL_FRAME_PARMS *frame_parms,uint32_t lte_gold_uespec_t void lte_gold_ue_spec_port5(uint32_t lte_gold_uespec_port5_table[20][38],uint16_t Nid_cell, uint16_t n_rnti) { - unsigned char ns,l; + unsigned char ns; unsigned int n,x1,x2; for (ns=0; ns<20; ns++) { - //for (l=0; l<2; l++) { - - x2 = ((((ns>>1)+1)*((Nid_cell<<1)+1))<<16) + n_rnti; //x2 = frame_parms->Ncp + (Nid_cell<<1) + (1+(Nid_cell<<1))*(1 + (3*l) + (7*(1+ns))); //cinit //n = 0 - // printf("cinit (ns %d, l %d) => %d\n",ns,l,x2); + //printf("cinit (ns %d, l %d) => %d\n",ns,l,x2); x1 = 1+ (1<<31); x2=x2 ^ ((x2 ^ (x2>>1) ^ (x2>>2) ^ (x2>>3))<<31); - // skip first 50 double words (1600 bits) + //skip first 50 double words (1600 bits) //printf("n=0 : x1 %x, x2 %x\n",x1,x2); for (n=1; n<50; n++) { x1 = (x1>>1) ^ (x1>>4); x1 = x1 ^ (x1<<31) ^ (x1<<28); x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4); x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28); - // printf("x1 : %x, x2 : %x\n",x1,x2); + //printf("x1 : %x, x2 : %x\n",x1,x2); } for (n=0; n<38; n++) { @@ -177,10 +174,9 @@ void lte_gold_ue_spec_port5(uint32_t lte_gold_uespec_port5_table[20][38],uint16_ x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4); x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28); lte_gold_uespec_port5_table[ns][n] = x1^x2; - // printf("n=%d : c %x\n",n,x1^x2); + //printf("n=%d : c %x\n",n,x1^x2); } - // } } } diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index db95c2362c..a13f6a100e 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -259,7 +259,7 @@ int dlsch_encoding(unsigned char *a, unsigned char mod_order; unsigned int Kr=0,Kr_bytes,r,r_offset=0; unsigned short m=dlsch->harq_processes[harq_pid]->mcs; - uint8_t transmission_mode_7to9=0; + uint8_t beamforming_mode=0; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_FUNCTION_IN); @@ -268,12 +268,12 @@ int dlsch_encoding(unsigned char *a, mod_order = get_Qm(dlsch->harq_processes[harq_pid]->mcs); if(dlsch->harq_processes[harq_pid]->mimo_mode == TM7) - transmission_mode_7to9 = 7; + beamforming_mode = 7; else if(dlsch->harq_processes[harq_pid]->mimo_mode == TM8) - transmission_mode_7to9 = 8; + beamforming_mode = 8; else if(dlsch->harq_processes[harq_pid]->mimo_mode == TM9_10) - transmission_mode_7to9 = 9; - G = get_G(frame_parms,nb_rb,dlsch->harq_processes[harq_pid]->rb_alloc,mod_order,dlsch->harq_processes[harq_pid]->Nl,num_pdcch_symbols,frame,subframe,transmission_mode_7to9); + beamforming_mode = 9; + G = get_G(frame_parms,nb_rb,dlsch->harq_processes[harq_pid]->rb_alloc,mod_order,dlsch->harq_processes[harq_pid]->Nl,num_pdcch_symbols,frame,subframe,beamforming_mode); // if (dlsch->harq_processes[harq_pid]->Ndi == 1) { // this is a new packet diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index 89dadbbd1c..c822543477 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -338,8 +338,6 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, aarx = frame_parms->nb_antennas_rx; if (dlsch0_harq->mimo_modedl_ch_estimates_ext[0][300]); - printf("dlsch compensation: symbol %d, dl_estimates_ext[0][2400] %d \n",symbol, lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext[0][2400]); dlsch_channel_compensation(lte_ue_pdsch_vars[eNB_id]->rxdataF_ext, lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext, @@ -557,8 +555,6 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, 1); } } else if (dlsch0_harq->mimo_mode==TM7) { //TM7 - printf("dlsch compensation: symbol %d, dl_bf_estimates_ext[0][300] %d \n",symbol, *(short*)<e_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext[0][300]); - printf("dlsch compensation: symbol %d, dl_bf_estimates_ext[0][2400] %d \n",symbol, lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext[0][2400]); dlsch_channel_compensation(lte_ue_pdsch_vars[eNB_id]->rxdataF_ext, lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext, @@ -4236,9 +4232,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, unsigned short rb,nb_rb=0; unsigned char rb_alloc_ind; unsigned char i,aarx,l,nsymb,skip_half=0,sss_symb,pss_symb=0; - int *dl_ch0,*dl_ch0_ext,*rxF,*rxF_ext,*rxF_uespec; + int *dl_ch0,*dl_ch0_ext,*rxF,*rxF_ext; - unsigned char symbol_mod,pilots=0,uespec_pilots=0,j=0,k=0,poffset=0,uespec_poffset=0; + unsigned char symbol_mod,pilots=0,uespec_pilots=0,j=0,poffset=0,uespec_poffset=0; int8_t uespec_nushift = frame_parms->Nid_cell%3; symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol; @@ -4340,7 +4336,7 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, } else if (pilots==0 && uespec_pilots==1) { j=0; - k=0; + for (i=0; i<12; i++){ if (frame_parms->Ncp==0){ @@ -4519,7 +4515,6 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, } else if(pilots==0 && uespec_pilots==1){ //printf("Extracting with uespec pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half); j=0; - k=0; if (skip_half==1) { if (frame_parms->Ncp==0){ @@ -4685,7 +4680,6 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, rxF_ext+=10; } else if(pilots==0 && uespec_pilots==1) { j=0; - k=0; for (i=0; i<6; i++) { if (frame_parms->Ncp==0){ @@ -4881,7 +4875,6 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, } } else if(pilots==0 && uespec_pilots==1) { j=0; - k=0; if (skip_half==1) { if (frame_parms->Ncp==0){ diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 2d769a6ccf..5366efcc12 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -916,15 +916,12 @@ break; ((int16_t*)&tmp_sample1)[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; *jj = *jj + 1; - //printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); //printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); for (aa=0; aa>15); ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((uint16_t*)&beamforming_weights[re][aa])[1])>>15); ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((uint16_t*)&beamforming_weights[re][aa])[1])>>15); ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*((uint16_t*)&beamforming_weights[re][aa])[0])>>15); - /* ((int16_t*)&txdataF[aa][tti_offset])[0] = ((int16_t*)&tmp_sample1)[0]; - ((int16_t*)&txdataF[aa][tti_offset])[1] = ((int16_t*)&tmp_sample1)[1]; */ } //printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); @@ -1028,7 +1025,6 @@ break; ind_qpsk_symb = ind&0xf; tmp_sample1 = qpsk[(phy_vars_eNB->lte_gold_uespec_port5_table[0][Ns][ind_dword]>>(2*ind_qpsk_symb))&3]; - //printf("lprime=%d,nb_rb=%d,mprime2=%d,ind=%d,Ns=%d,tmp_sample1=(%d,%d)\n",lprime,dlsch0_harq->nb_rb,mprime2,ind,Ns,((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((uint16_t*)&beamforming_weights[re][aa])[0])>>15); ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((uint16_t*)&beamforming_weights[re][aa])[1])>>15); @@ -1037,12 +1033,12 @@ break; // ((int16_t*)&txdataF[aa][tti_offset])[0] = 0xffff; // ((int16_t*)&txdataF[aa][tti_offset])[1] = 0xffff; + //printf("lprime=%d,nb_rb=%d,mprime2=%d,ind=%d,Ns=%d\n",lprime,dlsch0_harq->nb_rb,mprime2,ind,Ns); + //printf("tmp_sample1=(%d,%d)\n",((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); + //printf("beamforing_weights[%d][%d]=(%d,%d)\n",re,aa,((int16_t*)&beamforming_weights[re][aa])[0],((int16_t*)&beamforming_weights[re][aa])[1]); + //printf("txdataF[%d][%d]= (%d,%d)\n ",aa,tti_offset,((int16_t*)&txdataF[aa][tti_offset])[0],((int16_t*)&txdataF[aa][tti_offset])[1]); - //printf("tmp_sample1=%d+i%d\n",((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); - //printf("beamforing_weights[%d][%d]=%d+i%d\n",re,aa,((int16_t*)&beamforming_weights[re][aa])[0],((int16_t*)&beamforming_weights[re][aa])[1]); - //printf("txdataF[%d][%d]= %d+i%d\n ",aa,tti_offset,((int16_t*)&txdataF[aa][tti_offset])[0],((int16_t*)&txdataF[aa][tti_offset])[1]); - - mprime2 = mprime2++; + mprime2++; } } @@ -1284,7 +1280,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, uint16_t l,rb,re_offset; uint32_t rb_alloc_ind; uint32_t *rb_alloc = dlsch0_harq->rb_alloc; - uint8_t pilots=0,ue_spec_rs=0; + uint8_t pilots=0; uint8_t skip_dc,skip_half; uint8_t mod_order0 = get_Qm(dlsch0_harq->mcs); uint8_t mod_order1 = 0; @@ -1293,7 +1289,6 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, int16_t qam16_table_a1[4],qam64_table_a1[8],qam16_table_b1[4],qam64_table_b1[8]; int16_t *qam_table_s0,*qam_table_s1; MIMO_mode_t mimo_mode = dlsch0_harq->mimo_mode; - uint8_t beamforming_mode = 0; int32_t **beamforming_weights_RB = beamforming_weights; uint8_t mprime=0,Ns; int8_t lprime=-1; @@ -1377,7 +1372,6 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, } if(mimo_mode==TM7){ //36.211 V8.6.0 2009-03 - beamforming_mode = 7; mprime = 0; if (frame_parms->Ncp==0) { // normal prefix if (l==12) @@ -1400,10 +1394,6 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, else lprime=-1; } - }else if(mimo_mode==TM8){ - beamforming_mode = 8; - }else if(mimo_mode==TM9_10){ - beamforming_mode = 9; } Ns = 2*subframe_offset+(l>=(nsymb>>1)); diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 5c3db65afc..af67b54a96 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -921,6 +921,27 @@ uint16_t dlsch_extract_rbs_dual(int32_t **rxdataF, uint32_t high_speed_flag, LTE_DL_FRAME_PARMS *frame_parms); +/** \fn dlsch_extract_rbs_TM7(int32_t **rxdataF, + int32_t **dl_bf_ch_estimates, + int32_t **rxdataF_ext, + int32_t **dl_bf_ch_estimates_ext, + uint32_t *rb_alloc, + uint8_t symbol, + uint8_t subframe, + uint32_t high_speed_flag, + LTE_DL_FRAME_PARMS *frame_parms) + \brief This function extracts the received resource blocks, both channel estimates and data symbols, + for the current allocation and for single antenna eNB transmission. + @param rxdataF Raw FFT output of received signal + @param dl_bf_ch_estimates Beamforming channel estimates of current slot + @param rxdataF_ext FFT output for RBs in this allocation + @param dl_bf_ch_estimates_ext Beamforming channel estimates for RBs in this allocation + @param rb_alloc RB allocation vector + @param symbol Symbol to extract + @param subframe Subframe number + @param high_speed_flag + @param frame_parms Pointer to frame descriptor +*/ uint16_t dlsch_extract_rbs_TM7(int32_t **rxdataF, int32_t **dl_bf_ch_estimates, int32_t **rxdataF_ext, From 70e1e0cecfbfcbfd94204b1b186198d9cb76262a Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Wed, 9 Sep 2015 11:57:44 +0200 Subject: [PATCH 005/413] more cleanness --- openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index c822543477..fdc1ae846c 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -255,8 +255,6 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, phy_vars_ue->high_speed_flag, frame_parms); - printf("dlsch extract: symbol %d, dl_bf_estimates_ext[0][300] %d \n",symbol, lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext[0][300]); - } else if(beamforming_mode>7) { LOG_W(PHY,"dlsch_demodulation:beamforming mode not supported yet.\n"); } @@ -4278,7 +4276,6 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, rxF_ext = &rxdataF_ext[aarx][symbol*(frame_parms->N_RB_DL*12)]; rxF = &rxdataF[aarx][(frame_parms->first_carrier_offset + (symbol*(frame_parms->ofdm_symbol_size)))]; //printf("symbol:%d, (symbol-1)/3:%d\n",symbol,(symbol-1)/3); - //rxF_uespec = &rxdataF_uespec_pilots[aarx][(symbol-1)/3*frame_parms->N_RB_DL*(3+frame_parms->Ncp)]; //printf("symbol, rxF_uespec offset:%d\n",symbol,(symbol-1)/3*frame_parms->N_RB_DL*(3+frame_parms->Ncp)); if ((frame_parms->N_RB_DL&1) == 0) // even number of RBs @@ -4662,7 +4659,6 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=((frame_parms->nushift+poffset)%6)) { dl_ch0_ext[j]=dl_ch0[i]; rxF_ext[j++]=rxF[i]; - // printf("**extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); } } From aca66630ffc8681c2ddb8f9ab7c95cab76eb0385 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Wed, 23 Sep 2015 16:33:18 +0200 Subject: [PATCH 006/413] pass physical antenna number as an dlsim option --- openair1/SIMULATION/LTE_PHY/dlsim.c | 30 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 4d382c64ca..624fae921e 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -374,7 +374,7 @@ int main(int argc, char **argv) num_layers = 1; perfect_ce = 0; - while ((c = getopt (argc, argv, "ahdpZDe:m:n:o:s:f:t:c:g:r:F:x:y:z:AM:N:I:i:O:R:S:C:T:b:u:v:w:B:PLl:Y")) != -1) { + while ((c = getopt (argc, argv, "ahdpZDe:m:n:o:s:f:t:c:g:r:F:x:y:q:z:AM:N:I:i:O:R:S:C:T:b:u:v:w:B:PLl:Y")) != -1) { switch (c) { case 'a': awgn_flag = 1; @@ -539,28 +539,29 @@ int main(int argc, char **argv) exit(-1); } - if (transmission_mode>1 && transmission_mode<7) { + if (transmission_mode>1 && transmission_mode<7){ n_tx = 2; n_tx_phy = n_tx; } - if (transmission_mode>=7){ - n_tx = 1; - n_tx_phy = 1; - n_rx = 1; - } break; case 'y': n_tx=atoi(optarg); - if (transmission_mode<7){ - n_tx_phy = n_tx; + if ((n_tx==0) || ((n_tx>2))) { + msg("Unsupported number of tx antennas ports %d\n",n_tx); + exit(-1); + } - if ((n_tx==0) || ((n_tx>2))) { - msg("Unsupported number of tx antennas %d\n",n_tx); - exit(-1); - } + break; + + case 'q': + n_tx_phy=atoi(optarg); + + if (transmission_mode<7 && n_tx_phy!=n_tx) { + msg("For transmission mode below TM7, physical antenna number should be the same as antenna port number.\n"); + exit(-1); } break; @@ -668,7 +669,8 @@ int main(int argc, char **argv) printf("-g [A:M] Use 3GPP 25.814 SCM-A/B/C/D('A','B','C','D') or 36-101 EPA('E'), EVA ('F'),ETU('G') models (ignores delay spread and Ricean factor), Rayghleigh8 ('H'), Rayleigh1('I'), Rayleigh1_corr('J'), Rayleigh1_anticorr ('K'), Rice8('L'), Rice1('M')\n"); printf("-F forgetting factor (0 new channel every trial, 1 channel constant\n"); printf("-x Transmission mode (1,2,6,7 for the moment)\n"); - printf("-y Number of TX antennas used in eNB\n"); + printf("-y Number of TX antennas ports used in eNB\n"); + printf("-q Number of physical TX antennas used in eNB\n"); printf("-z Number of RX antennas used in UE\n"); printf("-t MCS of interfering UE\n"); printf("-R Number of HARQ rounds (fixed)\n"); From 3353735f3c7e5e6c258fe6165cd303a13f8c29a1 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 25 Sep 2015 11:32:07 +0200 Subject: [PATCH 007/413] beamforming weights modification --- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 8 ++++---- openair1/SIMULATION/LTE_PHY/dlsim.c | 10 +++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 5366efcc12..f2ec6afdfc 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -918,10 +918,10 @@ break; //printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); for (aa=0; aa>15); - ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((uint16_t*)&beamforming_weights[re][aa])[1])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((uint16_t*)&beamforming_weights[re][aa])[1])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*((uint16_t*)&beamforming_weights[re][aa])[0])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); } //printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 624fae921e..0e993b1fe5 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -752,7 +752,8 @@ int main(int argc, char **argv) for(re=0;re<12*N_RB_DL;re++){ beamforming_weights[re]=(int32_t *)malloc(n_tx_phy*sizeof(int32_t)); for(aa=0;aachF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x*AMP); ((int16_t *) PHY_vars_UE->lte_ue_common_vars.dl_ch_estimates[k][(aa<<1)+aarx])[2*i+1+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=(int16_t)( eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].y*AMP); + + if (transmission_mode == 7){ + ((int16_t *)PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size)*2]=(int16_t)( + eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x*AMP); + ((int16_t *)PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+1+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size)*2]=(int16_t)( + eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].y*AMP); + } } } } From fdea4022d191ecce45d6c87d67830b56bf1d495d Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 25 Sep 2015 18:14:22 +0200 Subject: [PATCH 008/413] bug fixed for more than 1 physical antenna --- .../lte_dl_bf_channel_estimation.c | 15 ++++++------ .../lte_dl_channel_estimation.c | 3 --- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 24 +++++++++---------- openair1/SIMULATION/LTE_PHY/dlsim.c | 21 +++++++++------- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c index 5feb1aaeda..e36a164468 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c @@ -229,7 +229,6 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); multadd_real_vector_complex_scalar(fl,ch,dl_bf_ch,16); - //printf("rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); @@ -378,13 +377,13 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); multadd_real_vector_complex_scalar(fm,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[8],rxF[9],pil[0],pil[1],ch[0],ch[1]); pil+=2; ch[0] = (short)(((int)pil[0]*rxF[16] - (int)pil[1]*rxF[17])>>15); ch[1] = (short)(((int)pil[0]*rxF[17] + (int)pil[1]*rxF[16])>>15); multadd_real_vector_complex_scalar(fr,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[16],rxF[17],pil[0],pil[1],ch[0],ch[1]); pil+=2; } @@ -604,19 +603,19 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); multadd_real_vector_complex_scalar(fl,ch,dl_bf_ch,16); - // printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); pil+=2; ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); multadd_real_vector_complex_scalar(fm,ch,dl_bf_ch,16); - // printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[8],rxF[9],pil[0],pil[1],ch[0],ch[1]); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[8],rxF[9],pil[0],pil[1],ch[0],ch[1]); pil+=2; ch[0] = (short)(((int)pil[0]*rxF[16] - (int)pil[1]*rxF[17])>>15); ch[1] = (short)(((int)pil[0]*rxF[17] + (int)pil[1]*rxF[16])>>15); multadd_real_vector_complex_scalar(fr,ch,dl_bf_ch,16); - // printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[16],rxF[17],pil[0],pil[1],ch[0],ch[1]); + //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[16],rxF[17],pil[0],pil[1],ch[0],ch[1]); pil+=2; } @@ -641,13 +640,13 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, if (phy_vars_ue->perfect_ce == 0) { dl_bf_ch = (short *)&dl_bf_ch_estimates[aarx][ch_offset]; - printf("dlsch_bf_ch_est.c:symbol %d, dl_bf_ch (%d,%d)\n",symbol,dl_bf_ch[0],dl_bf_ch[1]); + //printf("dlsch_bf_ch_est.c:symbol %d, dl_bf_ch (%d,%d)\n",symbol,dl_bf_ch[0],dl_bf_ch[1]); if (phy_vars_ue->high_speed_flag == 0) { multadd_complex_vector_real_scalar(dl_bf_ch, 32767-phy_vars_ue->ch_est_alpha, dl_bf_ch-(frame_parms->ofdm_symbol_size<<1),0,frame_parms->ofdm_symbol_size); - printf("dlsch_bf_ch_est.c:symbol %d,dl_bf_ch (%d,%d)\n",symbol,*(dl_bf_ch-512*2),*(dl_bf_ch-512*2+1)); + //printf("dlsch_bf_ch_est.c:symbol %d,dl_bf_ch (%d,%d)\n",symbol,*(dl_bf_ch-512*2),*(dl_bf_ch-512*2+1)); } else { // high_speed_flag == 1 if (beamforming_mode==7) { if (frame_parms->Ncp==0) { diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c index 27e9018477..318d499ccd 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c @@ -42,9 +42,6 @@ int lte_dl_channel_estimation(PHY_VARS_UE *phy_vars_ue, unsigned char l, unsigned char symbol) { - - - int pilot[2][200] __attribute__((aligned(16))); unsigned char nu,aarx; unsigned short k; diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index f2ec6afdfc..685d77b802 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -1018,18 +1018,20 @@ break; //precoding UE spec RS //printf("precoding UE spec RS\n"); + ind = 3*lprime*dlsch0_harq->nb_rb+mprime2; + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + tmp_sample1 = qpsk[(phy_vars_eNB->lte_gold_uespec_port5_table[0][Ns][ind_dword]>>(2*ind_qpsk_symb))&3]; + mprime2++; + for (aa=0; aanb_rb+mprime2; - ind_dword = ind>>4; - ind_qpsk_symb = ind&0xf; - - tmp_sample1 = qpsk[(phy_vars_eNB->lte_gold_uespec_port5_table[0][Ns][ind_dword]>>(2*ind_qpsk_symb))&3]; - - ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((uint16_t*)&beamforming_weights[re][aa])[0])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((uint16_t*)&beamforming_weights[re][aa])[1])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((uint16_t*)&beamforming_weights[re][aa])[1])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*((uint16_t*)&beamforming_weights[re][aa])[0])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); + ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); // ((int16_t*)&txdataF[aa][tti_offset])[0] = 0xffff; // ((int16_t*)&txdataF[aa][tti_offset])[1] = 0xffff; @@ -1037,8 +1039,6 @@ break; //printf("tmp_sample1=(%d,%d)\n",((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); //printf("beamforing_weights[%d][%d]=(%d,%d)\n",re,aa,((int16_t*)&beamforming_weights[re][aa])[0],((int16_t*)&beamforming_weights[re][aa])[1]); //printf("txdataF[%d][%d]= (%d,%d)\n ",aa,tti_offset,((int16_t*)&txdataF[aa][tti_offset])[0],((int16_t*)&txdataF[aa][tti_offset])[1]); - - mprime2++; } } diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 0e993b1fe5..39a0095ac3 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -564,6 +564,11 @@ int main(int argc, char **argv) exit(-1); } + if (transmission_mode==7 && (n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=8 && n_tx_phy!=16 && n_tx_phy!=64)) { + msg("For TM7, physical antenna number should be an exponent of 2, maximum 64 antennas supported.\n"); + exit(-1); + } + break; case 'z': @@ -753,7 +758,7 @@ int main(int argc, char **argv) beamforming_weights[re]=(int32_t *)malloc(n_tx_phy*sizeof(int32_t)); for(aa=0;aa>(n_tx_phy>>1); } } @@ -2924,12 +2929,12 @@ PMI_FEEDBACK: } else { for (aarx=0; aarxlte_frame_parms.nb_antennas_rx; aarx++) { if (aa==0) { - r_re[aarx][i] = ((double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)]); - r_im[aarx][i] = ((double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)+1]); + r_re[aarx][i] = (double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)]; + r_im[aarx][i] = (double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)+1]; //printf("r[%d][%d]=> %f, %f\n",aarx,i,r_re[aarx][i],r_im[aarx][i]); } else { - r_re[aarx][i] += ((double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)]); - r_im[aarx][i] += ((double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)+1]); + r_re[aarx][i] += (double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)]; + r_im[aarx][i] += (double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)+1]; } } @@ -3022,10 +3027,10 @@ PMI_FEEDBACK: // printf("s_re[0][%d]=> %f , r_re[0][%d]=> %f\n",i,s_re[aa][i],i,r_re[aa][i]); /*((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i] = (short) (r_re[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); - ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i+1] = + ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i+1] = (short) (r_im[aa][i] + (iqim*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0));*/ - ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i] = (short) (r_re[aa][i]); - ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i+1] = (short) (r_im[aa][i] + (iqim*r_re[aa][i])); + ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i] = (short) r_re[aa][i]; + ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i+1] = (short) r_im[aa][i]; //printf("rxdata[%d][%d]=> %d, %d\n",aa,subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti+i,r_re[aa][i],r_im[aa][i]); } } From 1a1d843f16dabcfa8740a5e148107f4df73d899d Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 25 Sep 2015 18:34:23 +0200 Subject: [PATCH 009/413] compilation for XFORMS --- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 1 - openair1/PHY/TOOLS/lte_phy_scope.c | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 685d77b802..9176f11fae 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -1026,7 +1026,6 @@ break; mprime2++; for (aa=0; aa>15); ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); diff --git a/openair1/PHY/TOOLS/lte_phy_scope.c b/openair1/PHY/TOOLS/lte_phy_scope.c index 5fdf89f253..0b5bc1c0fa 100644 --- a/openair1/PHY/TOOLS/lte_phy_scope.c +++ b/openair1/PHY/TOOLS/lte_phy_scope.c @@ -468,6 +468,7 @@ void phy_scope_UE(FD_lte_phy_scope_ue *form, int coded_bits_per_codeword = 0; int mcs = 0; unsigned char harq_pid = 0; + int beamforming_mode = phy_vars_ue->transmission_mode[eNB_id]>6 ? phy_vars_ue->transmission_mode[eNB_id] : 0; if (phy_vars_ue->dlsch_ue[eNB_id][0]!=NULL) { harq_pid = phy_vars_ue->dlsch_ue[eNB_id][0]->current_harq_pid; @@ -497,7 +498,8 @@ void phy_scope_UE(FD_lte_phy_scope_ue *form, phy_vars_ue->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->Nl, num_pdcch_symbols, frame, - subframe); + subframe, + beamforming_mode); } else { coded_bits_per_codeword = 0; //frame_parms->N_RB_DL*12*get_Qm(mcs)*(frame_parms->symbols_per_tti); } From e5013e5327608e42fc945dc9b9eb829b859863c8 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 29 Sep 2015 10:34:55 +0200 Subject: [PATCH 010/413] move DL beamforming channel estimation to dlsim top level file --- openair1/PHY/MODULATION/slot_fep.c | 11 ----------- openair1/SIMULATION/LTE_PHY/dlsim.c | 14 +++++++++++++- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/openair1/PHY/MODULATION/slot_fep.c b/openair1/PHY/MODULATION/slot_fep.c index a7639d9291..5597f3f7fb 100644 --- a/openair1/PHY/MODULATION/slot_fep.c +++ b/openair1/PHY/MODULATION/slot_fep.c @@ -247,17 +247,6 @@ int slot_fep(PHY_VARS_UE *phy_vars_ue, } } - if(phy_vars_ue->transmission_mode[eNB_id] == 7) { - - if(frame_parms->Ncp==0 && ((symbol==3) || (symbol==6) || (symbol==9) || (symbol==12))) - lte_dl_bf_channel_estimation(phy_vars_ue,eNB_id,0,Ns,5,symbol); - - else if(frame_parms->Ncp==1 && ((symbol==4) || (symbol==7) || (symbol==10))) - msg("slot_fep(slot_fep.c):channel estimation not supported yet for TM7 extented CP.\n"); - - } else if(phy_vars_ue->transmission_mode[eNB_id] > 7) { - msg("slot_fep(slot_fep.c):transmission mode not supported yet.\n"); - } } #ifdef DEBUG_FEP diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 39a0095ac3..96c6dfc14e 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -564,7 +564,7 @@ int main(int argc, char **argv) exit(-1); } - if (transmission_mode==7 && (n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=8 && n_tx_phy!=16 && n_tx_phy!=64)) { + if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=8 && n_tx_phy!=16 && n_tx_phy!=64)) { msg("For TM7, physical antenna number should be an exponent of 2, maximum 64 antennas supported.\n"); exit(-1); } @@ -3360,6 +3360,18 @@ PMI_FEEDBACK: } if (dlsch_active == 1) { + + if (transmission_mode==7) { + if (PHY_vars_UE->lte_frame_parms.Ncp==0) { + if ((Ns==(2*subframe) && ((l==3) || (l==6))) || + Ns==(1+(2*subframe)) && ((l==3) || (l==6))) { + lte_dl_bf_channel_estimation(PHY_vars_UE,eNB_id,0,Ns,5,l+7*(Ns%2==1)); + } + } else { + msg("Beamforming channel estimation not supported yet for TM7 extented CP.\n"); + } + } + if ((Ns==(1+(2*subframe))) && (l==0)) {// process PDSCH symbols 1,2,3,4,5,(6 Normal Prefix) if ((transmission_mode == 5) && From d89807b6ebaefe5872fa76e30ef6fc71e82ed22a Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 29 Sep 2015 10:35:47 +0200 Subject: [PATCH 011/413] skip half creterion for PSS RBs --- .../lte_dl_bf_channel_estimation.c | 8 ++--- .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 31 +++++++------------ 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c index e36a164468..909c7bd12e 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c @@ -308,8 +308,7 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, skip_half=2; } - if ((frame_parms->frame_type == TDD) && - (subframe==6)) { //TDD Subframe 6 + if ((frame_parms->frame_type == TDD) && ((subframe==1)||(subframe==6))) { //TDD Subframe 1 and 6 if ((rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { rb_alloc_ind = 0; } @@ -432,7 +431,7 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, } } - if ((frame_parms->frame_type == TDD) && (subframe==6)) { + if ((frame_parms->frame_type == TDD) && ((subframe==1)||(subframe==6))) { //PSS if ((rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { rb_alloc_ind = 0; @@ -540,8 +539,7 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, skip_half=2; } - if ((frame_parms->frame_type == TDD) && - (subframe==6)) { //TDD Subframe 6 + if ((frame_parms->frame_type == TDD) && ((subframe==1)||(subframe==6))) { //TDD Subframe 1 and 6 if ((rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { rb_alloc_ind = 0; } diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index fdc1ae846c..0d7ed4f16d 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -4265,18 +4265,14 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, for (aarx=0; aarxnb_antennas_rx; aarx++) { if (high_speed_flag == 1) - //dl_ch0 = &dl_bf_ch_estimates[aarx][5+(symbol*(frame_parms->ofdm_symbol_size))]; dl_ch0 = &dl_bf_ch_estimates[aarx][symbol*(frame_parms->ofdm_symbol_size)]; else - //dl_ch0 = &dl_bf_ch_estimates[aarx][5]; dl_ch0 = &dl_bf_ch_estimates[aarx][0]; dl_ch0_ext = &dl_bf_ch_estimates_ext[aarx][symbol*(frame_parms->N_RB_DL*12)]; rxF_ext = &rxdataF_ext[aarx][symbol*(frame_parms->N_RB_DL*12)]; rxF = &rxdataF[aarx][(frame_parms->first_carrier_offset + (symbol*(frame_parms->ofdm_symbol_size)))]; - //printf("symbol:%d, (symbol-1)/3:%d\n",symbol,(symbol-1)/3); - //printf("symbol, rxF_uespec offset:%d\n",symbol,(symbol-1)/3*frame_parms->N_RB_DL*(3+frame_parms->Ncp)); if ((frame_parms->N_RB_DL&1) == 0) // even number of RBs for (rb=0; rbN_RB_DL; rb++) { @@ -4367,7 +4363,6 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, } else { // Odd number of RBs for (rb=0; rbN_RB_DL>>1; rb++) { - // printf("dlch_ext %d\n",dl_ch0_ext-&dl_ch_estimates_ext[aarx][0]); skip_half=0; if (rb < 32) @@ -4424,8 +4419,7 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, skip_half=2; } - if ((frame_parms->frame_type == TDD) && - (subframe==6)) { //TDD Subframe 6 + if ((frame_parms->frame_type == TDD) && ((subframe==1)||(subframe==6))) { //TDD Subframe 1 and 6 if ((rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { rb_alloc_ind = 0; } @@ -4441,7 +4435,7 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, //printf("rb %d/symbol %d pilots %d, uespec_pilots %d, (skip_half %d)\n",rb,l,pilots,uespec_pilots,skip_half); if (pilots==0 && uespec_pilots==0) { - // printf("Extracting w/o pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half); + //printf("Extracting w/o pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half); if (skip_half==1) { memcpy(dl_ch0_ext,dl_ch0,6*sizeof(int)); @@ -4462,13 +4456,14 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, } else { memcpy(dl_ch0_ext,dl_ch0,12*sizeof(int)); - for (i=0; i<12; i++) + for (i=0; i<12; i++){ rxF_ext[i]=rxF[i]; - + //printf("symbol %d, extract rb %d, re %d => (%d,%d)\n",symbol,rb,i,*(short *)&rxF[i],*(1+(short*)&rxF[i])); + } dl_ch0_ext+=12; rxF_ext+=12; } - } else if (pilots==1 && uespec_pilots==0){ + } else if (pilots==1 && uespec_pilots==0) { // printf("Extracting with pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half); j=0; @@ -4564,7 +4559,6 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ rxF_ext[j] = rxF[i]; dl_ch0_ext[j++] = dl_ch0[i]; - //printf("symbol %d, extract rb %d, re %d => (%d,%d)\n",symbol,rb,i,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); //printf("symbol %d, extract rb %d, re %d, j %d => (%d,%d)\n",symbol,rb,i,j-1,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); } } else{ @@ -4625,8 +4619,7 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, } } - if ((frame_parms->frame_type == TDD) && - (subframe==6)) { + if ((frame_parms->frame_type == TDD) && ((subframe==1)||(subframe==6))) { //PSS if ((rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { rb_alloc_ind = 0; @@ -4766,21 +4759,19 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, else if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)+3)) && (l==sss_symb)) skip_half=2; + //PSS if (frame_parms->frame_type == FDD) { - //PSS if (((subframe==0)||(subframe==5)) && (rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { rb_alloc_ind = 0; } - //PSS if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)-3)) && (l==pss_symb)) skip_half=1; else if (((subframe==0)||(subframe==5)) && (rb==((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb)) skip_half=2; } - if ((frame_parms->frame_type == TDD) && - (subframe==6)) { //TDD Subframe 6 + if ((frame_parms->frame_type == TDD) && ((subframe==1)||(subframe==6))) { //TDD Subframe 1 and 6 if ((rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { rb_alloc_ind = 0; } @@ -4814,7 +4805,7 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, memcpy(dl_ch0_ext,dl_ch0+6,6*sizeof(int)); for (i=0; i<6; i++) - rxF_ext[i]=rxF[(i+6)]; + rxF_ext[i]=rxF[i+6]; dl_ch0_ext+=6; rxF_ext+=6; @@ -4898,7 +4889,7 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if(frame_parms->Ncp==0){ for (i=0; i<6; i++) { if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ - rxF_ext[j]=rxF[(i+6)]; + rxF_ext[j]=rxF[i+6]; dl_ch0_ext[j++]=dl_ch0[i+6]; } } From a6f2310e4b5e6e0dd42d42113c41bc27a2eb550e Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 29 Sep 2015 14:02:57 +0200 Subject: [PATCH 012/413] add beamforming mode as an input parameter of llr computation --- .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 6 ++- .../PHY/LTE_TRANSPORT/dlsch_llr_computation.c | 46 +++++++++++-------- openair1/PHY/LTE_TRANSPORT/proto.h | 8 +++- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index 0d7ed4f16d..b2e8218b37 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -739,7 +739,8 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, lte_ue_pdsch_vars[eNB_id]->dl_ch_mag0, symbol,first_symbol_flag,nb_rb, adjust_G2(frame_parms,dlsch0_harq->rb_alloc,4,subframe,symbol), - lte_ue_pdsch_vars[eNB_id]->llr128); + lte_ue_pdsch_vars[eNB_id]->llr128, + beamforming_mode); } else if (i_mod == 2) { dlsch_16qam_qpsk_llr(frame_parms, lte_ue_pdsch_vars[eNB_id]->rxdataF_comp0, @@ -785,7 +786,8 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, lte_ue_pdsch_vars[eNB_id]->dl_ch_magb0, symbol,first_symbol_flag,nb_rb, adjust_G2(frame_parms,dlsch0_harq->rb_alloc,6,subframe,symbol), - lte_ue_pdsch_vars[eNB_id]->llr128); + lte_ue_pdsch_vars[eNB_id]->llr128, + beamforming_mode); } else if (i_mod == 2) { dlsch_64qam_qpsk_llr(frame_parms, lte_ue_pdsch_vars[eNB_id]->rxdataF_comp0, diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c index 951e4afcd0..9ff04cb0ec 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c @@ -1,4 +1,5 @@ -/******************************************************************************* +/* +***************************************************************************** OpenAirInterface Copyright(c) 1999 - 2014 Eurecom @@ -663,16 +664,15 @@ int dlsch_qpsk_llr(LTE_DL_FRAME_PARMS *frame_parms, if ((symbol_mod==0) || (symbol_mod==(4-frame_parms->Ncp))) { if (frame_parms->mode1_flag==0 && beamforming_mode!=7) - len = (nb_rb*8);// - (2*pbch_pss_sss_adjust/3); + len = (nb_rb*8) - (2*pbch_pss_sss_adjust/3); else - len = (nb_rb*10);// - (5*pbch_pss_sss_adjust/6); + len = (nb_rb*10) - (5*pbch_pss_sss_adjust/6); } else if((beamforming_mode==7) && (frame_parms->Ncp==0) && (symbol==3 || symbol==6 || symbol==9 || symbol==12)){ - len = (nb_rb*9); + len = (nb_rb*9) - (3*pbch_pss_sss_adjust/4); } else if((beamforming_mode==7) && (frame_parms->Ncp==1) && (symbol==4 || symbol==7 || symbol==10)){ - len = (nb_rb*8); - } - else { - len = (nb_rb*12);// - pbch_pss_sss_adjust; + len = (nb_rb*8) - (2*pbch_pss_sss_adjust/3); + } else { + len = (nb_rb*12) - pbch_pss_sss_adjust; } // printf("dlsch_qpsk_llr: symbol %d,nb_rb %d, len %d,pbch_pss_sss_adjust %d\n",symbol,nb_rb,len,pbch_pss_sss_adjust); @@ -702,7 +702,8 @@ void dlsch_16qam_llr(LTE_DL_FRAME_PARMS *frame_parms, uint8_t first_symbol_flag, unsigned short nb_rb, uint16_t pbch_pss_sss_adjust, - int16_t **llr32p) + int16_t **llr32p, + uint8_t beamforming_mode) { __m128i *rxF = (__m128i*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)]; @@ -724,12 +725,16 @@ void dlsch_16qam_llr(LTE_DL_FRAME_PARMS *frame_parms, ch_mag = (__m128i*)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)]; if ((symbol_mod==0) || (symbol_mod==(4-frame_parms->Ncp))) { - if (frame_parms->mode1_flag==0) - len = nb_rb*8 - (2*pbch_pss_sss_adjust/3); + if (frame_parms->mode1_flag==0 && beamforming_mode!=7) + len = (nb_rb*8) - (2*pbch_pss_sss_adjust/3); else - len = nb_rb*10 - (5*pbch_pss_sss_adjust/6); + len = (nb_rb*10) - (5*pbch_pss_sss_adjust/6); + } else if((beamforming_mode==7) && (frame_parms->Ncp==0) && (symbol==3 || symbol==6 || symbol==9 || symbol==12)){ + len = (nb_rb*9) - (3*pbch_pss_sss_adjust/4); + } else if((beamforming_mode==7) && (frame_parms->Ncp==1) && (symbol==4 || symbol==7 || symbol==10)){ + len = (nb_rb*8) - (2*pbch_pss_sss_adjust/3); } else { - len = nb_rb*12 - pbch_pss_sss_adjust; + len = (nb_rb*12) - pbch_pss_sss_adjust; } // update output pointer according to number of REs in this symbol (<<2 because 4 bits per RE) @@ -778,7 +783,8 @@ void dlsch_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms, uint8_t first_symbol_flag, unsigned short nb_rb, uint16_t pbch_pss_sss_adjust, - short **llr_save) + short **llr_save, + uint8_t beamforming_mode) { __m128i *rxF = (__m128i*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)]; @@ -799,12 +805,16 @@ void dlsch_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms, ch_magb = (__m128i*)&dl_ch_magb[0][(symbol*frame_parms->N_RB_DL*12)]; if ((symbol_mod==0) || (symbol_mod==(4-frame_parms->Ncp))) { - if (frame_parms->mode1_flag==0) - len = nb_rb*8 - (2*pbch_pss_sss_adjust/3); + if (frame_parms->mode1_flag==0 && beamforming_mode!=7) + len = (nb_rb*8) - (2*pbch_pss_sss_adjust/3); else - len = nb_rb*10 - (5*pbch_pss_sss_adjust/6); + len = (nb_rb*10) - (5*pbch_pss_sss_adjust/6); + } else if((beamforming_mode==7) && (frame_parms->Ncp==0) && (symbol==3 || symbol==6 || symbol==9 || symbol==12)){ + len = (nb_rb*9) - (3*pbch_pss_sss_adjust/4); + } else if((beamforming_mode==7) && (frame_parms->Ncp==1) && (symbol==4 || symbol==7 || symbol==10)){ + len = (nb_rb*8) - (2*pbch_pss_sss_adjust/3); } else { - len = nb_rb*12 - pbch_pss_sss_adjust; + len = (nb_rb*12) - pbch_pss_sss_adjust; } llr2 = llr; diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index af67b54a96..3879c11db8 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -718,6 +718,7 @@ int32_t dlsch_qpsk_llr(LTE_DL_FRAME_PARMS *frame_parms, @param nb_rb number of RBs for this allocation @param pbch_pss_sss_adjust Adjustment factor in RE for PBCH/PSS/SSS allocations @param llr128p pointer to pointer to symbol in dlsch_llr + @param beamforming_mode beamforming mode */ void dlsch_16qam_llr(LTE_DL_FRAME_PARMS *frame_parms, @@ -728,7 +729,8 @@ void dlsch_16qam_llr(LTE_DL_FRAME_PARMS *frame_parms, uint8_t first_symbol_flag, uint16_t nb_rb, uint16_t pbch_pss_sss_adjust, - int16_t **llr128p); + int16_t **llr128p, + uint8_t beamforming_mode); /** \brief This function generates log-likelihood ratios (decoder input) for single-stream 16QAM received waveforms @@ -741,6 +743,7 @@ void dlsch_16qam_llr(LTE_DL_FRAME_PARMS *frame_parms, @param first_symbol_flag @param nb_rb number of RBs for this allocation @param pbch_pss_sss_adjust PBCH/PSS/SSS RE adjustment (in REs) + @param beamforming_mode beamforming mode */ void dlsch_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms, int32_t **rxdataF_comp, @@ -751,7 +754,8 @@ void dlsch_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms, uint8_t first_symbol_flag, uint16_t nb_rb, uint16_t pbch_pss_sss_adjust, - short **llr_save); + short **llr_save, + uint8_t beamforming_mode); /** \fn dlsch_siso(LTE_DL_FRAME_PARMS *frame_parms, int32_t **rxdataF_comp, From d09d042806e7f8a4159e57973cab78ddbc87d1ab Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 29 Sep 2015 17:00:17 +0200 Subject: [PATCH 013/413] bug fixed for symbols to activate beamforming channel estimation --- openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c | 1 - openair1/SIMULATION/LTE_PHY/dlsim.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c index 909c7bd12e..8b9405b499 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c @@ -81,7 +81,6 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, subframe = Ns>>1; - // if (beamforming_mode==7) { //generate ue specific pilots lprime = symbol/3-1; lte_dl_ue_spec_rx(phy_vars_ue,uespec_pilot,Ns,5,lprime,0,dlsch0_harq->nb_rb); diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 96c6dfc14e..1b483b35f6 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -3364,7 +3364,7 @@ PMI_FEEDBACK: if (transmission_mode==7) { if (PHY_vars_UE->lte_frame_parms.Ncp==0) { if ((Ns==(2*subframe) && ((l==3) || (l==6))) || - Ns==(1+(2*subframe)) && ((l==3) || (l==6))) { + Ns==(1+(2*subframe)) && ((l==2) || (l==5))) { lte_dl_bf_channel_estimation(PHY_vars_UE,eNB_id,0,Ns,5,l+7*(Ns%2==1)); } } else { From b6b7bd1c1927adb68d43685093ab5bd979bb6c11 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 1 Oct 2015 17:38:02 +0200 Subject: [PATCH 014/413] comment writing to file line --- openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c index 8b9405b499..faf366c520 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c @@ -84,7 +84,7 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, //generate ue specific pilots lprime = symbol/3-1; lte_dl_ue_spec_rx(phy_vars_ue,uespec_pilot,Ns,5,lprime,0,dlsch0_harq->nb_rb); - write_output("uespec_pilot_rx.m","uespec_pilot",uespec_pilot,300,1,1); + //write_output("uespec_pilot_rx.m","uespec_pilot",uespec_pilot,300,1,1); if (frame_parms->Ncp==0){ if (symbol==3 || symbol==6 || symbol==9 || symbol==12) From dc636f2b44e7f3e8a6089e32af73ebadde68e479 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 1 Oct 2015 17:42:20 +0200 Subject: [PATCH 015/413] calculate channel level for TM7 --- .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 74 ++++++++++++++++++- openair1/PHY/LTE_TRANSPORT/proto.h | 6 ++ 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index b2e8218b37..e87519225b 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -280,8 +280,8 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, avg, symbol, nb_rb); - else - dlsch_channel_level(lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext, + else if (beamforming_mode==7) + dlsch_channel_level_TM7(lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext, frame_parms, avg, symbol, @@ -2972,6 +2972,76 @@ void dlsch_channel_level_TM56(int **dl_ch_estimates_ext, #endif } +//compute average channel_level for TM7 +void dlsch_channel_level_TM7(int **dl_bf_ch_estimates_ext, + LTE_DL_FRAME_PARMS *frame_parms, + int *avg, + uint8_t symbol, + unsigned short nb_rb) +{ + +#if defined(__x86_64__)||defined(__i386__) + + short rb; + unsigned char aatx,aarx,nre=12,symbol_mod; + __m128i *dl_ch128,avg128D; + + symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol; + + for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) + for (aarx=0; aarxnb_antennas_rx; aarx++) { + //clear average level + avg128D = _mm_setzero_si128(); + // 5 is always a symbol with no pilots for both normal and extended prefix + + dl_ch128=(__m128i *)&dl_bf_ch_estimates_ext[(aatx<<1)+aarx][symbol*frame_parms->N_RB_DL*12]; + + for (rb=0; rbNcp-1)))&&(frame_parms->mode1_flag==0)) { + dl_ch128+=2; + } else { + avg128D = _mm_add_epi32(avg128D,_mm_madd_epi16(dl_ch128[2],dl_ch128[2])); + dl_ch128+=3; + } + + /* + if (rb==0) { + print_shorts("dl_ch128",&dl_ch128[0]); + print_shorts("dl_ch128",&dl_ch128[1]); + print_shorts("dl_ch128",&dl_ch128[2]); + } + */ + } + + if (((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp-1)))) + nre=10; + else if ((frame_parms->Ncp==0) && (symbol==3 || symbol==6 || symbol==9 || symbol==12)) + nre=9; + else if ((frame_parms->Ncp==1) && (symbol==4 || symbol==7 || symbol==9)) + nre=8; + else + nre=12; + + avg[(aatx<<1)+aarx] = (((int*)&avg128D)[0] + + ((int*)&avg128D)[1] + + ((int*)&avg128D)[2] + + ((int*)&avg128D)[3])/(nb_rb*nre); + + // printf("Channel level : %d\n",avg[(aatx<<1)+aarx]); + } + + _mm_empty(); + _m_empty(); + +#elif defined(__arm__) + +#endif +} void dlsch_alamouti(LTE_DL_FRAME_PARMS *frame_parms, int **rxdataF_comp, diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 3879c11db8..0bb327aa8a 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -1046,6 +1046,12 @@ void dlsch_channel_level_TM56(int32_t **dl_ch_estimates_ext, uint8_t symbol_mod, uint16_t nb_rb); +void dlsch_channel_level_TM7(int32_t **dl_bf_ch_estimates_ext, + LTE_DL_FRAME_PARMS *frame_parms, + int32_t *avg, + uint8_t pilots_flag, + uint16_t nb_rb); + void dlsch_scale_channel(int32_t **dl_ch_estimates_ext, LTE_DL_FRAME_PARMS *frame_parms, LTE_UE_DLSCH_t **dlsch_ue, From 7882472b73bfbf77ca6b4ba6e054bf6450facd3d Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 1 Oct 2015 17:43:46 +0200 Subject: [PATCH 016/413] revert dlsch_llr_computation --- openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c index 9ff04cb0ec..551043ea96 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_llr_computation.c @@ -663,7 +663,7 @@ int dlsch_qpsk_llr(LTE_DL_FRAME_PARMS *frame_parms, if ((symbol_mod==0) || (symbol_mod==(4-frame_parms->Ncp))) { - if (frame_parms->mode1_flag==0 && beamforming_mode!=7) + if (frame_parms->mode1_flag==0) len = (nb_rb*8) - (2*pbch_pss_sss_adjust/3); else len = (nb_rb*10) - (5*pbch_pss_sss_adjust/6); @@ -725,7 +725,7 @@ void dlsch_16qam_llr(LTE_DL_FRAME_PARMS *frame_parms, ch_mag = (__m128i*)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)]; if ((symbol_mod==0) || (symbol_mod==(4-frame_parms->Ncp))) { - if (frame_parms->mode1_flag==0 && beamforming_mode!=7) + if (frame_parms->mode1_flag==0) len = (nb_rb*8) - (2*pbch_pss_sss_adjust/3); else len = (nb_rb*10) - (5*pbch_pss_sss_adjust/6); @@ -805,7 +805,7 @@ void dlsch_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms, ch_magb = (__m128i*)&dl_ch_magb[0][(symbol*frame_parms->N_RB_DL*12)]; if ((symbol_mod==0) || (symbol_mod==(4-frame_parms->Ncp))) { - if (frame_parms->mode1_flag==0 && beamforming_mode!=7) + if (frame_parms->mode1_flag==0) len = (nb_rb*8) - (2*pbch_pss_sss_adjust/3); else len = (nb_rb*10) - (5*pbch_pss_sss_adjust/6); From b40ed6af9ba73870fa9f232bccd3e872a7c97649 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 2 Oct 2015 11:44:30 +0200 Subject: [PATCH 017/413] TM7 works for dlsim. --- openair1/SIMULATION/LTE_PHY/dlsim.c | 67 +++++++++++++++++++---------- targets/RT/USER/Makefile | 10 +++-- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 1b483b35f6..27ca4b8fbd 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -253,7 +253,8 @@ int main(int argc, char **argv) double forgetting_factor=0.0; //in [0,1] 0 means a new channel every time, 1 means keep the same channel double iqim=0.0; - uint8_t extended_prefix_flag=0,transmission_mode=1,n_tx=1,n_rx=2,n_tx_phy=1; + uint8_t extended_prefix_flag=0,transmission_mode=1,n_tx=1,n_rx=1; + uint16_t n_tx_phy=1; uint16_t Nid_cell=0; int32_t **beamforming_weights; @@ -564,8 +565,9 @@ int main(int argc, char **argv) exit(-1); } - if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=8 && n_tx_phy!=16 && n_tx_phy!=64)) { - msg("For TM7, physical antenna number should be an exponent of 2, maximum 64 antennas supported.\n"); + //if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=8 && n_tx_phy!=16 && n_tx_phy!=64 && n_tx_phy!=128)) { + if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=4 && n_tx_phy!=16 && n_tx_phy!=64)) { + msg("For TM7, physical antenna number should be an exponent of 4, maximum 64 antennas supported.\n"); exit(-1); } @@ -723,8 +725,10 @@ int main(int argc, char **argv) NB_RB=conv_nprb(0,DLSCH_RB_ALLOC,N_RB_DL); - if ((transmission_mode > 1) && (n_tx_phy == 1)) - printf("n_tx_phy must be >1 for transmission_mode %d\n",transmission_mode); + if ((transmission_mode>1&&transmission_mode<7) && (n_tx_phy == 1)){ + msg("n_tx_phy must be >1 for transmission_mode %d\n",transmission_mode); + exit(-1); + } #ifdef XFORMS fl_initialize (&argc, argv, NULL, 0, 0); @@ -756,10 +760,19 @@ int main(int argc, char **argv) beamforming_weights = (int32_t **)malloc(12*N_RB_DL*sizeof(int32_t*)); for(re=0;re<12*N_RB_DL;re++){ beamforming_weights[re]=(int32_t *)malloc(n_tx_phy*sizeof(int32_t)); - for(aa=0;aa>(n_tx_phy>>1); + for(aa=0;aa>1; + else if (n_tx_phy==16) + beamforming_weights[re][aa] = 0x00007fff>>2; + else if (n_tx_phy==64) + beamforming_weights[re][aa] = 0x00007fff>>3; + } } + printf("***n_tx_phy=%d,n_tx_phy>>2=%d,beamforming_weights=%d\n",n_tx_phy,n_tx_phy>>2,beamforming_weights[0][0]); } eNB_id_i = PHY_vars_UE->n_connected_eNB; @@ -799,9 +812,9 @@ int main(int argc, char **argv) SCM_A, SCM_B, SCM_C, SCM_D, EPA, EVA, ETU, Rayleigh8, Rayleigh1, Rayleigh1_corr, Rayleigh1_anticorr, Rice1, Rice8); if(transmission_mode==5) - sprintf(bler_fname,"bler_tx%d_chan%d_nrx%d_mcs%d_mcsi%d_u%d_imod%d.csv",transmission_mode,channel_model,n_rx,mcs1,mcs_i,dual_stream_UE,i_mod); + sprintf(bler_fname,"bler_tm%d_chan%d_perfce%d_ntx%d_nrx%d_mcs%d_mcsi%d_u%d_imod%d.csv",transmission_mode,channel_model,perfect_ce,n_tx_phy,n_rx,mcs1,mcs_i,dual_stream_UE,i_mod); else - sprintf(bler_fname,"bler_tx%d_chan%d_nrx%d_mcs%d.csv",transmission_mode,channel_model,n_rx,mcs1); + sprintf(bler_fname,"bler_tm%d_chan%d_perfce%d_ntx%d_nrx%d_mcs%d.csv",transmission_mode,channel_model,perfect_ce,n_tx_phy,n_rx,mcs1); bler_fd = fopen(bler_fname,"w"); fprintf(bler_fd,"SNR; MCS; TBS; rate; err0; trials0; err1; trials1; err2; trials2; err3; trials3; dci_err\n"); @@ -2167,7 +2180,7 @@ int main(int argc, char **argv) ret = PHY_vars_UE->dlsch_ue[0][0]->max_turbo_iterations+1; while ((round < num_rounds) && (ret > PHY_vars_UE->dlsch_ue[0][0]->max_turbo_iterations)) { - printf("Trial %d, round %d\n",trials,round); + //printf("Trial %d, round %d\n",trials,round); round_trials[round]++; if(transmission_mode>=5&&transmission_mode<7) @@ -2185,8 +2198,9 @@ int main(int argc, char **argv) PMI_FEEDBACK: - printf("Trial %d : Round %d, pmi_feedback %d \n",trials,round,pmi_feedback); - for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { + //printf("Trial %d : Round %d, pmi_feedback %d \n",trials,round,pmi_feedback); + //for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { + for (aa=0; aanb_antennas_tx_phy; aa++) { memset(&PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id][aa][0],0,FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t)); } @@ -3025,10 +3039,10 @@ PMI_FEEDBACK: for (i=0; i<2*frame_parms->samples_per_tti; i++) { for (aa=0; aalte_frame_parms.nb_antennas_rx; aa++) { // printf("s_re[0][%d]=> %f , r_re[0][%d]=> %f\n",i,s_re[aa][i],i,r_re[aa][i]); - /*((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i] = - (short) (r_re[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); - ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i+1] = - (short) (r_im[aa][i] + (iqim*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0));*/ + //((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i] = + // (short) (r_re[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); + // ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i+1] = + // (short) (r_im[aa][i] + (iqim*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i] = (short) r_re[aa][i]; ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i+1] = (short) r_im[aa][i]; //printf("rxdata[%d][%d]=> %d, %d\n",aa,subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti+i,r_re[aa][i],r_im[aa][i]); @@ -3081,7 +3095,7 @@ PMI_FEEDBACK: for (Ns=(2*subframe); Ns<((2*subframe)+3); Ns++) { for (l=0; llte_ue_common_vars.dl_ch_estimates[0][(aa<<1)+aarx])[2*i+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=(short)(AMP); ((int16_t *) PHY_vars_UE->lte_ue_common_vars.dl_ch_estimates[0][(aa<<1)+aarx])[2*i+1+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=0/2; if (transmission_mode == 7){ - ((int16_t *) PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size)*2]=(short)(AMP); - ((int16_t *) PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+1+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size)*2]=0/2; - + if (PHY_vars_UE->high_speed_flag==0){ + ((int16_t *) PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i]=(short)(AMP); + ((int16_t *) PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+1]=0/2; + } else { + ((int16_t *) PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size)*2]=(short)(AMP); + ((int16_t *) PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+1+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size)*2]=0/2; + } } } } @@ -3365,7 +3383,8 @@ PMI_FEEDBACK: if (PHY_vars_UE->lte_frame_parms.Ncp==0) { if ((Ns==(2*subframe) && ((l==3) || (l==6))) || Ns==(1+(2*subframe)) && ((l==2) || (l==5))) { - lte_dl_bf_channel_estimation(PHY_vars_UE,eNB_id,0,Ns,5,l+7*(Ns%2==1)); + if (perfect_ce==0) + lte_dl_bf_channel_estimation(PHY_vars_UE,eNB_id,0,Ns,5,l+7*(Ns%2==1)); } } else { msg("Beamforming channel estimation not supported yet for TM7 extented CP.\n"); @@ -4297,10 +4316,14 @@ PMI_FEEDBACK: free(r_im[i]); } + for(i=0;i<12*N_RB_DL;i++) + free(beamforming_weights[i]); + free(s_re); free(s_im); free(r_re); free(r_im); + free(beamforming_weights); // lte_sync_time_free(); diff --git a/targets/RT/USER/Makefile b/targets/RT/USER/Makefile index 531907d6af..72f9587e0a 100644 --- a/targets/RT/USER/Makefile +++ b/targets/RT/USER/Makefile @@ -194,7 +194,7 @@ CFLAGS += -DHARD_RT endif ifeq ($(EMOS),1) -CFLAGS += -D_FILE_OFFSET_BITS=64 -DEMOS #-DEMOS_CHANNEL +CFLAGS += -D_FILE_OFFSET_BITS=64 #-DEMOS -DEMOS_CHANNEL LDFLAGS += -lgps endif @@ -317,10 +317,12 @@ synctest_UE: synctest cp synctest synctest_UE drivers: - cd $(OPENAIR2_DIR) && make clean && make nasmesh_netlink.ko - cd $(OPENAIR2_DIR)/NAS/DRIVER/MESH/RB_TOOL && make clean && make - cd $(OPENAIR_TARGETS)/ARCH/EXMIMO/DRIVER/eurecom && make clean && make +# cd $(OPENAIR2_DIR) && make clean && make nasmesh_netlink.ko +# cd $(OPENAIR2_DIR)/NAS/DRIVER/MESH/RB_TOOL && make clean && make + cd $(OPENAIR_TARGETS)/ARCH/EXMIMO/DRIVER/eurecom && make clean && make + cp $(OPENAIR_TARGETS)/ARCH/EXMIMO/DRIVER/eurecom/openair_rf.ko $(OPENAIR_TARGETS)/bin/. cd $(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT && make clean && make + cp $(OPENAIR_TARGETS)/ARCH/EXMIMO/USERSPACE/OAI_FW_INIT/updatefw $(OPENAIR_TARGETS)/bin/. run: condtest rtai-load condtest --verbose From fac6a63f670e0f016cf00b6aaf967625b629c7bc Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 5 Oct 2015 15:41:18 +0200 Subject: [PATCH 018/413] adding new file --- openair1/PHY/LTE_REFSIG/lte_dl_uespec.c | 396 ++++++++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 openair1/PHY/LTE_REFSIG/lte_dl_uespec.c diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c b/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c new file mode 100644 index 0000000000..d029f959ed --- /dev/null +++ b/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c @@ -0,0 +1,396 @@ +/******************************************************************************* + 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + + *******************************************************************************/ + +/*! \file PHY/LTE_REFSIG/lte_dl_ue_spec.c +* \brief Top-level routines for generating UE-specific Reference signals from 36-211, V11.3.0 2013-06 +* \author R. Knopp X. Jiang +* \date 2015 +* \version 0.1 +* \company Eurecom +* \email: knopp@eurecom.fr xiwen.jiang@eurecom.fr +* \note +* \warning +*/ + +#ifdef USER_MODE +#include +#include +#endif + +#include "defs.h" +#include "PHY/defs.h" +#include "log.h" + +//extern unsigned int lte_gold_table[3][20][2][14]; +//#define DEBUG_DL_CELL_SPEC + +int Wbar_NCP[8][4] = {{1,1,1,1},{1,-1,1,-1},{1,1,1,1},{1,-1,1,-1},{1,1,-1,-1},{-1,-1,1,1},{1,-1,-1,1},{-1,1,1,-1}}; + +/* +int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, + uint8_t UE_id, + mod_sym_t *output, + short amp, + uint8_t Ns, + uint8_t lprime, + uint8_t p, + int SS_flag) +{ + + mod_sym_t qpsk[4],nqpsk[4]; + int16_t k=0,a; + int mprime,ind,ind_dword,ind_qpsk_symb; + unsigned nushift,kprime; + // LTE_eNB_DLSCH_t *dlsch = phy_vars_eNB->dlsch_eNB[UE_id][0]; + + a = (amp*ONE_OVER_SQRT2_Q15)>>15; + ((short *)&qpsk[0])[0] = a; + ((short *)&qpsk[0])[1] = a; + ((short *)&qpsk[1])[0] = -a; + ((short *)&qpsk[1])[1] = a; + ((short *)&qpsk[2])[0] = a; + ((short *)&qpsk[2])[1] = -a; + ((short *)&qpsk[3])[0] = -a; + ((short *)&qpsk[3])[1] = -a; + + ((short *)&nqpsk[0])[0] = -a; + ((short *)&nqpsk[0])[1] = -a; + ((short *)&nqpsk[1])[0] = a; + ((short *)&nqpsk[1])[1] = -a; + ((short *)&nqpsk[2])[0] = -a; + ((short *)&nqpsk[2])[1] = a; + ((short *)&nqpsk[3])[0] = a; + ((short *)&nqpsk[3])[1] = a; + + if (p==5) { + if (SS_flag==0) { + if (phy_vars_eNB->lte_frame_parms.Ncp == NORMAL) { + // this is 3GPP 36-211 6.10.3.2, NORMAL CP, p=5 + + nushift = phy_vars_eNB->lte_frame_parms.Nid_cell%3; + + if(lprime==0){ + kprime=nushift; + }else{ + kprime=(nushift+2*lprime)%4; + } + + k = kprime+phy_vars_eNB->lte_frame_parms.first_carrier_offset; + printf("lte_dl_ue_spec:k=%d\n",k); + + for (mprime=0;mprime<3*nRB_PDSCH-1;mprime++) { + ind = 3*lprime*nRB_PDSCH+mprime; + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + output[k] = qpsk[(phy_vars_UE->lte_gold_uespec_port5_table[Ns][ind_dword]>>(2*ind_qpsk_symb))&3]; + //output[k] = 0xffffffff; + + k += 4; + if (k >= phy_vars_eNB->lte_frame_parms.ofdm_symbol_size) { + k++; // skip DC carrier + k-=phy_vars_eNB->lte_frame_parms.ofdm_symbol_size; + } + + } + } + } + } else if (p>=7) { + printf("lte_dl_ue_spec:antenna ports >=7 not supported yet!\n"); + } else { + LOG_E(PHY,"Illegal p %d UE specific pilots\n",p); + } + + return(0); +} +*/ + + +int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, + mod_sym_t *output, + unsigned char Ns, + unsigned char p, + int lprime, + int SS_flag, + uint16_t nRB_PDSCH) +{ + mod_sym_t qpsk[4],nqpsk[4],*qpsk_p,*output_p; + int w,mprime,ind,l,ind_dword,ind_qpsk_symb,nPRB; + short pamp; + + // Compute the correct pilot amplitude, sqrt_rho_b = Q3.13 + pamp = ONE_OVER_SQRT2_Q15; + + // This includes complex conjugate for channel estimation + ((short *)&qpsk[0])[0] = pamp; + ((short *)&qpsk[0])[1] = -pamp; + ((short *)&qpsk[1])[0] = -pamp; + ((short *)&qpsk[1])[1] = -pamp; + ((short *)&qpsk[2])[0] = pamp; + ((short *)&qpsk[2])[1] = pamp; + ((short *)&qpsk[3])[0] = -pamp; + ((short *)&qpsk[3])[1] = pamp; + + ((short *)&nqpsk[0])[0] = -pamp; + ((short *)&nqpsk[0])[1] = pamp; + ((short *)&nqpsk[1])[0] = pamp; + ((short *)&nqpsk[1])[1] = pamp; + ((short *)&nqpsk[2])[0] = -pamp; + ((short *)&nqpsk[2])[1] = -pamp; + ((short *)&nqpsk[3])[0] = pamp; + ((short *)&nqpsk[3])[1] = -pamp; + + if (p>=7) { + if (SS_flag==0) { + if (phy_vars_ue->lte_frame_parms.Ncp == NORMAL) { + // this is 3GPP 36-211 6.10.3.2, NORMAL CP, p>=7 + + output_p = output; + + ind = 3*lprime*phy_vars_ue->lte_frame_parms.N_RB_DL; + l = lprime + ((Ns&1)<<1); + + // loop over pairs of PRBs, this is the periodicity of the W_bar_NCP sequence + // unroll the computations for the 6 pilots, select qpsk or nqpsk as function of W_bar_NCP + for (nPRB=0; nPRBlte_frame_parms.N_RB_DL; nPRB+=2) { + + // First pilot + w = Wbar_NCP[p-7][l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + + + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + + +#ifdef DEBUG_DL_UESPEC + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); +#endif + + output_p++; + ind++; + + w = Wbar_NCP[p-7][3-l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + + // Second pilot + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + +#ifdef DEBUG_DL_UESPEC + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); +#endif + + output_p++; + ind++; + + w = Wbar_NCP[p-7][l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + // Third pilot + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + +#ifdef DEBUG_DL_UESPEC + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_eNB->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); +#endif + + output_p++; + ind++; + + // Fourth pilot + w = Wbar_NCP[p-7][3-l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + + + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + + +#ifdef DEBUG_DL_UESPEC + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); +#endif + + output_p++; + ind++; + + w = Wbar_NCP[p-7][l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + + // Fifth pilot + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + +#ifdef DEBUG_DL_UESPEC + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); +#endif + + output_p++; + ind++; + + w = Wbar_NCP[p-7][3-l]; + qpsk_p = (w==1) ? qpsk : nqpsk; + // Sixth pilot + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk_p[(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3]; + +#ifdef DEBUG_DL_UESPEC + LOG_D(PHY,"Ns %d, l %d, m %d,ind_dword %d, ind_qpsk_symbol %d\n", + Ns,l,m,ind_dword,ind_qpsk_symb); + LOG_D(PHY,"index = %d\n",(phy_vars_ue->lte_gold_uespec_table[0][Ns][lprime][ind_dword]>>(2*ind_qpsk_symb))&3); +#endif + + output_p++; + ind++; + } + } else { + LOG_E(PHY,"Special subframe not supported for UE specific pilots yet\n"); + } + } + } else if (p==5) { + if (SS_flag==0) { + output_p = output; + + if (phy_vars_ue->lte_frame_parms.Ncp == NORMAL) { + for (mprime=0;mprime<3*nRB_PDSCH;mprime++) { + + ind = 3*lprime*nRB_PDSCH+mprime; + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + *output_p = qpsk[(phy_vars_ue->lte_gold_uespec_port5_table[Ns][ind_dword]>>(2*ind_qpsk_symb))&3]; + //printf("lprime=%d,ind=%d,Ns=%d,output_p=(%d,%d)\n",lprime,ind,Ns,((short *)&output_p[0])[0],((short *)&output_p[0])[1]); + output_p++; + + } + } + } + } else { + LOG_E(PHY,"Illegal p %d UE specific pilots\n",p); + } + + return(0); +} + + + +#ifdef LTE_DL_CELL_SPEC_MAIN + + + +//extern int write_output(const char *,const char *,void *,int,int,char); +// flag change eren +extern int write_output(const char *,const char *,void *,int,int,char); +main() +{ + + unsigned short Nid_cell=0; + unsigned int Ncp = 0; + int output00[1024]; + int output01[1024]; + int output10[1024]; + int output11[1024]; + + memset(output00,0,1024*sizeof(int)); + memset(output01,0,1024*sizeof(int)); + memset(output10,0,1024*sizeof(int)); + memset(output11,0,1024*sizeof(int)); + + lte_gold(Nid_cell,Ncp); + + lte_dl_ue_spec(output00, + ONE_OVER_SQRT2_Q15, + 50, + Nid_cell, + Ncp, + 0, + 0, + 0, + 0); + + lte_dl_ue_spec(output10, + ONE_OVER_SQRT2_Q15, + 50, + Nid_cell, + Ncp, + 0, + 1, + 0, + 0); + + lte_dl_ue_spec(output01, + ONE_OVER_SQRT2_Q15, + 50, + Nid_cell, + Ncp, + 0, + 0, + 1, + 0); + + lte_dl_ue_spec(output11, + ONE_OVER_SQRT2_Q15, + 50, + Nid_cell, + Ncp, + 0, + 1, + 1, + 0); + + + write_output("dl_ue_spec00.m","dl_cs00",output00,1024,1,1); + write_output("dl_ue_spec01.m","dl_cs01",output01,1024,1,1); + write_output("dl_ue_spec10.m","dl_cs10",output10,1024,1,1); + write_output("dl_ue_spec11.m","dl_cs11",output11,1024,1,1); +} + + +#endif From 67262694de414a9dda8156cac8d1eb5d62f44369 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 5 Oct 2015 16:19:52 +0200 Subject: [PATCH 019/413] bug fixed in free beamforming weights --- openair1/SIMULATION/LTE_PHY/dlsim.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 139d507e61..347b80cbc6 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -3059,12 +3059,12 @@ PMI_FEEDBACK: for (i=0; i<2*frame_parms->samples_per_tti; i++) { for (aa=0; aalte_frame_parms.nb_antennas_rx; aa++) { // printf("s_re[0][%d]=> %f , r_re[0][%d]=> %f\n",i,s_re[aa][i],i,r_re[aa][i]); - //((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i] = - // (short) (r_re[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); - // ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i+1] = - // (short) (r_im[aa][i] + (iqim*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); - ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i] = (short) r_re[aa][i]; - ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i+1] = (short) r_im[aa][i]; + ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i] = + (short) (r_re[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); + ((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i+1] = + (short) (r_im[aa][i] + (iqim*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0)); + //((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i] = (short) r_re[aa][i]; + //((short*) PHY_vars_UE->lte_ue_common_vars.rxdata[aa])[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti)+2*i+1] = (short) r_im[aa][i]; //printf("rxdata[%d][%d]=> %d, %d\n",aa,subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti+i,r_re[aa][i],r_im[aa][i]); } } @@ -4340,8 +4340,10 @@ PMI_FEEDBACK: free(r_im[i]); } - for(i=0;i<12*N_RB_DL;i++) - free(beamforming_weights[i]); + if(transmission_mode == 7){ + for(i=0;i<12*N_RB_DL;i++) + free(beamforming_weights[i]); + } free(s_re); free(s_im); From 0d681a0e727c61a95f95106d95eace3067e2a524 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 9 Oct 2015 10:04:25 +0200 Subject: [PATCH 020/413] use nb_antennas_tx as physical antenna number and nb_antennas_tx_eNB as antenna port --- openair1/PHY/INIT/lte_init.c | 12 +- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 9 +- openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c | 2 +- openair1/PHY/defs.h | 1 - openair1/SIMULATION/LTE_PHY/dlsim.c | 119 +++++++++--------- 5 files changed, 74 insertions(+), 69 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 83ed9c632c..b139f5cf4f 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1275,10 +1275,10 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, if (abstraction_flag==0) { // TX vars - eNB_common_vars->txdata[eNB_id] = (int32_t**)malloc16(phy_vars_eNB->nb_antennas_tx_phy*sizeof(int32_t*) ); - eNB_common_vars->txdataF[eNB_id] = (mod_sym_t **)malloc16(phy_vars_eNB->nb_antennas_tx_phy*sizeof(mod_sym_t*) ); + eNB_common_vars->txdata[eNB_id] = (int32_t**)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*) ); + eNB_common_vars->txdataF[eNB_id] = (mod_sym_t **)malloc16(frame_parms->nb_antennas_tx*sizeof(mod_sym_t*) ); - for (i=0; inb_antennas_tx_phy; i++) { + for (i=0; inb_antennas_tx; i++) { #ifdef USER_MODE eNB_common_vars->txdata[eNB_id][i] = (int32_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(int32_t) ); eNB_common_vars->txdataF[eNB_id][i] = (mod_sym_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t) ); @@ -1295,9 +1295,9 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, } // RX vars - eNB_common_vars->rxdata[eNB_id] = (int32_t**)malloc16( frame_parms->nb_antennas_rx*sizeof(int32_t*) ); - eNB_common_vars->rxdata_7_5kHz[eNB_id] = (int32_t**)malloc16( frame_parms->nb_antennas_rx*sizeof(int32_t*) ); - eNB_common_vars->rxdataF[eNB_id] = (int32_t**)malloc16( frame_parms->nb_antennas_rx*sizeof(int32_t*) ); + eNB_common_vars->rxdata[eNB_id] = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*) ); + eNB_common_vars->rxdata_7_5kHz[eNB_id] = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*) ); + eNB_common_vars->rxdataF[eNB_id] = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*) ); for (i=0; inb_antennas_rx; i++) { #ifndef USER_MODE diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 313134c28a..6580e827c1 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -192,7 +192,6 @@ int allocate_REs_in_RB(PHY_VARS_eNB *phy_vars_eNB, uint8_t *x1=NULL; uint8_t mod_order1=2; - uint8_t nb_antennas_tx_phy = phy_vars_eNB->nb_antennas_tx_phy; // Fill these in later for TM8-10 // int Nlayers1; @@ -917,7 +916,7 @@ break; *jj = *jj + 1; //printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); - for (aa=0; aanb_antennas_tx; aa++) { ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); @@ -956,7 +955,7 @@ break; ((int16_t*)&tmp_sample1)[0] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); ((int16_t*)&tmp_sample1)[1] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); - for (aa=0; aanb_antennas_tx; aa++) { ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); @@ -1004,7 +1003,7 @@ break; ((int16_t*)&tmp_sample1)[0] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); ((int16_t*)&tmp_sample1)[1] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); - for (aa=0; aanb_antennas_tx; aa++) { ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); @@ -1025,7 +1024,7 @@ break; tmp_sample1 = qpsk[(phy_vars_eNB->lte_gold_uespec_port5_table[0][Ns][ind_dword]>>(2*ind_qpsk_symb))&3]; mprime2++; - for (aa=0; aanb_antennas_tx; aa++) { ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); diff --git a/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c b/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c index 2287c44a5f..4651308dfd 100644 --- a/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c +++ b/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c @@ -68,7 +68,7 @@ void generate_ue_spec_pilots(PHY_VARS_eNB *phy_vars_eNB, printf("generate_dl_ue_spec:tti_offset=%d\n",tti_offset); if(frame_parms->Ncp==0) { - for(aa=0;aanb_antennas_tx_phy;aa++){ + for(aa=0;aanb_antennas_tx;aa++){ //antenna port 5 symbol 0 slot 0 lte_dl_ue_spec(phy_vars_eNB, UE_id, diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index ceacd43ee1..d9965b4e75 100755 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -209,7 +209,6 @@ typedef struct PHY_VARS_eNB_s { eNB_proc_t proc[NUM_ENB_THREADS]; uint8_t local_flag; uint32_t rx_total_gain_eNB_dB; - uint8_t nb_antennas_tx_phy; LTE_DL_FRAME_PARMS lte_frame_parms; PHY_MEASUREMENTS_eNB PHY_measurements_eNB[NUMBER_OF_eNB_SECTORS_MAX]; /// Measurement variables LTE_eNB_COMMON lte_eNB_common_vars; diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 347b80cbc6..2501baff25 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -1,4 +1,4 @@ -/****************************************************************************** + /****************************************************************************** ipenAirInterface Copyright(c) 1999 - 2014 Eurecom @@ -107,7 +107,7 @@ void handler(int sig) exit(1); } -void lte_param_init(unsigned char N_tx, unsigned char N_tx_phy, unsigned char N_rx,unsigned char transmission_mode,uint8_t extended_prefix_flag,uint8_t fdd_flag, uint16_t Nid_cell,uint8_t tdd_config,uint8_t N_RB_DL, uint8_t osf,uint32_t perfect_ce) +void lte_param_init(unsigned char N_tx_port_eNB, unsigned char N_tx_phy, unsigned char N_rx,unsigned char transmission_mode,uint8_t extended_prefix_flag,uint8_t fdd_flag, uint16_t Nid_cell,uint8_t tdd_config,uint8_t N_RB_DL, uint8_t osf,uint32_t perfect_ce) { LTE_DL_FRAME_PARMS *lte_frame_parms; @@ -132,9 +132,9 @@ void lte_param_init(unsigned char N_tx, unsigned char N_tx_phy, unsigned char N_ lte_frame_parms->Ncp = extended_prefix_flag; lte_frame_parms->Nid_cell = Nid_cell; lte_frame_parms->nushift = Nid_cell%6; - lte_frame_parms->nb_antennas_tx = N_tx; + lte_frame_parms->nb_antennas_tx = N_tx_phy; lte_frame_parms->nb_antennas_rx = N_rx; - lte_frame_parms->nb_antennas_tx_eNB = N_tx; + lte_frame_parms->nb_antennas_tx_eNB = N_tx_port_eNB; lte_frame_parms->phich_config_common.phich_resource = one; lte_frame_parms->tdd_config = tdd_config; lte_frame_parms->frame_type = (fdd_flag==1)?0 : 1; @@ -157,8 +157,6 @@ void lte_param_init(unsigned char N_tx, unsigned char N_tx_phy, unsigned char N_ PHY_vars_eNB->transmission_mode[0] = transmission_mode; PHY_vars_UE->transmission_mode[0] = transmission_mode; - //printf("lte_param_init: transmission mode = %d\n",PHY_vars_eNB->transmission_mode[0]); - PHY_vars_eNB->nb_antennas_tx_phy = N_tx_phy; phy_init_lte_top(lte_frame_parms); dump_frame_parms(lte_frame_parms); @@ -207,7 +205,7 @@ uint64_t DLSCH_alloc_pdu_1[2]; #define CCCH_RB_ALLOC computeRIV(PHY_vars_eNB->lte_frame_parms.N_RB_UL,0,2) //#define DLSCH_RB_ALLOC 0x1fbf // igore DC component,RB13 //#define DLSCH_RB_ALLOC 0x0001 -void do_OFDM_mod_l(mod_sym_t **txdataF, int32_t **txdata, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms, uint8_t nb_antennas_tx_phy) +void do_OFDM_mod_l(mod_sym_t **txdataF, int32_t **txdata, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms) { int aa, slot_offset, slot_offset_F; @@ -215,7 +213,7 @@ void do_OFDM_mod_l(mod_sym_t **txdataF, int32_t **txdata, uint16_t next_slot, LT slot_offset_F = (next_slot)*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); slot_offset = (next_slot)*(frame_parms->samples_per_tti>>1); - for (aa=0; aanb_antennas_tx; aa++) { // printf("Thread %d starting ... aa %d (%llu)\n",omp_get_thread_num(),aa,rdtsc()); if (frame_parms->Ncp == 1) @@ -253,8 +251,7 @@ int main(int argc, char **argv) double forgetting_factor=0.0; //in [0,1] 0 means a new channel every time, 1 means keep the same channel double iqim=0.0; - uint8_t extended_prefix_flag=0,transmission_mode=1,n_tx=1,n_rx=1; - uint16_t n_tx_phy=1; + uint8_t extended_prefix_flag=0,transmission_mode=1,n_tx_port=1,n_tx_phy=1,n_rx=1; uint16_t Nid_cell=0; int32_t **beamforming_weights; @@ -335,7 +332,8 @@ int main(int argc, char **argv) uint32_t DLSCH_RB_ALLOC = 0x1fff; int numCCE=0; int dci_length_bytes=0,dci_length=0; - double BW = 5.0; + //double BW = 5.0; + double BW = 7.68; int common_flag=0,TPC=0; double cpu_freq_GHz; @@ -387,7 +385,7 @@ int main(int argc, char **argv) num_layers = 1; perfect_ce = 0; - while ((c = getopt (argc, argv, "ahdpZDe:m:n:o:s:f:t:c:g:r:F:x:y:q:z:AM:N:I:i:O:R:S:C:T:b:u:v:w:B:PLl:Y")) != -1) { + while ((c = getopt (argc, argv, "ahdqZDe:m:n:o:s:f:t:c:g:r:F:x:p:y:z:AM:N:I:i:O:R:S:C:T:b:u:v:w:B:PLl:Y")) != -1) { switch (c) { case 'a': awgn_flag = 1; @@ -464,7 +462,7 @@ int main(int argc, char **argv) n_ch_rlz= atof(optarg); break; - case 'p': + case 'q': extended_prefix_flag=1; break; @@ -554,32 +552,39 @@ int main(int argc, char **argv) } if (transmission_mode>1 && transmission_mode<7){ - n_tx = 2; - n_tx_phy = n_tx; + n_tx_port = 2; + n_tx_phy = n_tx_port; + } else if (transmission_mode==7){ + n_tx_port = 1; } break; - case 'y': - n_tx=atoi(optarg); + case 'p': + n_tx_port=atoi(optarg); - if ((n_tx==0) || ((n_tx>2))) { - msg("Unsupported number of tx antennas ports %d\n",n_tx); + if ((n_tx_port==0) || ((n_tx_port>2))) { + msg("Unsupported number of cell specific antennas ports %d\n",n_tx_port); exit(-1); } break; - case 'q': + case 'y': n_tx_phy=atoi(optarg); - if (transmission_mode<7 && n_tx_phy!=n_tx) { - msg("For transmission mode below TM7, physical antenna number should be the same as antenna port number.\n"); - exit(-1); + if (transmission_mode>1&&transmission_mode<7) { + if(n_tx_phy==1) { + msg("n_tx_phy must be >1 for transmission_mode %d\n",transmission_mode); + exit(-1); + } else if (n_tx_phy!=n_tx_port) { // to be changed + msg("For transmission mode TM2-TM6, physical antenna number should be the same as antenna port number.\n"); + exit(-1); + } } //if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=8 && n_tx_phy!=16 && n_tx_phy!=64 && n_tx_phy!=128)) { - if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=4 && n_tx_phy!=16 && n_tx_phy!=64)) { + if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=16 && n_tx_phy!=64)) { msg("For TM7, physical antenna number should be an exponent of 4, maximum 64 antennas supported.\n"); exit(-1); } @@ -629,7 +634,7 @@ int main(int argc, char **argv) dual_stream_UE=1; openair_daq_vars.use_ia_receiver = 1; - if ((n_tx!=2) || (transmission_mode!=5)) { + if ((n_tx_port!=2) || (transmission_mode!=5)) { msg("IA receiver only supported for TM5!"); exit(-1); } @@ -689,8 +694,8 @@ int main(int argc, char **argv) printf("-g [A:M] Use 3GPP 25.814 SCM-A/B/C/D('A','B','C','D') or 36-101 EPA('E'), EVA ('F'),ETU('G') models (ignores delay spread and Ricean factor), Rayghleigh8 ('H'), Rayleigh1('I'), Rayleigh1_corr('J'), Rayleigh1_anticorr ('K'), Rice8('L'), Rice1('M')\n"); printf("-F forgetting factor (0 new channel every trial, 1 channel constant\n"); printf("-x Transmission mode (1,2,6,7 for the moment)\n"); - printf("-y Number of TX antennas ports used in eNB\n"); - printf("-q Number of physical TX antennas used in eNB\n"); + printf("-p Number of TX antennas ports used in eNB\n"); + printf("-y Number of physical TX antennas used in eNB\n"); printf("-z Number of RX antennas used in UE\n"); printf("-t MCS of interfering UE\n"); printf("-R Number of HARQ rounds (fixed)\n"); @@ -738,10 +743,6 @@ int main(int argc, char **argv) NB_RB=conv_nprb(0,DLSCH_RB_ALLOC,N_RB_DL); - if ((transmission_mode>1&&transmission_mode<7) && (n_tx_phy == 1)){ - msg("n_tx_phy must be >1 for transmission_mode %d\n",transmission_mode); - exit(-1); - } #ifdef XFORMS fl_initialize (&argc, argv, NULL, 0, 0); @@ -764,7 +765,7 @@ int main(int argc, char **argv) } - lte_param_init(n_tx,n_tx_phy,n_rx,transmission_mode,extended_prefix_flag,fdd_flag,Nid_cell,tdd_config,N_RB_DL,osf,perfect_ce); + lte_param_init(n_tx_port,n_tx_phy,n_rx,transmission_mode,extended_prefix_flag,fdd_flag,Nid_cell,tdd_config,N_RB_DL,osf,perfect_ce); if (transmission_mode==7){ lte_gold_ue_spec_port5(PHY_vars_eNB->lte_gold_uespec_port5_table[0],Nid_cell,n_rnti); @@ -775,14 +776,14 @@ int main(int argc, char **argv) beamforming_weights[i]=(int32_t *)malloc(n_tx_phy*sizeof(int32_t)); for(aa=0;aa>1; else if (n_tx_phy==16) beamforming_weights[i][aa] = 0x00007fff>>2; else if (n_tx_phy==64) - beamforming_weights[i][aa] = 0x00007fff>>3; + beamforming_weights[i][aa] = 0x00007fff>>4;//3 } } printf("***n_tx_phy=%d,n_tx_phy>>2=%d,beamforming_weights=%d\n",n_tx_phy,n_tx_phy>>2,beamforming_weights[0][0]); @@ -840,7 +841,7 @@ int main(int argc, char **argv) char dirname[FILENAME_MAX]; sprintf(dirname, "%s/SIMU/USER/pre-ci-logs-%s", getenv("OPENAIR_TARGETS"),hostname ); sprintf(time_meas_fname,"%s/time_meas_prb%d_mcs%d_anttx%d_antrx%d_pdcch%d_channel%s_tx%d.csv", - dirname,N_RB_DL,mcs1,n_tx,n_rx,num_pdcch_symbols,channel_model_input,transmission_mode); + dirname,N_RB_DL,mcs1,n_tx_phy,n_rx,num_pdcch_symbols,channel_model_input,transmission_mode); mkdir(dirname,0777); time_meas_fd = fopen(time_meas_fname,"w"); } @@ -2221,7 +2222,7 @@ PMI_FEEDBACK: //printf("Trial %d : Round %d, pmi_feedback %d \n",trials,round,pmi_feedback); //for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { - for (aa=0; aanb_antennas_tx_phy; aa++) { + for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { memset(&PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id][aa][0],0,FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t)); } @@ -2878,22 +2879,19 @@ PMI_FEEDBACK: do_OFDM_mod_l(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id], i, - &PHY_vars_eNB->lte_frame_parms, - PHY_vars_eNB->nb_antennas_tx_phy); + &PHY_vars_eNB->lte_frame_parms); } */ do_OFDM_mod_l(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id], (subframe*2), - &PHY_vars_eNB->lte_frame_parms, - PHY_vars_eNB->nb_antennas_tx_phy); + &PHY_vars_eNB->lte_frame_parms); do_OFDM_mod_l(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id], (subframe*2)+1, - &PHY_vars_eNB->lte_frame_parms, - PHY_vars_eNB->nb_antennas_tx_phy); + &PHY_vars_eNB->lte_frame_parms); stop_meas(&PHY_vars_eNB->ofdm_mod_stats); stop_meas(&PHY_vars_eNB->phy_proc_tx); @@ -2901,20 +2899,19 @@ PMI_FEEDBACK: do_OFDM_mod_l(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id], (subframe*2)+2, - &PHY_vars_eNB->lte_frame_parms, - PHY_vars_eNB->nb_antennas_tx_phy); + &PHY_vars_eNB->lte_frame_parms); if (n_frames==1) { write_output("txsigF0.m","txsF0", &PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id][0][subframe*nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size], nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size,1,1); - if (PHY_vars_eNB->nb_antennas_tx_phy>1)// to be updated + if (PHY_vars_eNB->lte_frame_parms.nb_antennas_tx>1)// to be updated write_output("txsigF1.m","txsF1", &PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id][1][subframe*nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size], nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size,1,1); } tx_lev = 0; - for (aa=0; aanb_antennas_tx_phy; aa++) { + for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { tx_lev += signal_energy(&PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa] [subframe*PHY_vars_eNB->lte_frame_parms.samples_per_tti], PHY_vars_eNB->lte_frame_parms.samples_per_tti); @@ -2956,7 +2953,7 @@ PMI_FEEDBACK: // printf("Copying tx ..., nsymb %d (n_tx %d), awgn %d\n",nsymb,PHY_vars_eNB->lte_frame_parms.nb_antennas_tx,awgn_flag); for (i=0; i<2*frame_parms->samples_per_tti; i++) { - for (aa=0; aanb_antennas_tx_phy; aa++) { + for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { if (awgn_flag == 0) { s_re[aa][i] = ((double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) + (i<<1)]); s_im[aa][i] = ((double)(((short *)PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id][aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) +(i<<1)+1]); @@ -3147,31 +3144,41 @@ PMI_FEEDBACK: //write_output("channel.m","ch",desc1->ch[0],desc1->channel_length,1,8); //write_output("channelF.m","chF",desc1->chF[0],nb_samples,1,8); for(k=0; knb_antennas_tx; aa++) { + for(aa=0; aanb_antennas_tx_eNB; aa++) { for (aarx=0; aarxnb_antennas_rx; aarx++) { for (i=0; iN_RB_DL*12; i++) { ((int16_t *) PHY_vars_UE->lte_ue_common_vars.dl_ch_estimates[k][(aa<<1)+aarx])[2*i+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=(int16_t)( eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x*AMP); + //printf("x=%d,AMP=%d\n",eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x,AMP); ((int16_t *) PHY_vars_UE->lte_ue_common_vars.dl_ch_estimates[k][(aa<<1)+aarx])[2*i+1+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=(int16_t)( eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].y*AMP); if (transmission_mode == 7){ - ((int16_t *)PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size)*2]=(int16_t)( - eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x*AMP); - ((int16_t *)PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+1+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size)*2]=(int16_t)( - eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].y*AMP); + if (PHY_vars_UE->high_speed_flag==0) { + ((int16_t *)PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i]=(int16_t)( + eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x*AMP); + ((int16_t *)PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+1]=(int16_t)( + eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].y*AMP); + //printf("**,x=%d,AMP=%d\n",eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x,AMP); + } else { + ((int16_t *)PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size)*2]=(int16_t)( + eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x*AMP); + ((int16_t *)PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+1+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size)*2]=(int16_t)( + eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].y*AMP); + + } } } } } } } else { - for(aa=0; aanb_antennas_tx; aa++) { + for(aa=0; aanb_antennas_tx_eNB; aa++) { for (aarx=0; aarxnb_antennas_rx; aarx++) { for (i=0; iN_RB_DL*12; i++) { - ((int16_t *) PHY_vars_UE->lte_ue_common_vars.dl_ch_estimates[0][(aa<<1)+aarx])[2*i+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=(short)(AMP); - ((int16_t *) PHY_vars_UE->lte_ue_common_vars.dl_ch_estimates[0][(aa<<1)+aarx])[2*i+1+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=0/2; - if (transmission_mode == 7){ + ((int16_t *) PHY_vars_UE->lte_ue_common_vars.dl_ch_estimates[0][(aa<<1)+aarx])[2*i+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=(short)(AMP); + ((int16_t *) PHY_vars_UE->lte_ue_common_vars.dl_ch_estimates[0][(aa<<1)+aarx])[2*i+1+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=0/2; + if (transmission_mode == 7) { if (PHY_vars_UE->high_speed_flag==0){ ((int16_t *) PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i]=(short)(AMP); ((int16_t *) PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i+1]=0/2; From ed83cbd1ebeb79fd7a7fd72ba2b943282e2bc5b6 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 26 Nov 2015 10:32:43 +0100 Subject: [PATCH 021/413] TM7 dlsim works --- cmake_targets/CMakeLists.txt | 4 +- common/utils/Makefile.inc | 4 +- openair1/PHY/INIT/lte_init.c | 58 +++- .../lte_dl_channel_estimation.c | 2 +- .../PHY/LTE_ESTIMATION/lte_ue_measurements.c | 2 +- .../lte_ul_channel_estimation.c | 4 +- openair1/PHY/LTE_TRANSPORT/dci.c | 76 ++--- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 74 ++--- openair1/PHY/LTE_TRANSPORT/defs.h | 2 + openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 14 +- .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 36 +-- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 294 +++++++++++------- openair1/PHY/LTE_TRANSPORT/initial_sync.c | 4 +- openair1/PHY/LTE_TRANSPORT/pbch.c | 14 +- openair1/PHY/LTE_TRANSPORT/pcfich.c | 2 +- openair1/PHY/LTE_TRANSPORT/pilots.c | 99 ++---- openair1/PHY/LTE_TRANSPORT/proto.h | 56 +++- openair1/PHY/MODULATION/slot_fep.c | 2 +- openair1/PHY/TOOLS/lte_phy_scope.c | 2 +- openair1/PHY/TOOLS/smbv.c | 2 +- openair1/PHY/defs.h | 4 +- openair1/PHY/impl_defs_lte.h | 28 +- openair1/PHY/impl_defs_top.h | 1 + openair1/SCHED/phy_procedures_lte_eNb.c | 11 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 174 +++++++---- openair1/SIMULATION/LTE_PHY/framegen.c | 2 +- openair1/SIMULATION/LTE_PHY/pbchsim.c | 2 +- openair1/SIMULATION/LTE_PHY/pdcchsim.c | 14 +- openair1/SIMULATION/LTE_PHY/scansim.c | 2 +- 29 files changed, 563 insertions(+), 426 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index ba7aa6c932..6898f21e4f 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -119,6 +119,7 @@ endmacro(add_list_string_option) #################################################### # compilation flags ############################################# +set(CMAKE_BUILD_TYPE "Debug") if (CMAKE_BUILD_TYPE STREQUAL "") set(CMAKE_BUILD_TYPE "RelWithDebInfo") endif() @@ -406,7 +407,7 @@ include_directories ("${X2AP_DIR}") # Hardware dependant options ################################### add_list1_option(NB_ANTENNAS_RX "2" "Number of antennas in reception" "1" "2" "4") -add_list1_option(NB_ANTENNAS_TX "2" "Number of antennas in transmission" "1" "2" "4") +add_list1_option(NB_ANTENNAS_TX "4" "Number of antennas in transmission" "1" "2" "4") add_list1_option(NB_ANTENNAS_TXRX "2" "Number of antennas in ????" "1" "2" "4") add_list2_option(RF_BOARD "EXMIMO" "RF head type" "False" "EXMIMO" "OAI_USRP" "ETHERNET" "OAI_BLADERF" "CPRIGW") @@ -819,6 +820,7 @@ set(PHY_SRC ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/rar_tools.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/print_stats.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/initial_sync.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/beamforming.c ${OPENAIR1_DIR}/PHY/MODULATION/ofdm_mod.c ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep.c ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_mbsfn.c diff --git a/common/utils/Makefile.inc b/common/utils/Makefile.inc index 8c4ebbe31e..33c126b8d7 100644 --- a/common/utils/Makefile.inc +++ b/common/utils/Makefile.inc @@ -11,8 +11,8 @@ CFLAGS += -Wall -g -ggdb -Wstrict-prototypes -fno-strict-aliasing CFLAGS += $(call cc-option,-mpreferred-stack-boundary=4) #For performance, if some option doesn't exist in all gcc versions, use $(call cc-option,MY_OPTION) -CFLAGS += -O2 -CFLAGS += -funroll-loops +#CFLAGS += -O2 +#CFLAGS += -funroll-loops CFLAGS += -Wno-packed-bitfield-compat # This is the minimum CPU faetures for OAI diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index b139f5cf4f..50c70b6d02 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -77,7 +77,7 @@ void phy_config_mib(LTE_DL_FRAME_PARMS *lte_frame_parms, lte_frame_parms->nushift = Nid_cell%6; lte_frame_parms->Ncp = Ncp; lte_frame_parms->frame_type = frame_type; - lte_frame_parms->nb_antennas_tx_eNB = p_eNB; + lte_frame_parms->nb_antenna_ports_eNB = p_eNB; lte_frame_parms->phich_config_common.phich_resource = phich_config->phich_resource; lte_frame_parms->phich_config_common.phich_duration = phich_config->phich_duration; } @@ -1262,8 +1262,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, phy_vars_eNB->physicalConfigDedicated[UE_id] = NULL; } - phy_vars_eNB->first_run_I0_measurements = - 1; ///This flag used to be static. With multiple eNBs this does no longer work, hence we put it in the structure. However it has to be initialized with 1, which is performed here. + phy_vars_eNB->first_run_I0_measurements = 1; ///This flag used to be static. With multiple eNBs this does no longer work, hence we put it in the structure. However it has to be initialized with 1, which is performed here. #ifndef USER_MODE AssertFatal( frame_parms->nb_antennas_tx <= NB_ANTENNAS_TX, "nb_antennas_tx too large" ); @@ -1275,25 +1274,58 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, if (abstraction_flag==0) { // TX vars - eNB_common_vars->txdata[eNB_id] = (int32_t**)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*) ); - eNB_common_vars->txdataF[eNB_id] = (mod_sym_t **)malloc16(frame_parms->nb_antennas_tx*sizeof(mod_sym_t*) ); + eNB_common_vars->txdata[eNB_id] = (int32_t**)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*)); + eNB_common_vars->txdataF[eNB_id] = (mod_sym_t **)malloc16(NB_ANTENNA_PORTS_ENB*sizeof(mod_sym_t*)); + eNB_common_vars->txdataF_BF[eNB_id] = (mod_sym_t ***)malloc16(frame_parms->nb_antennas_tx*sizeof(mod_sym_t**)); - for (i=0; inb_antennas_tx; i++) { -#ifdef USER_MODE - eNB_common_vars->txdata[eNB_id][i] = (int32_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(int32_t) ); + for (i=0; i<14; i++) { eNB_common_vars->txdataF[eNB_id][i] = (mod_sym_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t) ); -#else // USER_MODE - eNB_common_vars->txdata[eNB_id][i] = TX_DMA_BUFFER[eNB_id][i]; - eNB_common_vars->txdataF[eNB_id][i] = (mod_sym_t *)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t) ); -#endif //USER_MODE #ifdef DEBUG_PHY - msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->txdata[%d][%d] = %p\n",eNB_id,i,eNB_common_vars->txdata[eNB_id][i]); msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->txdataF[%d][%d] = %p (%d bytes)\n", eNB_id,i,eNB_common_vars->txdataF[eNB_id][i], FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t)); #endif } + for (i=0; inb_antennas_tx; i++) { + eNB_common_vars->txdataF_BF[eNB_id][i] = (mod_sym_t*)malloc16_clear( OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(mod_sym_t*) ); +#ifdef USER_MODE + eNB_common_vars->txdata[eNB_id][i] = (int32_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(int32_t) ); +#else // USER_MODE + eNB_common_vars->txdata[eNB_id][i] = TX_DMA_BUFFER[eNB_id][i]; +#endif // USER_MODE +#ifdef DEBUG_PHY + msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->txdataF_BF[%d][%d][%d] = %p (%d bytes)\n", + eNB_id,i,j,eNB_common_vars->txdataF_BF[eNB_id][i][j], + OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(mod_sym_t)); + msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->txdata[%d][%d] = %p\n",eNB_id,i,eNB_common_vars->txdata[eNB_id][i]); +#endif + } + + for (i=0; i<2; i++) { // 2 is the total number of cell specific antenna ports + eNB_common_vars->cell_spec_bf_weights[eNB_id][i] = (int32_t **)malloc16_clear(frame_parms->nb_antennas_tx*sizeof(int32_t*)); + for (j=0; jnb_antennas_tx; j++) { + eNB_common_vars->cell_spec_bf_weights[eNB_id][i][j] = (int32_t*)malloc16_clear(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); +#ifdef DEBUG_PUY + msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->cell_spec_bf_weights[%d][%d][%d] = %p (%d bytes)\n", + eNB_id,i,j,eNB_common_vars->cell_spec_bf_weights[eNB_id][i][j], + OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); +#endif + } + } + + for (i=0; i<8; i++) { //antenna port 5 for TM7, antenna port 7-15 for TM8-10 + eNB_common_vars->ue_spec_bf_weights[eNB_id][i] = (int32_t **)malloc16_clear(frame_parms->nb_antennas_tx*sizeof(int32_t*)); + for (j=0; jnb_antennas_tx; j++) { + eNB_common_vars->ue_spec_bf_weights[eNB_id][i][j] = (int32_t*)malloc16_clear(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); +#ifdef DEBUG_PUY + msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->ue_spec_bf_weights[%d][%d][%d] = %p (%d bytes)\n", + eNB_id,i,j,eNB_common_vars->ue_spec_bf_weights[eNB_id][i][j], + OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); +#endif + } + } + // RX vars eNB_common_vars->rxdata[eNB_id] = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*) ); eNB_common_vars->rxdata_7_5kHz[eNB_id] = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*) ); diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c index 56a097bfda..dd1d954b7b 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c @@ -728,7 +728,7 @@ int lte_dl_channel_estimation(PHY_VARS_UE *phy_vars_ue, // do ifft of channel estimate for (aarx=0; aarxlte_frame_parms.nb_antennas_rx; aarx++) - for (p=0; plte_frame_parms.nb_antennas_tx_eNB; p++) { + for (p=0; plte_frame_parms.nb_antenna_ports_eNB; p++) { if (phy_vars_ue->lte_ue_common_vars.dl_ch_estimates[eNB_offset][(p<<1)+aarx]) idft((int16_t*) &phy_vars_ue->lte_ue_common_vars.dl_ch_estimates[eNB_offset][(p<<1)+aarx][8], (int16_t*) phy_vars_ue->lte_ue_common_vars.dl_ch_estimates_time[eNB_offset][(p<<1)+aarx],1); diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c index 0fa0fc4ce1..50a71eb47a 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c @@ -453,7 +453,7 @@ void lte_ue_measurements(PHY_VARS_UE *phy_vars_ue, // signal measurements for (eNB_id=0; eNB_idn_connected_eNB; eNB_id++) { for (aarx=0; aarxnb_antennas_rx; aarx++) { - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) { + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) { phy_vars_ue->PHY_measurements.rx_spatial_power[eNB_id][aatx][aarx] = (signal_energy_nodc(&phy_vars_ue->lte_ue_common_vars.dl_ch_estimates[eNB_id][(aatx<<1) + aarx][0], (N_RB_DL*12))); diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c index 9a47a6b355..44214e8b9d 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c @@ -84,7 +84,7 @@ int32_t lte_ul_channel_estimation(PHY_VARS_eNB *phy_vars_eNB, int16_t ul_ch_estimates_re,ul_ch_estimates_im; int32_t rx_power_correction; - //uint8_t nb_antennas_rx = frame_parms->nb_antennas_tx_eNB; + //uint8_t nb_antennas_rx = frame_parms->nb_antenna_ports_eNB; uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx; uint8_t cyclic_shift; @@ -678,7 +678,7 @@ int32_t lte_srs_channel_estimation(LTE_DL_FRAME_PARMS *frame_parms, int T_SFC,aa; int N_symb,symbol; - uint8_t nb_antennas_rx = frame_parms->nb_antennas_tx_eNB; + uint8_t nb_antennas_rx = frame_parms->nb_antenna_ports_eNB; #ifdef DEBUG_SRS char fname[40], vname[40]; #endif diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index 43d2410cbb..dd18d16108 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -74,7 +74,7 @@ uint32_t check_phich_reg(LTE_DL_FRAME_PARMS *frame_parms,uint32_t kprime,uint8_t // compute REG based on symbol if ((lprime == 0)|| - ((lprime==1)&&(frame_parms->nb_antennas_tx_eNB == 4))) + ((lprime==1)&&(frame_parms->nb_antenna_ports_eNB == 4))) mprime = kprime/6; else mprime = kprime>>2; @@ -301,7 +301,7 @@ void pdcch_interleaving(LTE_DL_FRAME_PARMS *frame_parms,mod_sym_t **z, mod_sym_t for (row=0; row=ND) { - for (a=0; anb_antennas_tx_eNB; a++) { + for (a=0; anb_antenna_ports_eNB; a++) { //printf("a %d k %d\n",a,k); wptr = &wtemp[a][k<<2]; @@ -325,7 +325,7 @@ void pdcch_interleaving(LTE_DL_FRAME_PARMS *frame_parms,mod_sym_t **z, mod_sym_t // permutation for (i=0; inb_antennas_tx_eNB; a++) { + for (a=0; anb_antenna_ports_eNB; a++) { //wptr = &wtemp[a][i<<2]; //wptr2 = &wbar[a][((i+frame_parms->Nid_cell)%Mquad)<<2]; @@ -417,7 +417,7 @@ void pdcch_demapping(uint16_t *llr,uint16_t *wbar,LTE_DL_FRAME_PARMS *frame_parm re_offset0++; } } - } else if ((lprime==1)&&(frame_parms->nb_antennas_tx_eNB == 4)) { + } else if ((lprime==1)&&(frame_parms->nb_antenna_ports_eNB == 4)) { // LATER!!!! } else { // no pilots in this symbol kprime_mod12 = kprime%12; @@ -655,7 +655,7 @@ void pdcch_channel_level(int32_t **dl_ch_estimates_ext, int16x8_t *dl_ch128; int32x4_t *avg128P; #endif - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) for (aarx=0; aarxnb_antennas_rx; aarx++) { //clear average level #if defined(__x86_64__) || defined(__i386__) @@ -833,7 +833,7 @@ void pdcch_detection_mrc_i(LTE_DL_FRAME_PARMS *frame_parms, int32_t i; if (frame_parms->nb_antennas_rx>1) { - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) { + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) { //if (frame_parms->mode1_flag && (aatx>0)) break; #if defined(__x86_64__) || defined(__i386__) @@ -1396,8 +1396,8 @@ void pdcch_channel_compensation(int32_t **rxdataF_ext, if (symbol==0) pilots=1; - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) { - //if (frame_parms->mode1_flag && aatx>0) break; //if mode1_flag is set then there is only one stream to extract, independent of nb_antennas_tx_eNB + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) { + //if (frame_parms->mode1_flag && aatx>0) break; //if mode1_flag is set then there is only one stream to extract, independent of nb_antenna_ports_eNB for (aarx=0; aarxnb_antennas_rx; aarx++) { @@ -1603,7 +1603,7 @@ void pdcch_detection_mrc(LTE_DL_FRAME_PARMS *frame_parms, int32_t i; if (frame_parms->nb_antennas_rx>1) { - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) { + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) { #if defined(__x86_64__) || defined(__i386__) rxdataF_comp128_0 = (__m128i *)&rxdataF_comp[(aatx<<1)][symbol*frame_parms->N_RB_DL*12]; rxdataF_comp128_1 = (__m128i *)&rxdataF_comp[(aatx<<1)+1][symbol*frame_parms->N_RB_DL*12]; @@ -1724,7 +1724,7 @@ int32_t rx_pdcch(LTE_UE_COMMON *lte_ue_common_vars, high_speed_flag, frame_parms); #endif //MU_RECEIVER - } else if (frame_parms->nb_antennas_tx_eNB>1) { + } else if (frame_parms->nb_antenna_ports_eNB>1) { pdcch_extract_rbs_dual(lte_ue_common_vars->rxdataF, lte_ue_common_vars->dl_ch_estimates[eNB_id], lte_ue_pdcch_vars[eNB_id]->rxdataF_ext, @@ -1750,7 +1750,7 @@ int32_t rx_pdcch(LTE_UE_COMMON *lte_ue_common_vars, avgs = 0; - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) for (aarx=0; aarxnb_antennas_rx; aarx++) avgs = cmax(avgs,avgP[(aarx<<1)+aatx]); @@ -1991,10 +1991,10 @@ uint8_t get_num_pdcch_symbols(uint8_t num_dci, //if ((9*numCCE) <= (frame_parms->N_RB_DL*2)) if (numCCE <= get_nCCE(1, frame_parms, get_mi(frame_parms, subframe))) return(cmax(1,nCCEmin)); - //else if ((9*numCCE) <= (frame_parms->N_RB_DL*((frame_parms->nb_antennas_tx_eNB==4) ? 4 : 5))) + //else if ((9*numCCE) <= (frame_parms->N_RB_DL*((frame_parms->nb_antenna_ports_eNB==4) ? 4 : 5))) else if (numCCE <= get_nCCE(2, frame_parms, get_mi(frame_parms, subframe))) return(cmax(2,nCCEmin)); - //else if ((9*numCCE) <= (frame_parms->N_RB_DL*((frame_parms->nb_antennas_tx_eNB==4) ? 7 : 8))) + //else if ((9*numCCE) <= (frame_parms->N_RB_DL*((frame_parms->nb_antenna_ports_eNB==4) ? 7 : 8))) else if (numCCE <= get_nCCE(3, frame_parms, get_mi(frame_parms, subframe))) return(cmax(3,nCCEmin)); else if (frame_parms->N_RB_DL<=10) { @@ -2004,10 +2004,10 @@ uint8_t get_num_pdcch_symbols(uint8_t num_dci, get_nCCE(2, frame_parms, get_mi(frame_parms, subframe)), get_nCCE(3, frame_parms, get_mi(frame_parms, subframe))); - if ((9*numCCE) <= (frame_parms->N_RB_DL*((frame_parms->nb_antennas_tx_eNB==4) ? 10 : 11))) + if ((9*numCCE) <= (frame_parms->N_RB_DL*((frame_parms->nb_antenna_ports_eNB==4) ? 10 : 11))) return(4); } else { // extended CP - if ((9*numCCE) <= (frame_parms->N_RB_DL*((frame_parms->nb_antennas_tx_eNB==4) ? 9 : 10))) + if ((9*numCCE) <= (frame_parms->N_RB_DL*((frame_parms->nb_antenna_ports_eNB==4) ? 9 : 10))) return(4); } } @@ -2246,7 +2246,7 @@ uint8_t generate_dci_top(uint8_t num_ue_spec_dci, // Copy REG to TX buffer if ((lprime == 0)|| - ((lprime==1)&&(frame_parms->nb_antennas_tx_eNB == 4))) { + ((lprime==1)&&(frame_parms->nb_antenna_ports_eNB == 4))) { // first symbol, or second symbol+4 TX antennas skip pilots kprime_mod12 = kprime%12; @@ -2258,7 +2258,7 @@ uint8_t generate_dci_top(uint8_t num_ue_spec_dci, if ((i!=(nushiftmod3))&&(i!=(nushiftmod3+3))) { txdataF[0][tti_offset+i] = wbar[0][mprime]; - if (frame_parms->nb_antennas_tx_eNB > 1) + if (frame_parms->nb_antenna_ports_eNB > 1) txdataF[1][tti_offset+i] = wbar[1][mprime]; #ifdef DEBUG_DCI_ENCODING @@ -2277,7 +2277,7 @@ uint8_t generate_dci_top(uint8_t num_ue_spec_dci, for (i=0; i<4; i++) { txdataF[0][tti_offset+i] = wbar[0][mprime]; - if (frame_parms->nb_antennas_tx_eNB > 1) + if (frame_parms->nb_antenna_ports_eNB > 1) txdataF[1][tti_offset+i] = wbar[1][mprime]; #ifdef DEBUG_DCI_ENCODING @@ -2288,7 +2288,7 @@ uint8_t generate_dci_top(uint8_t num_ue_spec_dci, } else { txdataF[0][tti_offset+0] = wbar[0][mprime]; - if (frame_parms->nb_antennas_tx_eNB > 1) + if (frame_parms->nb_antenna_ports_eNB > 1) txdataF[1][tti_offset+0] = wbar[1][mprime]; #ifdef DEBUG_DCI_ENCODING @@ -2297,7 +2297,7 @@ uint8_t generate_dci_top(uint8_t num_ue_spec_dci, mprime++; txdataF[0][tti_offset+1] = wbar[0][mprime]; - if (frame_parms->nb_antennas_tx_eNB > 1) + if (frame_parms->nb_antenna_ports_eNB > 1) txdataF[1][tti_offset+1] = wbar[1][mprime]; #ifdef DEBUG_DCI_ENCODING @@ -2306,7 +2306,7 @@ uint8_t generate_dci_top(uint8_t num_ue_spec_dci, mprime++; txdataF[0][tti_offset-frame_parms->ofdm_symbol_size+3] = wbar[0][mprime]; - if (frame_parms->nb_antennas_tx_eNB > 1) + if (frame_parms->nb_antenna_ports_eNB > 1) txdataF[1][tti_offset-frame_parms->ofdm_symbol_size+3] = wbar[1][mprime]; #ifdef DEBUG_DCI_ENCODING @@ -2316,7 +2316,7 @@ uint8_t generate_dci_top(uint8_t num_ue_spec_dci, mprime++; txdataF[0][tti_offset-frame_parms->ofdm_symbol_size+4] = wbar[0][mprime]; - if (frame_parms->nb_antennas_tx_eNB > 1) + if (frame_parms->nb_antenna_ports_eNB > 1) txdataF[1][tti_offset-frame_parms->ofdm_symbol_size+4] = wbar[1][mprime]; #ifdef DEBUG_DCI_ENCODING @@ -2820,12 +2820,12 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *phy_vars_ue, format1_size_bits = sizeof_DCI1_1_5MHz_TDD_t; format1_size_bytes = sizeof(DCI1_1_5MHz_TDD_t); - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { format2_size_bits = sizeof_DCI2_1_5MHz_2A_TDD_t; format2_size_bytes = sizeof(DCI2_1_5MHz_2A_TDD_t); format2A_size_bits = sizeof_DCI2A_1_5MHz_2A_TDD_t; format2A_size_bytes = sizeof(DCI2A_1_5MHz_2A_TDD_t); - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { format2_size_bits = sizeof_DCI2_1_5MHz_4A_TDD_t; format2_size_bytes = sizeof(DCI2_1_5MHz_4A_TDD_t); format2A_size_bits = sizeof_DCI2A_1_5MHz_4A_TDD_t; @@ -2841,12 +2841,12 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *phy_vars_ue, format1_size_bits = sizeof_DCI1_1_5MHz_FDD_t; format1_size_bytes = sizeof(DCI1_1_5MHz_FDD_t); - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { format2_size_bits = sizeof_DCI2_1_5MHz_2A_FDD_t; format2_size_bytes = sizeof(DCI2_1_5MHz_2A_FDD_t); format2A_size_bits = sizeof_DCI2A_1_5MHz_2A_FDD_t; format2A_size_bytes = sizeof(DCI2A_1_5MHz_2A_FDD_t); - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { format2_size_bits = sizeof_DCI2_1_5MHz_4A_FDD_t; format2_size_bytes = sizeof(DCI2_1_5MHz_4A_FDD_t); format2A_size_bits = sizeof_DCI2A_1_5MHz_4A_FDD_t; @@ -2868,12 +2868,12 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *phy_vars_ue, format1_size_bits = sizeof_DCI1_5MHz_TDD_t; format1_size_bytes = sizeof(DCI1_5MHz_TDD_t); - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { format2_size_bits = sizeof_DCI2_5MHz_2A_TDD_t; format2_size_bytes = sizeof(DCI2_5MHz_2A_TDD_t); format2A_size_bits = sizeof_DCI2A_5MHz_2A_TDD_t; format2A_size_bytes = sizeof(DCI2A_5MHz_2A_TDD_t); - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { format2_size_bits = sizeof_DCI2_5MHz_4A_TDD_t; format2_size_bytes = sizeof(DCI2_5MHz_4A_TDD_t); format2A_size_bits = sizeof_DCI2A_5MHz_4A_TDD_t; @@ -2889,12 +2889,12 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *phy_vars_ue, format1_size_bits = sizeof_DCI1_5MHz_FDD_t; format1_size_bytes = sizeof(DCI1_5MHz_FDD_t); - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { format2_size_bits = sizeof_DCI2_5MHz_2A_FDD_t; format2_size_bytes = sizeof(DCI2_5MHz_2A_FDD_t); format2A_size_bits = sizeof_DCI2A_5MHz_2A_FDD_t; format2A_size_bytes = sizeof(DCI2A_5MHz_2A_FDD_t); - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { format2_size_bits = sizeof_DCI2_5MHz_4A_FDD_t; format2_size_bytes = sizeof(DCI2_5MHz_4A_FDD_t); format2A_size_bits = sizeof_DCI2A_5MHz_4A_FDD_t; @@ -2915,12 +2915,12 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *phy_vars_ue, format1_size_bits = sizeof_DCI1_10MHz_TDD_t; format1_size_bytes = sizeof(DCI1_10MHz_TDD_t); - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { format2_size_bits = sizeof_DCI2_10MHz_2A_TDD_t; format2_size_bytes = sizeof(DCI2_10MHz_2A_TDD_t); format2A_size_bits = sizeof_DCI2A_10MHz_2A_TDD_t; format2A_size_bytes = sizeof(DCI2A_10MHz_2A_TDD_t); - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { format2_size_bits = sizeof_DCI2_10MHz_4A_TDD_t; format2_size_bytes = sizeof(DCI2_10MHz_4A_TDD_t); format2A_size_bits = sizeof_DCI2A_10MHz_4A_TDD_t; @@ -2936,12 +2936,12 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *phy_vars_ue, format1_size_bits = sizeof_DCI1_10MHz_FDD_t; format1_size_bytes = sizeof(DCI1_10MHz_FDD_t); - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { format2_size_bits = sizeof_DCI2_10MHz_2A_FDD_t; format2_size_bytes = sizeof(DCI2_10MHz_2A_FDD_t); format2A_size_bits = sizeof_DCI2A_10MHz_2A_FDD_t; format2A_size_bytes = sizeof(DCI2A_10MHz_2A_FDD_t); - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { format2_size_bits = sizeof_DCI2_10MHz_4A_FDD_t; format2_size_bytes = sizeof(DCI2_10MHz_4A_FDD_t); format2A_size_bits = sizeof_DCI2A_10MHz_4A_FDD_t; @@ -2962,12 +2962,12 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *phy_vars_ue, format1_size_bits = sizeof_DCI1_20MHz_TDD_t; format1_size_bytes = sizeof(DCI1_20MHz_TDD_t); - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { format2_size_bits = sizeof_DCI2_20MHz_2A_TDD_t; format2_size_bytes = sizeof(DCI2_20MHz_2A_TDD_t); format2A_size_bits = sizeof_DCI2A_20MHz_2A_TDD_t; format2A_size_bytes = sizeof(DCI2A_20MHz_2A_TDD_t); - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { format2_size_bits = sizeof_DCI2_20MHz_4A_TDD_t; format2_size_bytes = sizeof(DCI2_20MHz_4A_TDD_t); format2A_size_bits = sizeof_DCI2A_20MHz_4A_TDD_t; @@ -2983,12 +2983,12 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *phy_vars_ue, format1_size_bits = sizeof_DCI1_20MHz_FDD_t; format1_size_bytes = sizeof(DCI1_20MHz_FDD_t); - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { format2_size_bits = sizeof_DCI2_20MHz_2A_FDD_t; format2_size_bytes = sizeof(DCI2_20MHz_2A_FDD_t); format2A_size_bits = sizeof_DCI2A_20MHz_2A_FDD_t; format2A_size_bytes = sizeof(DCI2A_20MHz_2A_FDD_t); - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { format2_size_bits = sizeof_DCI2_20MHz_4A_FDD_t; format2_size_bytes = sizeof(DCI2_20MHz_4A_FDD_t); format2A_size_bits = sizeof_DCI2A_20MHz_4A_FDD_t; diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index a0b4cba24e..7cb47a49e9 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -2662,7 +2662,7 @@ int generate_eNB_dlsch_params_from_dci(int frame, // compute DL power control parameters computeRhoA_eNB(pdsch_config_dedicated, dlsch[0],dlsch0_harq->dl_power_off); - computeRhoB_eNB(pdsch_config_dedicated,&(frame_parms->pdsch_config_common),frame_parms->nb_antennas_tx_eNB,dlsch[0],dlsch0_harq->dl_power_off); + computeRhoB_eNB(pdsch_config_dedicated,&(frame_parms->pdsch_config_common),frame_parms->nb_antenna_ports_eNB,dlsch[0],dlsch0_harq->dl_power_off); return(0); } @@ -3428,7 +3428,7 @@ int dump_dci(LTE_DL_FRAME_PARMS *frame_parms, DCI_ALLOC_t *dci) if ((frame_parms->frame_type == TDD) && (frame_parms->tdd_config>0)) { - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { switch(frame_parms->N_RB_DL) { case 6: LOG_D(PHY,"DCI format2A 2 antennas (FDD 1.5 MHz), rnti %x (%x): rb_alloc %x, mcs1 %d, mcs2 %d, harq_pid %d, ndi1 %d, ndi2 %d, RV1 %d, RV2 %d, TPC %d, dai %d, tbswap %d\n", @@ -3507,7 +3507,7 @@ int dump_dci(LTE_DL_FRAME_PARMS *frame_parms, DCI_ALLOC_t *dci) DevParam (frame_parms->N_RB_DL, 0, 0); break; } - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { switch(frame_parms->N_RB_DL) { case 6: LOG_D(PHY,"DCI format2A 4 antennas (TDD 1.5 MHz), rnti %x (%llx): rb_alloc %x, mcs1 %d, mcs2 %d, harq_pid %d, ndi1 %d, ndi2 %d, RV1 %d, RV2 %d, TPC %d, dai %d, tbswap %d, tpmi %d\n", @@ -3592,7 +3592,7 @@ int dump_dci(LTE_DL_FRAME_PARMS *frame_parms, DCI_ALLOC_t *dci) } } } else if (frame_parms->frame_type == FDD) { - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { switch(frame_parms->N_RB_DL) { case 6: LOG_D(PHY,"DCI format2A 2 antennas (FDD, 1.5 MHz), rnti %x (%x): rb_alloc %x, mcs1 %d, mcs2 %d, harq_pid %d, ndi1 %d, ndi2 %d, RV1 %d, RV2 %d, tb_swap %d, TPC %d\n", @@ -3666,7 +3666,7 @@ int dump_dci(LTE_DL_FRAME_PARMS *frame_parms, DCI_ALLOC_t *dci) DevParam (frame_parms->N_RB_DL, 0, 0); break; } - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { switch(frame_parms->N_RB_DL) { case 6: @@ -4467,7 +4467,7 @@ int generate_ue_dlsch_params_from_dci(int frame, switch (frame_parms->N_RB_DL) { case 6: - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { if (frame_type == TDD) { mcs1 = ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->mcs2; @@ -4487,7 +4487,7 @@ int generate_ue_dlsch_params_from_dci(int frame, tbswap = ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->tb_swap; tpmi = ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->tpmi; } - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { if (frame_type == TDD) { mcs1 = ((DCI2_1_5MHz_4A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2_1_5MHz_4A_TDD_t *)dci_pdu)->mcs2; @@ -4508,13 +4508,13 @@ int generate_ue_dlsch_params_from_dci(int frame, tpmi = ((DCI2_1_5MHz_4A_FDD_t *)dci_pdu)->tpmi; } } else { - LOG_E(PHY,"UE: subframe %d Format2 DCI: unsupported number of TX antennas %d\n",subframe,frame_parms->nb_antennas_tx_eNB); + LOG_E(PHY,"UE: subframe %d Format2 DCI: unsupported number of TX antennas %d\n",subframe,frame_parms->nb_antenna_ports_eNB); } break; case 25: - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { if (frame_type == TDD) { mcs1 = ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->mcs2; @@ -4536,7 +4536,7 @@ int generate_ue_dlsch_params_from_dci(int frame, tbswap = ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->tb_swap; tpmi = ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->tpmi; } - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { if (frame_type == TDD) { mcs1 = ((DCI2_5MHz_4A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2_5MHz_4A_TDD_t *)dci_pdu)->mcs2; @@ -4559,13 +4559,13 @@ int generate_ue_dlsch_params_from_dci(int frame, tpmi = ((DCI2_5MHz_4A_FDD_t *)dci_pdu)->tpmi; } } else { - LOG_E(PHY,"UE: Format2 DCI: unsupported number of TX antennas %d\n",frame_parms->nb_antennas_tx_eNB); + LOG_E(PHY,"UE: Format2 DCI: unsupported number of TX antennas %d\n",frame_parms->nb_antenna_ports_eNB); } break; case 50: - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { if (frame_type == TDD) { mcs1 = ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->mcs2; @@ -4587,7 +4587,7 @@ int generate_ue_dlsch_params_from_dci(int frame, tbswap = ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->tb_swap; tpmi = ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->tpmi; } - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { if (frame_type == TDD) { mcs1 = ((DCI2_10MHz_4A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2_10MHz_4A_TDD_t *)dci_pdu)->mcs2; @@ -4610,13 +4610,13 @@ int generate_ue_dlsch_params_from_dci(int frame, tpmi = ((DCI2_10MHz_4A_FDD_t *)dci_pdu)->tpmi; } } else { - LOG_E(PHY,"UE: Format2A DCI: unsupported number of TX antennas %d\n",frame_parms->nb_antennas_tx_eNB); + LOG_E(PHY,"UE: Format2A DCI: unsupported number of TX antennas %d\n",frame_parms->nb_antenna_ports_eNB); } break; case 100: - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { if (frame_type == TDD) { mcs1 = ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->mcs2; @@ -4638,7 +4638,7 @@ int generate_ue_dlsch_params_from_dci(int frame, tbswap = ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->tb_swap; tpmi = ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->tpmi; } - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { if (frame_type == TDD) { mcs1 = ((DCI2_20MHz_4A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2_20MHz_4A_TDD_t *)dci_pdu)->mcs2; @@ -4661,7 +4661,7 @@ int generate_ue_dlsch_params_from_dci(int frame, tpmi = ((DCI2_20MHz_4A_FDD_t *)dci_pdu)->tpmi; } } else { - LOG_E(PHY,"UE: Format2A DCI: unsupported number of TX antennas %d\n",frame_parms->nb_antennas_tx_eNB); + LOG_E(PHY,"UE: Format2A DCI: unsupported number of TX antennas %d\n",frame_parms->nb_antenna_ports_eNB); } break; @@ -4856,7 +4856,7 @@ int generate_ue_dlsch_params_from_dci(int frame, switch (frame_parms->N_RB_DL) { case 6: - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { if (frame_type == TDD) { mcs1 = ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->mcs2; @@ -4878,7 +4878,7 @@ int generate_ue_dlsch_params_from_dci(int frame, harq_pid = ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->harq_pid; tbswap = ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->tb_swap; } - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { if (frame_type == TDD) { mcs1 = ((DCI2A_1_5MHz_4A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2A_1_5MHz_4A_TDD_t *)dci_pdu)->mcs2; @@ -4903,13 +4903,13 @@ int generate_ue_dlsch_params_from_dci(int frame, tpmi = ((DCI2A_1_5MHz_4A_FDD_t *)dci_pdu)->tpmi; } } else { - LOG_E(PHY,"eNB: subframe %d UE %x, Format2A DCI: unsupported number of TX antennas %d\n",subframe,rnti,frame_parms->nb_antennas_tx_eNB); + LOG_E(PHY,"eNB: subframe %d UE %x, Format2A DCI: unsupported number of TX antennas %d\n",subframe,rnti,frame_parms->nb_antenna_ports_eNB); } break; case 25: - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { if (frame_type == TDD) { mcs1 = ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->mcs2; @@ -4933,7 +4933,7 @@ int generate_ue_dlsch_params_from_dci(int frame, harq_pid = ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->harq_pid; tbswap = ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->tb_swap; } - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { if (frame_type == TDD) { mcs1 = ((DCI2A_5MHz_4A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2A_5MHz_4A_TDD_t *)dci_pdu)->mcs2; @@ -4960,13 +4960,13 @@ int generate_ue_dlsch_params_from_dci(int frame, tpmi = ((DCI2A_5MHz_4A_FDD_t *)dci_pdu)->tpmi; } } else { - LOG_E(PHY,"eNB: subframe %d UE %x, Format2A DCI: unsupported number of TX antennas %d\n",subframe,rnti,frame_parms->nb_antennas_tx_eNB); + LOG_E(PHY,"eNB: subframe %d UE %x, Format2A DCI: unsupported number of TX antennas %d\n",subframe,rnti,frame_parms->nb_antenna_ports_eNB); } break; case 50: - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { if (frame_type == TDD) { mcs1 = ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->mcs2; @@ -4990,7 +4990,7 @@ int generate_ue_dlsch_params_from_dci(int frame, harq_pid = ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->harq_pid; tbswap = ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->tb_swap; } - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { if (frame_type == TDD) { mcs1 = ((DCI2A_10MHz_4A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2A_10MHz_4A_TDD_t *)dci_pdu)->mcs2; @@ -5017,13 +5017,13 @@ int generate_ue_dlsch_params_from_dci(int frame, tpmi = ((DCI2A_10MHz_4A_FDD_t *)dci_pdu)->tpmi; } } else { - LOG_E(PHY,"eNB: subframe %d UE %x, Format2A DCI: unsupported number of TX antennas %d\n",subframe,rnti,frame_parms->nb_antennas_tx_eNB); + LOG_E(PHY,"eNB: subframe %d UE %x, Format2A DCI: unsupported number of TX antennas %d\n",subframe,rnti,frame_parms->nb_antenna_ports_eNB); } break; case 100: - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { if (frame_type == TDD) { mcs1 = ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->mcs2; @@ -5047,7 +5047,7 @@ int generate_ue_dlsch_params_from_dci(int frame, harq_pid = ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->harq_pid; tbswap = ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->tb_swap; } - } else if (frame_parms->nb_antennas_tx_eNB == 4) { + } else if (frame_parms->nb_antenna_ports_eNB == 4) { if (frame_type == TDD) { mcs1 = ((DCI2A_20MHz_4A_TDD_t *)dci_pdu)->mcs1; mcs2 = ((DCI2A_20MHz_4A_TDD_t *)dci_pdu)->mcs2; @@ -5074,7 +5074,7 @@ int generate_ue_dlsch_params_from_dci(int frame, tpmi = ((DCI2A_20MHz_4A_FDD_t *)dci_pdu)->tpmi; } } else { - LOG_E(PHY,"eNB: subframe %d UE %x, Format2A DCI: unsupported number of TX antennas %d\n",subframe,rnti,frame_parms->nb_antennas_tx_eNB); + LOG_E(PHY,"eNB: subframe %d UE %x, Format2A DCI: unsupported number of TX antennas %d\n",subframe,rnti,frame_parms->nb_antenna_ports_eNB); } break; @@ -5217,7 +5217,7 @@ int generate_ue_dlsch_params_from_dci(int frame, } } - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { dlsch0_harq->TBS = TBStable[get_I_TBS(dlsch0_harq->mcs)][dlsch0_harq->nb_rb-1]; dlsch1_harq->TBS = TBStable[get_I_TBS(dlsch1_harq->mcs)][dlsch0_harq->nb_rb-1]; @@ -5232,7 +5232,7 @@ int generate_ue_dlsch_params_from_dci(int frame, dlsch0_harq->mimo_mode = ALAMOUTI; dlsch1_harq->mimo_mode = ALAMOUTI; } - } else if (frame_parms->nb_antennas_tx_eNB == 4) { // 4 antenna case + } else if (frame_parms->nb_antenna_ports_eNB == 4) { // 4 antenna case if ((dlsch0->active==1) && (dlsch1->active==1)) { switch (tpmi) { case 0: // one layer per transport block @@ -5316,7 +5316,7 @@ int generate_ue_dlsch_params_from_dci(int frame, } } } else { - LOG_E(PHY,"Illegal number of antennas for eNB %d\n",frame_parms->nb_antennas_tx_eNB); + LOG_E(PHY,"Illegal number of antennas for eNB %d\n",frame_parms->nb_antenna_ports_eNB); } if (mcs1 <= 28) @@ -5528,7 +5528,7 @@ int generate_ue_dlsch_params_from_dci(int frame, // compute DL power control parameters computeRhoA_UE(pdsch_config_dedicated, dlsch[0],dlsch0_harq->dl_power_off); - computeRhoB_UE(pdsch_config_dedicated,&(frame_parms->pdsch_config_common),frame_parms->nb_antennas_tx_eNB,dlsch[0],dlsch0_harq->dl_power_off); + computeRhoB_UE(pdsch_config_dedicated,&(frame_parms->pdsch_config_common),frame_parms->nb_antenna_ports_eNB,dlsch[0],dlsch0_harq->dl_power_off); return(0); } @@ -7676,7 +7676,7 @@ double sinr_eff_cqi_calc(PHY_VARS_UE *phy_vars_ue, uint8_t eNB_id) switch(transmission_mode) { case 1: for (count=0; countN_RB_DL*12; count++) { - for(a_tx=0; a_txnb_antennas_tx_eNB; a_tx++) { + for(a_tx=0; a_txnb_antenna_ports_eNB; a_tx++) { for (a_rx=0; a_rxnb_antennas_rx; a_rx++) { s_dB[count] = 10*log10(pow(((int16_t *) dl_channel_est[(a_tx<<1)+a_rx])[2*count+(LTE_CE_FILTER_LENGTH)*2],2) + pow(((int16_t *) dl_channel_est[(a_tx<<1)+a_rx])[2*count+1+(LTE_CE_FILTER_LENGTH)*2], 2)) - meas->n0_power_avg_dB; @@ -7690,7 +7690,7 @@ double sinr_eff_cqi_calc(PHY_VARS_UE *phy_vars_ue, uint8_t eNB_id) for (count=0; countN_RB_DL*12; count++) { abs_channel=0; - for(a_tx=0; a_txnb_antennas_tx_eNB; a_tx++) { + for(a_tx=0; a_txnb_antenna_ports_eNB; a_tx++) { for (a_rx=0; a_rxnb_antennas_rx; a_rx++) { abs_channel += (pow(((int16_t *) dl_channel_est[(a_tx<<1)+a_rx])[2*count+(LTE_CE_FILTER_LENGTH)*2],2) + pow(((int16_t *) dl_channel_est[(a_tx<<1)+a_rx])[2*count+1+(LTE_CE_FILTER_LENGTH)*2],2)); } @@ -7710,7 +7710,7 @@ double sinr_eff_cqi_calc(PHY_VARS_UE *phy_vars_ue, uint8_t eNB_id) qq = (q>>(((count/12)>>2)<<1))&3; //printf("pmi_alloc %d: rb %d, pmi %d\n",q,count/12,qq); - for(a_tx=0; a_txnb_antennas_tx_eNB; a_tx++) { + for(a_tx=0; a_txnb_antenna_ports_eNB; a_tx++) { for (a_rx=0; a_rxnb_antennas_rx; a_rx++) { switch(qq) { case 0: @@ -7792,7 +7792,7 @@ double sinr_eff_cqi_calc(PHY_VARS_UE *phy_vars_ue, uint8_t eNB_id) qq = (q>>(((count/12)>>2)<<1))&3; //printf("pmi_alloc %d: rb %d, pmi %d\n",q,count/12,qq); - for(a_tx=0; a_txnb_antennas_tx_eNB; a_tx++) { + for(a_tx=0; a_txnb_antenna_ports_eNB; a_tx++) { for (a_rx=0; a_rxnb_antennas_rx; a_rx++) { switch(qq) { case 0: diff --git a/openair1/PHY/LTE_TRANSPORT/defs.h b/openair1/PHY/LTE_TRANSPORT/defs.h index 0d3d028c8a..96c2b7d760 100644 --- a/openair1/PHY/LTE_TRANSPORT/defs.h +++ b/openair1/PHY/LTE_TRANSPORT/defs.h @@ -240,6 +240,8 @@ typedef struct { typedef struct { /// TX buffers for UE-spec transmission (antenna ports 5 or 7..14, prior to precoding) uint32_t *txdataF[8]; + /// beamforming weights for UE-spec transmission (antenna ports 5 or 7..14), for each codeword, maximum 4 layers? + uint32_t **ue_spec_bf_weights[4]; /// Allocated RNTI (0 means DLSCH_t is not currently used) uint16_t rnti; /// Active flag for baseband transmitter processing diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index f8af3038d3..0db7708860 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -117,12 +117,13 @@ void free_eNB_dlsch(LTE_eNB_DLSCH_t *dlsch) } -LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,unsigned char N_RB_DL, uint8_t abstraction_flag) +LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,unsigned char N_RB_DL, uint8_t abstraction_flag, LTE_DL_FRAME_PARMS* frame_parms) { LTE_eNB_DLSCH_t *dlsch; - unsigned char exit_flag = 0,i,j,r; + unsigned char exit_flag = 0,i,j,r,aa; unsigned char bw_scaling =1; + uint8_t nb_antennas_tx = frame_parms->nb_antennas_tx; switch (N_RB_DL) { case 6: @@ -193,6 +194,15 @@ LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,unsigne exit_flag=3; } } + + for (i=0; i<4; i++) { + dlsch->ue_spec_bf_weights[i] = (int32_t **)malloc16(nb_antennas_tx*sizeof(int32_t*)); + dlsch->ue_spec_bf_weights[i] = (int32_t **)malloc16(nb_antennas_tx*sizeof(int32_t*)); + + for (aa=0; aaue_spec_bf_weights[i][aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); + } + } if (exit_flag==0) { for (i=0; irb_alloc_even; - if (frame_parms->nb_antennas_tx_eNB>1 && beamforming_mode==0) { + if (frame_parms->nb_antenna_ports_eNB>1 && beamforming_mode==0) { #ifdef DEBUG_DLSCH_MOD LOG_I(PHY,"dlsch: using pmi %x (%p), rb_alloc %x\n",pmi2hex_2Ar1(dlsch0_harq->pmi_alloc),dlsch_ue[0],dlsch0_harq->rb_alloc_even[0]); #endif @@ -296,7 +296,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, // in case of precoding we add an additional factor of two for the precoding gain avgs = 0; - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) for (aarx=0; aarxnb_antennas_rx; aarx++) avgs = cmax(avgs,avg[(aatx<<1)+aarx]); @@ -304,7 +304,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, lte_ue_pdsch_vars[eNB_id]->log2_maxh = (log2_approx(avgs)/2); - // + log2_approx(frame_parms->nb_antennas_tx_eNB-1) //-1 because log2_approx counts the number of bits + // + log2_approx(frame_parms->nb_antenna_ports_eNB-1) //-1 because log2_approx counts the number of bits // + log2_approx(frame_parms->nb_antennas_rx-1); if ((dlsch0_harq->mimo_mode>=UNIFORM_PRECODING11) && @@ -317,11 +317,11 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, Nb_tx*Nb_rx in TM2,4,5 Nb_tx^2*Nb_rx in TM6 */ /* - K = frame_parms->nb_antennas_rx*frame_parms->nb_antennas_tx_eNB; //that also covers TM1 since Nb_tx=1 + K = frame_parms->nb_antennas_rx*frame_parms->nb_antenna_ports_eNB; //that also covers TM1 since Nb_tx=1 if ((dlsch0_harq->mimo_mode>=UNIFORM_PRECODING11) && (dlsch0_harq->mimo_mode< DUALSTREAM_UNIFORM_PRECODING1) && (dlsch0_harq->dl_power_off==1)) // we are in TM 6 - K *= frame_parms->nb_antennas_tx_eNB; + K *= frame_parms->nb_antenna_ports_eNB; lte_ue_pdsch_vars[eNB_id]->log2_maxh = (log2_approx(K*avgs)/2); */ @@ -332,7 +332,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, #endif } - aatx = frame_parms->nb_antennas_tx_eNB; + aatx = frame_parms->nb_antenna_ports_eNB; aarx = frame_parms->nb_antennas_rx; if (dlsch0_harq->mimo_modemimo_mode == LARGE_CDD) { // TM3 // LOG_I(PHY,"Running PDSCH RX for TM3\n"); - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { if (first_symbol_flag==1) { // effective channel of desired user is always stronger than interfering eff. channel dlsch_channel_level_TM3(lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext, @@ -573,7 +573,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, // printf("MRC\n"); if (frame_parms->nb_antennas_rx > 1) { if (dlsch0_harq->mimo_mode == LARGE_CDD) { - if (frame_parms->nb_antennas_tx_eNB == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { dlsch_detection_mrc(frame_parms, lte_ue_pdsch_vars[eNB_id]->rxdataF_comp0, lte_ue_pdsch_vars[eNB_id]->rxdataF_comp1[dlsch0_harq->round], @@ -870,7 +870,7 @@ void dlsch_channel_compensation(int **rxdataF_ext, pilots=1; } - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) { + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) { if (mod_order == 4) { QAM_amp128 = _mm_set1_epi16(QAM16_n1); // 2/sqrt(10) QAM_amp128b = _mm_setzero_si128(); @@ -1130,7 +1130,7 @@ void dlsch_channel_compensation(int **rxdataF_ext, } } - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) { + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) { if (mod_order == 4) { QAM_amp128 = vmovq_n_s16(QAM16_n1); // 2/sqrt(10) QAM_amp128b = vmovq_n_s16(0); @@ -2643,7 +2643,7 @@ void dlsch_detection_mrc(LTE_DL_FRAME_PARMS *frame_parms, if (frame_parms->nb_antennas_rx>1) { - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) { + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) { rxdataF_comp128_0 = (__m128i *)&rxdataF_comp[(aatx<<1)][symbol*frame_parms->N_RB_DL*12]; rxdataF_comp128_1 = (__m128i *)&rxdataF_comp[(aatx<<1)+1][symbol*frame_parms->N_RB_DL*12]; @@ -2703,7 +2703,7 @@ void dlsch_detection_mrc(LTE_DL_FRAME_PARMS *frame_parms, if (frame_parms->nb_antennas_rx>1) { - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) { + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) { rxdataF_comp128_0 = (int16x8_t *)&rxdataF_comp[(aatx<<1)][symbol*frame_parms->N_RB_DL*12]; rxdataF_comp128_1 = (int16x8_t *)&rxdataF_comp[(aatx<<1)+1][symbol*frame_parms->N_RB_DL*12]; @@ -2785,7 +2785,7 @@ void dlsch_scale_channel(int **dl_ch_estimates_ext, ch_amp128 = _mm_set1_epi16(ch_amp); // Q3.13 - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) { + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) { for (aarx=0; aarxnb_antennas_rx; aarx++) { dl_ch128=(__m128i *)&dl_ch_estimates_ext[(aatx<<1)+aarx][symbol*frame_parms->N_RB_DL*12]; @@ -2829,7 +2829,7 @@ void dlsch_channel_level(int **dl_ch_estimates_ext, symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol; - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) for (aarx=0; aarxnb_antennas_rx; aarx++) { //clear average level avg128D = _mm_setzero_si128(); @@ -2886,7 +2886,7 @@ void dlsch_channel_level(int **dl_ch_estimates_ext, symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol; - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) for (aarx=0; aarxnb_antennas_rx; aarx++) { //clear average level avg128D = vdupq_n_s32(0); @@ -3119,7 +3119,7 @@ void dlsch_channel_level_TM7(int **dl_bf_ch_estimates_ext, symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol; - for (aatx=0; aatxnb_antennas_tx_eNB; aatx++) + for (aatx=0; aatxnb_antenna_ports_eNB; aatx++) for (aarx=0; aarxnb_antennas_rx; aarx++) { //clear average level avg128D = _mm_setzero_si128(); @@ -4931,7 +4931,7 @@ void dump_dlsch2(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint16_t coded_bits_per write_output(fname,vname,phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext[1],12*N_RB_DL*nsymb,1,1); } - if (phy_vars_ue->lte_frame_parms.nb_antennas_tx_eNB == 2) { + if (phy_vars_ue->lte_frame_parms.nb_antenna_ports_eNB == 2) { sprintf(fname,"dlsch%d_ch_r%d_ext10.m",eNB_id,round); sprintf(vname,"dl%d_ch_r%d_ext10",eNB_id,round); write_output(fname,vname,phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_ch_estimates_ext[2],12*N_RB_DL*nsymb,1,1); @@ -4959,7 +4959,7 @@ void dump_dlsch2(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint16_t coded_bits_per sprintf(fname,"dlsch%d_rxF_r%d_comp0.m",eNB_id,round); sprintf(vname,"dl%d_rxF_r%d_comp0",eNB_id,round); write_output(fname,vname,phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->rxdataF_comp0[0],12*N_RB_DL*nsymb,1,1); - if (phy_vars_ue->lte_frame_parms.nb_antennas_tx_eNB == 2) { + if (phy_vars_ue->lte_frame_parms.nb_antenna_ports_eNB == 2) { sprintf(fname,"dlsch%d_rxF_r%d_comp1.m",eNB_id,round); sprintf(vname,"dl%d_rxF_r%d_comp1",eNB_id,round); write_output(fname,vname,phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->rxdataF_comp1[0][round],12*N_RB_DL*nsymb,1,1); diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 6580e827c1..6f05b14f87 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -70,7 +70,10 @@ uint8_t is_not_pilot(uint8_t pilots, uint8_t re, uint8_t nushift, uint8_t use2nd return(0); } -//uint8_t is_not_UEspecRS(int first_layer,int re) +/*uint8_t is_not_UEspecRS(int first_layer,int re) +{ + return(1); +}*/ uint8_t is_not_UEspecRS(int8_t lprime, uint8_t re, uint8_t nushift, uint8_t Ncp, uint8_t beamforming_mode) { uint8_t offset = (lprime==1||lprime==3)?2:0; @@ -165,8 +168,8 @@ int allocate_REs_in_RB(PHY_VARS_eNB *phy_vars_eNB, uint32_t *jj2, uint16_t re_offset, uint32_t symbol_offset, - LTE_DL_eNB_HARQ_t *dlsch0_harq, - LTE_DL_eNB_HARQ_t *dlsch1_harq, + LTE_eNB_DLSCH_t *dlsch0, + LTE_eNB_DLSCH_t *dlsch1, uint8_t pilots, int16_t amp, uint8_t precoder_index, @@ -177,10 +180,13 @@ int allocate_REs_in_RB(PHY_VARS_eNB *phy_vars_eNB, uint8_t skip_half, uint8_t lprime, uint8_t mprime, - uint8_t Ns, - int32_t **beamforming_weights) + uint8_t Ns) { + uint8_t harq_pid = dlsch0->current_harq_pid; + LTE_DL_eNB_HARQ_t *dlsch0_harq = dlsch0->harq_processes[harq_pid]; + LTE_DL_eNB_HARQ_t *dlsch1_harq = (dlsch1==NULL) ? NULL : dlsch1->harq_processes[harq_pid]; + LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_eNB->lte_frame_parms; uint8_t *x0 = dlsch0_harq->e; MIMO_mode_t mimo_mode = dlsch0_harq->mimo_mode; @@ -192,10 +198,11 @@ int allocate_REs_in_RB(PHY_VARS_eNB *phy_vars_eNB, uint8_t *x1=NULL; uint8_t mod_order1=2; - // Fill these in later for TM8-10 // int Nlayers1; // int first_layer1; + + int use2ndpilots = (frame_parms->mode1_flag==1)?1:0; uint32_t tti_offset,aa; @@ -281,7 +288,7 @@ break; else if (skip_half==2) first_re=6; - for (re=first_re; reofdm_symbol_size+1; @@ -301,20 +308,16 @@ break; switch (mod_order0) { case 2: //QPSK -// printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t*)&txdataF[aa][tti_offset])[0] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i - } + //printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + ((int16_t*)&txdataF[0][tti_offset])[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i *jj = *jj + 1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t*)&txdataF[aa][tti_offset])[1] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} - } + ((int16_t*)&txdataF[0][tti_offset])[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} *jj = *jj + 1; - // printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + //printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); break; case 4: //16QAM @@ -343,12 +346,8 @@ break; *jj=*jj+1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s0[qam16_table_offset_re]; - ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s0[qam16_table_offset_im]; - // ((int16_t *)&txdataF[aa][tti_offset])[0]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); - // ((int16_t *)&txdataF[aa][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); - } + ((int16_t *)&txdataF[0][tti_offset])[0]=qam_table_s0[qam16_table_offset_re];//(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); + ((int16_t *)&txdataF[0][tti_offset])[1]=qam_table_s0[qam16_table_offset_im];//(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); break; @@ -388,10 +387,8 @@ break; *jj=*jj+1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s0[qam64_table_offset_re];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); - ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s0[qam64_table_offset_im];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); - } + ((int16_t *)&txdataF[aa][tti_offset])[0]=qam_table_s0[qam64_table_offset_re];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); + ((int16_t *)&txdataF[aa][tti_offset])[1]=qam_table_s0[qam64_table_offset_im];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); break; @@ -587,7 +584,7 @@ break; *re_allocated = *re_allocated + 1; - if (frame_parms->nb_antennas_tx == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { switch (mod_order0) { default: LOG_E(PHY,"Unknown mod_order0 %d\n",mod_order0); @@ -799,11 +796,11 @@ break; ((int16_t*)&tmp_sample1)[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; *jj = *jj + 1; - // normalization for 2 tx antennas + // normalization for 2 tx antenna ports ((int16_t*)&txdataF[0][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*ONE_OVER_SQRT2_Q15)>>15); ((int16_t*)&txdataF[0][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*ONE_OVER_SQRT2_Q15)>>15); - if (frame_parms->nb_antennas_tx == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { layer1prec2A(&tmp_sample1,&tmp_sample2,precoder_index); ((int16_t*)&txdataF[1][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample2)[0]*ONE_OVER_SQRT2_Q15)>>15); ((int16_t*)&txdataF[1][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample2)[1]*ONE_OVER_SQRT2_Q15)>>15); @@ -843,7 +840,7 @@ break; ((int16_t *)&txdataF[0][tti_offset])[0] += ((int16_t*)&tmp_sample1)[0]; ((int16_t *)&txdataF[0][tti_offset])[1] += ((int16_t*)&tmp_sample1)[1]; - if (frame_parms->nb_antennas_tx == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { layer1prec2A(&tmp_sample1,&tmp_sample2,precoder_index); ((int16_t*)&txdataF[1][tti_offset])[0] += ((int16_t*)&tmp_sample2)[0]; ((int16_t*)&txdataF[1][tti_offset])[1] += ((int16_t*)&tmp_sample2)[1]; @@ -893,7 +890,7 @@ break; ((int16_t *)&txdataF[0][tti_offset])[0] += ((int16_t*)&tmp_sample1)[0]; ((int16_t *)&txdataF[0][tti_offset])[1] += ((int16_t*)&tmp_sample1)[1]; - if (frame_parms->nb_antennas_tx == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { layer1prec2A(&tmp_sample1,&tmp_sample2,precoder_index); ((int16_t*)&txdataF[1][tti_offset])[0] += ((int16_t*)&tmp_sample2)[0]; ((int16_t*)&txdataF[1][tti_offset])[1] += ((int16_t*)&tmp_sample2)[1]; @@ -902,7 +899,19 @@ break; break; } - } else if(mimo_mode == TM7){ + } + + if (mimo_mode == ALAMOUTI) { + re++; // adjacent carriers are taken care of by precoding + *re_allocated = *re_allocated + 1; + + if (is_not_pilot(pilots,re,frame_parms->nushift,use2ndpilots)==0) { + re++; + *re_allocated = *re_allocated + 1; + } + } + + if(mimo_mode == TM7) { *re_allocated = *re_allocated + 1; if (is_not_UEspecRS(lprime,re,frame_parms->Nid_cell%3,frame_parms->Ncp,7)) { @@ -910,20 +919,12 @@ break; switch (mod_order0){ case 2: //QPSK - ((int16_t*)&tmp_sample1)[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + ((int16_t*)&txdataF[5][tti_offset])[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; *jj = *jj + 1; - ((int16_t*)&tmp_sample1)[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + ((int16_t*)&txdataF[5][tti_offset])[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; *jj = *jj + 1; //printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); - } - - //printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); break; case 4: //16QAM @@ -952,15 +953,8 @@ break; *jj=*jj+1; - ((int16_t*)&tmp_sample1)[0] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); - ((int16_t*)&tmp_sample1)[1] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); - - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); - } + ((int16_t*)&txdataF[5][tti_offset])[0] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); + ((int16_t*)&txdataF[5][tti_offset])[1] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); break; @@ -1000,20 +994,13 @@ break; *jj=*jj+1; - ((int16_t*)&tmp_sample1)[0] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); - ((int16_t*)&tmp_sample1)[1] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); - - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); - } + ((int16_t*)&txdataF[5][tti_offset])[0] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); + ((int16_t*)&txdataF[5][tti_offset])[1] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); break; } - } else{ + } else { //precoding UE spec RS //printf("precoding UE spec RS\n"); @@ -1021,38 +1008,111 @@ break; ind_dword = ind>>4; ind_qpsk_symb = ind&0xf; - tmp_sample1 = qpsk[(phy_vars_eNB->lte_gold_uespec_port5_table[0][Ns][ind_dword]>>(2*ind_qpsk_symb))&3]; + txdataF[5][tti_offset] = qpsk[(phy_vars_eNB->lte_gold_uespec_port5_table[0][Ns][ind_dword]>>(2*ind_qpsk_symb))&3]; mprime2++; - for (aa=0; aanb_antennas_tx; aa++) { - - ((int16_t*)&txdataF[aa][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[0] +=-(int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[0]*((int16_t*)&beamforming_weights[re][aa])[1])>>15); - ((int16_t*)&txdataF[aa][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*((int16_t*)&beamforming_weights[re][aa])[0])>>15); - - // ((int16_t*)&txdataF[aa][tti_offset])[0] = 0xffff; - // ((int16_t*)&txdataF[aa][tti_offset])[1] = 0xffff; - //printf("lprime=%d,nb_rb=%d,mprime2=%d,ind=%d,Ns=%d\n",lprime,dlsch0_harq->nb_rb,mprime2,ind,Ns); - //printf("tmp_sample1=(%d,%d)\n",((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); - //printf("beamforing_weights[%d][%d]=(%d,%d)\n",re,aa,((int16_t*)&beamforming_weights[re][aa])[0],((int16_t*)&beamforming_weights[re][aa])[1]); - //printf("txdataF[%d][%d]= (%d,%d)\n ",aa,tti_offset,((int16_t*)&txdataF[aa][tti_offset])[0],((int16_t*)&txdataF[aa][tti_offset])[1]); - } - } + } else if (mimo_mode == TM8) { //TM8 + + // if (is_not_UEspecRS(first_layer0,re)) { + if (is_not_UEspecRS(lprime,re,frame_parms->Nid_cell%3,frame_parms->Ncp,8)) { + switch (mod_order0) { + case 2: //QPSK + + // printf("%d : %d,%d => ",tti_offset,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); + for (int layer=first_layer0; layer<=(first_layer0+Nlayers0); layer++) { + ((int16_t*)&txdataF[layer][tti_offset])[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i + *jj = *jj + 1; + ((int16_t*)&txdataF[layer][tti_offset])[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} + *jj = *jj + 1; + } + + break; + + case 4: //16QAM + // if (is_not_UEspecRS(0/*layer (FIXME uninitialized!)*/,re)) { + if (is_not_UEspecRS(lprime,re,frame_parms->Nid_cell%3,frame_parms->Ncp,8)) { + qam16_table_offset_re = 0; + qam16_table_offset_im = 0; + + if (x0[*jj] == 1) + qam16_table_offset_re+=2; + + *jj = *jj + 1; + + if (x0[*jj] == 1) + qam16_table_offset_im+=2; + + *jj = *jj + 1; + + if (x0[*jj] == 1) + qam16_table_offset_re+=1; + + *jj = *jj + 1; + + if (x0[*jj] == 1) + qam16_table_offset_im+=1; + + *jj = *jj + 1; + + for (int layer=first_layer0; layer<=(first_layer0+Nlayers0); layer++) { + ((int16_t*)&txdataF[layer][tti_offset])[0] = qam_table_s0[qam16_table_offset_re]; + ((int16_t*)&txdataF[layer][tti_offset])[1] = qam_table_s0[qam16_table_offset_im]; + } + } + + break; + + case 6: //64QAM + + + qam64_table_offset_re = 0; + qam64_table_offset_im = 0; + + if (x0[*jj] == 1) + qam64_table_offset_re+=4; + + *jj = *jj + 1; + + if (x0[*jj] == 1) + qam64_table_offset_im+=4; + + *jj = *jj + 1; + + if (x0[*jj] == 1) + qam64_table_offset_re+=2; + + *jj = *jj + 1; + + if (x0[*jj] == 1) + qam64_table_offset_im+=2; + + *jj = *jj + 1; + + if (x0[*jj] == 1) + qam64_table_offset_re+=1; + + *jj = *jj + 1; + + if (x0[*jj] == 1) + qam64_table_offset_im+=1; + + *jj = *jj + 1; + + for (int layer=first_layer0; layer<=(first_layer0+Nlayers0); layer++) { + ((int16_t*)&txdataF[layer][tti_offset])[0] = qam_table_s0[qam64_table_offset_re]; + ((int16_t*)&txdataF[layer][tti_offset])[1] = qam_table_s0[qam64_table_offset_im]; + } + + break; + + } + } + } else if (mimo_mode>=TM9_10) { msg("allocate_REs_in_RB() [dlsch.c] : ERROR, unknown mimo_mode %d\n",mimo_mode); return(-1); } - if (mimo_mode == ALAMOUTI) { - re++; // adjacent carriers are taken care of by precoding - *re_allocated = *re_allocated + 1; - - if (is_not_pilot(pilots,re,frame_parms->nushift,use2ndpilots)==0) { - re++; - *re_allocated = *re_allocated + 1; - } - } } @@ -1076,7 +1136,7 @@ int allocate_REs_in_RB_MCH(mod_sym_t **txdataF, LTE_DL_FRAME_PARMS *frame_parms) { - uint32_t tti_offset,aa; + uint32_t tti_offset; uint8_t re; uint8_t qam64_table_offset_re = 0; uint8_t qam64_table_offset_im = 0; @@ -1117,15 +1177,13 @@ int allocate_REs_in_RB_MCH(mod_sym_t **txdataF, case 2: //QPSK // printf("%d : %d,%d => ",tti_offset,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - for (aa=0; aanb_antennas_tx; aa++) - ((int16_t*)&txdataF[aa][tti_offset])[0] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i + ((int16_t*)&txdataF[4][tti_offset])[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i - *jj = *jj + 1; + *jj = *jj + 1; - for (aa=0; aanb_antennas_tx; aa++) - ((int16_t*)&txdataF[aa][tti_offset])[1] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} + ((int16_t*)&txdataF[4][tti_offset])[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} - *jj = *jj + 1; + *jj = *jj + 1; // printf("%d,%d\n",((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); break; @@ -1156,12 +1214,8 @@ int allocate_REs_in_RB_MCH(mod_sym_t **txdataF, *jj=*jj+1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s[qam16_table_offset_re]; - ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s[qam16_table_offset_im]; - // ((int16_t *)&txdataF[aa][tti_offset])[0]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); - // ((int16_t *)&txdataF[aa][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); - } + ((int16_t *)&txdataF[4][tti_offset])[0]=qam_table_s[qam16_table_offset_re];//(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); + ((int16_t *)&txdataF[4][tti_offset])[1]=qam_table_s[qam16_table_offset_im];//(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); break; @@ -1201,10 +1255,8 @@ int allocate_REs_in_RB_MCH(mod_sym_t **txdataF, *jj=*jj+1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s[qam64_table_offset_re];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); - ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s[qam64_table_offset_im];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); - } + ((int16_t *)&txdataF[4][tti_offset])[0]=qam_table_s[qam64_table_offset_re];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); + ((int16_t *)&txdataF[4][tti_offset])[1]=qam_table_s[qam64_table_offset_im];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); break; @@ -1265,8 +1317,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, uint32_t subframe_offset, uint8_t num_pdcch_symbols, LTE_eNB_DLSCH_t *dlsch0, - LTE_eNB_DLSCH_t *dlsch1, - int32_t **beamforming_weights) + LTE_eNB_DLSCH_t *dlsch1) { LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_eNB->lte_frame_parms; @@ -1287,9 +1338,9 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, int16_t qam16_table_a1[4],qam64_table_a1[8],qam16_table_b1[4],qam64_table_b1[8]; int16_t *qam_table_s0,*qam_table_s1; MIMO_mode_t mimo_mode = dlsch0_harq->mimo_mode; - int32_t **beamforming_weights_RB = beamforming_weights; uint8_t mprime=0,Ns; int8_t lprime=-1; + int aa=0; #ifdef DEBUG_DLSCH_MODULATION uint8_t Nl0 = dlsch0_harq->Nl; @@ -1392,6 +1443,12 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, else lprime=-1; } + + // mapping ue specific beamforming weights from UE specified DLSCH structure to common space + for (aa=0;aanb_antennas_tx;aa++){ + memcpy(phy_vars_eNB->lte_eNB_common_vars.ue_spec_bf_weights[0][0][aa],dlsch0->ue_spec_bf_weights[0][aa],frame_parms->ofdm_symbol_size*sizeof(int32_t)); + } + } Ns = 2*subframe_offset+(l>=(nsymb>>1)); @@ -1399,8 +1456,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, re_offset = frame_parms->first_carrier_offset; symbol_offset = (uint32_t)frame_parms->ofdm_symbol_size*(l+(subframe_offset*nsymb)); - //for (aa=0;aanb_antennas_tx;aa++) - // memset(&txdataF[aa][symbol_offset],0,frame_parms->ofdm_symbol_size<<2); + //memset(&txdataF[aa][symbol_offset],0,frame_parms->ofdm_symbol_size<<2); //printf("symbol_offset %d,subframe offset %d : pilots %d\n",symbol_offset,subframe_offset,pilots); for (rb=0; rbN_RB_DL; rb++) { @@ -1569,8 +1625,8 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, &jj2, re_offset, symbol_offset, - dlsch0->harq_processes[harq_pid], - (dlsch1==NULL) ? NULL : dlsch1->harq_processes[harq_pid], + dlsch0, + dlsch1, pilots, ((pilots) ? amp_rho_b : amp_rho_a), get_pmi(frame_parms->N_RB_DL,dlsch0->harq_processes[harq_pid],rb), @@ -1581,8 +1637,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, skip_half, lprime, mprime, - Ns, - beamforming_weights_RB); + Ns); if(mimo_mode==TM7 && lprime>=0) mprime +=3+frame_parms->Ncp; @@ -1590,20 +1645,17 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, } re_offset+=12; // go to next RB - beamforming_weights_RB +=12; - // check if we crossed the symbol boundary and skip DC if (re_offset >= frame_parms->ofdm_symbol_size) { - if (skip_dc == 0) //even number of RBs (doesn't straddle DC) - re_offset=1; - else - re_offset=7; // odd number of RBs - } - beamforming_weights_RB = beamforming_weights; - } - + if (skip_dc == 0) //even number of RBs (doesn't straddle DC) + re_offset=1; + else + re_offset=7; // odd number of RBs } + } + + } diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c index 69351e297f..10815bc3e0 100644 --- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c +++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c @@ -163,7 +163,7 @@ char phich_resource[6]; if (pbch_decoded) { - frame_parms->nb_antennas_tx_eNB = pbch_tx_ant; + frame_parms->nb_antenna_ports_eNB = pbch_tx_ant; // set initial transmission mode to 1 or 2 depending on number of detected TX antennas frame_parms->mode1_flag = (pbch_tx_ant==1); @@ -566,7 +566,7 @@ int initial_sync(PHY_VARS_UE *phy_vars_ue, runmode_t mode) phy_vars_ue->lte_frame_parms.N_RB_DL, phy_vars_ue->lte_frame_parms.phich_config_common.phich_duration, phich_string[phy_vars_ue->lte_frame_parms.phich_config_common.phich_resource], - phy_vars_ue->lte_frame_parms.nb_antennas_tx_eNB); + phy_vars_ue->lte_frame_parms.nb_antenna_ports_eNB); #if defined(OAI_USRP) || defined(EXMIMO) LOG_I(PHY,"[UE %d] Frame %d Measured Carrier Frequency %.0f Hz (offset %d Hz)\n", phy_vars_ue->Mod_id, diff --git a/openair1/PHY/LTE_TRANSPORT/pbch.c b/openair1/PHY/LTE_TRANSPORT/pbch.c index 0582a63956..21061c1654 100755 --- a/openair1/PHY/LTE_TRANSPORT/pbch.c +++ b/openair1/PHY/LTE_TRANSPORT/pbch.c @@ -200,7 +200,7 @@ int generate_pbch(LTE_eNB_PBCH *eNB_pbch, /* // scramble crc with PBCH CRC mask (Table 5.3.1.1-1 of 3GPP 36.212-860) - switch (frame_parms->nb_antennas_tx_eNB) { + switch (frame_parms->nb_antenna_ports_eNB) { case 1: crc = crc ^ (uint16_t) 0; break; @@ -232,7 +232,7 @@ int generate_pbch(LTE_eNB_PBCH *eNB_pbch, if (frame_parms->mode1_flag == 1) amask = 0x0000; else { - switch (frame_parms->nb_antennas_tx_eNB) { + switch (frame_parms->nb_antenna_ports_eNB) { case 1: amask = 0x0000; break; @@ -492,7 +492,7 @@ uint16_t pbch_extract(int **rxdataF, } } - for (aatx=0; aatx<4; aatx++) { //frame_parms->nb_antennas_tx_eNB;aatx++) { + for (aatx=0; aatx<4; aatx++) { //frame_parms->nb_antenna_ports_eNB;aatx++) { if (high_speed_flag == 1) dl_ch0 = &dl_ch_estimates[(aatx<<1)+aarx][LTE_CE_OFFSET+ch_offset+(symbol*(frame_parms->ofdm_symbol_size))]; else @@ -554,7 +554,7 @@ int pbch_channel_level(int **dl_ch_estimates_ext, uint32_t nsymb = (frame_parms->Ncp==0) ? 7:6; uint32_t symbol_mod = symbol % nsymb; - for (aatx=0; aatx<4; aatx++) //frame_parms->nb_antennas_tx_eNB;aatx++) + for (aatx=0; aatx<4; aatx++) //frame_parms->nb_antenna_ports_eNB;aatx++) for (aarx=0; aarxnb_antennas_rx; aarx++) { //clear average level @@ -624,7 +624,7 @@ void pbch_channel_compensation(int **rxdataF_ext, #endif symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol; - for (aatx=0; aatx<4; aatx++) //frame_parms->nb_antennas_tx_eNB;aatx++) + for (aatx=0; aatx<4; aatx++) //frame_parms->nb_antenna_ports_eNB;aatx++) for (aarx=0; aarxnb_antennas_rx; aarx++) { #if defined(__x86_64__) || defined(__i386__) @@ -731,7 +731,7 @@ void pbch_detection_mrc(LTE_DL_FRAME_PARMS *frame_parms, symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol; if (frame_parms->nb_antennas_rx>1) { - for (aatx=0; aatx<4; aatx++) { //frame_parms->nb_antennas_tx_eNB;aatx++) { + for (aatx=0; aatx<4; aatx++) { //frame_parms->nb_antenna_ports_eNB;aatx++) { #if defined(__x86_64__) || defined(__i386__) rxdataF_comp128_0 = (__m128i *)&rxdataF_comp[(aatx<<1)][symbol_mod*6*12]; rxdataF_comp128_1 = (__m128i *)&rxdataF_comp[(aatx<<1)+1][symbol_mod*6*12]; @@ -1077,7 +1077,7 @@ uint16_t rx_pbch_emul(PHY_VARS_UE *phy_vars_ue, if (pbch_phase == (phy_vars_ue->frame_rx % 4)) { if (uniformrandom() >= bler) { memcpy(phy_vars_ue->lte_ue_pbch_vars[eNB_id]->decoded_output,PHY_vars_eNB_g[eNB_id][CC_id]->pbch_pdu,PBCH_PDU_SIZE); - return(PHY_vars_eNB_g[eNB_id][CC_id]->lte_frame_parms.nb_antennas_tx_eNB); + return(PHY_vars_eNB_g[eNB_id][CC_id]->lte_frame_parms.nb_antenna_ports_eNB); } else return(-1); } else diff --git a/openair1/PHY/LTE_TRANSPORT/pcfich.c b/openair1/PHY/LTE_TRANSPORT/pcfich.c index 8e9038666b..aeac370001 100644 --- a/openair1/PHY/LTE_TRANSPORT/pcfich.c +++ b/openair1/PHY/LTE_TRANSPORT/pcfich.c @@ -217,7 +217,7 @@ void generate_pcfich(uint8_t num_pdcch_symbols, if ((i!=nushiftmod3)&&(i!=(nushiftmod3+3))) { txdataF[0][symbol_offset+reg_offset+i] = pcfich_d[0][m]; - if (frame_parms->nb_antennas_tx_eNB>1) + if (frame_parms->nb_antenna_ports_eNB>1) txdataF[1][symbol_offset+reg_offset+i] = pcfich_d[1][m]; m++; diff --git a/openair1/PHY/LTE_TRANSPORT/pilots.c b/openair1/PHY/LTE_TRANSPORT/pilots.c index 772a47e131..4c5409a8ae 100644 --- a/openair1/PHY/LTE_TRANSPORT/pilots.c +++ b/openair1/PHY/LTE_TRANSPORT/pilots.c @@ -70,7 +70,7 @@ void generate_pilots(PHY_VARS_eNB *phy_vars_eNB, // printf("tti %d : offset %d (slot %d)\n",tti,tti_offset,slot_offset); //Generate Pilots - //antenna 0 symbol 0 slot 0 + //antenna port 0 symbol 0 slot 0 lte_dl_cell_spec(phy_vars_eNB,&txdataF[0][tti_offset], amp, slot_offset, @@ -79,7 +79,7 @@ void generate_pilots(PHY_VARS_eNB *phy_vars_eNB, // printf("tti %d : second_pilot offset %d \n",tti,tti_offset+(second_pilot*samples_per_symbol)); - //antenna 0 symbol 3/4 slot 0 + //antenna port 0 symbol 3/4 slot 0 lte_dl_cell_spec(phy_vars_eNB,&txdataF[0][tti_offset+(second_pilot*samples_per_symbol)], amp, slot_offset, @@ -87,7 +87,7 @@ void generate_pilots(PHY_VARS_eNB *phy_vars_eNB, 0); // printf("tti %d : third_pilot offset %d \n",tti,tti_offset+((Nsymb>>1)*samples_per_symbol)); - //antenna 0 symbol 0 slot 1 + //antenna port 0 symbol 0 slot 1 lte_dl_cell_spec(phy_vars_eNB,&txdataF[0][tti_offset+((Nsymb>>1)*samples_per_symbol)], amp, 1+slot_offset, @@ -95,7 +95,7 @@ void generate_pilots(PHY_VARS_eNB *phy_vars_eNB, 0); // printf("tti %d : third_pilot offset %d \n",tti,tti_offset+(((Nsymb>>1)+second_pilot)*samples_per_symbol)); - //antenna 0 symbol 3/4 slot 1 + //antenna port 0 symbol 3/4 slot 1 lte_dl_cell_spec(phy_vars_eNB,&txdataF[0][tti_offset+(((Nsymb>>1)+second_pilot)*samples_per_symbol)], amp, 1+slot_offset, @@ -103,66 +103,35 @@ void generate_pilots(PHY_VARS_eNB *phy_vars_eNB, 0); - if (frame_parms->nb_antennas_tx > 1) { - if (frame_parms->mode1_flag) { - // antenna 1 symbol 0 slot 0 - lte_dl_cell_spec(phy_vars_eNB,&txdataF[1][tti_offset], - amp, - slot_offset, - 0, - 0); + if (frame_parms->nb_antenna_ports_eNB > 1) { - // antenna 1 symbol 3 slot 0 - lte_dl_cell_spec(phy_vars_eNB,&txdataF[1][tti_offset+(second_pilot*samples_per_symbol)], - amp, - slot_offset, - 1, - 0); - - //antenna 1 symbol 0 slot 1 - lte_dl_cell_spec(phy_vars_eNB,&txdataF[1][tti_offset+(Nsymb>>1)*samples_per_symbol], - amp, - 1+slot_offset, - 0, - 0); - - // antenna 1 symbol 3 slot 1 - lte_dl_cell_spec(phy_vars_eNB,&txdataF[1][tti_offset+(((Nsymb>>1)+second_pilot)*samples_per_symbol)], - amp, - 1+slot_offset, - 1, - 0); - - } else { - - // antenna 1 symbol 0 slot 0 + // antenna port 1 symbol 0 slot 0 lte_dl_cell_spec(phy_vars_eNB,&txdataF[1][tti_offset], amp, slot_offset, 0, 1); - // antenna 1 symbol 3 slot 0 + // antenna port 1 symbol 3 slot 0 lte_dl_cell_spec(phy_vars_eNB,&txdataF[1][tti_offset+(second_pilot*samples_per_symbol)], amp, slot_offset, 1, 1); - //antenna 1 symbol 0 slot 1 + //antenna port 1 symbol 0 slot 1 lte_dl_cell_spec(phy_vars_eNB,&txdataF[1][tti_offset+(Nsymb>>1)*samples_per_symbol], amp, 1+slot_offset, 0, 1); - // antenna 1 symbol 3 slot 1 + // antenna port 1 symbol 3 slot 1 lte_dl_cell_spec(phy_vars_eNB,&txdataF[1][tti_offset+(((Nsymb>>1)+second_pilot)*samples_per_symbol)], amp, 1+slot_offset, 1, 1); - } } } } @@ -193,7 +162,7 @@ int generate_pilots_slot(PHY_VARS_eNB *phy_vars_eNB, // printf("tti %d : offset %d (slot %d)\n",tti,tti_offset,slot_offset); //Generate Pilots - //antenna 0 symbol 0 slot 0 + //antenna port 0 symbol 0 slot 0 lte_dl_cell_spec(phy_vars_eNB, &txdataF[0][slot_offset], amp, @@ -212,44 +181,24 @@ int generate_pilots_slot(PHY_VARS_eNB *phy_vars_eNB, 0); } - if (frame_parms->nb_antennas_tx > 1) { - if (frame_parms->mode1_flag) { - // antenna 1 symbol 0 slot 0 + if (frame_parms->nb_antenna_ports_eNB > 1) { + + // antenna port 1 symbol 0 slot 0 + lte_dl_cell_spec(phy_vars_eNB, + &txdataF[1][slot_offset], + amp, + slot, + 0, + 1); + + if (first_pilot_only == 0) { + // antenna port 1 symbol 3 slot 0 lte_dl_cell_spec(phy_vars_eNB, - &txdataF[1][slot_offset], + &txdataF[1][slot_offset+(second_pilot*samples_per_symbol)], amp, slot, - 0, - 0); - - if (first_pilot_only==0) { - // antenna 1 symbol 3 slot 0 - lte_dl_cell_spec(phy_vars_eNB, - &txdataF[1][slot_offset+(second_pilot*samples_per_symbol)], - amp, - slot, - 1, - 0); - } - } else { - - // antenna 1 symbol 0 slot 0 - lte_dl_cell_spec(phy_vars_eNB, - &txdataF[1][slot_offset], - amp, - slot, - 0, + 1, 1); - - if (first_pilot_only == 0) { - // antenna 1 symbol 3 slot 0 - lte_dl_cell_spec(phy_vars_eNB, - &txdataF[1][slot_offset+(second_pilot*samples_per_symbol)], - amp, - slot, - 1, - 1); - } } } diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 1161950e8f..4d450ba5f5 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -63,8 +63,10 @@ void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch, uint8_t abstraction_flag); @param Mdlharq Maximum number of HARQ rounds (36-212/36-213) @params N_RB_DL total number of resource blocks (determine the operating BW) @param abstraction_flag Flag to indicate abstracted interface + @param nb_antenna_tx number of physical transmit antennas at eNB */ -LTE_eNB_DLSCH_t *new_eNB_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint8_t N_RB_DL, uint8_t abstraction_flag); +LTE_eNB_DLSCH_t *new_eNB_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint8_t +N_RB_DL, uint8_t abstraction_flag, LTE_DL_FRAME_PARMS* frame_parms); /** \fn free_ue_dlsch(LTE_UE_DLSCH_t *dlsch) \brief This function frees memory allocated for a particular DLSCH at UE @@ -157,7 +159,6 @@ void dlsch_encoding_emul(PHY_VARS_eNB *phy_vars_eNB, \param skip_half indicate that first or second half of RB must be skipped for PBCH/PSS/SSS \param ue_spec_rs UE specific RS indicator \param nb_antennas_tx_phy Physical antenna elements which can be different with antenna port number, especially in beamforming case - \param beamforming_weights_rb Beamforming weights applied on each antenna element and each carrier in case of TM7-10 \param use2ndpilots Set to use the pilots from antenna port 1 for PDSCH \param frame_parms Frame parameter descriptor */ @@ -168,8 +169,8 @@ int32_t allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, uint32_t *jj2, uint16_t re_offset, uint32_t symbol_offset, - LTE_DL_eNB_HARQ_t *dlsch0_harq, - LTE_DL_eNB_HARQ_t *dlsch1_harq, + LTE_eNB_DLSCH_t *dlsch0, + LTE_eNB_DLSCH_t *dlsch1, uint8_t pilots, int16_t amp, uint8_t precoder_index, @@ -178,10 +179,9 @@ int32_t allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, uint32_t *re_allocated, uint8_t skip_dc, uint8_t skip_half, - uint8_t lprime, - uint8_t mprime, - uint8_t Ns, - int32_t **beamforming_weights); + uint8_t lprime, + uint8_t mprime, + uint8_t Ns); /** \fn int32_t dlsch_modulation(mod_sym_t **txdataF, int16_t amp, @@ -198,8 +198,6 @@ int32_t allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, @param num_pdcch_symbols Number of PDCCH symbols in this subframe @param dlsch0 Pointer to Transport Block 0 DLSCH descriptor for this allocation @param dlsch1 Pointer to Transport Block 0 DLSCH descriptor for this allocation - @param nb_antennas_tx_phy Physical antenna elements which can be different with antenna port number, especially in beamforming case - @param beamforming_weights Beamforming weights applied on each antenna element and each carrier in case of TM7-10 */ int32_t dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, mod_sym_t **txdataF, @@ -207,8 +205,7 @@ int32_t dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, uint32_t sub_frame_offset, uint8_t num_pdcch_symbols, LTE_eNB_DLSCH_t *dlsch0, - LTE_eNB_DLSCH_t *dlsch1, - int32_t **beamforming_weights); + LTE_eNB_DLSCH_t *dlsch1); /* \brief This function is the top-level routine for generation of the sub-frame signal (frequency-domain) for MCH. @param txdataF Table of pointers for frequency-domain TX signals @@ -331,6 +328,41 @@ int32_t generate_pbch(LTE_eNB_PBCH *eNB_pbch, int32_t generate_pbch_emul(PHY_VARS_eNB *phy_vars_eNB,uint8_t *pbch_pdu); + +/** \brief This function performs UE specific beamforming especially for + * transmission mode TM7-10 + @param txdataF Table of pointers for frequency-domain TX signals + @param txdataF_BF Table of pointers for frequency-domain TX signals +after beamforming + @param frame_parms Frame descriptor structure + @param ue_spec_bf_weights UE specific beamforming weights applied on +each antenna element and each carrier + @param slot Slot number + @param symbol Symbol index on which to act*/ +int ue_spec_beamforming(int32_t **txdataF, + int32_t **txdataF_BF, + LTE_DL_FRAME_PARMS *frame_parms, + int32_t ***ue_spec_bf_weights, + int slot, + int symbol); + +/** \brief This function performs cell specific beamforming for common + * data + @param txdataF Table of pointers for frequency-domain TX signals + @param txdataF_BF Table of pointers for frequency-domain TX signals + @param frame_parms Frame descriptor structure +after beamforming + @param cell_spec_bf_weights Common beamforming weights applied on each +antenna element and each carrier + @param slot Slot number + @param symbol Symbol index on which to act*/ +int cell_spec_beamforming(int32_t **txdataF, + int32_t **txdataF_BF, + LTE_DL_FRAME_PARMS *frame_parms, + int32_t ***cell_spec_bf_weights, + int slot, + int symbol); + /** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream QPSK/QPSK reception. @param stream0_in Input from channel compensated (MR combined) stream 0 @param stream1_in Input from channel compensated (MR combined) stream 1 diff --git a/openair1/PHY/MODULATION/slot_fep.c b/openair1/PHY/MODULATION/slot_fep.c index ec1c0045b0..b259bc5148 100644 --- a/openair1/PHY/MODULATION/slot_fep.c +++ b/openair1/PHY/MODULATION/slot_fep.c @@ -184,7 +184,7 @@ int slot_fep(PHY_VARS_UE *phy_vars_ue, if (phy_vars_ue->perfect_ce == 0) { if ((l==0) || (l==(4-frame_parms->Ncp))) { - for (aa=0; aanb_antennas_tx_eNB; aa++) { + for (aa=0; aanb_antenna_ports_eNB; aa++) { #ifdef DEBUG_FEP msg("Channel estimation eNB %d, aatx %d, slot %d, symbol %d\n",eNB_id,aa,Ns,l); diff --git a/openair1/PHY/TOOLS/lte_phy_scope.c b/openair1/PHY/TOOLS/lte_phy_scope.c index bc3dbcf289..ba361247db 100644 --- a/openair1/PHY/TOOLS/lte_phy_scope.c +++ b/openair1/PHY/TOOLS/lte_phy_scope.c @@ -482,7 +482,7 @@ void phy_scope_UE(FD_lte_phy_scope_ue *form, LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_ue->lte_frame_parms; int nsymb_ce = frame_parms->ofdm_symbol_size;//*frame_parms->symbols_per_tti; uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx; - uint8_t nb_antennas_tx = frame_parms->nb_antennas_tx_eNB; + uint8_t nb_antennas_tx = frame_parms->nb_antennas_ports_eNB; int16_t **rxsig_t; int16_t **chest_t; int16_t **chest_f; diff --git a/openair1/PHY/TOOLS/smbv.c b/openair1/PHY/TOOLS/smbv.c index 426fb5b68e..25585d0c1c 100644 --- a/openair1/PHY/TOOLS/smbv.c +++ b/openair1/PHY/TOOLS/smbv.c @@ -127,7 +127,7 @@ int smbv_write_config_from_frame_parms(const char* fname, LTE_DL_FRAME_PARMS *fr fprintf(f_ptr, "BB:EUTR:TDD:SPSC %d\n",frame_parms->tdd_config_S); // MIMO - fprintf(f_ptr, "BB:EUTR:DL:MIMO:CONF TX%d\n",frame_parms->nb_antennas_tx_eNB); + fprintf(f_ptr, "BB:EUTR:DL:MIMO:CONF TX%d\n",frame_parms->nb_antenna_ports_eNB); fprintf(f_ptr, "BB:EUTR:DL:MIMO:ANTA ANT1\n"); fprintf(f_ptr, "BB:EUTR:DL:MIMO:ANTB NONE\n"); diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index d9965b4e75..5697ff0dd2 100755 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -220,8 +220,8 @@ typedef struct PHY_VARS_eNB_s { LTE_eNB_PUSCH *lte_eNB_pusch_vars[NUMBER_OF_UE_MAX]; LTE_eNB_PRACH lte_eNB_prach_vars; LTE_eNB_DLSCH_t *dlsch_eNB[NUMBER_OF_UE_MAX][2]; // Nusers times two spatial streams - // old: LTE_eNB_DLSCH_t **dlsch_eNB[2]; // Nusers times two spatial streams - LTE_eNB_ULSCH_t *ulsch_eNB[NUMBER_OF_UE_MAX+1]; // Nusers + number of RA + // old: LTE_eNB_DLSCH_t **dlsch_eNB[2]; // Nusers times two spatial streams + LTE_eNB_ULSCH_t *ulsch_eNB[NUMBER_OF_UE_MAX+1]; // Nusers + number of RA LTE_eNB_DLSCH_t *dlsch_eNB_SI,*dlsch_eNB_ra; LTE_eNB_DLSCH_t *dlsch_eNB_MCH; LTE_eNB_UE_stats eNB_UE_stats[NUMBER_OF_UE_MAX]; diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h index f580340827..3de93e100e 100644 --- a/openair1/PHY/impl_defs_lte.h +++ b/openair1/PHY/impl_defs_lte.h @@ -530,12 +530,12 @@ typedef struct { uint32_t samples_per_tti; /// Number of OFDM/SC-FDMA symbols in one subframe (to be modified to account for potential different in UL/DL) uint16_t symbols_per_tti; - /// Number of Transmit antennas in node + /// Number of Physical transmit antennas in node uint8_t nb_antennas_tx; /// Number of Receive antennas in node uint8_t nb_antennas_rx; - /// Number of Transmit antennas in eNodeB - uint8_t nb_antennas_tx_eNB; + /// Number of Logical transmit antenna ports in eNodeB + uint8_t nb_antenna_ports_eNB; /// PRACH_CONFIG PRACH_CONFIG_COMMON prach_config_common; /// PUCCH Config Common (from 36-331 RRC spec) @@ -602,11 +602,17 @@ typedef struct { /// - third index: int32_t **txdata[3]; /// \brief holds the transmit data in the frequency domain. - /// For IFFT_FPGA this points to the same memory as PHY_vars->rx_vars[a].RX_DMA_BUFFER. + /// For IFFT_FPGA this points to the same memory as PHY_vars->rx_vars[a].RX_DMA_BUFFER. //? + /// - first index: eNB id [0..2] (hard coded) + /// - second index: tx antenna [0..14[ where 14 is the total supported antenna ports. + /// - third index: sample [0..] + mod_sym_t **txdataF[3]; + /// \brief holds the transmit data after beamforming in the frequency domain. + /// For IFFT_FPGA this points to the same memory as PHY_vars->rx_vars[a].RX_DMA_BUFFER. //? /// - first index: eNB id [0..2] (hard coded) /// - second index: tx antenna [0..nb_antennas_tx[ /// - third index: sample [0..] - mod_sym_t **txdataF[3]; + mod_sym_t **txdataF_BF[3]; /// \brief Holds the received data in time domain. /// Should point to the same memory as PHY_vars->rx_vars[a].RX_DMA_BUFFER. /// - first index: eNB id [0..2] (hard coded) @@ -627,6 +633,18 @@ typedef struct { /// - first index: eNB id [0..2] (hard coded) /// - second index: sample [0..samples_per_tti*10[ uint32_t *sync_corr[3]; + /// \brief Holds the cell specific beamforming weights + /// - first index: eNB id [0..2] (hard coded) + /// - second index: cell specific eNB antenna port index, up to 2 logical antenna ports are supported + /// - third index: tx antenna [0..nb_antennas_tx[ + /// - fourth index: sample [0..] + int32_t **cell_spec_bf_weights[3][2]; + /// \brief Holds the ue specific beamforming weights + /// - first index: eNB id [0..2] (hard coded) + /// - second index: ue specific eNB antenna port index, port5->index0, port7-15->index0-7 + /// - third index: tx antenna [0..nb_antennas_tx[ + /// - fourth index: sample [0..] + int32_t **ue_spec_bf_weights[3][8]; } LTE_eNB_COMMON; typedef struct { diff --git a/openair1/PHY/impl_defs_top.h b/openair1/PHY/impl_defs_top.h index a0302fd526..0663d8152e 100755 --- a/openair1/PHY/impl_defs_top.h +++ b/openair1/PHY/impl_defs_top.h @@ -183,6 +183,7 @@ #define DMA_BLKS_PER_SLOT (SLOT_LENGTH_BYTES/2048) // Number of DMA blocks per slot #define SLOT_TIME_NS (SLOT_LENGTH_SAMPLES*(1e3)/7.68) // slot time in ns +#define NB_ANTENNA_PORTS_ENB 14 // total number of eNB antenna ports #ifdef EXMIMO #define TARGET_RX_POWER 55 // Target digital power for the AGC diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index aa4df65eff..106007cc22 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -1434,7 +1434,7 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e if (abstraction_flag==0) { // clear the transmit data array for the current subframe - for (aa=0; aalte_frame_parms.nb_antennas_tx_eNB; aa++) { + for (aa=0; aalte_frame_parms.nb_antenna_ports_eNB; aa++) { memset(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][subframe*phy_vars_eNB->lte_frame_parms.ofdm_symbol_size*(phy_vars_eNB->lte_frame_parms.symbols_per_tti)], 0,phy_vars_eNB->lte_frame_parms.ofdm_symbol_size*(phy_vars_eNB->lte_frame_parms.symbols_per_tti)*sizeof(mod_sym_t)); @@ -2243,8 +2243,7 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e subframe, num_pdcch_symbols, phy_vars_eNB->dlsch_eNB_SI, - (LTE_eNB_DLSCH_t *)NULL, - (int32_t **)NULL); + (LTE_eNB_DLSCH_t *)NULL); stop_meas(&phy_vars_eNB->dlsch_modulation_stats); } @@ -2381,8 +2380,7 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e subframe, num_pdcch_symbols, phy_vars_eNB->dlsch_eNB_ra, - (LTE_eNB_DLSCH_t *)NULL, - (int32_t **)NULL); + (LTE_eNB_DLSCH_t *)NULL); } @@ -2560,8 +2558,7 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e subframe, num_pdcch_symbols, phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0], - phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][1], - (int32_t **)NULL); + phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][1]); stop_meas(&phy_vars_eNB->dlsch_modulation_stats); } diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 2501baff25..fcea2f53af 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -134,7 +134,7 @@ void lte_param_init(unsigned char N_tx_port_eNB, unsigned char N_tx_phy, unsigne lte_frame_parms->nushift = Nid_cell%6; lte_frame_parms->nb_antennas_tx = N_tx_phy; lte_frame_parms->nb_antennas_rx = N_rx; - lte_frame_parms->nb_antennas_tx_eNB = N_tx_port_eNB; + lte_frame_parms->nb_antenna_ports_eNB = N_tx_port_eNB; lte_frame_parms->phich_config_common.phich_resource = one; lte_frame_parms->tdd_config = tdd_config; lte_frame_parms->frame_type = (fdd_flag==1)?0 : 1; @@ -205,32 +205,59 @@ uint64_t DLSCH_alloc_pdu_1[2]; #define CCCH_RB_ALLOC computeRIV(PHY_vars_eNB->lte_frame_parms.N_RB_UL,0,2) //#define DLSCH_RB_ALLOC 0x1fbf // igore DC component,RB13 //#define DLSCH_RB_ALLOC 0x0001 -void do_OFDM_mod_l(mod_sym_t **txdataF, int32_t **txdata, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms) +void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms, uint8_t num_pdcch_symbols, unsigned char transmission_mode) { - int aa, slot_offset, slot_offset_F; + int aa, l, slot_offset, slot_offset_F; + mod_sym_t **txdataF = eNB_common_vars->txdataF[eNB_id]; + mod_sym_t **txdataF_BF = eNB_common_vars->txdataF_BF[eNB_id]; + int32_t **txdata = eNB_common_vars->txdata[eNB_id]; - slot_offset_F = (next_slot)*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); + //slot_offset_F = (next_slot)*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); slot_offset = (next_slot)*(frame_parms->samples_per_tti>>1); - for (aa=0; aanb_antennas_tx; aa++) { - // printf("Thread %d starting ... aa %d (%llu)\n",omp_get_thread_num(),aa,rdtsc()); + // printf("Thread %d starting ... aa %d (%llu)\n",omp_get_thread_num(),aa,rdtsc()); + for (l=0; lsymbols_per_tti>>1; l++) { + + //printf("do_OFDM_mod_l, slot=%d, l=%d, NUMBER_OF_OFDM_CARRIERS=%d,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES=%d\n",next_slot, l,NUMBER_OF_OFDM_CARRIERS,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES); + if (lcell_spec_bf_weights,next_slot,l); + else + if (transmission_mode<7) + cell_spec_beamforming(txdataF,txdataF_BF,frame_parms,eNB_common_vars->cell_spec_bf_weights,next_slot,l); + else + ue_spec_beamforming(txdataF,txdataF_BF,frame_parms,eNB_common_vars->ue_spec_bf_weights,next_slot,l); - if (frame_parms->Ncp == 1) - PHY_ofdm_mod(&txdataF[aa][slot_offset_F], // input - &txdata[aa][slot_offset], // output - frame_parms->log2_symbol_size, // log2_fft_size - 6, // number of symbols - frame_parms->nb_prefix_samples, // number of prefix samples - CYCLIC_PREFIX); - else { - normal_prefix_mod(&txdataF[aa][slot_offset_F], - &txdata[aa][slot_offset], - 7, - frame_parms); + for (aa=0; aanb_antennas_tx; aa++) { + + if (frame_parms->Ncp == 1) + PHY_ofdm_mod(txdataF_BF[aa], // input + &txdata[aa][slot_offset+l*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES], // output + frame_parms->log2_symbol_size, // log2_fft_size + 1, // number of symbols + frame_parms->nb_prefix_samples, // number of prefix samples + CYCLIC_PREFIX); + else { + if (l==0) { + PHY_ofdm_mod(txdataF_BF[aa], // input + &txdata[aa][slot_offset], // output + frame_parms->log2_symbol_size, // log2_fft_size + 1, // number of symbols + frame_parms->nb_prefix_samples0, // number of prefix samples + CYCLIC_PREFIX); + + } else { + PHY_ofdm_mod(txdataF_BF[aa], // input + &txdata[aa][slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES], // output + frame_parms->log2_symbol_size, // log2_fft_size + 1, // number of symbols + frame_parms->nb_prefix_samples, // number of prefix samples + CYCLIC_PREFIX); + } + } + + } - - } } @@ -239,7 +266,8 @@ int main(int argc, char **argv) { int c; - int k,i,aa,aarx,aatx; + int k,i,j,aa,aarx,aatx; + int re; int s,Kr,Kr_bytes; @@ -253,7 +281,7 @@ int main(int argc, char **argv) uint8_t extended_prefix_flag=0,transmission_mode=1,n_tx_port=1,n_tx_phy=1,n_rx=1; uint16_t Nid_cell=0; - int32_t **beamforming_weights; + int32_t **ue_spec_bf_weights, **cell_spec_bf_weights; int eNB_id = 0, eNB_id_i = 1; unsigned char mcs1=0,mcs2=0,mcs_i=0,dual_stream_UE = 0,awgn_flag=0,round,dci_flag=0; @@ -585,7 +613,7 @@ int main(int argc, char **argv) //if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=8 && n_tx_phy!=16 && n_tx_phy!=64 && n_tx_phy!=128)) { if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=16 && n_tx_phy!=64)) { - msg("For TM7, physical antenna number should be an exponent of 4, maximum 64 antennas supported.\n"); + msg("Physical number of antennas not supported for TM7.\n"); exit(-1); } @@ -767,28 +795,21 @@ int main(int argc, char **argv) lte_param_init(n_tx_port,n_tx_phy,n_rx,transmission_mode,extended_prefix_flag,fdd_flag,Nid_cell,tdd_config,N_RB_DL,osf,perfect_ce); + frame_parms = &PHY_vars_eNB->lte_frame_parms; + + cell_spec_bf_weights = PHY_vars_eNB->lte_eNB_common_vars.cell_spec_bf_weights[0][0]; + for(aa=0;aaofdm_symbol_size;i++) { + cell_spec_bf_weights[aa][i] = 0x00007fff; + } + } + if (transmission_mode==7){ lte_gold_ue_spec_port5(PHY_vars_eNB->lte_gold_uespec_port5_table[0],Nid_cell,n_rnti); lte_gold_ue_spec_port5(PHY_vars_UE->lte_gold_uespec_port5_table,Nid_cell,n_rnti); - - beamforming_weights = (int32_t **)malloc(12*N_RB_DL*sizeof(int32_t*)); - for(i=0;i<12*N_RB_DL;i++){ - beamforming_weights[i]=(int32_t *)malloc(n_tx_phy*sizeof(int32_t)); - for(aa=0;aa>1; - else if (n_tx_phy==16) - beamforming_weights[i][aa] = 0x00007fff>>2; - else if (n_tx_phy==64) - beamforming_weights[i][aa] = 0x00007fff>>4;//3 - } - } - printf("***n_tx_phy=%d,n_tx_phy>>2=%d,beamforming_weights=%d\n",n_tx_phy,n_tx_phy>>2,beamforming_weights[0][0]); } + eNB_id_i = PHY_vars_UE->n_connected_eNB; printf("Setting mcs1 = %d\n",mcs1); @@ -810,8 +831,6 @@ int main(int argc, char **argv) txdata[1] = (int *)malloc16(FRAME_LENGTH_BYTES); */ - frame_parms = &PHY_vars_eNB->lte_frame_parms; - s_re = malloc(n_tx_phy*sizeof(double*)); s_im = malloc(n_tx_phy*sizeof(double*)); r_re = malloc(2*sizeof(double*)); @@ -1041,11 +1060,31 @@ int main(int argc, char **argv) for (k=0; kdlsch_eNB[k][i] = new_eNB_dlsch(Kmimo,8,N_RB_DL,0); + + PHY_vars_eNB->dlsch_eNB[k][i] = new_eNB_dlsch(Kmimo,8,N_RB_DL,0,&PHY_vars_UE->lte_frame_parms); if (!PHY_vars_eNB->dlsch_eNB[k][i]) { printf("Can't get eNB dlsch structures\n"); exit(-1); + } else { + // this initilisation may should be moved to another place + for (j=0; j<4; j++) { // antenna port 5,7-14 + + ue_spec_bf_weights = PHY_vars_eNB->dlsch_eNB[k][i]->ue_spec_bf_weights[j]; + + for (aa=0; aanb_antennas_tx; aa++) { + for (re=0;reofdm_symbol_size;re++) { + if (n_tx_phy==1 || n_tx_phy==2) + ue_spec_bf_weights[aa][re] = 0x00007fff; + else if (n_tx_phy==4) + ue_spec_bf_weights[aa][re] = 0x00007fff>>1; + else if (n_tx_phy==16) + ue_spec_bf_weights[aa][re] = 0x00007fff>>2; + else if (n_tx_phy==64) + ue_spec_bf_weights[aa][re] = 0x00007fff>>4; + } + } + } } PHY_vars_eNB->dlsch_eNB[k][i]->rnti = n_rnti+k; @@ -1064,7 +1103,7 @@ int main(int argc, char **argv) } // structure for SIC at UE - PHY_vars_UE->dlsch_eNB[0] = new_eNB_dlsch(Kmimo,8,N_RB_DL,0); + PHY_vars_UE->dlsch_eNB[0] = new_eNB_dlsch(Kmimo,8,N_RB_DL,0,&PHY_vars_eNB->lte_frame_parms); if (DLSCH_alloc_pdu2_1E[0].tpmi == 5) { @@ -2221,8 +2260,7 @@ int main(int argc, char **argv) PMI_FEEDBACK: //printf("Trial %d : Round %d, pmi_feedback %d \n",trials,round,pmi_feedback); - //for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { - for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { + for (aa=0; aalte_eNB_common_vars.txdataF[eNB_id][aa][0],0,FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t)); } @@ -2738,8 +2776,7 @@ PMI_FEEDBACK: subframe, num_pdcch_symbols, PHY_vars_eNB->dlsch_eNB[k][0], - PHY_vars_eNB->dlsch_eNB[k][1], - beamforming_weights); + PHY_vars_eNB->dlsch_eNB[k][1]); stop_meas(&PHY_vars_eNB->dlsch_modulation_stats); /* if (trials==0 && round==0) @@ -2883,27 +2920,37 @@ PMI_FEEDBACK: } */ - do_OFDM_mod_l(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], - PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id], + do_OFDM_mod_l(&PHY_vars_eNB->lte_eNB_common_vars, + eNB_id, (subframe*2), - &PHY_vars_eNB->lte_frame_parms); + &PHY_vars_eNB->lte_frame_parms, + num_pdcch_symbols, + transmission_mode); - do_OFDM_mod_l(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], - PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id], + do_OFDM_mod_l(&PHY_vars_eNB->lte_eNB_common_vars, + eNB_id, (subframe*2)+1, - &PHY_vars_eNB->lte_frame_parms); + &PHY_vars_eNB->lte_frame_parms, + num_pdcch_symbols, + transmission_mode); stop_meas(&PHY_vars_eNB->ofdm_mod_stats); stop_meas(&PHY_vars_eNB->phy_proc_tx); - do_OFDM_mod_l(PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id], - PHY_vars_eNB->lte_eNB_common_vars.txdata[eNB_id], + /* do_OFDM_mod_l(&PHY_vars_eNB->lte_eNB_common_vars, + eNB_id, (subframe*2)+2, - &PHY_vars_eNB->lte_frame_parms); + &PHY_vars_eNB->lte_frame_parms); */ if (n_frames==1) { - write_output("txsigF0.m","txsF0", &PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id][0][subframe*nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size], - nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size,1,1); + if (transmission_mode<7) + write_output("txsigF0.m","txsF0", &PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id][0][subframe*nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size], + nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size,1,1); + else if (transmission_mode==7) + write_output("txsigF0.m","txsF0", &PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id][5][subframe*nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size], + nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size,1,1); + write_output("txsigF0_BF.m","txsF0_BF", &PHY_vars_eNB->lte_eNB_common_vars.txdataF_BF[eNB_id][0][0], + PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size,1,1); if (PHY_vars_eNB->lte_frame_parms.nb_antennas_tx>1)// to be updated write_output("txsigF1.m","txsF1", &PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNB_id][1][subframe*nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size], @@ -3144,7 +3191,7 @@ PMI_FEEDBACK: //write_output("channel.m","ch",desc1->ch[0],desc1->channel_length,1,8); //write_output("channelF.m","chF",desc1->chF[0],nb_samples,1,8); for(k=0; knb_antennas_tx_eNB; aa++) { + for(aa=0; aanb_antenna_ports_eNB; aa++) { for (aarx=0; aarxnb_antennas_rx; aarx++) { for (i=0; iN_RB_DL*12; i++) { ((int16_t *) PHY_vars_UE->lte_ue_common_vars.dl_ch_estimates[k][(aa<<1)+aarx])[2*i+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=(int16_t)( @@ -3173,7 +3220,7 @@ PMI_FEEDBACK: } } } else { - for(aa=0; aanb_antennas_tx_eNB; aa++) { + for(aa=0; aanb_antenna_ports_eNB; aa++) { for (aarx=0; aarxnb_antennas_rx; aarx++) { for (i=0; iN_RB_DL*12; i++) { ((int16_t *) PHY_vars_UE->lte_ue_common_vars.dl_ch_estimates[0][(aa<<1)+aarx])[2*i+((l+(Ns%2)*pilot2)*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=(short)(AMP); @@ -4347,16 +4394,11 @@ PMI_FEEDBACK: free(r_im[i]); } - if(transmission_mode == 7){ - for(i=0;i<12*N_RB_DL;i++) - free(beamforming_weights[i]); - } free(s_re); free(s_im); free(r_re); free(r_im); - free(beamforming_weights); // lte_sync_time_free(); diff --git a/openair1/SIMULATION/LTE_PHY/framegen.c b/openair1/SIMULATION/LTE_PHY/framegen.c index 21124eba8d..db85d1f251 100644 --- a/openair1/SIMULATION/LTE_PHY/framegen.c +++ b/openair1/SIMULATION/LTE_PHY/framegen.c @@ -401,7 +401,7 @@ void lte_param_init( unsigned char transmission_mode, lte_frame_parms->Nid_cell = Nid_cell; lte_frame_parms->nushift = Nid_cell%6; lte_frame_parms->nb_antennas_tx = (transmission_mode == 1) ? 1 : 2; - lte_frame_parms->nb_antennas_tx_eNB = (transmission_mode == 1) ? 1 : 2; + lte_frame_parms->nb_antenna_ports_eNB = (transmission_mode == 1) ? 1 : 2; lte_frame_parms->nb_antennas_rx = (transmission_mode == 1) ? 1 : 2; lte_frame_parms->mode1_flag = (transmission_mode == 1)? 1 : 0; lte_frame_parms->phich_config_common.phich_resource = oneSixth; diff --git a/openair1/SIMULATION/LTE_PHY/pbchsim.c b/openair1/SIMULATION/LTE_PHY/pbchsim.c index 67080836b7..3533c7529c 100644 --- a/openair1/SIMULATION/LTE_PHY/pbchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pbchsim.c @@ -88,7 +88,7 @@ void lte_param_init(unsigned char N_tx, unsigned char N_rx,unsigned char transmi lte_frame_parms->Nid_cell = Nid_cell; lte_frame_parms->nushift = Nid_cell%6; lte_frame_parms->nb_antennas_tx = N_tx; - lte_frame_parms->nb_antennas_tx_eNB = N_tx; + lte_frame_parms->nb_antenna_ports_eNB = N_tx; lte_frame_parms->nb_antennas_rx = N_rx; // lte_frame_parms->Csrs = 2; // lte_frame_parms->Bsrs = 0; diff --git a/openair1/SIMULATION/LTE_PHY/pdcchsim.c b/openair1/SIMULATION/LTE_PHY/pdcchsim.c index 1852e349ec..8c3feaf538 100644 --- a/openair1/SIMULATION/LTE_PHY/pdcchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pdcchsim.c @@ -85,7 +85,7 @@ void lte_param_init(unsigned char N_tx, unsigned char N_rx,unsigned char transmi lte_frame_parms->Ncp = extended_prefix_flag; lte_frame_parms->Nid_cell = Nid_cell; lte_frame_parms->nushift = Nid_cell%6; - lte_frame_parms->nb_antennas_tx_eNB = N_tx; + lte_frame_parms->nb_antenna_ports_eNB = N_tx; lte_frame_parms->nb_antennas_tx = N_tx; lte_frame_parms->nb_antennas_rx = N_rx; lte_frame_parms->phich_config_common.phich_resource = one; //half @@ -858,7 +858,7 @@ int main(int argc, char **argv) break; } - eNB2UE = new_channel_desc_scm(PHY_vars_eNB->lte_frame_parms.nb_antennas_tx_eNB, + eNB2UE = new_channel_desc_scm(PHY_vars_eNB->lte_frame_parms.nb_antenna_ports_eNB, PHY_vars_UE->lte_frame_parms.nb_antennas_rx, channel_model, BW, @@ -940,7 +940,7 @@ int main(int argc, char **argv) for (trial=0; triallte_eNB_common_vars.txdataF[eNb_id][aa][512*14*subframe],&PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNb_id][aa][0]); - for (aa=0; aalte_frame_parms.nb_antennas_tx_eNB; aa++) { + for (aa=0; aalte_frame_parms.nb_antenna_ports_eNB; aa++) { memset(&PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNb_id][aa][0],0,FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t)); /* @@ -1090,7 +1090,7 @@ int main(int argc, char **argv) if (n_frames==1) { write_output("txsigF0.m","txsF0", PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNb_id][0],4*nsymb*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES_NO_PREFIX,1,1); - if (PHY_vars_eNB->lte_frame_parms.nb_antennas_tx_eNB > 1) + if (PHY_vars_eNB->lte_frame_parms.nb_antenna_ports_eNB > 1) write_output("txsigF1.m","txsF1", PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNb_id][1],4*nsymb*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES_NO_PREFIX,1,1); } @@ -1098,7 +1098,7 @@ int main(int argc, char **argv) - for (aa=0; aalte_frame_parms.nb_antennas_tx_eNB; aa++) { + for (aa=0; aalte_frame_parms.nb_antenna_ports_eNB; aa++) { if (PHY_vars_eNB->lte_frame_parms.Ncp == 1) PHY_ofdm_mod(&PHY_vars_eNB->lte_eNB_common_vars.txdataF[eNb_id][aa][subframe*nsymb*PHY_vars_eNB->lte_frame_parms.ofdm_symbol_size], // input, &txdata[aa][subframe*PHY_vars_eNB->lte_frame_parms.samples_per_tti], // output @@ -1123,7 +1123,7 @@ int main(int argc, char **argv) for (i=0; i<2*nsymb*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES; i++) { - for (aa=0; aalte_frame_parms.nb_antennas_tx_eNB; aa++) { + for (aa=0; aalte_frame_parms.nb_antenna_ports_eNB; aa++) { if (awgn_flag == 0) { s_re[aa][i] = ((double)(((short *)txdata[aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) + (i<<1)]); s_im[aa][i] = ((double)(((short *)txdata[aa]))[(2*subframe*PHY_vars_UE->lte_frame_parms.samples_per_tti) + (i<<1)+1]); @@ -1211,7 +1211,7 @@ int main(int argc, char **argv) } } } else { - for(aa=0; aanb_antennas_tx_eNB; aa++) { + for(aa=0; aanb_antenna_ports_eNB; aa++) { for (aarx=0; aarxnb_antennas_rx; aarx++) { for (i=0; iN_RB_DL*12; i++) { ((int16_t *) PHY_vars_UE->lte_ue_common_vars.dl_ch_estimates[0][(aa<<1)+aarx])[2*i+(l*frame_parms->ofdm_symbol_size+LTE_CE_FILTER_LENGTH)*2]=(short)(AMP); diff --git a/openair1/SIMULATION/LTE_PHY/scansim.c b/openair1/SIMULATION/LTE_PHY/scansim.c index 24167984b2..3bc042b86b 100644 --- a/openair1/SIMULATION/LTE_PHY/scansim.c +++ b/openair1/SIMULATION/LTE_PHY/scansim.c @@ -88,7 +88,7 @@ void lte_param_init(unsigned char N_tx, unsigned char N_rx,unsigned char transmi lte_frame_parms->Nid_cell = Nid_cell; lte_frame_parms->nushift = Nid_cell%6; lte_frame_parms->nb_antennas_tx = N_tx; - lte_frame_parms->nb_antennas_tx_eNB = N_tx; + lte_frame_parms->nb_antenna_ports_eNB = N_tx; lte_frame_parms->nb_antennas_rx = N_rx; // lte_frame_parms->Csrs = 2; // lte_frame_parms->Bsrs = 0; From ad5e6a9eeae1d327abaac155f6b8f229507d608c Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 26 Nov 2015 11:48:53 +0100 Subject: [PATCH 022/413] ulsim and mbmssim adaption --- openair1/SIMULATION/LTE_PHY/mbmssim.c | 2 +- openair1/SIMULATION/LTE_PHY/ulsim.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/mbmssim.c b/openair1/SIMULATION/LTE_PHY/mbmssim.c index 20d4e04cd8..9f426c9c6e 100644 --- a/openair1/SIMULATION/LTE_PHY/mbmssim.c +++ b/openair1/SIMULATION/LTE_PHY/mbmssim.c @@ -403,7 +403,7 @@ int main(int argc, char **argv) 0); // Create transport channel structures for 2 transport blocks (MIMO) - PHY_vars_eNB->dlsch_eNB_MCH = new_eNB_dlsch(1,8,N_RB_DL,0); + PHY_vars_eNB->dlsch_eNB_MCH = new_eNB_dlsch(1,8,N_RB_DL,0,&PHY_vars_eNB->lte_frame_parms); if (!PHY_vars_eNB->dlsch_eNB_MCH) { printf("Can't get eNB dlsch structures\n"); diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index dd697899b8..050071fa02 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -693,7 +693,7 @@ int main(int argc, char **argv) // Create transport channel structures for 2 transport blocks (MIMO) for (i=0; i<2; i++) { - PHY_vars_eNB->dlsch_eNB[0][i] = new_eNB_dlsch(1,8,N_RB_DL,0); + PHY_vars_eNB->dlsch_eNB[0][i] = new_eNB_dlsch(1,8,N_RB_DL,0,&PHY_vars_eNB->lte_frame_parms); PHY_vars_UE->dlsch_ue[0][i] = new_ue_dlsch(1,8,MAX_TURBO_ITERATIONS,N_RB_DL,0); if (!PHY_vars_eNB->dlsch_eNB[0][i]) { From 4a4a878507ecabd8a003249d56b4e0c187da61c5 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 26 Nov 2015 11:49:48 +0100 Subject: [PATCH 023/413] dlsim adaption for new_eNB_dlsch() --- openair1/SIMULATION/LTE_PHY/dlsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 5cb91e3025..43cf078b8f 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -1061,7 +1061,7 @@ int main(int argc, char **argv) // Create transport channel structures for 2 transport blocks (MIMO) for (i=0; i<2; i++) { - PHY_vars_eNB->dlsch_eNB[k][i] = new_eNB_dlsch(Kmimo,8,N_RB_DL,0,&PHY_vars_UE->lte_frame_parms); + PHY_vars_eNB->dlsch_eNB[k][i] = new_eNB_dlsch(Kmimo,8,N_RB_DL,0,&PHY_vars_eNB->lte_frame_parms); if (!PHY_vars_eNB->dlsch_eNB[k][i]) { printf("Can't get eNB dlsch structures\n"); From 8b56ae1755f5d76ba496fb126aa4f020c2cf3104 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 26 Nov 2015 17:21:14 +0100 Subject: [PATCH 024/413] bug fixed in do_OFDM_l() for the 7th symbol in a subframe --- openair1/SIMULATION/LTE_PHY/dlsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 43cf078b8f..1bcbe57717 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -220,7 +220,7 @@ void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_sl for (l=0; lsymbols_per_tti>>1; l++) { //printf("do_OFDM_mod_l, slot=%d, l=%d, NUMBER_OF_OFDM_CARRIERS=%d,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES=%d\n",next_slot, l,NUMBER_OF_OFDM_CARRIERS,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES); - if (lcell_spec_bf_weights,next_slot,l); else if (transmission_mode<7) From b86efd9cbe12c74c698ea045540d739264b3d0e8 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 26 Nov 2015 17:59:29 +0100 Subject: [PATCH 025/413] add printf for debug mode in TM7 data extraction --- .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 172 +++++++++++++++--- 1 file changed, 143 insertions(+), 29 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index 3e5ec84d46..9a5e670481 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -52,7 +52,7 @@ #endif //#define DEBUG_PHY 1 -//#define DEBUG_DLSCH_DEMOD 1 +#define DEBUG_DLSCH_DEMOD 1 int avg[4]; @@ -4373,15 +4373,41 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, else rb_alloc_ind = 0; + if (rb_alloc_ind == 1) + nb_rb++; + // For second half of RBs skip DC carrier if (rb==(frame_parms->N_RB_DL>>1)) { rxF = &rxdataF[aarx][(1 + (symbol*(frame_parms->ofdm_symbol_size)))]; //dl_ch0++; } + + // PBCH + if ((subframe==0) && (rb>=((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l>=nsymb>>1) && (l<((nsymb>>1) + 4))) { + rb_alloc_ind = 0; + } + + //SSS + if (((subframe==0)||(subframe==5)) && (rb>=((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==sss_symb) ) { + rb_alloc_ind = 0; + } + + + if (frame_parms->frame_type == FDD) { + //PSS + if (((subframe==0)||(subframe==5)) && (rb>=((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + } + + if ((frame_parms->frame_type == TDD) && + (subframe==6)) { //TDD Subframe 6 + if ((rb>=((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l==pss_symb) ) { + rb_alloc_ind = 0; + } + } if (rb_alloc_ind==1) { - //*pmi_ext = (pmi>>((rb>>2)<<1))&3; - //memcpy(dl_ch0_ext,dl_ch0,12*sizeof(int)); /* printf("rb %d\n",rb); @@ -4439,7 +4465,6 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, exit(-1); } - nb_rb++; } dl_ch0+=12; @@ -4517,7 +4542,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (rb_alloc_ind==1) { - //printf("rb %d/symbol %d pilots %d, uespec_pilots %d, (skip_half %d)\n",rb,l,pilots,uespec_pilots,skip_half); +#ifdef DEBUG_DLSCH_DEMOD + printf("rb %d/symbol %d pilots %d, uespec_pilots %d, (skip_half %d)\n",rb,l,pilots,uespec_pilots,skip_half); +#endif if (pilots==0 && uespec_pilots==0) { //printf("Extracting w/o pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half); @@ -4525,16 +4552,24 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (skip_half==1) { memcpy(dl_ch0_ext,dl_ch0,6*sizeof(int)); - for (i=0; i<6; i++) + for (i=0; i<6; i++) { rxF_ext[i]=rxF[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif + } dl_ch0_ext+=6; rxF_ext+=6; } else if (skip_half==2) { memcpy(dl_ch0_ext,dl_ch0+6,6*sizeof(int)); - for (i=0; i<6; i++) + for (i=0; i<6; i++) { rxF_ext[i]=rxF[(i+6)]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif + } dl_ch0_ext+=6; rxF_ext+=6; @@ -4543,7 +4578,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, for (i=0; i<12; i++){ rxF_ext[i]=rxF[i]; - //printf("symbol %d, extract rb %d, re %d => (%d,%d)\n",symbol,rb,i,*(short *)&rxF[i],*(1+(short*)&rxF[i])); +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",symbol,rb,i,*(short *)&rxF[i],*(1+(short*)&rxF[i])); +#endif } dl_ch0_ext+=12; rxF_ext+=12; @@ -4556,8 +4593,10 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, for (i=0; i<6; i++) { if (i!=((frame_parms->nushift+poffset)%6)) { rxF_ext[j]=rxF[i]; - // printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); dl_ch0_ext[j++]=dl_ch0[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } @@ -4567,8 +4606,10 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, for (i=0; i<6; i++) { if (i!=((frame_parms->nushift+poffset)%6)) { rxF_ext[j]=rxF[(i+6)]; - // printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); dl_ch0_ext[j++]=dl_ch0[i+6]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } @@ -4579,9 +4620,10 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if ((i!=(frame_parms->nushift+poffset)) && (i!=((frame_parms->nushift+poffset+6)%12))) { rxF_ext[j]=rxF[i]; - //printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); +#endif dl_ch0_ext[j++]=dl_ch0[i]; - //printf("symbol %d, extract rb %d => (%d,%d)\n",symbol,rb,*(short *)&dl_ch0[i],*(1+(short*)&dl_ch0[i])); } } @@ -4599,6 +4641,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ rxF_ext[j]=rxF[i]; dl_ch0_ext[j++]=dl_ch0[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } dl_ch0_ext+=6-(uespec_nushift+uespec_poffset<6)-(uespec_nushift+uespec_poffset+4<6)-((uespec_nushift+uespec_poffset+8)%12<6); @@ -4609,6 +4654,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ rxF_ext[j]=rxF[i]; dl_ch0_ext[j++]=dl_ch0[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } dl_ch0_ext+=4; @@ -4621,6 +4669,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ rxF_ext[j]=rxF[(i+6)]; dl_ch0_ext[j++]=dl_ch0[i+6]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } dl_ch0_ext+=6-(uespec_nushift+uespec_poffset>6)-(uespec_nushift+uespec_poffset+4>6)-((uespec_nushift+uespec_poffset+8)%12>6); @@ -4631,6 +4682,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ rxF_ext[j]=rxF[(i+6)]; dl_ch0_ext[j++]=dl_ch0[i+6]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } dl_ch0_ext+=4; @@ -4644,12 +4698,17 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ rxF_ext[j] = rxF[i]; dl_ch0_ext[j++] = dl_ch0[i]; - //printf("symbol %d, extract rb %d, re %d, j %d => (%d,%d)\n",symbol,rb,i,j-1,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d, j %d => (%d,%d)\n",symbol,rb,i,j-1,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); +#endif } } else{ if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ rxF_ext[j] = rxF[i]; dl_ch0_ext[j++]=dl_ch0[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } @@ -4685,7 +4744,8 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, else rb_alloc_ind = 0; - + if (rb_alloc_ind == 1) + nb_rb++; // PBCH if ((subframe==0) && (rb>=((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) { @@ -4719,6 +4779,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, for (i=0; i<6; i++) { dl_ch0_ext[i]=dl_ch0[i]; rxF_ext[i]=rxF[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } rxF = &rxdataF[aarx][((symbol*(frame_parms->ofdm_symbol_size)))]; @@ -4726,6 +4789,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, for (; i<12; i++) { dl_ch0_ext[i]=dl_ch0[i]; rxF_ext[i]=rxF[(1+i-6)]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } dl_ch0_ext+=12; @@ -4737,6 +4803,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=((frame_parms->nushift+poffset)%6)) { dl_ch0_ext[j]=dl_ch0[i]; rxF_ext[j++]=rxF[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } @@ -4746,7 +4815,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=((frame_parms->nushift+6+poffset)%12)) { dl_ch0_ext[j]=dl_ch0[i]; rxF_ext[j++]=rxF[(1+i-6)]; - //printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } @@ -4760,13 +4831,17 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ dl_ch0_ext[j]=dl_ch0[i]; rxF_ext[j++] = rxF[i]; - //printf("symbol %d, extract rb %d, re %d, j %d => (%d,%d)\n",symbol,rb,i,j-1,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); - //printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } else { if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ dl_ch0_ext[j]=dl_ch0[i]; rxF_ext[j++] = rxF[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } } @@ -4778,13 +4853,17 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ dl_ch0_ext[j]=dl_ch0[i]; rxF_ext[j++]=rxF[(1+i-6)]; - // printf("symbol %d, extract rb %d, re %d, j %d => (%d,%d)\n",symbol,rb,i,j-1,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); - // printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j-1],*(1+(short*)&rxF_ext[j-1])); +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } else { if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ dl_ch0_ext[j]=dl_ch0[i]; rxF_ext[j++] = rxF[(1+i-6)]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } } @@ -4794,7 +4873,6 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, }// symbol_mod==0 - nb_rb++; } // rballoc==1 else { rxF = &rxdataF[aarx][((symbol*(frame_parms->ofdm_symbol_size)))]; @@ -4868,7 +4946,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, } if (rb_alloc_ind==1) { - // printf("rb %d/symbol %d (skip_half %d)\n",rb,l,skip_half); +#ifdef DEBUG_DLSCH_DEMOD + printf("rb %d/symbol %d (skip_half %d)\n",rb,l,skip_half); +#endif /* printf("rb %d\n",rb); for (i=0;i<12;i++) @@ -4880,8 +4960,12 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (skip_half==1) { memcpy(dl_ch0_ext,dl_ch0,6*sizeof(int)); - for (i=0; i<6; i++) + for (i=0; i<6; i++) { rxF_ext[i]=rxF[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif + } dl_ch0_ext+=6; rxF_ext+=6; @@ -4889,8 +4973,12 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, } else if (skip_half==2) { memcpy(dl_ch0_ext,dl_ch0+6,6*sizeof(int)); - for (i=0; i<6; i++) + for (i=0; i<6; i++) { rxF_ext[i]=rxF[i+6]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif + } dl_ch0_ext+=6; rxF_ext+=6; @@ -4899,8 +4987,12 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, memcpy(dl_ch0_ext,dl_ch0,12*sizeof(int)); //printf("symbol %d, extract rb %d, => (%d,%d)\n",symbol,rb,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); - for (i=0; i<12; i++) + for (i=0; i<12; i++) { rxF_ext[i]=rxF[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif + } dl_ch0_ext+=12; rxF_ext+=12; @@ -4913,8 +5005,10 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, for (i=0; i<6; i++) { if (i!=((frame_parms->nushift+poffset)%6)) { rxF_ext[j]=rxF[i]; - //printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); dl_ch0_ext[j++]=dl_ch0[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } @@ -4924,8 +5018,10 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, for (i=0; i<6; i++) { if (i!=((frame_parms->nushift+poffset)%6)) { rxF_ext[j]=rxF[(i+6)]; - //printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); dl_ch0_ext[j++]=dl_ch0[i+6]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } @@ -4936,9 +5032,10 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if ((i!=(frame_parms->nushift+poffset)) && (i!=((frame_parms->nushift+poffset+6)%12))) { rxF_ext[j]=rxF[i]; - //printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j])); +#endif dl_ch0_ext[j++]=dl_ch0[i]; - //printf("symbol %d, extract rb %d => (%d,%d)\n",symbol,rb,*(short *)&dl_ch0[i],*(1+(short*)&dl_ch0[i])); } } @@ -4954,6 +5051,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ rxF_ext[j]=rxF[i]; dl_ch0_ext[j++]=dl_ch0[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } dl_ch0_ext+=6-(uespec_nushift+uespec_poffset<6)-(uespec_nushift+uespec_poffset+4<6)-((uespec_nushift+uespec_poffset+8)%12<6); @@ -4964,6 +5064,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ rxF_ext[j]=rxF[i]; dl_ch0_ext[j++]=dl_ch0[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } dl_ch0_ext+=4; @@ -4976,6 +5079,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ rxF_ext[j]=rxF[i+6]; dl_ch0_ext[j++]=dl_ch0[i+6]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } dl_ch0_ext+=6-(uespec_nushift+uespec_poffset>6)-(uespec_nushift+uespec_poffset+4>6)-((uespec_nushift+uespec_poffset+8)%12>6); @@ -4986,6 +5092,9 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ rxF_ext[j]=rxF[(i+6)]; dl_ch0_ext[j++]=dl_ch0[i+6]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } dl_ch0_ext+=4; @@ -4998,12 +5107,17 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+4 && i!=(uespec_nushift+uespec_poffset+8)%12){ rxF_ext[j] = rxF[i]; dl_ch0_ext[j++]=dl_ch0[i]; - // printf("symbol %d, extract rb %d, re %d, j %d => (%d,%d)\n",symbol,rb,i,j-1,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i])); +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } else{ if (i!=uespec_nushift+uespec_poffset && i!=uespec_nushift+uespec_poffset+3 && i!=uespec_nushift+uespec_poffset+6 && i!=(uespec_nushift+uespec_poffset+9)%12){ rxF_ext[j] = rxF[i]; dl_ch0_ext[j++]=dl_ch0[i]; +#ifdef DEBUG_DLSCH_DEMOD + printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[i],*(1+(short*)&rxF_ext[i])); +#endif } } } From 62e38a05c01608267d88477ee395a2df9feff78f Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 26 Nov 2015 18:03:39 +0100 Subject: [PATCH 026/413] comment debug mode in dlsch_demodulation --- openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index 9a5e670481..45a36e27a5 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -52,7 +52,7 @@ #endif //#define DEBUG_PHY 1 -#define DEBUG_DLSCH_DEMOD 1 +//#define DEBUG_DLSCH_DEMOD 1 int avg[4]; From bed11c711e536366ffe6c45e6a86a16306804f28 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 30 Nov 2015 15:29:10 +0100 Subject: [PATCH 027/413] dlsch data extraction bug fixed for special subframes in TM7 --- openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index 45a36e27a5..f578c6f3e4 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -4486,6 +4486,8 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, else rb_alloc_ind = 0; + if (rb_alloc_ind == 1) + nb_rb++; // PBCH if ((subframe==0) && (rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l>=(nsymb>>1)) && (l<((nsymb>>1) + 4))) { @@ -4723,8 +4725,6 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, exit(-1); } - - nb_rb++; } dl_ch0+=12; @@ -4898,7 +4898,8 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, else rb_alloc_ind = 0; - + if (rb_alloc_ind==1) + nb_rb++; // PBCH if ((subframe==0) && (rb>((frame_parms->N_RB_DL>>1)-3)) && (rb<((frame_parms->N_RB_DL>>1)+3)) && (l>=nsymb>>1) && (l<((nsymb>>1) + 4))) { @@ -5128,8 +5129,6 @@ unsigned short dlsch_extract_rbs_TM7(int **rxdataF, } }// pilots=0 - - nb_rb++; } dl_ch0+=12; From 1096744662ea84bc15fe47cdd5821d9843ff30c5 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 30 Nov 2015 15:31:33 +0100 Subject: [PATCH 028/413] cell specific beamforming weights adaption nb of tx antennas --- openair1/SIMULATION/LTE_PHY/dlsim.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 1bcbe57717..5c1c8fc896 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -799,8 +799,15 @@ int main(int argc, char **argv) cell_spec_bf_weights = PHY_vars_eNB->lte_eNB_common_vars.cell_spec_bf_weights[0][0]; for(aa=0;aaofdm_symbol_size;i++) { - cell_spec_bf_weights[aa][i] = 0x00007fff; + for(re=0;reofdm_symbol_size;re++) { + if (n_tx_phy==1 || n_tx_phy==2) + cell_spec_bf_weights[aa][re] = 0x00007fff; + else if (n_tx_phy==4) + cell_spec_bf_weights[aa][re] = 0x00007fff>>1; + else if (n_tx_phy==16) + cell_spec_bf_weights[aa][re] = 0x00007fff>>2; + else if (n_tx_phy==64) + cell_spec_bf_weights[aa][re] = 0x00007fff>>4; } } From 5c0098e2f0ed7c90ab121482cc8f402884f05551 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Tue, 15 Dec 2015 11:53:47 +0100 Subject: [PATCH 029/413] * add async interface support for eNB agent and create a lib --- cmake_targets/CMakeLists.txt | 15 +- openair2/UTIL/ASYNC_IF/link_manager.c | 247 +++++++++++++++++ openair2/UTIL/ASYNC_IF/link_manager.h | 69 +++++ openair2/UTIL/ASYNC_IF/message_queue.c | 211 +++++++++++++++ openair2/UTIL/ASYNC_IF/message_queue.h | 71 +++++ openair2/UTIL/ASYNC_IF/socket_link.c | 349 +++++++++++++++++++++++++ openair2/UTIL/ASYNC_IF/socket_link.h | 65 +++++ 7 files changed, 1026 insertions(+), 1 deletion(-) create mode 100644 openair2/UTIL/ASYNC_IF/link_manager.c create mode 100644 openair2/UTIL/ASYNC_IF/link_manager.h create mode 100644 openair2/UTIL/ASYNC_IF/message_queue.c create mode 100644 openair2/UTIL/ASYNC_IF/message_queue.h create mode 100644 openair2/UTIL/ASYNC_IF/socket_link.c create mode 100644 openair2/UTIL/ASYNC_IF/socket_link.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index d7a656e61c..122d41baa2 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -473,6 +473,9 @@ add_list_string_option(PACKAGE_NAME "NotDefined" "As per attribute name") add_boolean_option(MESSAGE_CHART_GENERATOR False "For generating sequence diagrams") add_boolean_option(MESSAGE_CHART_GENERATOR_RLC_MAC False "trace RLC-MAC exchanges in sequence diagrams") add_boolean_option(MESSAGE_CHART_GENERATOR_PHY False "trace some PHY exchanges in sequence diagrams") + +add_boolean_option(ENB_AGENT True "enable eNB agent to inteface with a SDN contrller") + ######################## # Include order ########################## @@ -687,6 +690,16 @@ include_directories("${OPENAIR_DIR}") # Utilities Library ################ +if (ENB_AGENT) + add_library(ASYNC_IF + ${OPENAIR2_DIR}/UTIL/ASYNC_IF/socket_link.c + ${OPENAIR2_DIR}/UTIL/ASYNC_IF/link_manager.c + ${OPENAIR2_DIR}/UTIL/ASYNC_IF/message_queue.c + ) + set(ASYNC_IF_LIB ASYNC_IF) +endif() +include_directories(${OPENAIR2_DIR}/UTIL/ASYNC_IF) + add_library(HASHTABLE ${OPENAIR_DIR}/common/utils/collection/hashtable/hashtable.c ${OPENAIR_DIR}/common/utils/collection/hashtable/obj_hashtable.c @@ -1591,7 +1604,7 @@ add_executable(oaisim_nos1 target_include_directories(oaisim_nos1 PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim_nos1 -Wl,--start-group - RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} + RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${ASYNC_IF_LIB} -Wl,--end-group ) target_link_libraries (oaisim_nos1 ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) diff --git a/openair2/UTIL/ASYNC_IF/link_manager.c b/openair2/UTIL/ASYNC_IF/link_manager.c new file mode 100644 index 0000000000..9b31fc043b --- /dev/null +++ b/openair2/UTIL/ASYNC_IF/link_manager.c @@ -0,0 +1,247 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2015 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ +/*! \file link_manager.c + * \brief this is the implementation of a link manager + * \author Cedric Roux + * \date November 2015 + * \version 1.0 + * \email: cedric.roux@eurecom.fr + * @ingroup _mac + */ + +#include "link_manager.h" +#include "log.h" + +#include +#include +#include + +/* that thread reads messages in the queue and sends them to the link */ +static void *link_manager_sender_thread(void *_manager) +{ + link_manager_t *manager = _manager; + void *data; + int size; + int priority; + + LOG_D(MAC, "starting link manager sender thread\n"); + + while (manager->run) { + if (message_get(manager->send_queue, &data, &size, &priority)) + goto error; + if (link_send_packet(manager->socket_link, data, size)) + goto error; + free(data); + } + + LOG_D(MAC, "link manager sender thread quits\n"); + + return NULL; + +error: + LOG_E(MAC, "%s: error\n", __FUNCTION__); + return NULL; +} + +/* that thread receives messages from the link and puts them in the queue */ +static void *link_manager_receiver_thread(void *_manager) +{ + link_manager_t *manager = _manager; + void *data; + int size; + + LOG_D(MAC, "starting link manager receiver thread\n"); + + while (manager->run) { + if (link_receive_packet(manager->socket_link, &data, &size)) + goto error; + /* todo: priority */ + if (message_put(manager->receive_queue, data, size, 0)) + goto error; + } + + LOG_D(MAC, "link manager receiver thread quits\n"); + + return NULL; + +error: + LOG_E(MAC, "%s: error\n", __FUNCTION__); + return NULL; +} + +link_manager_t *create_link_manager( + message_queue_t *send_queue, + message_queue_t *receive_queue, + socket_link_t *link) +{ + link_manager_t *ret = NULL; + pthread_attr_t attr; + pthread_t t; + + LOG_D(MAC, "create new link manager\n"); + + ret = calloc(1, sizeof(link_manager_t)); + if (ret == NULL) + goto error; + + ret->send_queue = send_queue; + ret->receive_queue = receive_queue; + ret->socket_link = link; + ret->run = 1; + + if (pthread_attr_init(&attr)) + goto error; + + if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) + goto error; + + if (pthread_create(&t, &attr, link_manager_sender_thread, ret)) + goto error; + ret->sender = t; + + if (pthread_create(&t, &attr, link_manager_receiver_thread, ret)) + /* we should destroy the other thread here */ + goto error; + ret->receiver = t; + + if (pthread_attr_destroy(&attr)) + /* to be clean we should destroy the threads at this point, + * even if in practice we never reach it */ + goto error; + + return ret; + +error: + LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + free(ret); + return NULL; +} + +void destroy_link_manager(link_manager_t *manager) +{ + LOG_D(MAC, "destroying link manager\n"); + manager->run = 0; + /* todo: force threads to stop (using a dummy message?) */ +} + +#ifdef SERVER_TEST + +#include + +int main(void) +{ + socket_link_t *link; + message_queue_t *send_queue; + message_queue_t *receive_queue; + link_manager_t *manager; + void *data; + int size; + int priority; + + printf("starting server\n"); + + link = new_link_server(2210); + if (link == NULL) goto error; + + send_queue = new_message_queue(); + if (send_queue == NULL) goto error; + receive_queue = new_message_queue(); + if (receive_queue == NULL) goto error; + + manager = create_link_manager(send_queue, receive_queue, link); + if (manager == NULL) goto error; + + data = strdup("hello"); if (data == NULL) goto error; + if (message_put(send_queue, data, 6, 100)) goto error; + + if (message_get(receive_queue, &data, &size, &priority)) goto error; + printf("received message:\n"); + printf(" data: %s\n", (char *)data); + printf(" size: %d\n", size); + printf(" priority: %d\n", priority); + + printf("server ends\n"); + return 0; + +error: + printf("there was an error\n"); + return 1; +} + +#endif + +#ifdef CLIENT_TEST + +#include +#include + +int main(void) +{ + socket_link_t *link; + message_queue_t *send_queue; + message_queue_t *receive_queue; + link_manager_t *manager; + void *data; + int size; + int priority; + + printf("starting client\n"); + + link = new_link_client("127.0.0.1", 2210); + if (link == NULL) goto error; + + send_queue = new_message_queue(); + if (send_queue == NULL) goto error; + receive_queue = new_message_queue(); + if (receive_queue == NULL) goto error; + + manager = create_link_manager(send_queue, receive_queue, link); + if (manager == NULL) goto error; + + if (message_get(receive_queue, &data, &size, &priority)) goto error; + printf("received message:\n"); + printf(" data: %s\n", (char *)data); + printf(" size: %d\n", size); + printf(" priority: %d\n", priority); + + data = strdup("world"); if (data == NULL) goto error; + if (message_put(send_queue, data, 6, 200)) goto error; + + /* let's wait for the message to be sent (unreliable sleep, but does it for the test) */ + sleep(1); + + printf("client ends\n"); + return 0; + +error: + printf("there was an error\n"); + return 1; +} + +#endif diff --git a/openair2/UTIL/ASYNC_IF/link_manager.h b/openair2/UTIL/ASYNC_IF/link_manager.h new file mode 100644 index 0000000000..3e24b8679a --- /dev/null +++ b/openair2/UTIL/ASYNC_IF/link_manager.h @@ -0,0 +1,69 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2015 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ +/*! \file link_manager.h + * \brief this is the implementation of a link manager + * \author Cedric Roux + * \date November 2015 + * \version 1.0 + * \email: cedric.roux@eurecom.fr + * @ingroup _mac + */ + +#ifndef LINK_MANAGER_H +#define LINK_MANAGER_H + +#include "message_queue.h" +#include "socket_link.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + message_queue_t *send_queue; + message_queue_t *receive_queue; + socket_link_t *socket_link; + pthread_t sender; + pthread_t receiver; + volatile int run; +} link_manager_t; + +link_manager_t *create_link_manager( + message_queue_t *send_queue, + message_queue_t *receive_queue, + socket_link_t *link); +void destroy_link_manager(link_manager_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* LINK_MANAGER_H */ diff --git a/openair2/UTIL/ASYNC_IF/message_queue.c b/openair2/UTIL/ASYNC_IF/message_queue.c new file mode 100644 index 0000000000..3e06b5021a --- /dev/null +++ b/openair2/UTIL/ASYNC_IF/message_queue.c @@ -0,0 +1,211 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2015 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ +/*! \file message_queue.c + * \brief this is the implementation of a message queue + * \author Cedric Roux + * \date November 2015 + * \version 1.0 + * \email: cedric.roux@eurecom.fr + * @ingroup _mac + */ + +#include "message_queue.h" +#include "log.h" + +#include +#include +#include +#include + +message_queue_t *new_message_queue(void) +{ + message_queue_t *ret = NULL; + + ret = calloc(1, sizeof(message_queue_t)); + if (ret == NULL) + goto error; + + ret->mutex = calloc(1, sizeof(pthread_mutex_t)); + if (ret->mutex == NULL) + goto error; + if (pthread_mutex_init(ret->mutex, NULL)) + goto error; + + ret->cond = calloc(1, sizeof(pthread_cond_t)); + if (ret->cond == NULL) + goto error; + if (pthread_cond_init(ret->cond, NULL)) + goto error; + + return ret; + +error: + LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + if (ret != NULL) { + free(ret->mutex); + free(ret->cond); + memset(ret, 0, sizeof(message_queue_t)); + free(ret); + } + return NULL; +} + +int message_put(message_queue_t *queue, void *data, int size, int priority) +{ + message_t *m = NULL; + + m = calloc(1, sizeof(message_t)); + if (m == NULL) + goto error; + + m->data = data; + m->size = size; + m->priority = priority; + m->next = NULL; + + if (pthread_mutex_lock(queue->mutex)) + goto error; + + if (queue->count == 0) + queue->head = m; + else + queue->tail->next = m; + queue->tail = m; + + queue->count++; + + if (pthread_cond_signal(queue->cond)) { + LOG_E(MAC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + pthread_mutex_unlock(queue->mutex); + exit(1); + } + if (pthread_mutex_unlock(queue->mutex)) { + LOG_E(MAC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + return 0; + +error: + free(m); + LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +int message_get(message_queue_t *queue, void **data, int *size, int *priority) +{ + message_t *m; + + if (pthread_mutex_lock(queue->mutex)) + goto error; + + while (queue->count == 0) { + if (pthread_cond_wait(queue->cond, queue->mutex)) { + pthread_mutex_unlock(queue->mutex); + goto error; + } + } + + m = queue->head; + queue->head = queue->head->next; + if (queue->head == NULL) + queue->tail = NULL; + + queue->count--; + + if (pthread_mutex_unlock(queue->mutex)) + goto error; + + *data = m->data; + *size = m->size; + *priority = m->priority; + free(m); + + return 0; + +error: + LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +/* when calling this function, the queue must not be used anymore (we don't lock it) */ +/* we suppose that the data pointer in messages was allocated by malloc/calloc/realloc */ +void destroy_message_queue(message_queue_t *queue) +{ + while (queue->head) { + message_t *m = queue->head; + queue->head = queue->head->next; + free(m->data); + memset(m, 0, sizeof(message_t)); + free(m); + } + free(queue->mutex); + free(queue->cond); + memset(queue, 0, sizeof(message_queue_t)); + free(queue); +} + +#ifdef TEST + +/* some very basic tests */ +int main(void) +{ + void *data; + int size; + int priority; + message_queue_t *q; + char *s; + + q = new_message_queue(); + if (q == NULL) goto error; + + if (message_put(q, "hello", 6, 0)) goto error; + if (message_put(q, "world", 6, 1)) goto error; + + if (message_get(q, &data, &size, &priority)) goto error; + printf("message:\n data: '%s'\n size: %d\n priority: %d\n", + (char *)data, size, priority); + if (message_get(q, &data, &size, &priority)) goto error; + printf("message:\n data: '%s'\n size: %d\n priority: %d\n", + (char *)data, size, priority); + + /* let's put a message before destroying the queue */ + s = malloc(10); if (s == NULL) goto error; + sprintf(s, "hello"); + if (message_put(q, s, 6, 0)) goto error; + destroy_message_queue(q); + + return 0; + +error: + printf("error\n"); + return 1; +} + +#endif diff --git a/openair2/UTIL/ASYNC_IF/message_queue.h b/openair2/UTIL/ASYNC_IF/message_queue.h new file mode 100644 index 0000000000..15fc4335a1 --- /dev/null +++ b/openair2/UTIL/ASYNC_IF/message_queue.h @@ -0,0 +1,71 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2015 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ +/*! \file message_queue.h + * \brief this is the implementation of a message queue + * \author Cedric Roux + * \date November 2015 + * \version 1.0 + * \email: cedric.roux@eurecom.fr + * @ingroup _mac + */ + +#ifndef MESSAGE_QUEUE_H +#define MESSAGE_QUEUE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct message_t { + void *data; + int size; + int priority; + struct message_t *next; +} message_t; + +typedef struct { + message_t *head; + message_t *tail; + volatile int count; + pthread_mutex_t *mutex; + pthread_cond_t *cond; +} message_queue_t; + +message_queue_t *new_message_queue(void); +int message_put(message_queue_t *queue, void *data, int size, int priority); +int message_get(message_queue_t *queue, void **data, int *size, int *priority); +void destroy_message_queue(message_queue_t *queue); + +#ifdef __cplusplus +} +#endif + +#endif /* MESSAGE_QUEUE_H */ diff --git a/openair2/UTIL/ASYNC_IF/socket_link.c b/openair2/UTIL/ASYNC_IF/socket_link.c new file mode 100644 index 0000000000..95a92ae3ee --- /dev/null +++ b/openair2/UTIL/ASYNC_IF/socket_link.c @@ -0,0 +1,349 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2015 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ +/*! \file socket_link.c + * \brief this is the implementation of a TCP socket ASYNC IF + * \author Cedric Roux + * \date November 2015 + * \version 1.0 + * \email: cedric.roux@eurecom.fr + * @ingroup _mac + */ + +#include "socket_link.h" +#include "log.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +socket_link_t *new_link_server(int port) +{ + socket_link_t *ret = NULL; + int reuse; + struct sockaddr_in addr; + socklen_t addrlen; + int socket_server = -1; + + ret = calloc(1, sizeof(socket_link_t)); + if (ret == NULL) { + LOG_E(MAC, "%s:%d: out of memory\n", __FILE__, __LINE__); + goto error; + } + ret->socket_fd = -1; + + LOG_D(MAC, "create a new link server socket at port %d\n", port); + + socket_server = socket(AF_INET, SOCK_STREAM, 0); + if (socket_server == -1) { + LOG_E(MAC, "%s:%d: socket: %s\n", __FILE__, __LINE__, strerror(errno)); + goto error; + } + + reuse = 1; + if (setsockopt(socket_server, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) { + LOG_E(MAC, "%s:%d: setsockopt: %s\n", __FILE__, __LINE__, strerror(errno)); + goto error; + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + if (bind(socket_server, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + LOG_E(MAC, "%s:%d: bind: %s\n", __FILE__, __LINE__, strerror(errno)); + goto error; + } + + if (listen(socket_server, 5)) { + LOG_E(MAC, "%s:%d: listen: %s\n", __FILE__, __LINE__, strerror(errno)); + goto error; + } + + addrlen = sizeof(addr); + ret->socket_fd = accept(socket_server, (struct sockaddr *)&addr, &addrlen); + if (ret->socket_fd == -1) { + LOG_E(MAC, "%s:%d: accept: %s\n", __FILE__, __LINE__, strerror(errno)); + goto error; + } + + close(socket_server); + + LOG_D(MAC, "connection from %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + return ret; + +error: + close(socket_server); + if (ret != NULL) close(ret->socket_fd); + free(ret); + LOG_E(MAC, "ERROR in new_link_server (see above), returning NULL\n"); + return NULL; +} + +socket_link_t *new_link_client(char *server, int port) +{ + socket_link_t *ret = NULL; + struct sockaddr_in addr; + + ret = calloc(1, sizeof(socket_link_t)); + if (ret == NULL) { + LOG_E(MAC, "%s:%d: out of memory\n", __FILE__, __LINE__); + goto error; + } + ret->socket_fd = -1; + + LOG_D(MAC, "create a new link client socket connecting to %s:%d\n", server, port); + + ret->socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (ret->socket_fd == -1) { + LOG_E(MAC, "%s:%d: socket: %s\n", __FILE__, __LINE__, strerror(errno)); + goto error; + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + if (inet_aton(server, &addr.sin_addr) == 0) { + LOG_E(MAC, "invalid IP address '%s', use a.b.c.d notation\n", server); + goto error; + } + if (connect(ret->socket_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + LOG_E(MAC, "%s:%d: connect: %s\n", __FILE__, __LINE__, strerror(errno)); + goto error; + } + + LOG_D(MAC, "connection to %s:%d established\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + return ret; + +error: + if (ret != NULL) close(ret->socket_fd); + free(ret); + LOG_E(MAC, "ERROR in new_link_client (see above), returning NULL\n"); + return NULL; +} + +/* + * return -1 on error and 0 if the sending was fine + */ +static int socket_send(int socket_fd, void *buf, int size) +{ + char *s = buf; + int l; + + while (size) { + l = send(socket_fd, s, size, MSG_NOSIGNAL); + if (l == -1) goto error; + if (l == 0) { LOG_E(MAC, "%s:%d: this cannot happen, normally...\n", __FILE__, __LINE__); abort(); } + size -= l; + s += l; + } + + return 0; + +error: + LOG_E(MAC, "socket_send: ERROR: %s\n", strerror(errno)); + return -1; +} + +/* + * return -1 on error and 0 if the receiving was fine + */ +static int socket_receive(int socket_fd, void *buf, int size) +{ + char *s = buf; + int l; + + while (size) { + l = read(socket_fd, s, size); + if (l == -1) goto error; + if (l == 0) goto socket_closed; + size -= l; + s += l; + } + + return 0; + +error: + LOG_E(MAC, "socket_receive: ERROR: %s\n", strerror(errno)); + return -1; + +socket_closed: + LOG_E(MAC, "socket_receive: socket closed\n"); + return -1; +} + +/* + * return -1 on error and 0 if the sending was fine + */ +int link_send_packet(socket_link_t *link, void *data, int size) +{ + char sizebuf[4]; + int32_t s = size; + + /* send the size first, maximum is 2^31 bytes */ + sizebuf[0] = (s >> 24) & 255; + sizebuf[1] = (s >> 16) & 255; + sizebuf[2] = (s >> 8) & 255; + sizebuf[3] = s & 255; + + if (socket_send(link->socket_fd, sizebuf, 4) == -1) + goto error; + + link->bytes_sent += 4; + + if (socket_send(link->socket_fd, data, size) == -1) + goto error; + + link->bytes_sent += size; + link->packets_sent++; + + return 0; + +error: + return -1; +} + +/* + * return -1 on error and 0 if the sending was fine + */ +int link_receive_packet(socket_link_t *link, void **ret_data, int *ret_size) +{ + unsigned char sizebuf[4]; + int32_t size; + void *data = NULL; + + /* received the size first, maximum is 2^31 bytes */ + if (socket_receive(link->socket_fd, sizebuf, 4) == -1) + goto error; + + size = (sizebuf[0] << 24) | + (sizebuf[1] << 16) | + (sizebuf[2] << 8) | + sizebuf[3]; + + link->bytes_received += 4; + + data = malloc(size); + if (data == NULL) { + LOG_E(MAC, "%s:%d: out of memory\n", __FILE__, __LINE__); + goto error; + } + + if (socket_receive(link->socket_fd, data, size) == -1) + goto error; + + link->bytes_received += size; + link->packets_received++; + + *ret_data = data; + *ret_size = size; + return 0; + +error: + free(data); + *ret_data = NULL; + *ret_size = 0; + return -1; +} + +/* + * return -1 on error, 0 if all is fine + */ +int close_link(socket_link_t *link) +{ + close(link->socket_fd); + memset(link, 0, sizeof(socket_link_t)); + free(link); + return 0; +} + +#ifdef SERVER_TEST + +#include + +int main(void) +{ + void *data; + int size; + socket_link_t *l = new_link_server(2210); + if (l == NULL) { printf("no link created\n"); return 1; } + printf("link is up\n"); + printf("server starts sleeping...\n"); + /* this sleep is here to test for broken pipe. You can run "nc localhost 2210" + * and interrupt it quickly so that the server gets a 'broken' pipe on the + * following link_send_packet. + */ + sleep(1); + printf("... done\n"); + if (link_send_packet(l, "hello\n", 6+1) || + link_send_packet(l, "world\n", 6+1)) return 1; + if (link_receive_packet(l, &data, &size)) return 1; printf("%s", (char *)data); free(data); + if (link_receive_packet(l, &data, &size)) return 1; printf("%s", (char *)data); free(data); + printf("stats:\n"); + printf(" sent packets %"PRIu64"\n", l->packets_sent); + printf(" sent bytes %"PRIu64"\n", l->bytes_sent); + printf(" received packets %"PRIu64"\n", l->packets_received); + printf(" received bytes %"PRIu64"\n", l->bytes_received); + if (close_link(l)) return 1; + printf("link is down\n"); + return 0; +} + +#endif + +#ifdef CLIENT_TEST + +#include + +int main(void) +{ + void *data; + int size; + socket_link_t *l = new_link_client("127.0.0.1", 2210); + if (l == NULL) { printf("no link created\n"); return 1; } + printf("link is up\n"); + if (link_receive_packet(l, &data, &size)) return 1; printf("%s", (char *)data); free(data); + if (link_receive_packet(l, &data, &size)) return 1; printf("%s", (char *)data); free(data); + if (link_send_packet(l, "bye\n", 4+1) || + link_send_packet(l, "server\n", 7+1)) return 1; + printf("stats:\n"); + printf(" sent packets %"PRIu64"\n", l->packets_sent); + printf(" sent bytes %"PRIu64"\n", l->bytes_sent); + printf(" received packets %"PRIu64"\n", l->packets_received); + printf(" received bytes %"PRIu64"\n", l->bytes_received); + if (close_link(l)) return 1; + printf("link is down\n"); + return 0; +} + +#endif diff --git a/openair2/UTIL/ASYNC_IF/socket_link.h b/openair2/UTIL/ASYNC_IF/socket_link.h new file mode 100644 index 0000000000..c9e99b839f --- /dev/null +++ b/openair2/UTIL/ASYNC_IF/socket_link.h @@ -0,0 +1,65 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2015 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ +/*! \file socket_link.h + * \brief this is the implementation of a TCP socket ASYNC IF + * \author Cedric Roux + * \date November 2015 + * \version 1.0 + * \email: cedric.roux@eurecom.fr + * @ingroup _mac + */ + +#ifndef SOCKET_LINK_H +#define SOCKET_LINK_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int socket_fd; + uint64_t bytes_sent; + uint64_t packets_sent; + uint64_t bytes_received; + uint64_t packets_received; +} socket_link_t; + +socket_link_t *new_link_server(int port); +socket_link_t *new_link_client(char *server, int port); +int link_send_packet(socket_link_t *link, void *data, int size); +int link_receive_packet(socket_link_t *link, void **data, int *size); +int close_link(socket_link_t *link); + +#ifdef __cplusplus +} +#endif + +#endif /* SOCKET_LINK_H */ From 7ccf7a917f2928858e3cc8ac86dea88e43a3be82 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Tue, 15 Dec 2015 19:44:12 +0100 Subject: [PATCH 030/413] * add protobuf messages and compliation directives --- openair2/ENB_APP/MESSAGES/V2/header.proto | 19 ++ openair2/ENB_APP/MESSAGES/V2/progran.proto | 69 +++++++ .../ENB_APP/MESSAGES/V2/stats_common.proto | 176 ++++++++++++++++++ .../ENB_APP/MESSAGES/V2/stats_messages.proto | 86 +++++++++ 4 files changed, 350 insertions(+) create mode 100644 openair2/ENB_APP/MESSAGES/V2/header.proto create mode 100644 openair2/ENB_APP/MESSAGES/V2/progran.proto create mode 100644 openair2/ENB_APP/MESSAGES/V2/stats_common.proto create mode 100644 openair2/ENB_APP/MESSAGES/V2/stats_messages.proto diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto new file mode 100644 index 0000000000..9193696491 --- /dev/null +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -0,0 +1,19 @@ +package protocol; + +message prp_header { + optional uint32 version = 1; + optional uint32 type = 2; + optional uint32 length = 3; + optional uint32 xid = 4; +} + +enum prp_type { + // Discovery and maintenance messages + PRPT_HELLO = 0; + PRPT_ECHO_REQUEST = 1; + PRPT_ECHO_REPLY = 2; + + // Statistics and measurement messages + PRPT_STATS_REQUEST = 3; + PRPT_STATS_REPLY = 4; +} \ No newline at end of file diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto new file mode 100644 index 0000000000..9e29f99532 --- /dev/null +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -0,0 +1,69 @@ +package protocol; + +import "stats_messages.proto"; + +// +// Maintenance and discovery messages +// + +// Empty message. Does not really have to be used. +// Could use only the header with the type set to PRPT_HELLO +message prp_hello { +} + +message prp_echo_request { + extensions 100 to 199; +} + + +message prp_echo_reply { + extensions 100 to 199; +} + + + +// +// Statistics request and reply message +// + +message prp_stats_request { + optional prp_stats_type type = 1; + oneof body { + prp_complete_stats_request complete_stats_request = 2; + prp_cell_stats_request cell_stats_request = 3; + prp_ue_stats_request ue_stats_request = 4; + } +} + +message prp_stats_reply { + optional prp_ue_stats_report ue_report = 1; + optional prp_cell_stats_report cell_report = 2; +} + + +// Extensions of the echo request and reply +// messages for carrying a latency value in ms +message prp_echo_request_latency { + extend prp_echo_request { + optional uint32 latency = 100; + } +} + +message prp_echo_reply_latency { + extend prp_echo_reply { + optional uint32 latency = 100; + } +} + + +//message progran_body { +// oneof msg { +// prp_hello hello_msg = 1; +// prp_echo_request echo_request_msg = 2; +// prp_echo_reply echo_reply_msg = 3; +// prp_stats_request stats_request_msg = 4; +// prp_stats_reply stats_reply_msg = 5; +// } +//} + + diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto new file mode 100644 index 0000000000..77df92a68b --- /dev/null +++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto @@ -0,0 +1,176 @@ +package protocol; + +// +// UE related statistics +// + +// RLC buffer status for a specific logical channel of a UE +message prp_rlc_bsr { + optional uint32 lc_id = 1; + optional uint32 tx_queue_size = 2; + optional uint32 tx_queue_hol_delay = 3; + optional uint32 retransmission_queue_size = 4; + optional uint32 retransmission_queue_hol_delay = 5; + optional uint32 status_pdu_size = 6; +} + +// Flags for MAC Control Elements +enum prp_ce_type { + PRPCET_TA = 1; + PRPCET_DRX = 2; + PRPCET_CR = 4; + PRPCET_CA = 8; +} + +// Types of DL CSI reports +enum prp_csi_type { + PRCSIT_P10 = 0; + PRCSIT_P11 = 1; + PRCSIT_P20 = 2; + PRCSIT_P21 = 3; + PRCSIT_A12 = 4; + PRCSIT_A22 = 5; + PRCSIT_A20 = 6; + PRCSIT_A30 = 7; + PRCSIT_A31 = 8; +} + +// CSI type P10 +message prp_csi_p10 { + optional uint32 wb_cqi = 1; +} + +// CSI type P11 +message prp_csi_p11 { + repeated uint32 wb_cqi = 1; + optional uint32 wb_pmi = 2; +} + +// CSI type P20 +message prp_csi_p20 { + optional uint32 wb_cqi = 1; + optional uint32 sb_cqi = 2; + optional uint32 bandwidth_part_index = 3; + optional uint32 sb_index = 4; +} + +// CSI type P21 +message prp_csi_p21 { + repeated uint32 wb_cqi = 1; + optional uint32 wb_pmi = 2; + repeated uint32 sb_cqi = 3; + optional uint32 badwidth_part_index = 4; + optional uint32 sb_index = 5; +} + +// CSI type A12 +message prp_csi_a12 { + repeated uint32 wb_cqi = 1; + repeated uint32 sb_pmi = 2; +} + +// CSI type A22 +message prp_csi_a22 { + repeated uint32 wb_cqi = 1; + repeated uint32 sb_cqi = 2; + optional uint32 wb_pmi = 3; + optional uint32 sb_pmi = 4; + repeated uint32 sb_list = 5; +} + +// CSI type A20 +message prp_csi_a20 { + optional uint32 wb_cqi = 1; + optional uint32 sb_cqi = 2; + repeated uint32 sb_list = 3; +} + +// CSI type A30 +message prp_csi_a30 { + optional uint32 wb_cqi = 1; + repeated uint32 sb_cqi = 2; +} + +// CSI type A31 +message prp_csi_a31 { + repeated uint32 wb_cqi = 1; + repeated prp_msb_cqi sb_cqi = 2; + optional uint32 wb_pmi = 3; +} + +// The CQI for the M-preffered subband +message prp_msb_cqi { + repeated uint32 sb_cqi = 1; +} + +// The CSI report of the UE for a specific servCellIndex +message prp_dl_csi { + optional uint32 serv_cell_index = 1; + optional uint32 ri = 2; + optional prp_csi_type type = 3; + oneof report { + prp_csi_p10 p10csi = 4; + prp_csi_p11 p11csi = 5; + prp_csi_p20 p20csi = 6; + prp_csi_p21 p21csi = 7; + prp_csi_a12 a12csi = 8; + prp_csi_a22 a22csi = 9; + prp_csi_a20 a20csi = 10; + prp_csi_a30 a30csi = 11; + prp_csi_a31 a31csi = 12; + } +} + +// The full DL CQI report for all CC of a UE +message prp_dl_cqi_report { + optional uint32 sfn_sn = 1; + repeated prp_dl_csi csi_report = 2; +} + +// Paging message info +message prp_paging_info { + optional uint32 paging_index = 1; + optional uint32 paging_message_size = 2; + optional uint32 paging_subframe = 3; + optional uint32 carrier_index = 4; +} + +// Report for the paging buffer status +message prp_paging_buffer_report { + repeated prp_paging_info paging_info = 1; +} + +// The type of UL CQI +enum prp_ul_cqi_type { + PRUCT_SRS = 0; + PRUCT_PUSCH = 1; + PRUCT_PUCCH_1 = 2; + PRUCT_PUCCH_2 = 3; + PRUCT_PRACH = 4; +} + +// UL CQI report for a specific UE for a given report type +message prp_ul_cqi { + optional prp_ul_cqi_type type = 1; + repeated uint32 sinr = 2; + optional uint32 serv_cell_index = 3; +} + +// Full UL CQI report for a specific UE +message prp_ul_cqi_report { + optional uint32 sfn_sn = 1; + repeated prp_ul_cqi cqi_meas = 2; +} + + +// +// Cell related statistics +// + +// The UL noise and interference report for a UE +message prp_noise_interference_report { + optional uint32 sfn_sf = 1; + optional uint32 rip = 2; + optional uint32 tnp = 3; +} + diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto new file mode 100644 index 0000000000..5ec7ae690c --- /dev/null +++ b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto @@ -0,0 +1,86 @@ +package protocol; + +//import "header.proto"; +import "stats_common.proto"; + +// +// Bodies of statistics report requests +// + +message prp_complete_stats_request { + optional prp_stats_report_freq report_frequency = 1; + optional uint32 sf = 2; + optional uint32 cell_report_flags = 3; + optional uint32 ue_report_flags = 4; +} + +message prp_cell_stats_request { + repeated uint32 cell = 1; + optional uint32 flags = 2; +} + +message prp_ue_stats_request { + repeated uint32 rnti = 1; + optional uint32 flags = 2; +} + +// +// Bodies of statistics reports +// + +// The full statistics report for a specific cell +message prp_cell_stats_report { + optional uint32 carrier_index = 1; + optional uint32 flags = 2; + optional prp_noise_interference_report noise_inter_report = 3; +} + +// Statistics report for a specific UE +message prp_ue_stats_report { + optional uint32 rnti = 1; + optional uint32 flags = 2; + repeated uint32 bsr = 3; + optional uint32 phr = 4; + repeated prp_rlc_bsr rlc_report = 5; + optional uint32 pending_mac_ces = 6; + optional prp_dl_cqi_report dl_cqi_report = 7; + optional prp_paging_buffer_report pbr = 8; + optional prp_ul_cqi_report ul_cqi_report = 9; +} + +// +// Types of statistics related enums +// + + +//Types of statistics requested by the controller +enum prp_stats_type { + PRST_COMPLETE_STATS = 0; + PRST_CELL_STATS = 1; + PRST_UE_STATS = 2; +} + +// Report frequency for the requested statistics +enum prp_stats_report_freq { + PRSRF_ONCE = 0; + PRSRF_PERIODICAL = 1; + PRSRF_CONTINUOUS = 2; + PRSRF_OFF = 3; +} + +// Flags for cell statistics +enum prp_cell_stats_type { + PRCST_NOISE_INTERFERENCE = 1; +} + +// Flags for UE-related statistics +enum prp_ue_stats_type { + PRUST_BSR = 1; + PRUST_PRH = 2; + PRUST_RLC_BS = 4; + PRUST_MAC_CE_BS = 8; + PRUST_DL_CQI = 16; + PRUST_PBS = 32; + PRUST_UL_CQI = 64; + // To be extended with more types of stats +} \ No newline at end of file From 694718963a9b6bbf3de73ea7fff3844b4e23e2c3 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Tue, 15 Dec 2015 19:46:52 +0100 Subject: [PATCH 031/413] * script for automatic generation of protobug messages --- cmake_targets/tools/generate_protobuf | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100755 cmake_targets/tools/generate_protobuf diff --git a/cmake_targets/tools/generate_protobuf b/cmake_targets/tools/generate_protobuf new file mode 100755 index 0000000000..203fd1b0de --- /dev/null +++ b/cmake_targets/tools/generate_protobuf @@ -0,0 +1,15 @@ +#!/bin/bash + +function main() +{ +mkdir -p $1 +cd $1 + +echo generate protobuf messages inside $1 $2 + +protoc-c --c_out=$1 $2 +protoc --cpp_out=$1 $2 + +} + +main "$@" From 5f1f1abe3f5d7c4e52d4294d7876782fd2cc799b Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 15 Dec 2015 22:47:08 +0200 Subject: [PATCH 032/413] Added header in messages and removed length field --- openair2/ENB_APP/MESSAGES/V2/header.proto | 5 ++- openair2/ENB_APP/MESSAGES/V2/progran.proto | 42 ++++++++++++---------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index 9193696491..f25613d86d 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -3,8 +3,7 @@ package protocol; message prp_header { optional uint32 version = 1; optional uint32 type = 2; - optional uint32 length = 3; - optional uint32 xid = 4; + optional uint32 xid = 3; } enum prp_type { @@ -16,4 +15,4 @@ enum prp_type { // Statistics and measurement messages PRPT_STATS_REQUEST = 3; PRPT_STATS_REPLY = 4; -} \ No newline at end of file +} diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index 9e29f99532..731bb2c4f5 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -1,22 +1,35 @@ package protocol; import "stats_messages.proto"; +import "header.proto" + +message progran_message { + oneof msg { + prp_hello hello_msg = 1; + prp_echo_request echo_request_msg = 2; + prp_echo_reply echo_reply_msg = 3; + prp_stats_request stats_request_msg = 4; + prp_stats_reply stats_reply_msg = 5; + } +} + // // Maintenance and discovery messages // -// Empty message. Does not really have to be used. -// Could use only the header with the type set to PRPT_HELLO message prp_hello { + optional prp_header header = 1; } message prp_echo_request { + optional prp_header header = 1; extensions 100 to 199; } message prp_echo_reply { + optional prp_header header = 1; extensions 100 to 199; } @@ -27,17 +40,19 @@ message prp_echo_reply { // message prp_stats_request { - optional prp_stats_type type = 1; + optional prp_header header = 1; + optional prp_stats_type type = 2; oneof body { - prp_complete_stats_request complete_stats_request = 2; - prp_cell_stats_request cell_stats_request = 3; - prp_ue_stats_request ue_stats_request = 4; + prp_complete_stats_request complete_stats_request = 3; + prp_cell_stats_request cell_stats_request = 4; + prp_ue_stats_request ue_stats_request = 5; } } message prp_stats_reply { - optional prp_ue_stats_report ue_report = 1; - optional prp_cell_stats_report cell_report = 2; + optional prp_header header = 1; + optional prp_ue_stats_report ue_report = 2; + optional prp_cell_stats_report cell_report = 3; } @@ -56,14 +71,3 @@ message prp_echo_reply_latency { } -//message progran_body { -// oneof msg { -// prp_hello hello_msg = 1; -// prp_echo_request echo_request_msg = 2; -// prp_echo_reply echo_reply_msg = 3; -// prp_stats_request stats_request_msg = 4; -// prp_stats_reply stats_reply_msg = 5; -// } -//} - - From 183e105f871d959609f9d541bb9fad63d38bd529 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Wed, 16 Dec 2015 11:58:48 +0100 Subject: [PATCH 033/413] update CMakeLists--generate .c files for protobufs --- cmake_targets/CMakeLists.txt | 45 +++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 122d41baa2..f8b1a343a5 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -244,6 +244,9 @@ endif (${RTAI}) set(asn1c_call "${OPENAIR_CMAKE}/tools/generate_asn1") set(asn1_generated_dir ${OPENAIR_BIN_DIR}) +set(protoc_call "${OPENAIR_CMAKE}/tools/generate_protobuf") +set(protobuf_generated_dir ${OPENAIR_BIN_DIR}) + # RRC ###### add_list2_option(RRC_ASN1_VERSION "Rel10" "ASN.1 version of RRC interface" "Rel8" "Rel10" "CBA") @@ -691,14 +694,54 @@ include_directories("${OPENAIR_DIR}") # Utilities Library ################ if (ENB_AGENT) + # set the version of protobuf messages, V3 not supported yet + add_list1_option(PRPT_VERSION V2 "PRPT MSG protobuf grammar version" V2 V3) + + if (${PRPT_VERSION} STREQUAL "V2") + set (PRPTDIR V2) + elseif (${PRPT_VERSION} STREQUAL "V3") + set (PRPTDIR V3) + endif(${PRPT_VERSION} STREQUAL "V2") + + set(PRPT_MSG_DIR ${OPENAIR2_DIR}/ENB_APP/MESSAGES/${PRPTDIR} ) + set(PRPT_MSG_FILES + ${PRPT_MSG_DIR}/header.proto + ${PRPT_MSG_DIR}/progran.proto + ${PRPT_MSG_DIR}/stats_common.proto + ${PRPT_MSG_DIR}/stats_messages.proto + ) + + set(PRPT_C_DIR ${protobuf_generated_dir}/${PRPTDIR}) + message("calling ${protoc_call} ${PRPT_C_DIR} ${PRPT_MSG_FILES}") + execute_process(COMMAND ${protoc_call} ${PRPT_C_DIR} ${PRPT_MSG_FILES}) + file(GLOB PRPT_source ${PRPT_C_DIR}/*.c) + set(PRPT_OAI_generated + ${PRPT_C_DIR}/header.pb-c.c + ${PRPT_C_DIR}/progran.pb-c.c + ${PRPT_C_DIR}/stats_common.pb-c.c + ${PRPT_C_DIR}/stats_messages.pb-c.c + ) + + file(GLOB prpt_h ${PRPT_C_DIR}/*.h) + set(prpt_h ${prpt_h} ) + + add_library(PRPT_MSG + ${PRPT_OAI_generated} + ${PRPT_source} + ) + + include_directories ("${PRPT_C_DIR}") + add_library(ASYNC_IF ${OPENAIR2_DIR}/UTIL/ASYNC_IF/socket_link.c ${OPENAIR2_DIR}/UTIL/ASYNC_IF/link_manager.c ${OPENAIR2_DIR}/UTIL/ASYNC_IF/message_queue.c ) set(ASYNC_IF_LIB ASYNC_IF) + include_directories(${OPENAIR2_DIR}/UTIL/ASYNC_IF) + endif() -include_directories(${OPENAIR2_DIR}/UTIL/ASYNC_IF) + add_library(HASHTABLE ${OPENAIR_DIR}/common/utils/collection/hashtable/hashtable.c From 988b483ab0c069f6b452c9beb392badc1ba330ce Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Wed, 16 Dec 2015 16:53:37 +0100 Subject: [PATCH 034/413] * automatic generation of protobuf messages in CMakeList.txt --- cmake_targets/CMakeLists.txt | 8 ++++---- cmake_targets/tools/generate_protobuf | 12 ++++++++---- openair2/ENB_APP/MESSAGES/V2/progran.proto | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index f8b1a343a5..197b94699c 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -712,8 +712,8 @@ if (ENB_AGENT) ) set(PRPT_C_DIR ${protobuf_generated_dir}/${PRPTDIR}) - message("calling ${protoc_call} ${PRPT_C_DIR} ${PRPT_MSG_FILES}") - execute_process(COMMAND ${protoc_call} ${PRPT_C_DIR} ${PRPT_MSG_FILES}) + #message("calling protoc_call=${protoc_call} PRPT_C_DIR=${PRPT_C_DIR} PRPT_MSG_FILES=${PRPT_MSG_FILES}") + execute_process(COMMAND ${protoc_call} ${PRPT_C_DIR} ${PRPT_MSG_DIR} ${PRPT_MSG_FILES}) file(GLOB PRPT_source ${PRPT_C_DIR}/*.c) set(PRPT_OAI_generated ${PRPT_C_DIR}/header.pb-c.c @@ -729,7 +729,7 @@ if (ENB_AGENT) ${PRPT_OAI_generated} ${PRPT_source} ) - + set(PRPT_MSG_LIB PRPT_MSG) include_directories ("${PRPT_C_DIR}") add_library(ASYNC_IF @@ -1647,7 +1647,7 @@ add_executable(oaisim_nos1 target_include_directories(oaisim_nos1 PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim_nos1 -Wl,--start-group - RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${ASYNC_IF_LIB} + RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} -Wl,--end-group ) target_link_libraries (oaisim_nos1 ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) diff --git a/cmake_targets/tools/generate_protobuf b/cmake_targets/tools/generate_protobuf index 203fd1b0de..5c1b523f8c 100755 --- a/cmake_targets/tools/generate_protobuf +++ b/cmake_targets/tools/generate_protobuf @@ -3,12 +3,16 @@ function main() { mkdir -p $1 -cd $1 -echo generate protobuf messages inside $1 $2 +#echo generate protobuf messages inside $1 $2 -protoc-c --c_out=$1 $2 -protoc --cpp_out=$1 $2 +c_out=$1 +shift +proto_path=$1 +shift + +protoc-c --c_out=$c_out --proto_path=$proto_path $* +#protoc --cpp_out=$c_out --proto_path=$proto_path $* } diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index 731bb2c4f5..41bbeaaf81 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -1,7 +1,7 @@ package protocol; import "stats_messages.proto"; -import "header.proto" +import "header.proto"; message progran_message { oneof msg { From 0dee574c578091efe8fc02c62b203cb910497eea Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 17 Dec 2015 11:37:18 +0200 Subject: [PATCH 035/413] Changed prp_stats_reply message to support multiple UE and cell reports --- openair2/ENB_APP/MESSAGES/V2/progran.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index 41bbeaaf81..e631762946 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -51,8 +51,8 @@ message prp_stats_request { message prp_stats_reply { optional prp_header header = 1; - optional prp_ue_stats_report ue_report = 2; - optional prp_cell_stats_report cell_report = 3; + repeated prp_ue_stats_report ue_report = 2; + repeated prp_cell_stats_report cell_report = 3; } From 17251ddaacb491793c3b1b2bbf42fb741a0f0e22 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Mon, 21 Dec 2015 03:36:37 +0100 Subject: [PATCH 036/413] Very basic version of the enb agent --- cmake_targets/CMakeLists.txt | 24 +- .../oaisim_noS1_build_oai/CMakeLists.template | 2 +- openair2/ENB_APP/MESSAGES/V2/header.proto | 3 +- openair2/ENB_APP/MESSAGES/V2/progran.proto | 31 +- openair2/ENB_APP/enb_agent.c | 202 +++++++ openair2/ENB_APP/enb_agent.h | 47 ++ openair2/ENB_APP/enb_agent_common.c | 246 ++++++++ openair2/ENB_APP/enb_agent_common.h | 88 +++ openair2/ENB_APP/enb_agent_handler.c | 133 +++++ openair2/ENB_APP/enb_agent_mac.c | 552 ++++++++++++++++++ openair2/ENB_APP/enb_agent_mac.h | 77 +++ openair2/ENB_APP/enb_app.c | 9 + targets/SIMU/USER/oaisim.c | 9 + 13 files changed, 1414 insertions(+), 9 deletions(-) create mode 100644 openair2/ENB_APP/enb_agent.c create mode 100644 openair2/ENB_APP/enb_agent.h create mode 100644 openair2/ENB_APP/enb_agent_common.c create mode 100644 openair2/ENB_APP/enb_agent_common.h create mode 100644 openair2/ENB_APP/enb_agent_handler.c create mode 100644 openair2/ENB_APP/enb_agent_mac.c create mode 100644 openair2/ENB_APP/enb_agent_mac.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 197b94699c..6fa30b2b35 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -477,7 +477,7 @@ add_boolean_option(MESSAGE_CHART_GENERATOR False "For generating sequenc add_boolean_option(MESSAGE_CHART_GENERATOR_RLC_MAC False "trace RLC-MAC exchanges in sequence diagrams") add_boolean_option(MESSAGE_CHART_GENERATOR_PHY False "trace some PHY exchanges in sequence diagrams") -add_boolean_option(ENB_AGENT True "enable eNB agent to inteface with a SDN contrller") +add_boolean_option(ENB_AGENT_SB_IF True "enable eNB agent to inteface with a SDN contrller") ######################## # Include order @@ -693,7 +693,7 @@ include_directories("${OPENAIR_DIR}") # Utilities Library ################ -if (ENB_AGENT) +if (ENB_AGENT_SB_IF) # set the version of protobuf messages, V3 not supported yet add_list1_option(PRPT_VERSION V2 "PRPT MSG protobuf grammar version" V2 V3) @@ -730,7 +730,8 @@ if (ENB_AGENT) ${PRPT_source} ) set(PRPT_MSG_LIB PRPT_MSG) - include_directories ("${PRPT_C_DIR}") + #message("prpt c dir is : ${PRPT_C_DIR}") + include_directories (${PRPT_C_DIR}) add_library(ASYNC_IF ${OPENAIR2_DIR}/UTIL/ASYNC_IF/socket_link.c @@ -740,6 +741,18 @@ if (ENB_AGENT) set(ASYNC_IF_LIB ASYNC_IF) include_directories(${OPENAIR2_DIR}/UTIL/ASYNC_IF) + add_library(ENB_AGENT + ${OPENAIR2_DIR}/ENB_APP/enb_agent_handler.c + ${OPENAIR2_DIR}/ENB_APP/enb_agent_common.c + ${OPENAIR2_DIR}/ENB_APP/enb_agent_mac.c + ${OPENAIR2_DIR}/ENB_APP/enb_agent.c + ) + set(ENB_AGENT_LIB ENB_AGENT) + #include_directories(${OPENAIR2_DIR}/ENB_APP) + + set(PROTOBUF_LIB "protobuf-c") + + #set(PROTOBUF_LIB "protobuf") #for Cpp endif() @@ -1647,15 +1660,16 @@ add_executable(oaisim_nos1 target_include_directories(oaisim_nos1 PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim_nos1 -Wl,--start-group - RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} + RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} -Wl,--end-group ) target_link_libraries (oaisim_nos1 ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) target_link_libraries (oaisim_nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib} - ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES}) + ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES} ${PROTOBUF_LIB}) #Force link with forms, regardless XFORMS option target_link_libraries (oaisim_nos1 forms) +#message("protobuflib is ${PROTOBUF_LIB}") # Unitary tests for each piece of L1: example, mbmssim is MBMS L1 simulator ##################################### diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index a905510150..7bdf252352 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -48,7 +48,7 @@ set ( NEW_FFT True ) set ( NO_RRM True ) set ( OAI_EMU True ) set ( OAISIM True ) -set ( OAI_NW_DRIVER_TYPE_ETHERNET True ) +set ( OAI_NW_DRIVER_TYPE_ETHERNET False ) set ( OAI_NW_DRIVER_USE_NETLINK True ) set ( OPENAIR1 True ) set ( OPENAIR2 True ) diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index f25613d86d..b2319c8220 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -3,7 +3,7 @@ package protocol; message prp_header { optional uint32 version = 1; optional uint32 type = 2; - optional uint32 xid = 3; + optional uint32 xid = 4; } enum prp_type { @@ -16,3 +16,4 @@ enum prp_type { PRPT_STATS_REQUEST = 3; PRPT_STATS_REPLY = 4; } + diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index e631762946..363592d6e3 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -1,10 +1,12 @@ +//'syntax = "proto2";' package protocol; import "stats_messages.proto"; import "header.proto"; message progran_message { - oneof msg { + required progran_direction msg_dir = 100; + oneof msg { prp_hello hello_msg = 1; prp_echo_request echo_request_msg = 2; prp_echo_reply echo_reply_msg = 3; @@ -13,6 +15,32 @@ message progran_message { } } +enum progran_direction { + //option allow_alias = true; + NOT_SET = 0; + INITIATING_MESSAGE = 1; + SUCCESSFUL_OUTCOME=2; + UNSUCCESSFUL_OUTCOME=3; +} + +enum progran_err { + option allow_alias = true; + // message errors + NO_ERR = 0; + MSG_DEQUEUING = -1; + MSG_ENQUEUING = -2; + MSG_DECODING = -3; + MSG_ENCODING = -4; + MSG_BUILD = -5; + MSG_NOT_SUPPORTED = -6; + MSG_NOT_HANDLED = -7; + MSG_NOT_VALIDATED = -8; + MSG_OUT_DATED = -9; + + + // other erros + UNEXPECTED = -100; +} // // Maintenance and discovery messages @@ -34,7 +62,6 @@ message prp_echo_reply { } - // // Statistics request and reply message // diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c new file mode 100644 index 0000000000..c9a00ae9ce --- /dev/null +++ b/openair2/ENB_APP/enb_agent.c @@ -0,0 +1,202 @@ +/******************************************************************************* + 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 + * \brief + * \author + * \date 2016 + * \version 0.1 + */ + + +#include +#include +#include +#include +#include + +#include "enb_agent_common.h" +#include "link_manager.h" +#include "log.h" +#include "enb_agent.h" + +typedef uint8_t xid_t; + +// tx and rx shared context +typedef struct { + message_queue_t *tx_mq; + message_queue_t *rx_mq; + xid_t tx_xid; + xid_t rx_xid; +} msg_context_t; +msg_context_t shared_ctxt; + +void *send_thread(void *arg); +void *receive_thread(void *arg); +pthread_t new_thread(void *(*f)(void *), void *b); + +void *send_thread(void *arg) { + + msg_context_t *d = arg; + void *data; + int size; + int priority; + + + while (1) { + // need logic for the timer, and + usleep(10); + if (message_put(d->tx_mq, data, size, priority)) goto error; + } + + return NULL; + +error: + printf("receive_thread: there was an error\n"); + return NULL; +} + +void *receive_thread(void *arg) { + + msg_context_t *d = arg; + void *data; + int size; + int priority; + err_code_t err_code; + + Protocol__ProgranMessage *msg; + + while (1) { + if (message_get(d->rx_mq, &data, &size, &priority)){ + err_code = PROTOCOL__PROGRAN_ERR__MSG_DEQUEUING; + goto error; + } + LOG_D(ENB_APP,"received message with size %d\n", size); + + + msg=enb_agent_handle_message(d->rx_xid, data, size); + + free(data); + + d->rx_xid = ((d->rx_xid)+1)%4; + d->tx_xid = d->rx_xid; + + // check if there is something to send back to the controller + if (msg != NULL){ + data=enb_agent_send_message(d->tx_xid,msg,&size); + + if (message_put(d->tx_mq, data, size, priority)){ + err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + goto error; + } + LOG_D(ENB_APP,"sent message with size %d\n", size); + } + + } + + return NULL; + +error: + printf("receive_thread: error %d occured\n",err_code); + return NULL; +} + + +/* utility function to create a thread */ +pthread_t new_thread(void *(*f)(void *), void *b) { + pthread_t t; + pthread_attr_t att; + + if (pthread_attr_init(&att)){ + fprintf(stderr, "pthread_attr_init err\n"); + exit(1); + } + if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) { + fprintf(stderr, "pthread_attr_setdetachstate err\n"); + exit(1); + } + if (pthread_create(&t, &att, f, b)) { + fprintf(stderr, "pthread_create err\n"); + exit(1); + } + if (pthread_attr_destroy(&att)) { + fprintf(stderr, "pthread_attr_destroy err\n"); + exit(1); + } + + return t; +} + +int enb_agent_start(){ + + socket_link_t *link; + message_queue_t *send_queue; + message_queue_t *receive_queue; + link_manager_t *manager; + + LOG_I(ENB_APP,"starting enb agent client\n"); + + link = new_link_client("127.0.0.1", 2210); + if (link == NULL) goto error; + + send_queue = new_message_queue(); + if (send_queue == NULL) goto error; + receive_queue = new_message_queue(); + if (receive_queue == NULL) goto error; + + manager = create_link_manager(send_queue, receive_queue, link); + if (manager == NULL) goto error; + + + memset(&shared_ctxt, 0, sizeof(msg_context_t)); + + shared_ctxt.tx_mq = send_queue; + shared_ctxt.rx_mq = receive_queue; + + new_thread(receive_thread, &shared_ctxt); + + // new_thread(send_thread, &shared_ctxt); + + // while (1) pause(); + + printf("client ends\n"); + return 0; + +error: + printf("there was an error\n"); + return 1; + +} + + + +int enb_agent_stop(){ + + +} diff --git a/openair2/ENB_APP/enb_agent.h b/openair2/ENB_APP/enb_agent.h new file mode 100644 index 0000000000..89d1d9e0c2 --- /dev/null +++ b/openair2/ENB_APP/enb_agent.h @@ -0,0 +1,47 @@ + +/******************************************************************************* + 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 + * \brief + * \author + * \date 2016 + * \version 0.1 + */ + +#ifndef ENB_AGENT_H_ +#define ENB_AGENT_H_ + + +int enb_agent_start(); + +int enb_agent_stop(); + + +#endif diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c new file mode 100644 index 0000000000..d71a5a6acc --- /dev/null +++ b/openair2/ENB_APP/enb_agent_common.c @@ -0,0 +1,246 @@ +/******************************************************************************* + 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 + * \brief + * \author + * \date 2016 + * \version 0.1 + */ + + +#include "enb_agent_common.h" +#include "log.h" + + +int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int *size) { + + *size = protocol__progran_message__get_packed_size(msg); + + *buf = malloc(*size); + if (buf == NULL) + goto error; + + protocol__progran_message__pack(msg, *buf); + + return 0; + + error: + LOG_E(ENB_APP, "an error occured\n"); // change the com + return -1; +} + + + +/* We assume that the buffer size is equal to the message size. + Should be chekced durint Tx/Rx */ +int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage **msg) { + *msg = protocol__progran_message__unpack(NULL, size, data); + if (*msg == NULL) + goto error; + + return 0; + + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + + + + + +int prp_create_header(uint32_t xid, Protocol__PrpType type, Protocol__PrpHeader **header) { + + *header = malloc(sizeof(Protocol__PrpHeader)); + if(*header == NULL) + goto error; + + protocol__prp_header__init(*header); + (*header)->version = PROGRAN_VERSION; + (*header)->has_version = 1; + // check if the type is set + (*header)->type = type; + (*header)->has_type = 1; + (*header)->xid = xid; + (*header)->has_xid = 1; + return 0; + + error: + LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + + +int enb_agent_hello(uint32_t xid, Protocol__ProgranMessage **msg) { + + Protocol__PrpHeader *header; + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_HELLO, &header) != 0) + goto error; + + Protocol__PrpHello *hello_msg; + hello_msg = malloc(sizeof(Protocol__PrpHello)); + if(hello_msg == NULL) + goto error; + protocol__prp_hello__init(hello_msg); + hello_msg->header = header; + + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if(*msg == NULL) + goto error; + + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + (*msg)->hello_msg = hello_msg; + return 0; + + error: + if(header != NULL) + free(header); + if(hello_msg != NULL) + free(hello_msg); + if(*msg != NULL) + free(*msg); + LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + + +int enb_agent_destroy_hello_message(Protocol__ProgranMessage *msg) { + + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG) + goto error; + + free(msg->hello_msg->header); + free(msg->hello_msg); + free(msg); + return 0; + + error: + LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + + +int enb_agent_echo_request(uint32_t xid, Protocol__ProgranMessage **msg) { + Protocol__PrpHeader *header; + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REQUEST, &header) != 0) + goto error; + + Protocol__PrpEchoRequest *echo_request_msg; + echo_request_msg = malloc(sizeof(Protocol__PrpEchoRequest)); + if(echo_request_msg == NULL) + goto error; + protocol__prp_echo_request__init(echo_request_msg); + echo_request_msg->header = header; + + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if(*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REQUEST_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + (*msg)->echo_request_msg = echo_request_msg; + return 0; + + error: + if(header != NULL) + free(header); + if(echo_request_msg != NULL) + free(echo_request_msg); + if(*msg != NULL) + free(*msg); + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + + +int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg) { + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REQUEST_MSG) + goto error; + + free(msg->echo_request_msg->header); + free(msg->echo_request_msg); + free(msg); + return 0; + + error: + LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + + + +int enb_agent_echo_reply(uint32_t xid, Protocol__ProgranMessage **msg) { + Protocol__PrpHeader *header; + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REPLY, &header) != 0) + goto error; + + Protocol__PrpEchoReply *echo_reply_msg; + echo_reply_msg = malloc(sizeof(Protocol__PrpEchoReply)); + if(echo_reply_msg == NULL) + goto error; + protocol__prp_echo_reply__init(echo_reply_msg); + echo_reply_msg->header = header; + + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if(*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + (*msg)->echo_reply_msg = echo_reply_msg; + return 0; + + error: + if(header != NULL) + free(header); + if(echo_reply_msg != NULL) + free(echo_reply_msg); + if(*msg != NULL) + free(*msg); + LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + + +int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg) { + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG) + goto error; + + free(msg->echo_reply_msg->header); + free(msg->echo_reply_msg); + free(msg); + return 0; + + error: + LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h new file mode 100644 index 0000000000..3fb0d366ac --- /dev/null +++ b/openair2/ENB_APP/enb_agent_common.h @@ -0,0 +1,88 @@ +/******************************************************************************* + 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 + * \brief + * \author + * \date 2016 + * \version 0.1 + */ + + + +#ifndef ENB_AGENT_COMMON_H_ +#define ENB_AGENT_COMMON_H_ + + +#include "header.pb-c.h" +#include "progran.pb-c.h" +#include "stats_messages.pb-c.h" +#include "stats_common.pb-c.h" + +#define PROGRAN_VERSION 0 + +typedef int (*enb_agent_message_decoded_callback)( + uint32_t xid, + Protocol__ProgranMessage **msg +); + +typedef int32_t err_code_t; + +int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int *size); +int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage **msg); + +int prp_create_header(uint32_t xid, Protocol__PrpType type, Protocol__PrpHeader **header); + +int enb_agent_hello(uint32_t xid, Protocol__ProgranMessage **msg); +int enb_agent_destroy_hello(Protocol__ProgranMessage *msg); + +int enb_agent_echo_request(uint32_t xid, Protocol__ProgranMessage **msg); +int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg); + +int enb_agent_echo_reply(uint32_t xid, Protocol__ProgranMessage **msg); +int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg); + + +Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid, + uint8_t *data, + uint32_t size); + +void * enb_agent_send_message(uint32_t xid, + Protocol__ProgranMessage *msg, + uint32_t * size); + + +#endif + + + + + + + diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c new file mode 100644 index 0000000000..2b9509f48e --- /dev/null +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -0,0 +1,133 @@ +/******************************************************************************* + 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 + * \brief + * \author + * \date 2016 + * \version 0.1 + */ + + +#include "enb_agent_common.h" +#include "enb_agent_mac.h" +#include "log.h" + +#include "assertions.h" + +enb_agent_message_decoded_callback messages_callback[][3] = { + {enb_agent_hello, enb_agent_hello,0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG*/ + {enb_agent_echo_request, enb_agent_echo_reply,0}, /**/ + {0, enb_agent_mac_reply,0}, /*stats*/ + {0,0,0}, + +}; + +static const char *enb_agent_direction2String[] = { + "", /* not_set */ + "originating message", /* originating message */ + "successfull outcome", /* successfull outcome */ + "unsuccessfull outcome", /* unsuccessfull outcome */ +}; + + +Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid, + uint8_t *data, + uint32_t size){ + + Protocol__ProgranMessage *message; + err_code_t err_code; + DevAssert(data != NULL); + + if (enb_agent_deserialize_message(data, size, &message) < 0) { + err_code= PROTOCOL__PROGRAN_ERR__MSG_DECODING; + goto error; + } + + if ((message->msg_case > sizeof(messages_callback) / (3*sizeof(enb_agent_message_decoded_callback))) || + (message->msg_dir > PROTOCOL__PROGRAN_DIRECTION__UNSUCCESSFUL_OUTCOME)){ + err_code= PROTOCOL__PROGRAN_ERR__MSG_NOT_HANDLED; + goto error; + } + + if (messages_callback[message->msg_case][message->msg_dir] == NULL) { + err_code= PROTOCOL__PROGRAN_ERR__MSG_NOT_SUPPORTED; + goto error; + + } + + err_code= ((*messages_callback[message->msg_case-1][message->msg_dir-1])(xid, &message)); + if ( err_code < 0 ){ + goto error; + } + + return message; + +error: + LOG_E(ENB_APP,"errno %d occured\n",err_code); + return err_code; + +} + + + +void * enb_agent_send_message(uint32_t xid, + Protocol__ProgranMessage *msg, + uint32_t * size){ + + void * buffer; + err_code_t err_code = PROTOCOL__PROGRAN_ERR__NO_ERR; + + if (enb_agent_serialize_message(msg, &buffer, size) < 0 ) { + err_code = PROTOCOL__PROGRAN_ERR__MSG_ENCODING; + goto error; + } + + // free the msg --> later keep this in the data struct and just update the values + enb_agent_mac_destroy_stats_reply(msg); + + DevAssert(buffer !=NULL); + + LOG_D(ENB_APP,"Serilized the enb mac stats reply (size %d)\n", size); + + return buffer; + +error : +LOG_E(ENB_APP,"errno %d occured\n",err_code); +return NULL; + +} + + + + + + + + diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c new file mode 100644 index 0000000000..0399d53d18 --- /dev/null +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -0,0 +1,552 @@ +/******************************************************************************* + 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 + * \brief + * \author + * \date 2016 + * \version 0.1 + */ + +#include "enb_agent_mac.h" +#include "enb_agent_common.h" +#include "LAYER2/MAC/extern.h" +#include "LAYER2/RLC/rlc.h" +#include "log.h" + +int enb_agent_mac_reply(uint32_t xid, Protocol__ProgranMessage **msg){ + + void *buffer; + int size; + err_code_t err_code; + // test code + + + // Create and serialize a stats reply message. This would be done by one of the agents + // Let's assume that we want the power headroom, the pending CEs for UEs 1 & 2 and their + // DL CQI reports as well as the noise and interference for cell 1 + report_config_t report_config; + + // We set the flags indicating what kind of stats we need for each UE. Both UEs will have + // the same flags in this example + uint32_t ue_flags = 0; + // Set the power headroom flag + ue_flags |= PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PRH; + // Set the pending CEs flag + ue_flags |= PROTOCOL__PRP_UE_STATS_TYPE__PRUST_MAC_CE_BS; + // Set the DL CQI report flag + ue_flags |= PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI; + + // We do the same with the Cell flags + uint32_t c_flags = 0; + // Set the noise and interference flag + c_flags |= PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE; + + // We create the appropriate configurations + ue_report_type_t ue_configs[2]; + cc_report_type_t cell_configs[1]; + + // Create the config for UE with RNTI 1 + ue_report_type_t ue1_config; + ue1_config.ue_rnti = 1; + ue1_config.ue_report_flags = ue_flags; + + // Do the same for UE with RNTI 2 + ue_report_type_t ue2_config; + ue2_config.ue_rnti = 2; + ue2_config.ue_report_flags = ue_flags; + + // Add them to the UE list + ue_configs[0] = ue1_config; + ue_configs[1] = ue2_config; + + // Do the same for cell with id 1 + cc_report_type_t c1_config; + c1_config.cc_id = 1; + c1_config.cc_report_flags = c_flags; + + // Add them to the cell list + cell_configs[0] = c1_config; + + //Create the full report configuration + report_config.nr_ue = 2; + report_config.nr_cc = 1; + report_config.ue_report_type = ue_configs; + report_config.cc_report_type = cell_configs; + + if (enb_agent_mac_stats_reply(xid, &report_config, msg) < 0 ){ + err_code = PROTOCOL__PROGRAN_ERR__MSG_BUILD; + goto error; + } + + return 0; + + error : + LOG_E(ENB_APP, "errno %d occured\n", err_code); + return err_code; +} + +int enb_agent_mac_stats_reply(uint32_t xid, + const report_config_t *report_config, + Protocol__ProgranMessage **msg) { + Protocol__PrpHeader *header; + int i, j, k; + int cc_id = 0; + int enb_id = 0; + eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; + UE_list_t *eNB_UE_list= &eNB->UE_list; + + + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_STATS_REPLY, &header) != 0) + goto error; + + Protocol__PrpStatsReply *stats_reply_msg; + stats_reply_msg = malloc(sizeof(Protocol__PrpStatsReply)); + if (stats_reply_msg == NULL) + goto error; + protocol__prp_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; + + Protocol__PrpUeStatsReport **ue_report; + Protocol__PrpCellStatsReport **cell_report; + + + /* Allocate memory for list of UE reports */ + if (report_config->nr_ue > 0) { + ue_report = malloc(sizeof(Protocol__PrpUeStatsReport *) * 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__PrpUeStatsReport)); + protocol__prp_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__PRP_UE_STATS_TYPE__PRUST_BSR) { + //TODO: Create a report for each LCG (4 elements). See prp_ue_stats_report of + // progRAN specifications for more details + 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++; j < ue_report[i]->n_bsr) { + // Set the actual BSR for LCG j of the current UE + // NN: we need to know the cc_id here, consider the first one + elem[j] = eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].bsr_info[j]; + } + ue_report[i]->bsr = elem; + } + + /* Check flag for creation of PRH report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PRH) { + // TODO: Fill in the actual power headroom value for the RNTI + ue_report[i]->phr = 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__PRP_UE_STATS_TYPE__PRUST_RLC_BS) { + // TODO: Fill in the actual RLC buffer status reports + ue_report[i]->n_rlc_report = 1; // Set this to the number of LCs for this UE + Protocol__PrpRlcBsr ** rlc_reports; + rlc_reports = malloc(sizeof(Protocol__PrpRlcBsr) * ue_report[i]->n_rlc_report); + if (rlc_reports == NULL) + goto error; + + // Fill the buffer status report for each logical channel of the UE + // 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__PrpRlcBsr)); + if (rlc_reports[j] == NULL) + goto error; + protocol__prp_rlc_bsr__init(rlc_reports[j]); + //TODO:Set logical channel id + rlc_reports[j]->lc_id = 1; + rlc_reports[j]->has_lc_id = 1; + //TODO:Set tx queue size in bytes + rlc_reports[j]->tx_queue_size = 10; + 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 = 100; + 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 = 1; + //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 = 1; + //TODO:Set current size of the pending message in bytes + rlc_reports[j]->status_pdu_size = 100; + rlc_reports[j]->has_status_pdu_size = 1; + } + // 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 MAC CE buffer status report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_MAC_CE_BS) { + // TODO: Fill in the actual MAC CE buffer status report + ue_report[i]->pending_mac_ces = -1; /* Use as bitmap. Set one or more of the + PROTOCOL__PRP_CE_TYPE__PRPCET_ values + found in stats_common.pb-c.h. See + prp_ce_type in progRAN specification */ + ue_report[i]->has_pending_mac_ces = 1; + } + + /* Check flag for creation of DL CQI report */ + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI) { + // TODO: Fill in the actual DL CQI report for the UE based on its configuration + Protocol__PrpDlCqiReport * dl_report; + dl_report = malloc(sizeof(Protocol__PrpDlCqiReport)); + if (dl_report == NULL) + goto error; + protocol__prp_dl_cqi_report__init(dl_report); + //TODO:Set the SFN and SF of the last report held in the agent. + dl_report->sfn_sn = eNB->frame*10 + eNB->subframe; + dl_report->has_sfn_sn = 1; + //TODO:Set the number of DL CQI reports for this UE. One for each CC + dl_report->n_csi_report = 1; + //TODO:Create the actual CSI reports. + Protocol__PrpDlCsi **csi_reports; + csi_reports = malloc(sizeof(Protocol__PrpDlCsi *)); + if (csi_reports == NULL) + goto error; + for (j = 0; j < dl_report->n_csi_report; j++) { + csi_reports[j] = malloc(sizeof(Protocol__PrpDlCsi)); + if (csi_reports[j] == NULL) + goto error; + protocol__prp_dl_csi__init(csi_reports[j]); + //TODO: the servCellIndex for this report + csi_reports[j]->serv_cell_index = 0; + csi_reports[j]->has_serv_cell_index = 1; + //TODO: the rank indicator value for this cc + csi_reports[j]->ri = 1; + csi_reports[j]->has_ri = 1; + //TODO: the type of CSI report based on the configuration of the UE + //For this example we use 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 progRAN specifications + csi_reports[j]->type = PROTOCOL__PRP_CSI_TYPE__PRCSIT_P10; + csi_reports[j]->has_type = 1; + csi_reports[j]->report_case = PROTOCOL__PRP_DL_CSI__REPORT_P10CSI; + Protocol__PrpCsiP10 *csi10; + csi10 = malloc(sizeof(Protocol__PrpCsiP10)); + if (csi10 == NULL) + goto error; + protocol__prp_csi_p10__init(csi10); + //TODO: set the wideband value + // NN: this is also depends on cc_id + csi10->wb_cqi = 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; + } + //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__PRP_UE_STATS_TYPE__PRUST_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__PrpPagingBufferReport *paging_report; + paging_report = malloc(sizeof(Protocol__PrpPagingBufferReport)); + if (paging_report == NULL) + goto error; + protocol__prp_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__PrpPagingInfo **p_info; + p_info = malloc(sizeof(Protocol__PrpPagingInfo *)); + if (p_info == NULL) + goto error; + for (j = 0; j < paging_report->n_paging_info; j++) { + p_info[j] = malloc(sizeof(Protocol__PrpPagingInfo)); + if(p_info[j] == NULL) + goto error; + protocol__prp_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__PRP_UE_STATS_TYPE__PRUST_UL_CQI) { + //Fill in the full UL CQI report of the UE + Protocol__PrpUlCqiReport *full_ul_report; + full_ul_report = malloc(sizeof(Protocol__PrpUlCqiReport)); + if(full_ul_report == NULL) + goto error; + protocol__prp_ul_cqi_report__init(full_ul_report); + //TODO:Set the SFN and SF of the generated report + full_ul_report->sfn_sn = 100; + 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__PrpUlCqi **ul_report; + ul_report = malloc(sizeof(Protocol__PrpUlCqi *) * 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++; j < full_ul_report->n_cqi_meas) { + ul_report[j] = malloc(sizeof(Protocol__PrpUlCqi)); + if(ul_report[j] == NULL) + goto error; + protocol__prp_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 prp_ul_cqi_type in progRAN specification for more details + ul_report[j]->type = PROTOCOL__PRP_UL_CQI_TYPE__PRUCT_SRS; + ul_report[j]->has_type = 1; + //TODO:Set the number of SINR measurements based on the report type + //See struct prp_ul_cqi in progRAN specification for more details + ul_report[j]->n_sinr = 100; + 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; + //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; + } + + /* Allocate memory for list of cell reports */ + if (report_config->nr_cc > 0) { + cell_report = malloc(sizeof(Protocol__PrpCellStatsReport *) * 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__PrpCellStatsReport)); + if(ue_report[i] == NULL) + goto error; + protocol__prp_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; + + /* Check flag for creation of noise and interference report */ + if(report_config->cc_report_type[i].cc_report_flags & PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE) { + // TODO: Fill in the actual noise and interference report for this cell + Protocol__PrpNoiseInterferenceReport *ni_report; + ni_report = malloc(sizeof(Protocol__PrpNoiseInterferenceReport)); + if(ni_report == NULL) + goto error; + protocol__prp_noise_interference_report__init(ni_report); + // Current frame and subframe number + ni_report->sfn_sf = 0; + ni_report->has_sfn_sf = 1; + // Received interference power in dbm + ni_report->rip = 0; + ni_report->has_rip = 1; + // Thermal noise power in dbm + ni_report->tnp = 0; + ni_report->has_tnp = 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; + } + + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if(*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_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__); + return -1; +} + +int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg) { + //TODO: Need to deallocate memory for the stats reply message + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG) + goto error; + free(msg->stats_reply_msg->header); + int i, j, k; + + Protocol__PrpStatsReply *reply = msg->stats_reply_msg; + Protocol__PrpDlCqiReport *dl_report; + Protocol__PrpUlCqiReport *ul_report; + Protocol__PrpPagingBufferReport *paging_report; + + // Free the memory for the UE reports + for (i = 0; i < reply->n_ue_report; i++) { + free(reply->ue_report[i]->bsr); + for (j = 0; j < reply->ue_report[i]->n_rlc_report; j++) { + free(reply->ue_report[i]->rlc_report[j]); + } + free(reply->ue_report[i]->rlc_report); + // If DL CQI report flag was set + if (reply->ue_report[i]->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI) { + dl_report = reply->ue_report[i]->dl_cqi_report; + // Delete all CSI reports + for (j = 0; j < dl_report->n_csi_report; j++) { + //Must free memory based on the type of report + switch(dl_report->csi_report[j]->report_case) { + case PROTOCOL__PRP_DL_CSI__REPORT_P10CSI: + free(dl_report->csi_report[j]->p10csi); + break; + case PROTOCOL__PRP_DL_CSI__REPORT_P11CSI: + free(dl_report->csi_report[j]->p11csi->wb_cqi); + free(dl_report->csi_report[j]->p11csi); + break; + case PROTOCOL__PRP_DL_CSI__REPORT_P20CSI: + free(dl_report->csi_report[j]->p20csi); + break; + case PROTOCOL__PRP_DL_CSI__REPORT_P21CSI: + free(dl_report->csi_report[j]->p21csi->wb_cqi); + free(dl_report->csi_report[j]->p21csi->sb_cqi); + free(dl_report->csi_report[j]->p21csi); + break; + case PROTOCOL__PRP_DL_CSI__REPORT_A12CSI: + free(dl_report->csi_report[j]->a12csi->wb_cqi); + free(dl_report->csi_report[j]->a12csi->sb_pmi); + free(dl_report->csi_report[j]->a12csi); + break; + case PROTOCOL__PRP_DL_CSI__REPORT_A22CSI: + free(dl_report->csi_report[j]->a22csi->wb_cqi); + free(dl_report->csi_report[j]->a22csi->sb_cqi); + free(dl_report->csi_report[j]->a22csi->sb_list); + free(dl_report->csi_report[j]->a22csi); + break; + case PROTOCOL__PRP_DL_CSI__REPORT_A20CSI: + free(dl_report->csi_report[j]->a20csi->sb_list); + free(dl_report->csi_report[j]->a20csi); + break; + case PROTOCOL__PRP_DL_CSI__REPORT_A30CSI: + free(dl_report->csi_report[j]->a30csi->sb_cqi); + free(dl_report->csi_report[j]->a30csi); + break; + case PROTOCOL__PRP_DL_CSI__REPORT_A31CSI: + free(dl_report->csi_report[j]->a31csi->wb_cqi); + for (k = 0; k < dl_report->csi_report[j]->a31csi->n_sb_cqi; k++) { + free(dl_report->csi_report[j]->a31csi->sb_cqi[k]); + } + free(dl_report->csi_report[j]->a31csi->sb_cqi); + break; + } + + free(dl_report->csi_report[j]); + } + free(dl_report->csi_report); + free(dl_report); + } + // If Paging buffer report flag was set + if (reply->ue_report[i]->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PBS) { + paging_report = reply->ue_report[i]->pbr; + // Delete all paging buffer reports + for (j = 0; j < paging_report->n_paging_info; j++) { + free(paging_report->paging_info[j]); + } + free(paging_report->paging_info); + free(paging_report); + } + // If UL CQI report flag was set + if (reply->ue_report[i]->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_UL_CQI) { + ul_report = reply->ue_report[i]->ul_cqi_report; + for (j = 0; j < ul_report->n_cqi_meas; j++) { + free(ul_report->cqi_meas[j]->sinr); + free(ul_report->cqi_meas[j]); + } + free(ul_report->cqi_meas); + } + free(reply->ue_report[i]); + } + free(reply->ue_report); + + // Free memory for all Cell reports + for (i = 0; i < reply->n_cell_report; i++) { + free(reply->cell_report[i]->noise_inter_report); + free(reply->cell_report[i]); + } + free(reply->cell_report); + + free(reply); + free(msg); + return 0; + + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h new file mode 100644 index 0000000000..6d36bbb6a1 --- /dev/null +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -0,0 +1,77 @@ +/******************************************************************************* + 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 + * \brief + * \author + * \date 2016 + * \version 0.1 + */ + +#ifndef ENB_AGENT_MAC_H_ +#define ENB_AGENT_MAC_H_ + +#include "header.pb-c.h" +#include "progran.pb-c.h" +#include "stats_messages.pb-c.h" +#include "stats_common.pb-c.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 + ProgRAN 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 + ProgRAN 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; + + +int enb_agent_mac_reply(uint32_t xid, Protocol__ProgranMessage **msg); + +int enb_agent_mac_stats_reply(uint32_t xid, const report_config_t *report_config, Protocol__ProgranMessage **msg); + +int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg); + +#endif diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 70fb5ad61f..d63d895711 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -57,6 +57,10 @@ # include "gtpv1u_eNB_task.h" # endif +#if defined(ENB_AGENT_SB_IF) +# include "enb_agent.h" +#endif + extern unsigned char NB_eNB_INST; #endif @@ -310,6 +314,11 @@ void *eNB_app_task(void *args_p) configure_rrc(enb_id, enb_properties_p); } +#if defined (ENB_AGENT_SB_IF) + printf("\n start enb agent\n"); + enb_agent_start(); +#endif + # if defined(ENABLE_USE_MME) /* Try to register each eNB */ registered_enb = 0; diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index c1d4d64ef6..7d31f476ef 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -90,6 +90,11 @@ uint8_t config_smbv = 0; char smbv_ip[16]; #endif +#if defined(ENB_AGENT_SB_IF) +# include "enb_agent.h" +#endif + + #include "oaisim_functions.h" #include "oaisim.h" @@ -1332,6 +1337,10 @@ main (int argc, char **argv) smbv_write_config_from_frame_parms(smbv_fname, &PHY_vars_eNB_g[0][0]->lte_frame_parms); #endif +#if defined (ENB_AGENT_SB_IF) + enb_agent_start(); +#endif + // add events to future event list: Currently not used //oai_emulation.info.oeh_enabled = 1; if (oai_emulation.info.oeh_enabled == 1) From 915af964f42bf38f9ad0b189148bffcc932ee363 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 22 Dec 2015 17:04:18 +0200 Subject: [PATCH 037/413] Fixed top-level message field msg_dir to be optional --- openair2/ENB_APP/MESSAGES/V2/progran.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index 363592d6e3..4f989361a9 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -5,7 +5,7 @@ import "stats_messages.proto"; import "header.proto"; message progran_message { - required progran_direction msg_dir = 100; + optional progran_direction msg_dir = 100; oneof msg { prp_hello hello_msg = 1; prp_echo_request echo_request_msg = 2; From d5830ced240aa9599f7278e53f034af22cb566e5 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 22 Dec 2015 17:06:37 +0200 Subject: [PATCH 038/413] Allow only a single instance of the eNB agent --- targets/SIMU/USER/oaisim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index 7d31f476ef..f54742fb8d 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -1337,9 +1337,9 @@ main (int argc, char **argv) smbv_write_config_from_frame_parms(smbv_fname, &PHY_vars_eNB_g[0][0]->lte_frame_parms); #endif -#if defined (ENB_AGENT_SB_IF) + /* #if defined (ENB_AGENT_SB_IF) enb_agent_start(); -#endif + #endif */ // add events to future event list: Currently not used //oai_emulation.info.oeh_enabled = 1; From 4f618d617077cb5acc651193676f583bd0d4e063 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 22 Dec 2015 17:08:16 +0200 Subject: [PATCH 039/413] Fixed some bugs that would lead to segfaults and modified to support changes in protocol --- openair2/ENB_APP/enb_agent_common.c | 4 +++- openair2/ENB_APP/enb_agent_handler.c | 30 ++++++++++++++++------------ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index d71a5a6acc..132044cf1f 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -64,7 +64,7 @@ int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage *msg = protocol__progran_message__unpack(NULL, size, data); if (*msg == NULL) goto error; - + return 0; error: @@ -118,6 +118,7 @@ int enb_agent_hello(uint32_t xid, Protocol__ProgranMessage **msg) { protocol__progran_message__init(*msg); (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG; (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + (*msg)->has_msg_dir = 1; (*msg)->hello_msg = hello_msg; return 0; @@ -216,6 +217,7 @@ int enb_agent_echo_reply(uint32_t xid, Protocol__ProgranMessage **msg) { protocol__progran_message__init(*msg); (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG; (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + (*msg)->has_msg_dir = 1; (*msg)->echo_reply_msg = echo_reply_msg; return 0; diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 2b9509f48e..2457ddbfdc 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -42,10 +42,11 @@ #include "assertions.h" enb_agent_message_decoded_callback messages_callback[][3] = { - {enb_agent_hello, enb_agent_hello,0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG*/ - {enb_agent_echo_request, enb_agent_echo_reply,0}, /**/ - {0, enb_agent_mac_reply,0}, /*stats*/ - {0,0,0}, + {enb_agent_hello, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG*/ + {enb_agent_echo_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REQUEST_MSG*/ + {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG*/ //Must add handler when receiving echo reply + {enb_agent_mac_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG*/ + {0,0,0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG*/ }; @@ -61,33 +62,35 @@ Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid, uint8_t *data, uint32_t size){ - Protocol__ProgranMessage *message; + Protocol__ProgranMessage *decoded_message, *reply_message; err_code_t err_code; DevAssert(data != NULL); - if (enb_agent_deserialize_message(data, size, &message) < 0) { + if (enb_agent_deserialize_message(data, size, &decoded_message) < 0) { err_code= PROTOCOL__PROGRAN_ERR__MSG_DECODING; goto error; } - if ((message->msg_case > sizeof(messages_callback) / (3*sizeof(enb_agent_message_decoded_callback))) || - (message->msg_dir > PROTOCOL__PROGRAN_DIRECTION__UNSUCCESSFUL_OUTCOME)){ + if ((decoded_message->msg_case > sizeof(messages_callback) / (3*sizeof(enb_agent_message_decoded_callback))) || + (decoded_message->msg_dir > PROTOCOL__PROGRAN_DIRECTION__UNSUCCESSFUL_OUTCOME)){ err_code= PROTOCOL__PROGRAN_ERR__MSG_NOT_HANDLED; goto error; } - if (messages_callback[message->msg_case][message->msg_dir] == NULL) { + if (messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1] == NULL) { err_code= PROTOCOL__PROGRAN_ERR__MSG_NOT_SUPPORTED; goto error; } - err_code= ((*messages_callback[message->msg_case-1][message->msg_dir-1])(xid, &message)); + err_code= ((*messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1])(xid, &reply_message)); if ( err_code < 0 ){ goto error; } - return message; + protocol__progran_message__free_unpacked(decoded_message, NULL); + + return reply_message; error: LOG_E(ENB_APP,"errno %d occured\n",err_code); @@ -110,11 +113,12 @@ void * enb_agent_send_message(uint32_t xid, } // free the msg --> later keep this in the data struct and just update the values - enb_agent_mac_destroy_stats_reply(msg); + //TODO call proper destroy function + // enb_agent_mac_destroy_stats_reply(msg); DevAssert(buffer !=NULL); - LOG_D(ENB_APP,"Serilized the enb mac stats reply (size %d)\n", size); + LOG_D(ENB_APP,"Serilized the enb mac stats reply (size %d)\n", *size); return buffer; From 7241aa6a385d8cae566bbdde99cdd5da1e2c18b1 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 23 Dec 2015 12:17:52 +0200 Subject: [PATCH 040/413] Added support for parameters in handlers --- openair2/ENB_APP/enb_agent_common.c | 6 +++--- openair2/ENB_APP/enb_agent_common.h | 7 ++++--- openair2/ENB_APP/enb_agent_handler.c | 2 +- openair2/ENB_APP/enb_agent_mac.c | 2 +- openair2/ENB_APP/enb_agent_mac.h | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 132044cf1f..a8ac24144b 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -98,7 +98,7 @@ int prp_create_header(uint32_t xid, Protocol__PrpType type, Protocol__PrpHeader } -int enb_agent_hello(uint32_t xid, Protocol__ProgranMessage **msg) { +int enb_agent_hello(uint32_t xid, const void *params, Protocol__ProgranMessage **msg) { Protocol__PrpHeader *header; if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_HELLO, &header) != 0) @@ -150,7 +150,7 @@ int enb_agent_destroy_hello_message(Protocol__ProgranMessage *msg) { } -int enb_agent_echo_request(uint32_t xid, Protocol__ProgranMessage **msg) { +int enb_agent_echo_request(uint32_t xid, const void* params, Protocol__ProgranMessage **msg) { Protocol__PrpHeader *header; if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REQUEST, &header) != 0) goto error; @@ -199,7 +199,7 @@ int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg) { -int enb_agent_echo_reply(uint32_t xid, Protocol__ProgranMessage **msg) { +int enb_agent_echo_reply(uint32_t xid, const void *params, Protocol__ProgranMessage **msg) { Protocol__PrpHeader *header; if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REPLY, &header) != 0) goto error; diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 3fb0d366ac..5aac604c1e 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -49,6 +49,7 @@ typedef int (*enb_agent_message_decoded_callback)( uint32_t xid, + const void *params, Protocol__ProgranMessage **msg ); @@ -59,13 +60,13 @@ int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage int prp_create_header(uint32_t xid, Protocol__PrpType type, Protocol__PrpHeader **header); -int enb_agent_hello(uint32_t xid, Protocol__ProgranMessage **msg); +int enb_agent_hello(uint32_t xid, const void *params, Protocol__ProgranMessage **msg); int enb_agent_destroy_hello(Protocol__ProgranMessage *msg); -int enb_agent_echo_request(uint32_t xid, Protocol__ProgranMessage **msg); +int enb_agent_echo_request(uint32_t xid, const void *params, Protocol__ProgranMessage **msg); int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg); -int enb_agent_echo_reply(uint32_t xid, Protocol__ProgranMessage **msg); +int enb_agent_echo_reply(uint32_t xid, const void *params, Protocol__ProgranMessage **msg); int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg); diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 2457ddbfdc..dd39a7315a 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -83,7 +83,7 @@ Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid, } - err_code= ((*messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1])(xid, &reply_message)); + err_code= ((*messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1])(xid, (void *) decoded_message, &reply_message)); if ( err_code < 0 ){ goto error; } diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 0399d53d18..4b299ca919 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -40,7 +40,7 @@ #include "LAYER2/RLC/rlc.h" #include "log.h" -int enb_agent_mac_reply(uint32_t xid, Protocol__ProgranMessage **msg){ +int enb_agent_mac_reply(uint32_t xid, const void *params, Protocol__ProgranMessage **msg){ void *buffer; int size; diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index 6d36bbb6a1..590570630e 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -68,7 +68,7 @@ typedef struct { } report_config_t; -int enb_agent_mac_reply(uint32_t xid, Protocol__ProgranMessage **msg); +int enb_agent_mac_reply(uint32_t xid, const void *params, Protocol__ProgranMessage **msg); int enb_agent_mac_stats_reply(uint32_t xid, const report_config_t *report_config, Protocol__ProgranMessage **msg); From 0bea0aafc44c5fdb413229e4625906d8e00afcdb Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 23 Dec 2015 15:29:28 +0200 Subject: [PATCH 041/413] Restructured statistics handler to consider the request message parameters --- openair2/ENB_APP/enb_agent_handler.c | 2 +- openair2/ENB_APP/enb_agent_mac.c | 148 ++++++++++++++++++--------- openair2/ENB_APP/enb_agent_mac.h | 2 +- 3 files changed, 104 insertions(+), 48 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index dd39a7315a..9a37d01fc1 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -45,7 +45,7 @@ enb_agent_message_decoded_callback messages_callback[][3] = { {enb_agent_hello, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG*/ {enb_agent_echo_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REQUEST_MSG*/ {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG*/ //Must add handler when receiving echo reply - {enb_agent_mac_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG*/ + {enb_agent_mac_handle_stats, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG*/ {0,0,0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG*/ }; diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 4b299ca919..e1c465105a 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -40,71 +40,127 @@ #include "LAYER2/RLC/rlc.h" #include "log.h" -int enb_agent_mac_reply(uint32_t xid, const void *params, Protocol__ProgranMessage **msg){ +int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__ProgranMessage **msg){ + // TODO: Must deal with sanitization of input + // TODO: Must check if RNTIs and cell ids of the request actually exist + + int i; void *buffer; int size; err_code_t err_code; - // test code + + //TODO: We do not deal with multiple CCs at the moment and eNB id is 0 + int cc_id = 0; + int enb_id = 0; + eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; + UE_list_t *eNB_UE_list= &eNB->UE_list; - // Create and serialize a stats reply message. This would be done by one of the agents - // Let's assume that we want the power headroom, the pending CEs for UEs 1 & 2 and their - // DL CQI reports as well as the noise and interference for cell 1 report_config_t report_config; - // We set the flags indicating what kind of stats we need for each UE. Both UEs will have - // the same flags in this example uint32_t ue_flags = 0; - // Set the power headroom flag - ue_flags |= PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PRH; - // Set the pending CEs flag - ue_flags |= PROTOCOL__PRP_UE_STATS_TYPE__PRUST_MAC_CE_BS; - // Set the DL CQI report flag - ue_flags |= PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI; - - // We do the same with the Cell flags uint32_t c_flags = 0; - // Set the noise and interference flag - c_flags |= PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE; - // We create the appropriate configurations - ue_report_type_t ue_configs[2]; - cc_report_type_t cell_configs[1]; + Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; - // Create the config for UE with RNTI 1 - ue_report_type_t ue1_config; - ue1_config.ue_rnti = 1; - ue1_config.ue_report_flags = ue_flags; + Protocol__PrpStatsRequest *stats_req = input->stats_request_msg; - // Do the same for UE with RNTI 2 - ue_report_type_t ue2_config; - ue2_config.ue_rnti = 2; - ue2_config.ue_report_flags = ue_flags; - - // Add them to the UE list - ue_configs[0] = ue1_config; - ue_configs[1] = ue2_config; - - // Do the same for cell with id 1 - cc_report_type_t c1_config; - c1_config.cc_id = 1; - c1_config.cc_report_flags = c_flags; - - // Add them to the cell list - cell_configs[0] = c1_config; - - //Create the full report configuration - report_config.nr_ue = 2; - report_config.nr_cc = 1; - report_config.ue_report_type = ue_configs; - report_config.cc_report_type = cell_configs; + // Check the type of request that is made + switch(stats_req->body_case) { + case PROTOCOL__PRP_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ; + Protocol__PrpCompleteStatsRequest *comp_req = stats_req->complete_stats_request; + if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_PERIODICAL) { + //TODO: Must create a periodic report. Implement once the + // timer functionality is supported + return -1; + } else if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_CONTINUOUS) { + //TODO: Must create an event based report mechanism + return -1; + } else if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_OFF) { + //TODO: Must implement to deactivate the event based reporting + } else { //One-off 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 = 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 = 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; + } + } + break; + case PROTOCOL__PRP_STATS_REQUEST__BODY_CELL_STATS_REQUEST:; + Protocol__PrpCellStatsRequest *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__PRP_STATS_REQUEST__BODY_UE_STATS_REQUEST:; + Protocol__PrpUeStatsRequest *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 (enb_agent_mac_stats_reply(xid, &report_config, msg) < 0 ){ err_code = PROTOCOL__PROGRAN_ERR__MSG_BUILD; goto error; } + free(report_config.ue_report_type); + free(report_config.cc_report_type); + return 0; error : diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index 590570630e..e22253cf27 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -68,7 +68,7 @@ typedef struct { } report_config_t; -int enb_agent_mac_reply(uint32_t xid, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__ProgranMessage **msg); int enb_agent_mac_stats_reply(uint32_t xid, const report_config_t *report_config, Protocol__ProgranMessage **msg); From b9cf840a10c6212cd75d0a422a4f1094258ac700 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 28 Dec 2015 15:25:27 +0200 Subject: [PATCH 042/413] Created callback mechanism for destruction of protocol messages sent by the agent --- openair2/ENB_APP/enb_agent_common.c | 2 +- openair2/ENB_APP/enb_agent_common.h | 4 ++++ openair2/ENB_APP/enb_agent_handler.c | 11 ++++++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index a8ac24144b..848c10b6fa 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -134,7 +134,7 @@ int enb_agent_hello(uint32_t xid, const void *params, Protocol__ProgranMessage * } -int enb_agent_destroy_hello_message(Protocol__ProgranMessage *msg) { +int enb_agent_destroy_hello(Protocol__ProgranMessage *msg) { if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG) goto error; diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 5aac604c1e..3bb6596f2e 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -53,6 +53,10 @@ typedef int (*enb_agent_message_decoded_callback)( Protocol__ProgranMessage **msg ); +typedef int (*enb_agent_message_destruction_callback)( + Protocol__ProgranMessage *msg +); + typedef int32_t err_code_t; int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int *size); diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 9a37d01fc1..5049e669e9 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -50,6 +50,15 @@ enb_agent_message_decoded_callback messages_callback[][3] = { }; +enb_agent_message_destruction_callback message_destruction_callback[] = { + enb_agent_destroy_hello, + enb_agent_destroy_echo_request, + enb_agent_destroy_echo_reply, + 0, /*No stats request message is created in the agent. No need for a callback*/ + enb_agent_mac_destroy_stats_reply, + +}; + static const char *enb_agent_direction2String[] = { "", /* not_set */ "originating message", /* originating message */ @@ -114,7 +123,7 @@ void * enb_agent_send_message(uint32_t xid, // free the msg --> later keep this in the data struct and just update the values //TODO call proper destroy function - // enb_agent_mac_destroy_stats_reply(msg); + err_code = ((*message_destruction_callback[msg->msg_case-1])(msg)); DevAssert(buffer !=NULL); From e5e58ec2f47a4b0e429e39e5042aadc2cdae785e Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 29 Dec 2015 15:43:42 +0200 Subject: [PATCH 043/413] Fixed mac stats handler for periodic and continuous stats updates --- openair2/ENB_APP/enb_agent_mac.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index e1c465105a..3c188881fb 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -73,12 +73,16 @@ int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__Progr if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_PERIODICAL) { //TODO: Must create a periodic report. Implement once the // timer functionality is supported - return -1; + *msg = NULL; + return 0; } else if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_CONTINUOUS) { //TODO: Must create an event based report mechanism - return -1; + *msg = NULL; + return 0; } else if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_OFF) { //TODO: Must implement to deactivate the event based reporting + *msg = NULL; + return 0; } else { //One-off reporting //Set the proper flags ue_flags = comp_req->ue_report_flags; From e42dd369679f05bc39f66ffd61c020eb8d52de06 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Fri, 1 Jan 2016 20:05:15 +0100 Subject: [PATCH 044/413] update the itti timer --- common/utils/itti/timer.c | 6 +++++- maketags | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/common/utils/itti/timer.c b/common/utils/itti/timer.c index 40e8791022..864ab16746 100644 --- a/common/utils/itti/timer.c +++ b/common/utils/itti/timer.c @@ -96,6 +96,8 @@ int timer_handle_signal(siginfo_t *info) // LG: To many traces for msc timer: // TMR_DEBUG("Timer with id 0x%lx has expired\n", (long)timer_p->timer); +#if defined(ENABLE_ITTI) + task_id = timer_p->task_id; instance = timer_p->instance; message_p = itti_alloc_new_message(TASK_TIMER, TIMER_HAS_EXPIRED); @@ -104,6 +106,7 @@ int timer_handle_signal(siginfo_t *info) timer_expired_p->timer_id = (long)timer_p->timer; timer_expired_p->arg = timer_p->timer_arg; +#endif /* Timer is a one shot timer, remove it */ if (timer_p->type == TIMER_ONE_SHOT) { @@ -120,13 +123,14 @@ int timer_handle_signal(siginfo_t *info) TMR_DEBUG("Failed to delete timer 0x%lx\n", (long)timer_p->timer); } } - +#ifdefined ENABLE_ITTI /* Notify task of timer expiry */ if (itti_send_msg_to_task(task_id, instance, message_p) < 0) { TMR_DEBUG("Failed to send msg TIMER_HAS_EXPIRED to task %u\n", task_id); free(message_p); return -1; } +#endif return 0; } diff --git a/maketags b/maketags index ec283c8bec..53bc1c12d0 100755 --- a/maketags +++ b/maketags @@ -1,3 +1,3 @@ #!/bin/sh echo "building ctags for openair1 and openair2 ..." -ctags -e -R --exclude=openair1/DOCS/ --exclude=openair2/DOCS/ --exclude=openair2/RRC/CELLULAR/ --exclude=openair2/NAS/DRIVER/CELLULAR/ --exclude=openair2/SIMULATION/ --exclude=targets/DOCS/ --exclude=targets/PROJECTS/ openair1 openair2 targets +ctags -e -R --exclude=openair1/DOCS/ --exclude=openair2/DOCS/ --exclude=openair2/RRC/CELLULAR/ --exclude=openair2/NAS/DRIVER/CELLULAR/ --exclude=openair2/SIMULATION/ --exclude=targets/DOCS/ --exclude=targets/PROJECTS/ openair1 openair2 openair3 targets common From 1f213b0b8e24bcc7498534b965b952173a5e8e3e Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Tue, 5 Jan 2016 11:33:40 +0100 Subject: [PATCH 045/413] * add options to enb configuration file for the enb agent * add timer api for the periodic and oneshot operations * create enb agent task --- common/utils/itti/timer.c | 16 +- openair2/COMMON/tasks_def.h | 2 + openair2/ENB_APP/MESSAGES/V2/progran.proto | 2 +- openair2/ENB_APP/enb_agent.c | 247 +++++++++++---- openair2/ENB_APP/enb_agent.h | 13 +- openair2/ENB_APP/enb_agent_common.c | 284 +++++++++++++++++- openair2/ENB_APP/enb_agent_common.h | 165 +++++++++- openair2/ENB_APP/enb_agent_defs.h | 142 +++++++++ openair2/ENB_APP/enb_agent_handler.c | 58 ++-- openair2/ENB_APP/enb_agent_mac.c | 45 ++- openair2/ENB_APP/enb_agent_mac.h | 12 +- openair2/ENB_APP/enb_app.c | 7 +- openair2/ENB_APP/enb_config.c | 43 +++ openair2/ENB_APP/enb_config.h | 3 + openair2/UTIL/LOG/log.c | 8 + openair2/UTIL/LOG/log.h | 1 + .../enb.band7.agent.oaisim.local_no_mme.conf | 153 ++++++++++ 17 files changed, 1059 insertions(+), 142 deletions(-) create mode 100644 openair2/ENB_APP/enb_agent_defs.h create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf diff --git a/common/utils/itti/timer.c b/common/utils/itti/timer.c index 864ab16746..683efd1279 100644 --- a/common/utils/itti/timer.c +++ b/common/utils/itti/timer.c @@ -94,9 +94,8 @@ int timer_handle_signal(siginfo_t *info) timer_p = (struct timer_elm_s *)info->si_ptr; // LG: To many traces for msc timer: - // TMR_DEBUG("Timer with id 0x%lx has expired\n", (long)timer_p->timer); - -#if defined(ENABLE_ITTI) + TMR_DEBUG("Timer with id 0x%lx has expired\n", (long)timer_p->timer); + printf("Timer with id 0x%lx has expired\n", (long)timer_p->timer); task_id = timer_p->task_id; instance = timer_p->instance; @@ -106,7 +105,6 @@ int timer_handle_signal(siginfo_t *info) timer_expired_p->timer_id = (long)timer_p->timer; timer_expired_p->arg = timer_p->timer_arg; -#endif /* Timer is a one shot timer, remove it */ if (timer_p->type == TIMER_ONE_SHOT) { @@ -123,13 +121,16 @@ int timer_handle_signal(siginfo_t *info) TMR_DEBUG("Failed to delete timer 0x%lx\n", (long)timer_p->timer); } } -#ifdefined ENABLE_ITTI + /* Notify task of timer expiry */ if (itti_send_msg_to_task(task_id, instance, message_p) < 0) { TMR_DEBUG("Failed to send msg TIMER_HAS_EXPIRED to task %u\n", task_id); free(message_p); return -1; } + +#if defined(ENB_AGENT_SB_IF) + #endif return 0; @@ -209,6 +210,11 @@ int timer_setup( type == TIMER_PERIODIC ? "periodic" : "single shot", *timer_id, interval_sec, interval_us); + printf("Requesting new %s timer with id 0x%lx that expires within " + "%d sec and %d usec\n", + type == TIMER_PERIODIC ? "periodic" : "single shot", + *timer_id, interval_sec, interval_us); + timer_p->timer = timer; /* Lock the queue and insert the timer at the tail */ diff --git a/openair2/COMMON/tasks_def.h b/openair2/COMMON/tasks_def.h index 5e0f8bd211..6cd74c3aed 100644 --- a/openair2/COMMON/tasks_def.h +++ b/openair2/COMMON/tasks_def.h @@ -63,6 +63,8 @@ TASK_DEF(TASK_X2AP, TASK_PRIORITY_MED, 200) TASK_DEF(TASK_SCTP, TASK_PRIORITY_MED, 200) /// eNB APP task TASK_DEF(TASK_ENB_APP, TASK_PRIORITY_MED, 200) +/// eNB Agent task +TASK_DEF(TASK_ENB_AGENT, TASK_PRIORITY_MED, 200) // UE tasks and sub-tasks: //// Layer 2 and Layer 1 sub-tasks diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index 4f989361a9..995cd6861b 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -37,7 +37,7 @@ enum progran_err { MSG_NOT_VALIDATED = -8; MSG_OUT_DATED = -9; - + // other erros UNEXPECTED = -100; } diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index c9a00ae9ce..7003a2c638 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -27,43 +27,82 @@ *******************************************************************************/ -/*! \file - * \brief - * \author +/*! \file enb_agent.h + * \brief top level enb agent receive thread and itti task + * \author Navid Nikaein and Xenofon Foukas * \date 2016 * \version 0.1 */ - -#include -#include -#include -#include -#include - #include "enb_agent_common.h" -#include "link_manager.h" #include "log.h" #include "enb_agent.h" -typedef uint8_t xid_t; +#include "assertions.h" -// tx and rx shared context -typedef struct { - message_queue_t *tx_mq; - message_queue_t *rx_mq; - xid_t tx_xid; - xid_t rx_xid; -} msg_context_t; -msg_context_t shared_ctxt; -void *send_thread(void *arg); -void *receive_thread(void *arg); +enb_agent_instance_t enb_agent[NUM_MAX_ENB_AGENT]; +msg_context_t shared_ctxt[NUM_MAX_ENB_AGENT]; +/* this could also go into enb_agent struct*/ +enb_agent_info_t enb_agent_info; + +char in_ip[40]; +static uint16_t in_port; + +//void *send_thread(void *args); +void *receive_thread(void *args); pthread_t new_thread(void *(*f)(void *), void *b); +err_code_t enb_agent_timeout(void* args); -void *send_thread(void *arg) { +/* + * enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller + * and can interact with other itti tasks +*/ +void *enb_agent_task(void *args){ - msg_context_t *d = arg; + MessageDef *msg_p = NULL; + const char *msg_name = NULL; + instance_t instance; + int result; + + + itti_mark_task_ready(TASK_ENB_AGENT); + + do { + // Wait for a message + itti_receive_msg (TASK_ENB_AGENT, &msg_p); + DevAssert(msg_p != NULL); + msg_name = ITTI_MSG_NAME (msg_p); + instance = ITTI_MSG_INSTANCE (msg_p); + + switch (ITTI_MSG_ID(msg_p)) { + case TERMINATE_MESSAGE: + itti_exit_task (); + break; + + case MESSAGE_TEST: + LOG_I(ENB_AGENT, "Received %s\n", ITTI_MSG_NAME(msg_p)); + break; + + case TIMER_HAS_EXPIRED: + enb_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, &msg_p->ittiMsg.timer_has_expired.arg); + break; + + default: + LOG_E(ENB_AGENT, "Received unexpected message %s\n", msg_name); + break; + } + + result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } while (1); + + return NULL; +} +/* +void *send_thread(void *args) { + + msg_context_t *d = args; void *data; int size; int priority; @@ -81,10 +120,10 @@ error: printf("receive_thread: there was an error\n"); return NULL; } +*/ +void *receive_thread(void *args) { -void *receive_thread(void *arg) { - - msg_context_t *d = arg; + msg_context_t *d = args; void *data; int size; int priority; @@ -97,10 +136,10 @@ void *receive_thread(void *arg) { err_code = PROTOCOL__PROGRAN_ERR__MSG_DEQUEUING; goto error; } - LOG_D(ENB_APP,"received message with size %d\n", size); + LOG_D(ENB_AGENT,"received message with size %d\n", size); - msg=enb_agent_handle_message(d->rx_xid, data, size); + msg=enb_agent_handle_message(d->mod_id, d->rx_xid, data, size); free(data); @@ -115,7 +154,7 @@ void *receive_thread(void *arg) { err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; goto error; } - LOG_D(ENB_APP,"sent message with size %d\n", size); + LOG_D(ENB_AGENT,"sent message with size %d\n", size); } } @@ -123,7 +162,7 @@ void *receive_thread(void *arg) { return NULL; error: - printf("receive_thread: error %d occured\n",err_code); + LOG_E(ENB_AGENT,"receive_thread: error %d occured\n",err_code); return NULL; } @@ -153,50 +192,146 @@ pthread_t new_thread(void *(*f)(void *), void *b) { return t; } -int enb_agent_start(){ +int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ - socket_link_t *link; - message_queue_t *send_queue; - message_queue_t *receive_queue; - link_manager_t *manager; + // + set_enb_vars(mod_id, RAN_LTE_OAI); + enb_agent[mod_id].mod_id = mod_id; + enb_agent_info.nb_modules+=1; + + /* + * check the configuration + */ + if (enb_properties->properties[mod_id]->enb_agent_ipv4_address != NULL) { + strncpy(in_ip, enb_properties->properties[mod_id]->enb_agent_ipv4_address, sizeof(in_ip) ); + in_ip[sizeof(in_ip) - 1] = 0; // terminate string + } else { + strcpy(in_ip, DEFAULT_ENB_AGENT_IPv4_ADDRESS ); + } + + if (enb_properties->properties[mod_id]->enb_agent_port != 0 ) { + in_port = enb_properties->properties[mod_id]->enb_agent_port; + } else { + in_port = DEFAULT_ENB_AGENT_PORT ; + } + LOG_I(ENB_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n", + enb_agent[mod_id].mod_id, + in_ip, + in_port); - LOG_I(ENB_APP,"starting enb agent client\n"); - - link = new_link_client("127.0.0.1", 2210); - if (link == NULL) goto error; - - send_queue = new_message_queue(); - if (send_queue == NULL) goto error; - receive_queue = new_message_queue(); - if (receive_queue == NULL) goto error; - - manager = create_link_manager(send_queue, receive_queue, link); - if (manager == NULL) goto error; + //#define TEST_TIMER 0 +#if !defined TEST_TIMER + /* + * create a socket + */ + enb_agent[mod_id].link = new_link_client(in_ip, in_port); + if (enb_agent[mod_id].link == NULL) goto error; + + LOG_I(ENB_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n", + enb_agent[mod_id].mod_id, + in_ip, + in_port); + /* + * create a message queue + */ + + enb_agent[mod_id].send_queue = new_message_queue(); + if (enb_agent[mod_id].send_queue == NULL) goto error; + enb_agent[mod_id].receive_queue = new_message_queue(); + if (enb_agent[mod_id].receive_queue == NULL) goto error; + + /* + * create a link manager + */ + + enb_agent[mod_id].manager = create_link_manager(enb_agent[mod_id].send_queue, enb_agent[mod_id].receive_queue, enb_agent[mod_id].link); + if (enb_agent[mod_id].manager == NULL) goto error; memset(&shared_ctxt, 0, sizeof(msg_context_t)); - shared_ctxt.tx_mq = send_queue; - shared_ctxt.rx_mq = receive_queue; + shared_ctxt[mod_id].mod_id = mod_id; + shared_ctxt[mod_id].tx_mq = enb_agent[mod_id].send_queue; + shared_ctxt[mod_id].rx_mq = enb_agent[mod_id].receive_queue; - new_thread(receive_thread, &shared_ctxt); + /* + * start the enb agent rx thread + */ + new_thread(receive_thread, &shared_ctxt[mod_id]); + +#endif + + /* + * initilize a timer + */ + + enb_agent_init_timer(); + + + + /* + * start the enb agent task for tx and interaction with the underlying network function + */ + + if (itti_create_task (TASK_ENB_AGENT, enb_agent_task, NULL) < 0) { + LOG_E(ENB_AGENT, "Create task for eNB Agent failed\n"); + return -1; + } + + +#ifdef TEST_TIMER + long timer_id=0; + enb_agent_timer_args_t timer_args; + memset (&timer_args, 0, sizeof(enb_agent_timer_args_t)); + timer_args.mod_id = mod_id; + timer_args.cc_actions= ENB_AGENT_ACTION_APPLY; + timer_args.cc_report_flags = PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE; + timer_args.ue_actions = ENB_AGENT_ACTION_SEND; + timer_args.ue_report_flags = PROTOCOL__PRP_UE_STATS_TYPE__PRUST_BSR | PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI; + enb_agent_create_timer(1, 0, ENB_AGENT_DEFAULT, mod_id, ENB_AGENT_TIMER_TYPE_PERIODIC, enb_agent_timeout,(void*)&timer_args, &timer_id); +#endif + // new_thread(send_thread, &shared_ctxt); - // while (1) pause(); + //while (1) pause(); - printf("client ends\n"); + LOG_I(ENB_AGENT,"client ends\n"); return 0; error: - printf("there was an error\n"); + LOG_I(ENB_AGENT,"there was an error\n"); return 1; } -int enb_agent_stop(){ - +int enb_agent_stop(mid_t mod_id){ + + int i=0; + enb_agent_destroy_timers(); + for ( i =0; i < enb_agent_info.nb_modules; i++) { + + destroy_link_manager(enb_agent[i].manager); + + destroy_message_queue(enb_agent[i].send_queue); + destroy_message_queue(enb_agent[i].receive_queue); + + close_link(enb_agent[i].link); + } +} + + + +err_code_t enb_agent_timeout(void* args){ + + enb_agent_timer_args_t *timer_args = (enb_agent_timer_args_t *) args; + + LOG_I(ENB_AGENT, "enb_agent %d timeout\n", timer_args->mod_id); + LOG_I(ENB_AGENT, "eNB action %d ENB flags %d \n", timer_args->cc_actions,timer_args->cc_report_flags); + LOG_I(ENB_AGENT, "UE action %d UE flags %d \n", timer_args->ue_actions,timer_args->ue_report_flags); + + return 0; } diff --git a/openair2/ENB_APP/enb_agent.h b/openair2/ENB_APP/enb_agent.h index 89d1d9e0c2..1a53841d45 100644 --- a/openair2/ENB_APP/enb_agent.h +++ b/openair2/ENB_APP/enb_agent.h @@ -28,9 +28,9 @@ *******************************************************************************/ -/*! \file - * \brief - * \author +/*! \file enb_agent.h + * \brief top level enb agent + * \author Navid Nikaein and Xenofon Foukas * \date 2016 * \version 0.1 */ @@ -38,10 +38,13 @@ #ifndef ENB_AGENT_H_ #define ENB_AGENT_H_ +#include "enb_config.h" // for enb properties +#include "enb_agent_common.h" -int enb_agent_start(); +int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties); -int enb_agent_stop(); +int enb_agent_stop(mid_t mod_id); +void *enb_agent_task(void *args); #endif diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 848c10b6fa..c2653f4c85 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -27,9 +27,9 @@ *******************************************************************************/ -/*! \file - * \brief - * \author +/*! \file enb_agent_common.c + * \brief common primitives for all agents + * \author Navid Nikaein and Xenofon Foukas * \date 2016 * \version 0.1 */ @@ -39,6 +39,12 @@ #include "log.h" +void * enb[NUM_MAX_ENB_AGENT]; +void * enb_ue[NUM_MAX_ENB_AGENT]; +/* + * message primitives + */ + int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int *size) { *size = protocol__progran_message__get_packed_size(msg); @@ -52,7 +58,7 @@ int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int * return 0; error: - LOG_E(ENB_APP, "an error occured\n"); // change the com + LOG_E(ENB_AGENT, "an error occured\n"); // change the com return -1; } @@ -74,9 +80,7 @@ int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage - - -int prp_create_header(uint32_t xid, Protocol__PrpType type, Protocol__PrpHeader **header) { +int prp_create_header(xid_t xid, Protocol__PrpType type, Protocol__PrpHeader **header) { *header = malloc(sizeof(Protocol__PrpHeader)); if(*header == NULL) @@ -98,7 +102,7 @@ int prp_create_header(uint32_t xid, Protocol__PrpType type, Protocol__PrpHeader } -int enb_agent_hello(uint32_t xid, const void *params, Protocol__ProgranMessage **msg) { +int enb_agent_hello(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg) { Protocol__PrpHeader *header; if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_HELLO, &header) != 0) @@ -150,7 +154,7 @@ int enb_agent_destroy_hello(Protocol__ProgranMessage *msg) { } -int enb_agent_echo_request(uint32_t xid, const void* params, Protocol__ProgranMessage **msg) { +int enb_agent_echo_request(mid_t mod_id, xid_t xid, const void* params, Protocol__ProgranMessage **msg) { Protocol__PrpHeader *header; if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REQUEST, &header) != 0) goto error; @@ -199,7 +203,7 @@ int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg) { -int enb_agent_echo_reply(uint32_t xid, const void *params, Protocol__ProgranMessage **msg) { +int enb_agent_echo_reply(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg) { Protocol__PrpHeader *header; if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REPLY, &header) != 0) goto error; @@ -246,3 +250,263 @@ int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg) { LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; } + +/* + * get generic info from RAN + */ + +void 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; + break; + default : + goto error; + } + + return; + + error: + LOG_E(ENB_AGENT, "unknown RAN name %d\n", ran); +} + +int 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; + } + +} + +int get_num_ues (mid_t mod_id){ + + return ((UE_list_t *)enb_ue[mod_id])->num_UEs; +} + +int get_ue_crnti (mid_t mod_id, mid_t ue_id){ + + return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].crnti; +} + +int 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 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 get_ue_wcqi (mid_t mod_id, mid_t ue_id) { + + return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].dl_cqi; +} +/* + * timer primitives + */ + + +//struct enb_agent_map agent_map; + +/* The timer_id might not be the best choice for the comparison */ +int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b){ + + //if (a->timer_id) return 0; + //if (b->timer_id) return 0; + + if (a->timer_id < b->timer_id) return -1; + if (a->timer_id > b->timer_id) return 1; + + // equal timers + return 0; +} + +RB_GENERATE(enb_agent_map,enb_agent_timer_element_s, entry, enb_agent_compare_timer); + +err_code_t enb_agent_init_timer(void){ + + RB_INIT(&enb_agent_head); + + /* + struct enb_agent_timer_element_s e; + memset(&e, 0, sizeof(enb_agent_timer_element_t)); + RB_INSERT(enb_agent_map, &agent_map, &e); + */ + return PROTOCOL__PROGRAN_ERR__NO_ERR; +} + +err_code_t enb_agent_create_timer(uint32_t interval_sec, + uint32_t interval_usec, + agent_id_t agent_id, + instance_t instance, + uint32_t timer_type, + enb_agent_timer_callback_t cb, + void* timer_args, + long *timer_id){ + + struct enb_agent_timer_element_s e; +//uint32_t timer_id; + int ret=-1; + + if ((interval_sec == 0) && (interval_usec == 0 )) + return TIMER_NULL; + + if (timer_type >= ENB_AGENT_TIMER_TYPE_MAX) + return TIMER_TYPE_INVALIDE; + + if (timer_type == ENB_AGENT_TIMER_TYPE_ONESHOT){ + ret = timer_setup(interval_sec, + interval_usec, + TASK_ENB_AGENT, + instance, + TIMER_ONE_SHOT, + timer_args, + timer_id); + + e.type = TIMER_ONE_SHOT; + } + else if (timer_type == ENB_AGENT_TIMER_TYPE_PERIODIC ){ + ret = timer_setup(interval_sec, + interval_usec, + TASK_ENB_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 = ENB_AGENT_TIMER_STATE_ACTIVE; + e.timer_id = *timer_id; + e.timer_args = timer_args; + e.cb = cb; + + LOG_I(ENB_AGENT,"created a timer with id 0x%lx for agent %d, instance %d \n", + e.timer_id, e.agent_id, e.instance); + + RB_INSERT(enb_agent_map, &enb_agent_head, &e); + + + /* + struct enb_agent_timer_element_s search; + search.timer_id = *timer_id; + printf("search 1: %p (expected %p)\n", RB_FIND(enb_agent_map, &enb_agent_head, &search), &e); + printf("search 1: %p (expected %p)\n", get_timer_entry(e.timer_id), &e); + */ + return 0; +} + +err_code_t enb_agent_destroy_timer(long timer_id){ + + struct enb_agent_timer_element_s *e = get_timer_entry(timer_id); + + if (e != NULL ) { + RB_REMOVE(enb_agent_map, &enb_agent_head, &e); + free(e); + } + + if (timer_remove(timer_id) < 0 ) + goto error; + + return 0; + + error: + LOG_E(ENB_AGENT, "timer can't be removed\n"); + return TIMER_REMOVED_FAILED ; +} + +err_code_t enb_agent_destroy_timers(void){ + + struct enb_agent_timer_element_s *e = NULL; + + RB_FOREACH(e, enb_agent_map, &enb_agent_head) { + RB_REMOVE(enb_agent_map, &enb_agent_head, e); + timer_remove(e->timer_id); + free(e); + } + + return 0; + +} + +struct enb_agent_timer_element_s * get_timer_entry(long timer_id) { + + struct enb_agent_timer_element_s search, *e; + memset(&search, 0, sizeof(struct enb_agent_timer_element_s)); + search.timer_id = timer_id; + + return RB_FIND(enb_agent_map, &enb_agent_head, &search); +} + +/* + int i =0; + RB_FOREACH(e, enb_agent_map, &enb_agent_head) { + printf("%d: %p\n", i, e); i++; + } +*/ + +/* +err_code_t enb_agent_stop_timer(uint32_t timer_id){ + + struct enb_agent_timer_element_s *e=NULL; + + RB_FOREACH(e, enb_agent_map, &enb_agent_head) { + if (e->timer_id == timer_id) + break; + } + + if (e != NULL ) { + e->state = ENB_AGENT_TIMER_STATE_STOPPED; + } + + timer_remove(timer_id); + + return 0; + +} + +// this will change the timer_id +err_code_t enb_agent_restart_timer(uint32_t *timer_id){ + + struct enb_agent_timer_element_s *e=NULL; + + RB_FOREACH(e, enb_agent_map, &enb_agent_head) { + if (e->timer_id == timer_id) + break; + } + + if (e != NULL ) { + e->state = ENB_AGENT_TIMER_STATE_ACTIVE; + } + + ret = timer_setup(e->interval_sec, + e->interval_usec, + e->agent_id, + e->instance, + e->type, + e->timer_args, + &timer_id); + + } + + if (ret < 0 ) { + return PROTOCOL__PROGRAN_ERR__TIMER_SETUP_FAILED; + } + + return 0; + +} + +*/ diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 3bb6596f2e..eb3de96145 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -27,9 +27,9 @@ *******************************************************************************/ -/*! \file - * \brief - * \author +/*! \file enb_agent_common.h + * \brief common message primitves and utilities + * \author Navid Nikaein and Xenofon Foukas * \date 2016 * \version 0.1 */ @@ -45,10 +45,20 @@ #include "stats_messages.pb-c.h" #include "stats_common.pb-c.h" +# include "enb_agent_defs.h" + +#include "LAYER2/MAC/extern.h" +#include "LAYER2/RLC/rlc.h" + +# include "tree.h" +# include "intertask_interface.h" +# include "timer.h" + #define PROGRAN_VERSION 0 typedef int (*enb_agent_message_decoded_callback)( - uint32_t xid, + mid_t mod_id, + xid_t xid, const void *params, Protocol__ProgranMessage **msg ); @@ -57,32 +67,163 @@ typedef int (*enb_agent_message_destruction_callback)( Protocol__ProgranMessage *msg ); -typedef int32_t err_code_t; - int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int *size); int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage **msg); -int prp_create_header(uint32_t xid, Protocol__PrpType type, Protocol__PrpHeader **header); +int prp_create_header(xid_t xid, Protocol__PrpType type, Protocol__PrpHeader **header); -int enb_agent_hello(uint32_t xid, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_hello(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg); int enb_agent_destroy_hello(Protocol__ProgranMessage *msg); -int enb_agent_echo_request(uint32_t xid, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_echo_request(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg); int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg); -int enb_agent_echo_reply(uint32_t xid, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_echo_reply(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg); int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg); -Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid, +Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, + xid_t xid, uint8_t *data, uint32_t size); -void * enb_agent_send_message(uint32_t xid, +void * enb_agent_send_message(xid_t xid, Protocol__ProgranMessage *msg, uint32_t * size); + + + + +/**************************** + * get generic info from RAN + ****************************/ + +void set_enb_vars(mid_t mod_id, ran_name_t ran); + +int get_current_time_ms (mid_t mod_id, int subframe_flag); + +int get_num_ues(mid_t mod_id); + +int get_ue_crnti (mid_t mod_id, mid_t ue_id); + +int get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid); + +int get_ue_phr (mid_t mod_id, mid_t ue_id); + +int get_ue_wcqi (mid_t mod_id, mid_t ue_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 err_code_t (*enb_agent_timer_callback_t)(void*); + +typedef enum { + /* oneshot timer: */ + ENB_AGENT_TIMER_TYPE_ONESHOT = 0x0, + + /* periodic timer */ + ENB_AGENT_TIMER_TYPE_PERIODIC = 0x1, + + /* Inactive state: initial state for any timer. */ + ENB_AGENT_TIMER_TYPE_EVENT_DRIVEN = 0x2, + + /* Max number of states available */ + ENB_AGENT_TIMER_TYPE_MAX, +} eNB_agent_timer_type_t; + +typedef enum { + /* Inactive state: initial state for any timer. */ + ENB_AGENT_TIMER_STATE_INACTIVE = 0x0, + + /* Inactive state: initial state for any timer. */ + ENB_AGENT_TIMER_STATE_ACTIVE = 0x1, + + /* Inactive state: initial state for any timer. */ + ENB_AGENT_TIMER_STATE_STOPPED = 0x2, + + /* Max number of states available */ + ENB_AGENT_TIMER_STATE_MAX, +} eNB_agent_timer_state_t; + +typedef struct enb_agent_timer_args_s{ + mid_t mod_id; + + agent_action_t cc_actions; + uint32_t cc_report_flags; + + agent_action_t ue_actions; + uint32_t ue_report_flags; + +} enb_agent_timer_args_t; + + + +typedef struct enb_agent_timer_element_s{ + RB_ENTRY(enb_agent_timer_element_s) entry; + + agent_id_t agent_id; + instance_t instance; + + eNB_agent_timer_type_t type; + eNB_agent_timer_state_t state; + + uint32_t interval_sec; + uint32_t interval_usec; + + long timer_id; /* Timer id returned by the timer API*/ + + enb_agent_timer_callback_t cb; + void* timer_args; + +} enb_agent_timer_element_t; + + +err_code_t enb_agent_init_timer(void); + +err_code_t enb_agent_create_timer(uint32_t interval_sec, + uint32_t interval_usec, + agent_id_t agent_id, + instance_t instance, + uint32_t timer_type, + enb_agent_timer_callback_t cb, + void* timer_args, + long *timer_id); + +err_code_t enb_agent_destroy_timers(void); +err_code_t enb_agent_destroy_timer(long timer_id); + +err_code_t enb_agent_stop_timer(long timer_id); + +err_code_t enb_agent_restart_timer(long *timer_id); + +struct enb_agent_timer_element_s * get_timer_entry(long timer_id); + +int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b); + +err_code_t enb_agent_process_timeout(long timer_id, void* timer_args); + +RB_HEAD(enb_agent_map, enb_agent_timer_element_s) enb_agent_head; + +/* RB_PROTOTYPE is for .h files */ +RB_PROTOTYPE(enb_agent_map, enb_agent_timer_element_s, entry, enb_agent_compare_timer); + + #endif diff --git a/openair2/ENB_APP/enb_agent_defs.h b/openair2/ENB_APP/enb_agent_defs.h new file mode 100644 index 0000000000..416e61a431 --- /dev/null +++ b/openair2/ENB_APP/enb_agent_defs.h @@ -0,0 +1,142 @@ +/******************************************************************************* + 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 enb_agent_defs.h + * \brief enb agent common definitions + * \author Navid Nikaein and Xenofon Foukas + * \date 2016 + * \version 0.1 + */ +#ifndef ENB_AGENT_DEFS_H_ +#define ENB_AGENT_DEFS_H_ + +#include +#include +#include +#include + +#include "link_manager.h" + +#define NUM_MAX_ENB_AGENT 2 +#define DEFAULT_ENB_AGENT_IPv4_ADDRESS "127.0.0.1" +#define DEFAULT_ENB_AGENT_PORT 2210 + +typedef enum { + + ENB_AGENT_DEFAULT=0, + + ENB_AGENT_PHY=1, + ENB_AGENT_MAC=2, + ENB_AGENT_RLC=3, + ENB_AGENT_PDCP=4, + ENB_AGENT_RRC=5, + ENB_AGENT_S1AP=6, + ENB_AGENT_GTP=7, + ENB_AGENT_X2AP=8, + + ENB_AGENT_MAX=9, + +} agent_id_t; + +typedef enum { + /* no action */ + ENB_AGENT_ACTION_NONE = 0x0, + + /* send action */ + ENB_AGENT_ACTION_SEND = 0x1, + + /* apply action */ + ENB_AGENT_ACTION_APPLY = 0x2, + + /* clear action */ + ENB_AGENT_ACTION_CLEAR = 0x4, + + /* write action */ + ENB_AGENT_ACTION_WRITE = 0x8, + + /* filter action */ + ENB_AGENT_ACTION_FILTER = 0x10, + + /* preprocess action */ + ENB_AGENT_ACTION_PREPROCESS = 0x20, + + /* meter action */ + ENB_AGENT_ACTION_METER = 0x40, + + /* Max number of states available */ + ENB_AGENT_ACTION_MAX = 0x7f, +} agent_action_t; + + +typedef enum { + + RAN_LTE_OAI= 0, + + /* Max number of states available */ + RAN_NAME_MAX = 0x7f, +} ran_name_t; + +typedef uint8_t xid_t; +typedef uint8_t mid_t; // module or enb id +typedef uint8_t lcid_t; +typedef int32_t err_code_t; + +// tx and rx shared context +typedef struct { + mid_t mod_id; + socket_link_t *link; + message_queue_t *send_queue; + message_queue_t *receive_queue; + link_manager_t *manager; +}enb_agent_instance_t; + +typedef struct { + /* general info */ + uint32_t nb_modules; + + + /* stats */ + + uint32_t total_rx_msg; + uint32_t total_tx_msg; + + uint32_t rx_msg[NUM_MAX_ENB_AGENT]; + uint32_t tx_msg[NUM_MAX_ENB_AGENT]; + +}enb_agent_info_t; + +typedef struct { + mid_t mod_id; + message_queue_t *tx_mq; + message_queue_t *rx_mq; + xid_t tx_xid; + xid_t rx_xid; +} msg_context_t; + +#endif diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 5049e669e9..27536c8b7f 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -27,9 +27,9 @@ *******************************************************************************/ -/*! \file - * \brief - * \author +/*! \file enb_agent_handler.c + * \brief enb agent tx and rx message handler + * \author Navid Nikaein and Xenofon Foukas * \date 2016 * \version 0.1 */ @@ -67,7 +67,8 @@ static const char *enb_agent_direction2String[] = { }; -Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid, +Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, + xid_t xid, uint8_t *data, uint32_t size){ @@ -92,7 +93,7 @@ Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid, } - err_code= ((*messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1])(xid, (void *) decoded_message, &reply_message)); + err_code = ((*messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1])(mod_id, xid, (void *) decoded_message, &reply_message)); if ( err_code < 0 ){ goto error; } @@ -102,16 +103,16 @@ Protocol__ProgranMessage* enb_agent_handle_message (uint32_t xid, return reply_message; error: - LOG_E(ENB_APP,"errno %d occured\n",err_code); - return err_code; + LOG_E(ENB_AGENT,"errno %d occured\n",err_code); + return NULL; } -void * enb_agent_send_message(uint32_t xid, - Protocol__ProgranMessage *msg, - uint32_t * size){ +void * enb_agent_send_message(xid_t xid, + Protocol__ProgranMessage *msg, + uint32_t * size){ void * buffer; err_code_t err_code = PROTOCOL__PROGRAN_ERR__NO_ERR; @@ -126,21 +127,32 @@ void * enb_agent_send_message(uint32_t xid, err_code = ((*message_destruction_callback[msg->msg_case-1])(msg)); DevAssert(buffer !=NULL); - - LOG_D(ENB_APP,"Serilized the enb mac stats reply (size %d)\n", *size); - + + LOG_D(ENB_AGENT,"Serilized the enb mac stats reply (size %d)\n", *size); + return buffer; - -error : -LOG_E(ENB_APP,"errno %d occured\n",err_code); -return NULL; + + error : + LOG_E(ENB_AGENT,"errno %d occured\n",err_code); + + return NULL; } +err_code_t enb_agent_process_timeout(long timer_id, void* timer_args){ + + struct enb_agent_timer_element_s *e = get_timer_entry(timer_id); + + LOG_I(ENB_AGENT, "element %p: timer_id is 0x%lx 0x%lx\n", e, timer_id, e->timer_id); + + if (e == NULL ) goto error; + if (timer_args == NULL) + LOG_W(ENB_AGENT,"null timer args\n"); + + return e->cb(timer_args); + - - - - - - + error: + LOG_E(ENB_AGENT, "can't get the timer element\n"); + return TIMER_ELEMENT_NOT_FOUND; +} diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 3c188881fb..edf1406296 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -27,20 +27,18 @@ *******************************************************************************/ -/*! \file - * \brief - * \author +/*! \file enb_agent_mac.c + * \brief enb agent message handler for MAC layer + * \author Navid Nikaein and Xenofon Foukas * \date 2016 * \version 0.1 */ #include "enb_agent_mac.h" -#include "enb_agent_common.h" -#include "LAYER2/MAC/extern.h" -#include "LAYER2/RLC/rlc.h" + #include "log.h" -int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__ProgranMessage **msg){ +int enb_agent_mac_handle_stats(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg){ // TODO: Must deal with sanitization of input // TODO: Must check if RNTIs and cell ids of the request actually exist @@ -52,11 +50,11 @@ int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__Progr //TODO: We do not deal with multiple CCs at the moment and eNB id is 0 int cc_id = 0; - int enb_id = 0; - - eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; - UE_list_t *eNB_UE_list= &eNB->UE_list; + 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; @@ -90,7 +88,7 @@ int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__Progr //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 = eNB_UE_list->num_UEs; + report_config.nr_ue = 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 @@ -98,7 +96,7 @@ int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__Progr goto error; } for (i = 0; i < report_config.nr_ue; i++) { - report_config.ue_report_type[i].ue_rnti = eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].crnti; + report_config.ue_report_type[i].ue_rnti = 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 @@ -157,7 +155,7 @@ int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__Progr goto error; } - if (enb_agent_mac_stats_reply(xid, &report_config, msg) < 0 ){ + if (enb_agent_mac_stats_reply(enb_id, xid, &report_config, msg) < 0 ){ err_code = PROTOCOL__PROGRAN_ERR__MSG_BUILD; goto error; } @@ -168,19 +166,20 @@ int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__Progr return 0; error : - LOG_E(ENB_APP, "errno %d occured\n", err_code); + LOG_E(ENB_AGENT, "errno %d occured\n", err_code); return err_code; } -int enb_agent_mac_stats_reply(uint32_t xid, +int enb_agent_mac_stats_reply(mid_t mod_id, + xid_t xid, const report_config_t *report_config, Protocol__ProgranMessage **msg) { Protocol__PrpHeader *header; int i, j, k; int cc_id = 0; - int enb_id = 0; - eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; - UE_list_t *eNB_UE_list= &eNB->UE_list; + int enb_id = mod_id; + //eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; + //UE_list_t *eNB_UE_list= &eNB->UE_list; if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_STATS_REPLY, &header) != 0) @@ -226,7 +225,7 @@ int enb_agent_mac_stats_reply(uint32_t xid, for (j = 0; j++; j < ue_report[i]->n_bsr) { // Set the actual BSR for LCG j of the current UE // NN: we need to know the cc_id here, consider the first one - elem[j] = eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].bsr_info[j]; + elem[j] = get_ue_bsr (enb_id, i, j); //eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].bsr_info[j]; } ue_report[i]->bsr = elem; } @@ -234,7 +233,7 @@ int enb_agent_mac_stats_reply(uint32_t xid, /* Check flag for creation of PRH report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PRH) { // TODO: Fill in the actual power headroom value for the RNTI - ue_report[i]->phr = eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].phr_info; + ue_report[i]->phr = 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; } @@ -297,7 +296,7 @@ int enb_agent_mac_stats_reply(uint32_t xid, goto error; protocol__prp_dl_cqi_report__init(dl_report); //TODO:Set the SFN and SF of the last report held in the agent. - dl_report->sfn_sn = eNB->frame*10 + eNB->subframe; + dl_report->sfn_sn = get_current_time_ms(enb_id, 1); dl_report->has_sfn_sn = 1; //TODO:Set the number of DL CQI reports for this UE. One for each CC dl_report->n_csi_report = 1; @@ -331,7 +330,7 @@ int enb_agent_mac_stats_reply(uint32_t xid, protocol__prp_csi_p10__init(csi10); //TODO: set the wideband value // NN: this is also depends on cc_id - csi10->wb_cqi = eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].dl_cqi; + csi10->wb_cqi = 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; diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index e22253cf27..6584111825 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -27,9 +27,9 @@ *******************************************************************************/ -/*! \file - * \brief - * \author +/*! \file enb_agent_mac.h + * \brief enb agent message handler APIs for MAC layer + * \author Navid Nikaein and Xenofon Foukas * \date 2016 * \version 0.1 */ @@ -42,6 +42,8 @@ #include "stats_messages.pb-c.h" #include "stats_common.pb-c.h" +#include "enb_agent_common.h" + /* These types will be used to give instructions for the type of stats reports @@ -68,9 +70,9 @@ typedef struct { } report_config_t; -int enb_agent_mac_handle_stats(uint32_t xid, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_mac_handle_stats(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg); -int enb_agent_mac_stats_reply(uint32_t xid, const report_config_t *report_config, Protocol__ProgranMessage **msg); +int enb_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *report_config, Protocol__ProgranMessage **msg); int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg); diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index d63d895711..b20d0912d8 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -315,8 +315,11 @@ void *eNB_app_task(void *args_p) } #if defined (ENB_AGENT_SB_IF) - printf("\n start enb agent\n"); - enb_agent_start(); + + for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { + printf("\n start enb agent %d\n", enb_id); + enb_agent_start(enb_id, enb_properties_p); + } #endif # if defined(ENABLE_USE_MME) diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index 07e0ffa640..39bd5028d8 100755 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -170,6 +170,11 @@ #define ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_S1U "ENB_IPV4_ADDRESS_FOR_S1U" #define ENB_CONFIG_STRING_ENB_PORT_FOR_S1U "ENB_PORT_FOR_S1U" +#define ENB_CONFIG_STRING_NETWORK_CONTROLLER_CONFIG "NETWORK_CONTROLLER" +#define ENB_CONFIG_STRING_ENB_AGENT_INTERFACE_NAME "ENB_AGENT_INTERFACE_NAME" +#define ENB_CONFIG_STRING_ENB_AGENT_IPV4_ADDRESS "ENB_AGENT_IPV4_ADDRESS" +#define ENB_CONFIG_STRING_ENB_AGENT_PORT "ENB_AGENT_PORT" + #define ENB_CONFIG_STRING_ASN1_VERBOSITY "Asn1_verbosity" #define ENB_CONFIG_STRING_ASN1_VERBOSITY_NONE "none" @@ -275,6 +280,14 @@ static void enb_config_display(void) printf( "\tMNC: \t%02"PRIu16":\n",enb_properties.properties[i]->mnc); } +#if defined(ENB_AGENT_SB_IF) + printf( "\nENB AGENT CONFIG : \n\n"); + printf( "\tInterface name: \t%s:\n",enb_properties.properties[i]->enb_agent_interface_name); + printf( "\tInterface IP Address: \t%s:\n",enb_properties.properties[i]->enb_agent_ipv4_address); + printf( "\tInterface PORT: \t%d:\n\n",enb_properties.properties[i]->enb_agent_port); + +#endif + for (j=0; j< enb_properties.properties[i]->nb_cc; j++) { printf( "\teutra band for CC %d: \t%"PRId16":\n",j,enb_properties.properties[i]->eutra_band[j]); printf( "\tdownlink freq for CC %d: \t%"PRIu64":\n",j,enb_properties.properties[i]->downlink_frequency[j]); @@ -571,6 +584,9 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) char *address = NULL; char *cidr = NULL; char *astring = NULL; + char* enb_agent_interface_name = NULL; + char* enb_agent_ipv4_address = NULL; + libconfig_int enb_agent_port = 0; libconfig_int otg_ue_id = 0; char* otg_app_type = NULL; char* otg_bg_traffic = NULL; @@ -2190,6 +2206,33 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) } } } + + // Network Controller + subsetting = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_NETWORK_CONTROLLER_CONFIG); + + if (subsetting != NULL) { + if ( ( + config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_AGENT_INTERFACE_NAME, + (const char **)&enb_agent_interface_name) + && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_AGENT_IPV4_ADDRESS, + (const char **)&enb_agent_ipv4_address) + && config_setting_lookup_int(subsetting, ENB_CONFIG_STRING_ENB_AGENT_PORT, + &enb_agent_port) + ) + ) { + enb_properties.properties[enb_properties_index]->enb_agent_interface_name = strdup(enb_agent_interface_name); + cidr = enb_agent_ipv4_address; + address = strtok(cidr, "/"); + enb_properties.properties[enb_properties_index]->enb_agent_ipv4_address = strdup(address); + /* if (address) { + IPV4_STR_ADDR_TO_INT_NWBO (address, enb_properties.properties[enb_properties_index]->enb_agent_ipv4_address, "BAD IP ADDRESS FORMAT FOR eNB Agent !\n" ); + }*/ + + enb_properties.properties[enb_properties_index]->enb_agent_port = enb_agent_port; + + } + } + // OTG _CONFIG setting_otg = config_setting_get_member (setting_enb, ENB_CONF_STRING_OTG_CONFIG); diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h index 113681dafe..7182628de0 100755 --- a/openair2/ENB_APP/enb_config.h +++ b/openair2/ENB_APP/enb_config.h @@ -203,6 +203,9 @@ typedef struct Enb_properties_s { char *enb_interface_name_for_S1_MME; in_addr_t enb_ipv4_address_for_S1_MME; + char *enb_agent_interface_name; + in_addr_t enb_agent_ipv4_address; + tcp_udp_port_t enb_agent_port; // otg config /* Nb of OTG elements */ uint8_t num_otg_elements; diff --git a/openair2/UTIL/LOG/log.c b/openair2/UTIL/LOG/log.c index abbdbc01ab..f8326be820 100755 --- a/openair2/UTIL/LOG/log.c +++ b/openair2/UTIL/LOG/log.c @@ -333,6 +333,14 @@ int logInit (void) g_log->log_component[ENB_APP].filelog = 0; g_log->log_component[ENB_APP].filelog_name = ""; + g_log->log_component[ENB_AGENT].name = "ENB_AGENT"; + g_log->log_component[ENB_AGENT].level = LOG_DEBUG; + g_log->log_component[ENB_AGENT].flag = LOG_MED; + g_log->log_component[ENB_AGENT].interval = 1; + g_log->log_component[ENB_AGENT].fd = 0; + g_log->log_component[ENB_AGENT].filelog = 0; + g_log->log_component[ENB_AGENT].filelog_name = ""; + g_log->log_component[TMR].name = "TMR"; g_log->log_component[TMR].level = LOG_EMERG; g_log->log_component[TMR].flag = LOG_MED; diff --git a/openair2/UTIL/LOG/log.h b/openair2/UTIL/LOG/log.h index c6abbfa001..1eb68f6e44 100755 --- a/openair2/UTIL/LOG/log.h +++ b/openair2/UTIL/LOG/log.h @@ -264,6 +264,7 @@ typedef enum { RAL_ENB, RAL_UE, ENB_APP, + ENB_AGENT, TMR, USIM, LOCALIZE, diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf new file mode 100644 index 0000000000..045a2855a0 --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf @@ -0,0 +1,153 @@ +Active_eNBs = ( "eNB_Eurecom_LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB_Eurecom_LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = "1"; + + mobile_country_code = "208"; + + mobile_network_code = "10"; + + ////////// Physical parameters: + + component_carriers = ( + { + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2680000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 25; + rx_gain = 20; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = 0; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 0; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -108; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -108; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 2; + rach_preambleInitialReceivedTargetPower = -100; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + } + ); + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "0.0.0.0"; + ipv6 = "0::0"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "none"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "0.0.0.0/24"; + + ENB_INTERFACE_NAME_FOR_S1U = "none"; + ENB_IPV4_ADDRESS_FOR_S1U = "0.0.0.0/24"; + ENB_PORT_FOR_S1U = 2153; # Spec 2152 + }; + + NETWORK_CONTROLLER : + { + ENB_AGENT_INTERFACE_NAME = "eth0"; + ENB_AGENT_IPV4_ADDRESS = "127.0.0.1/24"; + ENB_AGENT_PORT = 2210; + }; + + log_config : + { + global_log_level ="trace"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="trace"; + phy_log_verbosity ="medium"; + mac_log_level ="trace"; + mac_log_verbosity ="medium"; + rlc_log_level ="trace"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="trace"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="trace"; + rrc_log_verbosity ="medium"; + gtpu_log_level ="debug"; + gtpu_log_verbosity ="medium"; + udp_log_level ="debug"; + udp_log_verbosity ="medium"; + osa_log_level ="debug"; + osa_log_verbosity ="low"; + }; + + } +); From f7d591f150841ad30d9e4de3a5d68b1f43060fcc Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 5 Jan 2016 13:57:52 +0200 Subject: [PATCH 046/413] Created task manager support for agent messages in the for of a priority queue --- cmake_targets/CMakeLists.txt | 1 + openair2/ENB_APP/enb_agent_task_manager.c | 303 ++++++++++++++++++++++ openair2/ENB_APP/enb_agent_task_manager.h | 158 +++++++++++ 3 files changed, 462 insertions(+) create mode 100644 openair2/ENB_APP/enb_agent_task_manager.c create mode 100644 openair2/ENB_APP/enb_agent_task_manager.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 6fa30b2b35..0777e1f3a0 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -746,6 +746,7 @@ if (ENB_AGENT_SB_IF) ${OPENAIR2_DIR}/ENB_APP/enb_agent_common.c ${OPENAIR2_DIR}/ENB_APP/enb_agent_mac.c ${OPENAIR2_DIR}/ENB_APP/enb_agent.c + ${OPENAIR2_DIR}/ENB_APP/enb_agent_task_manager.c ) set(ENB_AGENT_LIB ENB_AGENT) #include_directories(${OPENAIR2_DIR}/ENB_APP) diff --git a/openair2/ENB_APP/enb_agent_task_manager.c b/openair2/ENB_APP/enb_agent_task_manager.c new file mode 100644 index 0000000000..0b987f1c22 --- /dev/null +++ b/openair2/ENB_APP/enb_agent_task_manager.c @@ -0,0 +1,303 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2015 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ +/*! \file enb_agent_task_manager.h + * \brief Implementation of scheduled tasks manager for the enb agent + * \author Xenofon Foukas + * \date January 2016 + * \version 0.1 + * \email: x.foukas@sms.ed.ac.uk + * @ingroup _mac + */ + +#include +#include +#include + +#include "enb_agent_task_manager.h" + + +/* Util macros */ +#define LEFT(x) (2 * (x) + 1) +#define RIGHT(x) (2 * (x) + 2) +#define PARENT(x) ((x - 1) / 2) + +enb_agent_task_t *enb_agent_task_create(Protocol__ProgranMessage *msg, + uint16_t frame_num, uint8_t subframe_num) { + enb_agent_task_t *task = NULL; + task = malloc(sizeof(enb_agent_task_t)); + + if (task == NULL) + goto error; + + task->frame_num = frame_num; + task->subframe_num = subframe_num; + task->task = msg; + + return task; + + error: + return NULL; +} + +void enb_agent_task_destroy(enb_agent_task_t *task) { + if (task == NULL) + return; + + /* TODO: must free the task properly */ + free(task->task); + free(task); +} + +enb_agent_task_queue_t *enb_agent_task_queue_init(size_t capacity, + int (*cmp)(const enb_agent_task_t *t1, const enb_agent_task_t *t2)) { + enb_agent_task_queue_t *queue = NULL; + + queue = malloc(sizeof(enb_agent_task_queue_t)); + if (queue == NULL) + goto error; + + /* If no comparator was given, use the default one */ + if (cmp == NULL) + queue->cmp = _enb_agent_task_queue_cmp; + else + queue->cmp = cmp; + + queue->first_frame = 0; + queue->first_subframe = 0; + + queue->task = malloc(capacity * sizeof(enb_agent_task_t *)); + if (queue->task == NULL) + goto error; + + queue->count = 0; + queue->capacity = capacity; + + queue->mutex = malloc(sizeof(pthread_mutex_t)); + if (queue->mutex == NULL) + goto error; + if (pthread_mutex_init(queue->mutex, NULL)) + goto error; + + return queue; + + error: + if (queue != NULL) { + free(queue->mutex); + free(queue->task); + free(queue); + } + return NULL; +} + +enb_agent_task_queue_t *enb_agent_task_queue_default_init() { + return enb_agent_task_queue_init(DEFAULT_CAPACITY, NULL); +} + +void enb_agent_task_queue_destroy(enb_agent_task_queue_t *queue) { + int i; + + if (queue == NULL) + return; + + for (i = 0; i < queue->count; i++) { + enb_agent_task_destroy(queue->task[i]); + } + free(queue->task); + free(queue->mutex); + free(queue); +} + +int enb_agent_task_queue_put(enb_agent_task_queue_t *queue, enb_agent_task_t *task) { + size_t i; + enb_agent_task_t *tmp = NULL; + int realloc_status, err_code; + + if (pthread_mutex_lock(queue->mutex)) { + /*TODO*/ + err_code = -1; + goto error; + } + + if (queue->count >= queue->capacity) { + /*TODO: need to call realloc heap*/ + realloc_status = _enb_agent_task_queue_realloc_heap(queue); + if (realloc_status != HEAP_OK) { + err_code = realloc_status; + goto error; + } + } + + queue->task[queue->count] = task; + i = queue->count; + queue->count++; + /*Swap elements to maintain heap properties*/ + while(i > 0 && queue->cmp(queue->task[i], queue->task[PARENT(i)]) > 0) { + tmp = queue->task[i]; + queue->task[i] = queue->task[PARENT(i)]; + queue->task[PARENT(i)] = tmp; + i = PARENT(i); + } + + if (pthread_mutex_unlock(queue->mutex)) { + // LOG_E(MAC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + return 0; + + error: + /*TODO*/ + return err_code; +} + + +int enb_agent_task_queue_get_current_task(enb_agent_task_queue_t *queue, enb_agent_task_t **task) { + int err_code; + + /*TODO*/ + /* Find current frame and subframe number */ + uint16_t curr_frame=1; + uint8_t curr_subframe=1; + + if (pthread_mutex_lock(queue->mutex)) { + /*TODO*/ + err_code = -1; + goto error; + } + + if (queue->count < 1) { + /* Priority Queue is empty */ + err_code = HEAP_EMPTY; + goto error; + } + /* If no task is scheduled for the current subframe, return without any task */ + if(queue->task[0]->frame_num != curr_frame || queue->task[0]->subframe_num != curr_subframe) { + *task = NULL; + return 0; + } + /* Otherwise, the first task should be returned */ + *task = queue->task[0]; + queue->task[0] = queue->task[queue->count-1]; + queue->count--; + /* Restore heap property */ + _enb_agent_task_queue_heapify(queue, 0); + + if (pthread_mutex_unlock(queue->mutex)) { + // LOG_E(MAC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + return HEAP_OK; + + error: + /*TODO*/ + return err_code; +} + +/*Warning: Internal function. Should not be called as API function. Not thread safe*/ +void _enb_agent_task_queue_heapify(enb_agent_task_queue_t *queue, size_t idx) { + /* left index, right index, largest */ + enb_agent_task_t *tmp = NULL; + size_t l_idx, r_idx, lrg_idx; + + l_idx = LEFT(idx); + r_idx = RIGHT(idx); + + /* Left child exists, compare left child with its parent */ + if (l_idx < queue->count && queue->cmp(queue->task[l_idx], queue->task[idx]) > 0) { + lrg_idx = l_idx; + } else { + lrg_idx = idx; + } + + /* Right child exists, compare right child with the largest element */ + if (r_idx < queue->count && queue->cmp(queue->task[r_idx], queue->task[lrg_idx]) > 0) { + lrg_idx = r_idx; + } + + /* At this point largest element was determined */ + if (lrg_idx != idx) { + /* Swap between the index at the largest element */ + tmp = queue->task[lrg_idx]; + queue->task[lrg_idx] = queue->task[idx]; + queue->task[idx] = tmp; + /* Heapify again */ + _enb_agent_task_queue_heapify(queue, lrg_idx); + } +} + +/*Warning: Internal function. Should not be called as API function. Not thread safe*/ +int _enb_agent_task_queue_realloc_heap(enb_agent_task_queue_t *queue) { + enb_agent_task_t **resized_task_heap; + if (queue->count >= queue->capacity) { + size_t task_size = sizeof(enb_agent_task_t); + + resized_task_heap = realloc(queue->task, (2*queue->capacity) * task_size); + if (resized_task_heap != NULL) { + queue->capacity *= 2; + queue->task = (enb_agent_task_t **) resized_task_heap; + return HEAP_OK; + } else return HEAP_REALLOCERROR; + } + return HEAP_NOREALLOC; +} + +int _enb_agent_task_queue_cmp(const enb_agent_task_t *t1, const enb_agent_task_t *t2) { + if ((t1->frame_num == t2->frame_num) && (t1->subframe_num == t2->subframe_num)) + return 0; + /* TODO: need to get current frame and subframe number */ + uint16_t curr_frame = 0; + uint8_t curr_subframe = 7; + + int f_offset, sf_offset, tmp1, tmp2; + + /*Check if the offsets have the same sign and compare the tasks position frame-wise*/ + tmp1 = t1->frame_num - curr_frame; + tmp2 = t2->frame_num - curr_frame; + if ((tmp1 >= 0) ^ (tmp2 < 0)) { + f_offset = tmp2 - tmp1; + } + else { + f_offset = tmp1 - tmp2; + } + /*Do the same for the subframe*/ + tmp1 = t1->subframe_num - curr_subframe; + tmp2 = t2->subframe_num - curr_subframe; + if ((tmp1 >= 0) ^ (tmp2 < 0)) + sf_offset = tmp2 - tmp1; + else + sf_offset = tmp1 - tmp2; + + /*Subframe position matters only if f_offset is 0. Multiply f_offset by 100 + to be the only comparisson parameter in all other cases */ + return f_offset*100 + sf_offset; +} + + +int main(int argc, char **argv) { + return 0; +} diff --git a/openair2/ENB_APP/enb_agent_task_manager.h b/openair2/ENB_APP/enb_agent_task_manager.h new file mode 100644 index 0000000000..5a3b5eb327 --- /dev/null +++ b/openair2/ENB_APP/enb_agent_task_manager.h @@ -0,0 +1,158 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2015 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ +/*! \file enb_agent_task_manager.h + * \brief Implementation of scheduled tasks manager for the enb agent + * \author Xenofon Foukas + * \date January 2016 + * \version 0.1 + * \email: x.foukas@sms.ed.ac.uk + * @ingroup _mac + */ + +#ifndef ENB_AGENT_TASK_MANAGER_ +#define ENB_AGENT_TASK_MANAGER_ + +#include +#include + +#include "progran.pb-c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DEFAULT_CAPACITY 512 + +/** + * The structure containing the enb agent task to be executed + */ +typedef struct enb_agent_task_s { + /* The frame in which the task needs to be executed */ + uint16_t frame_num; + /* The subframe in which the task needs to be executed */ + uint8_t subframe_num; + /* The task to be executed in the form of a Protocol__ProgranMessage */ + Protocol__ProgranMessage *task; +} enb_agent_task_t; + +/** + * Priority Queue Structure for tasks + */ +typedef struct enb_agent_task_queue_s { + /* The amount of allocated memory for agent tasks in the heap*/ + volatile size_t capacity; + /* The actual size of the tasks heap at a certain time */ + volatile size_t count; + /* The earliest frame that has a pending task */ + volatile uint16_t first_frame; + /* The earliest subframe within the frame that has a pending task */ + volatile uint8_t first_subframe; + /* An array of prioritized tasks stored in a heap */ + enb_agent_task_t **task; + /* A pointer to a comparator function, used to prioritize elements */ + int (*cmp)(const enb_agent_task_t *t1, const enb_agent_task_t *t2); + pthread_mutex_t *mutex; +} enb_agent_task_queue_t; + +typedef enum { + HEAP_OK = 0, + HEAP_EMPTY, + HEAP_FAILED, + HEAP_REALLOCERROR, + HEAP_NOREALLOC, + HEAP_FATAL, +} heapstatus_e; + +/** + * Allocate memory for a task in the queue + */ +enb_agent_task_t *enb_agent_task_create(Protocol__ProgranMessage *msg, + uint16_t frame_num, uint8_t subframe_num); + +/** + * Free memory for a task of the queue + */ +void enb_agent_task_destroy(enb_agent_task_t *task); + +/** + * Allocate initial memory for storing the tasks + */ +enb_agent_task_queue_t *enb_agent_task_queue_init(size_t capacity, + int (*cmp)(const enb_agent_task_t *t1, const enb_agent_task_t *t2)); + +/** + * Allocate initial memory for storing the tasks using default parameters + */ +enb_agent_task_queue_t *enb_agent_task_queue_default_init(); + +/** + * De-allocate memory for the tasks queue + */ +void enb_agent_task_queue_destroy(enb_agent_task_queue_t *queue); + +/** + * Insert task into the queue + */ +int enb_agent_task_queue_put(enb_agent_task_queue_t *queue, enb_agent_task_t *task); + +/** + * Remove the task with the highest priority from the queue + * task becomes NULL if there is no task for the current frame and subframe + */ +int enb_agent_task_queue_get_current_task(enb_agent_task_queue_t *queue, enb_agent_task_t **task); + +/** + * Check if the top priority task is for a specific frame and subframe + */ +int enb_agent_task_queue_has_upcoming_task (enb_agent_task_queue_t *queue, + const uint16_t frame, const uint8_t subframe); + +/** + * Restructure heap after modifications + */ +void _enb_agent_task_queue_heapify(enb_agent_task_queue_t *queue, size_t idx); + +/** + * Reallocate memory once the heap reaches max size + */ +int _enb_agent_task_queue_realloc_heap(enb_agent_task_queue_t *queue); + +/** + * Compare two agent tasks based on frame and subframe + * returns 0 if tasks t1, t2 have the same priority + * return negative value if t1 needs to be executed after t2 + * return positive value if t1 preceeds t2 + */ +int _enb_agent_task_queue_cmp(const enb_agent_task_t *t1, const enb_agent_task_t *t2); + +#ifdef __cplusplus +} +#endif + +#endif /*ENB_AGENT_TASK_MANAGER_*/ From f2f0e68f9db76695d0c91dc109d0f59cfba56c1d Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Tue, 5 Jan 2016 19:26:45 +0100 Subject: [PATCH 047/413] Fix the bug in the RB tree, and sanity test for the timer API --- common/utils/collection/tree.h | 231 ++++++++++++++++++++------- common/utils/itti/timer.c | 8 +- openair2/ENB_APP/enb_agent.c | 5 +- openair2/ENB_APP/enb_agent_common.c | 85 +++++----- openair2/ENB_APP/enb_agent_common.h | 9 +- openair2/ENB_APP/enb_agent_handler.c | 10 +- 6 files changed, 232 insertions(+), 116 deletions(-) diff --git a/common/utils/collection/tree.h b/common/utils/collection/tree.h index 8e4e35c408..c9df686fbb 100755 --- a/common/utils/collection/tree.h +++ b/common/utils/collection/tree.h @@ -1,4 +1,8 @@ -/* +/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */ +/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ +/* $FreeBSD$ */ + +/*- * Copyright 2002 Niels Provos * All rights reserved. * @@ -26,6 +30,8 @@ #ifndef _SYS_TREE_H_ #define _SYS_TREE_H_ +#include + /* * This file defines data structures for different types of trees: * splay trees and red-black trees. @@ -63,7 +69,7 @@ struct name { \ #define SPLAY_INIT(root) do { \ (root)->sph_root = NULL; \ -} while (0) +} while (/*CONSTCOND*/ 0) #define SPLAY_ENTRY(type) \ struct { \ @@ -81,32 +87,32 @@ struct { \ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ -} while (0) +} while (/*CONSTCOND*/ 0) #define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ -} while (0) +} while (/*CONSTCOND*/ 0) #define SPLAY_LINKLEFT(head, tmp, field) do { \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ -} while (0) +} while (/*CONSTCOND*/ 0) #define SPLAY_LINKRIGHT(head, tmp, field) do { \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ -} while (0) +} while (/*CONSTCOND*/ 0) #define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ -} while (0) +} while (/*CONSTCOND*/ 0) /* Generates prototypes and inline functions */ @@ -207,7 +213,7 @@ name##_SPLAY(struct name *head, struct type *elm) \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ - while ((__comp = (cmp)(elm, (head)->sph_root))) { \ + while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ @@ -286,7 +292,7 @@ void name##_SPLAY_MINMAX(struct name *head, int __comp) \ (x) != NULL; \ (x) = SPLAY_NEXT(name, head, x)) -/* Macros that define a red-back tree */ +/* Macros that define a red-black tree */ #define RB_HEAD(name, type) \ struct name { \ struct type *rbh_root; /* root of the tree */ \ @@ -297,7 +303,7 @@ struct name { \ #define RB_INIT(root) do { \ (root)->rbh_root = NULL; \ -} while (0) +} while (/*CONSTCOND*/ 0) #define RB_BLACK 0 #define RB_RED 1 @@ -320,24 +326,24 @@ struct { \ RB_PARENT(elm, field) = parent; \ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ RB_COLOR(elm, field) = RB_RED; \ -} while (0) +} while (/*CONSTCOND*/ 0) #define RB_SET_BLACKRED(black, red, field) do { \ RB_COLOR(black, field) = RB_BLACK; \ RB_COLOR(red, field) = RB_RED; \ -} while (0) +} while (/*CONSTCOND*/ 0) #ifndef RB_AUGMENT -#define RB_AUGMENT(x) +#define RB_AUGMENT(x) do {} while (0) #endif #define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ (tmp) = RB_RIGHT(elm, field); \ - if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ @@ -349,15 +355,15 @@ struct { \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (0) +} while (/*CONSTCOND*/ 0) #define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ (tmp) = RB_LEFT(elm, field); \ - if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ @@ -369,28 +375,66 @@ struct { \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (0) +} while (/*CONSTCOND*/ 0) /* Generates prototypes and inline functions */ -#define RB_PROTOTYPE(name, type, field, cmp) \ -void name##_RB_INSERT_COLOR(struct name *, struct type *); \ -void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ -struct type *name##_RB_REMOVE(struct name *, struct type *); \ -struct type *name##_RB_INSERT(struct name *, struct type *); \ -struct type *name##_RB_FIND(struct name *, struct type *); \ -struct type *name##_RB_NEXT(struct type *); \ -struct type *name##_RB_MINMAX(struct name *, int); \ - \ +#define RB_PROTOTYPE(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ + RB_PROTOTYPE_INSERT_COLOR(name, type, attr); \ + RB_PROTOTYPE_REMOVE_COLOR(name, type, attr); \ + RB_PROTOTYPE_INSERT(name, type, attr); \ + RB_PROTOTYPE_REMOVE(name, type, attr); \ + RB_PROTOTYPE_FIND(name, type, attr); \ + RB_PROTOTYPE_NFIND(name, type, attr); \ + RB_PROTOTYPE_NEXT(name, type, attr); \ + RB_PROTOTYPE_PREV(name, type, attr); \ + RB_PROTOTYPE_MINMAX(name, type, attr); +#define RB_PROTOTYPE_INSERT_COLOR(name, type, attr) \ + attr void name##_RB_INSERT_COLOR(struct name *, struct type *) +#define RB_PROTOTYPE_REMOVE_COLOR(name, type, attr) \ + attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *) +#define RB_PROTOTYPE_REMOVE(name, type, attr) \ + attr struct type *name##_RB_REMOVE(struct name *, struct type *) +#define RB_PROTOTYPE_INSERT(name, type, attr) \ + attr struct type *name##_RB_INSERT(struct name *, struct type *) +#define RB_PROTOTYPE_FIND(name, type, attr) \ + attr struct type *name##_RB_FIND(struct name *, struct type *) +#define RB_PROTOTYPE_NFIND(name, type, attr) \ + attr struct type *name##_RB_NFIND(struct name *, struct type *) +#define RB_PROTOTYPE_NEXT(name, type, attr) \ + attr struct type *name##_RB_NEXT(struct type *) +#define RB_PROTOTYPE_PREV(name, type, attr) \ + attr struct type *name##_RB_PREV(struct type *) +#define RB_PROTOTYPE_MINMAX(name, type, attr) \ + attr struct type *name##_RB_MINMAX(struct name *, int) /* Main rb operation. * Moves node close to the key of elm to top */ -#define RB_GENERATE(name, type, field, cmp) \ -void \ +#define RB_GENERATE(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp,) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ + RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ + RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ + RB_GENERATE_INSERT(name, type, field, cmp, attr) \ + RB_GENERATE_REMOVE(name, type, field, attr) \ + RB_GENERATE_FIND(name, type, field, cmp, attr) \ + RB_GENERATE_NFIND(name, type, field, cmp, attr) \ + RB_GENERATE_NEXT(name, type, field, attr) \ + RB_GENERATE_PREV(name, type, field, attr) \ + RB_GENERATE_MINMAX(name, type, field, attr) + +#define RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ +attr void \ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ { \ struct type *parent, *gparent, *tmp; \ - while ((parent = RB_PARENT(elm, field)) && \ + while ((parent = RB_PARENT(elm, field)) != NULL && \ RB_COLOR(parent, field) == RB_RED) { \ gparent = RB_PARENT(parent, field); \ if (parent == RB_LEFT(gparent, field)) { \ @@ -428,9 +472,10 @@ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ } \ } \ RB_COLOR(head->rbh_root, field) = RB_BLACK; \ -} \ - \ -void \ +} + +#define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ +attr void \ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ { \ struct type *tmp; \ @@ -454,7 +499,8 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) if (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ struct type *oleft; \ - if ((oleft = RB_LEFT(tmp, field)))\ + if ((oleft = RB_LEFT(tmp, field)) \ + != NULL) \ RB_COLOR(oleft, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_RIGHT(head, tmp, oleft, field);\ @@ -486,7 +532,8 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) if (RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ struct type *oright; \ - if ((oright = RB_RIGHT(tmp, field)))\ + if ((oright = RB_RIGHT(tmp, field)) \ + != NULL) \ RB_COLOR(oright, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_LEFT(head, tmp, oright, field);\ @@ -504,9 +551,10 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) } \ if (elm) \ RB_COLOR(elm, field) = RB_BLACK; \ -} \ - \ -struct type * \ +} + +#define RB_GENERATE_REMOVE(name, type, field, attr) \ +attr struct type * \ name##_RB_REMOVE(struct name *head, struct type *elm) \ { \ struct type *child, *parent, *old = elm; \ @@ -518,7 +566,7 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \ else { \ struct type *left; \ elm = RB_RIGHT(elm, field); \ - while ((left = RB_LEFT(elm, field))) \ + while ((left = RB_LEFT(elm, field)) != NULL) \ elm = left; \ child = RB_RIGHT(elm, field); \ parent = RB_PARENT(elm, field); \ @@ -551,7 +599,7 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \ left = parent; \ do { \ RB_AUGMENT(left); \ - } while ((left = RB_PARENT(left, field))); \ + } while ((left = RB_PARENT(left, field)) != NULL); \ } \ goto color; \ } \ @@ -572,9 +620,10 @@ color: \ name##_RB_REMOVE_COLOR(head, parent, child); \ return (old); \ } \ - \ + +#define RB_GENERATE_INSERT(name, type, field, cmp, attr) \ /* Inserts a node into the RB tree */ \ -struct type * \ +attr struct type * \ name##_RB_INSERT(struct name *head, struct type *elm) \ { \ struct type *tmp; \ @@ -599,15 +648,14 @@ name##_RB_INSERT(struct name *head, struct type *elm) \ RB_RIGHT(parent, field) = elm; \ RB_AUGMENT(parent); \ } else \ - { \ RB_ROOT(head) = elm; \ - } \ name##_RB_INSERT_COLOR(head, elm); \ return (NULL); \ -} \ - \ +} + +#define RB_GENERATE_FIND(name, type, field, cmp, attr) \ /* Finds the node with the same key as elm */ \ -struct type * \ +attr struct type * \ name##_RB_FIND(struct name *head, struct type *elm) \ { \ struct type *tmp = RB_ROOT(head); \ @@ -622,9 +670,33 @@ name##_RB_FIND(struct name *head, struct type *elm) \ return (tmp); \ } \ return (NULL); \ -} \ - \ -struct type * \ +} + +#define RB_GENERATE_NFIND(name, type, field, cmp, attr) \ +/* Finds the first node greater than or equal to the search key */ \ +attr struct type * \ +name##_RB_NFIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *res = NULL; \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) { \ + res = tmp; \ + tmp = RB_LEFT(tmp, field); \ + } \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (res); \ +} + +#define RB_GENERATE_NEXT(name, type, field, attr) \ +/* ARGSUSED */ \ +attr struct type * \ name##_RB_NEXT(struct type *elm) \ { \ if (RB_RIGHT(elm, field)) { \ @@ -643,9 +715,33 @@ name##_RB_NEXT(struct type *elm) \ } \ } \ return (elm); \ -} \ - \ -struct type * \ +} + +#define RB_GENERATE_PREV(name, type, field, attr) \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_PREV(struct type *elm) \ +{ \ + if (RB_LEFT(elm, field)) { \ + elm = RB_LEFT(elm, field); \ + while (RB_RIGHT(elm, field)) \ + elm = RB_RIGHT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} + +#define RB_GENERATE_MINMAX(name, type, field, attr) \ +attr struct type * \ name##_RB_MINMAX(struct name *head, int val) \ { \ struct type *tmp = RB_ROOT(head); \ @@ -666,7 +762,9 @@ name##_RB_MINMAX(struct name *head, int val) \ #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) #define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) #define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) @@ -675,4 +773,29 @@ name##_RB_MINMAX(struct name *head, int val) \ (x) != NULL; \ (x) = name##_RB_NEXT(x)) +#define RB_FOREACH_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_SAFE(x, name, head, y) \ + for ((x) = RB_MIN(name, head); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE(x, name, head) \ + for ((x) = RB_MAX(name, head); \ + (x) != NULL; \ + (x) = name##_RB_PREV(x)) + +#define RB_FOREACH_REVERSE_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ + for ((x) = RB_MAX(name, head); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + #endif /* _SYS_TREE_H_ */ diff --git a/common/utils/itti/timer.c b/common/utils/itti/timer.c index 683efd1279..9c742c19cc 100644 --- a/common/utils/itti/timer.c +++ b/common/utils/itti/timer.c @@ -95,8 +95,7 @@ int timer_handle_signal(siginfo_t *info) // LG: To many traces for msc timer: TMR_DEBUG("Timer with id 0x%lx has expired\n", (long)timer_p->timer); - printf("Timer with id 0x%lx has expired\n", (long)timer_p->timer); - + task_id = timer_p->task_id; instance = timer_p->instance; message_p = itti_alloc_new_message(TASK_TIMER, TIMER_HAS_EXPIRED); @@ -210,11 +209,6 @@ int timer_setup( type == TIMER_PERIODIC ? "periodic" : "single shot", *timer_id, interval_sec, interval_us); - printf("Requesting new %s timer with id 0x%lx that expires within " - "%d sec and %d usec\n", - type == TIMER_PERIODIC ? "periodic" : "single shot", - *timer_id, interval_sec, interval_us); - timer_p->timer = timer; /* Lock the queue and insert the timer at the tail */ diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index 7003a2c638..01eb61fc0b 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -40,6 +40,7 @@ #include "assertions.h" +//#define TEST_TIMER enb_agent_instance_t enb_agent[NUM_MAX_ENB_AGENT]; msg_context_t shared_ctxt[NUM_MAX_ENB_AGENT]; @@ -327,8 +328,10 @@ int enb_agent_stop(mid_t mod_id){ err_code_t enb_agent_timeout(void* args){ + // enb_agent_timer_args_t *timer_args = calloc(1, sizeof(*timer_args)); + //memcpy (timer_args, args, sizeof(*timer_args)); enb_agent_timer_args_t *timer_args = (enb_agent_timer_args_t *) args; - + LOG_I(ENB_AGENT, "enb_agent %d timeout\n", timer_args->mod_id); LOG_I(ENB_AGENT, "eNB action %d ENB flags %d \n", timer_args->cc_actions,timer_args->cc_report_flags); LOG_I(ENB_AGENT, "UE action %d UE flags %d \n", timer_args->ue_actions,timer_args->ue_report_flags); diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index c2653f4c85..70f1092bdd 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -312,25 +312,12 @@ int get_ue_wcqi (mid_t mod_id, mid_t ue_id) { //struct enb_agent_map agent_map; - -/* The timer_id might not be the best choice for the comparison */ -int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b){ - - //if (a->timer_id) return 0; - //if (b->timer_id) return 0; - - if (a->timer_id < b->timer_id) return -1; - if (a->timer_id > b->timer_id) return 1; - - // equal timers - return 0; -} - -RB_GENERATE(enb_agent_map,enb_agent_timer_element_s, entry, enb_agent_compare_timer); - +enb_agent_timer_instance_t timer_instance; err_code_t enb_agent_init_timer(void){ + + LOG_I(ENB_AGENT, "init RB tree\n"); - RB_INIT(&enb_agent_head); + RB_INIT(&timer_instance.enb_agent_head); /* struct enb_agent_timer_element_s e; @@ -340,6 +327,18 @@ err_code_t enb_agent_init_timer(void){ return PROTOCOL__PROGRAN_ERR__NO_ERR; } +RB_GENERATE(enb_agent_map,enb_agent_timer_element_s, entry, enb_agent_compare_timer); + +/* The timer_id might not be the best choice for the comparison */ +int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_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 enb_agent_create_timer(uint32_t interval_sec, uint32_t interval_usec, agent_id_t agent_id, @@ -349,7 +348,9 @@ err_code_t enb_agent_create_timer(uint32_t interval_sec, void* timer_args, long *timer_id){ - struct enb_agent_timer_element_s e; + struct enb_agent_timer_element_s *e = calloc(1, sizeof(*e)); + DevAssert(e != NULL); + //uint32_t timer_id; int ret=-1; @@ -368,7 +369,7 @@ err_code_t enb_agent_create_timer(uint32_t interval_sec, timer_args, timer_id); - e.type = TIMER_ONE_SHOT; + e->type = TIMER_ONE_SHOT; } else if (timer_type == ENB_AGENT_TIMER_TYPE_PERIODIC ){ ret = timer_setup(interval_sec, @@ -379,32 +380,25 @@ err_code_t enb_agent_create_timer(uint32_t interval_sec, timer_args, timer_id); - e.type = TIMER_PERIODIC; + e->type = TIMER_PERIODIC; } if (ret < 0 ) { return TIMER_SETUP_FAILED; } - e.agent_id = agent_id; - e.instance = instance; - e.state = ENB_AGENT_TIMER_STATE_ACTIVE; - e.timer_id = *timer_id; - e.timer_args = timer_args; - e.cb = cb; - - LOG_I(ENB_AGENT,"created a timer with id 0x%lx for agent %d, instance %d \n", - e.timer_id, e.agent_id, e.instance); - - RB_INSERT(enb_agent_map, &enb_agent_head, &e); + e->agent_id = agent_id; + e->instance = instance; + e->state = ENB_AGENT_TIMER_STATE_ACTIVE; + e->timer_id = *timer_id; + // e->timer_args = timer_args; + e->cb = cb; + /*element should be a real pointer*/ + RB_INSERT(enb_agent_map, &timer_instance.enb_agent_head, e); - - /* - struct enb_agent_timer_element_s search; - search.timer_id = *timer_id; - printf("search 1: %p (expected %p)\n", RB_FIND(enb_agent_map, &enb_agent_head, &search), &e); - printf("search 1: %p (expected %p)\n", get_timer_entry(e.timer_id), &e); - */ + LOG_I(ENB_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; } @@ -413,7 +407,7 @@ err_code_t enb_agent_destroy_timer(long timer_id){ struct enb_agent_timer_element_s *e = get_timer_entry(timer_id); if (e != NULL ) { - RB_REMOVE(enb_agent_map, &enb_agent_head, &e); + RB_REMOVE(enb_agent_map, &timer_instance.enb_agent_head, &e); free(e); } @@ -431,8 +425,8 @@ err_code_t enb_agent_destroy_timers(void){ struct enb_agent_timer_element_s *e = NULL; - RB_FOREACH(e, enb_agent_map, &enb_agent_head) { - RB_REMOVE(enb_agent_map, &enb_agent_head, e); + RB_FOREACH(e, enb_agent_map, &timer_instance.enb_agent_head) { + RB_REMOVE(enb_agent_map, &timer_instance.enb_agent_head, e); timer_remove(e->timer_id); free(e); } @@ -443,11 +437,10 @@ err_code_t enb_agent_destroy_timers(void){ struct enb_agent_timer_element_s * get_timer_entry(long timer_id) { - struct enb_agent_timer_element_s search, *e; - memset(&search, 0, sizeof(struct enb_agent_timer_element_s)); - search.timer_id = timer_id; - - return RB_FIND(enb_agent_map, &enb_agent_head, &search); + struct enb_agent_timer_element_s *search= calloc(1,sizeof(*search)); + search->timer_id = timer_id; + + return RB_FIND(enb_agent_map, &timer_instance.enb_agent_head, search); } /* diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index eb3de96145..662ea73ed7 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -189,10 +189,13 @@ typedef struct enb_agent_timer_element_s{ long timer_id; /* Timer id returned by the timer API*/ enb_agent_timer_callback_t cb; - void* timer_args; + // void* timer_args; } enb_agent_timer_element_t; +typedef struct enb_agent_timer_instance_s{ + RB_HEAD(enb_agent_map, enb_agent_timer_element_s) enb_agent_head; +}enb_agent_timer_instance_t; err_code_t enb_agent_init_timer(void); @@ -214,11 +217,11 @@ err_code_t enb_agent_restart_timer(long *timer_id); struct enb_agent_timer_element_s * get_timer_entry(long timer_id); -int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b); + err_code_t enb_agent_process_timeout(long timer_id, void* timer_args); -RB_HEAD(enb_agent_map, enb_agent_timer_element_s) enb_agent_head; +int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b); /* RB_PROTOTYPE is for .h files */ RB_PROTOTYPE(enb_agent_map, enb_agent_timer_element_s, entry, enb_agent_compare_timer); diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 27536c8b7f..1b8457d474 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -141,15 +141,15 @@ void * enb_agent_send_message(xid_t xid, err_code_t enb_agent_process_timeout(long timer_id, void* timer_args){ - struct enb_agent_timer_element_s *e = get_timer_entry(timer_id); + struct enb_agent_timer_element_s *found = get_timer_entry(timer_id); + + if (found == NULL ) goto error; + LOG_I(ENB_AGENT, "Found the entry (%p): timer_id is 0x%lx 0x%lx\n", found, timer_id, found->timer_id); - LOG_I(ENB_AGENT, "element %p: timer_id is 0x%lx 0x%lx\n", e, timer_id, e->timer_id); - - if (e == NULL ) goto error; if (timer_args == NULL) LOG_W(ENB_AGENT,"null timer args\n"); - return e->cb(timer_args); + return found->cb(timer_args); error: From 99cf3b654ab8b4a42fac031bdac116f98b8247cc Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 5 Jan 2016 21:30:55 +0200 Subject: [PATCH 048/413] Added functions to get the current frame and subframe --- openair2/ENB_APP/enb_agent_common.c | 12 ++++++++++++ openair2/ENB_APP/enb_agent_common.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 70f1092bdd..c1d65f95cc 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -282,6 +282,18 @@ int get_current_time_ms (mid_t mod_id, int subframe_flag){ } +int get_current_frame (mid_t mod_id) { + + return ((eNB_MAC_INST *)enb[mod_id])->frame; + +} + +int get_current_subframe (mid_t mod_id) { + + return ((eNB_MAC_INST *)enb[mod_id])->subframe; + +} + int get_num_ues (mid_t mod_id){ return ((UE_list_t *)enb_ue[mod_id])->num_UEs; diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 662ea73ed7..ca5aafbfdd 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -104,6 +104,10 @@ void set_enb_vars(mid_t mod_id, ran_name_t ran); int get_current_time_ms (mid_t mod_id, int subframe_flag); +int get_current_frame(mid_t mod_id); + +int get_current_subframe(mid_t mod_id); + int get_num_ues(mid_t mod_id); int get_ue_crnti (mid_t mod_id, mid_t ue_id); From 3bc88cfd11b581bcd1ab1615b377cf8734b91fc9 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 5 Jan 2016 21:52:05 +0200 Subject: [PATCH 049/413] Fixed agent to support proper frame and subframe reporting in progRAN messages --- openair2/ENB_APP/enb_agent_common.c | 11 +++++++++++ openair2/ENB_APP/enb_agent_common.h | 4 ++++ openair2/ENB_APP/enb_agent_mac.c | 6 +++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index c1d65f95cc..c719777aaf 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -294,6 +294,17 @@ int get_current_subframe (mid_t mod_id) { } +uint16_t get_sfn_sf (mid_t mod_id) { + + uint16_t frame, subframe; + uint16_t sfn_sf; + + frame = (uint16_t) get_current_frame(mod_id); + subframe = (uint16_t) get_current_subframe(mod_id); + sfn_sf = (frame << 12) | subframe; + return sfn_sf; +} + int get_num_ues (mid_t mod_id){ return ((UE_list_t *)enb_ue[mod_id])->num_UEs; diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index ca5aafbfdd..9c5f4044fa 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -108,6 +108,10 @@ int get_current_frame(mid_t mod_id); int get_current_subframe(mid_t mod_id); +/*Return the frame and subframe number in compact 16-bit format. + Bits 0-3 frame, rest for subframe. Required by progRAN protocol*/ +uint16_t get_sfn_sf (mid_t mod_id); + int get_num_ues(mid_t mod_id); int get_ue_crnti (mid_t mod_id, mid_t ue_id); diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index edf1406296..4801d21686 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -296,7 +296,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, goto error; protocol__prp_dl_cqi_report__init(dl_report); //TODO:Set the SFN and SF of the last report held in the agent. - dl_report->sfn_sn = get_current_time_ms(enb_id, 1); + dl_report->sfn_sn = get_sfn_sf(enb_id); dl_report->has_sfn_sn = 1; //TODO:Set the number of DL CQI reports for this UE. One for each CC dl_report->n_csi_report = 1; @@ -391,7 +391,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, goto error; protocol__prp_ul_cqi_report__init(full_ul_report); //TODO:Set the SFN and SF of the generated report - full_ul_report->sfn_sn = 100; + full_ul_report->sfn_sn = 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 @@ -461,7 +461,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, goto error; protocol__prp_noise_interference_report__init(ni_report); // Current frame and subframe number - ni_report->sfn_sf = 0; + ni_report->sfn_sf = get_sfn_sf(enb_id); ni_report->has_sfn_sf = 1; // Received interference power in dbm ni_report->rip = 0; From e0c459be755f002e81bbefb0a8a78ee38d3b87ba Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 6 Jan 2016 11:57:03 +0200 Subject: [PATCH 050/413] Changed handlers not to require the xid in their signature. Containted in the received message, or generated in them --- openair2/ENB_APP/enb_agent.c | 4 ++-- openair2/ENB_APP/enb_agent_common.c | 16 +++++++++++++--- openair2/ENB_APP/enb_agent_common.h | 13 +++++-------- openair2/ENB_APP/enb_agent_handler.c | 6 ++---- openair2/ENB_APP/enb_agent_mac.c | 4 +++- openair2/ENB_APP/enb_agent_mac.h | 2 +- 6 files changed, 26 insertions(+), 19 deletions(-) diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index 01eb61fc0b..3c9ad7d24d 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -140,7 +140,7 @@ void *receive_thread(void *args) { LOG_D(ENB_AGENT,"received message with size %d\n", size); - msg=enb_agent_handle_message(d->mod_id, d->rx_xid, data, size); + msg=enb_agent_handle_message(d->mod_id, data, size); free(data); @@ -149,7 +149,7 @@ void *receive_thread(void *args) { // check if there is something to send back to the controller if (msg != NULL){ - data=enb_agent_send_message(d->tx_xid,msg,&size); + data=enb_agent_send_message(msg,&size); if (message_put(d->tx_mq, data, size, priority)){ err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index c719777aaf..0fe2c8e1ac 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -102,9 +102,11 @@ int prp_create_header(xid_t xid, Protocol__PrpType type, Protocol__PrpHeader ** } -int enb_agent_hello(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg) { +int enb_agent_hello(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { Protocol__PrpHeader *header; + /*TODO: Need to set random xid or xid from received hello message*/ + xid_t xid = 1; if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_HELLO, &header) != 0) goto error; @@ -154,8 +156,10 @@ int enb_agent_destroy_hello(Protocol__ProgranMessage *msg) { } -int enb_agent_echo_request(mid_t mod_id, xid_t xid, const void* params, Protocol__ProgranMessage **msg) { +int enb_agent_echo_request(mid_t mod_id, const void* params, Protocol__ProgranMessage **msg) { Protocol__PrpHeader *header; + /*TODO: Need to set a random xid*/ + xid_t xid = 1; if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REQUEST, &header) != 0) goto error; @@ -203,7 +207,13 @@ int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg) { -int enb_agent_echo_reply(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg) { +int enb_agent_echo_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { + + xid_t xid; + Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; + Protocol__PrpEchoRequest *echo_req = input->echo_request_msg; + xid = (echo_req->header)->xid; + Protocol__PrpHeader *header; if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REPLY, &header) != 0) goto error; diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 9c5f4044fa..f918914f92 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -58,8 +58,7 @@ typedef int (*enb_agent_message_decoded_callback)( mid_t mod_id, - xid_t xid, - const void *params, + const void *params, Protocol__ProgranMessage **msg ); @@ -72,23 +71,21 @@ int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage int prp_create_header(xid_t xid, Protocol__PrpType type, Protocol__PrpHeader **header); -int enb_agent_hello(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_hello(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); int enb_agent_destroy_hello(Protocol__ProgranMessage *msg); -int enb_agent_echo_request(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_echo_request(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg); -int enb_agent_echo_reply(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_echo_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg); Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, - xid_t xid, uint8_t *data, uint32_t size); -void * enb_agent_send_message(xid_t xid, - Protocol__ProgranMessage *msg, +void * enb_agent_send_message(Protocol__ProgranMessage *msg, uint32_t * size); diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 1b8457d474..8c2b9e010a 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -68,7 +68,6 @@ static const char *enb_agent_direction2String[] = { Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, - xid_t xid, uint8_t *data, uint32_t size){ @@ -93,7 +92,7 @@ Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, } - err_code = ((*messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1])(mod_id, xid, (void *) decoded_message, &reply_message)); + err_code = ((*messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1])(mod_id, (void *) decoded_message, &reply_message)); if ( err_code < 0 ){ goto error; } @@ -110,8 +109,7 @@ error: -void * enb_agent_send_message(xid_t xid, - Protocol__ProgranMessage *msg, +void * enb_agent_send_message(Protocol__ProgranMessage *msg, uint32_t * size){ void * buffer; diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 4801d21686..d2504e4dec 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -38,7 +38,7 @@ #include "log.h" -int enb_agent_mac_handle_stats(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg){ +int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg){ // TODO: Must deal with sanitization of input // TODO: Must check if RNTIs and cell ids of the request actually exist @@ -47,6 +47,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, xid_t xid, const void *params, Prot void *buffer; int size; err_code_t err_code; + xid_t xid; //TODO: We do not deal with multiple CCs at the moment and eNB id is 0 int cc_id = 0; @@ -63,6 +64,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, xid_t xid, const void *params, Prot Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; Protocol__PrpStatsRequest *stats_req = input->stats_request_msg; + xid = (stats_req->header)->xid; // Check the type of request that is made switch(stats_req->body_case) { diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index 6584111825..569eb51e5e 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -70,7 +70,7 @@ typedef struct { } report_config_t; -int enb_agent_mac_handle_stats(mid_t mod_id, xid_t xid, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); int enb_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *report_config, Protocol__ProgranMessage **msg); From e78075e8310de179176db94aa6ae0be7746d872d Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 6 Jan 2016 16:22:59 +0200 Subject: [PATCH 051/413] Integrated task manager with system frame and subframe clock and added support for one task queue per eNB --- openair2/ENB_APP/enb_agent_task_manager.c | 51 +++++++++++++---------- openair2/ENB_APP/enb_agent_task_manager.h | 14 ++++--- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_task_manager.c b/openair2/ENB_APP/enb_agent_task_manager.c index 0b987f1c22..e2c31319e4 100644 --- a/openair2/ENB_APP/enb_agent_task_manager.c +++ b/openair2/ENB_APP/enb_agent_task_manager.c @@ -40,6 +40,7 @@ #include #include "enb_agent_task_manager.h" +#include "enb_agent_common.c" /* Util macros */ @@ -74,8 +75,8 @@ void enb_agent_task_destroy(enb_agent_task_t *task) { free(task); } -enb_agent_task_queue_t *enb_agent_task_queue_init(size_t capacity, - int (*cmp)(const enb_agent_task_t *t1, const enb_agent_task_t *t2)) { +enb_agent_task_queue_t *enb_agent_task_queue_init(mid_t mod_id, size_t capacity, + int (*cmp)(mid_t mod_id, const enb_agent_task_t *t1, const enb_agent_task_t *t2)) { enb_agent_task_queue_t *queue = NULL; queue = malloc(sizeof(enb_agent_task_queue_t)); @@ -88,6 +89,8 @@ enb_agent_task_queue_t *enb_agent_task_queue_init(size_t capacity, else queue->cmp = cmp; + queue->mod_id = mod_id; + queue->first_frame = 0; queue->first_subframe = 0; @@ -115,8 +118,8 @@ enb_agent_task_queue_t *enb_agent_task_queue_init(size_t capacity, return NULL; } -enb_agent_task_queue_t *enb_agent_task_queue_default_init() { - return enb_agent_task_queue_init(DEFAULT_CAPACITY, NULL); +enb_agent_task_queue_t *enb_agent_task_queue_default_init(mid_t mod_id) { + return enb_agent_task_queue_init(mod_id, DEFAULT_CAPACITY, NULL); } void enb_agent_task_queue_destroy(enb_agent_task_queue_t *queue) { @@ -157,7 +160,7 @@ int enb_agent_task_queue_put(enb_agent_task_queue_t *queue, enb_agent_task_t *ta i = queue->count; queue->count++; /*Swap elements to maintain heap properties*/ - while(i > 0 && queue->cmp(queue->task[i], queue->task[PARENT(i)]) > 0) { + while(i > 0 && queue->cmp(queue->mod_id, queue->task[i], queue->task[PARENT(i)]) > 0) { tmp = queue->task[i]; queue->task[i] = queue->task[PARENT(i)]; queue->task[PARENT(i)] = tmp; @@ -178,11 +181,6 @@ int enb_agent_task_queue_put(enb_agent_task_queue_t *queue, enb_agent_task_t *ta int enb_agent_task_queue_get_current_task(enb_agent_task_queue_t *queue, enb_agent_task_t **task) { int err_code; - - /*TODO*/ - /* Find current frame and subframe number */ - uint16_t curr_frame=1; - uint8_t curr_subframe=1; if (pthread_mutex_lock(queue->mutex)) { /*TODO*/ @@ -195,6 +193,11 @@ int enb_agent_task_queue_get_current_task(enb_agent_task_queue_t *queue, enb_age err_code = HEAP_EMPTY; goto error; } + + /* Find current frame and subframe number */ + uint16_t curr_frame=get_current_frame(queue->mod_id); + uint8_t curr_subframe=get_current_subframe(queue->mod_id); + /* If no task is scheduled for the current subframe, return without any task */ if(queue->task[0]->frame_num != curr_frame || queue->task[0]->subframe_num != curr_subframe) { *task = NULL; @@ -206,7 +209,16 @@ int enb_agent_task_queue_get_current_task(enb_agent_task_queue_t *queue, enb_age queue->count--; /* Restore heap property */ _enb_agent_task_queue_heapify(queue, 0); - + + /*If queue has no element*/ + if (queue->count < 1) { + queue->first_frame = 0; + queue->first_subframe = 0; + } else { + queue->first_frame = queue->task[0]->frame_num; + queue->first_subframe = queue->task[0]->subframe_num; + } + if (pthread_mutex_unlock(queue->mutex)) { // LOG_E(MAC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); exit(1); @@ -228,14 +240,14 @@ void _enb_agent_task_queue_heapify(enb_agent_task_queue_t *queue, size_t idx) { r_idx = RIGHT(idx); /* Left child exists, compare left child with its parent */ - if (l_idx < queue->count && queue->cmp(queue->task[l_idx], queue->task[idx]) > 0) { + if (l_idx < queue->count && queue->cmp(queue->mod_id, queue->task[l_idx], queue->task[idx]) > 0) { lrg_idx = l_idx; } else { lrg_idx = idx; } /* Right child exists, compare right child with the largest element */ - if (r_idx < queue->count && queue->cmp(queue->task[r_idx], queue->task[lrg_idx]) > 0) { + if (r_idx < queue->count && queue->cmp(queue->mod_id, queue->task[r_idx], queue->task[lrg_idx]) > 0) { lrg_idx = r_idx; } @@ -266,12 +278,12 @@ int _enb_agent_task_queue_realloc_heap(enb_agent_task_queue_t *queue) { return HEAP_NOREALLOC; } -int _enb_agent_task_queue_cmp(const enb_agent_task_t *t1, const enb_agent_task_t *t2) { +int _enb_agent_task_queue_cmp(mid_t mod_id, const enb_agent_task_t *t1, const enb_agent_task_t *t2) { if ((t1->frame_num == t2->frame_num) && (t1->subframe_num == t2->subframe_num)) return 0; - /* TODO: need to get current frame and subframe number */ - uint16_t curr_frame = 0; - uint8_t curr_subframe = 7; + + uint16_t curr_frame = get_current_frame(mod_id); + uint8_t curr_subframe = get_current_subframe(mod_id); int f_offset, sf_offset, tmp1, tmp2; @@ -296,8 +308,3 @@ int _enb_agent_task_queue_cmp(const enb_agent_task_t *t1, const enb_agent_task_t to be the only comparisson parameter in all other cases */ return f_offset*100 + sf_offset; } - - -int main(int argc, char **argv) { - return 0; -} diff --git a/openair2/ENB_APP/enb_agent_task_manager.h b/openair2/ENB_APP/enb_agent_task_manager.h index 5a3b5eb327..ef60152b27 100644 --- a/openair2/ENB_APP/enb_agent_task_manager.h +++ b/openair2/ENB_APP/enb_agent_task_manager.h @@ -43,6 +43,8 @@ #include "progran.pb-c.h" +#include "enb_agent_common.h" + #ifdef __cplusplus extern "C" { #endif @@ -65,6 +67,7 @@ typedef struct enb_agent_task_s { * Priority Queue Structure for tasks */ typedef struct enb_agent_task_queue_s { + mid_t mod_id; /* The amount of allocated memory for agent tasks in the heap*/ volatile size_t capacity; /* The actual size of the tasks heap at a certain time */ @@ -76,7 +79,7 @@ typedef struct enb_agent_task_queue_s { /* An array of prioritized tasks stored in a heap */ enb_agent_task_t **task; /* A pointer to a comparator function, used to prioritize elements */ - int (*cmp)(const enb_agent_task_t *t1, const enb_agent_task_t *t2); + int (*cmp)(mid_t mod_id, const enb_agent_task_t *t1, const enb_agent_task_t *t2); pthread_mutex_t *mutex; } enb_agent_task_queue_t; @@ -103,13 +106,13 @@ void enb_agent_task_destroy(enb_agent_task_t *task); /** * Allocate initial memory for storing the tasks */ -enb_agent_task_queue_t *enb_agent_task_queue_init(size_t capacity, - int (*cmp)(const enb_agent_task_t *t1, const enb_agent_task_t *t2)); + enb_agent_task_queue_t *enb_agent_task_queue_init(mid_t mod_id, size_t capacity, + int (*cmp)(mid_t mod_id, const enb_agent_task_t *t1, const enb_agent_task_t *t2)); /** * Allocate initial memory for storing the tasks using default parameters */ -enb_agent_task_queue_t *enb_agent_task_queue_default_init(); +enb_agent_task_queue_t *enb_agent_task_queue_default_init(mid_t mod_id); /** * De-allocate memory for the tasks queue @@ -148,8 +151,9 @@ int _enb_agent_task_queue_realloc_heap(enb_agent_task_queue_t *queue); * returns 0 if tasks t1, t2 have the same priority * return negative value if t1 needs to be executed after t2 * return positive value if t1 preceeds t2 + * Need to give eNB id for the comparisson based on the current frame-subframe */ -int _enb_agent_task_queue_cmp(const enb_agent_task_t *t1, const enb_agent_task_t *t2); + int _enb_agent_task_queue_cmp(mid_t mod_id, const enb_agent_task_t *t1, const enb_agent_task_t *t2); #ifdef __cplusplus } From e88779c4ef7c265c32d73f83ca7ba3ca78821638 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 6 Jan 2016 18:06:48 +0200 Subject: [PATCH 052/413] Added support for lightweight finegrained task timer --- openair2/ENB_APP/enb_agent.c | 30 ++++++++++++++++++++++------- openair2/ENB_APP/enb_agent_common.c | 9 +++++++++ openair2/ENB_APP/enb_agent_common.h | 4 ++++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index 3c9ad7d24d..e8a4466b26 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -50,7 +50,7 @@ enb_agent_info_t enb_agent_info; char in_ip[40]; static uint16_t in_port; -//void *send_thread(void *args); +void *send_thread(void *args); void *receive_thread(void *args); pthread_t new_thread(void *(*f)(void *), void *b); err_code_t enb_agent_timeout(void* args); @@ -100,20 +100,35 @@ void *enb_agent_task(void *args){ return NULL; } -/* + void *send_thread(void *args) { +#ifdef TEST_TIMER + msg_context_t *d = args; void *data; int size; int priority; - - while (1) { + struct timeval t1, t2; + long long t; + struct timespec ts; + unsigned int delay = 250*1000; + while(1) { + gettimeofday(&t1, NULL); + enb_agent_sleep_until(&ts, delay); + gettimeofday(&t2, NULL); + t = ((t2.tv_sec * 1000000) + t2.tv_usec) - ((t1.tv_sec * 1000000) + t1.tv_usec); + LOG_I(ENB_AGENT, "Call to sleep_until(%d) took %lld us\n", delay, t); + sleep(1); + } + +#endif + /* while (1) { // need logic for the timer, and usleep(10); if (message_put(d->tx_mq, data, size, priority)) goto error; - } + }*/ return NULL; @@ -121,7 +136,7 @@ error: printf("receive_thread: there was an error\n"); return NULL; } -*/ + void *receive_thread(void *args) { msg_context_t *d = args; @@ -293,9 +308,10 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ enb_agent_create_timer(1, 0, ENB_AGENT_DEFAULT, mod_id, ENB_AGENT_TIMER_TYPE_PERIODIC, enb_agent_timeout,(void*)&timer_args, &timer_id); #endif - // new_thread(send_thread, &shared_ctxt); + new_thread(send_thread, &shared_ctxt); //while (1) pause(); + LOG_I(ENB_AGENT,"client ends\n"); return 0; diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 0fe2c8e1ac..490658c671 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -476,6 +476,15 @@ struct enb_agent_timer_element_s * get_timer_entry(long timer_id) { return RB_FIND(enb_agent_map, &timer_instance.enb_agent_head, search); } +void enb_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); +} + /* int i =0; RB_FOREACH(e, enb_agent_map, &enb_agent_head) { diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index f918914f92..d12d3849ec 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -39,6 +39,7 @@ #ifndef ENB_AGENT_COMMON_H_ #define ENB_AGENT_COMMON_H_ +#include #include "header.pb-c.h" #include "progran.pb-c.h" @@ -228,6 +229,9 @@ err_code_t enb_agent_process_timeout(long timer_id, void* timer_args); int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b); +/*Specify a delay in nanoseconds to timespec and sleep until then*/ +void enb_agent_sleep_until(struct timespec *ts, int delay); + /* RB_PROTOTYPE is for .h files */ RB_PROTOTYPE(enb_agent_map, enb_agent_timer_element_s, entry, enb_agent_compare_timer); From 11b2f829367c39ab7479a0b410cd62e773d24117 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 7 Jan 2016 17:41:51 +0200 Subject: [PATCH 053/413] Integrated timer to work with periodic report messages and agent tasks --- openair2/ENB_APP/enb_agent.c | 104 ++++++++++------- openair2/ENB_APP/enb_agent_common.c | 2 +- openair2/ENB_APP/enb_agent_common.h | 16 +-- openair2/ENB_APP/enb_agent_handler.c | 24 +++- openair2/ENB_APP/enb_agent_mac.c | 169 +++++++++++++++++++++++++-- openair2/ENB_APP/enb_agent_mac.h | 13 +++ 6 files changed, 263 insertions(+), 65 deletions(-) diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index e8a4466b26..dbefc60502 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -53,7 +53,7 @@ static uint16_t in_port; void *send_thread(void *args); void *receive_thread(void *args); pthread_t new_thread(void *(*f)(void *), void *b); -err_code_t enb_agent_timeout(void* args); +Protocol__ProgranMessage *enb_agent_timeout(void* args); /* * enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller @@ -61,6 +61,13 @@ err_code_t enb_agent_timeout(void* args); */ void *enb_agent_task(void *args){ + msg_context_t *d = (msg_context_t *) args; + Protocol__ProgranMessage *msg; + void *data; + int size; + err_code_t err_code; + int priority; + MessageDef *msg_p = NULL; const char *msg_name = NULL; instance_t instance; @@ -86,7 +93,15 @@ void *enb_agent_task(void *args){ break; case TIMER_HAS_EXPIRED: - enb_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, &msg_p->ittiMsg.timer_has_expired.arg); + msg = enb_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, msg_p->ittiMsg.timer_has_expired.arg); + if (msg != NULL){ + data=enb_agent_send_message(msg,&size); + if (message_put(d->tx_mq, data, size, priority)){ + err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + goto error; + } + LOG_D(ENB_AGENT,"sent message with size %d\n", size); + } break; default: @@ -96,46 +111,49 @@ void *enb_agent_task(void *args){ result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + continue; + error: + LOG_E(ENB_AGENT,"enb_agent_task: error %d occured\n",err_code); } while (1); return NULL; } -void *send_thread(void *args) { +/* void *send_thread(void *args) { */ -#ifdef TEST_TIMER +/* #ifdef TEST_TIMER */ - msg_context_t *d = args; - void *data; - int size; - int priority; +/* msg_context_t *d = args; */ +/* void *data; */ +/* int size; */ +/* int priority; */ - struct timeval t1, t2; - long long t; - struct timespec ts; - unsigned int delay = 250*1000; - while(1) { - gettimeofday(&t1, NULL); - enb_agent_sleep_until(&ts, delay); - gettimeofday(&t2, NULL); - t = ((t2.tv_sec * 1000000) + t2.tv_usec) - ((t1.tv_sec * 1000000) + t1.tv_usec); - LOG_I(ENB_AGENT, "Call to sleep_until(%d) took %lld us\n", delay, t); - sleep(1); - } +/* struct timeval t1, t2; */ +/* long long t; */ +/* struct timespec ts; */ +/* unsigned int delay = 250*1000; */ +/* while(1) { */ +/* gettimeofday(&t1, NULL); */ +/* enb_agent_sleep_until(&ts, delay); */ +/* gettimeofday(&t2, NULL); */ +/* t = ((t2.tv_sec * 1000000) + t2.tv_usec) - ((t1.tv_sec * 1000000) + t1.tv_usec); */ +/* LOG_I(ENB_AGENT, "Call to sleep_until(%d) took %lld us\n", delay, t); */ +/* sleep(1); */ +/* } */ -#endif - /* while (1) { - // need logic for the timer, and - usleep(10); - if (message_put(d->tx_mq, data, size, priority)) goto error; - }*/ +/* #endif */ +/* /\* while (1) { */ +/* // need logic for the timer, and */ +/* usleep(10); */ +/* if (message_put(d->tx_mq, data, size, priority)) goto error; */ +/* }*\/ */ - return NULL; +/* return NULL; */ -error: - printf("receive_thread: there was an error\n"); - return NULL; -} +/* error: */ +/* printf("receive_thread: there was an error\n"); */ +/* return NULL; */ +/* } */ void *receive_thread(void *args) { @@ -290,25 +308,25 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ * start the enb agent task for tx and interaction with the underlying network function */ - if (itti_create_task (TASK_ENB_AGENT, enb_agent_task, NULL) < 0) { + if (itti_create_task (TASK_ENB_AGENT, enb_agent_task, (void *) &shared_ctxt[mod_id]) < 0) { LOG_E(ENB_AGENT, "Create task for eNB Agent failed\n"); return -1; } -#ifdef TEST_TIMER + //#ifdef TEST_TIMER long timer_id=0; enb_agent_timer_args_t timer_args; memset (&timer_args, 0, sizeof(enb_agent_timer_args_t)); timer_args.mod_id = mod_id; - timer_args.cc_actions= ENB_AGENT_ACTION_APPLY; - timer_args.cc_report_flags = PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE; - timer_args.ue_actions = ENB_AGENT_ACTION_SEND; - timer_args.ue_report_flags = PROTOCOL__PRP_UE_STATS_TYPE__PRUST_BSR | PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI; + //timer_args.cc_actions= ENB_AGENT_ACTION_APPLY; + //timer_args.cc_report_flags = PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE; + //timer_args.ue_actions = ENB_AGENT_ACTION_SEND; + //timer_args.ue_report_flags = PROTOCOL__PRP_UE_STATS_TYPE__PRUST_BSR | PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI; enb_agent_create_timer(1, 0, ENB_AGENT_DEFAULT, mod_id, ENB_AGENT_TIMER_TYPE_PERIODIC, enb_agent_timeout,(void*)&timer_args, &timer_id); -#endif + //#endif - new_thread(send_thread, &shared_ctxt); + //new_thread(send_thread, &shared_ctxt); //while (1) pause(); @@ -342,15 +360,15 @@ int enb_agent_stop(mid_t mod_id){ -err_code_t enb_agent_timeout(void* args){ +Protocol__ProgranMessage *enb_agent_timeout(void* args){ // enb_agent_timer_args_t *timer_args = calloc(1, sizeof(*timer_args)); //memcpy (timer_args, args, sizeof(*timer_args)); enb_agent_timer_args_t *timer_args = (enb_agent_timer_args_t *) args; LOG_I(ENB_AGENT, "enb_agent %d timeout\n", timer_args->mod_id); - LOG_I(ENB_AGENT, "eNB action %d ENB flags %d \n", timer_args->cc_actions,timer_args->cc_report_flags); - LOG_I(ENB_AGENT, "UE action %d UE flags %d \n", timer_args->ue_actions,timer_args->ue_report_flags); + //LOG_I(ENB_AGENT, "eNB action %d ENB flags %d \n", timer_args->cc_actions,timer_args->cc_report_flags); + //LOG_I(ENB_AGENT, "UE action %d UE flags %d \n", timer_args->ue_actions,timer_args->ue_report_flags); - return 0; + return NULL; } diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 490658c671..0417f4956e 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -311,7 +311,7 @@ uint16_t get_sfn_sf (mid_t mod_id) { frame = (uint16_t) get_current_frame(mod_id); subframe = (uint16_t) get_current_subframe(mod_id); - sfn_sf = (frame << 12) | subframe; + sfn_sf = (subframe << 12) | frame; return sfn_sf; } diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index d12d3849ec..31d882d0c9 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -86,6 +86,8 @@ Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, uint8_t *data, uint32_t size); +Protocol__ProgranMessage *enb_agent_handle_timed_task(void *args); + void * enb_agent_send_message(Protocol__ProgranMessage *msg, uint32_t * size); @@ -107,7 +109,7 @@ int get_current_frame(mid_t mod_id); int get_current_subframe(mid_t mod_id); /*Return the frame and subframe number in compact 16-bit format. - Bits 0-3 frame, rest for subframe. Required by progRAN protocol*/ + Bits 0-3 subframe, rest for frame. Required by progRAN protocol*/ uint16_t get_sfn_sf (mid_t mod_id); int get_num_ues(mid_t mod_id); @@ -137,7 +139,7 @@ int get_ue_wcqi (mid_t mod_id, mid_t ue_id); /* Type of the callback executed when the timer expired */ -typedef err_code_t (*enb_agent_timer_callback_t)(void*); +typedef Protocol__ProgranMessage *(*enb_agent_timer_callback_t)(void*); typedef enum { /* oneshot timer: */ @@ -169,13 +171,7 @@ typedef enum { typedef struct enb_agent_timer_args_s{ mid_t mod_id; - - agent_action_t cc_actions; - uint32_t cc_report_flags; - - agent_action_t ue_actions; - uint32_t ue_report_flags; - + Protocol__ProgranMessage *msg; } enb_agent_timer_args_t; @@ -225,7 +221,7 @@ struct enb_agent_timer_element_s * get_timer_entry(long timer_id); -err_code_t enb_agent_process_timeout(long timer_id, void* timer_args); +Protocol__ProgranMessage * enb_agent_process_timeout(long timer_id, void* timer_args); int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b); diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 8c2b9e010a..2841f9b6e5 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -133,11 +133,28 @@ void * enb_agent_send_message(Protocol__ProgranMessage *msg, error : LOG_E(ENB_AGENT,"errno %d occured\n",err_code); - return NULL; - + return NULL; } -err_code_t enb_agent_process_timeout(long timer_id, void* timer_args){ +Protocol__ProgranMessage *enb_agent_handle_timed_task(void *args) { + err_code_t err_code; + enb_agent_timer_args_t *timer_args = (enb_agent_timer_args_t *) args; + + Protocol__ProgranMessage *timed_task, *reply_message; + timed_task = timer_args->msg; + err_code = ((*messages_callback[timed_task->msg_case-1][timed_task->msg_dir-1])(timer_args->mod_id, (void *) timed_task, &reply_message)); + if ( err_code < 0 ){ + goto error; + } + + return reply_message; + + error: + LOG_E(ENB_AGENT,"errno %d occured\n",err_code); + return NULL; +} + +Protocol__ProgranMessage* enb_agent_process_timeout(long timer_id, void* timer_args){ struct enb_agent_timer_element_s *found = get_timer_entry(timer_id); @@ -148,7 +165,6 @@ err_code_t enb_agent_process_timeout(long timer_id, void* timer_args){ LOG_W(ENB_AGENT,"null timer args\n"); return found->cb(timer_args); - error: LOG_E(ENB_AGENT, "can't get the timer element\n"); diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index d2504e4dec..1a21db5e15 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -48,6 +48,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr int size; 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 cc_id = 0; @@ -70,12 +71,13 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr switch(stats_req->body_case) { case PROTOCOL__PRP_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ; Protocol__PrpCompleteStatsRequest *comp_req = stats_req->complete_stats_request; - if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_PERIODICAL) { - //TODO: Must create a periodic report. Implement once the - // timer functionality is supported - *msg = NULL; - return 0; - } else if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_CONTINUOUS) { + /* if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_PERIODICAL) { */ + /* //TODO: Must create a periodic report. Implement once the */ + /* // timer functionality is supported */ + /* *msg = NULL; */ + /* return 0; */ + /* } else */ + if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_CONTINUOUS) { //TODO: Must create an event based report mechanism *msg = NULL; return 0; @@ -83,7 +85,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr //TODO: Must implement to deactivate the event based reporting *msg = NULL; return 0; - } else { //One-off reporting + } else { //One-off or periodical reporting //Set the proper flags ue_flags = comp_req->ue_report_flags; c_flags = comp_req->cell_report_flags; @@ -114,6 +116,33 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr 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__PRP_STATS_REPORT_FREQ__PRSRF_PERIODICAL) { + /* Create a one off progran message as an argument for the periodical task */ + Protocol__ProgranMessage *timer_msg; + stats_request_config_t request_config; + request_config.report_type = PROTOCOL__PRP_STATS_TYPE__PRST_COMPLETE_STATS; + request_config.report_frequency = PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_ONCE; + request_config.period = 0; + request_config.config = &report_config; + enb_agent_mac_stats_request(enb_id, xid, &request_config, &timer_msg); + /* Create a timer */ + long timer_id = 0; + enb_agent_timer_args_t *timer_args; + timer_args = malloc(sizeof(enb_agent_timer_args_t)); + memset (timer_args, 0, sizeof(enb_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); + } + enb_agent_create_timer(sec_interval, usec_interval, ENB_AGENT_DEFAULT, enb_id, ENB_AGENT_TIMER_TYPE_PERIODIC, enb_agent_handle_timed_task,(void*) timer_args, &timer_id); + } } break; case PROTOCOL__PRP_STATS_REQUEST__BODY_CELL_STATS_REQUEST:; @@ -172,6 +201,132 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr return err_code; } +int enb_agent_mac_stats_request(mid_t mod_id, + xid_t xid, + const stats_request_config_t *report_config, + Protocol__ProgranMessage **msg) { + Protocol__PrpHeader *header; + int i; + + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_STATS_REQUEST, &header) != 0) + goto error; + + Protocol__PrpStatsRequest *stats_request_msg; + stats_request_msg = malloc(sizeof(Protocol__PrpStatsRequest)); + if(stats_request_msg == NULL) + goto error; + + protocol__prp_stats_request__init(stats_request_msg); + 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__PRP_STATS_TYPE__PRST_COMPLETE_STATS: + stats_request_msg->body_case = PROTOCOL__PRP_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST; + Protocol__PrpCompleteStatsRequest *complete_stats; + complete_stats = malloc(sizeof(Protocol__PrpCompleteStatsRequest)); + if(complete_stats == NULL) + goto error; + protocol__prp_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__PRP_STATS_TYPE__PRST_CELL_STATS: + stats_request_msg->body_case = PROTOCOL__PRP_STATS_REQUEST__BODY_CELL_STATS_REQUEST; + Protocol__PrpCellStatsRequest *cell_stats; + cell_stats = malloc(sizeof(Protocol__PrpCellStatsRequest)); + if(cell_stats == NULL) + goto error; + protocol__prp_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__PRP_STATS_TYPE__PRST_UE_STATS: + stats_request_msg->body_case = PROTOCOL__PRP_STATS_REQUEST__BODY_UE_STATS_REQUEST; + Protocol__PrpUeStatsRequest *ue_stats; + ue_stats = malloc(sizeof(Protocol__PrpUeStatsRequest)); + if(ue_stats == NULL) + goto error; + protocol__prp_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__ProgranMessage)); + if(*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_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 enb_agent_mac_destroy_stats_request(Protocol__ProgranMessage *msg) { + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG) + goto error; + free(msg->stats_request_msg->header); + if (msg->stats_request_msg->body_case == PROTOCOL__PRP_STATS_REQUEST__BODY_CELL_STATS_REQUEST) { + free(msg->stats_request_msg->cell_stats_request->cell); + } + if (msg->stats_request_msg->body_case == PROTOCOL__PRP_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 enb_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *report_config, diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index 569eb51e5e..871d6e5ae2 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -69,11 +69,24 @@ typedef struct { cc_report_type_t *cc_report_type; } report_config_t; +typedef struct { + uint8_t report_type; + uint8_t report_frequency; + uint16_t period; /*In number of subframes*/ + report_config_t *config; +} stats_request_config_t; + int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_mac_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__ProgranMessage **msg); + +int enb_agent_mac_destroy_stats_request(Protocol__ProgranMessage *msg); + int enb_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *report_config, Protocol__ProgranMessage **msg); int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg); + + #endif From 3e2adfbcbc8d2e51c364c3573a42def46b528199 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 8 Jan 2016 12:53:34 +0200 Subject: [PATCH 054/413] Fixed bug to allocate memory in the stack instead of dynamically for the timer search key --- openair2/ENB_APP/enb_agent_common.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 0417f4956e..1522cad07d 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -470,10 +470,11 @@ err_code_t enb_agent_destroy_timers(void){ struct enb_agent_timer_element_s * get_timer_entry(long timer_id) { - struct enb_agent_timer_element_s *search= calloc(1,sizeof(*search)); - search->timer_id = timer_id; + struct enb_agent_timer_element_s search; + memset(&search, 0, sizeof(struct enb_agent_timer_element_s)); + search.timer_id = timer_id; - return RB_FIND(enb_agent_map, &timer_instance.enb_agent_head, search); + return RB_FIND(enb_agent_map, &timer_instance.enb_agent_head, &search); } void enb_agent_sleep_until(struct timespec *ts, int delay) { From 2ef32ad9bc4683016d32906a228ec9bee9c3590e Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 8 Jan 2016 15:59:24 +0200 Subject: [PATCH 055/413] Added support for turning off periodical timer tasks --- openair2/ENB_APP/enb_agent.c | 13 ------ openair2/ENB_APP/enb_agent_common.c | 65 +++++++++++++++++++--------- openair2/ENB_APP/enb_agent_common.h | 10 +++-- openair2/ENB_APP/enb_agent_handler.c | 7 ++- openair2/ENB_APP/enb_agent_mac.c | 10 +---- 5 files changed, 59 insertions(+), 46 deletions(-) diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index dbefc60502..6fff535590 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -313,19 +313,6 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ return -1; } - - //#ifdef TEST_TIMER - long timer_id=0; - enb_agent_timer_args_t timer_args; - memset (&timer_args, 0, sizeof(enb_agent_timer_args_t)); - timer_args.mod_id = mod_id; - //timer_args.cc_actions= ENB_AGENT_ACTION_APPLY; - //timer_args.cc_report_flags = PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE; - //timer_args.ue_actions = ENB_AGENT_ACTION_SEND; - //timer_args.ue_report_flags = PROTOCOL__PRP_UE_STATS_TYPE__PRUST_BSR | PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI; - enb_agent_create_timer(1, 0, ENB_AGENT_DEFAULT, mod_id, ENB_AGENT_TIMER_TYPE_PERIODIC, enb_agent_timeout,(void*)&timer_args, &timer_id); - //#endif - //new_thread(send_thread, &shared_ctxt); //while (1) pause(); diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 1522cad07d..8d9997e746 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -377,6 +377,7 @@ err_code_t enb_agent_create_timer(uint32_t interval_sec, agent_id_t agent_id, instance_t instance, uint32_t timer_type, + xid_t xid, enb_agent_timer_callback_t cb, void* timer_args, long *timer_id){ @@ -424,7 +425,8 @@ err_code_t enb_agent_create_timer(uint32_t interval_sec, e->instance = instance; e->state = ENB_AGENT_TIMER_STATE_ACTIVE; e->timer_id = *timer_id; - // e->timer_args = timer_args; + e->xid = xid; + e->timer_args = timer_args; e->cb = cb; /*element should be a real pointer*/ RB_INSERT(enb_agent_map, &timer_instance.enb_agent_head, e); @@ -440,7 +442,8 @@ err_code_t enb_agent_destroy_timer(long timer_id){ struct enb_agent_timer_element_s *e = get_timer_entry(timer_id); if (e != NULL ) { - RB_REMOVE(enb_agent_map, &timer_instance.enb_agent_head, &e); + RB_REMOVE(enb_agent_map, &timer_instance.enb_agent_head, e); + enb_agent_destroy_progran_message(e->timer_args->msg); free(e); } @@ -454,13 +457,35 @@ err_code_t enb_agent_destroy_timer(long timer_id){ return TIMER_REMOVED_FAILED ; } +err_code_t enb_agent_destroy_timer_by_task_id(xid_t xid) { + struct enb_agent_timer_element_s *e = NULL; + long timer_id; + RB_FOREACH(e, enb_agent_map, &timer_instance.enb_agent_head) { + if (e->xid == xid) { + timer_id = e->timer_id; + RB_REMOVE(enb_agent_map, &timer_instance.enb_agent_head, e); + enb_agent_destroy_progran_message(e->timer_args->msg); + free(e); + if (timer_remove(timer_id) < 0 ) { + goto error; + } + } + } + return 0; + + error: + LOG_E(ENB_AGENT, "timer can't be removed\n"); + return TIMER_REMOVED_FAILED ; +} + err_code_t enb_agent_destroy_timers(void){ struct enb_agent_timer_element_s *e = NULL; RB_FOREACH(e, enb_agent_map, &timer_instance.enb_agent_head) { RB_REMOVE(enb_agent_map, &timer_instance.enb_agent_head, e); - timer_remove(e->timer_id); + timer_remove(e->timer_id); + enb_agent_destroy_progran_message(e->timer_args->msg); free(e); } @@ -468,15 +493,6 @@ err_code_t enb_agent_destroy_timers(void){ } -struct enb_agent_timer_element_s * get_timer_entry(long timer_id) { - - struct enb_agent_timer_element_s search; - memset(&search, 0, sizeof(struct enb_agent_timer_element_s)); - search.timer_id = timer_id; - - return RB_FIND(enb_agent_map, &timer_instance.enb_agent_head, &search); -} - void enb_agent_sleep_until(struct timespec *ts, int delay) { ts->tv_nsec += delay; if(ts->tv_nsec >= 1000*1000*1000){ @@ -493,15 +509,15 @@ void enb_agent_sleep_until(struct timespec *ts, int delay) { } */ -/* -err_code_t enb_agent_stop_timer(uint32_t timer_id){ + +err_code_t enb_agent_stop_timer(long timer_id){ struct enb_agent_timer_element_s *e=NULL; - - RB_FOREACH(e, enb_agent_map, &enb_agent_head) { - if (e->timer_id == timer_id) - break; - } + struct enb_agent_timer_element_s search; + memset(&search, 0, sizeof(struct enb_agent_timer_element_s)); + search.timer_id = timer_id; + + e = RB_FIND(enb_agent_map, &timer_instance.enb_agent_head, &search); if (e != NULL ) { e->state = ENB_AGENT_TIMER_STATE_STOPPED; @@ -510,9 +526,18 @@ err_code_t enb_agent_stop_timer(uint32_t timer_id){ timer_remove(timer_id); return 0; - } +struct enb_agent_timer_element_s * get_timer_entry(long timer_id) { + + struct enb_agent_timer_element_s search; + memset(&search, 0, sizeof(struct enb_agent_timer_element_s)); + search.timer_id = timer_id; + + return RB_FIND(enb_agent_map, &timer_instance.enb_agent_head, &search); +} + +/* // this will change the timer_id err_code_t enb_agent_restart_timer(uint32_t *timer_id){ diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 31d882d0c9..c2c57ca4ea 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -70,6 +70,8 @@ typedef int (*enb_agent_message_destruction_callback)( int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int *size); int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage **msg); +err_code_t enb_agent_destroy_progran_message(Protocol__ProgranMessage *msg); + int prp_create_header(xid_t xid, Protocol__PrpType type, Protocol__PrpHeader **header); int enb_agent_hello(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); @@ -189,9 +191,11 @@ typedef struct enb_agent_timer_element_s{ 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*/ enb_agent_timer_callback_t cb; - // void* timer_args; + enb_agent_timer_args_t *timer_args; } enb_agent_timer_element_t; @@ -206,12 +210,14 @@ err_code_t enb_agent_create_timer(uint32_t interval_sec, agent_id_t agent_id, instance_t instance, uint32_t timer_type, + xid_t xid, enb_agent_timer_callback_t cb, void* timer_args, long *timer_id); err_code_t enb_agent_destroy_timers(void); err_code_t enb_agent_destroy_timer(long timer_id); +err_code_t enb_agent_destroy_timer_by_task_id(xid_t xid); err_code_t enb_agent_stop_timer(long timer_id); @@ -219,8 +225,6 @@ err_code_t enb_agent_restart_timer(long *timer_id); struct enb_agent_timer_element_s * get_timer_entry(long timer_id); - - Protocol__ProgranMessage * enb_agent_process_timeout(long timer_id, void* timer_args); int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b); diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 2841f9b6e5..02092a84f8 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -54,9 +54,8 @@ enb_agent_message_destruction_callback message_destruction_callback[] = { enb_agent_destroy_hello, enb_agent_destroy_echo_request, enb_agent_destroy_echo_reply, - 0, /*No stats request message is created in the agent. No need for a callback*/ + enb_agent_mac_destroy_stats_request, enb_agent_mac_destroy_stats_reply, - }; static const char *enb_agent_direction2String[] = { @@ -170,3 +169,7 @@ Protocol__ProgranMessage* enb_agent_process_timeout(long timer_id, void* timer_a LOG_E(ENB_AGENT, "can't get the timer element\n"); return TIMER_ELEMENT_NOT_FOUND; } + +err_code_t enb_agent_destroy_progran_message(Protocol__ProgranMessage *msg) { + return ((*message_destruction_callback[msg->msg_case-1])(msg)); +} diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 1a21db5e15..411480254f 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -71,18 +71,12 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr switch(stats_req->body_case) { case PROTOCOL__PRP_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ; Protocol__PrpCompleteStatsRequest *comp_req = stats_req->complete_stats_request; - /* if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_PERIODICAL) { */ - /* //TODO: Must create a periodic report. Implement once the */ - /* // timer functionality is supported */ - /* *msg = NULL; */ - /* return 0; */ - /* } else */ if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_CONTINUOUS) { //TODO: Must create an event based report mechanism *msg = NULL; return 0; } else if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_OFF) { - //TODO: Must implement to deactivate the event based reporting + enb_agent_destroy_timer_by_task_id(xid); *msg = NULL; return 0; } else { //One-off or periodical reporting @@ -141,7 +135,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr sec_interval = usec_interval/(1000*1000); usec_interval = usec_interval%(1000*1000); } - enb_agent_create_timer(sec_interval, usec_interval, ENB_AGENT_DEFAULT, enb_id, ENB_AGENT_TIMER_TYPE_PERIODIC, enb_agent_handle_timed_task,(void*) timer_args, &timer_id); + enb_agent_create_timer(sec_interval, usec_interval, ENB_AGENT_DEFAULT, enb_id, ENB_AGENT_TIMER_TYPE_PERIODIC, xid, enb_agent_handle_timed_task,(void*) timer_args, &timer_id); } } break; From a9a67824dd8c7f343bf25bed72710a2f8bc28df8 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 11 Jan 2016 14:58:31 +0200 Subject: [PATCH 056/413] Added API functions for eNB agent - technology interaction --- openair2/ENB_APP/enb_agent_mac.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index 871d6e5ae2..11e981a51b 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -88,5 +88,19 @@ int enb_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *re int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg); +/********************************** + * eNB agent - technology mac API + **********************************/ + +/*Set DCI for particular RNTI in defined subframe (UL/DL)*/ +int enb_agent_mac_dl_config(mid_t mod_id, Protocol__ProgranMessage *msg); + +int enb_agent_mac_ul_config(mid_t mod_id, Protocol__ProgranMessage *msg); + +/*Push controller configurations to the eNB for cells and UEs*/ +int enb_agent_set_cell_config(mid_t mod_id, Protocol__ProgranMessage *msg); + +int enb_agent_set_ue_config(mid_t mod_id, Protocol__ProgranMessage *msg); + #endif From 3ce2ba4e5d19cda16176981304d0b2f69cdb1300 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 12 Jan 2016 14:24:31 +0200 Subject: [PATCH 057/413] Added support for scheduling requests messages --- openair2/ENB_APP/MESSAGES/V2/progran.proto | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index 995cd6861b..53718b87c4 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -12,6 +12,7 @@ message progran_message { prp_echo_reply echo_reply_msg = 3; prp_stats_request stats_request_msg = 4; prp_stats_reply stats_reply_msg = 5; + prp_ul_sr_info ul_sr_info_msg = 6; } } @@ -82,6 +83,15 @@ message prp_stats_reply { repeated prp_cell_stats_report cell_report = 3; } +// +// Asynchronous messages +// + +message prp_ul_sr_info { + optional prp_header header = 1; + optional uint32 sfn_sf = 2; + repeated uint32 rnti = 3; +} // Extensions of the echo request and reply // messages for carrying a latency value in ms From a8dabcefea873ab7f7374b292d8a55516af29971 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 12 Jan 2016 17:58:09 +0200 Subject: [PATCH 058/413] Added support for UL SR info type in the header of progRAN messages --- openair2/ENB_APP/MESSAGES/V2/header.proto | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index b2319c8220..5670b9bd77 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -15,5 +15,8 @@ enum prp_type { // Statistics and measurement messages PRPT_STATS_REQUEST = 3; PRPT_STATS_REPLY = 4; + + //Asynchronous messages + PRPT_UL_SR_INFO = 5; } From 694a5bb1b5a03339143ced6bee734ce544ef4dd2 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 12 Jan 2016 18:02:07 +0200 Subject: [PATCH 059/413] Changed the function signature for handling the packing of protocol messages --- openair2/ENB_APP/enb_agent.c | 6 ++++-- openair2/ENB_APP/enb_agent_common.h | 13 ++++++++----- openair2/ENB_APP/enb_agent_handler.c | 3 ++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index 6fff535590..d3e74348f8 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -38,6 +38,8 @@ #include "log.h" #include "enb_agent.h" +#include "enb_agent_extern.h" + #include "assertions.h" //#define TEST_TIMER @@ -95,7 +97,7 @@ void *enb_agent_task(void *args){ case TIMER_HAS_EXPIRED: msg = enb_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, msg_p->ittiMsg.timer_has_expired.arg); if (msg != NULL){ - data=enb_agent_send_message(msg,&size); + data=enb_agent_pack_message(msg,&size); if (message_put(d->tx_mq, data, size, priority)){ err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; goto error; @@ -182,7 +184,7 @@ void *receive_thread(void *args) { // check if there is something to send back to the controller if (msg != NULL){ - data=enb_agent_send_message(msg,&size); + data=enb_agent_pack_message(msg,&size); if (message_put(d->tx_mq, data, size, priority)){ err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index c2c57ca4ea..f4add1ae2e 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -67,9 +67,17 @@ typedef int (*enb_agent_message_destruction_callback)( Protocol__ProgranMessage *msg ); +/********************************** + * progRAN protocol messages helper + * functions and generic handlers + **********************************/ + int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int *size); int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage **msg); +void * enb_agent_pack_message(Protocol__ProgranMessage *msg, + uint32_t * size); + err_code_t enb_agent_destroy_progran_message(Protocol__ProgranMessage *msg); int prp_create_header(xid_t xid, Protocol__PrpType type, Protocol__PrpHeader **header); @@ -90,11 +98,6 @@ Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, Protocol__ProgranMessage *enb_agent_handle_timed_task(void *args); -void * enb_agent_send_message(Protocol__ProgranMessage *msg, - uint32_t * size); - - - diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 02092a84f8..0f5146fe6d 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -56,6 +56,7 @@ enb_agent_message_destruction_callback message_destruction_callback[] = { enb_agent_destroy_echo_reply, enb_agent_mac_destroy_stats_request, enb_agent_mac_destroy_stats_reply, + enb_agent_mac_destroy_sr_info, }; static const char *enb_agent_direction2String[] = { @@ -108,7 +109,7 @@ error: -void * enb_agent_send_message(Protocol__ProgranMessage *msg, +void * enb_agent_pack_message(Protocol__ProgranMessage *msg, uint32_t * size){ void * buffer; From 22d0f60e126b359aa348a062f53a5fcdc0f50bae Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 12 Jan 2016 18:08:57 +0200 Subject: [PATCH 060/413] Added support for creation of SR protocol messages and defined initial MAC-Agent interface --- openair2/ENB_APP/enb_agent_extern.h | 50 +++++++++++ openair2/ENB_APP/enb_agent_mac.c | 121 ++++++++++++++++++++++++++ openair2/ENB_APP/enb_agent_mac.h | 21 +++-- openair2/ENB_APP/enb_agent_mac_defs.h | 54 ++++++++++++ 4 files changed, 238 insertions(+), 8 deletions(-) create mode 100644 openair2/ENB_APP/enb_agent_extern.h create mode 100644 openair2/ENB_APP/enb_agent_mac_defs.h diff --git a/openair2/ENB_APP/enb_agent_extern.h b/openair2/ENB_APP/enb_agent_extern.h new file mode 100644 index 0000000000..2cd072f25a --- /dev/null +++ b/openair2/ENB_APP/enb_agent_extern.h @@ -0,0 +1,50 @@ +/******************************************************************************* + 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 ENB_APP/extern.h + * \brief enb agent - mac interface primitives + * \author Xenofon Foukas + * \date 2016 + * \version 0.1 + * \mail x.foukas@sms.ed.ac.uk + */ + +#ifndef __ENB_AGENT_EXTERN_H__ +#define __ENB_AGENT_EXTERN_H__ + +#include "enb_agent_defs.h" +#include "enb_agent_mac_defs.h" + +extern msg_context_t shared_ctxt[NUM_MAX_ENB_AGENT]; + +extern AGENT_MAC_xface *agent_mac_xface; + +extern unsigned int mac_agent_registered[NUM_MAX_ENB_AGENT]; + +#endif diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 411480254f..36b7788d23 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -760,3 +760,124 @@ int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg) { //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; } + +int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { + Protocol__PrpHeader *header; + int i; + const int xid = *((int *)params); + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_UL_SR_INFO, &header) != 0) + goto error; + + Protocol__PrpUlSrInfo *ul_sr_info_msg; + ul_sr_info_msg = malloc(sizeof(Protocol__PrpUlSrInfo)); + if (ul_sr_info_msg == NULL) { + goto error; + } + protocol__prp_ul_sr_info__init(ul_sr_info_msg); + + ul_sr_info_msg->header = header; + ul_sr_info_msg->has_sfn_sf = 1; + ul_sr_info_msg->sfn_sf = get_sfn_sf(mod_id); + /*TODO: Set the number of UEs that sent an SR */ + ul_sr_info_msg->n_rnti = 1; + ul_sr_info_msg->rnti = (uint32_t *) malloc(ul_sr_info_msg->n_rnti * sizeof(uint32_t)); + + if(ul_sr_info_msg->rnti == NULL) { + goto error; + } + /*TODO:Set the rnti of the UEs that sent an SR */ + for (i = 0; i < ul_sr_info_msg->n_rnti; i++) { + ul_sr_info_msg->rnti[i] = 1; + } + + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if(*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_UL_SR_INFO_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + (*msg)->ul_sr_info_msg = ul_sr_info_msg; + return 0; + + error: + // TODO: Need to make proper error handling + if (header != NULL) + free(header); + if (ul_sr_info_msg != NULL) { + free(ul_sr_info_msg->rnti); + free(ul_sr_info_msg); + } + if(*msg != NULL) + free(*msg); + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +int enb_agent_mac_destroy_sr_info(Protocol__ProgranMessage *msg) { + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_UL_SR_INFO_MSG) + goto error; + + free(msg->ul_sr_info_msg->header); + free(msg->ul_sr_info_msg->rnti); + free(msg->ul_sr_info_msg); + free(msg); + return 0; + + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +void enb_agent_send_sr_info(mid_t mod_id, msg_context_t *context) { + int size; + Protocol__ProgranMessage *msg; + void *data; + int priority; + err_code_t err_code; + + /*TODO: Must use a proper xid*/ + int xid = 1; + err_code = enb_agent_mac_sr_info(mod_id, (void *) &xid, &msg); + if (err_code < 0) { + goto error; + } + + if (msg != NULL){ + data=enb_agent_pack_message(msg, &size); + + if (message_put(context->tx_mq, data, size, priority)){ + err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + goto error; + } + LOG_D(ENB_AGENT,"sent message with size %d\n", size); + } + error: + LOG_D(ENB_AGENT, "Could not send sr message\n"); +} + +int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { + if (!mac_agent_registered[mod_id]) { + LOG_E(MAC, "MAC agent for eNB %d is already registered\n", mod_id); + return -1; + } + + xface->agent_ctxt = &shared_ctxt[mod_id]; + xface->enb_agent_send_sr_info = enb_agent_send_sr_info; + + mac_agent_registered[mod_id] = 1; + return 1; +} + +int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { + + if(mac_agent_registered[mod_id]) { + LOG_E(MAC, "MAC agent for eNB %d is already registered\n", mod_id); + return -1; + } + + xface->agent_ctxt = NULL; + xface->enb_agent_send_sr_info = NULL; + + mac_agent_registered[mod_id] = NULL; + return 1; +} diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index 11e981a51b..7945082410 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -43,7 +43,10 @@ #include "stats_common.pb-c.h" #include "enb_agent_common.h" +#include "enb_agent_extern.h" +/*Flags showing if a mac agent has already been registered*/ +unsigned int mac_agent_registered[NUM_MAX_ENB_AGENT]; /* These types will be used to give instructions for the type of stats reports @@ -87,20 +90,22 @@ int enb_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *re int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg); +int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); + +int enb_agent_mac_destroy_sr_info(Protocol__ProgranMessage *msg); + /********************************** * eNB agent - technology mac API **********************************/ -/*Set DCI for particular RNTI in defined subframe (UL/DL)*/ -int enb_agent_mac_dl_config(mid_t mod_id, Protocol__ProgranMessage *msg); +/*Inform controller about received scheduling requests during a subframe*/ +void enb_agent_send_sr_info(mid_t mod_id, msg_context_t *context); -int enb_agent_mac_ul_config(mid_t mod_id, Protocol__ProgranMessage *msg); - -/*Push controller configurations to the eNB for cells and UEs*/ -int enb_agent_set_cell_config(mid_t mod_id, Protocol__ProgranMessage *msg); - -int enb_agent_set_ue_config(mid_t mod_id, Protocol__ProgranMessage *msg); +/*Register technology specific interface callbacks*/ +int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface); +/*Unregister technology specific callbacks*/ +int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface*xface); #endif diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/enb_agent_mac_defs.h new file mode 100644 index 0000000000..28a424706b --- /dev/null +++ b/openair2/ENB_APP/enb_agent_mac_defs.h @@ -0,0 +1,54 @@ +/******************************************************************************* + 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 enb_agent_mac_defs.h + * \brief enb agent - mac interface primitives + * \author Xenofon Foukas + * \date 2016 + * \version 0.1 + * \mail x.foukas@sms.ed.ac.uk + */ + +#ifndef __ENB_AGENT_MAC_PRIMITIVES_H__ +#define __ENB_AGENT_MAC_PRIMITIVES_H__ + +#include "enb_agent_defs.h" + +/* ENB AGENT-MAC Interface */ +typedef struct { + msg_context_t *agent_ctxt; + + /// Inform the controller about the scheduling requests received during the subframe + void (*enb_agent_send_sr_info)(mid_t mod_id, msg_context_t *context); + + /*TODO: Fill in with the rest of the MAC layer technology specific callbacks (UL/DL scheduling, RACH info etc)*/ + +} AGENT_MAC_xface; + +#endif From dbcf482f07284a547400b835d37e5cd8256c1c44 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 14 Jan 2016 17:46:06 +0200 Subject: [PATCH 061/413] Added eNB agent abstract network interface support --- cmake_targets/CMakeLists.txt | 1 + openair2/ENB_APP/enb_agent_net_comm.c | 196 ++++++++++++++++++++++++++ openair2/ENB_APP/enb_agent_net_comm.h | 90 ++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 openair2/ENB_APP/enb_agent_net_comm.c create mode 100644 openair2/ENB_APP/enb_agent_net_comm.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 0777e1f3a0..8cd37613fa 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -747,6 +747,7 @@ if (ENB_AGENT_SB_IF) ${OPENAIR2_DIR}/ENB_APP/enb_agent_mac.c ${OPENAIR2_DIR}/ENB_APP/enb_agent.c ${OPENAIR2_DIR}/ENB_APP/enb_agent_task_manager.c + ${OPENAIR2_DIR}/ENB_APP/enb_agent_net_comm.c ) set(ENB_AGENT_LIB ENB_AGENT) #include_directories(${OPENAIR2_DIR}/ENB_APP) diff --git a/openair2/ENB_APP/enb_agent_net_comm.c b/openair2/ENB_APP/enb_agent_net_comm.c new file mode 100644 index 0000000000..096779f261 --- /dev/null +++ b/openair2/ENB_APP/enb_agent_net_comm.c @@ -0,0 +1,196 @@ +/******************************************************************************* + 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 enb_agent_net_comm.c + * \brief enb agent network interface abstraction + * \author Xenofon Foukas + * \date 2016 + * \version 0.1 + */ + +#include "enb_agent_net_comm.h" +#include "log.h" + +enb_agent_channel_t *agent_channel[ENB_AGENT_MAX]; +enb_agent_channel_instance_t channel_instance; +int enb_agent_channel_id = 0; + +int enb_agent_msg_send(void *data, int size, int priority, agent_id_t agent_id) { + /*Check if agent id is valid*/ + if (agent_id >= ENB_AGENT_MAX || agent_id < 0) { + goto error; + } + enb_agent_channel_t *channel; + channel = agent_channel[agent_id]; + + /*Check if agent has a channel registered*/ + if (channel == NULL) { + goto error; + } + + return channel->msg_send(data, size, priority, channel->channel_info); + + error: + LOG_E(ENB_AGENT, "No channel registered for agent with id %d\n", agent_id); + return -1; +} + +int enb_agent_msg_recv(void **data, int *size, int *priority, agent_id_t agent_id) { + /*Check if agent id is valid*/ + if (agent_id >= ENB_AGENT_MAX || agent_id < 0) { + goto error; + } + enb_agent_channel_t *channel; + channel = agent_channel[agent_id]; + + /*Check if agent has a channel registered*/ + if (channel == NULL) { + goto error; + } + + return channel->msg_recv(data, size, priority, channel->channel_info); + + error: + LOG_E(ENB_AGENT, "No channel registered for agent with id %d\n", agent_id); + return -1; +} + +int enb_agent_register_channel(enb_agent_channel_t *channel, agent_id_t agent_id) { + int i; + + if (channel == NULL) { + return -1; + } + + if (agent_id == ENB_AGENT_MAX) { + for (i = 0; i < ENB_AGENT_MAX; i++) { + agent_channel[i] = channel; + } + } else { + agent_channel[agent_id] = channel; + } + return 0; +} + +void enb_agent_unregister_channel(agent_id_t agent_id) { + int i; + + if (agent_id == ENB_AGENT_MAX) { + for (i = 0; i < ENB_AGENT_MAX; i++) { + agent_channel[i] = NULL; + } + } else { + agent_channel[agent_id] = NULL; + } +} + +int enb_agent_create_channel(void *channel_info, + int (*msg_send)(void *data, int size, int priority, void *channel_info), + int (*msg_recv)(void **data, int *size, int *priority, void *channel_info), + void (*release)(enb_agent_channel_t *channel)) { + + int channel_id = ++enb_agent_channel_id; + enb_agent_channel_t *channel = (enb_agent_channel_t *) malloc(sizeof(enb_agent_channel_t)); + channel->channel_id = channel_id; + channel->channel_info = channel_info; + channel->msg_send = msg_send; + channel->msg_recv = msg_recv; + channel->release = release; + + /*element should be a real pointer*/ + RB_INSERT(enb_agent_channel_map, &channel_instance.enb_agent_head, channel); + + LOG_I(ENB_AGENT,"Created a new channel with id 0x%lx\n", channel->channel_id); + + return channel_id; +} + +int enb_agent_destroy_channel(int channel_id) { + int i; + + /*Check to see if channel exists*/ + struct enb_agent_channel_s *e = NULL; + struct enb_agent_channel_s search; + memset(&search, 0, sizeof(struct enb_agent_channel_s)); + + e = RB_FIND(enb_agent_channel_map, &channel_instance.enb_agent_head, &search); + + if (e == NULL) { + return -1; + } + + /*Unregister the channel from all agents*/ + for (i = 0; i < ENB_AGENT_MAX; i++) { + if (agent_channel[i] != NULL) { + if (agent_channel[i]->channel_id == e->channel_id) { + agent_channel[i] == NULL; + } + } + } + + /*Remove the channel from the tree and free memory*/ + RB_REMOVE(enb_agent_channel_map, &channel_instance.enb_agent_head, e); + e->release(e); + free(e); + + return 0; +} + +err_code_t enb_agent_init_channel_container(void) { + int i; + LOG_I(ENB_AGENT, "init RB tree for channel container\n"); + + RB_INIT(&channel_instance.enb_agent_head); + + for (i = 0; i < ENB_AGENT_MAX; i++) { + agent_channel[i] == NULL; + } + + return 0; +} + +RB_GENERATE(enb_agent_channel_map,enb_agent_channel_s, entry, enb_agent_compare_channel); + +int enb_agent_compare_channel(struct enb_agent_channel_s *a, struct enb_agent_channel_s *b) { + if (a->channel_id < b->channel_id) return -1; + if (a->channel_id > b->channel_id) return 1; + + // equal timers + return 0; +} + +enb_agent_channel_t * get_channel(int channel_id) { + + struct enb_agent_channel_s search; + memset(&search, 0, sizeof(struct enb_agent_channel_s)); + search.channel_id = channel_id; + + return RB_FIND(enb_agent_channel_map, &channel_instance.enb_agent_head, &search); + +} diff --git a/openair2/ENB_APP/enb_agent_net_comm.h b/openair2/ENB_APP/enb_agent_net_comm.h new file mode 100644 index 0000000000..50237379d4 --- /dev/null +++ b/openair2/ENB_APP/enb_agent_net_comm.h @@ -0,0 +1,90 @@ +/******************************************************************************* + 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 enb_agent_net_comm.h + * \brief enb agent network interface abstraction + * \autho Xenofon Foukas + * \date 2016 + * \version 0.1 + */ +#ifndef ENB_AGENT_NET_COMM_H_ +#define ENB_AGENT_NET_COMM_H_ + +#include "enb_agent_defs.h" + +#include "tree.h" + +/*Channel related information used for Tx/Rx of protocol messages*/ +typedef struct enb_agent_channel_s { + RB_ENTRY(enb_agent_channel_s) entry; +int channel_id; +void *channel_info; +/*Callbacks for channel message Tx and Rx*/ +int (*msg_send)(void *data, int size, int priority, void *channel_info); +int (*msg_recv)(void **data, int *size, int *priority, void *channel_info); +void (*release)(struct enb_agent_channel_s *channel); +} enb_agent_channel_t; + +typedef struct enb_agent_channel_instance_s{ + RB_HEAD(enb_agent_channel_map, enb_agent_channel_s) enb_agent_head; +} enb_agent_channel_instance_t; + +/*Send and receive messages using the channel registered for a specific agent*/ +int enb_agent_msg_send(void *data, int size, int priority, agent_id_t agent_id); + +int enb_agent_msg_recv(void **data, int *size, int *priority, agent_id_t agent_id); + +/*Register a channel to an agent. Use ENB_AGENT_MAX to register the + *same channel to all agents*/ +int enb_agent_register_channel(enb_agent_channel_t *channel, agent_id_t agent_id); + +/*Unregister the current channel of an agent. Use ENB_AGENT_MAX to unregister all channels*/ +void enb_agent_unregister_channel(agent_id_t agent_id); + +/*Create a new channel. Returns the id of the new channel or negative number otherwise*/ +int enb_agent_create_channel(void *channel_info, + int (*msg_send)(void *data, int size, int priority, void *channel_info), + int (*msg_recv)(void **data, int *size, int *priority, void *channel_info), + void (*release)(enb_agent_channel_t *channel)); + +/*Unregister a channel from all agents and destroy it. Returns 0 in case of success*/ +int enb_agent_destroy_channel(int channel_id); + +/*Return an agent communication channel based on its id*/ +enb_agent_channel_t * get_channel(int channel_id); + +/*Should be called before performing any channel operations*/ +err_code_t enb_agent_init_channel_container(void); + +int enb_agent_compare_channel(struct enb_agent_channel_s *a, struct enb_agent_channel_s *b); + +/* RB_PROTOTYPE is for .h files */ +RB_PROTOTYPE(enb_agent_channel_map, enb_agent_channel_s, entry, enb_agent_compare_channel); + +#endif /*ENB_AGENT_COMM_H_*/ From e6762ffe1fbade7087bea5031b09814f97a94e13 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 14 Jan 2016 19:10:27 +0200 Subject: [PATCH 062/413] Added support for multiple eNBs in an emulation environment --- openair2/ENB_APP/enb_agent_net_comm.c | 44 +++++++++++++++------------ openair2/ENB_APP/enb_agent_net_comm.h | 8 ++--- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_net_comm.c b/openair2/ENB_APP/enb_agent_net_comm.c index 096779f261..5c4544ad63 100644 --- a/openair2/ENB_APP/enb_agent_net_comm.c +++ b/openair2/ENB_APP/enb_agent_net_comm.c @@ -37,17 +37,17 @@ #include "enb_agent_net_comm.h" #include "log.h" -enb_agent_channel_t *agent_channel[ENB_AGENT_MAX]; +enb_agent_channel_t *agent_channel[NUM_MAX_ENB_AGENT][ENB_AGENT_MAX]; enb_agent_channel_instance_t channel_instance; int enb_agent_channel_id = 0; -int enb_agent_msg_send(void *data, int size, int priority, agent_id_t agent_id) { +int enb_agent_msg_send(mid_t mod_id, agent_id_t agent_id, void *data, int size, int priority) { /*Check if agent id is valid*/ if (agent_id >= ENB_AGENT_MAX || agent_id < 0) { goto error; } enb_agent_channel_t *channel; - channel = agent_channel[agent_id]; + channel = agent_channel[mod_id][agent_id]; /*Check if agent has a channel registered*/ if (channel == NULL) { @@ -61,13 +61,13 @@ int enb_agent_msg_send(void *data, int size, int priority, agent_id_t agent_id) return -1; } -int enb_agent_msg_recv(void **data, int *size, int *priority, agent_id_t agent_id) { +int enb_agent_msg_recv(mid_t mod_id, agent_id_t agent_id, void **data, int *size, int *priority) { /*Check if agent id is valid*/ if (agent_id >= ENB_AGENT_MAX || agent_id < 0) { goto error; } enb_agent_channel_t *channel; - channel = agent_channel[agent_id]; + channel = agent_channel[mod_id][agent_id]; /*Check if agent has a channel registered*/ if (channel == NULL) { @@ -81,7 +81,7 @@ int enb_agent_msg_recv(void **data, int *size, int *priority, agent_id_t agent_i return -1; } -int enb_agent_register_channel(enb_agent_channel_t *channel, agent_id_t agent_id) { +int enb_agent_register_channel(mid_t mod_id, enb_agent_channel_t *channel, agent_id_t agent_id) { int i; if (channel == NULL) { @@ -90,23 +90,23 @@ int enb_agent_register_channel(enb_agent_channel_t *channel, agent_id_t agent_id if (agent_id == ENB_AGENT_MAX) { for (i = 0; i < ENB_AGENT_MAX; i++) { - agent_channel[i] = channel; + agent_channel[mod_id][i] = channel; } } else { - agent_channel[agent_id] = channel; + agent_channel[mod_id][agent_id] = channel; } return 0; } -void enb_agent_unregister_channel(agent_id_t agent_id) { +void enb_agent_unregister_channel(mid_t mod_id, agent_id_t agent_id) { int i; if (agent_id == ENB_AGENT_MAX) { for (i = 0; i < ENB_AGENT_MAX; i++) { - agent_channel[i] = NULL; + agent_channel[mod_id][i] = NULL; } } else { - agent_channel[agent_id] = NULL; + agent_channel[mod_id][agent_id] = NULL; } } @@ -132,7 +132,7 @@ int enb_agent_create_channel(void *channel_info, } int enb_agent_destroy_channel(int channel_id) { - int i; + int i, j; /*Check to see if channel exists*/ struct enb_agent_channel_s *e = NULL; @@ -146,10 +146,12 @@ int enb_agent_destroy_channel(int channel_id) { } /*Unregister the channel from all agents*/ - for (i = 0; i < ENB_AGENT_MAX; i++) { - if (agent_channel[i] != NULL) { - if (agent_channel[i]->channel_id == e->channel_id) { - agent_channel[i] == NULL; + for (i = 0; i < NUM_MAX_ENB_AGENT; i++) { + for (j = 0; j < ENB_AGENT_MAX; j++) { + if (agent_channel[i][j] != NULL) { + if (agent_channel[i][j]->channel_id == e->channel_id) { + agent_channel[i][j] == NULL; + } } } } @@ -163,13 +165,15 @@ int enb_agent_destroy_channel(int channel_id) { } err_code_t enb_agent_init_channel_container(void) { - int i; + int i, j; LOG_I(ENB_AGENT, "init RB tree for channel container\n"); RB_INIT(&channel_instance.enb_agent_head); - - for (i = 0; i < ENB_AGENT_MAX; i++) { - agent_channel[i] == NULL; + + for (i = 0; i < NUM_MAX_ENB_AGENT; i++) { + for (j = 0; j < ENB_AGENT_MAX; j++) { + agent_channel[i][j] == NULL; + } } return 0; diff --git a/openair2/ENB_APP/enb_agent_net_comm.h b/openair2/ENB_APP/enb_agent_net_comm.h index 50237379d4..ab42bdc34f 100644 --- a/openair2/ENB_APP/enb_agent_net_comm.h +++ b/openair2/ENB_APP/enb_agent_net_comm.h @@ -56,16 +56,16 @@ typedef struct enb_agent_channel_instance_s{ } enb_agent_channel_instance_t; /*Send and receive messages using the channel registered for a specific agent*/ -int enb_agent_msg_send(void *data, int size, int priority, agent_id_t agent_id); +int enb_agent_msg_send(mid_t mod_id, agent_id_t agent_id, void *data, int size, int priority); -int enb_agent_msg_recv(void **data, int *size, int *priority, agent_id_t agent_id); +int enb_agent_msg_recv(mid_t mod_id, agent_id_t agent_id, void **data, int *size, int *priority); /*Register a channel to an agent. Use ENB_AGENT_MAX to register the *same channel to all agents*/ -int enb_agent_register_channel(enb_agent_channel_t *channel, agent_id_t agent_id); +int enb_agent_register_channel(mid_t mod_id, enb_agent_channel_t *channel, agent_id_t agent_id); /*Unregister the current channel of an agent. Use ENB_AGENT_MAX to unregister all channels*/ -void enb_agent_unregister_channel(agent_id_t agent_id); +void enb_agent_unregister_channel(mid_t mod_id, agent_id_t agent_id); /*Create a new channel. Returns the id of the new channel or negative number otherwise*/ int enb_agent_create_channel(void *channel_info, From 8fde111b93ba7c6736758300ef4df4d8ba8e18cb Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 14 Jan 2016 19:49:02 +0200 Subject: [PATCH 063/413] Channel implementation for async interface --- cmake_targets/CMakeLists.txt | 1 + openair2/ENB_APP/enb_agent_async.c | 107 +++++++++++++++++++++++++++++ openair2/ENB_APP/enb_agent_async.h | 51 ++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 openair2/ENB_APP/enb_agent_async.c create mode 100644 openair2/ENB_APP/enb_agent_async.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 8cd37613fa..56ee7b71d3 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -748,6 +748,7 @@ if (ENB_AGENT_SB_IF) ${OPENAIR2_DIR}/ENB_APP/enb_agent.c ${OPENAIR2_DIR}/ENB_APP/enb_agent_task_manager.c ${OPENAIR2_DIR}/ENB_APP/enb_agent_net_comm.c + ${OPENAIR2_DIR}/ENB_APP/enb_agent_async.c ) set(ENB_AGENT_LIB ENB_AGENT) #include_directories(${OPENAIR2_DIR}/ENB_APP) diff --git a/openair2/ENB_APP/enb_agent_async.c b/openair2/ENB_APP/enb_agent_async.c new file mode 100644 index 0000000000..962e1a81ed --- /dev/null +++ b/openair2/ENB_APP/enb_agent_async.c @@ -0,0 +1,107 @@ +/******************************************************************************* + 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 enb_agent_async.c + * \brief channel implementation for async interface + * \author Xenofon Foukas + * \date 2016 + * \version 0.1 + */ + +#include "enb_agent_async.h" +#include "enb_agent_defs.h" + +#include "log.h" + +enb_agent_instance_t * enb_agent_async_channel_info(mid_t mod_id, char *dst_ip, uint16_t dst_port) { + + enb_agent_instance_t *channel; + channel = (enb_agent_instance_t *) malloc(sizeof(enb_agent_instance_t)); + + if (channel == NULL) + goto error; + + channel->mod_id = mod_id; + /*Create a socket*/ + channel->link = new_link_client(dst_ip, dst_port); + if (channel->link == NULL) goto error; + + LOG_I(ENB_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n", + channel->mod_id, + dst_ip, + dst_port); + + /* + * create a message queue + */ + + channel->send_queue = new_message_queue(); + if (channel->send_queue == NULL) goto error; + channel->receive_queue = new_message_queue(); + if (channel->receive_queue == NULL) goto error; + + /* + * create a link manager + */ + channel->manager = create_link_manager(channel->send_queue, channel->receive_queue, channel->link); + if (channel->manager == NULL) goto error; + + return channel; + + error: + LOG_I(ENB_AGENT,"there was an error\n"); + return 1; +} + +int enb_agent_async_msg_send(void *data, int size, int priority, void *channel_info) { + enb_agent_instance_t *channel; + channel = (enb_agent_instance_t *)channel_info; + + return message_put(channel->send_queue, data, size, priority); +} + +int enb_agent_async_msg_recv(void **data, int *size, int *priority, void *channel_info) { + enb_agent_instance_t *channel; + channel = (enb_agent_instance_t *)channel_info; + + return message_get(channel->receive_queue, data, size, priority); +} + +void enb_agent_async_release(enb_agent_channel_t *channel) { + enb_agent_instance_t *channel_info; + channel_info = (enb_agent_instance_t *) channel->channel_info; + + destroy_link_manager(channel_info->manager); + + destroy_message_queue(channel_info->send_queue); + destroy_message_queue(channel_info->receive_queue); + + close_link(channel_info->link); + free(channel_info); +} diff --git a/openair2/ENB_APP/enb_agent_async.h b/openair2/ENB_APP/enb_agent_async.h new file mode 100644 index 0000000000..53614cc87d --- /dev/null +++ b/openair2/ENB_APP/enb_agent_async.h @@ -0,0 +1,51 @@ +/******************************************************************************* + 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 enb_agent_async.h + * \brief channel implementation for async interface + * \author Xenofon Foukas + * \date 2016 + * \version 0.1 + */ + +#ifndef ENB_AGENT_ASYNC_H_ +#define ENB_AGENT_ASYNC_H_ + +#include "enb_agent_net_comm.h" + +enb_agent_instance_t * enb_agent_async_channel_info(mid_t mod_id, char *dst_ip, uint16_t dst_port); + +int enb_agent_async_msg_send(void *data, int size, int priority, void *channel_info); + +int enb_agent_async_msg_recv(void **data, int *size, int *priority, void *channel_info); + +void enb_agent_async_release(enb_agent_channel_t *channel); + + +#endif /*ENB_AGENT_ASYNC_H_*/ From ed7e13c6ebf0bdfb95bc3951d512e76cb6d0fef3 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 15 Jan 2016 14:31:21 +0200 Subject: [PATCH 064/413] Integrated abstract network communication in main agent --- openair2/ENB_APP/enb_agent.c | 169 ++++++++++++++++-------------- openair2/ENB_APP/enb_agent_defs.h | 4 +- openair2/ENB_APP/enb_agent_mac.c | 12 ++- 3 files changed, 98 insertions(+), 87 deletions(-) diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index d3e74348f8..fa24cacf8a 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -42,6 +42,9 @@ #include "assertions.h" +#include "enb_agent_net_comm.h" +#include "enb_agent_async.h" + //#define TEST_TIMER enb_agent_instance_t enb_agent[NUM_MAX_ENB_AGENT]; @@ -98,10 +101,15 @@ void *enb_agent_task(void *args){ msg = enb_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, msg_p->ittiMsg.timer_has_expired.arg); if (msg != NULL){ data=enb_agent_pack_message(msg,&size); - if (message_put(d->tx_mq, data, size, priority)){ + if (enb_agent_msg_send(d->mod_id, ENB_AGENT_DEFAULT, data, size, priority)) { err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; goto error; } + + /* if (message_put(d->tx_mq, data, size, priority)){ */ + /* err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; */ + /* goto error; */ + /* } */ LOG_D(ENB_AGENT,"sent message with size %d\n", size); } break; @@ -121,42 +129,6 @@ void *enb_agent_task(void *args){ return NULL; } -/* void *send_thread(void *args) { */ - -/* #ifdef TEST_TIMER */ - -/* msg_context_t *d = args; */ -/* void *data; */ -/* int size; */ -/* int priority; */ - -/* struct timeval t1, t2; */ -/* long long t; */ -/* struct timespec ts; */ -/* unsigned int delay = 250*1000; */ -/* while(1) { */ -/* gettimeofday(&t1, NULL); */ -/* enb_agent_sleep_until(&ts, delay); */ -/* gettimeofday(&t2, NULL); */ -/* t = ((t2.tv_sec * 1000000) + t2.tv_usec) - ((t1.tv_sec * 1000000) + t1.tv_usec); */ -/* LOG_I(ENB_AGENT, "Call to sleep_until(%d) took %lld us\n", delay, t); */ -/* sleep(1); */ -/* } */ - -/* #endif */ -/* /\* while (1) { */ -/* // need logic for the timer, and */ -/* usleep(10); */ -/* if (message_put(d->tx_mq, data, size, priority)) goto error; */ -/* }*\/ */ - -/* return NULL; */ - -/* error: */ -/* printf("receive_thread: there was an error\n"); */ -/* return NULL; */ -/* } */ - void *receive_thread(void *args) { msg_context_t *d = args; @@ -168,10 +140,15 @@ void *receive_thread(void *args) { Protocol__ProgranMessage *msg; while (1) { - if (message_get(d->rx_mq, &data, &size, &priority)){ + if (enb_agent_msg_recv(d->mod_id, ENB_AGENT_DEFAULT, &data, &size, &priority)) { err_code = PROTOCOL__PROGRAN_ERR__MSG_DEQUEUING; goto error; } + + /* if (message_get(d->rx_mq, &data, &size, &priority)){ */ + /* err_code = PROTOCOL__PROGRAN_ERR__MSG_DEQUEUING; */ + /* goto error; */ + /* } */ LOG_D(ENB_AGENT,"received message with size %d\n", size); @@ -186,10 +163,15 @@ void *receive_thread(void *args) { if (msg != NULL){ data=enb_agent_pack_message(msg,&size); - if (message_put(d->tx_mq, data, size, priority)){ + if (enb_agent_msg_send(d->mod_id, ENB_AGENT_DEFAULT, data, size, priority)) { err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; goto error; } + + /* if (message_put(d->tx_mq, data, size, priority)){ */ + /* err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; */ + /* goto error; */ + /* } */ LOG_D(ENB_AGENT,"sent message with size %d\n", size); } @@ -229,7 +211,9 @@ pthread_t new_thread(void *(*f)(void *), void *b) { } int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ - + + int channel_id; + // set_enb_vars(mod_id, RAN_LTE_OAI); enb_agent[mod_id].mod_id = mod_id; @@ -255,48 +239,78 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ in_ip, in_port); - //#define TEST_TIMER 0 -#if !defined TEST_TIMER + /* + * Initialize the channel container + */ + enb_agent_init_channel_container(); - /* - * create a socket - */ - enb_agent[mod_id].link = new_link_client(in_ip, in_port); - if (enb_agent[mod_id].link == NULL) goto error; - - LOG_I(ENB_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n", - enb_agent[mod_id].mod_id, - in_ip, - in_port); - /* - * create a message queue - */ - - enb_agent[mod_id].send_queue = new_message_queue(); - if (enb_agent[mod_id].send_queue == NULL) goto error; - enb_agent[mod_id].receive_queue = new_message_queue(); - if (enb_agent[mod_id].receive_queue == NULL) goto error; - - /* - * create a link manager - */ - - enb_agent[mod_id].manager = create_link_manager(enb_agent[mod_id].send_queue, enb_agent[mod_id].receive_queue, enb_agent[mod_id].link); - if (enb_agent[mod_id].manager == NULL) goto error; + /*Create the async channel info*/ + enb_agent_instance_t *channel_info = enb_agent_async_channel_info(mod_id, in_ip, in_port); + + /*Create a channel using the async channel info*/ + channel_id = enb_agent_create_channel((void *) channel_info, + enb_agent_async_msg_send, + enb_agent_async_msg_recv, + enb_agent_async_release); - memset(&shared_ctxt, 0, sizeof(msg_context_t)); - shared_ctxt[mod_id].mod_id = mod_id; - shared_ctxt[mod_id].tx_mq = enb_agent[mod_id].send_queue; - shared_ctxt[mod_id].rx_mq = enb_agent[mod_id].receive_queue; + if (channel_id <= 0) { + goto error; + } + + enb_agent_channel_t *channel = get_channel(channel_id); + + if (channel == NULL) { + goto error; + } + + /*Register the channel for all underlying agents (use ENB_AGENT_MAX)*/ + enb_agent_register_channel(mod_id, channel, ENB_AGENT_MAX); + + /*Example of registration for a specific agent(MAC): + *enb_agent_register_channel(mod_id, channel, ENB_AGENT_MAC); + */ + + /* /\* */ + /* * create a socket */ + /* *\/ */ + /* enb_agent[mod_id].link = new_link_client(in_ip, in_port); */ + /* if (enb_agent[mod_id].link == NULL) goto error; */ + + /* LOG_I(ENB_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n", */ + /* enb_agent[mod_id].mod_id, */ + /* in_ip, */ + /* in_port); */ + /* /\* */ + /* * create a message queue */ + /* *\/ */ + + /* enb_agent[mod_id].send_queue = new_message_queue(); */ + /* if (enb_agent[mod_id].send_queue == NULL) goto error; */ + /* enb_agent[mod_id].receive_queue = new_message_queue(); */ + /* if (enb_agent[mod_id].receive_queue == NULL) goto error; */ + + /* /\* */ + /* * create a link manager */ + /* *\/ */ + + /* enb_agent[mod_id].manager = create_link_manager(enb_agent[mod_id].send_queue, enb_agent[mod_id].receive_queue, enb_agent[mod_id].link); */ + /* if (enb_agent[mod_id].manager == NULL) goto error; */ + + /* memset(&shared_ctxt, 0, sizeof(msg_context_t)); */ + + /* shared_ctxt[mod_id].mod_id = mod_id; */ + /* shared_ctxt[mod_id].tx_mq = enb_agent[mod_id].send_queue; */ + /* shared_ctxt[mod_id].rx_mq = enb_agent[mod_id].receive_queue; */ /* * start the enb agent rx thread */ + memset(&shared_ctxt, 0, sizeof(msg_context_t)); + shared_ctxt[mod_id].mod_id = mod_id; + new_thread(receive_thread, &shared_ctxt[mod_id]); - -#endif /* * initilize a timer @@ -304,8 +318,6 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ enb_agent_init_timer(); - - /* * start the enb agent task for tx and interaction with the underlying network function */ @@ -313,12 +325,7 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ if (itti_create_task (TASK_ENB_AGENT, enb_agent_task, (void *) &shared_ctxt[mod_id]) < 0) { LOG_E(ENB_AGENT, "Create task for eNB Agent failed\n"); return -1; - } - - //new_thread(send_thread, &shared_ctxt); - - //while (1) pause(); - + } LOG_I(ENB_AGENT,"client ends\n"); return 0; diff --git a/openair2/ENB_APP/enb_agent_defs.h b/openair2/ENB_APP/enb_agent_defs.h index 416e61a431..e7ffe60c3f 100644 --- a/openair2/ENB_APP/enb_agent_defs.h +++ b/openair2/ENB_APP/enb_agent_defs.h @@ -133,8 +133,8 @@ typedef struct { typedef struct { mid_t mod_id; - message_queue_t *tx_mq; - message_queue_t *rx_mq; + // message_queue_t *tx_mq; + // message_queue_t *rx_mq; xid_t tx_xid; xid_t rx_xid; } msg_context_t; diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 36b7788d23..41a3ff6a3b 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -836,19 +836,23 @@ void enb_agent_send_sr_info(mid_t mod_id, msg_context_t *context) { err_code_t err_code; /*TODO: Must use a proper xid*/ - int xid = 1; - err_code = enb_agent_mac_sr_info(mod_id, (void *) &xid, &msg); + err_code = enb_agent_mac_sr_info(mod_id, (void *) &(context->tx_xid), &msg); if (err_code < 0) { goto error; } if (msg != NULL){ data=enb_agent_pack_message(msg, &size); - - if (message_put(context->tx_mq, data, size, priority)){ + /*Send sr info using the MAC channel of the eNB*/ + if (enb_agent_msg_send(mod_id, ENB_AGENT_MAC, data, size, priority)) { err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; goto error; } + + /* if (message_put(context->tx_mq, data, size, priority)){ */ + /* err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; */ + /* goto error; */ + /* } */ LOG_D(ENB_AGENT,"sent message with size %d\n", size); } error: From 2fbe01e15fd2c020f6a448d20db16db16c5d2808 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 15 Jan 2016 16:38:37 +0200 Subject: [PATCH 065/413] Added support for timing messages in DL/UL --- cmake_targets/CMakeLists.txt | 2 ++ openair2/ENB_APP/MESSAGES/V2/header.proto | 6 +++- openair2/ENB_APP/MESSAGES/V2/progran.proto | 21 +++++++++++++- .../ENB_APP/MESSAGES/V2/time_common.proto | 29 +++++++++++++++++++ openair2/ENB_APP/enb_agent_handler.c | 5 ++++ 5 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 openair2/ENB_APP/MESSAGES/V2/time_common.proto diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 56ee7b71d3..a040013e56 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -709,6 +709,7 @@ if (ENB_AGENT_SB_IF) ${PRPT_MSG_DIR}/progran.proto ${PRPT_MSG_DIR}/stats_common.proto ${PRPT_MSG_DIR}/stats_messages.proto + ${PRPT_MSG_DIR}/time_common.proto ) set(PRPT_C_DIR ${protobuf_generated_dir}/${PRPTDIR}) @@ -720,6 +721,7 @@ if (ENB_AGENT_SB_IF) ${PRPT_C_DIR}/progran.pb-c.c ${PRPT_C_DIR}/stats_common.pb-c.c ${PRPT_C_DIR}/stats_messages.pb-c.c + ${PRPT_C_DIR}/time_common.pb-c.c ) file(GLOB prpt_h ${PRPT_C_DIR}/*.h) diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index 5670b9bd77..7130f8448c 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -15,8 +15,12 @@ enum prp_type { // Statistics and measurement messages PRPT_STATS_REQUEST = 3; PRPT_STATS_REPLY = 4; + + // Time indication messages + PRPT_DL_TRIGGER = 5; + PRPT_UL_TRIGGER = 6; //Asynchronous messages - PRPT_UL_SR_INFO = 5; + PRPT_UL_SR_INFO = 7; } diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index 53718b87c4..314678b1d6 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -3,6 +3,7 @@ package protocol; import "stats_messages.proto"; import "header.proto"; +import "time_common.proto"; message progran_message { optional progran_direction msg_dir = 100; @@ -12,7 +13,9 @@ message progran_message { prp_echo_reply echo_reply_msg = 3; prp_stats_request stats_request_msg = 4; prp_stats_reply stats_reply_msg = 5; - prp_ul_sr_info ul_sr_info_msg = 6; + prp_dl_trigger dl_trigger_msg = 6; + prp_ul_trigger ul_trigger_msg = 7; + prp_ul_sr_info ul_sr_info_msg = 8; } } @@ -83,6 +86,22 @@ message prp_stats_reply { repeated prp_cell_stats_report cell_report = 3; } +// +// Time indication messages +// + +message prp_dl_trigger { + optional prp_header header = 1; + optional uint32 sfn_sf = 2; + repeated prp_dl_info dl_info = 3; +} + +message prp_ul_trigger { + optional prp_header header = 1; + optional uint32 sfn_sf = 2; + repeated prp_ul_info ul_info = 3; +} + // // Asynchronous messages // diff --git a/openair2/ENB_APP/MESSAGES/V2/time_common.proto b/openair2/ENB_APP/MESSAGES/V2/time_common.proto new file mode 100644 index 0000000000..4c3ac4911e --- /dev/null +++ b/openair2/ENB_APP/MESSAGES/V2/time_common.proto @@ -0,0 +1,29 @@ +package protocol; + +enum prp_harq_status { + PRHS_ACK = 0; + PRHS_NACK = 1; + PRHS_DTX = 2; +} + +enum prp_reception_status { + PRRS_OK = 0; + PRRS_NOT_OK = 1; + PRRS_NOT_VALID = 2; +} + +message prp_dl_info { + optional uint32 rnti = 1; + optional uint32 harq_process_id = 2; + repeated uint32 harq_status = 3; + optional uint32 serv_cell_index = 4; +} + +message prp_ul_info { + optional uint32 rnti = 1; + repeated uint32 ul_reception = 2; + optional uint32 reception_status = 3; + optional uint32 tpc = 4; + optional uint32 serv_cell_index = 5; +} + diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 0f5146fe6d..62b026e63b 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -47,6 +47,9 @@ enb_agent_message_decoded_callback messages_callback[][3] = { {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG*/ //Must add handler when receiving echo reply {enb_agent_mac_handle_stats, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG*/ {0,0,0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG*/ + {0,0,0}, /*DL_TRIGGER*/ + {0,0,0}, /*UL_TRIGGER*/ + {0,0,0}, /*SR_INFO*/ }; @@ -56,6 +59,8 @@ enb_agent_message_destruction_callback message_destruction_callback[] = { enb_agent_destroy_echo_reply, enb_agent_mac_destroy_stats_request, enb_agent_mac_destroy_stats_reply, + 0, + 0, enb_agent_mac_destroy_sr_info, }; From 5cec297209a9253f0a342e38778c99e94af50060 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 15 Jan 2016 18:07:42 +0200 Subject: [PATCH 066/413] Implemented handlers for the UL/DL trigger messages --- openair2/ENB_APP/enb_agent_handler.c | 4 +- openair2/ENB_APP/enb_agent_mac.c | 261 +++++++++++++++++++++++++- openair2/ENB_APP/enb_agent_mac.h | 13 ++ openair2/ENB_APP/enb_agent_mac_defs.h | 4 + 4 files changed, 276 insertions(+), 6 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 62b026e63b..4a936ff3db 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -59,8 +59,8 @@ enb_agent_message_destruction_callback message_destruction_callback[] = { enb_agent_destroy_echo_reply, enb_agent_mac_destroy_stats_request, enb_agent_mac_destroy_stats_reply, - 0, - 0, + enb_agent_mac_destroy_dl_trigger, + enb_agent_mac_destroy_ul_trigger, enb_agent_mac_destroy_sr_info, }; diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 41a3ff6a3b..194d8c96b8 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -828,6 +828,209 @@ int enb_agent_mac_destroy_sr_info(Protocol__ProgranMessage *msg) { return -1; } +int enb_agent_mac_dl_trigger(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { + Protocol__PrpHeader *header; + int i,j; + const int xid = *((int *)params); + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_DL_TRIGGER, &header) != 0) + goto error; + + Protocol__PrpDlTrigger *dl_trigger_msg; + dl_trigger_msg = malloc(sizeof(Protocol__PrpDlTrigger)); + if (dl_trigger_msg == NULL) { + goto error; + } + protocol__prp_dl_trigger__init(dl_trigger_msg); + + dl_trigger_msg->header = header; + dl_trigger_msg->has_sfn_sf = 1; + dl_trigger_msg->sfn_sf = get_sfn_sf(mod_id); + + /*TODO: Fill in the number of dl HARQ related info, based on the number of currently + *transmitting UEs + */ + dl_trigger_msg->n_dl_info = get_num_ues(mod_id); + + Protocol__PrpDlInfo **dl_info = NULL; + + if (dl_trigger_msg->n_dl_info > 0) { + dl_info = malloc(sizeof(Protocol__PrpDlInfo *) * dl_trigger_msg->n_dl_info); + if(dl_info == NULL) + goto error; + //Fill the status of the current HARQ process for each UE + for(i = 0; i++; i < dl_trigger_msg->n_dl_info) { + dl_info[i] = malloc(sizeof(Protocol__PrpDlInfo)); + if(dl_info[i] == NULL) + goto error; + protocol__prp_dl_info__init(dl_info[i]); + dl_info[i]->rnti = get_ue_crnti(mod_id, i); + dl_info[i]->has_rnti = 1; + /*TODO: fill in the right id of this round's HARQ process for this UE*/ + dl_info[i]->harq_process_id = 1; + dl_info[i]->has_harq_process_id = 1; + /*TODO: fill in the status of the HARQ process (2 TBs)*/ + dl_info[i]->n_harq_status = 2; + dl_info[i]->harq_status = malloc(sizeof(uint32_t) * dl_info[i]->n_harq_status); + for (j = 0; j < dl_info[j]->n_harq_status; j++) { + dl_info[i]->harq_status[j] = PROTOCOL__PRP_HARQ_STATUS__PRHS_ACK; + } + /*TODO: fill in the serving cell index for this UE */ + dl_info[i]->serv_cell_index = 0; + dl_info[i]->has_serv_cell_index = 1; + } + } + + dl_trigger_msg->dl_info = dl_info; + + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if(*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_DL_TRIGGER_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + (*msg)->dl_trigger_msg = dl_trigger_msg; + return 0; + + error: + if (header != NULL) + free(header); + if (dl_trigger_msg != NULL) { + for (i = 0; i < dl_trigger_msg->n_dl_info; i++) { + free(dl_trigger_msg->dl_info[i]->harq_status); + } + free(dl_trigger_msg->dl_info); + free(dl_trigger_msg); + } + if(*msg != NULL) + free(*msg); + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +int enb_agent_mac_destroy_dl_trigger(Protocol__ProgranMessage *msg) { + int i; + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_DL_TRIGGER_MSG) + goto error; + + free(msg->dl_trigger_msg->header); + for (i = 0; i < msg->dl_trigger_msg->n_dl_info; i++) { + free(msg->dl_trigger_msg->dl_info[i]->harq_status); + } + free(msg->dl_trigger_msg->dl_info); + free(msg->dl_trigger_msg); + free(msg); + + return 0; + + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +int enb_agent_mac_ul_trigger(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { + Protocol__PrpHeader *header; + int i,j; + const int xid = *((int *)params); + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_UL_TRIGGER, &header) != 0) + goto error; + + Protocol__PrpUlTrigger *ul_trigger_msg; + ul_trigger_msg = malloc(sizeof(Protocol__PrpUlTrigger)); + if (ul_trigger_msg == NULL) { + goto error; + } + protocol__prp_ul_trigger__init(ul_trigger_msg); + + ul_trigger_msg->header = header; + ul_trigger_msg->has_sfn_sf = 1; + /*TODO: Must fix this to get the proper subframe number*/ + ul_trigger_msg->sfn_sf = get_sfn_sf(mod_id); + + /*TODO: Fill in the number of UL reception status related info, based on the number of currently + *transmitting UEs + */ + ul_trigger_msg->n_ul_info = get_num_ues(mod_id); + + Protocol__PrpUlInfo **ul_info = NULL; + + if (ul_trigger_msg->n_ul_info > 0) { + ul_info = malloc(sizeof(Protocol__PrpUlInfo *) * ul_trigger_msg->n_ul_info); + if(ul_info == NULL) + goto error; + //Fill the reception info for each transmitting UE + for(i = 0; i++; i < ul_trigger_msg->n_ul_info) { + ul_info[i] = malloc(sizeof(Protocol__PrpUlInfo)); + if(ul_info[i] == NULL) + goto error; + protocol__prp_ul_info__init(ul_info[i]); + ul_info[i]->rnti = get_ue_crnti(mod_id, i); + ul_info[i]->has_rnti = 1; + /*TODO: fill in the Tx power control command for this UE (if available)*/ + ul_info[i]->tpc = 1; + ul_info[i]->has_tpc = 0; + /*TODO: fill in the amount of data in bytes in the MAC SDU received in this subframe for the + given logical channel*/ + ul_info[i]->n_ul_reception = 11; + ul_info[i]->ul_reception = malloc(sizeof(uint32_t) * ul_info[i]->n_ul_reception); + for (j = 0; j < ul_info[j]->n_ul_reception; j++) { + ul_info[i]->ul_reception[j] = 100; + } + /*TODO: Fill in the reception status for each UEs data*/ + ul_info[i]->reception_status = PROTOCOL__PRP_RECEPTION_STATUS__PRRS_OK; + ul_info[i]->has_reception_status = 1; + /*TODO: fill in the serving cell index for this UE */ + ul_info[i]->serv_cell_index = 0; + ul_info[i]->has_serv_cell_index = 1; + } + } + + ul_trigger_msg->ul_info = ul_info; + + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if(*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_UL_TRIGGER_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + (*msg)->ul_trigger_msg = ul_trigger_msg; + return 0; + + error: + if (header != NULL) + free(header); + if (ul_trigger_msg != NULL) { + for (i = 0; i < ul_trigger_msg->n_ul_info; i++) { + free(ul_trigger_msg->ul_info[i]->reception_status); + } + free(ul_trigger_msg->ul_info); + free(ul_trigger_msg); + } + if(*msg != NULL) + free(*msg); + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +int enb_agent_mac_destroy_ul_trigger(Protocol__ProgranMessage *msg) { + int i; + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_UL_TRIGGER_MSG) + goto error; + + free(msg->ul_trigger_msg->header); + for (i = 0; i < msg->ul_trigger_msg->n_ul_info; i++) { + free(msg->ul_trigger_msg->ul_info[i]->reception_status); + } + free(msg->ul_trigger_msg->ul_info); + free(msg->ul_trigger_msg); + free(msg); + + return 0; + + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + void enb_agent_send_sr_info(mid_t mod_id, msg_context_t *context) { int size; Protocol__ProgranMessage *msg; @@ -849,16 +1052,66 @@ void enb_agent_send_sr_info(mid_t mod_id, msg_context_t *context) { goto error; } - /* if (message_put(context->tx_mq, data, size, priority)){ */ - /* err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; */ - /* goto error; */ - /* } */ LOG_D(ENB_AGENT,"sent message with size %d\n", size); } error: LOG_D(ENB_AGENT, "Could not send sr message\n"); } +void enb_agent_send_dl_trigger(mid_t mod_id, msg_context_t *context) { + int size; + Protocol__ProgranMessage *msg; + void *data; + int priority; + err_code_t err_code; + + /*TODO: Must use a proper xid*/ + err_code = enb_agent_mac_dl_trigger(mod_id, (void *) &(context->tx_xid), &msg); + if (err_code < 0) { + goto error; + } + + if (msg != NULL){ + data=enb_agent_pack_message(msg, &size); + /*Send sr info using the MAC channel of the eNB*/ + if (enb_agent_msg_send(mod_id, ENB_AGENT_MAC, data, size, priority)) { + err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + goto error; + } + + LOG_D(ENB_AGENT,"sent message with size %d\n", size); + } + error: + LOG_D(ENB_AGENT, "Could not send dl trigger message\n"); +} + +void enb_agent_send_ul_trigger(mid_t mod_id, msg_context_t *context) { + int size; + Protocol__ProgranMessage *msg; + void *data; + int priority; + err_code_t err_code; + + /*TODO: Must use a proper xid*/ + err_code = enb_agent_mac_ul_trigger(mod_id, (void *) &(context->tx_xid), &msg); + if (err_code < 0) { + goto error; + } + + if (msg != NULL){ + data=enb_agent_pack_message(msg, &size); + /*Send sr info using the MAC channel of the eNB*/ + if (enb_agent_msg_send(mod_id, ENB_AGENT_MAC, data, size, priority)) { + err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + goto error; + } + + LOG_D(ENB_AGENT,"sent message with size %d\n", size); + } + error: + LOG_D(ENB_AGENT, "Could not send ul trigger message\n"); +} + int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { if (!mac_agent_registered[mod_id]) { LOG_E(MAC, "MAC agent for eNB %d is already registered\n", mod_id); diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index 7945082410..18a91716b0 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -94,6 +94,14 @@ int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__ProgranMes int enb_agent_mac_destroy_sr_info(Protocol__ProgranMessage *msg); +int enb_agent_mac_dl_trigger(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); + +int enb_agent_mac_destroy_dl_trigger(Protocol__ProgranMessage *msg); + +int enb_agent_mac_ul_trigger(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); + +int enb_agent_mac_destroy_ul_trigger(Protocol__ProgranMessage *msg); + /********************************** * eNB agent - technology mac API @@ -102,6 +110,11 @@ int enb_agent_mac_destroy_sr_info(Protocol__ProgranMessage *msg); /*Inform controller about received scheduling requests during a subframe*/ void enb_agent_send_sr_info(mid_t mod_id, msg_context_t *context); +/*Inform the controller about the current UL/DL subframe*/ +void enb_agent_send_dl_trigger(mid_t mod_id, msg_context_t *context); + +void enb_agent_send_ul_trigger(mid_t mod_id, msg_context_t *context); + /*Register technology specific interface callbacks*/ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface); diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/enb_agent_mac_defs.h index 28a424706b..14d149f40c 100644 --- a/openair2/ENB_APP/enb_agent_mac_defs.h +++ b/openair2/ENB_APP/enb_agent_mac_defs.h @@ -46,6 +46,10 @@ typedef struct { /// Inform the controller about the scheduling requests received during the subframe void (*enb_agent_send_sr_info)(mid_t mod_id, msg_context_t *context); + + /// Inform the controller about the current UL/DL subframe + void (*enb_agent_send_dl_trigger)(mid_t mod_id, msg_context_t *context); + void (*enb_agent_send_ul_trigger)(mid_t mod_id, msg_context_t *context); /*TODO: Fill in with the rest of the MAC layer technology specific callbacks (UL/DL scheduling, RACH info etc)*/ From 876d9eac5214e3ad954d3ac075f64bced0785f5a Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 19 Jan 2016 10:12:48 +0000 Subject: [PATCH 067/413] Fixed bug when creating cell report stats reply --- openair2/ENB_APP/enb_agent_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 194d8c96b8..d13f7fa63a 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -595,7 +595,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, // Fill in the Cell reports for (i = 0; i < report_config->nr_cc; i++) { cell_report[i] = malloc(sizeof(Protocol__PrpCellStatsReport)); - if(ue_report[i] == NULL) + if(cell_report[i] == NULL) goto error; protocol__prp_cell_stats_report__init(cell_report[i]); cell_report[i]->carrier_index = report_config->cc_report_type[i].cc_id; From 1f520630658f071c32b89b13cfd126cdeea0a002 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 19 Jan 2016 11:11:05 +0000 Subject: [PATCH 068/413] Merged UL/DL trigger messages to a single SF trigger message --- openair2/ENB_APP/MESSAGES/V2/header.proto | 5 +- openair2/ENB_APP/MESSAGES/V2/progran.proto | 14 +- openair2/ENB_APP/enb_agent_handler.c | 6 +- openair2/ENB_APP/enb_agent_mac.c | 177 ++++++--------------- openair2/ENB_APP/enb_agent_mac.h | 12 +- openair2/ENB_APP/enb_agent_mac_defs.h | 3 +- 6 files changed, 60 insertions(+), 157 deletions(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index 7130f8448c..8534d2f304 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -17,10 +17,9 @@ enum prp_type { PRPT_STATS_REPLY = 4; // Time indication messages - PRPT_DL_TRIGGER = 5; - PRPT_UL_TRIGGER = 6; + PRPT_SF_TRIGGER = 5; //Asynchronous messages - PRPT_UL_SR_INFO = 7; + PRPT_UL_SR_INFO = 6; } diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index 314678b1d6..730726aab4 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -13,9 +13,8 @@ message progran_message { prp_echo_reply echo_reply_msg = 3; prp_stats_request stats_request_msg = 4; prp_stats_reply stats_reply_msg = 5; - prp_dl_trigger dl_trigger_msg = 6; - prp_ul_trigger ul_trigger_msg = 7; - prp_ul_sr_info ul_sr_info_msg = 8; + prp_sf_trigger sf_trigger_msg = 6; + prp_ul_sr_info ul_sr_info_msg = 7; } } @@ -90,16 +89,11 @@ message prp_stats_reply { // Time indication messages // -message prp_dl_trigger { +message prp_sf_trigger { optional prp_header header = 1; optional uint32 sfn_sf = 2; repeated prp_dl_info dl_info = 3; -} - -message prp_ul_trigger { - optional prp_header header = 1; - optional uint32 sfn_sf = 2; - repeated prp_ul_info ul_info = 3; + repeated prp_ul_info ul_info = 4; } // diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 4a936ff3db..7b63227d7e 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -47,8 +47,7 @@ enb_agent_message_decoded_callback messages_callback[][3] = { {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG*/ //Must add handler when receiving echo reply {enb_agent_mac_handle_stats, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG*/ {0,0,0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG*/ - {0,0,0}, /*DL_TRIGGER*/ - {0,0,0}, /*UL_TRIGGER*/ + {0,0,0}, /*PROTOCOK__PROGRAN_MESSAGE__MSG_SF_TRIGGER_MSG*/ {0,0,0}, /*SR_INFO*/ }; @@ -59,8 +58,7 @@ enb_agent_message_destruction_callback message_destruction_callback[] = { enb_agent_destroy_echo_reply, enb_agent_mac_destroy_stats_request, enb_agent_mac_destroy_stats_reply, - enb_agent_mac_destroy_dl_trigger, - enb_agent_mac_destroy_ul_trigger, + enb_agent_mac_destroy_sf_trigger, enb_agent_mac_destroy_sr_info, }; diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index d13f7fa63a..34423ee01a 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -828,37 +828,37 @@ int enb_agent_mac_destroy_sr_info(Protocol__ProgranMessage *msg) { return -1; } -int enb_agent_mac_dl_trigger(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { +int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { Protocol__PrpHeader *header; int i,j; const int xid = *((int *)params); - if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_DL_TRIGGER, &header) != 0) + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_SF_TRIGGER, &header) != 0) goto error; - Protocol__PrpDlTrigger *dl_trigger_msg; - dl_trigger_msg = malloc(sizeof(Protocol__PrpDlTrigger)); - if (dl_trigger_msg == NULL) { + Protocol__PrpSfTrigger *sf_trigger_msg; + sf_trigger_msg = malloc(sizeof(Protocol__PrpSfTrigger)); + if (sf_trigger_msg == NULL) { goto error; } - protocol__prp_dl_trigger__init(dl_trigger_msg); + protocol__prp_sf_trigger__init(sf_trigger_msg); - dl_trigger_msg->header = header; - dl_trigger_msg->has_sfn_sf = 1; - dl_trigger_msg->sfn_sf = get_sfn_sf(mod_id); + sf_trigger_msg->header = header; + sf_trigger_msg->has_sfn_sf = 1; + sf_trigger_msg->sfn_sf = get_sfn_sf(mod_id); /*TODO: Fill in the number of dl HARQ related info, based on the number of currently *transmitting UEs */ - dl_trigger_msg->n_dl_info = get_num_ues(mod_id); + sf_trigger_msg->n_dl_info = get_num_ues(mod_id); Protocol__PrpDlInfo **dl_info = NULL; - if (dl_trigger_msg->n_dl_info > 0) { - dl_info = malloc(sizeof(Protocol__PrpDlInfo *) * dl_trigger_msg->n_dl_info); + if (sf_trigger_msg->n_dl_info > 0) { + dl_info = malloc(sizeof(Protocol__PrpDlInfo *) * sf_trigger_msg->n_dl_info); if(dl_info == NULL) goto error; //Fill the status of the current HARQ process for each UE - for(i = 0; i++; i < dl_trigger_msg->n_dl_info) { + for(i = 0; i++; i < sf_trigger_msg->n_dl_info) { dl_info[i] = malloc(sizeof(Protocol__PrpDlInfo)); if(dl_info[i] == NULL) goto error; @@ -880,85 +880,21 @@ int enb_agent_mac_dl_trigger(mid_t mod_id, const void *params, Protocol__Progran } } - dl_trigger_msg->dl_info = dl_info; - - *msg = malloc(sizeof(Protocol__ProgranMessage)); - if(*msg == NULL) - goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_DL_TRIGGER_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; - (*msg)->dl_trigger_msg = dl_trigger_msg; - return 0; - - error: - if (header != NULL) - free(header); - if (dl_trigger_msg != NULL) { - for (i = 0; i < dl_trigger_msg->n_dl_info; i++) { - free(dl_trigger_msg->dl_info[i]->harq_status); - } - free(dl_trigger_msg->dl_info); - free(dl_trigger_msg); - } - if(*msg != NULL) - free(*msg); - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - return -1; -} + sf_trigger_msg->dl_info = dl_info; -int enb_agent_mac_destroy_dl_trigger(Protocol__ProgranMessage *msg) { - int i; - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_DL_TRIGGER_MSG) - goto error; - - free(msg->dl_trigger_msg->header); - for (i = 0; i < msg->dl_trigger_msg->n_dl_info; i++) { - free(msg->dl_trigger_msg->dl_info[i]->harq_status); - } - free(msg->dl_trigger_msg->dl_info); - free(msg->dl_trigger_msg); - free(msg); - - return 0; - - error: - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - return -1; -} - -int enb_agent_mac_ul_trigger(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { - Protocol__PrpHeader *header; - int i,j; - const int xid = *((int *)params); - if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_UL_TRIGGER, &header) != 0) - goto error; - - Protocol__PrpUlTrigger *ul_trigger_msg; - ul_trigger_msg = malloc(sizeof(Protocol__PrpUlTrigger)); - if (ul_trigger_msg == NULL) { - goto error; - } - protocol__prp_ul_trigger__init(ul_trigger_msg); - - ul_trigger_msg->header = header; - ul_trigger_msg->has_sfn_sf = 1; - /*TODO: Must fix this to get the proper subframe number*/ - ul_trigger_msg->sfn_sf = get_sfn_sf(mod_id); - - /*TODO: Fill in the number of UL reception status related info, based on the number of currently + /*TODO: Fill in the number of UL reception status related info, based on the number of currently *transmitting UEs */ - ul_trigger_msg->n_ul_info = get_num_ues(mod_id); + sf_trigger_msg->n_ul_info = get_num_ues(mod_id); Protocol__PrpUlInfo **ul_info = NULL; - if (ul_trigger_msg->n_ul_info > 0) { - ul_info = malloc(sizeof(Protocol__PrpUlInfo *) * ul_trigger_msg->n_ul_info); + if (sf_trigger_msg->n_ul_info > 0) { + ul_info = malloc(sizeof(Protocol__PrpUlInfo *) * sf_trigger_msg->n_ul_info); if(ul_info == NULL) goto error; //Fill the reception info for each transmitting UE - for(i = 0; i++; i < ul_trigger_msg->n_ul_info) { + for(i = 0; i++; i < sf_trigger_msg->n_ul_info) { ul_info[i] = malloc(sizeof(Protocol__PrpUlInfo)); if(ul_info[i] == NULL) goto error; @@ -984,26 +920,30 @@ int enb_agent_mac_ul_trigger(mid_t mod_id, const void *params, Protocol__Progran } } - ul_trigger_msg->ul_info = ul_info; - + sf_trigger_msg->ul_info = ul_info; + *msg = malloc(sizeof(Protocol__ProgranMessage)); if(*msg == NULL) goto error; protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_UL_TRIGGER_MSG; + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_SF_TRIGGER_MSG; (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; - (*msg)->ul_trigger_msg = ul_trigger_msg; + (*msg)->sf_trigger_msg = sf_trigger_msg; return 0; error: if (header != NULL) free(header); - if (ul_trigger_msg != NULL) { - for (i = 0; i < ul_trigger_msg->n_ul_info; i++) { - free(ul_trigger_msg->ul_info[i]->reception_status); + if (sf_trigger_msg != NULL) { + for (i = 0; i < sf_trigger_msg->n_dl_info; i++) { + free(sf_trigger_msg->dl_info[i]->harq_status); } - free(ul_trigger_msg->ul_info); - free(ul_trigger_msg); + free(sf_trigger_msg->dl_info); + for (i = 0; i < sf_trigger_msg->n_ul_info; i++) { + free(sf_trigger_msg->ul_info[i]->reception_status); + } + free(sf_trigger_msg->ul_info); + free(sf_trigger_msg); } if(*msg != NULL) free(*msg); @@ -1011,17 +951,21 @@ int enb_agent_mac_ul_trigger(mid_t mod_id, const void *params, Protocol__Progran return -1; } -int enb_agent_mac_destroy_ul_trigger(Protocol__ProgranMessage *msg) { +int enb_agent_mac_destroy_sf_trigger(Protocol__ProgranMessage *msg) { int i; - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_UL_TRIGGER_MSG) + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_SF_TRIGGER_MSG) goto error; - free(msg->ul_trigger_msg->header); - for (i = 0; i < msg->ul_trigger_msg->n_ul_info; i++) { - free(msg->ul_trigger_msg->ul_info[i]->reception_status); + free(msg->sf_trigger_msg->header); + for (i = 0; i < msg->sf_trigger_msg->n_dl_info; i++) { + free(msg->sf_trigger_msg->dl_info[i]->harq_status); } - free(msg->ul_trigger_msg->ul_info); - free(msg->ul_trigger_msg); + free(msg->sf_trigger_msg->dl_info); + for (i = 0; i < msg->sf_trigger_msg->n_ul_info; i++) { + free(msg->sf_trigger_msg->ul_info[i]->reception_status); + } + free(msg->sf_trigger_msg->ul_info); + free(msg->sf_trigger_msg); free(msg); return 0; @@ -1058,7 +1002,7 @@ void enb_agent_send_sr_info(mid_t mod_id, msg_context_t *context) { LOG_D(ENB_AGENT, "Could not send sr message\n"); } -void enb_agent_send_dl_trigger(mid_t mod_id, msg_context_t *context) { +void enb_agent_send_sf_trigger(mid_t mod_id, msg_context_t *context) { int size; Protocol__ProgranMessage *msg; void *data; @@ -1066,7 +1010,7 @@ void enb_agent_send_dl_trigger(mid_t mod_id, msg_context_t *context) { err_code_t err_code; /*TODO: Must use a proper xid*/ - err_code = enb_agent_mac_dl_trigger(mod_id, (void *) &(context->tx_xid), &msg); + err_code = enb_agent_mac_sf_trigger(mod_id, (void *) &(context->tx_xid), &msg); if (err_code < 0) { goto error; } @@ -1082,34 +1026,7 @@ void enb_agent_send_dl_trigger(mid_t mod_id, msg_context_t *context) { LOG_D(ENB_AGENT,"sent message with size %d\n", size); } error: - LOG_D(ENB_AGENT, "Could not send dl trigger message\n"); -} - -void enb_agent_send_ul_trigger(mid_t mod_id, msg_context_t *context) { - int size; - Protocol__ProgranMessage *msg; - void *data; - int priority; - err_code_t err_code; - - /*TODO: Must use a proper xid*/ - err_code = enb_agent_mac_ul_trigger(mod_id, (void *) &(context->tx_xid), &msg); - if (err_code < 0) { - goto error; - } - - if (msg != NULL){ - data=enb_agent_pack_message(msg, &size); - /*Send sr info using the MAC channel of the eNB*/ - if (enb_agent_msg_send(mod_id, ENB_AGENT_MAC, data, size, priority)) { - err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; - goto error; - } - - LOG_D(ENB_AGENT,"sent message with size %d\n", size); - } - error: - LOG_D(ENB_AGENT, "Could not send ul trigger message\n"); + LOG_D(ENB_AGENT, "Could not send sf trigger message\n"); } int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { @@ -1120,6 +1037,7 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->agent_ctxt = &shared_ctxt[mod_id]; xface->enb_agent_send_sr_info = enb_agent_send_sr_info; + xface->enb_agent_send_sf_trigger = enb_agent_send_sf_trigger; mac_agent_registered[mod_id] = 1; return 1; @@ -1134,6 +1052,7 @@ int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->agent_ctxt = NULL; xface->enb_agent_send_sr_info = NULL; + xface->enb_agent_send_sf_trigger = NULL; mac_agent_registered[mod_id] = NULL; return 1; diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index 18a91716b0..4f8afbac08 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -94,13 +94,9 @@ int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__ProgranMes int enb_agent_mac_destroy_sr_info(Protocol__ProgranMessage *msg); -int enb_agent_mac_dl_trigger(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); -int enb_agent_mac_destroy_dl_trigger(Protocol__ProgranMessage *msg); - -int enb_agent_mac_ul_trigger(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); - -int enb_agent_mac_destroy_ul_trigger(Protocol__ProgranMessage *msg); +int enb_agent_mac_destroy_sf_trigger(Protocol__ProgranMessage *msg); /********************************** @@ -111,9 +107,7 @@ int enb_agent_mac_destroy_ul_trigger(Protocol__ProgranMessage *msg); void enb_agent_send_sr_info(mid_t mod_id, msg_context_t *context); /*Inform the controller about the current UL/DL subframe*/ -void enb_agent_send_dl_trigger(mid_t mod_id, msg_context_t *context); - -void enb_agent_send_ul_trigger(mid_t mod_id, msg_context_t *context); +void enb_agent_send_sf_trigger(mid_t mod_id, msg_context_t *context); /*Register technology specific interface callbacks*/ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface); diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/enb_agent_mac_defs.h index 14d149f40c..a570165919 100644 --- a/openair2/ENB_APP/enb_agent_mac_defs.h +++ b/openair2/ENB_APP/enb_agent_mac_defs.h @@ -48,8 +48,7 @@ typedef struct { void (*enb_agent_send_sr_info)(mid_t mod_id, msg_context_t *context); /// Inform the controller about the current UL/DL subframe - void (*enb_agent_send_dl_trigger)(mid_t mod_id, msg_context_t *context); - void (*enb_agent_send_ul_trigger)(mid_t mod_id, msg_context_t *context); + void (*enb_agent_send_sf_trigger)(mid_t mod_id, msg_context_t *context); /*TODO: Fill in with the rest of the MAC layer technology specific callbacks (UL/DL scheduling, RACH info etc)*/ From 78bc736c19584dcac9106ad33cbaa39e0b9d05d2 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 19 Jan 2016 14:51:20 +0000 Subject: [PATCH 069/413] Fixed frame-subframe numbering bug --- openair2/ENB_APP/enb_agent_common.c | 25 +++++++++++++++++-------- openair2/ENB_APP/enb_agent_common.h | 10 ++++++++-- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 8d9997e746..ce838766ee 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -292,13 +292,18 @@ int get_current_time_ms (mid_t mod_id, int subframe_flag){ } -int get_current_frame (mid_t mod_id) { - +unsigned int 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; } -int get_current_subframe (mid_t mod_id) { +unsigned int get_current_system_frame_num(mid_t mod_id) { + return (get_current_frame(mod_id) %1024); +} + +unsigned int get_current_subframe (mid_t mod_id) { return ((eNB_MAC_INST *)enb[mod_id])->subframe; @@ -306,12 +311,16 @@ int get_current_subframe (mid_t mod_id) { uint16_t get_sfn_sf (mid_t mod_id) { - uint16_t frame, subframe; - uint16_t sfn_sf; + frame_t frame; + sub_frame_t subframe; + uint16_t sfn_sf, frame_mask, sf_mask; + + frame = (frame_t) get_current_system_frame_num(mod_id); + subframe = (sub_frame_t) get_current_subframe(mod_id); + frame_mask = ((1<<12) - 1); + sf_mask = ((1<<4) -1); + sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4); - frame = (uint16_t) get_current_frame(mod_id); - subframe = (uint16_t) get_current_subframe(mod_id); - sfn_sf = (subframe << 12) | frame; return sfn_sf; } diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index f4add1ae2e..4762637b66 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -109,9 +109,15 @@ void set_enb_vars(mid_t mod_id, ran_name_t ran); int get_current_time_ms (mid_t mod_id, int subframe_flag); -int get_current_frame(mid_t mod_id); +/*Return the current frame number + *Could be using implementation specific numbering of frames + */ +unsigned int get_current_frame(mid_t mod_id); -int get_current_subframe(mid_t mod_id); +/*Return the current SFN (0-1023)*/ +unsigned int get_current_system_frame_num(mid_t mod_id); + +unsigned int 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 progRAN protocol*/ From a054eb81396bb49504fb8875ffafb719ff87dbbc Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 21 Jan 2016 15:27:52 +0000 Subject: [PATCH 070/413] Added helper functions for the continuous update of MAC stats --- cmake_targets/CMakeLists.txt | 1 + openair2/ENB_APP/enb_agent_defs.h | 1 + openair2/ENB_APP/enb_agent_mac_internal.c | 560 ++++++++++++++++++++++ openair2/ENB_APP/enb_agent_mac_internal.h | 104 ++++ 4 files changed, 666 insertions(+) create mode 100644 openair2/ENB_APP/enb_agent_mac_internal.c create mode 100644 openair2/ENB_APP/enb_agent_mac_internal.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index a040013e56..eb9474e670 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -751,6 +751,7 @@ if (ENB_AGENT_SB_IF) ${OPENAIR2_DIR}/ENB_APP/enb_agent_task_manager.c ${OPENAIR2_DIR}/ENB_APP/enb_agent_net_comm.c ${OPENAIR2_DIR}/ENB_APP/enb_agent_async.c + ${OPENAIR2_DIR}/ENB_APP/enb_agent_mac_internal.c ) set(ENB_AGENT_LIB ENB_AGENT) #include_directories(${OPENAIR2_DIR}/ENB_APP) diff --git a/openair2/ENB_APP/enb_agent_defs.h b/openair2/ENB_APP/enb_agent_defs.h index e7ffe60c3f..0ddbc2064e 100644 --- a/openair2/ENB_APP/enb_agent_defs.h +++ b/openair2/ENB_APP/enb_agent_defs.h @@ -44,6 +44,7 @@ #include "link_manager.h" #define NUM_MAX_ENB_AGENT 2 +#define NUM_MAX_UE 2048 #define DEFAULT_ENB_AGENT_IPv4_ADDRESS "127.0.0.1" #define DEFAULT_ENB_AGENT_PORT 2210 diff --git a/openair2/ENB_APP/enb_agent_mac_internal.c b/openair2/ENB_APP/enb_agent_mac_internal.c new file mode 100644 index 0000000000..c3cc584bcd --- /dev/null +++ b/openair2/ENB_APP/enb_agent_mac_internal.c @@ -0,0 +1,560 @@ +/******************************************************************************* + 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 enb_agent_mac_internal.c + * \brief Helper functions for the MAC agent + * \author Xenofon Foukas + * \date 2016 + * \version 0.1 + */ + +#include "enb_agent_mac_internal.h" + +Protocol__ProgranMessage * enb_agent_generate_diff_mac_stats_report(Protocol__ProgranMessage *new_message, + Protocol__ProgranMessage *old_message) { + + int i, j; + + Protocol__PrpStatsReply *old_report, *new_report; + + Protocol__PrpStatsReply *stats_reply_msg = NULL; + Protocol__ProgranMessage *msg = NULL; + + Protocol__PrpUeStatsReport **ue_report; + Protocol__PrpUeStatsReport *tmp_ue_report[NUM_MAX_UE]; + Protocol__PrpCellStatsReport **cell_report; + Protocol__PrpCellStatsReport *tmp_cell_report[NUM_MAX_UE]; + + old_report = old_message->stats_reply_msg; + new_report = new_message->stats_reply_msg; + + /*Flags to designate changes in various levels of the message*/ + int stats_had_changes = 0; + int ue_had_change = 0; + int cell_had_change = 0; + + /*See how many and which UE reports should be included in the final stats message*/ + int n_ue_report = 0; + int ue_found = 0; + + /*Go through each RNTI of the new report and see if it exists in the old one*/ + for (i = 0; i < new_report->n_ue_report; i++) { + for (j = 0; j < old_report->n_ue_report; i++) { + if (new_report->ue_report[i]->rnti == old_report->ue_report[j]->rnti) { + ue_found = 1; + /*Need to check if something changed*/ + if (compare_ue_stats_reports(new_report->ue_report[i], old_report->ue_report[j]) != 0) { + tmp_ue_report[n_ue_report] = copy_ue_stats_report(new_report->ue_report[i]); + n_ue_report++; + } + break; + } + } + if (!ue_found) { + tmp_ue_report[n_ue_report] = copy_ue_stats_report(new_report->ue_report[i]); + n_ue_report++; + } + ue_found = 0; + } + + /*See how many and which cell reports should be included in the final stats message*/ + int n_cell_report = 0; + int cell_found = 0; + + /*Go through each cell of the new report and see if it exists in the old one*/ + for (i = 0; i < new_report->n_cell_report; i++) { + for (j = 0; j < old_report->n_cell_report; i++) { + if (new_report->cell_report[i]->carrier_index == old_report->cell_report[j]->carrier_index) { + cell_found = 1; + /*Need to check if something changed*/ + if (compare_cell_stats_reports(new_report->cell_report[i], old_report->cell_report[j]) != 0) { + tmp_cell_report[n_cell_report] = copy_cell_stats_report(new_report->cell_report[i]); + n_cell_report++; + } + break; + } + } + if (!cell_found) { + tmp_cell_report[n_cell_report] = copy_cell_stats_report(new_report->cell_report[i]); + n_cell_report++; + } + cell_found = 0; + } + + /*TODO: create the reply message based on the findings*/ + /*Create ue report list*/ + if (n_ue_report > 0) { + ue_report = malloc(sizeof(Protocol__PrpUeStatsReport *)); + for (i = 0; i 0) { + cell_report = malloc(sizeof(Protocol__PrpCellStatsReport *)); + for (i = 0; i 0 || n_ue_report > 0) { + /*Create header*/ + int xid = old_report->header->xid; + Protocol__PrpHeader *header; + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_STATS_REPLY, &header) != 0) { + goto error; + } + stats_reply_msg = malloc(sizeof(Protocol__PrpStatsReply)); + protocol__prp_stats_reply__init(stats_reply_msg); + stats_reply_msg->header = header; + stats_reply_msg->n_ue_report = n_ue_report; + stats_reply_msg->ue_report = ue_report; + stats_reply_msg->n_cell_report = n_cell_report; + stats_reply_msg->cell_report = cell_report; + msg = malloc(sizeof(Protocol__ProgranMessage)); + if(msg == NULL) + goto error; + protocol__progran_message__init(msg); + msg->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG; + msg->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + msg->stats_reply_msg = stats_reply_msg; + } + return msg; + + error: + return NULL; +} + +int compare_ue_stats_reports(Protocol__PrpUeStatsReport *rep1, + Protocol__PrpUeStatsReport *rep2) { + return 1; +} + +int compare_cell_stats_reports(Protocol__PrpCellStatsReport *rep1, + Protocol__PrpCellStatsReport *rep2) { + return 1; +} + +Protocol__PrpUeStatsReport * copy_ue_stats_report(Protocol__PrpUeStatsReport * original) { + int i; + Protocol__PrpUeStatsReport *copy = malloc(sizeof(Protocol__PrpUeStatsReport)); + if (copy == NULL) + goto error; + protocol__prp_ue_stats_report__init(copy); + copy->rnti = original->rnti; + copy->has_rnti = original->has_rnti; + copy->flags = original->flags; + copy->has_flags = original->has_flags; + + if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_BSR) { + copy->n_bsr = original->n_bsr; + if (copy->n_bsr > 0) { + uint32_t *elem; + elem = (uint32_t *) malloc(sizeof(uint32_t)*copy->n_bsr); + if (elem == NULL) + goto error; + for (i = 0; i < original->n_bsr; i++) { + elem[i] = original->bsr[i]; + } + copy->bsr = elem; + } + } + + if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PRH) { + copy->has_phr = original->has_phr; + copy->phr = original->phr; + } + + if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_RLC_BS) { + copy->n_rlc_report = original->n_rlc_report; + if (copy->n_rlc_report > 0) { + Protocol__PrpRlcBsr ** rlc_reports; + rlc_reports = malloc(sizeof(Protocol__PrpRlcBsr) * copy->n_rlc_report); + if (rlc_reports == NULL) + goto error; + for (i = 0; i < copy->n_rlc_report; i++) { + rlc_reports[i] = copy_rlc_report(original->rlc_report[i]); + } + copy->rlc_report = rlc_reports; + } + } + + if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_MAC_CE_BS) { + copy->has_pending_mac_ces = original->has_pending_mac_ces; + copy->pending_mac_ces = original->pending_mac_ces; + + } + + if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI) { + copy->dl_cqi_report = copy_dl_cqi_report(original->dl_cqi_report); + } + + if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PBS) { + /*Copy the Paging Buffer report*/ + copy->pbr = copy_paging_buffer_report(original->pbr); + } + + if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_UL_CQI) { + /*TODO: Copy the UL report*/ + copy->ul_cqi_report = copy_ul_cqi_report(original->ul_cqi_report); + } + + return copy; + + error: + return NULL; +} + +Protocol__PrpRlcBsr * copy_rlc_report(Protocol__PrpRlcBsr * original) { + Protocol__PrpRlcBsr * copy = malloc(sizeof(Protocol__PrpRlcBsr)); + if (copy == NULL) + goto error; + protocol__prp_rlc_bsr__init(copy); + copy->lc_id = original->lc_id; + copy->has_lc_id = original->has_lc_id; + copy->tx_queue_size = original->tx_queue_size; + copy->has_tx_queue_size = original->has_tx_queue_size; + copy->tx_queue_hol_delay = original->tx_queue_hol_delay; + copy->has_tx_queue_hol_delay = original->has_tx_queue_hol_delay; + copy->retransmission_queue_size = original->retransmission_queue_size; + copy->has_retransmission_queue_size = original->has_retransmission_queue_size; + copy->retransmission_queue_hol_delay = original->retransmission_queue_hol_delay; + copy->has_retransmission_queue_hol_delay = original->has_retransmission_queue_hol_delay; + copy->status_pdu_size = original->status_pdu_size; + copy->has_status_pdu_size = original->has_status_pdu_size; + + return copy; + + error: + return NULL; +} + +Protocol__PrpUlCqiReport * copy_ul_cqi_report(Protocol__PrpUlCqiReport * original) { + int i, j; + + //Fill in the full UL CQI report of the UE + Protocol__PrpUlCqiReport *full_ul_report; + full_ul_report = malloc(sizeof(Protocol__PrpUlCqiReport)); + if(full_ul_report == NULL) { + goto error; + } + protocol__prp_ul_cqi_report__init(full_ul_report); + //TODO:Set the SFN and SF of the generated report + full_ul_report->sfn_sn = original->sfn_sn; + full_ul_report->has_sfn_sn = original->has_sfn_sn; + full_ul_report->n_cqi_meas = original->n_cqi_meas; + + Protocol__PrpUlCqi **ul_report; + ul_report = malloc(sizeof(Protocol__PrpUlCqi *) * full_ul_report->n_cqi_meas); + if(ul_report == NULL) + goto error; + for(i = 0; i++; i < full_ul_report->n_cqi_meas) { + ul_report[i] = malloc(sizeof(Protocol__PrpUlCqi)); + if(ul_report[i] == NULL) + goto error; + protocol__prp_ul_cqi__init(ul_report[i]); + ul_report[i]->type = original->cqi_meas[i]->type; + ul_report[i]->has_type = original->cqi_meas[i]->has_type; + ul_report[i]->n_sinr = original->cqi_meas[i]->n_sinr; + uint32_t *sinr_meas; + sinr_meas = (uint32_t *) malloc(sizeof(uint32_t) * ul_report[i]->n_sinr); + if (sinr_meas == NULL) + goto error; + for (j = 0; j < ul_report[i]->n_sinr; j++) { + sinr_meas[j] = original->cqi_meas[i]->sinr[j]; + } + ul_report[i]->sinr = sinr_meas; + ul_report[i]->serv_cell_index = original->cqi_meas[i]->serv_cell_index; + ul_report[i]->has_serv_cell_index = original->cqi_meas[i]->has_serv_cell_index; + } + full_ul_report->cqi_meas = ul_report; + + return full_ul_report; + + error: + return NULL; +} + +Protocol__PrpDlCqiReport * copy_dl_cqi_report(Protocol__PrpDlCqiReport * original) { + int i; + /*Copy the DL report*/ + Protocol__PrpDlCqiReport * dl_report; + dl_report = malloc(sizeof(Protocol__PrpDlCqiReport)); + if (dl_report == NULL) + goto error; + protocol__prp_dl_cqi_report__init(dl_report); + + dl_report->sfn_sn = original->sfn_sn; + dl_report->has_sfn_sn = original->has_sfn_sn; + dl_report->n_csi_report = original->n_csi_report; + + Protocol__PrpDlCsi **csi_reports; + csi_reports = malloc(sizeof(Protocol__PrpDlCsi *) * dl_report->n_csi_report); + if (csi_reports == NULL) + goto error; + + for (i = 0; i < dl_report->n_csi_report; i++) { + csi_reports[i] = copy_csi_report(original->csi_report[i]); + } + dl_report->csi_report = csi_reports; + return dl_report; + + error: + /*TODO: Must free memory properly*/ + return NULL; +} + +Protocol__PrpPagingBufferReport * copy_paging_buffer_report(Protocol__PrpPagingBufferReport *original) { + + int i; + Protocol__PrpPagingBufferReport *copy; + copy = malloc(sizeof(Protocol__PrpPagingBufferReport)); + if (copy == NULL) + goto error; + + protocol__prp_paging_buffer_report__init(copy); + copy->n_paging_info = original->n_paging_info; + + Protocol__PrpPagingInfo **p_info; + p_info = malloc(sizeof(Protocol__PrpPagingInfo *) * copy->n_paging_info); + if (p_info == NULL) + goto error; + for (i = 0; i < copy->n_paging_info; i++) { + p_info[i] = malloc(sizeof(Protocol__PrpPagingInfo)); + if(p_info[i] == NULL) + goto error; + protocol__prp_paging_info__init(p_info[i]); + p_info[i]->paging_index = original->paging_info[i]->paging_index; + p_info[i]->has_paging_index = original->paging_info[i]->has_paging_index;; + p_info[i]->paging_message_size = original->paging_info[i]->paging_message_size; + p_info[i]->has_paging_message_size = original->paging_info[i]->has_paging_message_size; + p_info[i]->paging_subframe = original->paging_info[i]->paging_subframe; + p_info[i]->has_paging_subframe = original->paging_info[i]->has_paging_subframe; + p_info[i]->carrier_index = original->paging_info[i]->carrier_index; + p_info[i]->has_carrier_index = original->paging_info[i]->has_carrier_index; + } + copy->paging_info = p_info; + return copy; + + error: + /*TODO: free memory properly*/ + return NULL; +} + +Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original) { + int i, j; + Protocol__PrpDlCsi *copy = malloc(sizeof(Protocol__PrpDlCsi)); + if (copy == NULL) + goto error; + protocol__prp_dl_csi__init(copy); + copy->serv_cell_index = original->serv_cell_index; + copy->has_serv_cell_index = original->has_serv_cell_index; + copy->ri = original->ri; + copy->has_ri = original->ri; + + copy->type = original->type; + copy->has_type = original->has_type; + copy->report_case = original->report_case; + + switch (copy->report_case) { + case PROTOCOL__PRP_DL_CSI__REPORT_P10CSI: + copy->p10csi->wb_cqi = original->p10csi->wb_cqi; + copy->p10csi->has_wb_cqi = original->p10csi->has_wb_cqi; + break; + case PROTOCOL__PRP_DL_CSI__REPORT_P11CSI: + copy->p11csi->n_wb_cqi = original->p11csi->n_wb_cqi; + copy->p11csi->wb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->p11csi->n_wb_cqi); + for (i = 0; i < copy->p11csi->n_wb_cqi; i++) { + copy->p11csi->wb_cqi[i] = original->p11csi->wb_cqi[i]; + } + copy->p11csi->has_wb_pmi = original->p11csi->has_wb_pmi; + copy->p11csi->wb_pmi = original->p11csi->wb_pmi; + break; + case PROTOCOL__PRP_DL_CSI__REPORT_P20CSI: + copy->p20csi->has_wb_cqi = original->p20csi->has_wb_cqi; + copy->p20csi->wb_cqi = original->p20csi->wb_cqi; + copy->p20csi->has_sb_cqi = original->p20csi->has_sb_cqi; + copy->p20csi->sb_cqi = original->p20csi->sb_cqi; + copy->p20csi->has_bandwidth_part_index = original->p20csi->has_bandwidth_part_index; + copy->p20csi->bandwidth_part_index = original->p20csi->bandwidth_part_index; + copy->p20csi->has_sb_index = original->p20csi->has_sb_index; + copy->p20csi->sb_index = original->p20csi->sb_index; + break; + case PROTOCOL__PRP_DL_CSI__REPORT_P21CSI: + copy->p21csi->n_wb_cqi = original->p21csi->n_wb_cqi; + copy->p21csi->wb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->p21csi->n_wb_cqi); + for (i = 0; i < copy->p21csi->n_wb_cqi; i++) { + copy->p21csi->wb_cqi[i] = original->p21csi->wb_cqi[i]; + } + copy->p21csi->has_wb_pmi = original->p21csi->has_wb_pmi; + copy->p21csi->wb_pmi = original->p21csi->wb_pmi; + copy->p21csi->n_sb_cqi = original->p21csi->n_sb_cqi; + copy->p21csi->sb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->p21csi->n_sb_cqi); + for (i = 0; i < copy->p21csi->n_sb_cqi; i++) { + copy->p21csi->sb_cqi[i] = original->p21csi->sb_cqi[i]; + } + copy->p21csi->has_badwidth_part_index = original->p21csi->has_badwidth_part_index; + copy->p21csi->badwidth_part_index = original->p21csi->badwidth_part_index; + copy->p21csi->has_sb_index = original->p21csi->has_sb_index; + copy->p21csi->sb_index = original->p21csi->sb_index; + break; + case PROTOCOL__PRP_DL_CSI__REPORT_A12CSI: + copy->a12csi->n_wb_cqi = original->a12csi->n_wb_cqi; + copy->a12csi->wb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->a12csi->n_wb_cqi); + for (i = 0; i < copy->a12csi->n_wb_cqi; i++) { + copy->a12csi->wb_cqi[i] = original->a12csi->wb_cqi[i]; + } + copy->a12csi->n_sb_pmi = original->a12csi->n_sb_pmi; + copy->a12csi->sb_pmi = (uint32_t *) malloc(sizeof(uint32_t) * copy->a12csi->n_sb_pmi); + for (i = 0; i < copy->a12csi->n_sb_pmi; i++) { + copy->a12csi->sb_pmi[i] = original->a12csi->sb_pmi[i]; + } + break; + case PROTOCOL__PRP_DL_CSI__REPORT_A22CSI: + copy->a22csi->n_wb_cqi = original->a22csi->n_wb_cqi; + copy->a22csi->wb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->a22csi->n_wb_cqi); + for (i = 0; i < copy->a22csi->n_wb_cqi; i++) { + copy->a22csi->wb_cqi[i] = original->a22csi->wb_cqi[i]; + } + copy->a22csi->n_sb_cqi = original->a22csi->n_sb_cqi; + copy->a22csi->sb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->a22csi->n_sb_cqi); + for (i = 0; i < copy->a22csi->n_sb_cqi; i++) { + copy->a22csi->sb_cqi[i] = original->a22csi->sb_cqi[i]; + } + copy->a22csi->has_wb_pmi = original->a22csi->has_wb_pmi; + copy->a22csi->wb_pmi = original->a22csi->wb_pmi; + copy->a22csi->has_sb_pmi = original->a22csi->has_sb_pmi; + copy->a22csi->sb_pmi = original->a22csi->sb_pmi; + copy->a22csi->n_sb_list = original->a22csi->n_sb_list; + copy->a22csi->sb_list = (uint32_t *) malloc(sizeof(uint32_t) * copy->a22csi->n_sb_list); + for (i = 0; i < copy->a22csi->n_sb_list; i++) { + copy->a22csi->sb_list[i] = original->a22csi->sb_list[i]; + } + break; + case PROTOCOL__PRP_DL_CSI__REPORT_A20CSI: + copy->a20csi->has_wb_cqi = original->a20csi->has_wb_cqi; + copy->a20csi->wb_cqi = original->a20csi->wb_cqi; + copy->a20csi->has_sb_cqi = original->a20csi->has_sb_cqi; + copy->a20csi->sb_cqi = original->a20csi->sb_cqi; + copy->a20csi->n_sb_list = original->a20csi->n_sb_list; + copy->a20csi->sb_list = (uint32_t *) malloc(sizeof(uint32_t) * copy->a20csi->n_sb_list); + for (i = 0; i < copy->a20csi->n_sb_list; i++) { + copy->a20csi->sb_list[i] = original->a20csi->sb_list[i]; + } + break; + case PROTOCOL__PRP_DL_CSI__REPORT_A30CSI: + copy->a30csi->has_wb_cqi = original->a30csi->has_wb_cqi; + copy->a30csi->wb_cqi = original->a30csi->wb_cqi; + copy->a30csi->n_sb_cqi = original->a30csi->n_sb_cqi; + copy->a30csi->sb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->a30csi->n_sb_cqi); + for (i = 0; i < copy->a30csi->n_sb_cqi; i++) { + copy->a30csi->sb_cqi[i] = original->a30csi->sb_cqi[i]; + } + break; + case PROTOCOL__PRP_DL_CSI__REPORT_A31CSI: + copy->a31csi->n_wb_cqi = original->a31csi->n_wb_cqi; + copy->a31csi->wb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->a31csi->n_wb_cqi); + for (i = 0; i < copy->a31csi->n_wb_cqi; i++) { + copy->a31csi->wb_cqi[i] = original->a31csi->wb_cqi[i]; + } + copy->a31csi->has_wb_pmi = original->a31csi->has_wb_pmi; + copy->a31csi->wb_pmi = original->a31csi->wb_pmi; + copy->a31csi->n_sb_cqi = original->a31csi->n_sb_cqi; + copy->a31csi->sb_cqi = malloc(sizeof(Protocol__PrpMsbCqi *) * copy->a31csi->n_sb_cqi); + if (copy->a31csi == NULL) { + goto error; + } + for (i = 0; i < copy->a31csi->n_sb_cqi; i++) { + copy->a31csi->sb_cqi[i] = malloc(sizeof(Protocol__PrpMsbCqi)); + if (copy->a31csi->sb_cqi[i] == NULL) { + goto error; + } + protocol__prp_msb_cqi__init(copy->a31csi->sb_cqi[i]); + copy->a31csi->sb_cqi[i]->n_sb_cqi = original->a31csi->sb_cqi[i]->n_sb_cqi; + copy->a31csi->sb_cqi[i]->sb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->a31csi->sb_cqi[i]->n_sb_cqi); + for (j = 0; j < copy->a31csi->sb_cqi[i]->n_sb_cqi; j++) { + copy->a31csi->sb_cqi[i]->sb_cqi[j] = original->a31csi->sb_cqi[i]->sb_cqi[j]; + } + } + break; + default: + goto error; + } + return copy; + + error: + return NULL; +} + +Protocol__PrpCellStatsReport * copy_cell_stats_report(Protocol__PrpCellStatsReport *original) { + + Protocol__PrpCellStatsReport * copy = malloc(sizeof(Protocol__PrpCellStatsReport)); + + if(copy == NULL) { + goto error; + } + protocol__prp_cell_stats_report__init(copy); + copy->carrier_index = original->carrier_index; + copy->has_carrier_index = original->has_carrier_index; + copy->flags = original->flags; + copy->has_flags = original->has_flags; + + if(copy->flags & PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE) { + copy->noise_inter_report = copy_noise_inter_report(original->noise_inter_report); + } + + return copy; + + error: + return NULL; +} + +Protocol__PrpNoiseInterferenceReport * copy_noise_inter_report(Protocol__PrpNoiseInterferenceReport *original) { + Protocol__PrpNoiseInterferenceReport *ni_report; + ni_report = malloc(sizeof(Protocol__PrpNoiseInterferenceReport)); + if(ni_report == NULL) { + goto error; + } + protocol__prp_noise_interference_report__init(ni_report); + // Current frame and subframe number + ni_report->sfn_sf = original->sfn_sf; + ni_report->has_sfn_sf = original->sfn_sf; + // Received interference power in dbm + ni_report->rip = original->rip; + ni_report->has_rip = original->has_rip; + // Thermal noise power in dbm + ni_report->tnp = original->tnp; + ni_report->has_tnp = original->has_tnp; + + return ni_report; + + error: + return NULL; +} diff --git a/openair2/ENB_APP/enb_agent_mac_internal.h b/openair2/ENB_APP/enb_agent_mac_internal.h new file mode 100644 index 0000000000..98c15e083f --- /dev/null +++ b/openair2/ENB_APP/enb_agent_mac_internal.h @@ -0,0 +1,104 @@ +/******************************************************************************* + 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 enb_agent_mac_internal.h + * \brief Implementation specific definitions for the eNB MAC agent + * \author Xenofon Foukas + * \date 2016 + * \version 0.1 + */ + +#ifndef ENB_AGENT_MAC_INTERNAL_H_ +#define ENB_AGENT_MAC_INTERNAL_H_ + +#include + +#include "enb_agent_mac.h" +#include "enb_agent_common.h" + + +/*Flags showing if a mac agent has already been registered*/ +unsigned int mac_agent_registered[NUM_MAX_ENB_AGENT]; + +/*This will be used for producing continuous status updates for the MAC + *Needs to be thread-safe + */ +typedef struct { + /*Flag showing if continuous mac stats update is enabled*/ + uint8_t is_initialized; + volatile uint8_t cont_update; + xid_t xid; + Protocol__ProgranMessage *stats_req; + Protocol__ProgranMessage *prev_stats_reply; + + pthread_mutex_t *mutex; +} mac_stats_updates_context_t; + +/*Array holding the last stats reports for each eNB. Used for continuous reporting*/ +mac_stats_updates_context_t mac_stats_context[NUM_MAX_ENB_AGENT]; + +/*Functions to initialize and destroy the struct required for the + *continuous stats update report*/ +err_code_t enb_agent_init_cont_mac_stats_update(mid_t mod_id); + +err_code_t enb_agent_destroy_cont_mac_stats_update(mid_t mod_id); + + +/*Enable/Disable the continuous stats update service for the MAC*/ +err_code_t enb_agent_enable_cont_mac_stats_update(mid_t mod_id, xid_t xid, + stats_request_config_t *stats_req); + +err_code_t enb_agent_disable_cont_mac_stats_update(mid_t mod_id); + +Protocol__ProgranMessage * enb_agent_generate_diff_mac_stats_report(Protocol__ProgranMessage *new_report, + Protocol__ProgranMessage *old_report); + +Protocol__PrpUeStatsReport * copy_ue_stats_report(Protocol__PrpUeStatsReport * original); + +Protocol__PrpCellStatsReport * copy_cell_stats_report(Protocol__PrpCellStatsReport *original); + +Protocol__PrpRlcBsr * copy_rlc_report(Protocol__PrpRlcBsr * original); + +Protocol__PrpUlCqiReport * copy_ul_cqi_report(Protocol__PrpUlCqiReport * original); + +Protocol__PrpDlCqiReport * copy_dl_cqi_report(Protocol__PrpDlCqiReport * original); + +Protocol__PrpPagingBufferReport * copy_paging_buffer_report(Protocol__PrpPagingBufferReport *original); + +Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original); + +Protocol__PrpNoiseInterferenceReport * copy_noise_inter_report(Protocol__PrpNoiseInterferenceReport *original); + +int compare_ue_stats_reports(Protocol__PrpUeStatsReport *rep1, + Protocol__PrpUeStatsReport *rep2); + +int compare_cell_stats_reports(Protocol__PrpCellStatsReport *rep1, + Protocol__PrpCellStatsReport *rep2); + +#endif /*ENB_AGENT_MAC_INTERNAL_H_*/ From dec1c93c3dc716bfc9c0abd86677bef8fe1e6c17 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 22 Jan 2016 16:18:54 +0000 Subject: [PATCH 071/413] Changed channel struct for async_channel implementation --- openair2/ENB_APP/enb_agent_async.c | 22 +++++++++++----------- openair2/ENB_APP/enb_agent_async.h | 10 +++++++++- openair2/ENB_APP/enb_agent_net_comm.c | 6 +++--- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_async.c b/openair2/ENB_APP/enb_agent_async.c index 962e1a81ed..d6389ea65f 100644 --- a/openair2/ENB_APP/enb_agent_async.c +++ b/openair2/ENB_APP/enb_agent_async.c @@ -39,21 +39,21 @@ #include "log.h" -enb_agent_instance_t * enb_agent_async_channel_info(mid_t mod_id, char *dst_ip, uint16_t dst_port) { +enb_agent_async_channel_t * enb_agent_async_channel_info(mid_t mod_id, char *dst_ip, uint16_t dst_port) { - enb_agent_instance_t *channel; - channel = (enb_agent_instance_t *) malloc(sizeof(enb_agent_instance_t)); + enb_agent_async_channel_t *channel; + channel = (enb_agent_async_channel_t *) malloc(sizeof(enb_agent_channel_t)); if (channel == NULL) goto error; - channel->mod_id = mod_id; + channel->enb_id = mod_id; /*Create a socket*/ channel->link = new_link_client(dst_ip, dst_port); if (channel->link == NULL) goto error; LOG_I(ENB_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n", - channel->mod_id, + channel->enb_id, dst_ip, dst_port); @@ -80,22 +80,22 @@ enb_agent_instance_t * enb_agent_async_channel_info(mid_t mod_id, char *dst_ip, } int enb_agent_async_msg_send(void *data, int size, int priority, void *channel_info) { - enb_agent_instance_t *channel; - channel = (enb_agent_instance_t *)channel_info; + enb_agent_async_channel_t *channel; + channel = (enb_agent_channel_t *)channel_info; return message_put(channel->send_queue, data, size, priority); } int enb_agent_async_msg_recv(void **data, int *size, int *priority, void *channel_info) { - enb_agent_instance_t *channel; - channel = (enb_agent_instance_t *)channel_info; + enb_agent_async_channel_t *channel; + channel = (enb_agent_async_channel_t *)channel_info; return message_get(channel->receive_queue, data, size, priority); } void enb_agent_async_release(enb_agent_channel_t *channel) { - enb_agent_instance_t *channel_info; - channel_info = (enb_agent_instance_t *) channel->channel_info; + enb_agent_async_channel_t *channel_info; + channel_info = (enb_agent_async_channel_t *) channel->channel_info; destroy_link_manager(channel_info->manager); diff --git a/openair2/ENB_APP/enb_agent_async.h b/openair2/ENB_APP/enb_agent_async.h index 53614cc87d..d722f92a8e 100644 --- a/openair2/ENB_APP/enb_agent_async.h +++ b/openair2/ENB_APP/enb_agent_async.h @@ -39,7 +39,15 @@ #include "enb_agent_net_comm.h" -enb_agent_instance_t * enb_agent_async_channel_info(mid_t mod_id, char *dst_ip, uint16_t dst_port); +typedef struct { + mid_t enb_id; + socket_link_t *link; + message_queue_t *send_queue; + message_queue_t *receive_queue; + link_manager_t *manager; +} enb_agent_async_channel_t; + +enb_agent_async_channel_t * enb_agent_async_channel_info(mid_t mod_id, char *dst_ip, uint16_t dst_port); int enb_agent_async_msg_send(void *data, int size, int priority, void *channel_info); diff --git a/openair2/ENB_APP/enb_agent_net_comm.c b/openair2/ENB_APP/enb_agent_net_comm.c index 5c4544ad63..e180d7affd 100644 --- a/openair2/ENB_APP/enb_agent_net_comm.c +++ b/openair2/ENB_APP/enb_agent_net_comm.c @@ -37,7 +37,7 @@ #include "enb_agent_net_comm.h" #include "log.h" -enb_agent_channel_t *agent_channel[NUM_MAX_ENB_AGENT][ENB_AGENT_MAX]; +enb_agent_channel_t *agent_channel[NUM_MAX_ENB][ENB_AGENT_MAX]; enb_agent_channel_instance_t channel_instance; int enb_agent_channel_id = 0; @@ -146,7 +146,7 @@ int enb_agent_destroy_channel(int channel_id) { } /*Unregister the channel from all agents*/ - for (i = 0; i < NUM_MAX_ENB_AGENT; i++) { + for (i = 0; i < NUM_MAX_ENB; i++) { for (j = 0; j < ENB_AGENT_MAX; j++) { if (agent_channel[i][j] != NULL) { if (agent_channel[i][j]->channel_id == e->channel_id) { @@ -170,7 +170,7 @@ err_code_t enb_agent_init_channel_container(void) { RB_INIT(&channel_instance.enb_agent_head); - for (i = 0; i < NUM_MAX_ENB_AGENT; i++) { + for (i = 0; i < NUM_MAX_ENB; i++) { for (j = 0; j < ENB_AGENT_MAX; j++) { agent_channel[i][j] == NULL; } From 3ad4d26fd1f619ef98f3fa94f41e5973ce537493 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 22 Jan 2016 16:26:06 +0000 Subject: [PATCH 072/413] Changed the structures for storing agent context info --- openair2/ENB_APP/enb_agent.c | 103 +++++----------------- openair2/ENB_APP/enb_agent_common.c | 4 +- openair2/ENB_APP/enb_agent_defs.h | 29 ++---- openair2/ENB_APP/enb_agent_extern.h | 7 +- openair2/ENB_APP/enb_agent_mac_defs.h | 10 ++- openair2/ENB_APP/enb_agent_mac_internal.h | 5 +- 6 files changed, 47 insertions(+), 111 deletions(-) diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index fa24cacf8a..c48f8f67fb 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -37,6 +37,7 @@ #include "enb_agent_common.h" #include "log.h" #include "enb_agent.h" +#include "enb_agent_mac_defs.h" #include "enb_agent_extern.h" @@ -47,10 +48,7 @@ //#define TEST_TIMER -enb_agent_instance_t enb_agent[NUM_MAX_ENB_AGENT]; -msg_context_t shared_ctxt[NUM_MAX_ENB_AGENT]; -/* this could also go into enb_agent struct*/ -enb_agent_info_t enb_agent_info; +enb_agent_instance_t enb_agent[NUM_MAX_ENB]; char in_ip[40]; static uint16_t in_port; @@ -66,7 +64,7 @@ Protocol__ProgranMessage *enb_agent_timeout(void* args); */ void *enb_agent_task(void *args){ - msg_context_t *d = (msg_context_t *) args; + enb_agent_instance_t *d = (enb_agent_instance_t *) args; Protocol__ProgranMessage *msg; void *data; int size; @@ -101,15 +99,11 @@ void *enb_agent_task(void *args){ msg = enb_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, msg_p->ittiMsg.timer_has_expired.arg); if (msg != NULL){ data=enb_agent_pack_message(msg,&size); - if (enb_agent_msg_send(d->mod_id, ENB_AGENT_DEFAULT, data, size, priority)) { + if (enb_agent_msg_send(d->enb_id, ENB_AGENT_DEFAULT, data, size, priority)) { err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; goto error; } - /* if (message_put(d->tx_mq, data, size, priority)){ */ - /* err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; */ - /* goto error; */ - /* } */ LOG_D(ENB_AGENT,"sent message with size %d\n", size); } break; @@ -131,7 +125,7 @@ void *enb_agent_task(void *args){ void *receive_thread(void *args) { - msg_context_t *d = args; + enb_agent_instance_t *d = args; void *data; int size; int priority; @@ -140,38 +134,27 @@ void *receive_thread(void *args) { Protocol__ProgranMessage *msg; while (1) { - if (enb_agent_msg_recv(d->mod_id, ENB_AGENT_DEFAULT, &data, &size, &priority)) { + if (enb_agent_msg_recv(d->enb_id, ENB_AGENT_DEFAULT, &data, &size, &priority)) { err_code = PROTOCOL__PROGRAN_ERR__MSG_DEQUEUING; goto error; } - /* if (message_get(d->rx_mq, &data, &size, &priority)){ */ - /* err_code = PROTOCOL__PROGRAN_ERR__MSG_DEQUEUING; */ - /* goto error; */ - /* } */ LOG_D(ENB_AGENT,"received message with size %d\n", size); - msg=enb_agent_handle_message(d->mod_id, data, size); + msg=enb_agent_handle_message(d->enb_id, data, size); free(data); - d->rx_xid = ((d->rx_xid)+1)%4; - d->tx_xid = d->rx_xid; - // check if there is something to send back to the controller if (msg != NULL){ data=enb_agent_pack_message(msg,&size); - if (enb_agent_msg_send(d->mod_id, ENB_AGENT_DEFAULT, data, size, priority)) { + if (enb_agent_msg_send(d->enb_id, ENB_AGENT_DEFAULT, data, size, priority)) { err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; goto error; } - /* if (message_put(d->tx_mq, data, size, priority)){ */ - /* err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; */ - /* goto error; */ - /* } */ LOG_D(ENB_AGENT,"sent message with size %d\n", size); } @@ -214,10 +197,8 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ int channel_id; - // set_enb_vars(mod_id, RAN_LTE_OAI); - enb_agent[mod_id].mod_id = mod_id; - enb_agent_info.nb_modules+=1; + enb_agent[mod_id].enb_id = mod_id; /* * check the configuration @@ -235,7 +216,7 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ in_port = DEFAULT_ENB_AGENT_PORT ; } LOG_I(ENB_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n", - enb_agent[mod_id].mod_id, + enb_agent[mod_id].enb_id, in_ip, in_port); @@ -271,46 +252,10 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ *enb_agent_register_channel(mod_id, channel, ENB_AGENT_MAC); */ - /* /\* */ - /* * create a socket */ - /* *\/ */ - /* enb_agent[mod_id].link = new_link_client(in_ip, in_port); */ - /* if (enb_agent[mod_id].link == NULL) goto error; */ + /*Initialize the continuous MAC stats update mechanism*/ + enb_agent_init_cont_mac_stats_update(mod_id); - /* LOG_I(ENB_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n", */ - /* enb_agent[mod_id].mod_id, */ - /* in_ip, */ - /* in_port); */ - /* /\* */ - /* * create a message queue */ - /* *\/ */ - - /* enb_agent[mod_id].send_queue = new_message_queue(); */ - /* if (enb_agent[mod_id].send_queue == NULL) goto error; */ - /* enb_agent[mod_id].receive_queue = new_message_queue(); */ - /* if (enb_agent[mod_id].receive_queue == NULL) goto error; */ - - /* /\* */ - /* * create a link manager */ - /* *\/ */ - - /* enb_agent[mod_id].manager = create_link_manager(enb_agent[mod_id].send_queue, enb_agent[mod_id].receive_queue, enb_agent[mod_id].link); */ - /* if (enb_agent[mod_id].manager == NULL) goto error; */ - - /* memset(&shared_ctxt, 0, sizeof(msg_context_t)); */ - - /* shared_ctxt[mod_id].mod_id = mod_id; */ - /* shared_ctxt[mod_id].tx_mq = enb_agent[mod_id].send_queue; */ - /* shared_ctxt[mod_id].rx_mq = enb_agent[mod_id].receive_queue; */ - - /* - * start the enb agent rx thread - */ - - memset(&shared_ctxt, 0, sizeof(msg_context_t)); - shared_ctxt[mod_id].mod_id = mod_id; - - new_thread(receive_thread, &shared_ctxt[mod_id]); + new_thread(receive_thread, &enb_agent[mod_id]); /* * initilize a timer @@ -322,7 +267,7 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ * start the enb agent task for tx and interaction with the underlying network function */ - if (itti_create_task (TASK_ENB_AGENT, enb_agent_task, (void *) &shared_ctxt[mod_id]) < 0) { + if (itti_create_task (TASK_ENB_AGENT, enb_agent_task, (void *) &enb_agent[mod_id]) < 0) { LOG_E(ENB_AGENT, "Create task for eNB Agent failed\n"); return -1; } @@ -338,21 +283,21 @@ error: -int enb_agent_stop(mid_t mod_id){ +/* int enb_agent_stop(mid_t mod_id){ */ - int i=0; +/* int i=0; */ - enb_agent_destroy_timers(); - for ( i =0; i < enb_agent_info.nb_modules; i++) { +/* enb_agent_destroy_timers(); */ +/* for ( i =0; i < enb_agent_info.nb_modules; i++) { */ - destroy_link_manager(enb_agent[i].manager); +/* destroy_link_manager(enb_agent[i].manager); */ - destroy_message_queue(enb_agent[i].send_queue); - destroy_message_queue(enb_agent[i].receive_queue); +/* destroy_message_queue(enb_agent[i].send_queue); */ +/* destroy_message_queue(enb_agent[i].receive_queue); */ - close_link(enb_agent[i].link); - } -} +/* close_link(enb_agent[i].link); */ +/* } */ +/* } */ diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index ce838766ee..ab9546036f 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -39,8 +39,8 @@ #include "log.h" -void * enb[NUM_MAX_ENB_AGENT]; -void * enb_ue[NUM_MAX_ENB_AGENT]; +void * enb[NUM_MAX_ENB]; +void * enb_ue[NUM_MAX_ENB]; /* * message primitives */ diff --git a/openair2/ENB_APP/enb_agent_defs.h b/openair2/ENB_APP/enb_agent_defs.h index 0ddbc2064e..020c631ff1 100644 --- a/openair2/ENB_APP/enb_agent_defs.h +++ b/openair2/ENB_APP/enb_agent_defs.h @@ -43,7 +43,7 @@ #include "link_manager.h" -#define NUM_MAX_ENB_AGENT 2 +#define NUM_MAX_ENB 2 #define NUM_MAX_UE 2048 #define DEFAULT_ENB_AGENT_IPv4_ADDRESS "127.0.0.1" #define DEFAULT_ENB_AGENT_PORT 2210 @@ -108,36 +108,25 @@ typedef uint8_t mid_t; // module or enb id typedef uint8_t lcid_t; typedef int32_t err_code_t; -// tx and rx shared context -typedef struct { - mid_t mod_id; - socket_link_t *link; - message_queue_t *send_queue; - message_queue_t *receive_queue; - link_manager_t *manager; -}enb_agent_instance_t; + typedef struct { /* general info */ - uint32_t nb_modules; - - + /* stats */ uint32_t total_rx_msg; uint32_t total_tx_msg; - uint32_t rx_msg[NUM_MAX_ENB_AGENT]; - uint32_t tx_msg[NUM_MAX_ENB_AGENT]; + uint32_t rx_msg[NUM_MAX_ENB]; + uint32_t tx_msg[NUM_MAX_ENB]; }enb_agent_info_t; typedef struct { - mid_t mod_id; - // message_queue_t *tx_mq; - // message_queue_t *rx_mq; - xid_t tx_xid; - xid_t rx_xid; -} msg_context_t; + mid_t enb_id; + enb_agent_info_t agent_info; + +}enb_agent_instance_t; #endif diff --git a/openair2/ENB_APP/enb_agent_extern.h b/openair2/ENB_APP/enb_agent_extern.h index 2cd072f25a..f191d86907 100644 --- a/openair2/ENB_APP/enb_agent_extern.h +++ b/openair2/ENB_APP/enb_agent_extern.h @@ -41,10 +41,11 @@ #include "enb_agent_defs.h" #include "enb_agent_mac_defs.h" -extern msg_context_t shared_ctxt[NUM_MAX_ENB_AGENT]; -extern AGENT_MAC_xface *agent_mac_xface; +//extern msg_context_t shared_ctxt[NUM_MAX_ENB][ENB_AGENT_MAX]; -extern unsigned int mac_agent_registered[NUM_MAX_ENB_AGENT]; +extern AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB][ENB_AGENT_MAX]; + +extern unsigned int mac_agent_registered[NUM_MAX_ENB]; #endif diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/enb_agent_mac_defs.h index a570165919..f6dccb1570 100644 --- a/openair2/ENB_APP/enb_agent_mac_defs.h +++ b/openair2/ENB_APP/enb_agent_mac_defs.h @@ -42,14 +42,18 @@ /* ENB AGENT-MAC Interface */ typedef struct { - msg_context_t *agent_ctxt; + //msg_context_t *agent_ctxt; /// Inform the controller about the scheduling requests received during the subframe - void (*enb_agent_send_sr_info)(mid_t mod_id, msg_context_t *context); + void (*enb_agent_send_sr_info)(mid_t mod_id); /// Inform the controller about the current UL/DL subframe - void (*enb_agent_send_sf_trigger)(mid_t mod_id, msg_context_t *context); + void (*enb_agent_send_sf_trigger)(mid_t mod_id); + /// Send to the controller all the mac stat updates that occured during this subframe + /// based on the stats request configuration + void (*enb_agent_send_update_mac_stats)(mid_t mod_id); + /*TODO: Fill in with the rest of the MAC layer technology specific callbacks (UL/DL scheduling, RACH info etc)*/ } AGENT_MAC_xface; diff --git a/openair2/ENB_APP/enb_agent_mac_internal.h b/openair2/ENB_APP/enb_agent_mac_internal.h index 98c15e083f..394d3e7730 100644 --- a/openair2/ENB_APP/enb_agent_mac_internal.h +++ b/openair2/ENB_APP/enb_agent_mac_internal.h @@ -43,9 +43,6 @@ #include "enb_agent_common.h" -/*Flags showing if a mac agent has already been registered*/ -unsigned int mac_agent_registered[NUM_MAX_ENB_AGENT]; - /*This will be used for producing continuous status updates for the MAC *Needs to be thread-safe */ @@ -61,7 +58,7 @@ typedef struct { } mac_stats_updates_context_t; /*Array holding the last stats reports for each eNB. Used for continuous reporting*/ -mac_stats_updates_context_t mac_stats_context[NUM_MAX_ENB_AGENT]; +mac_stats_updates_context_t mac_stats_context[NUM_MAX_ENB]; /*Functions to initialize and destroy the struct required for the *continuous stats update report*/ From e3e01a64c97a8db2f8b9501f09f1b48e91959965 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 22 Jan 2016 16:28:44 +0000 Subject: [PATCH 073/413] Added continuous update functionality in the MAC layer --- openair2/ENB_APP/enb_agent_mac.c | 200 ++++++++++++++++++++++++++++--- 1 file changed, 184 insertions(+), 16 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 34423ee01a..6e66267391 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -35,14 +35,22 @@ */ #include "enb_agent_mac.h" +#include "enb_agent_extern.h" +#include "enb_agent_common.h" +#include "enb_agent_mac_internal.h" #include "log.h" + +/*Flags showing if a mac agent has already been registered*/ +unsigned int mac_agent_registered[NUM_MAX_ENB]; + int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__ProgranMessage **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; void *buffer; int size; @@ -71,15 +79,13 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr switch(stats_req->body_case) { case PROTOCOL__PRP_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ; Protocol__PrpCompleteStatsRequest *comp_req = stats_req->complete_stats_request; - if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_CONTINUOUS) { - //TODO: Must create an event based report mechanism - *msg = NULL; - return 0; - } else if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_OFF) { + if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_OFF) { + /*Disable both periodic and continuous updates*/ + enb_agent_disable_cont_mac_stats_update(mod_id); enb_agent_destroy_timer_by_task_id(xid); *msg = NULL; return 0; - } else { //One-off or periodical reporting + } 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; @@ -136,6 +142,16 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr usec_interval = usec_interval%(1000*1000); } enb_agent_create_timer(sec_interval, usec_interval, ENB_AGENT_DEFAULT, enb_id, ENB_AGENT_TIMER_TYPE_PERIODIC, xid, enb_agent_handle_timed_task,(void*) timer_args, &timer_id); + } else if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_CONTINUOUS) { + /*If request was for continuous updates, disable the previous configuration and + set up a new one*/ + enb_agent_disable_cont_mac_stats_update(mod_id); + stats_request_config_t request_config; + request_config.report_type = PROTOCOL__PRP_STATS_TYPE__PRST_COMPLETE_STATS; + request_config.report_frequency = PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_ONCE; + request_config.period = 0; + request_config.config = &report_config; + enb_agent_enable_cont_mac_stats_update(enb_id, xid, &request_config); } } break; @@ -453,7 +469,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, dl_report->n_csi_report = 1; //TODO:Create the actual CSI reports. Protocol__PrpDlCsi **csi_reports; - csi_reports = malloc(sizeof(Protocol__PrpDlCsi *)); + csi_reports = malloc(sizeof(Protocol__PrpDlCsi *)*dl_report->n_csi_report); if (csi_reports == NULL) goto error; for (j = 0; j < dl_report->n_csi_report; j++) { @@ -505,7 +521,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, paging_report->n_paging_info = 1; //Provide a report for each pending paging message Protocol__PrpPagingInfo **p_info; - p_info = malloc(sizeof(Protocol__PrpPagingInfo *)); + p_info = malloc(sizeof(Protocol__PrpPagingInfo *) * paging_report->n_paging_info); if (p_info == NULL) goto error; for (j = 0; j < paging_report->n_paging_info; j++) { @@ -975,15 +991,21 @@ int enb_agent_mac_destroy_sf_trigger(Protocol__ProgranMessage *msg) { return -1; } -void enb_agent_send_sr_info(mid_t mod_id, msg_context_t *context) { +/*********************************************** + * eNB agent - technology mac API implementation + ***********************************************/ + +void enb_agent_send_sr_info(mid_t mod_id) { int size; Protocol__ProgranMessage *msg; void *data; int priority; err_code_t err_code; + int xid = 0; + /*TODO: Must use a proper xid*/ - err_code = enb_agent_mac_sr_info(mod_id, (void *) &(context->tx_xid), &msg); + err_code = enb_agent_mac_sr_info(mod_id, (void *) &xid, &msg); if (err_code < 0) { goto error; } @@ -997,20 +1019,23 @@ void enb_agent_send_sr_info(mid_t mod_id, msg_context_t *context) { } LOG_D(ENB_AGENT,"sent message with size %d\n", size); + return; } error: LOG_D(ENB_AGENT, "Could not send sr message\n"); } -void enb_agent_send_sf_trigger(mid_t mod_id, msg_context_t *context) { +void enb_agent_send_sf_trigger(mid_t mod_id) { int size; Protocol__ProgranMessage *msg; void *data; int priority; err_code_t err_code; + int xid = 0; + /*TODO: Must use a proper xid*/ - err_code = enb_agent_mac_sf_trigger(mod_id, (void *) &(context->tx_xid), &msg); + err_code = enb_agent_mac_sf_trigger(mod_id, (void *) &xid, &msg); if (err_code < 0) { goto error; } @@ -1024,6 +1049,60 @@ void enb_agent_send_sf_trigger(mid_t mod_id, msg_context_t *context) { } LOG_D(ENB_AGENT,"sent message with size %d\n", size); + return; + } + error: + LOG_D(ENB_AGENT, "Could not send sf trigger message\n"); +} + +void enb_agent_send_update_mac_stats(mid_t mod_id) { + + Protocol__ProgranMessage *current_report, *msg; + void *data; + int size; + err_code_t err_code; + int priority; + + mac_stats_updates_context_t stats_context = mac_stats_context[mod_id]; + + if (pthread_mutex_lock(mac_stats_context[mod_id].mutex)) { + goto error; + } + + /*Create a fresh report with the required flags*/ + err_code = enb_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 = enb_agent_generate_diff_mac_stats_report(current_report, mac_stats_context[mod_id].prev_stats_reply); + + /*Destroy the old stats*/ + enb_agent_destroy_progran_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 (msg != NULL){ + data=enb_agent_pack_message(msg, &size); + /*Send any stats updates using the MAC channel of the eNB*/ + if (enb_agent_msg_send(mod_id, ENB_AGENT_MAC, data, size, priority)) { + err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + goto error; + } + + LOG_D(ENB_AGENT,"sent message with size %d\n", size); + return; } error: LOG_D(ENB_AGENT, "Could not send sf trigger message\n"); @@ -1035,12 +1114,14 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { return -1; } - xface->agent_ctxt = &shared_ctxt[mod_id]; + //xface->agent_ctxt = &shared_ctxt[mod_id]; xface->enb_agent_send_sr_info = enb_agent_send_sr_info; xface->enb_agent_send_sf_trigger = enb_agent_send_sf_trigger; + xface->enb_agent_send_update_mac_stats = enb_agent_send_update_mac_stats; mac_agent_registered[mod_id] = 1; - return 1; + + return 0; } int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { @@ -1050,10 +1131,97 @@ int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { return -1; } - xface->agent_ctxt = NULL; + //xface->agent_ctxt = NULL; xface->enb_agent_send_sr_info = NULL; xface->enb_agent_send_sf_trigger = NULL; + return 0; +} + + +/****************************************************** + *Implementations of enb_agent_mac_internal.h functions + ******************************************************/ + +err_code_t enb_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 enb_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; + enb_agent_destroy_progran_message(mac_stats_context[mod_id].stats_req); + enb_agent_destroy_progran_message(mac_stats_context[mod_id].prev_stats_reply); + free(mac_stats_context[mod_id].mutex); + mac_agent_registered[mod_id] = NULL; return 1; } + + +err_code_t enb_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__ProgranMessage *req_msg; + + enb_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(ENB_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); + return -1; +} + +err_code_t enb_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) { + enb_agent_destroy_progran_message(mac_stats_context[mod_id].stats_req); + } + if (mac_stats_context[mod_id].prev_stats_reply != NULL) { + enb_agent_destroy_progran_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(ENB_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); + return -1; + +} From 16bbb96d5bb0bdd692bc8365e781bc5e29643b01 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 22 Jan 2016 16:28:44 +0000 Subject: [PATCH 074/413] Added continuous update functionality in the MAC layer --- openair2/ENB_APP/enb_agent_mac.c | 200 ++++++++++++++++++++++++++++--- openair2/ENB_APP/enb_agent_mac.h | 14 +-- 2 files changed, 191 insertions(+), 23 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 34423ee01a..6e66267391 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -35,14 +35,22 @@ */ #include "enb_agent_mac.h" +#include "enb_agent_extern.h" +#include "enb_agent_common.h" +#include "enb_agent_mac_internal.h" #include "log.h" + +/*Flags showing if a mac agent has already been registered*/ +unsigned int mac_agent_registered[NUM_MAX_ENB]; + int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__ProgranMessage **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; void *buffer; int size; @@ -71,15 +79,13 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr switch(stats_req->body_case) { case PROTOCOL__PRP_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ; Protocol__PrpCompleteStatsRequest *comp_req = stats_req->complete_stats_request; - if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_CONTINUOUS) { - //TODO: Must create an event based report mechanism - *msg = NULL; - return 0; - } else if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_OFF) { + if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_OFF) { + /*Disable both periodic and continuous updates*/ + enb_agent_disable_cont_mac_stats_update(mod_id); enb_agent_destroy_timer_by_task_id(xid); *msg = NULL; return 0; - } else { //One-off or periodical reporting + } 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; @@ -136,6 +142,16 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr usec_interval = usec_interval%(1000*1000); } enb_agent_create_timer(sec_interval, usec_interval, ENB_AGENT_DEFAULT, enb_id, ENB_AGENT_TIMER_TYPE_PERIODIC, xid, enb_agent_handle_timed_task,(void*) timer_args, &timer_id); + } else if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_CONTINUOUS) { + /*If request was for continuous updates, disable the previous configuration and + set up a new one*/ + enb_agent_disable_cont_mac_stats_update(mod_id); + stats_request_config_t request_config; + request_config.report_type = PROTOCOL__PRP_STATS_TYPE__PRST_COMPLETE_STATS; + request_config.report_frequency = PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_ONCE; + request_config.period = 0; + request_config.config = &report_config; + enb_agent_enable_cont_mac_stats_update(enb_id, xid, &request_config); } } break; @@ -453,7 +469,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, dl_report->n_csi_report = 1; //TODO:Create the actual CSI reports. Protocol__PrpDlCsi **csi_reports; - csi_reports = malloc(sizeof(Protocol__PrpDlCsi *)); + csi_reports = malloc(sizeof(Protocol__PrpDlCsi *)*dl_report->n_csi_report); if (csi_reports == NULL) goto error; for (j = 0; j < dl_report->n_csi_report; j++) { @@ -505,7 +521,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, paging_report->n_paging_info = 1; //Provide a report for each pending paging message Protocol__PrpPagingInfo **p_info; - p_info = malloc(sizeof(Protocol__PrpPagingInfo *)); + p_info = malloc(sizeof(Protocol__PrpPagingInfo *) * paging_report->n_paging_info); if (p_info == NULL) goto error; for (j = 0; j < paging_report->n_paging_info; j++) { @@ -975,15 +991,21 @@ int enb_agent_mac_destroy_sf_trigger(Protocol__ProgranMessage *msg) { return -1; } -void enb_agent_send_sr_info(mid_t mod_id, msg_context_t *context) { +/*********************************************** + * eNB agent - technology mac API implementation + ***********************************************/ + +void enb_agent_send_sr_info(mid_t mod_id) { int size; Protocol__ProgranMessage *msg; void *data; int priority; err_code_t err_code; + int xid = 0; + /*TODO: Must use a proper xid*/ - err_code = enb_agent_mac_sr_info(mod_id, (void *) &(context->tx_xid), &msg); + err_code = enb_agent_mac_sr_info(mod_id, (void *) &xid, &msg); if (err_code < 0) { goto error; } @@ -997,20 +1019,23 @@ void enb_agent_send_sr_info(mid_t mod_id, msg_context_t *context) { } LOG_D(ENB_AGENT,"sent message with size %d\n", size); + return; } error: LOG_D(ENB_AGENT, "Could not send sr message\n"); } -void enb_agent_send_sf_trigger(mid_t mod_id, msg_context_t *context) { +void enb_agent_send_sf_trigger(mid_t mod_id) { int size; Protocol__ProgranMessage *msg; void *data; int priority; err_code_t err_code; + int xid = 0; + /*TODO: Must use a proper xid*/ - err_code = enb_agent_mac_sf_trigger(mod_id, (void *) &(context->tx_xid), &msg); + err_code = enb_agent_mac_sf_trigger(mod_id, (void *) &xid, &msg); if (err_code < 0) { goto error; } @@ -1024,6 +1049,60 @@ void enb_agent_send_sf_trigger(mid_t mod_id, msg_context_t *context) { } LOG_D(ENB_AGENT,"sent message with size %d\n", size); + return; + } + error: + LOG_D(ENB_AGENT, "Could not send sf trigger message\n"); +} + +void enb_agent_send_update_mac_stats(mid_t mod_id) { + + Protocol__ProgranMessage *current_report, *msg; + void *data; + int size; + err_code_t err_code; + int priority; + + mac_stats_updates_context_t stats_context = mac_stats_context[mod_id]; + + if (pthread_mutex_lock(mac_stats_context[mod_id].mutex)) { + goto error; + } + + /*Create a fresh report with the required flags*/ + err_code = enb_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 = enb_agent_generate_diff_mac_stats_report(current_report, mac_stats_context[mod_id].prev_stats_reply); + + /*Destroy the old stats*/ + enb_agent_destroy_progran_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 (msg != NULL){ + data=enb_agent_pack_message(msg, &size); + /*Send any stats updates using the MAC channel of the eNB*/ + if (enb_agent_msg_send(mod_id, ENB_AGENT_MAC, data, size, priority)) { + err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + goto error; + } + + LOG_D(ENB_AGENT,"sent message with size %d\n", size); + return; } error: LOG_D(ENB_AGENT, "Could not send sf trigger message\n"); @@ -1035,12 +1114,14 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { return -1; } - xface->agent_ctxt = &shared_ctxt[mod_id]; + //xface->agent_ctxt = &shared_ctxt[mod_id]; xface->enb_agent_send_sr_info = enb_agent_send_sr_info; xface->enb_agent_send_sf_trigger = enb_agent_send_sf_trigger; + xface->enb_agent_send_update_mac_stats = enb_agent_send_update_mac_stats; mac_agent_registered[mod_id] = 1; - return 1; + + return 0; } int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { @@ -1050,10 +1131,97 @@ int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { return -1; } - xface->agent_ctxt = NULL; + //xface->agent_ctxt = NULL; xface->enb_agent_send_sr_info = NULL; xface->enb_agent_send_sf_trigger = NULL; + return 0; +} + + +/****************************************************** + *Implementations of enb_agent_mac_internal.h functions + ******************************************************/ + +err_code_t enb_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 enb_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; + enb_agent_destroy_progran_message(mac_stats_context[mod_id].stats_req); + enb_agent_destroy_progran_message(mac_stats_context[mod_id].prev_stats_reply); + free(mac_stats_context[mod_id].mutex); + mac_agent_registered[mod_id] = NULL; return 1; } + + +err_code_t enb_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__ProgranMessage *req_msg; + + enb_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(ENB_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); + return -1; +} + +err_code_t enb_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) { + enb_agent_destroy_progran_message(mac_stats_context[mod_id].stats_req); + } + if (mac_stats_context[mod_id].prev_stats_reply != NULL) { + enb_agent_destroy_progran_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(ENB_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); + return -1; + +} diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index 4f8afbac08..c30da76d3e 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -45,9 +45,6 @@ #include "enb_agent_common.h" #include "enb_agent_extern.h" -/*Flags showing if a mac agent has already been registered*/ -unsigned int mac_agent_registered[NUM_MAX_ENB_AGENT]; - /* These types will be used to give instructions for the type of stats reports we need to create */ @@ -72,14 +69,13 @@ typedef struct { cc_report_type_t *cc_report_type; } report_config_t; -typedef struct { +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; - int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); int enb_agent_mac_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__ProgranMessage **msg); @@ -104,10 +100,14 @@ int enb_agent_mac_destroy_sf_trigger(Protocol__ProgranMessage *msg); **********************************/ /*Inform controller about received scheduling requests during a subframe*/ -void enb_agent_send_sr_info(mid_t mod_id, msg_context_t *context); +void enb_agent_send_sr_info(mid_t mod_id); /*Inform the controller about the current UL/DL subframe*/ -void enb_agent_send_sf_trigger(mid_t mod_id, msg_context_t *context); +void enb_agent_send_sf_trigger(mid_t mod_id); + +/// Send to the controller all the mac stat updates that occured during this subframe +/// based on the stats request configuration +void enb_agent_send_update_mac_stats(mid_t mod_id); /*Register technology specific interface callbacks*/ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface); From c1c9b0bcbe31fd026f607b2d37f1a73dd248976d Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 27 Jan 2016 12:01:37 +0000 Subject: [PATCH 075/413] Added support for DL scheduling command messages --- cmake_targets/CMakeLists.txt | 4 + .../MESSAGES/V2/controller_commands.proto | 58 ++++++++++++++ openair2/ENB_APP/MESSAGES/V2/header.proto | 3 + .../ENB_APP/MESSAGES/V2/mac_primitives.proto | 76 +++++++++++++++++++ openair2/ENB_APP/MESSAGES/V2/progran.proto | 15 ++++ 5 files changed, 156 insertions(+) create mode 100644 openair2/ENB_APP/MESSAGES/V2/controller_commands.proto create mode 100644 openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index eb9474e670..2a847b3073 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -710,6 +710,8 @@ if (ENB_AGENT_SB_IF) ${PRPT_MSG_DIR}/stats_common.proto ${PRPT_MSG_DIR}/stats_messages.proto ${PRPT_MSG_DIR}/time_common.proto + ${PRPT_MSG_DIR}/controller_commands.proto + ${PRPT_MSG_DIR}/mac_primitives.proto ) set(PRPT_C_DIR ${protobuf_generated_dir}/${PRPTDIR}) @@ -722,6 +724,8 @@ if (ENB_AGENT_SB_IF) ${PRPT_C_DIR}/stats_common.pb-c.c ${PRPT_C_DIR}/stats_messages.pb-c.c ${PRPT_C_DIR}/time_common.pb-c.c + ${PRPT_C_DIR}/controller_commands.pb-c.c + ${PRPT_C_DIR}/mac_primitives.pb-c.c ) file(GLOB prpt_h ${PRPT_C_DIR}/*.h) diff --git a/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto b/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto new file mode 100644 index 0000000000..4ef8c0a370 --- /dev/null +++ b/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto @@ -0,0 +1,58 @@ +package protocol; + +import "mac_primitives.proto"; + +// +// Body of UE DL MAC scheduling configuration info +// + +message prp_dl_data { + optional uint32 rnti = 1; + optional prp_dl_dci dl_dci = 2; + repeated uint32 ce_bitmap = 3; // list of 2 MAC CEs, one for each TB + repeated prp_rlc_pdu rlc_pdu = 4; // list of parameters for the creation of RLC PDUs. One for each lcid + optional uint32 serv_cell_index = 5; + optional uint32 act_deact_ce = 6; //Hex content of MAC CE for Activation/Deactivation in CA +} + +// +// Body of the RAR scheduler configuration +// +message prp_dl_rar { + optional uint32 rnti = 1; + optional uint32 grant = 2; // The 20-bit UL grant. TS 36.213, sec 6.2 + optional prp_dl_dci rar_dci = 3; + optional uint32 carrier_index = 4; // The carrier index for the RAR +} + +// +// Body of the paging/broadcast configuration message +// + +message prp_dl_broadcast { + optional uint32 type = 1; // The PRBT_* values + optional uint32 index = 2; // Index of the broadcast message: + // 0 - SIB1, + // 1..31 - Six, + // 32..63 - PCCH (PCCH index obtained from prp_paging_info) + optional prp_dl_dci broad_dci = 3; + optional uint32 carrier_index = 4; // Index of the carrier for broadcast +} + +// +// Body of the OFDM symbol count message +// + +message prp_pdcch_ofdm_sym_count { + optional uint32 carrier_index = 1; + optional uint32 num_pdcch_ofdm_symbols = 2; +} + +// +// Types of commands related enums +// + +enum prp_broadcast_type { + PRBT_BCCH = 0; + PRBT_PCCH = 1; +} \ No newline at end of file diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index 8534d2f304..10a18ddcef 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -21,5 +21,8 @@ enum prp_type { //Asynchronous messages PRPT_UL_SR_INFO = 6; + + //Controller command messages + PRPT_DL_MAC_CONFIG = 7; } diff --git a/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto new file mode 100644 index 0000000000..4378e6d668 --- /dev/null +++ b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto @@ -0,0 +1,76 @@ +package protocol; + +// +// Message containing the DL DCI info +// + +message prp_dl_dci { + optional uint32 rnti = 1; + optional uint32 res_alloc = 2; // Type of resource allocation + optional uint32 rb_bitmap = 3; // Bitmap for RB allocation + optional uint32 rb_shift = 4; // See TS 36.214, section 7.1.6.2 + repeated uint32 tbs_size = 5; // The size of each TBS + repeated uint32 mcs = 6; // The MCS of each TB + repeated uint32 ndi = 7; // New data indicator of each TB + repeated uint32 rv = 8; // Redundancy version of each TB + optional uint32 cce_index = 9; // CCE index used to send the DCI + optional uint32 aggr_level = 10; + optional uint32 precoding_info = 11; // 2 antenna ports:0..6, + // 4 antenna ports:0..50 + optional uint32 format = 12; // DCI format. A PRDCIF_* value + optional uint32 tpc = 13; // TS 36.213, sec 5.1.1.1 + optional uint32 harq_process = 14; // HARQ process ID + optional uint32 dai = 15; // TDD only + optional uint32 vrb_format = 16; // One of the PRVRBF_* values + optional uint32 tb_swap = 17; // Boolean. TB to codeword swap flag + optional uint32 sps_release = 18; // Flag value + optional uint32 pdcch_order = 19; + optional uint32 preamble_index = 20; // Only valid if pdcch_order = 1 + optional uint32 prach_mask_index = 21; // Only valid if pdcch_order = 1 + optional uint32 n_gap = 22; // One of the PRNGV_* values + optional uint32 tbs_idx = 23; // The TBS index for Format 1A + optional uint32 dl_power_offset = 24; // For format 1D + optional uint32 pdcch_power_offset = 25; // DL PDCCH power boosting in dB + optional uint32 cif_present = 26; // Boolean. Indication of CIF field + optional uint32 cif = 27; // CIF for cross-carrier scheduling +} + +// +// Messages related to the creation of RLC PDUs +// + +message prp_rlc_pdu { + repeated prp_rlc_pdu_tb rlc_pdu_tb = 1; // list of parameters for the creation of RLC PDUs. One for each TB +} + +message prp_rlc_pdu_tb { + optional uint32 logical_channel_id = 1; + optional uint32 size = 2; // Maximum RLC PDU to be created in bytes +} + +// +// MAC content types related enums +// + +enum prp_dci_format { + PRDCIF_1 = 0; + PRDCIF_1A = 1; + PRDCIF_1B = 2; + PRDCIF_1C = 3; + PRDCIF_1D = 4; + PRDCIF_2 = 5; + PRDCIF_2A = 6; + PRDCIF_2B = 7; + PRDCIF_3 = 8; + PRDCIF_3A = 9; +} + +enum prp_vrb_format { + PRVRBF_LOCALIZED = 0; + PRVRBF_DISTRIBUTED = 1; +} + +enum prp_ngap_val { + PRNGV_1 = 0; + PRNGV_2 = 1; +} \ No newline at end of file diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index 730726aab4..5d0ec15518 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -4,6 +4,7 @@ package protocol; import "stats_messages.proto"; import "header.proto"; import "time_common.proto"; +import "controller_commands.proto"; message progran_message { optional progran_direction msg_dir = 100; @@ -15,6 +16,7 @@ message progran_message { prp_stats_reply stats_reply_msg = 5; prp_sf_trigger sf_trigger_msg = 6; prp_ul_sr_info ul_sr_info_msg = 7; + prp_dl_mac_config dl_mac_config_msg = 8; } } @@ -106,6 +108,19 @@ message prp_ul_sr_info { repeated uint32 rnti = 3; } +// +// Controller command messages +// + +message prp_dl_mac_config { + optional prp_header header = 1; + optional uint32 sfn_sf = 2; + repeated prp_dl_data dl_ue_data = 3; + repeated prp_dl_rar dl_rar = 4; + repeated prp_dl_broadcast dl_broadcast = 5; + repeated prp_pdcch_ofdm_sym_count ofdm_sym = 6; // OFDM symbol count for each CC +} + // Extensions of the echo request and reply // messages for carrying a latency value in ms message prp_echo_request_latency { From 92f547655c4a352d7c65053a30f453b6a06c599b Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 27 Jan 2016 12:54:33 +0000 Subject: [PATCH 076/413] Integrated MAC DL config progran message to agent --- openair2/ENB_APP/enb_agent_handler.c | 8 +++-- openair2/ENB_APP/enb_agent_mac.c | 53 ++++++++++++++++++++++++---- openair2/ENB_APP/enb_agent_mac.h | 4 +++ 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 7b63227d7e..3e9752b539 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -46,9 +46,10 @@ enb_agent_message_decoded_callback messages_callback[][3] = { {enb_agent_echo_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REQUEST_MSG*/ {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG*/ //Must add handler when receiving echo reply {enb_agent_mac_handle_stats, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG*/ - {0,0,0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG*/ - {0,0,0}, /*PROTOCOK__PROGRAN_MESSAGE__MSG_SF_TRIGGER_MSG*/ - {0,0,0}, /*SR_INFO*/ + {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG*/ + {0, 0, 0}, /*PROTOCOK__PROGRAN_MESSAGE__MSG_SF_TRIGGER_MSG*/ + {0, 0, 0}, /*SR_INFO*/ + {0, 0, 0}, /*DL_MAC_CONFIG*/ }; @@ -60,6 +61,7 @@ enb_agent_message_destruction_callback message_destruction_callback[] = { enb_agent_mac_destroy_stats_reply, enb_agent_mac_destroy_sf_trigger, enb_agent_mac_destroy_sr_info, + enb_agent_mac_destroy_dl_config, }; static const char *enb_agent_direction2String[] = { diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 6e66267391..157b83581d 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -45,6 +45,9 @@ /*Flags showing if a mac agent has already been registered*/ unsigned int mac_agent_registered[NUM_MAX_ENB]; +/*Array containing the Agent-MAC interfaces*/ +AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB]; + int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg){ // TODO: Must deal with sanitization of input @@ -991,6 +994,43 @@ int enb_agent_mac_destroy_sf_trigger(Protocol__ProgranMessage *msg) { return -1; } +int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__ProgranMessage **msg) { + + int xid = 0; + Protocol__PrpHeader *header; + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_DL_MAC_CONFIG, &header) != 0) + goto error; + + Protocol__PrpDlMacConfig *dl_mac_config_msg; + dl_mac_config_msg = malloc(sizeof(Protocol__PrpDlMacConfig)); + if (dl_mac_config_msg == NULL) { + goto error; + } + protocol__prp_dl_mac_config__init(dl_mac_config_msg); + + dl_mac_config_msg->header = header; + dl_mac_config_msg->has_sfn_sf = 1; + dl_mac_config_msg->sfn_sf = get_sfn_sf(mod_id); + + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if(*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + (*msg)->dl_mac_config_msg = dl_mac_config_msg; + + return 0; + + error: + return -1; +} + +int enb_agent_mac_destroy_dl_config(Protocol__ProgranMessage *msg) { + //TODO: De-allocate the memory of the message + return -1; +} + /*********************************************** * eNB agent - technology mac API implementation ***********************************************/ @@ -1109,7 +1149,7 @@ void enb_agent_send_update_mac_stats(mid_t mod_id) { } int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { - if (!mac_agent_registered[mod_id]) { + if (mac_agent_registered[mod_id]) { LOG_E(MAC, "MAC agent for eNB %d is already registered\n", mod_id); return -1; } @@ -1119,22 +1159,23 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_send_sf_trigger = enb_agent_send_sf_trigger; xface->enb_agent_send_update_mac_stats = enb_agent_send_update_mac_stats; + mac_agent_registered[mod_id] = 1; + agent_mac_xface[mod_id] = xface; return 0; } int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { - if(mac_agent_registered[mod_id]) { - LOG_E(MAC, "MAC agent for eNB %d is already registered\n", mod_id); - return -1; - } - //xface->agent_ctxt = NULL; xface->enb_agent_send_sr_info = NULL; xface->enb_agent_send_sf_trigger = NULL; + xface->enb_agent_send_update_mac_stats = NULL; + mac_agent_registered[mod_id] = 0; + agent_mac_xface[mod_id] = NULL; + return 0; } diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index c30da76d3e..221d76e57f 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -94,6 +94,10 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran int enb_agent_mac_destroy_sf_trigger(Protocol__ProgranMessage *msg); +int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__ProgranMessage **msg); + +int enb_agent_mac_destroy_dl_config(Protocol__ProgranMessage *msg); + /********************************** * eNB agent - technology mac API From cb8007bb3182acf0be139d94b67ba9f821064d90 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 28 Jan 2016 14:45:47 +0000 Subject: [PATCH 077/413] Added support for enb agent MAC scheduler hot-plugging. Deactivated schedule_ue_spec and added agent UE specific DL scheduler --- cmake_targets/CMakeLists.txt | 1 + openair2/ENB_APP/enb_agent.c | 6 + openair2/ENB_APP/enb_agent_extern.h | 2 +- openair2/ENB_APP/enb_agent_mac.c | 4 + openair2/ENB_APP/enb_agent_mac_defs.h | 9 +- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 944 ++++++++++++++++++ openair2/LAYER2/MAC/eNB_scheduler.c | 273 ++++- openair2/LAYER2/MAC/proto.h | 10 + 8 files changed, 1228 insertions(+), 21 deletions(-) create mode 100644 openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 2a847b3073..01d0c8aabd 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1007,6 +1007,7 @@ set (MAC_SRC ${MAC_DIR}/eNB_scheduler_RA.c ${MAC_DIR}/pre_processor.c ${MAC_DIR}/config.c + ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue.c ) set (ENB_APP_SRC diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index c48f8f67fb..c9c42a41d9 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -256,6 +256,12 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ enb_agent_init_cont_mac_stats_update(mod_id); new_thread(receive_thread, &enb_agent[mod_id]); + + /*Initialize and register the mac xface. Must be modified later + *for more flexibility in agent management */ + + AGENT_MAC_xface *mac_agent_xface = (AGENT_MAC_xface *) malloc(sizeof(AGENT_MAC_xface)); + enb_agent_register_mac_xface(mod_id, mac_agent_xface); /* * initilize a timer diff --git a/openair2/ENB_APP/enb_agent_extern.h b/openair2/ENB_APP/enb_agent_extern.h index f191d86907..1ef2250483 100644 --- a/openair2/ENB_APP/enb_agent_extern.h +++ b/openair2/ENB_APP/enb_agent_extern.h @@ -44,7 +44,7 @@ //extern msg_context_t shared_ctxt[NUM_MAX_ENB][ENB_AGENT_MAX]; -extern AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB][ENB_AGENT_MAX]; +extern AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB]; extern unsigned int mac_agent_registered[NUM_MAX_ENB]; diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 157b83581d..05b2a7a364 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -39,6 +39,8 @@ #include "enb_agent_common.h" #include "enb_agent_mac_internal.h" +#include "LAYER2/MAC/proto.h" + #include "log.h" @@ -1158,6 +1160,7 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_send_sr_info = enb_agent_send_sr_info; xface->enb_agent_send_sf_trigger = enb_agent_send_sf_trigger; xface->enb_agent_send_update_mac_stats = enb_agent_send_update_mac_stats; + xface->enb_agent_schedule_ue_spec = schedule_ue_spec_default; mac_agent_registered[mod_id] = 1; @@ -1172,6 +1175,7 @@ int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_send_sr_info = NULL; xface->enb_agent_send_sf_trigger = NULL; xface->enb_agent_send_update_mac_stats = NULL; + xface->enb_agent_schedule_ue_spec = NULL; mac_agent_registered[mod_id] = 0; agent_mac_xface[mod_id] = NULL; diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/enb_agent_mac_defs.h index f6dccb1570..67b89bf610 100644 --- a/openair2/ENB_APP/enb_agent_mac_defs.h +++ b/openair2/ENB_APP/enb_agent_mac_defs.h @@ -53,7 +53,14 @@ typedef struct { /// Send to the controller all the mac stat updates that occured during this subframe /// based on the stats request configuration void (*enb_agent_send_update_mac_stats)(mid_t mod_id); - + + /// Run the UE DL scheduler and fill the Protocol__ProgranMessage. Assumes that + /// dl_info is already initialized as prp_dl_mac_config and fills the + /// prp_dl_data part of it + void (*enb_agent_schedule_ue_spec)(mid_t mod_id, uint32_t frame, uint32_t subframe, + unsigned int *nb_rb_used, unsigned int *nCCE_used, + int *mbsfn_flag, Protocol__ProgranMessage *dl_info); + /*TODO: Fill in with the rest of the MAC layer technology specific callbacks (UL/DL scheduling, RACH info etc)*/ } AGENT_MAC_xface; diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c new file mode 100644 index 0000000000..5adc4abc40 --- /dev/null +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -0,0 +1,944 @@ +/******************************************************************************* + 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ + +/*! \file eNB_agent_scheduler_dlsch_ue.c + * \brief procedures related to eNB for the DLSCH transport channel + * \author Xenofon Foukas + * \date 2016 + * \email: x.foukas@sms.ed.ac.uk + * \version 0.1 + * @ingroup _mac + + */ + +#include "assertions.h" +#include "PHY/defs.h" +#include "PHY/extern.h" + +#include "SCHED/defs.h" +#include "SCHED/extern.h" + +#include "LAYER2/MAC/defs.h" +#include "LAYER2/MAC/proto.h" +#include "LAYER2/MAC/extern.h" +#include "UTIL/LOG/log.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "OCG.h" +#include "OCG_extern.h" + +#include "RRC/LITE/extern.h" +#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" + +#include "ENB_APP/enb_agent_defs.h" + +//#include "LAYER2/MAC/pre_processor.c" +#include "pdcp.h" + +#include "header.pb-c.h" +#include "progran.pb-c.h" + +#include "SIMULATION/TOOLS/defs.h" // for taus + +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +#endif + +#define ENABLE_MAC_PAYLOAD_DEBUG + +//------------------------------------------------------------------------------ +void +schedule_ue_spec_default( + mid_t mod_id, + uint32_t frame, + uint32_t subframe, + unsigned int *nb_rb_used, + unsigned int *nCCE_used, + int *mbsfn_flag, + Protocol__ProgranMessage *dl_info +) +//------------------------------------------------------------------------------ +{ + //TODO + uint8_t CC_id; + int UE_id; + uint16_t nCCE[MAX_NUM_CCs]; + 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,header_len_dtch=0,header_len_dtch_tmp=0, ta_len=0; + unsigned char sdu_lcids[11],offset,num_sdus=0; + uint16_t nb_rb,nb_rb_temp,total_nb_available_rb[MAX_NUM_CCs],nb_available_rb; + uint16_t TBS,j,sdu_lengths[11],rnti,padding=0,post_padding=0; + unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; + unsigned char round = 0; + unsigned char harq_pid = 0; + void *DLSCH_dci = NULL; + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + uint16_t sdu_length_total = 0; + // uint8_t dl_pow_off[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + // unsigned char rballoc_sub_UE[MAX_NUM_CCs][NUMBER_OF_UE_MAX][N_RBG_MAX]; + // uint16_t pre_nb_available_rbs[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + int mcs; + uint16_t min_rb_unit[MAX_NUM_CCs]; + short ta_update = 0; + eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; + UE_list_t *UE_list = &eNB->UE_list; + LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; + int continue_flag=0; + int32_t normalized_rx_power, target_rx_power; + int32_t tpc=1; + static int32_t tpc_accumulated=0; + UE_sched_ctrl *ue_sched_ctl; + + Protocol__PrpDlData *dl_data[NUM_MAX_UE]; + int num_ues_added = 0; + + Protocol__PrpDlDci *dl_dci; + Protocol__PrpRlcPdu *rlc_pdus[11]; + uint32_t *ce_bitmap; + Protocol__PrpRlcPdu **rlc_pdu; + int num_tb; + uint32_t ce_flags = 0; + + uint8_t rballoc_sub[25]; + int i; + + + if (UE_list->head==-1) { + return; + } + + start_meas(&eNB->schedule_dlsch); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_IN); + + //weight = get_ue_weight(module_idP,UE_id); + aggregation = 1; // set to the maximum aggregation level + + for (CC_id=0; CC_idget_lte_frame_parms(mod_id, CC_id); + total_nb_available_rb[CC_id] = frame_parms[CC_id]->N_RB_DL - nb_rb_used[CC_id]; + nCCE[CC_id] = mac_xface->get_nCCE_max(mod_id, CC_id) - nCCE_used[CC_id]; + N_RBG[CC_id] = frame_parms[CC_id]->N_RBG; + + // store the global enb stats: + eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs; + eNB->eNB_stats[CC_id].available_prbs = total_nb_available_rb[CC_id]; + eNB->eNB_stats[CC_id].total_available_prbs += total_nb_available_rb[CC_id]; + eNB->eNB_stats[CC_id].available_ncces = nCCE[CC_id]; + eNB->eNB_stats[CC_id].dlsch_bytes_tx=0; + eNB->eNB_stats[CC_id].dlsch_pdus_tx=0; + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,VCD_FUNCTION_IN); + + start_meas(&eNB->schedule_dlsch_preprocessor); + dlsch_scheduler_pre_processor(mod_id, + frame, + subframe, + N_RBG, + mbsfn_flag); + stop_meas(&eNB->schedule_dlsch_preprocessor); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,VCD_FUNCTION_OUT); + + for (CC_id=0; CC_id0) + continue; + + for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { + continue_flag=0; // reset the flag to allow allocation for the remaining UEs + rnti = UE_RNTI(mod_id, UE_id); + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + + if (rnti==NOT_A_RNTI) { + LOG_D(MAC,"Cannot find rnti for UE_id %d (num_UEs %d)\n",UE_id,UE_list->num_UEs); + // mac_xface->macphy_exit("Cannot find rnti for UE_id"); + continue_flag=1; + } + + if (eNB_UE_stats==NULL) { + LOG_D(MAC,"[eNB] Cannot find eNB_UE_stats\n"); + // mac_xface->macphy_exit("[MAC][eNB] Cannot find eNB_UE_stats\n"); + continue_flag=1; + } + + if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || (nCCE[CC_id] < (1<pre_nb_available_rbs[CC_id], nCCE[CC_id], aggregation); + //if(mac_xface->get_transmission_mode(module_idP,rnti)==5) + continue_flag=1; //to next user (there might be rbs availiable for other UEs in TM5 + // else + // break; + } + + if (frame_parms[CC_id]->frame_type == TDD) { + set_ue_dai (subframe, + frame_parms[CC_id]->tdd_config, + UE_id, + CC_id, + UE_list); + // update UL DAI after DLSCH scheduling + set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe,frame_parms); + } + + if (continue_flag == 1 ) { + add_ue_dlsch_info(mod_id, + CC_id, + UE_id, + subframe, + S_DL_NONE); + continue; + } + + // After this point all the UEs will be scheduled + // TODO create a Protocol__PrpDlData struct for the UE + dl_data[num_ues_added] = (Protocol__PrpDlData *) malloc(sizeof(Protocol__PrpDlData)); + protocol__prp_dl_data__init(dl_data[num_ues_added]); + dl_data[num_ues_added]->has_rnti = 1; + dl_data[num_ues_added]->rnti = rnti; + dl_data[num_ues_added]->n_rlc_pdu = 0; + dl_data[num_ues_added]->has_serv_cell_index = 1; + dl_data[num_ues_added]->serv_cell_index = CC_id; + + nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; + harq_pid = ue_sched_ctl->harq_pid[CC_id]; + 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(mod_id, rnti); + 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; + num_sdus=0; + + /* + DevCheck(((eNB_UE_stats->DL_cqi[0] < MIN_CQI_VALUE) || (eNB_UE_stats->DL_cqi[0] > MAX_CQI_VALUE)), + eNB_UE_stats->DL_cqi[0], MIN_CQI_VALUE, MAX_CQI_VALUE); + */ + eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; + eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); + + +#ifdef EXMIMO + + if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)==5) { + eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1,16); + } + +#endif + + // store stats + UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->DL_cqi[0]; + + // initializing the rb allocation indicator for each UE + for(j=0; jN_RBG; j++) { + UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0; + } + + 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, ncc %d, rrc %d)\n", + mod_id, frame, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb, + eNB_UE_stats->DL_cqi[0], eNB_UE_stats->dlsch_mcs1, + nCCE[CC_id], + UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); + + dl_dci = (Protocol__PrpDlDci*) malloc(sizeof(Protocol__PrpDlDci)); + protocol__prp_dl_dci__init(dl_dci); + dl_data[num_ues_added]->dl_dci = dl_dci; + + + dl_dci->has_rnti = 1; + dl_dci->rnti = rnti; + dl_dci->has_harq_process = 1; + dl_dci->harq_process = harq_pid; + + /* process retransmission */ + + if (round > 0) { + + if (frame_parms[CC_id]->frame_type == TDD) { + UE_list->UE_template[CC_id][UE_id].DAI++; + update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); + LOG_D(MAC,"DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", + CC_id, subframe,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); + } + + // get freq_allocation + nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + + if (nb_rb <= nb_available_rb) { + + if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { + for(j=0; jN_RBG; j++) { // for indicating the rballoc for each sub-band + UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + } + } else { + nb_rb_temp = nb_rb; + j = 0; + + while((nb_rb_temp > 0) && (jN_RBG)) { + if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { + UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + if((j == frame_parms[CC_id]->N_RBG-1) && + ((frame_parms[CC_id]->N_RB_DL == 25)|| + (frame_parms[CC_id]->N_RB_DL == 50))) { + nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]+1; + } else { + nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; + } + } + + j = j + 1; + } + } + + nb_available_rb -= nb_rb; + aggregation = process_ue_cqi(mod_id, UE_id); + nCCE[CC_id]-=(1<mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; + + for(j=0; jN_RBG; j++) { + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; + } + + switch (mac_xface->get_transmission_mode(mod_id,CC_id,rnti)) { + case 1: + case 2: + default: + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 0; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round&3; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", + mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); + } else { + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", + mod_id, CC_id, harq_pid, round); + } + break; + case 4: + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; + dl_dci->n_ndi = 2; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 0; + dl_dci->ndi[1] = 0; + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + dl_dci->n_rv = 2; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round&3; + dl_dci->rv[1] = round&3; + + break; + case 5: + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 0; + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round&3; + + if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { + ue_sched_ctl->dl_pow_off[CC_id] = 1; + } + + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; + + break; + case 6: + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 0; + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round&3; + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; + + break; + } + + add_ue_dlsch_info(mod_id, + CC_id, + UE_id, + subframe, + S_DL_SCHEDULED); + + //eNB_UE_stats->dlsch_trials[round]++; + UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx=nCCE[CC_id]; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=eNB_UE_stats->dlsch_mcs1; + } else { + LOG_D(MAC,"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", + mod_id, frame, CC_id, UE_id); + } + + num_ues_added += 1; + + } else { /* This is a potentially new SDU opportunity */ + + rlc_status.bytes_in_buffer = 0; + // Now check RLC information to compute number of required RBs + // get maximum TBS size for RLC request + //TBS = mac_xface->get_TBS(eNB_UE_stats->DL_cqi[0]<<1,nb_available_rb); + TBS = mac_xface->get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_available_rb); + // check first for RLC data on DCCH + // add the length for all the control elements (timing adv, drx, etc) : header + payload + + //#ifndef EXMIMO_IOT + // to be checked by RK, NN, FK + uint8_t update_TA=4; + + switch (frame_parms[CC_id]->N_RB_DL) { + case 6: + update_TA = 1; + break; + + case 25: + update_TA = 4; + break; + + case 50: + update_TA = 8; + break; + + case 100: + update_TA = 16; + break; + } + + ta_len = ((eNB_UE_stats->timing_advance_update/update_TA)!=0) ? 2 : 0; + + dl_data[num_ues_added]->n_ce_bitmap = 2; + dl_data[num_ues_added]->ce_bitmap = (uint32_t *) malloc(sizeof(uint32_t) * 2); + + if (ta_len > 0) { + ce_flags |= PROTOCOL__PRP_CE_TYPE__PRPCET_TA; + } + + + header_len_dcch = 2; // 2 bytes DCCH SDU subheader + + if ( TBS-ta_len-header_len_dcch > 0 ) { + + + rlc_status = mac_rlc_status_ind( + mod_id, + rnti, + mod_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + DCCH, + (TBS-ta_len-header_len_dcch)); // transport block set size + + if (rlc_status.bytes_in_buffer > 0) { + sdu_length_total = cmin(rlc_status.bytes_in_buffer, TBS-ta_len-header_len_dcch); + // TODO: This should be replaced with the proper description of the CE + ce_flags |= PROTOCOL__PRP_CE_TYPE__PRPCET_CR; + } else { + header_len_dcch = 0; + 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( + mod_id, + rnti, + mod_id, + frame, + 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 + + if (rlc_status.bytes_in_buffer > 0) { + // TODO: Again hypothetical flag. Need to check how to find the actual type of CE + ce_flags |= PROTOCOL__PRP_CE_TYPE__PRPCET_CA; + sdu_length_total += cmin(rlc_status.bytes_in_buffer, TBS-ta_len-header_len_dcch-sdu_length_total); + header_len_dcch += 2; + } + } + + // Add the control element flags to the progran message + dl_data[num_ues_added]->ce_bitmap = ce_flags; + + // check for DTCH and update header information + // here we should loop over all possible DTCH + + header_len_dtch = 3; // 3 bytes DTCH SDU subheader + + LOG_D(MAC,"[eNB %d], Frame %d, DTCH->DLSCH, CC_id %d, Checking RLC status (rab %d, tbs %d, len %d)\n", + mod_id, frame, CC_id, DTCH, 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 ) { + rlc_status = mac_rlc_status_ind( + mod_id, + rnti, + mod_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + DTCH, + TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); + + if (rlc_status.bytes_in_buffer > 0) { + + //TODO: Set rlc pdu info. Hardcoded for the moment + + dl_data[num_ues_added]->n_rlc_pdu++; + rlc_pdus[0] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); + protocol__prp_rlc_pdu__init(rlc_pdus[0]); + rlc_pdus[0]->n_rlc_pdu_tb = 2; + rlc_pdus[0]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); + rlc_pdus[0]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + rlc_pdus[0]->rlc_pdu_tb[0]->has_logical_channel_id = 1; + rlc_pdus[0]->rlc_pdu_tb[0]->logical_channel_id = DTCH; + rlc_pdus[0]->rlc_pdu_tb[0]->has_size = 1; + rlc_pdus[0]->rlc_pdu_tb[0]->size = TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch; + rlc_pdus[0]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + rlc_pdus[0]->rlc_pdu_tb[1]->has_logical_channel_id = 1; + rlc_pdus[0]->rlc_pdu_tb[1]->logical_channel_id = DTCH; + rlc_pdus[0]->rlc_pdu_tb[1]->has_size = 1; + rlc_pdus[0]->rlc_pdu_tb[1]->size = TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch; + + // Add rlc_pdus to the dl_data message + dl_data[num_ues_added]->rlc_pdu = (Protocol__PrpRlcPdu **) malloc(sizeof(Protocol__PrpRlcPdu *) * + dl_data[num_ues_added]->n_rlc_pdu); + for (i = 0; i< dl_data[num_ues_added]->n_rlc_pdu; i++) { + dl_data[num_ues_added]->rlc_pdu[i] = rlc_pdus[i]; + } + + sdu_length_total += cmin(rlc_status.bytes_in_buffer, TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); + + if(cmin(rlc_status.bytes_in_buffer, TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch) < 128) { + header_len_dtch = 2; + } + + } else { + header_len_dtch = 0; + } + } + + // there is a payload + 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 : header_len_dcch; // remove length field + } else { + header_len_dtch = (header_len_dtch > 0) ? 1 :header_len_dtch; // remove length field for the last SDU + } + + mcs = eNB_UE_stats->dlsch_mcs1; + + if (mcs==0) { + nb_rb = 4; // don't let the TBS get too small + } else { + nb_rb=min_rb_unit[CC_id]; + } + + TBS = mac_xface->get_TBS_DL(mcs,nb_rb); + + while (TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) { + nb_rb += min_rb_unit[CC_id]; // + + if (nb_rb>nb_available_rb) { // if we've gone beyond the maximum number of RBs + // (can happen if N_RB_DL is odd) + TBS = mac_xface->get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_available_rb); + nb_rb = nb_available_rb; + break; + } + + TBS = mac_xface->get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_rb); + } + + if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { + for(j=0; jN_RBG; j++) { // for indicating the rballoc for each sub-band + UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + } + } else { + nb_rb_temp = nb_rb; + j = 0; + + while((nb_rb_temp > 0) && (jN_RBG)) { + if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { + UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + + if ((j == frame_parms[CC_id]->N_RBG-1) && + ((frame_parms[CC_id]->N_RB_DL == 25)|| + (frame_parms[CC_id]->N_RB_DL == 50))) { + nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]+1; + } else { + nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; + } + } + + j = j+1; + } + } + + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; + + for(j=0; jN_RBG; j++) { + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; + } + + // decrease mcs until TBS falls below required length + while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs>0)) { + mcs--; + TBS = mac_xface->get_TBS_DL(mcs,nb_rb); + } + + // if we have decreased too much or we don't have enough RBs, increase MCS + while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && ((( ue_sched_ctl->dl_pow_off[CC_id]>0) && (mcs<28)) + || ( (ue_sched_ctl->dl_pow_off[CC_id]==0) && (mcs<=15)))) { + mcs++; + TBS = mac_xface->get_TBS_DL(mcs,nb_rb); + } + + dl_dci->n_tbs_size = 2; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * 2); + dl_dci->tbs_size[0] = TBS; + dl_dci->tbs_size[1] = TBS; + + LOG_D(MAC,"dlsch_mcs before and after the rate matching = (%d, %d)\n",eNB_UE_stats->dlsch_mcs1, mcs); + + aggregation = process_ue_cqi(mod_id,UE_id); + dl_dci->has_aggr_level = 1; + dl_dci->aggr_level = aggregation; + dl_dci->has_cce_index = 1; + dl_dci->cce_index = nCCE_used[CC_id]; + nCCE[CC_id]-=(1<UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; + + add_ue_dlsch_info(mod_id, + CC_id, + UE_id, + subframe, + S_DL_SCHEDULED); + + if (frame_parms[CC_id]->frame_type == TDD) { + UE_list->UE_template[CC_id][UE_id].DAI++; + // printf("DAI update: subframeP %d: UE %d, DAI %d\n",subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); +#warning only for 5MHz channel + update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); + } + + // do PUCCH power control + // this is the normalized RX power + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + normalized_rx_power = eNB_UE_stats->Po_PUCCH_dBm; + target_rx_power = mac_xface->get_target_pucch_rx_power(mod_id, CC_id) + 10; + + // 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; + + if (((framex10psubframe+10)<=(frame*10+subframe)) || //normal case + ((framex10psubframe>(frame*10+subframe)) && (((10240-framex10psubframe+frame*10+subframe)>=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=frame; + UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe=subframe; + 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_D(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", + mod_id, frame, subframe, 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 + } + + for(i=0; ilte_frame_parms.N_RBG; i++) { + rballoc_sub[i] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][i]; + } + + switch (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)) { + case 1: + case 2: + default: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = 0; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", + mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); + } else { + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", + mod_id, CC_id, harq_pid, round); + } + break; + case 3: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 2; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->ndi[1] = 0; + dl_dci->n_rv = 2; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = 0; + dl_dci->rv[1] = 1; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 2; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->mcs[1] = 0; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", + mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); + } else { + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", + mod_id, CC_id, harq_pid, round); + } + break; + case 4: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 2; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->ndi[1] = 0; + dl_dci->n_rv = 2; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = 0; + dl_dci->rv[1] = round&3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 2; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->mcs[1] = 0; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", + mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); + } else { + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", + mod_id, CC_id, harq_pid, round); + } + break; + case 5: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 1; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round&3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", + mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); + } else { + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", + mod_id, CC_id, harq_pid, round); + } + + if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { + ue_sched_ctl->dl_pow_off[CC_id] = 1; + } + + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; + dl_dci->has_precoding_info = 1; + dl_dci->precoding_info = 5; // Is this right?? + + break; + case 6: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 1; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round&3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", + mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); + } else { + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", + mod_id, CC_id, harq_pid, round); + } + + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; + dl_dci->has_precoding_info = 1; + dl_dci->precoding_info = 5; // Is this right?? + break; + } + // Toggle NDI for next time + LOG_D(MAC,"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", + CC_id, frame, subframe, UE_id, + UE_list->UE_template[CC_id][UE_id].rnti,harq_pid, UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]); + UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]=1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + + // Increase the pointer for the number of scheduled UEs + num_ues_added++; + } else { // There is no data from RLC or MAC header, so don't schedule + + } + } + if (frame_parms[CC_id]->frame_type == TDD) { + set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe, frame_parms); + } + } + } + + // Add all the dl_data elements to the progran message + dl_info->dl_mac_config_msg->n_dl_ue_data = num_ues_added; + dl_info->dl_mac_config_msg->dl_ue_data = (Protocol__PrpDlData **) malloc(sizeof(Protocol__PrpDlData *) * num_ues_added); + for (i = 0; i < num_ues_added; i++) { + dl_info->dl_mac_config_msg->dl_ue_data[i] = dl_data[i]; + } + + stop_meas(&eNB->schedule_dlsch); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_OUT); +} diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 329c40be05..0de9253fef 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -59,6 +59,10 @@ //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" +//Agent-related headers +#include "ENB_APP/enb_agent_extern.h" +#include "ENB_APP/enb_agent_mac.h" + #if defined(ENABLE_ITTI) # include "intertask_interface.h" #endif @@ -85,6 +89,9 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, int mbsfn_status[MAX_NUM_CCs]; uint32_t RBalloc[MAX_NUM_CCs]; protocol_ctxt_t ctxt; + + Protocol__ProgranMessage *msg; + #ifdef EXMIMO int ret; #endif @@ -275,7 +282,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; } } else { //FDD - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); schedule_ulsch(module_idP,frameP,cooperation_flag,1,5,nCCE); } @@ -287,7 +306,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // TDD, nothing // FDD, normal UL/DLSCH if (mac_xface->lte_frame_parms->frame_type == FDD) { //FDD - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); schedule_ulsch(module_idP,frameP,cooperation_flag,2,6,nCCE); } @@ -306,7 +337,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // no break here! case 5: - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -314,7 +357,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; } } else { //FDD - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); schedule_ulsch(module_idP,frameP,cooperation_flag,3,7,nCCE); @@ -341,7 +396,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // no break here! case 5: - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,1,mbsfn_status); break; @@ -352,7 +419,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, if (mac_xface->lte_frame_parms->frame_type == FDD) { //FDD // schedule_RA(module_idP,frameP, subframeP, 0, nprb, nCCE); // schedule_ulsch(module_idP, frameP, cooperation_flag, 4, 8, nCCE); - schedule_ue_spec(module_idP, frameP, subframeP, nprb, nCCE, mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP, frameP, subframeP, nprb, nCCE, mbsfn_status); fill_DLSCH_dci(module_idP, frameP, subframeP, RBalloc, 1, mbsfn_status); } @@ -408,13 +487,37 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 5: schedule_RA(module_idP,frameP,subframeP,2,nprb,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,1,mbsfn_status); break; case 3: case 4: - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -423,7 +526,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD // schedule_ulsch(module_idP,frameP,cooperation_flag,6,0,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); } @@ -438,12 +553,36 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 3: case 4: schedule_RA(module_idP,frameP,subframeP,3,nprb,nCCE); // 3 = Msg3 subframeP, not - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,1,mbsfn_status); break; case 5: - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -452,7 +591,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD //schedule_ulsch(module_idP,frameP,cooperation_flag,7,1,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); } @@ -472,7 +623,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // schedule_RA(module_idP,subframeP,nprb,nCCE); schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,2,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -481,7 +644,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD //schedule_ulsch(module_idP,frameP,cooperation_flag,8,2,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); } @@ -495,28 +670,76 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 1: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3,nCCE); schedule_RA(module_idP,frameP,subframeP,7,nprb,nCCE); // 7 = Msg3 subframeP, not - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,1,mbsfn_status); break; case 3: case 4: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; case 6: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,4,nCCE); //schedule_RA(module_idP,frameP,subframeP,nprb,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; case 2: case 5: //schedule_RA(module_idP,frameP,subframeP,nprb,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -525,7 +748,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD // schedule_ulsch(module_idP,frameP,cooperation_flag,9,3,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); } diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index d02e42ee16..28df04ef64 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -35,6 +35,11 @@ */ #ifndef __LAYER2_MAC_PROTO_H__ #define __LAYER2_MAC_PROTO_H__ + +#include "enb_agent_defs.h" +#include "header.pb-c.h" +#include "progran.pb-c.h" + /** \addtogroup _mac * @{ */ @@ -139,6 +144,11 @@ void fill_DLSCH_dci(module_id_t module_idP,frame_t frameP,sub_frame_t subframe,u */ void schedule_ue_spec(module_id_t module_idP,frame_t frameP,sub_frame_t subframe,unsigned int *nb_rb_used0,unsigned int *nCCE_used,int *mbsfn_flag); +//To be used by the agent +void schedule_ue_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, + unsigned int *nb_rb_used, unsigned int *nCCE_used, + int *mbsfn_flag, Protocol__ProgranMessage *dl_info); + /** \brief Function for UE/PHY to compute PUSCH transmit power in power-control procedure. @param Mod_id Module id of UE @returns Po_NOMINAL_PUSCH (PREAMBLE_RECEIVED_TARGET_POWER+DELTA_PREAMBLE From cdb3e36b9949f15dbfbe57f0b62dd7af217df19b Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Sun, 31 Jan 2016 18:13:05 +0000 Subject: [PATCH 078/413] Fixes to merge with develop --- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 691 ++++++++++++++++-- openair2/LAYER2/MAC/eNB_scheduler.c | 273 +------ 2 files changed, 630 insertions(+), 334 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index 5adc4abc40..30894909a7 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -129,6 +129,8 @@ schedule_ue_spec_default( uint8_t rballoc_sub[25]; int i; + uint32_t data_to_request; + uint32_t dci_tbs; if (UE_list->head==-1) { @@ -233,10 +235,10 @@ schedule_ue_spec_default( nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; harq_pid = ue_sched_ctl->harq_pid[CC_id]; 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(mod_id, rnti); - 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; + //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(mod_id, rnti); + //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; @@ -246,20 +248,22 @@ schedule_ue_spec_default( DevCheck(((eNB_UE_stats->DL_cqi[0] < MIN_CQI_VALUE) || (eNB_UE_stats->DL_cqi[0] > MAX_CQI_VALUE)), eNB_UE_stats->DL_cqi[0], MIN_CQI_VALUE, MAX_CQI_VALUE); */ - eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; - eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); + + mcs = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; + //eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; + //eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); #ifdef EXMIMO - if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)==5) { - eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1,16); - } + // if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)==5) { + // eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1,16); + // } #endif // store stats - UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->DL_cqi[0]; + //UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->DL_cqi[0]; // initializing the rb allocation indicator for each UE for(j=0; jN_RBG; j++) { @@ -268,7 +272,7 @@ schedule_ue_spec_default( 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, ncc %d, rrc %d)\n", mod_id, frame, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb, - eNB_UE_stats->DL_cqi[0], eNB_UE_stats->dlsch_mcs1, + eNB_UE_stats->DL_cqi[0], mcs, nCCE[CC_id], UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); @@ -338,8 +342,21 @@ schedule_ue_spec_default( case 1: case 2: default: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t)); + dl_dci->mcs[0] = mcs; //eNB_UE_stats->dlsch_mcs1; + dl_dci->has_tpc = 1; + dl_dci->tpc = 1; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; dl_dci->has_format = 1; dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid], UE_list->UE_template[CC_id][UE_id].rballoc_subband); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); dl_dci->ndi[0] = 0; @@ -357,12 +374,20 @@ schedule_ue_spec_default( } break; case 4: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; dl_dci->has_format = 1; dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; dl_dci->n_ndi = 2; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); dl_dci->ndi[0] = 0; dl_dci->ndi[1] = 0; + //dl_dci->has_rb_bitmap = 1; + //dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; dl_dci->n_rv = 2; @@ -372,11 +397,19 @@ schedule_ue_spec_default( break; case 5: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; dl_dci->has_format = 1; dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); dl_dci->ndi[0] = 0; + //dl_dci->has_rb_bitmap = 1; + //dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; dl_dci->n_rv = 1; @@ -392,11 +425,19 @@ schedule_ue_spec_default( break; case 6: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; dl_dci->has_format = 1; dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); dl_dci->ndi[0] = 0; + //dl_dci->has_rb_bitmap = 1; + //dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; dl_dci->n_rv = 1; @@ -415,18 +456,18 @@ schedule_ue_spec_default( S_DL_SCHEDULED); //eNB_UE_stats->dlsch_trials[round]++; - UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; - UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx=nCCE[CC_id]; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=eNB_UE_stats->dlsch_mcs1; + //UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; + //UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; + //UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; + //UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx=nCCE[CC_id]; + //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1; + //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=eNB_UE_stats->dlsch_mcs1; + + num_ues_added += 1; } else { LOG_D(MAC,"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", mod_id, frame, CC_id, UE_id); } - - num_ues_added += 1; } else { /* This is a potentially new SDU opportunity */ @@ -434,7 +475,8 @@ schedule_ue_spec_default( // Now check RLC information to compute number of required RBs // get maximum TBS size for RLC request //TBS = mac_xface->get_TBS(eNB_UE_stats->DL_cqi[0]<<1,nb_available_rb); - TBS = mac_xface->get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_available_rb); + TBS = mac_xface->get_TBS_DL(mcs, nb_available_rb); + dci_tbs = TBS; // check first for RLC data on DCCH // add the length for all the control elements (timing adv, drx, etc) : header + payload @@ -468,13 +510,19 @@ schedule_ue_spec_default( if (ta_len > 0) { ce_flags |= PROTOCOL__PRP_CE_TYPE__PRPCET_TA; } - + + + // Add the control element flags to the progran message + dl_data[num_ues_added]->ce_bitmap[0] = ce_flags; + dl_data[num_ues_added]->ce_bitmap[1] = ce_flags; header_len_dcch = 2; // 2 bytes DCCH SDU subheader + // Need to see if we have space for data from this channel if ( TBS-ta_len-header_len_dcch > 0 ) { - + //If we have space, we need to see how much data we can request at most (if any are available) + rlc_status = mac_rlc_status_ind( mod_id, rnti, @@ -485,10 +533,30 @@ schedule_ue_spec_default( DCCH, (TBS-ta_len-header_len_dcch)); // transport block set size + //If data are available in the DCCH if (rlc_status.bytes_in_buffer > 0) { - sdu_length_total = cmin(rlc_status.bytes_in_buffer, TBS-ta_len-header_len_dcch); - // TODO: This should be replaced with the proper description of the CE - ce_flags |= PROTOCOL__PRP_CE_TYPE__PRPCET_CR; + + // Fill at most 1/3 of the remaining TB + data_to_request = 3;//cmin(3, rlc_status.bytes_in_buffer); + + rlc_pdus[0] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); + protocol__prp_rlc_pdu__init(rlc_pdus[0]); + rlc_pdus[0]->n_rlc_pdu_tb = 2; + rlc_pdus[0]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); + rlc_pdus[0]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + rlc_pdus[0]->rlc_pdu_tb[0]->has_logical_channel_id = 1; + rlc_pdus[0]->rlc_pdu_tb[0]->logical_channel_id = DCCH; + rlc_pdus[0]->rlc_pdu_tb[0]->has_size = 1; + rlc_pdus[0]->rlc_pdu_tb[0]->size = data_to_request; + rlc_pdus[0]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + rlc_pdus[0]->rlc_pdu_tb[1]->has_logical_channel_id = 1; + rlc_pdus[0]->rlc_pdu_tb[1]->logical_channel_id = DCCH; + rlc_pdus[0]->rlc_pdu_tb[1]->has_size = 1; + rlc_pdus[0]->rlc_pdu_tb[1]->size = data_to_request; + dl_data[num_ues_added]->n_rlc_pdu++; + + //Set this to the max value that we might request + sdu_length_total = data_to_request; } else { header_len_dcch = 0; sdu_length_total = 0; @@ -496,7 +564,9 @@ schedule_ue_spec_default( } // check for DCCH1 and update header information (assume 2 byte sub-header) - if (TBS-ta_len-header_len_dcch-sdu_length_total > 0 ) { + if (TBS-ta_len-header_len_dcch+2-sdu_length_total > 0 ) { + + //If we have space, we need to see how much data we can request at most (if any are available) rlc_status = mac_rlc_status_ind( mod_id, rnti, @@ -505,20 +575,36 @@ schedule_ue_spec_default( 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 + (TBS-ta_len-header_len_dcch+2-sdu_length_total)); // transport block set size less allocations for timing advance and // DCCH SDU + // If data are available in DCCH1 if (rlc_status.bytes_in_buffer > 0) { - // TODO: Again hypothetical flag. Need to check how to find the actual type of CE - ce_flags |= PROTOCOL__PRP_CE_TYPE__PRPCET_CA; - sdu_length_total += cmin(rlc_status.bytes_in_buffer, TBS-ta_len-header_len_dcch-sdu_length_total); header_len_dcch += 2; + + //Fill another 1/3 of the remaining TB + data_to_request = 3;//cmin(3, rlc_status.bytes_in_buffer); + + rlc_pdus[1] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); + protocol__prp_rlc_pdu__init(rlc_pdus[1]); + rlc_pdus[1]->n_rlc_pdu_tb = 2; + rlc_pdus[1]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); + rlc_pdus[1]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + rlc_pdus[1]->rlc_pdu_tb[0]->has_logical_channel_id = 1; + rlc_pdus[1]->rlc_pdu_tb[0]->logical_channel_id = DCCH; + rlc_pdus[1]->rlc_pdu_tb[0]->has_size = 1; + rlc_pdus[1]->rlc_pdu_tb[0]->size = data_to_request; + rlc_pdus[1]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + rlc_pdus[1]->rlc_pdu_tb[1]->has_logical_channel_id = 1; + rlc_pdus[1]->rlc_pdu_tb[1]->logical_channel_id = DCCH+1; + rlc_pdus[1]->rlc_pdu_tb[1]->has_size = 1; + rlc_pdus[1]->rlc_pdu_tb[1]->size = data_to_request; + dl_data[num_ues_added]->n_rlc_pdu++; + + sdu_length_total += data_to_request; } } - // Add the control element flags to the progran message - dl_data[num_ues_added]->ce_bitmap = ce_flags; - // check for DTCH and update header information // here we should loop over all possible DTCH @@ -529,6 +615,8 @@ schedule_ue_spec_default( 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 ) { + + //If we have space, we need to see how much data we can request at most (if any are available) rlc_status = mac_rlc_status_ind( mod_id, rnti, @@ -539,36 +627,31 @@ schedule_ue_spec_default( DTCH, TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); + // If data are available in DTCH if (rlc_status.bytes_in_buffer > 0) { - //TODO: Set rlc pdu info. Hardcoded for the moment + //Fill what remains in the TB + data_to_request = 3;//cmin(3, rlc_status.bytes_in_buffer); + rlc_pdus[2] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); + protocol__prp_rlc_pdu__init(rlc_pdus[2]); + rlc_pdus[2]->n_rlc_pdu_tb = 2; + rlc_pdus[2]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); + rlc_pdus[2]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + rlc_pdus[2]->rlc_pdu_tb[0]->has_logical_channel_id = 1; + rlc_pdus[2]->rlc_pdu_tb[0]->logical_channel_id = DTCH; + rlc_pdus[2]->rlc_pdu_tb[0]->has_size = 1; + rlc_pdus[2]->rlc_pdu_tb[0]->size = data_to_request; + rlc_pdus[2]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + rlc_pdus[2]->rlc_pdu_tb[1]->has_logical_channel_id = 1; + rlc_pdus[2]->rlc_pdu_tb[1]->logical_channel_id = DTCH; + rlc_pdus[2]->rlc_pdu_tb[1]->has_size = 1; + rlc_pdus[2]->rlc_pdu_tb[1]->size = data_to_request; dl_data[num_ues_added]->n_rlc_pdu++; - rlc_pdus[0] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); - protocol__prp_rlc_pdu__init(rlc_pdus[0]); - rlc_pdus[0]->n_rlc_pdu_tb = 2; - rlc_pdus[0]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); - rlc_pdus[0]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - rlc_pdus[0]->rlc_pdu_tb[0]->has_logical_channel_id = 1; - rlc_pdus[0]->rlc_pdu_tb[0]->logical_channel_id = DTCH; - rlc_pdus[0]->rlc_pdu_tb[0]->has_size = 1; - rlc_pdus[0]->rlc_pdu_tb[0]->size = TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch; - rlc_pdus[0]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - rlc_pdus[0]->rlc_pdu_tb[1]->has_logical_channel_id = 1; - rlc_pdus[0]->rlc_pdu_tb[1]->logical_channel_id = DTCH; - rlc_pdus[0]->rlc_pdu_tb[1]->has_size = 1; - rlc_pdus[0]->rlc_pdu_tb[1]->size = TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch; - // Add rlc_pdus to the dl_data message - dl_data[num_ues_added]->rlc_pdu = (Protocol__PrpRlcPdu **) malloc(sizeof(Protocol__PrpRlcPdu *) * - dl_data[num_ues_added]->n_rlc_pdu); - for (i = 0; i< dl_data[num_ues_added]->n_rlc_pdu; i++) { - dl_data[num_ues_added]->rlc_pdu[i] = rlc_pdus[i]; - } + sdu_length_total += data_to_request; - sdu_length_total += cmin(rlc_status.bytes_in_buffer, TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); - - if(cmin(rlc_status.bytes_in_buffer, TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch) < 128) { + if(data_to_request < 128) { header_len_dtch = 2; } @@ -577,41 +660,53 @@ schedule_ue_spec_default( } } + // Add rlc_pdus to the dl_data message + dl_data[num_ues_added]->rlc_pdu = (Protocol__PrpRlcPdu **) malloc(sizeof(Protocol__PrpRlcPdu *) * + dl_data[num_ues_added]->n_rlc_pdu); + for (i = 0; i< dl_data[num_ues_added]->n_rlc_pdu; i++) { + dl_data[num_ues_added]->rlc_pdu[i] = rlc_pdus[i]; + } + // there is a payload - if (((sdu_length_total + header_len_dcch + header_len_dtch )> 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) { + if (header_len_dtch == 0) { header_len_dcch = (header_len_dcch >0) ? 1 : header_len_dcch; // remove length field } else { header_len_dtch = (header_len_dtch > 0) ? 1 :header_len_dtch; // remove length field for the last SDU } - mcs = eNB_UE_stats->dlsch_mcs1; + int mcs2; - if (mcs==0) { + mcs2 = mcs; + + // TODO: Need to compute this and not take it from the stats + // mcs = eNB_UE_stats->dlsch_mcs1; + + if (mcs2==0) { nb_rb = 4; // don't let the TBS get too small } else { nb_rb=min_rb_unit[CC_id]; } - TBS = mac_xface->get_TBS_DL(mcs,nb_rb); + TBS = mac_xface->get_TBS_DL(mcs2,nb_rb); while (TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) { nb_rb += min_rb_unit[CC_id]; // if (nb_rb>nb_available_rb) { // if we've gone beyond the maximum number of RBs // (can happen if N_RB_DL is odd) - TBS = mac_xface->get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_available_rb); + TBS = mac_xface->get_TBS_DL(mcs2, nb_available_rb); nb_rb = nb_available_rb; break; } - TBS = mac_xface->get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_rb); + TBS = mac_xface->get_TBS_DL(mcs, nb_rb); } if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { @@ -647,16 +742,16 @@ schedule_ue_spec_default( } // decrease mcs until TBS falls below required length - while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs>0)) { - mcs--; - TBS = mac_xface->get_TBS_DL(mcs,nb_rb); + while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs2>0)) { + mcs2--; + TBS = mac_xface->get_TBS_DL(mcs2,nb_rb); } // if we have decreased too much or we don't have enough RBs, increase MCS - while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && ((( ue_sched_ctl->dl_pow_off[CC_id]>0) && (mcs<28)) - || ( (ue_sched_ctl->dl_pow_off[CC_id]==0) && (mcs<=15)))) { - mcs++; - TBS = mac_xface->get_TBS_DL(mcs,nb_rb); + while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && ((( ue_sched_ctl->dl_pow_off[CC_id]>0) && (mcs2<28)) + || ( (ue_sched_ctl->dl_pow_off[CC_id]==0) && (mcs2<=15)))) { + mcs2++; + TBS = mac_xface->get_TBS_DL(mcs2,nb_rb); } dl_dci->n_tbs_size = 2; @@ -664,7 +759,7 @@ schedule_ue_spec_default( dl_dci->tbs_size[0] = TBS; dl_dci->tbs_size[1] = TBS; - LOG_D(MAC,"dlsch_mcs before and after the rate matching = (%d, %d)\n",eNB_UE_stats->dlsch_mcs1, mcs); + LOG_D(MAC,"dlsch_mcs before and after the rate matching = (%d, %d)\n", mcs, mcs2); aggregation = process_ue_cqi(mod_id,UE_id); dl_dci->has_aggr_level = 1; @@ -745,7 +840,7 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->ndi[0] = 1; //1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = 0; @@ -754,6 +849,9 @@ schedule_ue_spec_default( dl_dci->n_mcs = 1; dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); dl_dci->mcs[0] = mcs; + dl_dci->n_tbs_size = 1; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t)); + dl_dci->tbs_size[0] = dci_tbs; if (frame_parms[CC_id]->frame_type == TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; @@ -777,7 +875,7 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 2; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->ndi[0] = 1; //1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_dci->ndi[1] = 0; dl_dci->n_rv = 2; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); @@ -812,7 +910,7 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 2; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->ndi[0] = 1; // 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_dci->ndi[1] = 0; dl_dci->n_rv = 2; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); @@ -846,7 +944,7 @@ schedule_ue_spec_default( dl_dci->has_rb_shift = 1; dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi = 1;//(uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); dl_dci->ndi[0] = 1; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); @@ -915,10 +1013,10 @@ schedule_ue_spec_default( break; } // Toggle NDI for next time - LOG_D(MAC,"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", - CC_id, frame, subframe, UE_id, - UE_list->UE_template[CC_id][UE_id].rnti,harq_pid, UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]); - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]=1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + //LOG_D(MAC,"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", + // CC_id, frame, subframe, UE_id, + // UE_list->UE_template[CC_id][UE_id].rnti,harq_pid, UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]); + //UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]=1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; // Increase the pointer for the number of scheduled UEs num_ues_added++; @@ -942,3 +1040,436 @@ schedule_ue_spec_default( stop_meas(&eNB->schedule_dlsch); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_OUT); } + +void apply_scheduling_decisions(mid_t mod_id, + uint32_t frame, + uint32_t subframe, + uint32_t *rballoc, + int *mbsfn_flag, + Protocol__ProgranMessage *dl_scheduling_info) { + + uint8_t CC_id; + int UE_id; + uint16_t nCCE[MAX_NUM_CCs]; + 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,header_len_dtch=0,header_len_dtch_tmp=0, ta_len=0; + unsigned char sdu_lcids[11],offset,num_sdus=0; + uint16_t nb_rb,nb_rb_temp,total_nb_available_rb[MAX_NUM_CCs],nb_available_rb; + uint16_t TBS,j,sdu_lengths[11],rnti,padding=0,post_padding=0; + unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; + unsigned char round = 0; + unsigned char harq_pid = 0; + void *DLSCH_dci = NULL; + DCI_PDU *DCI_pdu; + + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + uint16_t sdu_length_total = 0; + int mcs; + uint16_t min_rb_unit[MAX_NUM_CCs]; + short ta_update = 0; + eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; + UE_list_t *UE_list = &eNB->UE_list; + LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; + int32_t normalized_rx_power, target_rx_power; + int32_t tpc=1; + static int32_t tpc_accumulated=0; + UE_sched_ctrl *ue_sched_ctl; + + int i; + int size_bits,size_bytes; + + Protocol__PrpDlMacConfig *mac_config = dl_scheduling_info->dl_mac_config_msg; + Protocol__PrpDlData *dl_data; + Protocol__PrpDlDci *dl_dci; + + uint32_t rlc_size, n_lc, lcid; + + // Check if there is any scheduling command for UE data + if (mac_config->n_dl_ue_data > 0) { + + // For each UE-related command + for (i = 0; i < mac_config->n_dl_ue_data; i++) { + + dl_data = mac_config->dl_ue_data[i]; + dl_dci = dl_data->dl_dci; + + CC_id = dl_data->serv_cell_index; + rnti = dl_data->rnti; + UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); + + //NOTICE: Maybe later will not be required, once scheduler fully restructured + eNB_dlsch_info[mod_id][CC_id][UE_id].status = S_DL_WAITING; + + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); + + round = dl_dci->rv[0]; + harq_pid = dl_dci->harq_process; + + // Note this code is for a specific DCI format + DLSCH_dci = (void *)UE_list->UE_template[CC_id][UE_id].DLSCH_DCI[harq_pid]; + DCI_pdu = &eNB->common_channels[CC_id].DCI_pdu; + + frame_parms[CC_id] = mac_xface->get_lte_frame_parms(mod_id, CC_id); + + switch (frame_parms[CC_id]->N_RB_DL) { + case 6: + if (frame_parms[CC_id]->frame_type == TDD) { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rv = round; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_1_5MHz_TDD_t); + size_bits = sizeof_DCI1_1_5MHz_TDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } else { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rv = round; + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_1_5MHz_FDD_t); + size_bits = sizeof_DCI1_1_5MHz_FDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } + break; + case 25: + if (frame_parms[CC_id]->frame_type == TDD) { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rv = round; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_5MHz_TDD_t); + size_bits = sizeof_DCI1_5MHz_TDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } else { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rv = round; + if (dl_dci->has_rb_bitmap) { + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + } + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_5MHz_FDD_t); + size_bits = sizeof_DCI1_5MHz_FDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } + break; + case 50: + if (frame_parms[CC_id]->frame_type == TDD) { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rv = round; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_10MHz_TDD_t); + size_bits = sizeof_DCI1_10MHz_TDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } else { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_10MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rv = round; + ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_10MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_10MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_10MHz_FDD_t); + size_bits = sizeof_DCI1_10MHz_FDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } + break; + case 100: + if (frame_parms[CC_id]->frame_type == TDD) { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rv = round; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_20MHz_TDD_t); + size_bits = sizeof_DCI1_20MHz_TDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } else { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rv = round; + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_20MHz_FDD_t); + size_bits = sizeof_DCI1_20MHz_FDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } + break; + } + + // If this is a new transmission + if (round == 0) { + // First we have to deal with the creation of the PDU based on the message instructions + rlc_status.bytes_in_buffer = 0; + + TBS = dl_dci->tbs_size[0]; + + if (dl_data->n_ce_bitmap > 0) { + //Check if there is TA command + if (dl_data->ce_bitmap[0] & PROTOCOL__PRP_CE_TYPE__PRPCET_TA) { + ta_len = 2; + } else { + ta_len = 0; + } + } + + n_lc = dl_data->n_rlc_pdu; + num_sdus = 0; + // Go through each one of the channel commands and create SDUs + for (i = 0; i < n_lc; i++) { + lcid = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->logical_channel_id; + rlc_size = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->size; + + if (rlc_size > 0) { + rlc_status = mac_rlc_status_ind( + mod_id, + rnti, + mod_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + rlc_size); // transport block set size + + sdu_lengths[i]=0; + + LOG_D(MAC,"[eNB %d] Frame %d, LCID %d, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", + mod_id, frame, lcid, CC_id, rlc_size); + + sdu_lengths[i] += mac_rlc_data_req( + mod_id, + rnti, + mod_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + (char *)&dlsch_buffer[sdu_lengths[i]]); + + LOG_D(MAC,"[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n",mod_id, CC_id, sdu_lengths[i]); + sdu_length_total += sdu_lengths[i]; + sdu_lcids[i] = lcid; + + if (lcid == DCCH || lcid == DCCH+1) { + header_len_dcch += 2; + } else if (lcid == DTCH) { + if (sdu_lengths[i] < 128) { + header_len_dtch = 2; + } else { + header_len_dtch = 3; + } + } + + UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH] += 1; + UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH] += sdu_lengths[i]; + num_sdus++; + + } + } // SDU creation end + + + if (header_len_dtch==0) { + header_len_dcch = (header_len_dcch >0) ? 1 : header_len_dcch; // remove length field + } else { + header_len_dtch = (header_len_dtch > 0) ? 1 :header_len_dtch; // remove length field for the last SDU + } + + // there is a payload + if (((sdu_length_total + header_len_dcch + header_len_dtch ) > 0)) { + if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2) { + padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); + post_padding = 0; + } else { + padding = 0; + + // adjust the header len + if (header_len_dtch==0) { + header_len_dcch = header_len_dcch_tmp; + } else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2))) + header_len_dtch = header_len_dtch_tmp; + } + + post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len ; // 1 is for the postpadding header + } + } + + uint8_t update_TA=4; + + switch (frame_parms[CC_id]->N_RB_DL) { + case 6: + update_TA = 1; + break; + + case 25: + update_TA = 4; + break; + + case 50: + update_TA = 8; + break; + + case 100: + update_TA = 16; + break; + } + + if (ta_len > 0) { + ta_update = eNB_UE_stats->timing_advance_update/update_TA; + } else { + ta_update = 0; + } + /*#else + ta_update = 0; + #endif*/ + + offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], + // offset = generate_dlsch_header((unsigned char*)eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0], + num_sdus, //num_sdus + sdu_lengths, // + sdu_lcids, + 255, // no drx + ta_update, // timing advance + NULL, // contention res id + padding, + post_padding); + + +#ifdef DEBUG_eNB_SCHEDULER + LOG_T(MAC,"[eNB %d] First 16 bytes of DLSCH : \n"); + + for (i=0; i<16; i++) { + LOG_T(MAC,"%x.",dlsch_buffer[i]); + } + + LOG_T(MAC,"\n"); +#endif + // cycle through SDUs and place in dlsch_buffer + memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset],dlsch_buffer,sdu_length_total); + // memcpy(&eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]); + + // fill remainder of DLSCH with random data + for (j=0; j<(TBS-sdu_length_total-offset); j++) { + UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset+sdu_length_total+j] = (char)(taus()&0xff); + } + + //eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0][offset+sdu_lengths[0]+j] = (char)(taus()&0xff); + if (opt_enabled == 1) { + trace_pdu(1, (uint8_t *)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], + TBS, mod_id, 3, UE_RNTI(mod_id, UE_id), + eNB->subframe,0,0); + LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", + mod_id, CC_id, frame, UE_RNTI(mod_id,UE_id), TBS); + } + + // store stats + eNB->eNB_stats[CC_id].dlsch_bytes_tx+=sdu_length_total; + eNB->eNB_stats[CC_id].dlsch_pdus_tx+=1; + + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used = nCCE[CC_id]; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=dl_dci->mcs[0]; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=dl_dci->mcs[0]; + UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; + + UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes= TBS- sdu_length_total; + UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes+= sdu_length_total; + UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes+= TBS; + UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus+=1; + // TODO + + + } else { + // No need to create anything apart of DCI in case of retransmission + } + + //Add DCI based on format + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + add_ue_spec_dci(DCI_pdu, + DLSCH_dci, + rnti, + size_bytes, + process_ue_cqi (mod_id, UE_id),//aggregation + size_bits, + format1, + 0); + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + add_ue_spec_dci(DCI_pdu, + DLSCH_dci, + rnti, + size_bytes, + process_ue_cqi (mod_id, UE_id),//aggregation + size_bits, + format2A, + 0); + } + } + } +} + diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 0de9253fef..329c40be05 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -59,10 +59,6 @@ //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" -//Agent-related headers -#include "ENB_APP/enb_agent_extern.h" -#include "ENB_APP/enb_agent_mac.h" - #if defined(ENABLE_ITTI) # include "intertask_interface.h" #endif @@ -89,9 +85,6 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, int mbsfn_status[MAX_NUM_CCs]; uint32_t RBalloc[MAX_NUM_CCs]; protocol_ctxt_t ctxt; - - Protocol__ProgranMessage *msg; - #ifdef EXMIMO int ret; #endif @@ -282,19 +275,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; } } else { //FDD - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); schedule_ulsch(module_idP,frameP,cooperation_flag,1,5,nCCE); } @@ -306,19 +287,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // TDD, nothing // FDD, normal UL/DLSCH if (mac_xface->lte_frame_parms->frame_type == FDD) { //FDD - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); schedule_ulsch(module_idP,frameP,cooperation_flag,2,6,nCCE); } @@ -337,19 +306,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // no break here! case 5: - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -357,19 +314,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; } } else { //FDD - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); schedule_ulsch(module_idP,frameP,cooperation_flag,3,7,nCCE); @@ -396,19 +341,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // no break here! case 5: - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,1,mbsfn_status); break; @@ -419,19 +352,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, if (mac_xface->lte_frame_parms->frame_type == FDD) { //FDD // schedule_RA(module_idP,frameP, subframeP, 0, nprb, nCCE); // schedule_ulsch(module_idP, frameP, cooperation_flag, 4, 8, nCCE); - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP, frameP, subframeP, nprb, nCCE, mbsfn_status); + schedule_ue_spec(module_idP, frameP, subframeP, nprb, nCCE, mbsfn_status); fill_DLSCH_dci(module_idP, frameP, subframeP, RBalloc, 1, mbsfn_status); } @@ -487,37 +408,13 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 5: schedule_RA(module_idP,frameP,subframeP,2,nprb,nCCE); - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,1,mbsfn_status); break; case 3: case 4: - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -526,19 +423,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD // schedule_ulsch(module_idP,frameP,cooperation_flag,6,0,nCCE); - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); } @@ -553,36 +438,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 3: case 4: schedule_RA(module_idP,frameP,subframeP,3,nprb,nCCE); // 3 = Msg3 subframeP, not - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,1,mbsfn_status); break; case 5: - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -591,19 +452,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD //schedule_ulsch(module_idP,frameP,cooperation_flag,7,1,nCCE); - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); } @@ -623,19 +472,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // schedule_RA(module_idP,subframeP,nprb,nCCE); schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,2,nCCE); - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -644,19 +481,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD //schedule_ulsch(module_idP,frameP,cooperation_flag,8,2,nCCE); - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); } @@ -670,76 +495,28 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 1: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3,nCCE); schedule_RA(module_idP,frameP,subframeP,7,nprb,nCCE); // 7 = Msg3 subframeP, not - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,1,mbsfn_status); break; case 3: case 4: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3,nCCE); - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; case 6: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,4,nCCE); //schedule_RA(module_idP,frameP,subframeP,nprb,nCCE); - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; case 2: case 5: //schedule_RA(module_idP,frameP,subframeP,nprb,nCCE); - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -748,19 +525,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD // schedule_ulsch(module_idP,frameP,cooperation_flag,9,3,nCCE); - if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - nprb, - nCCE, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } - //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); } From a91a25c97258ab6307628dc2de10b5f5359ae9e8 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 1 Feb 2016 11:38:07 +0000 Subject: [PATCH 079/413] Changed signature of DL scheduling function of agent --- openair2/ENB_APP/enb_agent_mac_defs.h | 1 - .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 17 +++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/enb_agent_mac_defs.h index 67b89bf610..c2891e87ca 100644 --- a/openair2/ENB_APP/enb_agent_mac_defs.h +++ b/openair2/ENB_APP/enb_agent_mac_defs.h @@ -58,7 +58,6 @@ typedef struct { /// dl_info is already initialized as prp_dl_mac_config and fills the /// prp_dl_data part of it void (*enb_agent_schedule_ue_spec)(mid_t mod_id, uint32_t frame, uint32_t subframe, - unsigned int *nb_rb_used, unsigned int *nCCE_used, int *mbsfn_flag, Protocol__ProgranMessage *dl_info); /*TODO: Fill in with the rest of the MAC layer technology specific callbacks (UL/DL scheduling, RACH info etc)*/ diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index 30894909a7..7435194d33 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -78,8 +78,6 @@ schedule_ue_spec_default( mid_t mod_id, uint32_t frame, uint32_t subframe, - unsigned int *nb_rb_used, - unsigned int *nCCE_used, int *mbsfn_flag, Protocol__ProgranMessage *dl_info ) @@ -146,8 +144,8 @@ schedule_ue_spec_default( for (CC_id=0; CC_idget_lte_frame_parms(mod_id, CC_id); - total_nb_available_rb[CC_id] = frame_parms[CC_id]->N_RB_DL - nb_rb_used[CC_id]; - nCCE[CC_id] = mac_xface->get_nCCE_max(mod_id, CC_id) - nCCE_used[CC_id]; + //total_nb_available_rb[CC_id] = frame_parms[CC_id]->N_RB_DL - nb_rb_used[CC_id]; + //nCCE[CC_id] = mac_xface->get_nCCE_max(mod_id, CC_id) - nCCE_used[CC_id]; N_RBG[CC_id] = frame_parms[CC_id]->N_RBG; // store the global enb stats: @@ -195,8 +193,8 @@ schedule_ue_spec_default( } if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || (nCCE[CC_id] < (1<pre_nb_available_rbs[CC_id], nCCE[CC_id], aggregation); + // LOG_D(MAC,"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", + // mod_id, frame, UE_id, CC_id, nb_rb_used[CC_id], ue_sched_ctl->pre_nb_available_rbs[CC_id], nCCE[CC_id], aggregation); //if(mac_xface->get_transmission_mode(module_idP,rnti)==5) continue_flag=1; //to next user (there might be rbs availiable for other UEs in TM5 // else @@ -329,7 +327,7 @@ schedule_ue_spec_default( nb_available_rb -= nb_rb; aggregation = process_ue_cqi(mod_id, UE_id); nCCE[CC_id]-=(1<mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; @@ -765,9 +763,9 @@ schedule_ue_spec_default( dl_dci->has_aggr_level = 1; dl_dci->aggr_level = aggregation; dl_dci->has_cce_index = 1; - dl_dci->cce_index = nCCE_used[CC_id]; + // dl_dci->cce_index = nCCE_used[CC_id]; nCCE[CC_id]-=(1<UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; add_ue_dlsch_info(mod_id, @@ -1044,7 +1042,6 @@ schedule_ue_spec_default( void apply_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, - uint32_t *rballoc, int *mbsfn_flag, Protocol__ProgranMessage *dl_scheduling_info) { From ab0e4aadaebe1fc40d4a4359f76424b866685210 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 1 Feb 2016 17:20:35 +0000 Subject: [PATCH 080/413] Reintroduced support for agent scheduler after merge with develop --- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 476 +++++++++--------- openair2/LAYER2/MAC/eNB_scheduler.c | 441 +++++++++++++++- openair2/LAYER2/MAC/proto.h | 1 - 3 files changed, 668 insertions(+), 250 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index 7435194d33..a4fbac6de2 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -86,7 +86,6 @@ schedule_ue_spec_default( //TODO uint8_t CC_id; int UE_id; - uint16_t nCCE[MAX_NUM_CCs]; int N_RBG[MAX_NUM_CCs]; unsigned char aggregation; mac_rlc_status_resp_t rlc_status; @@ -103,9 +102,8 @@ schedule_ue_spec_default( // uint8_t dl_pow_off[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; // unsigned char rballoc_sub_UE[MAX_NUM_CCs][NUMBER_OF_UE_MAX][N_RBG_MAX]; // uint16_t pre_nb_available_rbs[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - int mcs; + int mcs, mcs_tmp; uint16_t min_rb_unit[MAX_NUM_CCs]; - short ta_update = 0; eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; UE_list_t *UE_list = &eNB->UE_list; LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; @@ -144,15 +142,18 @@ schedule_ue_spec_default( for (CC_id=0; CC_idget_lte_frame_parms(mod_id, CC_id); - //total_nb_available_rb[CC_id] = frame_parms[CC_id]->N_RB_DL - nb_rb_used[CC_id]; - //nCCE[CC_id] = mac_xface->get_nCCE_max(mod_id, CC_id) - nCCE_used[CC_id]; + // get number of PRBs less those used by common channels + 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]--; + N_RBG[CC_id] = frame_parms[CC_id]->N_RBG; // store the global enb stats: eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs; eNB->eNB_stats[CC_id].available_prbs = total_nb_available_rb[CC_id]; eNB->eNB_stats[CC_id].total_available_prbs += total_nb_available_rb[CC_id]; - eNB->eNB_stats[CC_id].available_ncces = nCCE[CC_id]; eNB->eNB_stats[CC_id].dlsch_bytes_tx=0; eNB->eNB_stats[CC_id].dlsch_pdus_tx=0; } @@ -192,15 +193,17 @@ schedule_ue_spec_default( continue_flag=1; } - if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || (nCCE[CC_id] < (1<pre_nb_available_rbs[CC_id], nCCE[CC_id], aggregation); + if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated + CCE_allocation_infeasible(mod_id, CC_id, 0, subframe, aggregation, rnti) + ) { + LOG_D(MAC,"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", + mod_id, frame, UE_id, CC_id); //if(mac_xface->get_transmission_mode(module_idP,rnti)==5) continue_flag=1; //to next user (there might be rbs availiable for other UEs in TM5 // else // break; } - + if (frame_parms[CC_id]->frame_type == TDD) { set_ue_dai (subframe, frame_parms[CC_id]->tdd_config, @@ -233,6 +236,8 @@ schedule_ue_spec_default( nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; harq_pid = ue_sched_ctl->harq_pid[CC_id]; round = ue_sched_ctl->round[CC_id]; + + /* TODO: Must add these stats (probably in the apply_scheduling function) */ //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(mod_id, rnti); //UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid; @@ -248,15 +253,18 @@ schedule_ue_spec_default( */ mcs = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; + + /*TODO: Must also update these stats*/ //eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; //eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); #ifdef EXMIMO - // if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)==5) { - // eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1,16); - // } + if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)==5) { + mcs = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; + //eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1,16); + } #endif @@ -264,14 +272,13 @@ schedule_ue_spec_default( //UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->DL_cqi[0]; // initializing the rb allocation indicator for each UE - for(j=0; jN_RBG; j++) { + for(j = 0; j < frame_parms[CC_id]->N_RBG; j++) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0; } - 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, ncc %d, rrc %d)\n", + 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", mod_id, frame, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb, eNB_UE_stats->DL_cqi[0], mcs, - nCCE[CC_id], UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); dl_dci = (Protocol__PrpDlDci*) malloc(sizeof(Protocol__PrpDlDci)); @@ -301,14 +308,14 @@ schedule_ue_spec_default( if (nb_rb <= nb_available_rb) { if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { - for(j=0; jN_RBG; j++) { // for indicating the rballoc for each sub-band + for(j = 0; j < frame_parms[CC_id]->N_RBG; j++) { // for indicating the rballoc for each sub-band UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; } } else { nb_rb_temp = nb_rb; j = 0; - while((nb_rb_temp > 0) && (jN_RBG)) { + while((nb_rb_temp > 0) && (j < frame_parms[CC_id]->N_RBG)) { if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; if((j == frame_parms[CC_id]->N_RBG-1) && @@ -326,8 +333,6 @@ schedule_ue_spec_default( nb_available_rb -= nb_rb; aggregation = process_ue_cqi(mod_id, UE_id); - nCCE[CC_id]-=(1<mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; @@ -344,7 +349,8 @@ schedule_ue_spec_default( dl_dci->res_alloc = 0; dl_dci->n_mcs = 1; dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t)); - dl_dci->mcs[0] = mcs; //eNB_UE_stats->dlsch_mcs1; + dl_dci->mcs[0] = mcs; + //TODO:Need to fix tpc for retransmissions dl_dci->has_tpc = 1; dl_dci->tpc = 1; dl_dci->has_vrb_format = 1; @@ -352,7 +358,7 @@ schedule_ue_spec_default( dl_dci->has_format = 1; dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1; dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid], UE_list->UE_template[CC_id][UE_id].rballoc_subband); + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, UE_list->UE_template[CC_id][UE_id].rballoc_subband); dl_dci->has_rb_shift = 1; dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; @@ -374,29 +380,48 @@ schedule_ue_spec_default( case 4: dl_dci->has_res_alloc = 1; dl_dci->res_alloc = 0; + dl_dci->n_mcs = 2; + dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->mcs[1] = mcs; + //TODO:Need to fix tpc for retransmissions + dl_dci->has_tpc = 1; + dl_dci->tpc = 1; dl_dci->has_vrb_format = 1; dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; dl_dci->has_format = 1; dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, UE_list->UE_template[CC_id][UE_id].rballoc_subband); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; dl_dci->n_ndi = 2; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); dl_dci->ndi[0] = 0; dl_dci->ndi[1] = 0; - //dl_dci->has_rb_bitmap = 1; - //dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; dl_dci->n_rv = 2; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = round&3; dl_dci->rv[1] = round&3; - + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", + mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); + } else { + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", + mod_id, CC_id, harq_pid, round); + } break; case 5: dl_dci->has_res_alloc = 1; dl_dci->res_alloc = 0; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t)); + dl_dci->mcs[0] = mcs; + //TODO:Need to fix tpc for retransmissions + dl_dci->has_tpc = 1; + dl_dci->tpc = 1; dl_dci->has_vrb_format = 1; dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; dl_dci->has_format = 1; @@ -404,8 +429,8 @@ schedule_ue_spec_default( dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); dl_dci->ndi[0] = 0; - //dl_dci->has_rb_bitmap = 1; - //dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, UE_list->UE_template[CC_id][UE_id].rballoc_subband); dl_dci->has_rb_shift = 1; dl_dci->rb_shift = 0; dl_dci->has_dai = 1; @@ -425,6 +450,12 @@ schedule_ue_spec_default( case 6: dl_dci->has_res_alloc = 1; dl_dci->res_alloc = 0; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t)); + dl_dci->mcs[0] = mcs; + //TODO:Need to fix tpc for retransmissions + dl_dci->has_tpc = 1; + dl_dci->tpc = 1; dl_dci->has_vrb_format = 1; dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; dl_dci->has_format = 1; @@ -432,8 +463,8 @@ schedule_ue_spec_default( dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); dl_dci->ndi[0] = 0; - //dl_dci->has_rb_bitmap = 1; - //dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, UE_list->UE_template[CC_id][UE_id].rballoc_subband); dl_dci->has_rb_shift = 1; dl_dci->rb_shift = 0; dl_dci->has_dai = 1; @@ -447,17 +478,18 @@ schedule_ue_spec_default( break; } - add_ue_dlsch_info(mod_id, - CC_id, - UE_id, - subframe, - S_DL_SCHEDULED); + /*We now probably don't need this*/ + /* add_ue_dlsch_info(mod_id, */ + /* CC_id, */ + /* UE_id, */ + /* subframe, */ + /* S_DL_SCHEDULED); */ //eNB_UE_stats->dlsch_trials[round]++; //UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; //UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; //UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; - //UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx=nCCE[CC_id]; + //UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx=nCCECC_id]; //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1; //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=eNB_UE_stats->dlsch_mcs1; @@ -475,33 +507,12 @@ schedule_ue_spec_default( //TBS = mac_xface->get_TBS(eNB_UE_stats->DL_cqi[0]<<1,nb_available_rb); TBS = mac_xface->get_TBS_DL(mcs, nb_available_rb); dci_tbs = TBS; + // check first for RLC data on DCCH // add the length for all the control elements (timing adv, drx, etc) : header + payload - //#ifndef EXMIMO_IOT - // to be checked by RK, NN, FK - uint8_t update_TA=4; - - switch (frame_parms[CC_id]->N_RB_DL) { - case 6: - update_TA = 1; - break; - - case 25: - update_TA = 4; - break; - - case 50: - update_TA = 8; - break; - - case 100: - update_TA = 16; - break; - } - - ta_len = ((eNB_UE_stats->timing_advance_update/update_TA)!=0) ? 2 : 0; - + ta_len = (ue_sched_ctl->ta_update!=0) ? 2 : 0; + dl_data[num_ues_added]->n_ce_bitmap = 2; dl_data[num_ues_added]->ce_bitmap = (uint32_t *) malloc(sizeof(uint32_t) * 2); @@ -509,6 +520,7 @@ schedule_ue_spec_default( ce_flags |= PROTOCOL__PRP_CE_TYPE__PRPCET_TA; } + /*TODO: Add other flags if DRX and other CE are required*/ // Add the control element flags to the progran message dl_data[num_ues_added]->ce_bitmap[0] = ce_flags; @@ -519,24 +531,22 @@ schedule_ue_spec_default( // Need to see if we have space for data from this channel if ( TBS-ta_len-header_len_dcch > 0 ) { - //If we have space, we need to see how much data we can request at most (if any are available) - - rlc_status = mac_rlc_status_ind( - mod_id, - rnti, - mod_id, - frame, - ENB_FLAG_YES, - MBMS_FLAG_NO, - DCCH, - (TBS-ta_len-header_len_dcch)); // transport block set size + //If we have space, we need to see how much data we can request at most (if any available) + rlc_status = mac_rlc_status_ind(mod_id, + rnti, + mod_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + DCCH, + (dci_tbs-ta_len-header_len_dcch)); // transport block set size //If data are available in the DCCH if (rlc_status.bytes_in_buffer > 0) { - - // Fill at most 1/3 of the remaining TB - data_to_request = 3;//cmin(3, rlc_status.bytes_in_buffer); - + LOG_D(MAC, "[TEST]Have %d bytes in buffer DCCH during first call\n", rlc_status.bytes_in_buffer); + //Fill in as much as possible + data_to_request = cmin(dci_tbs-ta_len-header_len_dcch, rlc_status.bytes_in_buffer) + 1; + LOG_D(MAC, "[TEST]Will request %d \n", data_to_request); rlc_pdus[0] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); protocol__prp_rlc_pdu__init(rlc_pdus[0]); rlc_pdus[0]->n_rlc_pdu_tb = 2; @@ -562,26 +572,25 @@ schedule_ue_spec_default( } // check for DCCH1 and update header information (assume 2 byte sub-header) - if (TBS-ta_len-header_len_dcch+2-sdu_length_total > 0 ) { + if (dci_tbs-ta_len-header_len_dcch-sdu_length_total > 0 ) { //If we have space, we need to see how much data we can request at most (if any are available) - rlc_status = mac_rlc_status_ind( - mod_id, + rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH+1, - (TBS-ta_len-header_len_dcch+2-sdu_length_total)); // transport block set size less allocations for timing advance and + (dci_tbs-ta_len-header_len_dcch-sdu_length_total)); // transport block set size less allocations for timing advance and // DCCH SDU // If data are available in DCCH1 if (rlc_status.bytes_in_buffer > 0) { header_len_dcch += 2; - - //Fill another 1/3 of the remaining TB - data_to_request = 3;//cmin(3, rlc_status.bytes_in_buffer); + + //Fill in as much as possible + data_to_request = cmin(dci_tbs-ta_len-header_len_dcch-sdu_length_total, rlc_status.bytes_in_buffer) + 1; rlc_pdus[1] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); protocol__prp_rlc_pdu__init(rlc_pdus[1]); @@ -589,7 +598,7 @@ schedule_ue_spec_default( rlc_pdus[1]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); rlc_pdus[1]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); rlc_pdus[1]->rlc_pdu_tb[0]->has_logical_channel_id = 1; - rlc_pdus[1]->rlc_pdu_tb[0]->logical_channel_id = DCCH; + rlc_pdus[1]->rlc_pdu_tb[0]->logical_channel_id = DCCH+1; rlc_pdus[1]->rlc_pdu_tb[0]->has_size = 1; rlc_pdus[1]->rlc_pdu_tb[0]->size = data_to_request; rlc_pdus[1]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); @@ -610,27 +619,26 @@ schedule_ue_spec_default( LOG_D(MAC,"[eNB %d], Frame %d, DTCH->DLSCH, CC_id %d, Checking RLC status (rab %d, tbs %d, len %d)\n", mod_id, frame, CC_id, DTCH, TBS, - TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); + dci_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 ) { + if (dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch > 0 ) { //If we have space, we need to see how much data we can request at most (if any are available) - rlc_status = mac_rlc_status_ind( - mod_id, + rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, ENB_FLAG_YES, MBMS_FLAG_NO, DTCH, - TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); + dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); // If data are available in DTCH if (rlc_status.bytes_in_buffer > 0) { - + LOG_D(MAC, "[TEST] Have %d bytes in buffer DTCH during first call\n", rlc_status.bytes_in_buffer); //Fill what remains in the TB - data_to_request = 3;//cmin(3, rlc_status.bytes_in_buffer); - + data_to_request = cmin(dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch, rlc_status.bytes_in_buffer) + 1; + LOG_D(MAC, "[TEST]Will request %d \n", data_to_request); rlc_pdus[2] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); protocol__prp_rlc_pdu__init(rlc_pdus[2]); rlc_pdus[2]->n_rlc_pdu_tb = 2; @@ -654,14 +662,14 @@ schedule_ue_spec_default( } } else { - header_len_dtch = 0; + header_len_dtch = 3; } } // Add rlc_pdus to the dl_data message dl_data[num_ues_added]->rlc_pdu = (Protocol__PrpRlcPdu **) malloc(sizeof(Protocol__PrpRlcPdu *) * dl_data[num_ues_added]->n_rlc_pdu); - for (i = 0; i< dl_data[num_ues_added]->n_rlc_pdu; i++) { + for (i = 0; i < dl_data[num_ues_added]->n_rlc_pdu; i++) { dl_data[num_ues_added]->rlc_pdu[i] = rlc_pdus[i]; } @@ -674,51 +682,48 @@ schedule_ue_spec_default( header_len_dtch_tmp = header_len_dtch; if (header_len_dtch == 0) { - header_len_dcch = (header_len_dcch >0) ? 1 : header_len_dcch; // remove length field + header_len_dcch = (header_len_dcch > 0) ? 1 : header_len_dcch; // remove length field } else { - header_len_dtch = (header_len_dtch > 0) ? 1 :header_len_dtch; // remove length field for the last SDU + header_len_dtch = (header_len_dtch > 0) ? 1 : header_len_dtch; // remove length field for the last SDU } - int mcs2; - - mcs2 = mcs; + mcs_tmp = mcs; // TODO: Need to compute this and not take it from the stats // mcs = eNB_UE_stats->dlsch_mcs1; - if (mcs2==0) { + if (mcs_tmp == 0) { nb_rb = 4; // don't let the TBS get too small } else { nb_rb=min_rb_unit[CC_id]; } - TBS = mac_xface->get_TBS_DL(mcs2,nb_rb); + TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); while (TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) { nb_rb += min_rb_unit[CC_id]; // - if (nb_rb>nb_available_rb) { // if we've gone beyond the maximum number of RBs + if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs // (can happen if N_RB_DL is odd) - TBS = mac_xface->get_TBS_DL(mcs2, nb_available_rb); + TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_available_rb); nb_rb = nb_available_rb; break; } - TBS = mac_xface->get_TBS_DL(mcs, nb_rb); + TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); } if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { - for(j=0; jN_RBG; j++) { // for indicating the rballoc for each sub-band + for(j = 0; j < frame_parms[CC_id]->N_RBG; j++) { // for indicating the rballoc for each sub-band UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; } } else { nb_rb_temp = nb_rb; j = 0; - while((nb_rb_temp > 0) && (jN_RBG)) { + while((nb_rb_temp > 0) && (j < frame_parms[CC_id]->N_RBG)) { if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - if ((j == frame_parms[CC_id]->N_RBG-1) && ((frame_parms[CC_id]->N_RB_DL == 25)|| (frame_parms[CC_id]->N_RB_DL == 50))) { @@ -735,44 +740,41 @@ schedule_ue_spec_default( PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; - for(j=0; jN_RBG; j++) { + for(j = 0; j < frame_parms[CC_id]->N_RBG; j++) { PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; } // decrease mcs until TBS falls below required length - while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs2>0)) { - mcs2--; - TBS = mac_xface->get_TBS_DL(mcs2,nb_rb); + while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs_tmp > 0)) { + mcs_tmp--; + TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); } // if we have decreased too much or we don't have enough RBs, increase MCS - while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && ((( ue_sched_ctl->dl_pow_off[CC_id]>0) && (mcs2<28)) - || ( (ue_sched_ctl->dl_pow_off[CC_id]==0) && (mcs2<=15)))) { - mcs2++; - TBS = mac_xface->get_TBS_DL(mcs2,nb_rb); + while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && + ((( ue_sched_ctl->dl_pow_off[CC_id] > 0) && (mcs_tmp < 28)) || ( (ue_sched_ctl->dl_pow_off[CC_id]==0) && (mcs_tmp <= 15)))) { + mcs_tmp++; + TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); } - dl_dci->n_tbs_size = 2; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * 2); - dl_dci->tbs_size[0] = TBS; - dl_dci->tbs_size[1] = TBS; + LOG_D(MAC,"dlsch_mcs and TBS before and after the rate matching = (%d, %d) (%d, %d)\n", mcs, mcs_tmp, dci_tbs, TBS); - LOG_D(MAC,"dlsch_mcs before and after the rate matching = (%d, %d)\n", mcs, mcs2); + dci_tbs = TBS; + + mcs = mcs_tmp; aggregation = process_ue_cqi(mod_id,UE_id); dl_dci->has_aggr_level = 1; dl_dci->aggr_level = aggregation; - dl_dci->has_cce_index = 1; - // dl_dci->cce_index = nCCE_used[CC_id]; - nCCE[CC_id]-=(1<UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; - add_ue_dlsch_info(mod_id, - CC_id, - UE_id, - subframe, - S_DL_SCHEDULED); + /*Deactivate here as well*/ + /* add_ue_dlsch_info(mod_id, */ + /* CC_id, */ + /* UE_id, */ + /* subframe, */ + /* S_DL_SCHEDULED); */ if (frame_parms[CC_id]->frame_type == TDD) { UE_list->UE_template[CC_id][UE_id].DAI++; @@ -838,8 +840,8 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1; //1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->n_rv = 1; + dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->n_rv = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = 0; dl_dci->has_tpc = 1; @@ -848,16 +850,11 @@ schedule_ue_spec_default( dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); dl_dci->mcs[0] = mcs; dl_dci->n_tbs_size = 1; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t)); + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); dl_dci->tbs_size[0] = dci_tbs; if (frame_parms[CC_id]->frame_type == TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", - mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); - } else { - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", - mod_id, CC_id, harq_pid, round); } break; case 3: @@ -873,26 +870,25 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 2; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1; //1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->ndi[1] = 0; + dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];; + dl_dci->ndi[1] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];; dl_dci->n_rv = 2; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = 0; - dl_dci->rv[1] = 1; + dl_dci->rv[1] = 0; dl_dci->has_tpc = 1; dl_dci->tpc = tpc; dl_dci->n_mcs = 2; dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); dl_dci->mcs[0] = mcs; - dl_dci->mcs[1] = 0; + dl_dci->mcs[1] = mcs; + dl_dci->n_tbs_size = 2; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + dl_dci->tbs_size[1] = dci_tbs; if (frame_parms[CC_id]->frame_type == TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", - mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); - } else { - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", - mod_id, CC_id, harq_pid, round); } break; case 4: @@ -901,33 +897,32 @@ schedule_ue_spec_default( dl_dci->has_vrb_format = 1; dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; dl_dci->has_rb_bitmap = 1; dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); dl_dci->has_rb_shift = 1; dl_dci->rb_shift = 0; dl_dci->n_ndi = 2; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1; // 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->ndi[1] = 0; + dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];; + dl_dci->ndi[1] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];; dl_dci->n_rv = 2; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = 0; - dl_dci->rv[1] = round&3; + dl_dci->rv[1] = 0; dl_dci->has_tpc = 1; dl_dci->tpc = tpc; dl_dci->n_mcs = 2; dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); dl_dci->mcs[0] = mcs; - dl_dci->mcs[1] = 0; + dl_dci->mcs[1] = mcs; + dl_dci->n_tbs_size = 2; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + dl_dci->tbs_size[1] = dci_tbs; if (frame_parms[CC_id]->frame_type == TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", - mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); - } else { - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", - mod_id, CC_id, harq_pid, round); } break; case 5: @@ -942,8 +937,8 @@ schedule_ue_spec_default( dl_dci->has_rb_shift = 1; dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; - dl_dci->ndi = 1;//(uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1; + dl_dci->ndi = 1; + dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = round&3; @@ -952,14 +947,12 @@ schedule_ue_spec_default( dl_dci->n_mcs = 1; dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); dl_dci->mcs[0] = mcs; + dl_dci->n_tbs_size = 1; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; if (frame_parms[CC_id]->frame_type == TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", - mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); - } else { - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", - mod_id, CC_id, harq_pid, round); } if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { @@ -985,7 +978,7 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1; + dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = round&3; @@ -997,11 +990,6 @@ schedule_ue_spec_default( if (frame_parms[CC_id]->frame_type == TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", - mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); - } else { - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", - mod_id, CC_id, harq_pid, round); } dl_dci->has_dl_power_offset = 1; @@ -1011,14 +999,14 @@ schedule_ue_spec_default( break; } // Toggle NDI for next time - //LOG_D(MAC,"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", - // CC_id, frame, subframe, UE_id, - // UE_list->UE_template[CC_id][UE_id].rnti,harq_pid, UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]); - //UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]=1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + LOG_D(MAC,"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", + CC_id, frame, subframe, UE_id, + UE_list->UE_template[CC_id][UE_id].rnti,harq_pid, UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]); + UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]=1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; // Increase the pointer for the number of scheduled UEs num_ues_added++; - } else { // There is no data from RLC or MAC header, so don't schedule + } else { // There is no data from RLC or MAC header, so don't schedule } } @@ -1047,7 +1035,6 @@ void apply_scheduling_decisions(mid_t mod_id, uint8_t CC_id; int UE_id; - uint16_t nCCE[MAX_NUM_CCs]; int N_RBG[MAX_NUM_CCs]; unsigned char aggregation; mac_rlc_status_resp_t rlc_status; @@ -1097,7 +1084,7 @@ void apply_scheduling_decisions(mid_t mod_id, UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); //NOTICE: Maybe later will not be required, once scheduler fully restructured - eNB_dlsch_info[mod_id][CC_id][UE_id].status = S_DL_WAITING; + //eNB_dlsch_info[mod_id][CC_id][UE_id].status = S_DL_WAITING; ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); @@ -1275,6 +1262,7 @@ void apply_scheduling_decisions(mid_t mod_id, ta_len = 0; } } + n_lc = dl_data->n_rlc_pdu; num_sdus = 0; @@ -1282,7 +1270,7 @@ void apply_scheduling_decisions(mid_t mod_id, for (i = 0; i < n_lc; i++) { lcid = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->logical_channel_id; rlc_size = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->size; - + LOG_D(MAC,"[TEST]Have to check %d channels\n", n_lc); if (rlc_size > 0) { rlc_status = mac_rlc_status_ind( mod_id, @@ -1294,11 +1282,13 @@ void apply_scheduling_decisions(mid_t mod_id, lcid, rlc_size); // transport block set size - sdu_lengths[i]=0; + sdu_lengths[i] = 0; LOG_D(MAC,"[eNB %d] Frame %d, LCID %d, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", mod_id, frame, lcid, CC_id, rlc_size); + LOG_D(MAC, "[TEST] Have %d bytes in buffer DCCH during second call\n", rlc_status.bytes_in_buffer); + sdu_lengths[i] += mac_rlc_data_req( mod_id, rnti, @@ -1309,6 +1299,8 @@ void apply_scheduling_decisions(mid_t mod_id, lcid, (char *)&dlsch_buffer[sdu_lengths[i]]); + LOG_D(MAC, "[TEST] This is what I actuallty got %d\n", sdu_lengths[i]); + LOG_D(MAC,"[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n",mod_id, CC_id, sdu_lengths[i]); sdu_length_total += sdu_lengths[i]; sdu_lcids[i] = lcid; @@ -1331,72 +1323,58 @@ void apply_scheduling_decisions(mid_t mod_id, } // SDU creation end - if (header_len_dtch==0) { - header_len_dcch = (header_len_dcch >0) ? 1 : header_len_dcch; // remove length field - } else { - header_len_dtch = (header_len_dtch > 0) ? 1 :header_len_dtch; // remove length field for the last SDU - } + if (((sdu_length_total + header_len_dcch + header_len_dtch) > 0)) { - // there is a payload - if (((sdu_length_total + header_len_dcch + header_len_dtch ) > 0)) { - if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2) { - padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); - post_padding = 0; - } else { - padding = 0; + 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 : header_len_dcch; // remove length field + } else { + header_len_dtch = (header_len_dtch > 0) ? 1 :header_len_dtch; // remove length field for the last SDU + } + + // there is a payload + LOG_D(MAC, "[TEST] This is the padding %d\n", TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); + if (((sdu_length_total + header_len_dcch + header_len_dtch ) > 0)) { + if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2) { + padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); + post_padding = 0; + } else { + padding = 0; - // adjust the header len - if (header_len_dtch==0) { - header_len_dcch = header_len_dcch_tmp; - } else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2))) - header_len_dtch = header_len_dtch_tmp; - } - - post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len ; // 1 is for the postpadding header - } - } - - uint8_t update_TA=4; - - switch (frame_parms[CC_id]->N_RB_DL) { - case 6: - update_TA = 1; - break; - - case 25: - update_TA = 4; - break; - - case 50: - update_TA = 8; - break; - - case 100: - update_TA = 16; - break; - } - - if (ta_len > 0) { - ta_update = eNB_UE_stats->timing_advance_update/update_TA; - } else { - ta_update = 0; - } - /*#else - ta_update = 0; - #endif*/ - - offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], - // offset = generate_dlsch_header((unsigned char*)eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0], - num_sdus, //num_sdus - sdu_lengths, // - sdu_lcids, - 255, // no drx - ta_update, // timing advance - NULL, // contention res id - padding, - post_padding); - - + // adjust the header len + if (header_len_dtch==0) { + header_len_dcch = header_len_dcch_tmp; + } else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2))) + header_len_dtch = header_len_dtch_tmp; + } + + post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len ; // 1 is for the postpadding header + } + } + + LOG_D(MAC, "[TEST] This is the current SDU length %d and this is the TBS %d\n", sdu_length_total, TBS); + + + if (ta_len > 0) { + ta_update = ue_sched_ctl->ta_update; + } else { + ta_update = 0; + } + + offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], + // offset = generate_dlsch_header((unsigned char*)eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0], + num_sdus, //num_sdus + sdu_lengths, // + sdu_lcids, + 255, // no drx + ta_update, // timing advance + NULL, // contention res id + padding, + post_padding); + + #ifdef DEBUG_eNB_SCHEDULER LOG_T(MAC,"[eNB %d] First 16 bytes of DLSCH : \n"); @@ -1428,9 +1406,13 @@ void apply_scheduling_decisions(mid_t mod_id, eNB->eNB_stats[CC_id].dlsch_bytes_tx+=sdu_length_total; eNB->eNB_stats[CC_id].dlsch_pdus_tx+=1; + 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(mod_id, rnti); + 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; + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used = nCCE[CC_id]; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=dl_dci->mcs[0]; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=dl_dci->mcs[0]; UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; @@ -1441,6 +1423,10 @@ void apply_scheduling_decisions(mid_t mod_id, UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus+=1; // TODO + + } + + } else { // No need to create anything apart of DCI in case of retransmission diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 21e9337dbb..f0e0a9f84b 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -59,12 +59,18 @@ //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" +//Agent-related headers +#include "ENB_APP/enb_agent_extern.h" +#include "ENB_APP/enb_agent_mac.h" + #if defined(ENABLE_ITTI) # include "intertask_interface.h" #endif #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 +//#define ENABLE_ENB_AGENT_DL_SCHEDULER + //#define DEBUG_HEADER_PARSING 1 //#define DEBUG_PACKET_TRACE 1 @@ -99,6 +105,8 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, UE_list_t *UE_list=&eNB_mac_inst[module_idP].UE_list; rnti_t rnti; + Protocol__ProgranMessage *msg; + LOG_D(MAC,"[eNB %d] Frame %d, Subframe %d, entering MAC scheduler (UE_list->head %d)\n",module_idP, frameP, subframeP,UE_list->head); start_meas(&eNB_mac_inst[module_idP].eNB_scheduler); @@ -252,10 +260,27 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, (mac_xface->lte_frame_parms->tdd_config == 6)) { //schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,4);//,calibration_flag); } - +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); - +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif break; case 1: @@ -267,12 +292,16 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 0: case 1: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,7); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#endif break; case 6: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,8); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#endif break; default: @@ -280,8 +309,27 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD schedule_ulsch(module_idP,frameP,cooperation_flag,1,5); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif } break; @@ -292,8 +340,27 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // FDD, normal UL/DLSCH if (mac_xface->lte_frame_parms->frame_type == FDD) { //FDD schedule_ulsch(module_idP,frameP,cooperation_flag,2,6); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif } break; @@ -310,8 +377,27 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // no break here! case 5: +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif break; default: @@ -320,8 +406,27 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } else { //FDD schedule_ulsch(module_idP,frameP,cooperation_flag,3,7); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif } break; @@ -345,9 +450,27 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // no break here! case 5: - +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); - fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); + fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif break; default: @@ -358,8 +481,27 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // schedule_RA(module_idP,frameP, subframeP, 0); schedule_ulsch(module_idP, frameP, cooperation_flag, 4, 8); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP, frameP, subframeP, mbsfn_status); fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif } } @@ -376,15 +518,55 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, if (mac_xface->lte_frame_parms->frame_type == FDD) { schedule_RA(module_idP,frameP,subframeP,1); schedule_ulsch(module_idP,frameP,cooperation_flag,5,9); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP, frameP, subframeP, mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif } else if ((mac_xface->lte_frame_parms->tdd_config == 0) || // TDD Config 0 (mac_xface->lte_frame_parms->tdd_config == 6)) { // TDD Config 6 //schedule_ulsch(module_idP,cooperation_flag,subframeP); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#endif } else { +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif } break; @@ -402,25 +584,67 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 1: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,2); // schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#endif break; case 6: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3); // schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#endif break; case 5: schedule_RA(module_idP,frameP,subframeP,2); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif break; case 3: case 4: +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif break; default: @@ -428,8 +652,27 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD // schedule_ulsch(module_idP,frameP,cooperation_flag,6,0); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif } break; @@ -443,13 +686,51 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 3: case 4: schedule_RA(module_idP,frameP,subframeP,3); // 3 = Msg3 subframeP, not +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif break; case 5: +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif break; default: @@ -457,8 +738,27 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD //schedule_ulsch(module_idP,frameP,cooperation_flag,7,1); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif } break; @@ -477,8 +777,27 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // schedule_RA(module_idP,subframeP); schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,2); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif break; default: @@ -486,8 +805,27 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD //schedule_ulsch(module_idP,frameP,cooperation_flag,8,2); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif } break; @@ -500,29 +838,105 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 1: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3); schedule_RA(module_idP,frameP,subframeP,7); // 7 = Msg3 subframeP, not +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif break; case 3: case 4: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif break; case 6: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,4); //schedule_RA(module_idP,frameP,subframeP); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif break; case 2: case 5: //schedule_RA(module_idP,frameP,subframeP); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif break; default: @@ -530,8 +944,27 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD // schedule_ulsch(module_idP,frameP,cooperation_flag,9,3); +#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); +#else + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + + apply_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } +#endif } break; diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index c522d5920e..faf0bf9954 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -135,7 +135,6 @@ void schedule_ue_spec(module_id_t module_idP,frame_t frameP,sub_frame_t subframe //To be used by the agent void schedule_ue_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, - unsigned int *nb_rb_used, unsigned int *nCCE_used, int *mbsfn_flag, Protocol__ProgranMessage *dl_info); /** \brief Function for UE/PHY to compute PUSCH transmit power in power-control procedure. From 07edce1712e61db5e8d72c908feb59745ad4653c Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 2 Feb 2016 16:39:39 +0000 Subject: [PATCH 081/413] Changes to the progran default scheduler --- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 264 +++++++++--------- openair2/LAYER2/MAC/eNB_scheduler.c | 2 +- 2 files changed, 133 insertions(+), 133 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index a4fbac6de2..fcf866d657 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -115,6 +115,7 @@ schedule_ue_spec_default( Protocol__PrpDlData *dl_data[NUM_MAX_UE]; int num_ues_added = 0; + int channels_added = 0; Protocol__PrpDlDci *dl_dci; Protocol__PrpRlcPdu *rlc_pdus[11]; @@ -237,11 +238,6 @@ schedule_ue_spec_default( harq_pid = ue_sched_ctl->harq_pid[CC_id]; round = ue_sched_ctl->round[CC_id]; - /* TODO: Must add these stats (probably in the apply_scheduling function) */ - //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(mod_id, rnti); - //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; @@ -363,10 +359,10 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 0; + dl_dci->ndi[0] = 1; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round&3; + dl_dci->rv[0] = (round+1) % 4; if (frame_parms[CC_id]->frame_type == TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; @@ -401,8 +397,8 @@ schedule_ue_spec_default( dl_dci->ndi[1] = 0; dl_dci->n_rv = 2; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round&3; - dl_dci->rv[1] = round&3; + dl_dci->rv[0] = (round+1) % 4; + dl_dci->rv[1] = (round+1) % 4; if (frame_parms[CC_id]->frame_type == TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; @@ -437,7 +433,7 @@ schedule_ue_spec_default( dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round&3; + dl_dci->rv[0] = (round + 1) % 4; if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { ue_sched_ctl->dl_pow_off[CC_id] = 1; @@ -471,28 +467,12 @@ schedule_ue_spec_default( dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round&3; + dl_dci->rv[0] = (round + 1) % 4; dl_dci->has_dl_power_offset = 1; dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; break; } - - /*We now probably don't need this*/ - /* add_ue_dlsch_info(mod_id, */ - /* CC_id, */ - /* UE_id, */ - /* subframe, */ - /* S_DL_SCHEDULED); */ - - //eNB_UE_stats->dlsch_trials[round]++; - //UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; - //UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; - //UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; - //UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx=nCCECC_id]; - //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1; - //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=eNB_UE_stats->dlsch_mcs1; - num_ues_added += 1; } else { LOG_D(MAC,"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", @@ -529,6 +509,7 @@ schedule_ue_spec_default( header_len_dcch = 2; // 2 bytes DCCH SDU subheader // Need to see if we have space for data from this channel + if ( TBS-ta_len-header_len_dcch > 0 ) { //If we have space, we need to see how much data we can request at most (if any available) @@ -543,26 +524,28 @@ schedule_ue_spec_default( //If data are available in the DCCH if (rlc_status.bytes_in_buffer > 0) { - LOG_D(MAC, "[TEST]Have %d bytes in buffer DCCH during first call\n", rlc_status.bytes_in_buffer); + LOG_D(MAC, "[TEST]Have %d bytes in buffer during first call\n", rlc_status.bytes_in_buffer); //Fill in as much as possible data_to_request = cmin(dci_tbs-ta_len-header_len_dcch, rlc_status.bytes_in_buffer) + 1; LOG_D(MAC, "[TEST]Will request %d \n", data_to_request); - rlc_pdus[0] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); - protocol__prp_rlc_pdu__init(rlc_pdus[0]); - rlc_pdus[0]->n_rlc_pdu_tb = 2; - rlc_pdus[0]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); - rlc_pdus[0]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - rlc_pdus[0]->rlc_pdu_tb[0]->has_logical_channel_id = 1; - rlc_pdus[0]->rlc_pdu_tb[0]->logical_channel_id = DCCH; - rlc_pdus[0]->rlc_pdu_tb[0]->has_size = 1; - rlc_pdus[0]->rlc_pdu_tb[0]->size = data_to_request; - rlc_pdus[0]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - rlc_pdus[0]->rlc_pdu_tb[1]->has_logical_channel_id = 1; - rlc_pdus[0]->rlc_pdu_tb[1]->logical_channel_id = DCCH; - rlc_pdus[0]->rlc_pdu_tb[1]->has_size = 1; - rlc_pdus[0]->rlc_pdu_tb[1]->size = data_to_request; + rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); + protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]); + rlc_pdus[channels_added]->n_rlc_pdu_tb = 2; + rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); + rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]); + rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_logical_channel_id = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[0]->logical_channel_id = DCCH; + rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_size = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = data_to_request; + rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]); + rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_logical_channel_id = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[1]->logical_channel_id = DCCH; + rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_size = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[1]->size = data_to_request; dl_data[num_ues_added]->n_rlc_pdu++; - + channels_added++; //Set this to the max value that we might request sdu_length_total = data_to_request; } else { @@ -572,7 +555,7 @@ schedule_ue_spec_default( } // check for DCCH1 and update header information (assume 2 byte sub-header) - if (dci_tbs-ta_len-header_len_dcch-sdu_length_total > 0 ) { + if (dci_tbs-ta_len-header_len_dcch-sdu_length_total-2 > 0 ) { //If we have space, we need to see how much data we can request at most (if any are available) rlc_status = mac_rlc_status_ind(mod_id, @@ -581,33 +564,36 @@ schedule_ue_spec_default( frame, ENB_FLAG_YES, MBMS_FLAG_NO, - DCCH+1, - (dci_tbs-ta_len-header_len_dcch-sdu_length_total)); // transport block set size less allocations for timing advance and + DCCH1, + (dci_tbs-ta_len-header_len_dcch-sdu_length_total-2)); // transport block set size less allocations for timing advance and // DCCH SDU // If data are available in DCCH1 if (rlc_status.bytes_in_buffer > 0) { + //Add this subheader header_len_dcch += 2; //Fill in as much as possible data_to_request = cmin(dci_tbs-ta_len-header_len_dcch-sdu_length_total, rlc_status.bytes_in_buffer) + 1; - rlc_pdus[1] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); - protocol__prp_rlc_pdu__init(rlc_pdus[1]); - rlc_pdus[1]->n_rlc_pdu_tb = 2; - rlc_pdus[1]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); - rlc_pdus[1]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - rlc_pdus[1]->rlc_pdu_tb[0]->has_logical_channel_id = 1; - rlc_pdus[1]->rlc_pdu_tb[0]->logical_channel_id = DCCH+1; - rlc_pdus[1]->rlc_pdu_tb[0]->has_size = 1; - rlc_pdus[1]->rlc_pdu_tb[0]->size = data_to_request; - rlc_pdus[1]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - rlc_pdus[1]->rlc_pdu_tb[1]->has_logical_channel_id = 1; - rlc_pdus[1]->rlc_pdu_tb[1]->logical_channel_id = DCCH+1; - rlc_pdus[1]->rlc_pdu_tb[1]->has_size = 1; - rlc_pdus[1]->rlc_pdu_tb[1]->size = data_to_request; + rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); + protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]); + rlc_pdus[channels_added]->n_rlc_pdu_tb = 2; + rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); + rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]); + rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_logical_channel_id = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[0]->logical_channel_id = DCCH1; + rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_size = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = data_to_request; + rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]); + rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_logical_channel_id = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[1]->logical_channel_id = DCCH1; + rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_size = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[1]->size = data_to_request; dl_data[num_ues_added]->n_rlc_pdu++; - + channels_added++; sdu_length_total += data_to_request; } } @@ -615,7 +601,7 @@ schedule_ue_spec_default( // check for DTCH and update header information // here we should loop over all possible DTCH - header_len_dtch = 3; // 3 bytes DTCH SDU subheader + header_len_dtch = 3; // Assume max 3 bytes DTCH SDU subheader LOG_D(MAC,"[eNB %d], Frame %d, DTCH->DLSCH, CC_id %d, Checking RLC status (rab %d, tbs %d, len %d)\n", mod_id, frame, CC_id, DTCH, TBS, @@ -623,6 +609,8 @@ schedule_ue_spec_default( if (dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch > 0 ) { + LOG_D(MAC, "[TEST] This is how much we request at most during first call %d\n", dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); + //If we have space, we need to see how much data we can request at most (if any are available) rlc_status = mac_rlc_status_ind(mod_id, rnti, @@ -639,33 +627,34 @@ schedule_ue_spec_default( //Fill what remains in the TB data_to_request = cmin(dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch, rlc_status.bytes_in_buffer) + 1; LOG_D(MAC, "[TEST]Will request %d \n", data_to_request); - rlc_pdus[2] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); - protocol__prp_rlc_pdu__init(rlc_pdus[2]); - rlc_pdus[2]->n_rlc_pdu_tb = 2; - rlc_pdus[2]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); - rlc_pdus[2]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - rlc_pdus[2]->rlc_pdu_tb[0]->has_logical_channel_id = 1; - rlc_pdus[2]->rlc_pdu_tb[0]->logical_channel_id = DTCH; - rlc_pdus[2]->rlc_pdu_tb[0]->has_size = 1; - rlc_pdus[2]->rlc_pdu_tb[0]->size = data_to_request; - rlc_pdus[2]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - rlc_pdus[2]->rlc_pdu_tb[1]->has_logical_channel_id = 1; - rlc_pdus[2]->rlc_pdu_tb[1]->logical_channel_id = DTCH; - rlc_pdus[2]->rlc_pdu_tb[1]->has_size = 1; - rlc_pdus[2]->rlc_pdu_tb[1]->size = data_to_request; + rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); + protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]); + rlc_pdus[channels_added]->n_rlc_pdu_tb = 2; + rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); + rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]); + rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_logical_channel_id = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[0]->logical_channel_id = DTCH; + rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_size = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = data_to_request; + rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]); + rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_logical_channel_id = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[1]->logical_channel_id = DTCH; + rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_size = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[1]->size = data_to_request; dl_data[num_ues_added]->n_rlc_pdu++; - + channels_added++; sdu_length_total += data_to_request; if(data_to_request < 128) { header_len_dtch = 2; } - } else { - header_len_dtch = 3; + header_len_dtch = 0; } } - + // Add rlc_pdus to the dl_data message dl_data[num_ues_added]->rlc_pdu = (Protocol__PrpRlcPdu **) malloc(sizeof(Protocol__PrpRlcPdu *) * dl_data[num_ues_added]->n_rlc_pdu); @@ -674,7 +663,7 @@ schedule_ue_spec_default( } // there is a payload - if (((sdu_length_total + header_len_dcch + header_len_dtch) > 0)) { + if (( dl_data[num_ues_added]->n_rlc_pdu > 0)) { // Now compute number of required RBs for total sdu length // Assume RAH format 2 // adjust header lengths @@ -682,15 +671,12 @@ schedule_ue_spec_default( header_len_dtch_tmp = header_len_dtch; if (header_len_dtch == 0) { - header_len_dcch = (header_len_dcch > 0) ? 1 : header_len_dcch; // remove length field + header_len_dcch = (header_len_dcch > 0) ? (header_len_dcch - 1) : header_len_dcch; // remove length field } else { header_len_dtch = (header_len_dtch > 0) ? 1 : header_len_dtch; // remove length field for the last SDU } mcs_tmp = mcs; - - // TODO: Need to compute this and not take it from the stats - // mcs = eNB_UE_stats->dlsch_mcs1; if (mcs_tmp == 0) { nb_rb = 4; // don't let the TBS get too small @@ -757,7 +743,7 @@ schedule_ue_spec_default( TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); } - LOG_D(MAC,"dlsch_mcs and TBS before and after the rate matching = (%d, %d) (%d, %d)\n", mcs, mcs_tmp, dci_tbs, TBS); + LOG_D(MAC,"[TEST] dlsch_mcs and TBS before and after the rate matching = (%d, %d) (%d, %d)\n", mcs, mcs_tmp, dci_tbs, TBS); dci_tbs = TBS; @@ -840,8 +826,8 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->n_rv = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->ndi[0] = 1; + dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = 0; dl_dci->has_tpc = 1; @@ -870,8 +856,8 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 2; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];; - dl_dci->ndi[1] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];; + dl_dci->ndi[0] = 1; + dl_dci->ndi[1] = 1; dl_dci->n_rv = 2; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = 0; @@ -904,8 +890,8 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 2; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];; - dl_dci->ndi[1] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];; + dl_dci->ndi[0] = 1; + dl_dci->ndi[1] = 1; dl_dci->n_rv = 2; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = 0; @@ -938,10 +924,10 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; dl_dci->ndi = 1; - dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];; + dl_dci->ndi[0] = 1; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round&3; + dl_dci->rv[0] = 0; dl_dci->has_tpc = 1; dl_dci->tpc = tpc; dl_dci->n_mcs = 1; @@ -978,7 +964,7 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];; + dl_dci->ndi[0] = 1; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = round&3; @@ -1106,7 +1092,7 @@ void apply_scheduling_decisions(mid_t mod_id, ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rv = round; ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; @@ -1122,7 +1108,7 @@ void apply_scheduling_decisions(mid_t mod_id, ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rv = round; ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; @@ -1142,7 +1128,7 @@ void apply_scheduling_decisions(mid_t mod_id, ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rv = round; ((DCI1_5MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; ((DCI1_5MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; ((DCI1_5MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; ((DCI1_5MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; @@ -1157,10 +1143,8 @@ void apply_scheduling_decisions(mid_t mod_id, if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { ((DCI1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rv = round; - if (dl_dci->has_rb_bitmap) { - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - } - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; ((DCI1_5MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; ((DCI1_5MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; ((DCI1_5MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; @@ -1180,7 +1164,7 @@ void apply_scheduling_decisions(mid_t mod_id, ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rv = round; ((DCI1_10MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; ((DCI1_10MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; ((DCI1_10MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; ((DCI1_10MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; @@ -1196,7 +1180,7 @@ void apply_scheduling_decisions(mid_t mod_id, ((DCI1_10MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rv = round; ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; ((DCI1_10MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; ((DCI1_10MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; ((DCI1_10MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; @@ -1216,7 +1200,7 @@ void apply_scheduling_decisions(mid_t mod_id, ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rv = round; ((DCI1_20MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; ((DCI1_20MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; ((DCI1_20MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; ((DCI1_20MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; @@ -1232,7 +1216,7 @@ void apply_scheduling_decisions(mid_t mod_id, ((DCI1_20MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rv = round; ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->rb_shift; + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; ((DCI1_20MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; ((DCI1_20MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; ((DCI1_20MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; @@ -1266,14 +1250,17 @@ void apply_scheduling_decisions(mid_t mod_id, n_lc = dl_data->n_rlc_pdu; num_sdus = 0; + sdu_length_total = 0; // Go through each one of the channel commands and create SDUs for (i = 0; i < n_lc; i++) { lcid = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->logical_channel_id; rlc_size = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->size; LOG_D(MAC,"[TEST]Have to check %d channels\n", n_lc); if (rlc_size > 0) { - rlc_status = mac_rlc_status_ind( - mod_id, + if (lcid == 3) { + rlc_size--; + } + rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, @@ -1287,25 +1274,27 @@ void apply_scheduling_decisions(mid_t mod_id, LOG_D(MAC,"[eNB %d] Frame %d, LCID %d, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", mod_id, frame, lcid, CC_id, rlc_size); - LOG_D(MAC, "[TEST] Have %d bytes in buffer DCCH during second call\n", rlc_status.bytes_in_buffer); + LOG_D(MAC, "[TEST] Have %d bytes for LCID %d during second call\n", rlc_status.bytes_in_buffer, lcid); - sdu_lengths[i] += mac_rlc_data_req( - mod_id, + sdu_lengths[i] += mac_rlc_data_req(mod_id, rnti, mod_id, frame, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, - (char *)&dlsch_buffer[sdu_lengths[i]]); + (char *)&dlsch_buffer[sdu_lengths[sdu_length_total]]); - LOG_D(MAC, "[TEST] This is what I actuallty got %d\n", sdu_lengths[i]); + LOG_D(MAC, "[TEST] This is what I actually got from LCID %d -> %d\n",lcid, sdu_lengths[i]); - LOG_D(MAC,"[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n",mod_id, CC_id, sdu_lengths[i]); + LOG_D(MAC,"[eNB %d][LCID %d] CC_id %d Got %d bytes from RLC\n",mod_id, lcid, CC_id, sdu_lengths[i]); sdu_length_total += sdu_lengths[i]; sdu_lcids[i] = lcid; - if (lcid == DCCH || lcid == DCCH+1) { + 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[i]; + + if (lcid == DCCH || lcid == DCCH1) { header_len_dcch += 2; } else if (lcid == DTCH) { if (sdu_lengths[i] < 128) { @@ -1313,12 +1302,8 @@ void apply_scheduling_decisions(mid_t mod_id, } else { header_len_dtch = 3; } - } - - UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH] += 1; - UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH] += sdu_lengths[i]; + } num_sdus++; - } } // SDU creation end @@ -1329,15 +1314,16 @@ void apply_scheduling_decisions(mid_t mod_id, header_len_dtch_tmp = header_len_dtch; if (header_len_dtch==0) { - header_len_dcch = (header_len_dcch >0) ? 1 : header_len_dcch; // remove length field + header_len_dcch = (header_len_dcch >0) ? (header_len_dcch - 1) : header_len_dcch; // remove length field } else { - header_len_dtch = (header_len_dtch > 0) ? 1 :header_len_dtch; // remove length field for the last SDU + header_len_dtch = (header_len_dtch > 0) ? 1 : header_len_dtch; // remove length field for the last SDU } // there is a payload LOG_D(MAC, "[TEST] This is the padding %d\n", TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); if (((sdu_length_total + header_len_dcch + header_len_dtch ) > 0)) { - if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2) { + if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2 + || (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) > TBS) { //protect from overflow padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); post_padding = 0; } else { @@ -1345,18 +1331,19 @@ void apply_scheduling_decisions(mid_t mod_id, // adjust the header len if (header_len_dtch==0) { - header_len_dcch = header_len_dcch_tmp; - } else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2))) - header_len_dtch = header_len_dtch_tmp; + header_len_dcch = header_len_dcch_tmp; + } else { + header_len_dtch = header_len_dtch_tmp; } - post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len ; // 1 is for the postpadding header + post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len - 1; // 1 is for the postpadding header } } LOG_D(MAC, "[TEST] This is the current SDU length %d and this is the TBS %d\n", sdu_length_total, TBS); + if (ta_len > 0) { ta_update = ue_sched_ctl->ta_update; } else { @@ -1373,7 +1360,8 @@ void apply_scheduling_decisions(mid_t mod_id, NULL, // contention res id padding, post_padding); - + + LOG_D(MAC, "[TEST]Have to schedule %d SDUs with length %d. TBS is %d, LCID is %d, post padding is %d, padding is %d, header offset is %d, total sdu size is %d\n", num_sdus, sdu_lengths[0], TBS, sdu_lcids[0], post_padding, padding, offset, sdu_length_total); #ifdef DEBUG_eNB_SCHEDULER LOG_T(MAC,"[eNB %d] First 16 bytes of DLSCH : \n"); @@ -1411,8 +1399,8 @@ void apply_scheduling_decisions(mid_t mod_id, 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; - UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; + //UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; + //UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=dl_dci->mcs[0]; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=dl_dci->mcs[0]; UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; @@ -1421,6 +1409,9 @@ void apply_scheduling_decisions(mid_t mod_id, UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes+= sdu_length_total; UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes+= TBS; UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus+=1; + + eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; + eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); // TODO @@ -1430,6 +1421,15 @@ void apply_scheduling_decisions(mid_t mod_id, } else { // No need to create anything apart of DCI in case of retransmission + + /*TODO: Must add these */ + //eNB_UE_stats->dlsch_trials[round]++; + //UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; + //UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; + //UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; + //UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx=nCCECC_id]; + //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1; + //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=eNB_UE_stats->dlsch_mcs1; } //Add DCI based on format @@ -1438,7 +1438,7 @@ void apply_scheduling_decisions(mid_t mod_id, DLSCH_dci, rnti, size_bytes, - process_ue_cqi (mod_id, UE_id),//aggregation + dl_dci->aggr_level,//aggregation size_bits, format1, 0); @@ -1447,7 +1447,7 @@ void apply_scheduling_decisions(mid_t mod_id, DLSCH_dci, rnti, size_bytes, - process_ue_cqi (mod_id, UE_id),//aggregation + dl_dci->aggr_level,//aggregation size_bits, format2A, 0); diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index f0e0a9f84b..caf7457fea 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -69,7 +69,7 @@ #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 -//#define ENABLE_ENB_AGENT_DL_SCHEDULER +#define ENABLE_ENB_AGENT_DL_SCHEDULER //#define DEBUG_HEADER_PARSING 1 //#define DEBUG_PACKET_TRACE 1 From a8cd23944f2b3deec8b3d6e586e3588c16adab03 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 2 Feb 2016 19:18:42 +0000 Subject: [PATCH 082/413] Progran scheduler fixes --- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index fcf866d657..0b6157932f 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -487,6 +487,8 @@ schedule_ue_spec_default( //TBS = mac_xface->get_TBS(eNB_UE_stats->DL_cqi[0]<<1,nb_available_rb); TBS = mac_xface->get_TBS_DL(mcs, nb_available_rb); dci_tbs = TBS; + + // check first for RLC data on DCCH // add the length for all the control elements (timing adv, drx, etc) : header + payload @@ -511,7 +513,8 @@ schedule_ue_spec_default( // Need to see if we have space for data from this channel if ( TBS-ta_len-header_len_dcch > 0 ) { - + LOG_D(MAC, "[TEST]Requested %d bytes in DCCH buffer during first call\n", dci_tbs-ta_len-header_len_dcch); + LOG_D(MAC, "DCCH dci_tbus is %d\n", dci_tbs); //If we have space, we need to see how much data we can request at most (if any available) rlc_status = mac_rlc_status_ind(mod_id, rnti, @@ -524,10 +527,10 @@ schedule_ue_spec_default( //If data are available in the DCCH if (rlc_status.bytes_in_buffer > 0) { - LOG_D(MAC, "[TEST]Have %d bytes in buffer during first call\n", rlc_status.bytes_in_buffer); + LOG_D(MAC, "[TEST]Have %d bytes in DCCH buffer during first call\n", rlc_status.bytes_in_buffer); //Fill in as much as possible data_to_request = cmin(dci_tbs-ta_len-header_len_dcch, rlc_status.bytes_in_buffer) + 1; - LOG_D(MAC, "[TEST]Will request %d \n", data_to_request); + LOG_D(MAC, "[TEST]Will request %d from DCCH\n", data_to_request); rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]); rlc_pdus[channels_added]->n_rlc_pdu_tb = 2; @@ -1257,9 +1260,6 @@ void apply_scheduling_decisions(mid_t mod_id, rlc_size = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->size; LOG_D(MAC,"[TEST]Have to check %d channels\n", n_lc); if (rlc_size > 0) { - if (lcid == 3) { - rlc_size--; - } rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, @@ -1283,7 +1283,7 @@ void apply_scheduling_decisions(mid_t mod_id, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, - (char *)&dlsch_buffer[sdu_lengths[sdu_length_total]]); + (char *)&dlsch_buffer[sdu_length_total]); LOG_D(MAC, "[TEST] This is what I actually got from LCID %d -> %d\n",lcid, sdu_lengths[i]); @@ -1302,7 +1302,8 @@ void apply_scheduling_decisions(mid_t mod_id, } else { header_len_dtch = 3; } - } + } + num_sdus++; } } // SDU creation end From fd09bd61bfed2ed92fc4273da79a2a7302aa1477 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 3 Feb 2016 14:27:17 +0000 Subject: [PATCH 083/413] Fixed bug with NDI toggling --- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 63 ++++++++++++------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index 0b6157932f..f31ed2bf86 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -249,6 +249,8 @@ schedule_ue_spec_default( */ mcs = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; + mcs = cmin(mcs, openair_daq_vars.target_ue_dl_mcs); + /*TODO: Must also update these stats*/ //eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; @@ -514,7 +516,6 @@ schedule_ue_spec_default( if ( TBS-ta_len-header_len_dcch > 0 ) { LOG_D(MAC, "[TEST]Requested %d bytes in DCCH buffer during first call\n", dci_tbs-ta_len-header_len_dcch); - LOG_D(MAC, "DCCH dci_tbus is %d\n", dci_tbs); //If we have space, we need to see how much data we can request at most (if any available) rlc_status = mac_rlc_status_ind(mod_id, rnti, @@ -552,6 +553,7 @@ schedule_ue_spec_default( //Set this to the max value that we might request sdu_length_total = data_to_request; } else { + LOG_D(MAC, "[TEST]Nothing here\n"); header_len_dcch = 0; sdu_length_total = 0; } @@ -559,6 +561,7 @@ schedule_ue_spec_default( // check for DCCH1 and update header information (assume 2 byte sub-header) if (dci_tbs-ta_len-header_len_dcch-sdu_length_total-2 > 0 ) { + LOG_D(MAC, "[TEST]Requested %d bytes in DCCH1 buffer during first call\n", dci_tbs-ta_len-header_len_dcch-sdu_length_total-2); //If we have space, we need to see how much data we can request at most (if any are available) rlc_status = mac_rlc_status_ind(mod_id, @@ -577,7 +580,7 @@ schedule_ue_spec_default( header_len_dcch += 2; //Fill in as much as possible - data_to_request = cmin(dci_tbs-ta_len-header_len_dcch-sdu_length_total, rlc_status.bytes_in_buffer) + 1; + data_to_request = cmin(dci_tbs-ta_len-header_len_dcch-sdu_length_total, rlc_status.bytes_in_buffer); rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]); @@ -628,7 +631,7 @@ schedule_ue_spec_default( if (rlc_status.bytes_in_buffer > 0) { LOG_D(MAC, "[TEST] Have %d bytes in buffer DTCH during first call\n", rlc_status.bytes_in_buffer); //Fill what remains in the TB - data_to_request = cmin(dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch, rlc_status.bytes_in_buffer) + 1; + data_to_request = cmin(dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch, rlc_status.bytes_in_buffer); LOG_D(MAC, "[TEST]Will request %d \n", data_to_request); rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]); @@ -687,11 +690,15 @@ schedule_ue_spec_default( nb_rb=min_rb_unit[CC_id]; } + LOG_D(MAC,"[TEST]The initial number of resource blocks was %d\n", nb_rb); + LOG_D(MAC,"[TEST] The initial mcs was %d\n", mcs_tmp); + TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); + LOG_D(MAC,"[TEST]The TBS during rate matching was %d\n", TBS); while (TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) { nb_rb += min_rb_unit[CC_id]; // - + LOG_D(MAC, "[TEST]Had to increase the number of RBs\n"); if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs // (can happen if N_RB_DL is odd) TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_available_rb); @@ -702,14 +709,18 @@ schedule_ue_spec_default( TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); } + LOG_D(MAC,"[TEST] After the first pass the resource blocks became %d\n", nb_rb); + LOG_D(MAC,"[TEST] After the first pass the MCS was %d\n", mcs_tmp); + if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { + LOG_D(MAC, "[TEST]We had the exact number of rbs. Time to fill the rballoc subband\n"); for(j = 0; j < frame_parms[CC_id]->N_RBG; j++) { // for indicating the rballoc for each sub-band UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; } } else { nb_rb_temp = nb_rb; j = 0; - + LOG_D(MAC, "[TEST]Will only partially fill the bitmap\n"); while((nb_rb_temp > 0) && (j < frame_parms[CC_id]->N_RBG)) { if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; @@ -726,6 +737,9 @@ schedule_ue_spec_default( } } + LOG_D(MAC,"[TEST] After the second pass the resource blocks became %d\n", nb_rb); + LOG_D(MAC,"[TEST] After the second pass the mcs was %d\n", mcs_tmp); + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; @@ -829,7 +843,7 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1; + dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = 0; @@ -987,6 +1001,7 @@ schedule_ue_spec_default( dl_dci->precoding_info = 5; // Is this right?? break; } + // Toggle NDI for next time LOG_D(MAC,"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", CC_id, frame, subframe, UE_id, @@ -998,12 +1013,12 @@ schedule_ue_spec_default( } else { // There is no data from RLC or MAC header, so don't schedule } - } + } if (frame_parms[CC_id]->frame_type == TDD) { set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe, frame_parms); } - } - } + } // UE_id loop + } // CC_id loop // Add all the dl_data elements to the progran message dl_info->dl_mac_config_msg->n_dl_ue_data = num_ues_added; @@ -1072,9 +1087,6 @@ void apply_scheduling_decisions(mid_t mod_id, rnti = dl_data->rnti; UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); - //NOTICE: Maybe later will not be required, once scheduler fully restructured - //eNB_dlsch_info[mod_id][CC_id][UE_id].status = S_DL_WAITING; - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); @@ -1108,6 +1120,7 @@ void apply_scheduling_decisions(mid_t mod_id, } } else { if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + LOG_D(MAC,"[TEST] Setting DCI format 1\n"); ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rv = round; ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; @@ -1240,13 +1253,16 @@ void apply_scheduling_decisions(mid_t mod_id, rlc_status.bytes_in_buffer = 0; TBS = dl_dci->tbs_size[0]; + LOG_D(MAC,"[TEST] The TBS during the creation process is %d\n", TBS); if (dl_data->n_ce_bitmap > 0) { //Check if there is TA command if (dl_data->ce_bitmap[0] & PROTOCOL__PRP_CE_TYPE__PRPCET_TA) { ta_len = 2; + LOG_D(MAC, "[TEST] Need to send timing advance\n"); } else { ta_len = 0; + LOG_D(MAC, "[TEST] No timing advance\n"); } } @@ -1257,9 +1273,12 @@ void apply_scheduling_decisions(mid_t mod_id, // Go through each one of the channel commands and create SDUs for (i = 0; i < n_lc; i++) { lcid = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->logical_channel_id; + LOG_D(MAC, "[TEST] Going through SDU of channel %d\n", lcid); rlc_size = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->size; - LOG_D(MAC,"[TEST]Have to check %d channels\n", n_lc); + LOG_D(MAC,"[TEST] [eNB %d] Frame %d, LCID %d, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", + mod_id, frame, lcid, CC_id, rlc_size); if (rlc_size > 0) { + rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, @@ -1271,10 +1290,7 @@ void apply_scheduling_decisions(mid_t mod_id, sdu_lengths[i] = 0; - LOG_D(MAC,"[eNB %d] Frame %d, LCID %d, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", - mod_id, frame, lcid, CC_id, rlc_size); - - LOG_D(MAC, "[TEST] Have %d bytes for LCID %d during second call\n", rlc_status.bytes_in_buffer, lcid); + LOG_D(MAC, "[TEST] RLC can give %d bytes for LCID %d during second call\n", rlc_status.bytes_in_buffer, lcid); sdu_lengths[i] += mac_rlc_data_req(mod_id, rnti, @@ -1285,10 +1301,11 @@ void apply_scheduling_decisions(mid_t mod_id, lcid, (char *)&dlsch_buffer[sdu_length_total]); - LOG_D(MAC, "[TEST] This is what I actually got from LCID %d -> %d\n",lcid, sdu_lengths[i]); + LOG_D(MAC, "[TEST] RLC gave %d bytes in LCID %d\n", sdu_lengths[i], lcid); LOG_D(MAC,"[eNB %d][LCID %d] CC_id %d Got %d bytes from RLC\n",mod_id, lcid, CC_id, sdu_lengths[i]); sdu_length_total += sdu_lengths[i]; + LOG_D(MAC, "[TEST] Total sdu size became %d\n", sdu_length_total); sdu_lcids[i] = lcid; UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid] += 1; @@ -1321,7 +1338,6 @@ void apply_scheduling_decisions(mid_t mod_id, } // there is a payload - LOG_D(MAC, "[TEST] This is the padding %d\n", TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); if (((sdu_length_total + header_len_dcch + header_len_dtch ) > 0)) { if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2 || (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) > TBS) { //protect from overflow @@ -1341,9 +1357,6 @@ void apply_scheduling_decisions(mid_t mod_id, } } - LOG_D(MAC, "[TEST] This is the current SDU length %d and this is the TBS %d\n", sdu_length_total, TBS); - - if (ta_len > 0) { ta_update = ue_sched_ctl->ta_update; @@ -1400,8 +1413,10 @@ void apply_scheduling_decisions(mid_t mod_id, 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; - //UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; - //UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; + nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + LOG_D(MAC,"[TEST] %d Number of resource blocks allocated\n", nb_rb); + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=dl_dci->mcs[0]; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=dl_dci->mcs[0]; UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; From 3d3c0c7c03d6ed06c37ec4ca86891fa5372a1d76 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 3 Feb 2016 15:39:51 +0000 Subject: [PATCH 084/413] Bug fixes for UE retransmission --- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 79 ++++++++++++------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index f31ed2bf86..b97c15c9f5 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -251,12 +251,6 @@ schedule_ue_spec_default( mcs = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; mcs = cmin(mcs, openair_daq_vars.target_ue_dl_mcs); - - /*TODO: Must also update these stats*/ - //eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; - //eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); - - #ifdef EXMIMO if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)==5) { @@ -293,6 +287,13 @@ schedule_ue_spec_default( if (round > 0) { + mcs = UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1; + + // get freq_allocation + nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + + dci_tbs = mac_xface->get_TBS_DL(mcs, nb_rb); + if (frame_parms[CC_id]->frame_type == TDD) { UE_list->UE_template[CC_id][UE_id].DAI++; update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); @@ -300,8 +301,7 @@ schedule_ue_spec_default( CC_id, subframe,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); } - // get freq_allocation - nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + if (nb_rb <= nb_available_rb) { @@ -348,7 +348,6 @@ schedule_ue_spec_default( dl_dci->n_mcs = 1; dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t)); dl_dci->mcs[0] = mcs; - //TODO:Need to fix tpc for retransmissions dl_dci->has_tpc = 1; dl_dci->tpc = 1; dl_dci->has_vrb_format = 1; @@ -359,12 +358,18 @@ schedule_ue_spec_default( dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, UE_list->UE_template[CC_id][UE_id].rballoc_subband); dl_dci->has_rb_shift = 1; dl_dci->rb_shift = 0; - dl_dci->n_ndi = 1; + dl_dci->n_ndi = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); dl_dci->ndi[0] = 1; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = (round+1) % 4; + dl_dci->rv[0] = round&3; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->n_tbs_size = 1; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; if (frame_parms[CC_id]->frame_type == TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; @@ -382,7 +387,6 @@ schedule_ue_spec_default( dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t) * dl_dci->n_mcs); dl_dci->mcs[0] = mcs; dl_dci->mcs[1] = mcs; - //TODO:Need to fix tpc for retransmissions dl_dci->has_tpc = 1; dl_dci->tpc = 1; dl_dci->has_vrb_format = 1; @@ -395,12 +399,19 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 2; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 0; - dl_dci->ndi[1] = 0; + dl_dci->ndi[0] = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->ndi[1] = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->n_tbs_size = 2; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + dl_dci->tbs_size[1] = dci_tbs; dl_dci->n_rv = 2; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = (round+1) % 4; - dl_dci->rv[1] = (round+1) % 4; + dl_dci->rv[0] = round&3; + dl_dci->rv[1] = round&3; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->mcs[1] = mcs; if (frame_parms[CC_id]->frame_type == TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; @@ -417,7 +428,6 @@ schedule_ue_spec_default( dl_dci->n_mcs = 1; dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t)); dl_dci->mcs[0] = mcs; - //TODO:Need to fix tpc for retransmissions dl_dci->has_tpc = 1; dl_dci->tpc = 1; dl_dci->has_vrb_format = 1; @@ -426,16 +436,22 @@ schedule_ue_spec_default( dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 0; + dl_dci->ndi[0] = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_dci->has_rb_bitmap = 1; dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, UE_list->UE_template[CC_id][UE_id].rballoc_subband); dl_dci->has_rb_shift = 1; dl_dci->rb_shift = 0; dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->n_tbs_size = 1; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = (round + 1) % 4; + dl_dci->rv[0] = round&3; if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { ue_sched_ctl->dl_pow_off[CC_id] = 1; @@ -451,7 +467,6 @@ schedule_ue_spec_default( dl_dci->n_mcs = 1; dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t)); dl_dci->mcs[0] = mcs; - //TODO:Need to fix tpc for retransmissions dl_dci->has_tpc = 1; dl_dci->tpc = 1; dl_dci->has_vrb_format = 1; @@ -460,16 +475,22 @@ schedule_ue_spec_default( dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 0; + dl_dci->ndi[0] = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_dci->has_rb_bitmap = 1; dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, UE_list->UE_template[CC_id][UE_id].rballoc_subband); dl_dci->has_rb_shift = 1; dl_dci->rb_shift = 0; dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->n_tbs_size = 1; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = (round + 1) % 4; + dl_dci->rv[0] = round&3; dl_dci->has_dl_power_offset = 1; dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; @@ -843,7 +864,7 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->ndi[0] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = 0; @@ -873,8 +894,8 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 2; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1; - dl_dci->ndi[1] = 1; + dl_dci->ndi[0] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->ndi[1] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_dci->n_rv = 2; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = 0; @@ -907,8 +928,8 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 2; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1; - dl_dci->ndi[1] = 1; + dl_dci->ndi[0] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->ndi[1] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_dci->n_rv = 2; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = 0; @@ -941,7 +962,7 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; dl_dci->ndi = 1; - dl_dci->ndi[0] = 1; + dl_dci->ndi[0] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = 0; @@ -981,7 +1002,7 @@ schedule_ue_spec_default( dl_dci->rb_shift = 0; dl_dci->n_ndi = 1; dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1; + dl_dci->ndi[0] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_dci->n_rv = 1; dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); dl_dci->rv[0] = round&3; From e8f4e4e01f7b4cef8b284e7bb8bad87bc9899aca Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 3 Feb 2016 17:44:20 +0000 Subject: [PATCH 085/413] Separated control from data plane in MAC agent scheduler --- cmake_targets/CMakeLists.txt | 1 + .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 458 +----------------- openair2/LAYER2/MAC/eNB_scheduler.c | 45 +- 3 files changed, 29 insertions(+), 475 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 631872f847..b555f67ebc 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1010,6 +1010,7 @@ set (MAC_SRC ${MAC_DIR}/pre_processor.c ${MAC_DIR}/config.c ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue.c + ${MAC_DIR}/eNB_agent_scheduler_dataplane.c ) set (ENB_APP_SRC diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index b97c15c9f5..6da07ac558 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -44,6 +44,7 @@ #include "SCHED/defs.h" #include "SCHED/extern.h" +#include "LAYER2/MAC/enb_agent_mac_proto.h" #include "LAYER2/MAC/defs.h" #include "LAYER2/MAC/proto.h" #include "LAYER2/MAC/extern.h" @@ -83,25 +84,19 @@ schedule_ue_spec_default( ) //------------------------------------------------------------------------------ { - //TODO uint8_t CC_id; int UE_id; 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,header_len_dtch=0,header_len_dtch_tmp=0, ta_len=0; - unsigned char sdu_lcids[11],offset,num_sdus=0; - uint16_t nb_rb,nb_rb_temp,total_nb_available_rb[MAX_NUM_CCs],nb_available_rb; - uint16_t TBS,j,sdu_lengths[11],rnti,padding=0,post_padding=0; - unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; + unsigned char header_len_dcch=0, header_len_dcch_tmp=0, header_len_dtch=0, header_len_dtch_tmp=0, ta_len=0; + uint16_t nb_rb, nb_rb_temp, total_nb_available_rb[MAX_NUM_CCs], nb_available_rb; + uint16_t TBS, j, rnti, padding=0, post_padding=0; unsigned char round = 0; unsigned char harq_pid = 0; void *DLSCH_dci = NULL; LTE_eNB_UE_stats *eNB_UE_stats = NULL; uint16_t sdu_length_total = 0; - // uint8_t dl_pow_off[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; - // unsigned char rballoc_sub_UE[MAX_NUM_CCs][NUMBER_OF_UE_MAX][N_RBG_MAX]; - // uint16_t pre_nb_available_rbs[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; int mcs, mcs_tmp; uint16_t min_rb_unit[MAX_NUM_CCs]; eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; @@ -241,7 +236,6 @@ schedule_ue_spec_default( sdu_length_total=0; - num_sdus=0; /* DevCheck(((eNB_UE_stats->DL_cqi[0] < MIN_CQI_VALUE) || (eNB_UE_stats->DL_cqi[0] > MAX_CQI_VALUE)), @@ -261,7 +255,7 @@ schedule_ue_spec_default( #endif // store stats - //UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->DL_cqi[0]; + // // initializing the rb allocation indicator for each UE for(j = 0; j < frame_parms[CC_id]->N_RBG; j++) { @@ -1051,445 +1045,3 @@ schedule_ue_spec_default( stop_meas(&eNB->schedule_dlsch); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_OUT); } - -void apply_scheduling_decisions(mid_t mod_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__ProgranMessage *dl_scheduling_info) { - - uint8_t CC_id; - int UE_id; - 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,header_len_dtch=0,header_len_dtch_tmp=0, ta_len=0; - unsigned char sdu_lcids[11],offset,num_sdus=0; - uint16_t nb_rb,nb_rb_temp,total_nb_available_rb[MAX_NUM_CCs],nb_available_rb; - uint16_t TBS,j,sdu_lengths[11],rnti,padding=0,post_padding=0; - unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; - unsigned char round = 0; - unsigned char harq_pid = 0; - void *DLSCH_dci = NULL; - DCI_PDU *DCI_pdu; - - LTE_eNB_UE_stats *eNB_UE_stats = NULL; - uint16_t sdu_length_total = 0; - int mcs; - uint16_t min_rb_unit[MAX_NUM_CCs]; - short ta_update = 0; - eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; - UE_list_t *UE_list = &eNB->UE_list; - LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; - int32_t normalized_rx_power, target_rx_power; - int32_t tpc=1; - static int32_t tpc_accumulated=0; - UE_sched_ctrl *ue_sched_ctl; - - int i; - int size_bits,size_bytes; - - Protocol__PrpDlMacConfig *mac_config = dl_scheduling_info->dl_mac_config_msg; - Protocol__PrpDlData *dl_data; - Protocol__PrpDlDci *dl_dci; - - uint32_t rlc_size, n_lc, lcid; - - // Check if there is any scheduling command for UE data - if (mac_config->n_dl_ue_data > 0) { - - // For each UE-related command - for (i = 0; i < mac_config->n_dl_ue_data; i++) { - - dl_data = mac_config->dl_ue_data[i]; - dl_dci = dl_data->dl_dci; - - CC_id = dl_data->serv_cell_index; - rnti = dl_data->rnti; - UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); - - ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); - - round = dl_dci->rv[0]; - harq_pid = dl_dci->harq_process; - - // Note this code is for a specific DCI format - DLSCH_dci = (void *)UE_list->UE_template[CC_id][UE_id].DLSCH_DCI[harq_pid]; - DCI_pdu = &eNB->common_channels[CC_id].DCI_pdu; - - frame_parms[CC_id] = mac_xface->get_lte_frame_parms(mod_id, CC_id); - - switch (frame_parms[CC_id]->N_RB_DL) { - case 6: - if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rv = round; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; - size_bytes = sizeof(DCI1_1_5MHz_TDD_t); - size_bits = sizeof_DCI1_1_5MHz_TDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { - //TODO - } - } else { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - LOG_D(MAC,"[TEST] Setting DCI format 1\n"); - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rv = round; - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; - size_bytes = sizeof(DCI1_1_5MHz_FDD_t); - size_bits = sizeof_DCI1_1_5MHz_FDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { - //TODO - } - } - break; - case 25: - if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rv = round; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; - size_bytes = sizeof(DCI1_5MHz_TDD_t); - size_bits = sizeof_DCI1_5MHz_TDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { - //TODO - } - } else { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rv = round; - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; - size_bytes = sizeof(DCI1_5MHz_FDD_t); - size_bits = sizeof_DCI1_5MHz_FDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { - //TODO - } - } - break; - case 50: - if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rv = round; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; - size_bytes = sizeof(DCI1_10MHz_TDD_t); - size_bits = sizeof_DCI1_10MHz_TDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { - //TODO - } - } else { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_10MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rv = round; - ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_10MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_10MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; - size_bytes = sizeof(DCI1_10MHz_FDD_t); - size_bits = sizeof_DCI1_10MHz_FDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { - //TODO - } - } - break; - case 100: - if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rv = round; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; - size_bytes = sizeof(DCI1_20MHz_TDD_t); - size_bits = sizeof_DCI1_20MHz_TDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { - //TODO - } - } else { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rv = round; - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; - size_bytes = sizeof(DCI1_20MHz_FDD_t); - size_bits = sizeof_DCI1_20MHz_FDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { - //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { - //TODO - } - } - break; - } - - // If this is a new transmission - if (round == 0) { - // First we have to deal with the creation of the PDU based on the message instructions - rlc_status.bytes_in_buffer = 0; - - TBS = dl_dci->tbs_size[0]; - LOG_D(MAC,"[TEST] The TBS during the creation process is %d\n", TBS); - - if (dl_data->n_ce_bitmap > 0) { - //Check if there is TA command - if (dl_data->ce_bitmap[0] & PROTOCOL__PRP_CE_TYPE__PRPCET_TA) { - ta_len = 2; - LOG_D(MAC, "[TEST] Need to send timing advance\n"); - } else { - ta_len = 0; - LOG_D(MAC, "[TEST] No timing advance\n"); - } - } - - - n_lc = dl_data->n_rlc_pdu; - num_sdus = 0; - sdu_length_total = 0; - // Go through each one of the channel commands and create SDUs - for (i = 0; i < n_lc; i++) { - lcid = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->logical_channel_id; - LOG_D(MAC, "[TEST] Going through SDU of channel %d\n", lcid); - rlc_size = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->size; - LOG_D(MAC,"[TEST] [eNB %d] Frame %d, LCID %d, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", - mod_id, frame, lcid, CC_id, rlc_size); - if (rlc_size > 0) { - - rlc_status = mac_rlc_status_ind(mod_id, - rnti, - mod_id, - frame, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - rlc_size); // transport block set size - - sdu_lengths[i] = 0; - - LOG_D(MAC, "[TEST] RLC can give %d bytes for LCID %d during second call\n", rlc_status.bytes_in_buffer, lcid); - - sdu_lengths[i] += mac_rlc_data_req(mod_id, - rnti, - mod_id, - frame, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - (char *)&dlsch_buffer[sdu_length_total]); - - LOG_D(MAC, "[TEST] RLC gave %d bytes in LCID %d\n", sdu_lengths[i], lcid); - - LOG_D(MAC,"[eNB %d][LCID %d] CC_id %d Got %d bytes from RLC\n",mod_id, lcid, CC_id, sdu_lengths[i]); - sdu_length_total += sdu_lengths[i]; - LOG_D(MAC, "[TEST] Total sdu size became %d\n", sdu_length_total); - sdu_lcids[i] = lcid; - - 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[i]; - - if (lcid == DCCH || lcid == DCCH1) { - header_len_dcch += 2; - } else if (lcid == DTCH) { - if (sdu_lengths[i] < 128) { - header_len_dtch = 2; - } else { - header_len_dtch = 3; - } - } - - num_sdus++; - } - } // SDU creation end - - - if (((sdu_length_total + header_len_dcch + header_len_dtch) > 0)) { - - 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) ? (header_len_dcch - 1) : header_len_dcch; // remove length field - } else { - header_len_dtch = (header_len_dtch > 0) ? 1 : header_len_dtch; // remove length field for the last SDU - } - - // there is a payload - if (((sdu_length_total + header_len_dcch + header_len_dtch ) > 0)) { - if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2 - || (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) > TBS) { //protect from overflow - padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); - post_padding = 0; - } else { - padding = 0; - - // adjust the header len - if (header_len_dtch==0) { - header_len_dcch = header_len_dcch_tmp; - } else { - header_len_dtch = header_len_dtch_tmp; - } - - post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len - 1; // 1 is for the postpadding header - } - } - - - if (ta_len > 0) { - ta_update = ue_sched_ctl->ta_update; - } else { - ta_update = 0; - } - - offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], - // offset = generate_dlsch_header((unsigned char*)eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0], - num_sdus, //num_sdus - sdu_lengths, // - sdu_lcids, - 255, // no drx - ta_update, // timing advance - NULL, // contention res id - padding, - post_padding); - - LOG_D(MAC, "[TEST]Have to schedule %d SDUs with length %d. TBS is %d, LCID is %d, post padding is %d, padding is %d, header offset is %d, total sdu size is %d\n", num_sdus, sdu_lengths[0], TBS, sdu_lcids[0], post_padding, padding, offset, sdu_length_total); - -#ifdef DEBUG_eNB_SCHEDULER - LOG_T(MAC,"[eNB %d] First 16 bytes of DLSCH : \n"); - - for (i=0; i<16; i++) { - LOG_T(MAC,"%x.",dlsch_buffer[i]); - } - - LOG_T(MAC,"\n"); -#endif - // cycle through SDUs and place in dlsch_buffer - memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset],dlsch_buffer,sdu_length_total); - // memcpy(&eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]); - - // fill remainder of DLSCH with random data - for (j=0; j<(TBS-sdu_length_total-offset); j++) { - UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset+sdu_length_total+j] = (char)(taus()&0xff); - } - - //eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0][offset+sdu_lengths[0]+j] = (char)(taus()&0xff); - if (opt_enabled == 1) { - trace_pdu(1, (uint8_t *)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], - TBS, mod_id, 3, UE_RNTI(mod_id, UE_id), - eNB->subframe,0,0); - LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", - mod_id, CC_id, frame, UE_RNTI(mod_id,UE_id), TBS); - } - - // store stats - eNB->eNB_stats[CC_id].dlsch_bytes_tx+=sdu_length_total; - eNB->eNB_stats[CC_id].dlsch_pdus_tx+=1; - - 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(mod_id, rnti); - 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; - - nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - LOG_D(MAC,"[TEST] %d Number of resource blocks allocated\n", nb_rb); - UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=dl_dci->mcs[0]; - UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=dl_dci->mcs[0]; - UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; - - UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes= TBS- sdu_length_total; - UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes+= sdu_length_total; - UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes+= TBS; - UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus+=1; - - eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; - eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); - // TODO - - - } - - - - } else { - // No need to create anything apart of DCI in case of retransmission - - /*TODO: Must add these */ - //eNB_UE_stats->dlsch_trials[round]++; - //UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; - //UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; - //UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; - //UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx=nCCECC_id]; - //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1; - //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=eNB_UE_stats->dlsch_mcs1; - } - - //Add DCI based on format - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - add_ue_spec_dci(DCI_pdu, - DLSCH_dci, - rnti, - size_bytes, - dl_dci->aggr_level,//aggregation - size_bits, - format1, - 0); - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { - add_ue_spec_dci(DCI_pdu, - DLSCH_dci, - rnti, - size_bytes, - dl_dci->aggr_level,//aggregation - size_bits, - format2A, - 0); - } - } - } -} - diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index caf7457fea..fec058b27e 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -62,6 +62,7 @@ //Agent-related headers #include "ENB_APP/enb_agent_extern.h" #include "ENB_APP/enb_agent_mac.h" +#include "LAYER2/MAC/enb_agent_mac_proto.h" #if defined(ENABLE_ITTI) # include "intertask_interface.h" @@ -273,7 +274,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -322,7 +323,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -353,7 +354,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -390,7 +391,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -419,7 +420,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -463,7 +464,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -494,7 +495,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -531,7 +532,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -559,7 +560,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -612,7 +613,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -637,7 +638,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -665,7 +666,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -699,7 +700,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -723,7 +724,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -751,7 +752,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -790,7 +791,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -818,7 +819,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -851,7 +852,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -877,7 +878,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -903,7 +904,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -929,7 +930,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, @@ -957,7 +958,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, mbsfn_status, msg); - apply_scheduling_decisions(module_idP, + apply_dl_scheduling_decisions(module_idP, frameP, subframeP, mbsfn_status, From db255c130dd97721f70bb4f8ba2e70281b2007f9 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 4 Feb 2016 11:28:22 +0000 Subject: [PATCH 086/413] Added definitions for the mac agent scheduler --- openair2/ENB_APP/enb_agent_mac_defs.h | 2 + .../MAC/eNB_agent_scheduler_dataplane.c | 544 ++++++++++++++++++ openair2/LAYER2/MAC/enb_agent_mac_proto.h | 71 +++ openair2/LAYER2/MAC/proto.h | 7 - 4 files changed, 617 insertions(+), 7 deletions(-) create mode 100644 openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c create mode 100644 openair2/LAYER2/MAC/enb_agent_mac_proto.h diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/enb_agent_mac_defs.h index c2891e87ca..6e960cdb69 100644 --- a/openair2/ENB_APP/enb_agent_mac_defs.h +++ b/openair2/ENB_APP/enb_agent_mac_defs.h @@ -39,6 +39,8 @@ #define __ENB_AGENT_MAC_PRIMITIVES_H__ #include "enb_agent_defs.h" +#include "progran.pb-c.h" +#include "header.pb-c.h" /* ENB AGENT-MAC Interface */ typedef struct { diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c new file mode 100644 index 0000000000..43d4ad2b51 --- /dev/null +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c @@ -0,0 +1,544 @@ +/******************************************************************************* + 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ + +/*! \file eNB_agent_scheduler_dataplane.c + * \brief data plane procedures related to eNB scheduling + * \author Xenofon Foukas + * \date 2016 + * \email: x.foukas@sms.ed.ac.uk + * \version 0.1 + * @ingroup _mac + + */ + +#include "assertions.h" +#include "PHY/defs.h" +#include "PHY/extern.h" + +#include "SCHED/defs.h" +#include "SCHED/extern.h" + +#include "LAYER2/MAC/enb_agent_mac_proto.h" +#include "LAYER2/MAC/defs.h" +#include "LAYER2/MAC/proto.h" +#include "LAYER2/MAC/extern.h" + +#include "UTIL/LOG/log.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "OCG.h" +#include "OCG_extern.h" + +#include "RRC/LITE/extern.h" +#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" + +#include "header.pb-c.h" +#include "progran.pb-c.h" + +#include "SIMULATION/TOOLS/defs.h" // for taus + + +void apply_dl_scheduling_decisions(mid_t mod_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__ProgranMessage *dl_scheduling_info) { + + Protocol__PrpDlMacConfig *mac_config = dl_scheduling_info->dl_mac_config_msg; + + // Check if there is anything to schedule for random access + if (mac_config->n_dl_rar > 0) { + /*TODO: call the random access data plane function*/ + } + + // Check if there is anything to schedule for paging/broadcast + if (mac_config->n_dl_broadcast > 0) { + /*TODO: call the broadcast/paging data plane function*/ + } + + // Check if there is anything to schedule for the UEs + if (mac_config->n_dl_ue_data > 0) { + apply_ue_spec_scheduling_decisions(mod_id, frame, subframe, mbsfn_flag, + mac_config->n_dl_ue_data, mac_config->dl_ue_data); + } + +} + + +void apply_ue_spec_scheduling_decisions(mid_t mod_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + uint32_t n_dl_ue_data, + const Protocol__PrpDlData **dl_ue_data) { + + uint8_t CC_id; + int UE_id; + 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,header_len_dtch=0,header_len_dtch_tmp=0, ta_len=0; + unsigned char sdu_lcids[11],offset,num_sdus=0; + uint16_t nb_rb,nb_rb_temp,total_nb_available_rb[MAX_NUM_CCs],nb_available_rb; + uint16_t TBS,j,sdu_lengths[11],rnti,padding=0,post_padding=0; + unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; + unsigned char round = 0; + unsigned char harq_pid = 0; + + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + uint16_t sdu_length_total = 0; + int mcs; + uint16_t min_rb_unit[MAX_NUM_CCs]; + short ta_update = 0; + eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; + UE_list_t *UE_list = &eNB->UE_list; + LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; + int32_t normalized_rx_power, target_rx_power; + int32_t tpc=1; + static int32_t tpc_accumulated=0; + UE_sched_ctrl *ue_sched_ctl; + + int i; + + Protocol__PrpDlData *dl_data; + Protocol__PrpDlDci *dl_dci; + + uint32_t rlc_size, n_lc, lcid; + + + // For each UE-related command + for (i = 0; i < n_dl_ue_data; i++) { + + dl_data = dl_ue_data[i]; + dl_dci = dl_data->dl_dci; + + CC_id = dl_data->serv_cell_index; + frame_parms[CC_id] = mac_xface->get_lte_frame_parms(mod_id, CC_id); + + rnti = dl_data->rnti; + UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); + + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); + + round = dl_dci->rv[0]; + harq_pid = dl_dci->harq_process; + + // If this is a new transmission + if (round == 0) { + // First we have to deal with the creation of the PDU based on the message instructions + rlc_status.bytes_in_buffer = 0; + + TBS = dl_dci->tbs_size[0]; + LOG_D(MAC,"[TEST] The TBS during the creation process is %d\n", TBS); + + if (dl_data->n_ce_bitmap > 0) { + //Check if there is TA command + if (dl_data->ce_bitmap[0] & PROTOCOL__PRP_CE_TYPE__PRPCET_TA) { + ta_len = 2; + LOG_D(MAC, "[TEST] Need to send timing advance\n"); + } else { + ta_len = 0; + LOG_D(MAC, "[TEST] No timing advance\n"); + } + } + + + n_lc = dl_data->n_rlc_pdu; + num_sdus = 0; + sdu_length_total = 0; + // Go through each one of the channel commands and create SDUs + for (i = 0; i < n_lc; i++) { + lcid = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->logical_channel_id; + LOG_D(MAC, "[TEST] Going through SDU of channel %d\n", lcid); + rlc_size = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->size; + LOG_D(MAC,"[TEST] [eNB %d] Frame %d, LCID %d, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", + mod_id, frame, lcid, CC_id, rlc_size); + if (rlc_size > 0) { + + rlc_status = mac_rlc_status_ind(mod_id, + rnti, + mod_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + rlc_size); // transport block set size + + sdu_lengths[i] = 0; + + LOG_D(MAC, "[TEST] RLC can give %d bytes for LCID %d during second call\n", rlc_status.bytes_in_buffer, lcid); + + sdu_lengths[i] += mac_rlc_data_req(mod_id, + rnti, + mod_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + (char *)&dlsch_buffer[sdu_length_total]); + + LOG_D(MAC, "[TEST] RLC gave %d bytes in LCID %d\n", sdu_lengths[i], lcid); + + LOG_D(MAC,"[eNB %d][LCID %d] CC_id %d Got %d bytes from RLC\n",mod_id, lcid, CC_id, sdu_lengths[i]); + sdu_length_total += sdu_lengths[i]; + LOG_D(MAC, "[TEST] Total sdu size became %d\n", sdu_length_total); + sdu_lcids[i] = lcid; + + 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[i]; + + if (lcid == DCCH || lcid == DCCH1) { + header_len_dcch += 2; + } else if (lcid == DTCH) { + if (sdu_lengths[i] < 128) { + header_len_dtch = 2; + } else { + header_len_dtch = 3; + } + } + + num_sdus++; + } + } // SDU creation end + + + if (((sdu_length_total + header_len_dcch + header_len_dtch) > 0)) { + + 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) ? (header_len_dcch - 1) : header_len_dcch; // remove length field + } else { + header_len_dtch = (header_len_dtch > 0) ? 1 : header_len_dtch; // remove length field for the last SDU + } + + // there is a payload + if (((sdu_length_total + header_len_dcch + header_len_dtch ) > 0)) { + if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2 + || (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) > TBS) { //protect from overflow + padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); + post_padding = 0; + } else { + padding = 0; + + // adjust the header len + if (header_len_dtch==0) { + header_len_dcch = header_len_dcch_tmp; + } else { + header_len_dtch = header_len_dtch_tmp; + } + + post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len - 1; // 1 is for the postpadding header + } + } + + + if (ta_len > 0) { + ta_update = ue_sched_ctl->ta_update; + } else { + ta_update = 0; + } + + offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], + // offset = generate_dlsch_header((unsigned char*)eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0], + num_sdus, //num_sdus + sdu_lengths, // + sdu_lcids, + 255, // no drx + ta_update, // timing advance + NULL, // contention res id + padding, + post_padding); + + LOG_D(MAC, "[TEST]Have to schedule %d SDUs with length %d. TBS is %d, LCID is %d, post padding is %d, padding is %d, header offset is %d, total sdu size is %d\n", num_sdus, sdu_lengths[0], TBS, sdu_lcids[0], post_padding, padding, offset, sdu_length_total); + +#ifdef DEBUG_eNB_SCHEDULER + LOG_T(MAC,"[eNB %d] First 16 bytes of DLSCH : \n"); + + for (i=0; i<16; i++) { + LOG_T(MAC,"%x.",dlsch_buffer[i]); + } + + LOG_T(MAC,"\n"); +#endif + // cycle through SDUs and place in dlsch_buffer + memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset],dlsch_buffer,sdu_length_total); + // memcpy(&eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]); + + // fill remainder of DLSCH with random data + for (j=0; j<(TBS-sdu_length_total-offset); j++) { + UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset+sdu_length_total+j] = (char)(taus()&0xff); + } + + //eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0][offset+sdu_lengths[0]+j] = (char)(taus()&0xff); + if (opt_enabled == 1) { + trace_pdu(1, (uint8_t *)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], + TBS, mod_id, 3, UE_RNTI(mod_id, UE_id), + eNB->subframe,0,0); + LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", + mod_id, CC_id, frame, UE_RNTI(mod_id,UE_id), TBS); + } + + // store stats + eNB->eNB_stats[CC_id].dlsch_bytes_tx+=sdu_length_total; + eNB->eNB_stats[CC_id].dlsch_pdus_tx+=1; + UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->DL_cqi[0]; + + 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(mod_id, rnti); + 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; + + nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=dl_dci->mcs[0]; + UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=dl_dci->mcs[0]; + UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; + + UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes= TBS- sdu_length_total; + UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes+= sdu_length_total; + UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes+= TBS; + UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus+=1; + + eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; + eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); + } + } else { + // No need to create anything apart of DCI in case of retransmission + + /*TODO: Must add these */ + //eNB_UE_stats->dlsch_trials[round]++; + //UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; + //UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; + //UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; + //UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx=nCCECC_id]; + //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1; + //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=eNB_UE_stats->dlsch_mcs1; + } + //Fill the proper DCI of OAI + fill_oai_dci(mod_id, CC_id, rnti, dl_dci); + } +} + +void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, + const Protocol__PrpDlDci *dl_dci) { + + void *DLSCH_dci = NULL; + DCI_PDU *DCI_pdu; + + unsigned char round = 0; + unsigned char harq_pid = 0; + LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; + int size_bits, size_bytes; + eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; + UE_list_t *UE_list = &eNB->UE_list; + + int UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); + + harq_pid = dl_dci->harq_process; + round = dl_dci->rv[0]; + + // Note this code is for a specific DCI format + DLSCH_dci = (void *)UE_list->UE_template[CC_id][UE_id].DLSCH_DCI[harq_pid]; + DCI_pdu = &eNB->common_channels[CC_id].DCI_pdu; + + frame_parms[CC_id] = mac_xface->get_lte_frame_parms(mod_id, CC_id); + + switch (frame_parms[CC_id]->N_RB_DL) { + case 6: + if (frame_parms[CC_id]->frame_type == TDD) { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rv = round; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_1_5MHz_TDD_t); + size_bits = sizeof_DCI1_1_5MHz_TDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } else { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + LOG_D(MAC,"[TEST] Setting DCI format 1\n"); + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rv = round; + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_1_5MHz_FDD_t); + size_bits = sizeof_DCI1_1_5MHz_FDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } + break; + case 25: + if (frame_parms[CC_id]->frame_type == TDD) { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rv = round; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_5MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_5MHz_TDD_t); + size_bits = sizeof_DCI1_5MHz_TDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } else { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rv = round; + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_5MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_5MHz_FDD_t); + size_bits = sizeof_DCI1_5MHz_FDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } + break; + case 50: + if (frame_parms[CC_id]->frame_type == TDD) { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rv = round; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_10MHz_TDD_t); + size_bits = sizeof_DCI1_10MHz_TDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } else { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_10MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rv = round; + ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; + ((DCI1_10MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_10MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_10MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_10MHz_FDD_t); + size_bits = sizeof_DCI1_10MHz_FDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } + break; + case 100: + if (frame_parms[CC_id]->frame_type == TDD) { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rv = round; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_20MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_20MHz_TDD_t); + size_bits = sizeof_DCI1_20MHz_TDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } else { + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rv = round; + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; + ((DCI1_20MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + size_bytes = sizeof(DCI1_20MHz_FDD_t); + size_bits = sizeof_DCI1_20MHz_FDD_t; + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + //TODO + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + //TODO + } + } + break; + } + + //Add DCI based on format + if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + add_ue_spec_dci(DCI_pdu, + DLSCH_dci, + rnti, + size_bytes, + dl_dci->aggr_level,//aggregation + size_bits, + format1, + 0); + } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + add_ue_spec_dci(DCI_pdu, + DLSCH_dci, + rnti, + size_bytes, + dl_dci->aggr_level,//aggregation + size_bits, + format2A, + 0); + } +} diff --git a/openair2/LAYER2/MAC/enb_agent_mac_proto.h b/openair2/LAYER2/MAC/enb_agent_mac_proto.h new file mode 100644 index 0000000000..7fcdbc29c3 --- /dev/null +++ b/openair2/LAYER2/MAC/enb_agent_mac_proto.h @@ -0,0 +1,71 @@ +/******************************************************************************* + 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ + +/*! \file enb_agent_mac_proto.h + * \brief MAC functions for eNB agent + * \author Xenofon Foukas + * \date 2016 + * \email: x.foukas@sms.ed.ac.uk + * \version 0.1 + * @ingroup _mac + + */ + +#ifndef __LAYER2_MAC_ENB_AGENT_MAC_PROTO_H__ +#define __LAYER2_MAC_ENB_AGENT_MAC_PROTO_H__ + +#include "enb_agent_defs.h" +#include "header.pb-c.h" +#include "progran.pb-c.h" + +/* + * Default scheduler used by the eNB agent + */ +void schedule_ue_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, + int *mbsfn_flag, Protocol__ProgranMessage *dl_info); + + +/* + * Data plane function for applying the DL decisions of the scheduler + */ +void apply_dl_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, + Protocol__ProgranMessage *dl_scheduling_info); + +/* + * Data plane function for applying the UE specific DL decisions of the scheduler + */ +void apply_ue_spec_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, + uint32_t n_dl_ue_data, const Protocol__PrpDlData **dl_ue_data); + +/* + * Data plane function for filling the DCI structure + */ +void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, const Protocol__PrpDlDci *dl_dci); + +#endif diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index faf0bf9954..be553c278d 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -36,10 +36,6 @@ #ifndef __LAYER2_MAC_PROTO_H__ #define __LAYER2_MAC_PROTO_H__ -#include "enb_agent_defs.h" -#include "header.pb-c.h" -#include "progran.pb-c.h" - /** \addtogroup _mac * @{ */ @@ -133,9 +129,6 @@ void fill_DLSCH_dci(module_id_t module_idP,frame_t frameP,sub_frame_t subframe,i */ void schedule_ue_spec(module_id_t module_idP,frame_t frameP,sub_frame_t subframe,int *mbsfn_flag); -//To be used by the agent -void schedule_ue_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__ProgranMessage *dl_info); /** \brief Function for UE/PHY to compute PUSCH transmit power in power-control procedure. @param Mod_id Module id of UE From e3aa8400d4f8e962195e197f39df1a28a670e61a Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 4 Feb 2016 11:28:54 +0000 Subject: [PATCH 087/413] Added support for progran dl_mac_config message destruction --- openair2/ENB_APP/enb_agent_mac.c | 59 +++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 05b2a7a364..df614df60c 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -40,6 +40,7 @@ #include "enb_agent_mac_internal.h" #include "LAYER2/MAC/proto.h" +#include "LAYER2/MAC/enb_agent_mac_proto.h" #include "log.h" @@ -1029,7 +1030,63 @@ int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__ProgranMessage } int enb_agent_mac_destroy_dl_config(Protocol__ProgranMessage *msg) { - //TODO: De-allocate the memory of the message + int i,j, k; + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG) + goto error; + + Protocol__PrpDlDci *dl_dci; + + free(msg->dl_mac_config_msg->header); + for (i = 0; i < msg->dl_mac_config_msg->n_dl_ue_data; i++) { + free(msg->dl_mac_config_msg->dl_ue_data[i]->ce_bitmap); + for (j = 0; j < msg->dl_mac_config_msg->dl_ue_data[i]->n_rlc_pdu; j++) { + for (k = 0; k < msg->dl_mac_config_msg->dl_ue_data[i]->rlc_pdu[j]->n_rlc_pdu_tb; k++) { + free(msg->dl_mac_config_msg->dl_ue_data[i]->rlc_pdu[j]->rlc_pdu_tb[k]); + } + free(msg->dl_mac_config_msg->dl_ue_data[i]->rlc_pdu[j]->rlc_pdu_tb); + free(msg->dl_mac_config_msg->dl_ue_data[i]->rlc_pdu[j]); + } + free(msg->dl_mac_config_msg->dl_ue_data[i]->rlc_pdu); + dl_dci = msg->dl_mac_config_msg->dl_ue_data[i]->dl_dci; + free(dl_dci->tbs_size); + free(dl_dci->mcs); + free(dl_dci->ndi); + free(dl_dci->rv); + free(dl_dci); + free(msg->dl_mac_config_msg->dl_ue_data[i]); + } + free(msg->dl_mac_config_msg->dl_ue_data); + + for (i = 0; i < msg->dl_mac_config_msg->n_dl_rar; i++) { + dl_dci = msg->dl_mac_config_msg->dl_rar[i]->rar_dci; + free(dl_dci->tbs_size); + free(dl_dci->mcs); + free(dl_dci->ndi); + free(dl_dci->rv); + free(dl_dci); + free(msg->dl_mac_config_msg->dl_rar[i]); + } + free(msg->dl_mac_config_msg->dl_rar); + + for (i = 0; i < msg->dl_mac_config_msg->n_dl_broadcast; i++) { + dl_dci = msg->dl_mac_config_msg->dl_broadcast[i]->broad_dci; + free(dl_dci->tbs_size); + free(dl_dci->mcs); + free(dl_dci->ndi); + free(dl_dci->rv); + free(dl_dci); + free(msg->dl_mac_config_msg->dl_broadcast[i]); + } + free(msg->dl_mac_config_msg->dl_broadcast); + + for ( i = 0; i < msg->dl_mac_config_msg->n_ofdm_sym; i++) { + free(msg->dl_mac_config_msg->ofdm_sym[i]); + } + free(msg->dl_mac_config_msg->ofdm_sym); + + return 0; + + error: return -1; } From b784e6bd64b4aa6512b5c468c3e255d941e81f46 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 4 Feb 2016 12:52:01 +0000 Subject: [PATCH 088/413] Refactored code to improve readability in fill_oai_dci function --- .../MAC/eNB_agent_scheduler_dataplane.c | 205 +++++++----------- openair2/LAYER2/MAC/progran_dci_conversions.h | 59 +++++ 2 files changed, 134 insertions(+), 130 deletions(-) create mode 100644 openair2/LAYER2/MAC/progran_dci_conversions.h diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c index 43d4ad2b51..6fe11c59cd 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c @@ -48,6 +48,7 @@ #include "LAYER2/MAC/defs.h" #include "LAYER2/MAC/proto.h" #include "LAYER2/MAC/extern.h" +#include "LAYER2/MAC/progran_dci_conversions.h" #include "UTIL/LOG/log.h" #include "UTIL/LOG/vcd_signal_dumper.h" @@ -104,6 +105,7 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, unsigned char aggregation; mac_rlc_status_resp_t rlc_status; unsigned char header_len_dcch=0, header_len_dcch_tmp=0,header_len_dtch=0,header_len_dtch_tmp=0, ta_len=0; + unsigned char header_len = 0, header_len_tmp = 0; unsigned char sdu_lcids[11],offset,num_sdus=0; uint16_t nb_rb,nb_rb_temp,total_nb_available_rb[MAX_NUM_CCs],nb_available_rb; uint16_t TBS,j,sdu_lengths[11],rnti,padding=0,post_padding=0; @@ -156,27 +158,18 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, rlc_status.bytes_in_buffer = 0; TBS = dl_dci->tbs_size[0]; - LOG_D(MAC,"[TEST] The TBS during the creation process is %d\n", TBS); if (dl_data->n_ce_bitmap > 0) { - //Check if there is TA command - if (dl_data->ce_bitmap[0] & PROTOCOL__PRP_CE_TYPE__PRPCET_TA) { - ta_len = 2; - LOG_D(MAC, "[TEST] Need to send timing advance\n"); - } else { - ta_len = 0; - LOG_D(MAC, "[TEST] No timing advance\n"); - } + //Check if there is TA command and set the length appropriately + ta_len = (dl_data->ce_bitmap[0] & PROTOCOL__PRP_CE_TYPE__PRPCET_TA) ? 2 : 0; } - n_lc = dl_data->n_rlc_pdu; num_sdus = 0; sdu_length_total = 0; // Go through each one of the channel commands and create SDUs for (i = 0; i < n_lc; i++) { lcid = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->logical_channel_id; - LOG_D(MAC, "[TEST] Going through SDU of channel %d\n", lcid); rlc_size = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->size; LOG_D(MAC,"[TEST] [eNB %d] Frame %d, LCID %d, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", mod_id, frame, lcid, CC_id, rlc_size); @@ -204,24 +197,17 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, lcid, (char *)&dlsch_buffer[sdu_length_total]); - LOG_D(MAC, "[TEST] RLC gave %d bytes in LCID %d\n", sdu_lengths[i], lcid); - LOG_D(MAC,"[eNB %d][LCID %d] CC_id %d Got %d bytes from RLC\n",mod_id, lcid, CC_id, sdu_lengths[i]); sdu_length_total += sdu_lengths[i]; - LOG_D(MAC, "[TEST] Total sdu size became %d\n", sdu_length_total); sdu_lcids[i] = lcid; 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[i]; - if (lcid == DCCH || lcid == DCCH1) { - header_len_dcch += 2; - } else if (lcid == DTCH) { - if (sdu_lengths[i] < 128) { - header_len_dtch = 2; - } else { - header_len_dtch = 3; - } + if (sdu_lengths[i] < 128) { + header_len += 2; + } else { + header_len += 3; } num_sdus++; @@ -229,46 +215,34 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, } // SDU creation end - if (((sdu_length_total + header_len_dcch + header_len_dtch) > 0)) { + if (((sdu_length_total + header_len) > 0)) { + + header_len_tmp = header_len; - 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) ? (header_len_dcch - 1) : header_len_dcch; // remove length field + // If we have only a single SDU, header length becomes 1 + if (header_len == 2 || header_len == 3) { + header_len = 1; } else { - header_len_dtch = (header_len_dtch > 0) ? 1 : header_len_dtch; // remove length field for the last SDU + header_len--; } // there is a payload - if (((sdu_length_total + header_len_dcch + header_len_dtch ) > 0)) { - if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2 - || (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) > TBS) { //protect from overflow - padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); + if (((sdu_length_total + header_len) > 0)) { + // If we need a 1 or 2 bit padding or no padding at all + if ((TBS - header_len - sdu_length_total - ta_len) <= 2 + || (TBS - header_len - sdu_length_total - ta_len) > TBS) { //protect from overflow + padding = (TBS - header_len - sdu_length_total - ta_len); post_padding = 0; - } else { + } else { // The last sdu needs to have a length field, since we add padding padding = 0; - - // adjust the header len - if (header_len_dtch==0) { - header_len_dcch = header_len_dcch_tmp; - } else { - header_len_dtch = header_len_dtch_tmp; - } - - post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len - 1; // 1 is for the postpadding header + header_len = header_len_tmp; + post_padding = TBS - sdu_length_total - header_len - ta_len - 1; // 1 is for the postpadding header } } - - if (ta_len > 0) { - ta_update = ue_sched_ctl->ta_update; - } else { - ta_update = 0; - } + ta_update = (ta_len > 0) ? ue_sched_ctl->ta_update : 0; offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], - // offset = generate_dlsch_header((unsigned char*)eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0], num_sdus, //num_sdus sdu_lengths, // sdu_lcids, @@ -364,6 +338,8 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, int UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); + uint32_t format; + harq_pid = dl_dci->harq_process; round = dl_dci->rv[0]; @@ -377,14 +353,7 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, case 6: if (frame_parms[CC_id]->frame_type == TDD) { if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rv = round; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + FILL_DCI_TDD_1(DCI1_1_5MHz_TDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_1_5MHz_TDD_t); size_bits = sizeof_DCI1_1_5MHz_TDD_t; } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { @@ -394,14 +363,7 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, } } else { if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - LOG_D(MAC,"[TEST] Setting DCI format 1\n"); - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rv = round; - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + FILL_DCI_FDD_1(DCI1_1_5MHz_FDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_1_5MHz_FDD_t); size_bits = sizeof_DCI1_1_5MHz_FDD_t; } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { @@ -414,14 +376,7 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, case 25: if (frame_parms[CC_id]->frame_type == TDD) { if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rv = round; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_5MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + FILL_DCI_TDD_1(DCI1_5MHz_TDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_5MHz_TDD_t); size_bits = sizeof_DCI1_5MHz_TDD_t; } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { @@ -431,13 +386,7 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, } } else { if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rv = round; - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_5MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + FILL_DCI_FDD_1(DCI1_5MHz_FDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_5MHz_FDD_t); size_bits = sizeof_DCI1_5MHz_FDD_t; } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { @@ -450,14 +399,7 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, case 50: if (frame_parms[CC_id]->frame_type == TDD) { if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rv = round; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + FILL_DCI_TDD_1(DCI1_10MHz_TDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_10MHz_TDD_t); size_bits = sizeof_DCI1_10MHz_TDD_t; } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { @@ -467,13 +409,7 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, } } else { if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_10MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rv = round; - ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_10MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_10MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_10MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + FILL_DCI_FDD_1(DCI1_10MHz_FDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_10MHz_FDD_t); size_bits = sizeof_DCI1_10MHz_FDD_t; } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { @@ -486,14 +422,7 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, case 100: if (frame_parms[CC_id]->frame_type == TDD) { if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rv = round; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->dai = dl_dci->dai; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_20MHz_TDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + FILL_DCI_TDD_1(DCI1_20MHz_TDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_20MHz_TDD_t); size_bits = sizeof_DCI1_20MHz_TDD_t; } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { @@ -503,13 +432,7 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, } } else { if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rv = round; - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rballoc = dl_dci->rb_bitmap; - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rah = dl_dci->res_alloc; - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->mcs = dl_dci->mcs[0]; - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->TPC = dl_dci->tpc; - ((DCI1_20MHz_FDD_t*)DLSCH_dci)->ndi = dl_dci->ndi[0]; + FILL_DCI_FDD_1(DCI1_20MHz_FDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_20MHz_FDD_t); size_bits = sizeof_DCI1_20MHz_FDD_t; } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { @@ -521,24 +444,46 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, break; } - //Add DCI based on format - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { - add_ue_spec_dci(DCI_pdu, - DLSCH_dci, - rnti, - size_bytes, - dl_dci->aggr_level,//aggregation - size_bits, - format1, - 0); - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { - add_ue_spec_dci(DCI_pdu, - DLSCH_dci, - rnti, - size_bytes, - dl_dci->aggr_level,//aggregation - size_bits, - format2A, - 0); + //Set format to the proper type + switch(dl_dci->format) { + case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1: + format = format1; + break; + case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1A: + format = format1A; + break; + case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1B: + format = format1B; + break; + case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1C: + format = format1C; + break; + case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D: + format = format1E_2A_M10PRB; + break; + case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2: + format = format2; + break; + case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A: + format = format2A; + break; + case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2B: + format = format2B; + break; + case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_3: + format = 3; + break; + default: + /*TODO: Need to deal with unsupported DCI type*/ + return; } + + add_ue_spec_dci(DCI_pdu, + DLSCH_dci, + rnti, + size_bytes, + dl_dci->aggr_level, + size_bits, + format, + 0); } diff --git a/openair2/LAYER2/MAC/progran_dci_conversions.h b/openair2/LAYER2/MAC/progran_dci_conversions.h new file mode 100644 index 0000000000..90324fdb30 --- /dev/null +++ b/openair2/LAYER2/MAC/progran_dci_conversions.h @@ -0,0 +1,59 @@ +/******************************************************************************* + 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 dci_conversions.h + * \brief Conversion helpers from progran messages to OAI formats DCI + * \author Xenofon Foukas + * \date 2016 + * \version 0.1 + */ + +#ifndef LAYER2_MAC_PROGRAN_DCI_CONVERISIONS_H__ +#define LAYER2_MAC_DCI_PROGRAN_CONVERISIONS_H__ + +#define FILL_DCI_FDD_1(TYPE, DCI, PROGRAN_DCI) \ + ((TYPE*)DCI)->harq_pid = PROGRAN_DCI->harq_process; \ + ((TYPE*)DCI)->rv = PROGRAN_DCI->rv[0]; \ + ((TYPE*)DCI)->rballoc = PROGRAN_DCI->rb_bitmap; \ + ((TYPE*)DCI)->rah = PROGRAN_DCI->res_alloc; \ + ((TYPE*)DCI)->mcs = PROGRAN_DCI->mcs[0]; \ + ((TYPE*)DCI)->TPC = PROGRAN_DCI->tpc; \ + ((TYPE*)DCI)->ndi = PROGRAN_DCI->ndi[0]; + +#define FILL_DCI_TDD_1(TYPE, DCI, PROGRAN_DCI) \ + ((TYPE*)DCI)->harq_pid = PROGRAN_DCI->harq_process; \ + ((TYPE*)DCI)->rv = PROGRAN_DCI->rv[0]; \ + ((TYPE*)DCI)->dai = PROGRAN_DCI->dai; \ + ((TYPE*)DCI)->rballoc = PROGRAN_DCI->rb_bitmap; \ + ((TYPE*)DCI)->rah = PROGRAN_DCI->res_alloc; \ + ((TYPE*)DCI)->mcs = PROGRAN_DCI->mcs[0]; \ + ((TYPE*)DCI)->TPC = PROGRAN_DCI->tpc; \ + ((TYPE*)DCI)->ndi = PROGRAN_DCI->ndi[0]; + +#endif From a404bfd96cb853a8dc36ab3ad985b54131a3e1c1 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 4 Feb 2016 17:32:37 +0000 Subject: [PATCH 089/413] Refactored eNB agent scheduler code to improve readability --- .../MAC/eNB_agent_scheduler_dataplane.c | 6 +- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 797 ++++++------------ 2 files changed, 264 insertions(+), 539 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c index 6fe11c59cd..04efcb44ad 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c @@ -104,8 +104,8 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, 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,header_len_dtch=0,header_len_dtch_tmp=0, ta_len=0; - unsigned char header_len = 0, header_len_tmp = 0; + unsigned char ta_len=0; + unsigned char header_len = 0, header_len_tmp = 0; unsigned char sdu_lcids[11],offset,num_sdus=0; uint16_t nb_rb,nb_rb_temp,total_nb_available_rb[MAX_NUM_CCs],nb_available_rb; uint16_t TBS,j,sdu_lengths[11],rnti,padding=0,post_padding=0; @@ -252,8 +252,6 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, padding, post_padding); - LOG_D(MAC, "[TEST]Have to schedule %d SDUs with length %d. TBS is %d, LCID is %d, post padding is %d, padding is %d, header offset is %d, total sdu size is %d\n", num_sdus, sdu_lengths[0], TBS, sdu_lcids[0], post_padding, padding, offset, sdu_length_total); - #ifdef DEBUG_eNB_SCHEDULER LOG_T(MAC,"[eNB %d] First 16 bytes of DLSCH : \n"); diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index 6da07ac558..dd0a9942ac 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -90,6 +90,7 @@ schedule_ue_spec_default( unsigned char aggregation; mac_rlc_status_resp_t rlc_status; unsigned char header_len_dcch=0, header_len_dcch_tmp=0, header_len_dtch=0, header_len_dtch_tmp=0, ta_len=0; + unsigned char header_len = 0, header_len_tmp = 0; uint16_t nb_rb, nb_rb_temp, total_nb_available_rb[MAX_NUM_CCs], nb_available_rb; uint16_t TBS, j, rnti, padding=0, post_padding=0; unsigned char round = 0; @@ -102,7 +103,6 @@ schedule_ue_spec_default( eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; UE_list_t *UE_list = &eNB->UE_list; LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; - int continue_flag=0; int32_t normalized_rx_power, target_rx_power; int32_t tpc=1; static int32_t tpc_accumulated=0; @@ -123,6 +123,8 @@ schedule_ue_spec_default( int i; uint32_t data_to_request; uint32_t dci_tbs; + uint8_t ue_has_transmission = 0; + uint32_t ndi; if (UE_list->head==-1) { @@ -172,7 +174,6 @@ schedule_ue_spec_default( continue; for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { - continue_flag=0; // reset the flag to allow allocation for the remaining UEs rnti = UE_RNTI(mod_id, UE_id); eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; @@ -180,13 +181,13 @@ schedule_ue_spec_default( if (rnti==NOT_A_RNTI) { LOG_D(MAC,"Cannot find rnti for UE_id %d (num_UEs %d)\n",UE_id,UE_list->num_UEs); // mac_xface->macphy_exit("Cannot find rnti for UE_id"); - continue_flag=1; + continue; } if (eNB_UE_stats==NULL) { LOG_D(MAC,"[eNB] Cannot find eNB_UE_stats\n"); // mac_xface->macphy_exit("[MAC][eNB] Cannot find eNB_UE_stats\n"); - continue_flag=1; + continue; } if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated @@ -195,7 +196,7 @@ schedule_ue_spec_default( LOG_D(MAC,"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", mod_id, frame, UE_id, CC_id); //if(mac_xface->get_transmission_mode(module_idP,rnti)==5) - continue_flag=1; //to next user (there might be rbs availiable for other UEs in TM5 + continue; //to next user (there might be rbs availiable for other UEs in TM5 // else // break; } @@ -210,17 +211,7 @@ schedule_ue_spec_default( set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe,frame_parms); } - if (continue_flag == 1 ) { - add_ue_dlsch_info(mod_id, - CC_id, - UE_id, - subframe, - S_DL_NONE); - continue; - } - // After this point all the UEs will be scheduled - // TODO create a Protocol__PrpDlData struct for the UE dl_data[num_ues_added] = (Protocol__PrpDlData *) malloc(sizeof(Protocol__PrpDlData)); protocol__prp_dl_data__init(dl_data[num_ues_added]); dl_data[num_ues_added]->has_rnti = 1; @@ -232,8 +223,6 @@ schedule_ue_spec_default( nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; harq_pid = ue_sched_ctl->harq_pid[CC_id]; round = ue_sched_ctl->round[CC_id]; - - sdu_length_total=0; @@ -247,16 +236,13 @@ schedule_ue_spec_default( #ifdef EXMIMO - if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)==5) { + if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti) == 5) { mcs = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; - //eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1,16); + mcs = cmin(mcs,16); } #endif - // store stats - // - // initializing the rb allocation indicator for each UE for(j = 0; j < frame_parms[CC_id]->N_RBG; j++) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0; @@ -295,8 +281,6 @@ schedule_ue_spec_default( CC_id, subframe,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); } - - if (nb_rb <= nb_available_rb) { if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { @@ -318,7 +302,6 @@ schedule_ue_spec_default( nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; } } - j = j + 1; } } @@ -333,171 +316,21 @@ schedule_ue_spec_default( PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; } - switch (mac_xface->get_transmission_mode(mod_id,CC_id,rnti)) { - case 1: - case 2: - default: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t)); - dl_dci->mcs[0] = mcs; - dl_dci->has_tpc = 1; - dl_dci->tpc = 1; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, UE_list->UE_template[CC_id][UE_id].rballoc_subband); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round&3; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->n_tbs_size = 1; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - if (frame_parms[CC_id]->frame_type == TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", - mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); - } else { - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", - mod_id, CC_id, harq_pid, round); - } - break; - case 4: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->n_mcs = 2; - dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->mcs[1] = mcs; - dl_dci->has_tpc = 1; - dl_dci->tpc = 1; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, UE_list->UE_template[CC_id][UE_id].rballoc_subband); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 2; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->ndi[1] = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->n_tbs_size = 2; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - dl_dci->tbs_size[1] = dci_tbs; - dl_dci->n_rv = 2; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round&3; - dl_dci->rv[1] = round&3; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->mcs[1] = mcs; - if (frame_parms[CC_id]->frame_type == TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d\n", - mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); - } else { - LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", - mod_id, CC_id, harq_pid, round); - } - break; - case 5: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t)); - dl_dci->mcs[0] = mcs; - dl_dci->has_tpc = 1; - dl_dci->tpc = 1; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; - dl_dci->n_ndi = 1; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, UE_list->UE_template[CC_id][UE_id].rballoc_subband); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->n_tbs_size = 1; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round&3; + for(i=0; ilte_frame_parms.N_RBG; i++) { + rballoc_sub[i] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][i]; + } - if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { - ue_sched_ctl->dl_pow_off[CC_id] = 1; - } - - dl_dci->has_dl_power_offset = 1; - dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; - - break; - case 6: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t)); - dl_dci->mcs[0] = mcs; - dl_dci->has_tpc = 1; - dl_dci->tpc = 1; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; - dl_dci->n_ndi = 1; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, UE_list->UE_template[CC_id][UE_id].rballoc_subband); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->n_tbs_size = 1; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round&3; - dl_dci->has_dl_power_offset = 1; - dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; - - break; - } - num_ues_added += 1; + ndi = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + tpc = 1; + + ue_has_transmission = 1; + num_ues_added++; } else { LOG_D(MAC,"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", mod_id, frame, CC_id, UE_id); } - + //End of retransmission } else { /* This is a potentially new SDU opportunity */ - rlc_status.bytes_in_buffer = 0; // Now check RLC information to compute number of required RBs // get maximum TBS size for RLC request @@ -505,8 +338,6 @@ schedule_ue_spec_default( TBS = mac_xface->get_TBS_DL(mcs, nb_available_rb); dci_tbs = TBS; - - // check first for RLC data on DCCH // add the length for all the control elements (timing adv, drx, etc) : header + payload @@ -527,154 +358,61 @@ schedule_ue_spec_default( header_len_dcch = 2; // 2 bytes DCCH SDU subheader - // Need to see if we have space for data from this channel - - if ( TBS-ta_len-header_len_dcch > 0 ) { - LOG_D(MAC, "[TEST]Requested %d bytes in DCCH buffer during first call\n", dci_tbs-ta_len-header_len_dcch); - //If we have space, we need to see how much data we can request at most (if any available) - rlc_status = mac_rlc_status_ind(mod_id, - rnti, - mod_id, - frame, - ENB_FLAG_YES, - MBMS_FLAG_NO, - DCCH, - (dci_tbs-ta_len-header_len_dcch)); // transport block set size + // Loop through the UE logical channels (DCCH, DCCH1, DTCH for now) + for (j = 1; j < 4; j++) { + header_len+=3; - //If data are available in the DCCH - if (rlc_status.bytes_in_buffer > 0) { - LOG_D(MAC, "[TEST]Have %d bytes in DCCH buffer during first call\n", rlc_status.bytes_in_buffer); - //Fill in as much as possible - data_to_request = cmin(dci_tbs-ta_len-header_len_dcch, rlc_status.bytes_in_buffer) + 1; - LOG_D(MAC, "[TEST]Will request %d from DCCH\n", data_to_request); - rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); - protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]); - rlc_pdus[channels_added]->n_rlc_pdu_tb = 2; - rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); - rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]); - rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_logical_channel_id = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->logical_channel_id = DCCH; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_size = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = data_to_request; - rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]); - rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_logical_channel_id = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->logical_channel_id = DCCH; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_size = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->size = data_to_request; - dl_data[num_ues_added]->n_rlc_pdu++; - channels_added++; - //Set this to the max value that we might request - sdu_length_total = data_to_request; - } else { - LOG_D(MAC, "[TEST]Nothing here\n"); - header_len_dcch = 0; - sdu_length_total = 0; - } - } + // Need to see if we have space for data from this channel + if (dci_tbs - ta_len - header_len > 0) { + LOG_D(MAC, "[TEST]Requested %d bytes from RLC buffer if channel %d during first call\n", dci_tbs-ta_len-header_len); + //If we have space, we need to see how much data we can request at most (if any available) + rlc_status = mac_rlc_status_ind(mod_id, + rnti, + mod_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + j, + (dci_tbs-ta_len-header_len)); // transport block set size - // check for DCCH1 and update header information (assume 2 byte sub-header) - if (dci_tbs-ta_len-header_len_dcch-sdu_length_total-2 > 0 ) { - LOG_D(MAC, "[TEST]Requested %d bytes in DCCH1 buffer during first call\n", dci_tbs-ta_len-header_len_dcch-sdu_length_total-2); - - //If we have space, we need to see how much data we can request at most (if any are available) - rlc_status = mac_rlc_status_ind(mod_id, - rnti, - mod_id, - frame, - ENB_FLAG_YES, - MBMS_FLAG_NO, - DCCH1, - (dci_tbs-ta_len-header_len_dcch-sdu_length_total-2)); // transport block set size less allocations for timing advance and - // DCCH SDU - - // If data are available in DCCH1 - if (rlc_status.bytes_in_buffer > 0) { - //Add this subheader - header_len_dcch += 2; - - //Fill in as much as possible - data_to_request = cmin(dci_tbs-ta_len-header_len_dcch-sdu_length_total, rlc_status.bytes_in_buffer); - - rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); - protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]); - rlc_pdus[channels_added]->n_rlc_pdu_tb = 2; - rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); - rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]); - rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_logical_channel_id = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->logical_channel_id = DCCH1; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_size = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = data_to_request; - rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]); - rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_logical_channel_id = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->logical_channel_id = DCCH1; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_size = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->size = data_to_request; - dl_data[num_ues_added]->n_rlc_pdu++; - channels_added++; - sdu_length_total += data_to_request; - } - } - - // check for DTCH and update header information - // here we should loop over all possible DTCH - - header_len_dtch = 3; // Assume max 3 bytes DTCH SDU subheader - - LOG_D(MAC,"[eNB %d], Frame %d, DTCH->DLSCH, CC_id %d, Checking RLC status (rab %d, tbs %d, len %d)\n", - mod_id, frame, CC_id, DTCH, TBS, - dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); - - if (dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch > 0 ) { - - LOG_D(MAC, "[TEST] This is how much we request at most during first call %d\n", dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); - - //If we have space, we need to see how much data we can request at most (if any are available) - rlc_status = mac_rlc_status_ind(mod_id, - rnti, - mod_id, - frame, - ENB_FLAG_YES, - MBMS_FLAG_NO, - DTCH, - dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); - - // If data are available in DTCH - if (rlc_status.bytes_in_buffer > 0) { - LOG_D(MAC, "[TEST] Have %d bytes in buffer DTCH during first call\n", rlc_status.bytes_in_buffer); - //Fill what remains in the TB - data_to_request = cmin(dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch, rlc_status.bytes_in_buffer); - LOG_D(MAC, "[TEST]Will request %d \n", data_to_request); - rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); - protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]); - rlc_pdus[channels_added]->n_rlc_pdu_tb = 2; - rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); - rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]); - rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_logical_channel_id = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->logical_channel_id = DTCH; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_size = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = data_to_request; - rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]); - rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_logical_channel_id = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->logical_channel_id = DTCH; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_size = 1; - rlc_pdus[channels_added]->rlc_pdu_tb[1]->size = data_to_request; - dl_data[num_ues_added]->n_rlc_pdu++; - channels_added++; - sdu_length_total += data_to_request; - - if(data_to_request < 128) { - header_len_dtch = 2; - } - } else { - header_len_dtch = 0; - } - } + //If data are available in channel j + if (rlc_status.bytes_in_buffer > 0) { + LOG_D(MAC, "[TEST]Have %d bytes in DCCH buffer during first call\n", rlc_status.bytes_in_buffer); + //Fill in as much as possible + data_to_request = cmin(dci_tbs-ta_len-header_len, rlc_status.bytes_in_buffer); + if (data_to_request < 128) { //The header will be one byte less + header_len--; + } + if (j == 1) { + data_to_request++; //It is not correct but fixes some RLC bug for DCCH + } + LOG_D(MAC, "[TEST]Will request %d from DCCH\n", data_to_request); + rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); + protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]); + rlc_pdus[channels_added]->n_rlc_pdu_tb = 2; + rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); + rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]); + rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_logical_channel_id = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[0]->logical_channel_id = j; + rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_size = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = data_to_request; + rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]); + rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_logical_channel_id = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[1]->logical_channel_id = j; + rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_size = 1; + rlc_pdus[channels_added]->rlc_pdu_tb[1]->size = data_to_request; + dl_data[num_ues_added]->n_rlc_pdu++; + channels_added++; + //Set this to the max value that we might request + sdu_length_total = data_to_request; + } else { + //Take back the assumption of a header for this channel + header_len -= 3; + } //End rlc_status.bytes_in_buffer <= 0 + } //end of if dci_tbs - ta_len - header_len > 0 + } // End of iterating the logical channels // Add rlc_pdus to the dl_data message dl_data[num_ues_added]->rlc_pdu = (Protocol__PrpRlcPdu **) malloc(sizeof(Protocol__PrpRlcPdu *) * @@ -688,17 +426,15 @@ schedule_ue_spec_default( // 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; + header_len_tmp = header_len; - if (header_len_dtch == 0) { - header_len_dcch = (header_len_dcch > 0) ? (header_len_dcch - 1) : header_len_dcch; // remove length field - } else { - header_len_dtch = (header_len_dtch > 0) ? 1 : header_len_dtch; // remove length field for the last SDU - } + if (header_len == 2 || header_len == 3) { //Only one SDU, remove length field + header_len = 1; + } else { //Remove length field from the last SDU + header_len--; + } mcs_tmp = mcs; - if (mcs_tmp == 0) { nb_rb = 4; // don't let the TBS get too small } else { @@ -711,7 +447,7 @@ schedule_ue_spec_default( TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); LOG_D(MAC,"[TEST]The TBS during rate matching was %d\n", TBS); - while (TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) { + while (TBS < (sdu_length_total + header_len + ta_len)) { nb_rb += min_rb_unit[CC_id]; // LOG_D(MAC, "[TEST]Had to increase the number of RBs\n"); if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs @@ -724,9 +460,6 @@ schedule_ue_spec_default( TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); } - LOG_D(MAC,"[TEST] After the first pass the resource blocks became %d\n", nb_rb); - LOG_D(MAC,"[TEST] After the first pass the MCS was %d\n", mcs_tmp); - if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { LOG_D(MAC, "[TEST]We had the exact number of rbs. Time to fill the rballoc subband\n"); for(j = 0; j < frame_parms[CC_id]->N_RBG; j++) { // for indicating the rballoc for each sub-band @@ -747,13 +480,9 @@ schedule_ue_spec_default( nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; } } - j = j+1; } } - - LOG_D(MAC,"[TEST] After the second pass the resource blocks became %d\n", nb_rb); - LOG_D(MAC,"[TEST] After the second pass the mcs was %d\n", mcs_tmp); PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; @@ -763,22 +492,19 @@ schedule_ue_spec_default( } // decrease mcs until TBS falls below required length - while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs_tmp > 0)) { + while ((TBS > (sdu_length_total + header_len + ta_len)) && (mcs_tmp > 0)) { mcs_tmp--; TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); } // if we have decreased too much or we don't have enough RBs, increase MCS - while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && + while ((TBS < (sdu_length_total + header_len + ta_len)) && ((( ue_sched_ctl->dl_pow_off[CC_id] > 0) && (mcs_tmp < 28)) || ( (ue_sched_ctl->dl_pow_off[CC_id]==0) && (mcs_tmp <= 15)))) { mcs_tmp++; TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb); } - LOG_D(MAC,"[TEST] dlsch_mcs and TBS before and after the rate matching = (%d, %d) (%d, %d)\n", mcs, mcs_tmp, dci_tbs, TBS); - dci_tbs = TBS; - mcs = mcs_tmp; aggregation = process_ue_cqi(mod_id,UE_id); @@ -787,12 +513,6 @@ schedule_ue_spec_default( UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; - /*Deactivate here as well*/ - /* add_ue_dlsch_info(mod_id, */ - /* CC_id, */ - /* UE_id, */ - /* subframe, */ - /* S_DL_SCHEDULED); */ if (frame_parms[CC_id]->frame_type == TDD) { UE_list->UE_template[CC_id][UE_id].DAI++; @@ -840,183 +560,10 @@ schedule_ue_spec_default( for(i=0; ilte_frame_parms.N_RBG; i++) { rballoc_sub[i] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][i]; - } - - switch (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)) { - case 1: - case 2: - default: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 1; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = 0; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->n_tbs_size = 1; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - if (frame_parms[CC_id]->frame_type == TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - break; - case 3: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 2; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->ndi[1] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->n_rv = 2; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = 0; - dl_dci->rv[1] = 0; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 2; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->mcs[1] = mcs; - dl_dci->n_tbs_size = 2; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - dl_dci->tbs_size[1] = dci_tbs; - if (frame_parms[CC_id]->frame_type == TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - break; - case 4: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 2; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->ndi[1] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->n_rv = 2; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = 0; - dl_dci->rv[1] = 0; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 2; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->mcs[1] = mcs; - dl_dci->n_tbs_size = 2; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - dl_dci->tbs_size[1] = dci_tbs; - if (frame_parms[CC_id]->frame_type == TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - break; - case 5: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 1; - dl_dci->ndi = 1; - dl_dci->ndi[0] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = 0; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - dl_dci->n_tbs_size = 1; - dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); - dl_dci->tbs_size[0] = dci_tbs; - if (frame_parms[CC_id]->frame_type == TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - - if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { - ue_sched_ctl->dl_pow_off[CC_id] = 1; - } - - dl_dci->has_dl_power_offset = 1; - dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; - dl_dci->has_precoding_info = 1; - dl_dci->precoding_info = 5; // Is this right?? - - break; - case 6: - dl_dci->has_res_alloc = 1; - dl_dci->res_alloc = 0; - dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; - dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; - dl_dci->has_rb_bitmap = 1; - dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); - dl_dci->has_rb_shift = 1; - dl_dci->rb_shift = 0; - dl_dci->n_ndi = 1; - dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); - dl_dci->ndi[0] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - dl_dci->n_rv = 1; - dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); - dl_dci->rv[0] = round&3; - dl_dci->has_tpc = 1; - dl_dci->tpc = tpc; - dl_dci->n_mcs = 1; - dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); - dl_dci->mcs[0] = mcs; - if (frame_parms[CC_id]->frame_type == TDD) { - dl_dci->has_dai = 1; - dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - } - - dl_dci->has_dl_power_offset = 1; - dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; - dl_dci->has_precoding_info = 1; - dl_dci->precoding_info = 5; // Is this right?? - break; - } + } + ndi = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + // Toggle NDI for next time LOG_D(MAC,"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", CC_id, frame, subframe, UE_id, @@ -1025,10 +572,190 @@ schedule_ue_spec_default( // Increase the pointer for the number of scheduled UEs num_ues_added++; + ue_has_transmission = 1; } else { // There is no data from RLC or MAC header, so don't schedule + ue_has_transmission = 0; + } + } // End of new scheduling + + // If we has transmission or retransmission + if (ue_has_transmission) { + switch (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)) { + case 1: + case 2: + default: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = ndi; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->n_tbs_size = 1; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + } + break; + case 3: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 2; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = ndi; + dl_dci->ndi[1] = ndi; + dl_dci->n_rv = 2; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->rv[1] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 2; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->mcs[1] = mcs; + dl_dci->n_tbs_size = 2; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + dl_dci->tbs_size[1] = dci_tbs; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + } + break; + case 4: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 2; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = ndi; + dl_dci->ndi[1] = ndi; + dl_dci->n_rv = 2; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->rv[1] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 2; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->mcs[1] = mcs; + dl_dci->n_tbs_size = 2; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + dl_dci->tbs_size[1] = dci_tbs; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + } + break; + case 5: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi = 1; + dl_dci->ndi[0] = ndi; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->n_tbs_size = 1; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); + dl_dci->tbs_size[0] = dci_tbs; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + } + + if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { + ue_sched_ctl->dl_pow_off[CC_id] = 1; + } + + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; + dl_dci->has_precoding_info = 1; + dl_dci->precoding_info = 5; // Is this right?? + + break; + case 6: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = ndi; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round & 3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + } + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; + dl_dci->has_precoding_info = 1; + dl_dci->precoding_info = 5; // Is this right?? + break; } } + if (frame_parms[CC_id]->frame_type == TDD) { set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe, frame_parms); } From bb874258980e9bb70cbb81b5cf2d676d56f933c7 Mon Sep 17 00:00:00 2001 From: Navid Nikaein Date: Sat, 6 Feb 2016 09:31:33 +0100 Subject: [PATCH 090/413] add eNB agent libs to lte-softmodem --- cmake_targets/CMakeLists.txt | 8 ++++---- openair2/ENB_APP/enb_agent_handler.c | 10 +++++----- openair2/LAYER2/MAC/eNB_scheduler.c | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index b555f67ebc..8631fe92a5 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1512,12 +1512,12 @@ add_executable(lte-softmodem target_link_libraries (lte-softmodem -Wl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} + RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} -Wl,--end-group ) target_link_libraries (lte-softmodem ${LIBXML2_LIBRARIES}) -target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${option_HW_lib} ${XFORMS_LIBRARIES} ) +target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${option_HW_lib} ${XFORMS_LIBRARIES} ${PROTOBUF_LIB}) target_link_libraries (lte-softmodem ${LIBBOOST_LIBRARIES}) # lte-softmodem-nos1 is both eNB and UE implementation @@ -1545,11 +1545,11 @@ add_executable(lte-softmodem-nos1 ) target_link_libraries (lte-softmodem-nos1 -Wl,--start-group - RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${MIH_LIB} + RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} -Wl,--end-group ) target_link_libraries (lte-softmodem-nos1 ${LIBXML2_LIBRARIES}) -target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib} ${XFORMS_LIBRARIES} ) +target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib} ${XFORMS_LIBRARIES} ${PROTOBUF_LIB}) target_link_libraries (lte-softmodem-nos1 ${LIBBOOST_LIBRARIES}) diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 3e9752b539..4894683723 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -41,7 +41,7 @@ #include "assertions.h" -enb_agent_message_decoded_callback messages_callback[][3] = { +enb_agent_message_decoded_callback agent_messages_callback[][3] = { {enb_agent_hello, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG*/ {enb_agent_echo_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REQUEST_MSG*/ {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG*/ //Must add handler when receiving echo reply @@ -85,19 +85,19 @@ Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, goto error; } - if ((decoded_message->msg_case > sizeof(messages_callback) / (3*sizeof(enb_agent_message_decoded_callback))) || + if ((decoded_message->msg_case > sizeof(agent_messages_callback) / (3*sizeof(enb_agent_message_decoded_callback))) || (decoded_message->msg_dir > PROTOCOL__PROGRAN_DIRECTION__UNSUCCESSFUL_OUTCOME)){ err_code= PROTOCOL__PROGRAN_ERR__MSG_NOT_HANDLED; goto error; } - if (messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1] == NULL) { + if (agent_messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1] == NULL) { err_code= PROTOCOL__PROGRAN_ERR__MSG_NOT_SUPPORTED; goto error; } - err_code = ((*messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1])(mod_id, (void *) decoded_message, &reply_message)); + err_code = ((*agent_messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1])(mod_id, (void *) decoded_message, &reply_message)); if ( err_code < 0 ){ goto error; } @@ -147,7 +147,7 @@ Protocol__ProgranMessage *enb_agent_handle_timed_task(void *args) { Protocol__ProgranMessage *timed_task, *reply_message; timed_task = timer_args->msg; - err_code = ((*messages_callback[timed_task->msg_case-1][timed_task->msg_dir-1])(timer_args->mod_id, (void *) timed_task, &reply_message)); + err_code = ((*agent_messages_callback[timed_task->msg_case-1][timed_task->msg_dir-1])(timer_args->mod_id, (void *) timed_task, &reply_message)); if ( err_code < 0 ){ goto error; } diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index fec058b27e..54b31b6e64 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -60,9 +60,9 @@ #include "pdcp.h" //Agent-related headers -#include "ENB_APP/enb_agent_extern.h" -#include "ENB_APP/enb_agent_mac.h" -#include "LAYER2/MAC/enb_agent_mac_proto.h" +#include "enb_agent_extern.h" +#include "enb_agent_mac.h" +#include "enb_agent_mac_proto.h" #if defined(ENABLE_ITTI) # include "intertask_interface.h" From a0289d74fa610bd73ac2bb79d20da8bc8a685411 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 9 Feb 2016 13:03:31 +0000 Subject: [PATCH 091/413] Added support for eNB, cell, UE and logical channel configuration messages to the progRAN protocol --- cmake_targets/CMakeLists.txt | 4 + .../ENB_APP/MESSAGES/V2/config_common.proto | 174 ++++++++++++++++++ .../ENB_APP/MESSAGES/V2/config_messages.proto | 88 +++++++++ openair2/ENB_APP/MESSAGES/V2/header.proto | 12 +- openair2/ENB_APP/MESSAGES/V2/progran.proto | 40 +++- 5 files changed, 315 insertions(+), 3 deletions(-) create mode 100644 openair2/ENB_APP/MESSAGES/V2/config_common.proto create mode 100644 openair2/ENB_APP/MESSAGES/V2/config_messages.proto diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 8631fe92a5..93aa36c727 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -713,6 +713,8 @@ if (ENB_AGENT_SB_IF) ${PRPT_MSG_DIR}/time_common.proto ${PRPT_MSG_DIR}/controller_commands.proto ${PRPT_MSG_DIR}/mac_primitives.proto + ${PRPT_MSG_DIR}/config_messages.proto + ${PRPT_MSG_DIR}/config_common.proto ) set(PRPT_C_DIR ${protobuf_generated_dir}/${PRPTDIR}) @@ -727,6 +729,8 @@ if (ENB_AGENT_SB_IF) ${PRPT_C_DIR}/time_common.pb-c.c ${PRPT_C_DIR}/controller_commands.pb-c.c ${PRPT_C_DIR}/mac_primitives.pb-c.c + ${PRPT_C_DIR}/config_messages.pb-c.c + ${PRPT_C_DIR}/config_common.pb-c.c ) file(GLOB prpt_h ${PRPT_C_DIR}/*.h) diff --git a/openair2/ENB_APP/MESSAGES/V2/config_common.proto b/openair2/ENB_APP/MESSAGES/V2/config_common.proto new file mode 100644 index 0000000000..ab6e8b8c22 --- /dev/null +++ b/openair2/ENB_APP/MESSAGES/V2/config_common.proto @@ -0,0 +1,174 @@ +//'syntax = "proto2";' +package protocol; + +// +// Cell config related structures and enums +// + +message prp_si_config { + optional uint32 sfn = 1; + optional uint32 sib1_length = 2; // The length of SIB1 in bytes + optional uint32 si_window_length = 3; // The scheduling window for all SIs in SF + repeated prp_si_message si_message = 4; // List of SI messages to be sent. + // The index identifies the type of an SI message + // 0 - SIB1 + // 1..31 - SIx + // 32..63 - PCCH +} + +message prp_si_message { + optional uint32 periodicity = 1; // Periodicity of SI msg in radio frames + optional uint32 length = 2; // The length of the SI message in bytes +} + +enum prp_hopping_mode { + PRHM_INTER = 0; + PRHM_INTERINTRA = 1; +} + +enum prp_phich_resource { + PRPR_ONE_SIXTH = 0; + PRPR_HALF = 1; + PRPR_ONE = 2; + PRPR_TWO = 3; +} + +enum prp_phich_duration { + PRPD_NORMAL = 0; + PRPD_EXTENDED = 1; +} + +enum prp_ul_cyclic_prefix_length { + PRUCPL_NORMAL = 0; + PRUCPL_EXTENDED = 1; +} + +enum prp_dl_cyclic_prefix_length { + PRDCPL_NORMAL = 0; + PRDCPL_EXTENDED = 1; +} + +enum prp_duplex_mode { + PRDM_TDD = 0; + PRDM_FDD = 1; +} + +enum prp_qam { + PREQ_MOD_16QAM = 0; + PREQ_MOD_64QAM = 1; +} + +// +// UE config related structures and enums +// + +message prp_drx_config { + optional uint32 on_duration_timer = 1; // Timer in SF. See TS 36.321 + optional uint32 drx_inactivity_timer = 2; // Timer in SF. See TS 36.321 + optional uint32 drx_retransmission_timer = 3; // Timer in SF. See TS 36.321 + optional uint32 long_drx_cycle = 4; // In SF. See TS 36.321 + optional uint32 long_drx_cycle_start_offset = 5;// See TS 36.321 + optional uint32 short_drx_cycle = 6; // In SF + optional uint32 drx_short_cycle_timer = 7; // Timer in subframes. See TS 36.321 +} + +message prp_sps_config { + optional uint32 semi_persistent_sched_interval_UL = 1; // SPS UL scheduling interval in SF + optional uint32 semi_persistent_sched_interval_DL = 2; // SPS DL scheduling interval in SF + optional uint32 num_of_conf_sps_proc = 3; // Number of SPS HARQ processes. See TS 36.321 + repeated uint32 n1_PUCCH_AN_persistent_element = 4;// See TS36.213. Ignored when config is used + // as part of PRPT_SET_UE_CONFIG + optional uint32 implicit_release_after = 5; // number of empty transmissions before release of SPS +} + +message prp_sr_config { + optional uint32 sr_action = 1; // Indicates if SR config should be changed or released + // One of the PRSRA_* enum values + optional uint32 sched_interval = 2; // SR scheduling interval in SF + optional uint32 dsr_trans_max = 3; // See TS 36.213 +} + +message prp_cqi_config { + optional uint32 cqi_action = 1; // Indicats if CQI changed or released. + // One of the PRSRA_* enum values + optional uint32 cqi_sched_interval = 2; // CQI scheduling interval in SF + optional uint32 ri_sched_interval = 3; // RI scheduling interval in SF +} + +message prp_ue_capabilities { + optional uint32 half_duplex = 1; // Boolean value. Only half duplex support. FDD operation + optional uint32 intra_SF_hopping = 2; // Support for intra-subframe hopping. Boolean value + optional uint32 type2_sb_1 = 3; // Support for type 2 hopping with n_sb > 1 + optional uint32 ue_category = 4; + optional uint32 res_alloc_type1 = 5; // Boolean value. UE support for resource allocation type 1 +} + +message prp_scell_config { + optional uint32 carrier_index = 1; // Id of the carrier component + optional uint32 scell_index = 2; // Index of this Scell (RRC SCellIndex) + optional uint32 use_ccs = 3; // Boolean value. Indicates if cross-carrier scheduling + // is used by this SCell + optional uint32 sched_cell_index = 4; // Index of the cell responsible for scheduling + // this SCell if cross-carrier scheduling is enabled + optional uint32 pdsch_start = 5; // Starting OFDM symbol of PDSCH data region for this SCell +} + +enum prp_meas_gap_config_pattern { + PRMGCP_GP1 = 0; + PRMGCP_GP2 = 1; + PRMGCP_OFF = 2; +} + +enum prp_setup_release_action { + PRSRA_SETUP = 0; + PRSRA_RELEASE = 1; +} + +enum prp_ue_transmission_antenna { + PRUTA_NONE = 0; + PRUTA_OPEN_LOOP = 1; + PRUTA_CLOSED_LOOP = 2; +} + +enum prp_aperiodic_cqi_report_mode { + PRACRM_RM12 = 0; + PRACRM_RM20 = 1; + PRACRM_RM22 = 2; + PRACRM_RM30 = 3; + PRACRM_RM31 = 4; + PRACRM_NONE = 5; +} + +enum prp_tdd_ack_nack_feedback_mode { + PRTANFM_BUNDLING = 0; + PRTANFM_MULTIPLEXING = 1; +} + +// +// Logical channel config related structures and enums +// + +message prp_lc_config { + optional uint32 lcid = 1; // The logical channel id + optional uint32 lcg = 2; // The logical channel group (0..3) the LC is mapped to + optional uint32 direction = 3; // The LC direction. One of the PRLCD_* enum values + optional uint32 qos_bearer_type = 4;// GBR or NGBR bearer. One of the PRQBT_* enum values + optional uint32 qci = 5; // The QCI defined in TS 23.203, coded as defined in TS 36.413 + // One less than the actual QCI value + optional uint64 e_RAB_max_bitrate_UL = 6; // In bps (GBR only) + optional uint64 e_RAB_max_bitrate_DL = 7; // In bps (GBR only) + optional uint64 e_RAB_guaranteed_bitrate_UL = 8; // In bps (GBR only) + optional uint64 e_RAB_guranteed_bitrate_DL = 9; // In bps (GBR only) +} + +enum prp_lc_direction { + PRLCD_UL = 0; + PRLCD_DL = 1; + PRLCD_BOTH = 2; +} + +enum prp_qos_bearer_type { + PRQBT_NON_GBR = 0; + PRQBT_GBR = 1; +} + diff --git a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto new file mode 100644 index 0000000000..4e1151a7e8 --- /dev/null +++ b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto @@ -0,0 +1,88 @@ +//'syntax = "proto2";' +package protocol; + +import "config_common.proto"; + +message prp_cell_config { + optional uint32 phy_cell_id = 1; // The PCI of this cell + optional uint32 cell_id = 2; // The PLMN cell id of this cell + optional uint32 pusch_hopping_offset = 3; // PUSCH resources in RBs for hopping + optional uint32 hopping_mode = 4; // One of the PRHM_* enum values + optional uint32 n_sb = 5; // The number of subbands + optional uint32 phich_resource = 6; // The number of REGs used for PHICH + // One of the PRPR_* enum values + optional uint32 phich_duration = 7; // One of the PRPD_* enum values + optional uint32 init_nr_PDCCH_OFDM_sym = 8; // See TS 36.211, section 6.9 + optional prp_si_config si_config = 9; // The SI configuration + optional uint32 dl_bandwidth = 10; // The DL transmission bandwidth in RBs + optional uint32 ul_bandwidth = 11; // The UL transmission bandwidth in RBs + optional uint32 ul_cyclic_prefix_length = 13; // One of the PRUCPL_* enum values + optional uint32 dl_cyclic_prefix_length = 14; // One of the PRDCPL_* enum values + optional uint32 antenna_ports_count = 15; // Number of cell specific antenna ports + optional uint32 duplex_mode = 16; // One of the PRDM_* enum values + optional uint32 subframe_assignment = 17; // DL/UL subframe assignment. TDD only + optional uint32 special_subframe_patterns = 18; // TDD only. See TS 36.211, table 4.2.1 + repeated uint32 mbsfn_subframe_config_rfperiod = 19; // The MBSFN radio frame period (Optional) + repeated uint32 mbsfn_subframe_config_rfoffset = 20; // The radio frame offset (Optional) + repeated uint32 mbsfn_subframe_config_sfalloc = 21; // Bitmap indicating the MBSFN subframes (Optional) + optional uint32 prach_config_index = 22; // See TS 36.211, section 5.7.1 + optional uint32 prach_freq_offset = 23; // See TS 36.211, section 5.7.1 + optional uint32 ra_response_window_size = 24; // The duration of the RA response window in SF + optional uint32 mac_contention_resolution_timer = 25; // Timer for RA + optional uint32 max_HARQ_Msg3Tx = 26; // See TS 36.321 + optional uint32 n1PUCCH_AN = 27; // See TS 36.213, section 10.1 + optional uint32 deltaPUCCH_shift = 28; // See TS 36.211, section 5.4 + optional uint32 nRB_cqi = 29; // See TS 36.211, section 5.4 + optional uint32 srs_subframe_config = 30; // See TS 36.211, table 5.5.3.3-1 and 2 + optional uint32 srs_bw_config = 31; // See TS 36.211, section 5.5.3.2 + optional uint32 srs_mac_up_pts = 32; // Boolean value. See TS 36.211, section 5.5.3.2. TDD only + optional uint32 enable_64QAM = 33; // One of the PREQ_* enum values + optional uint32 carrier_index = 34; // Carrier component index +} + +message prp_ue_config { + optional uint32 rnti = 1; + optional prp_drx_config drx_config = 2; // The DRX configuration (Optional) + optional uint32 time_alignment_timer = 3; // Timer in SF. Control the synchronization + // status of the UE, not the actual advance procedure + // See TS 36.321 + optional uint32 meas_gap_config_pattern = 4; // Measurement gap configuration. + // One of the PRMGCP_* enum values + // See TS 36.133 + optional uint32 meas_gap_config_sf_offset = 5; // Measurement gap offset if applicable + optional prp_sps_config sps_config = 6; // The SPS configuration (Optional) + optional prp_sr_config sr_config = 7; // The SR configuration (Optional) + optional prp_cqi_config cqi_config = 8; // The CQI configuration (Optional) + optional uint32 transmission_mode = 9; // The UE transmission mode + optional uint64 ue_aggregated_max_bitrate_UL = 10; // Aggregated bit-rate of non-gbr bearer + // per UE. See TS 36.413 + optional uint64 ue_aggregated_max_bitrate_DL = 11; // Aggregated bit-rate of non-gbr bearer + // per UE. See TS 36.413 + optional prp_ue_capabilities capabilities = 12; + optional uint32 ue_transmission_antenna = 13; // One of the PRUTA_* enum values + optional uint32 tti_bundling = 14; // Boolean value. See TS 36.321 + optional uint32 max_HARQ_tx = 15; // The max HARQ retransmission for UL + optional uint32 beta_offset_ACK_index = 16; // See TS 36.213 + optional uint32 beta_offset_RI_index = 17; // See TS 36.213 + optional uint32 beta_offset_CQI_index = 18; // See TS 36.213 + optional uint32 ack_nack_simultaneous_trans = 19;// Boolean. See TS 36.213 + optional uint32 simultaneous_ack_nack_cqi = 20; // Boolean. See TS 36.213 + optional uint32 aperiodic_cqi_rep_mode = 21; // One of the PRACRM_* enum values + optional uint32 tdd_ack_nack_feedback = 22; // One of the PRTANFM_* enum values + optional uint32 ack_nack_repetition_factor = 23;// See TS 36.213, section 10.1 + optional uint32 extended_bsr_size = 24; // Boolean for extended BSR size + optional uint32 ca_support = 25; // Boolean. Support for carrier aggregation + optional uint32 cross_carrier_sched_support = 26; // Boolean value + optional uint32 pcell_carrier_index = 27; // Index of primary cell + repeated prp_scell_config scell_config = 28; // Secondary cells configuration + optional uint32 scell_deactivation_timer = 29;// Deactivation timer for secondary cell +} + +message prp_lc_ue_config { + optional uint32 rnti = 1; + repeated prp_lc_config lc_config = 2; // A list of LC configurations for the given UE +} + + + + diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index 10a18ddcef..be0341f132 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -19,10 +19,18 @@ enum prp_type { // Time indication messages PRPT_SF_TRIGGER = 5; - //Asynchronous messages + // Asynchronous messages PRPT_UL_SR_INFO = 6; + // eNB configuration messages + PRPT_GET_ENB_CONFIG_REQUEST = 7; + PRPT_GET_ENB_CONFIG_REPLY = 8; + PRPT_GET_UE_CONFIG_REQUEST = 9; + PRPT_GET_UE_CONFIG_REPLY = 10; + PRPT_GET_LC_CONFIG_REQUEST = 11; + PRPT_GET_LC_CONFIG_REPLY = 12; + //Controller command messages - PRPT_DL_MAC_CONFIG = 7; + PRPT_DL_MAC_CONFIG = 13; } diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index 5d0ec15518..f1178c0f57 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -4,6 +4,7 @@ package protocol; import "stats_messages.proto"; import "header.proto"; import "time_common.proto"; +import "config_messages.proto"; import "controller_commands.proto"; message progran_message { @@ -16,7 +17,13 @@ message progran_message { prp_stats_reply stats_reply_msg = 5; prp_sf_trigger sf_trigger_msg = 6; prp_ul_sr_info ul_sr_info_msg = 7; - prp_dl_mac_config dl_mac_config_msg = 8; + prp_enb_config_request enb_config_request = 8; + prp_enb_config_reply enb_config_reply = 9; + prp_ue_config_request ue_config_request = 10; + prp_ue_config_reply ue_config_reply = 11; + prp_lc_config_request lc_config_request = 12; + prp_lc_config_reply lc_config_reply = 13; + prp_dl_mac_config dl_mac_config_msg = 14; } } @@ -108,6 +115,37 @@ message prp_ul_sr_info { repeated uint32 rnti = 3; } +// +// eNB configuration messages +// +message prp_enb_config_request { + optional prp_header header = 1; +} + +message prp_enb_config_reply { + optional prp_header header = 1; + optional uint32 eNB_id = 2; // Unique id to distinguish the eNB + repeated prp_cell_config cell_config = 3; +} + +message prp_ue_config_request { + optional prp_header header = 1; +} + +message prp_ue_config_reply { + optional prp_header header = 1; + repeated prp_ue_config ue_config = 2; +} + +message prp_lc_config_request { + optional prp_header header = 1; +} + +message prp_lc_config_reply { + optional prp_header header = 1; + repeated prp_lc_ue_config lc_ue_config = 2; +} + // // Controller command messages // From ff72fbc6bcaf916eb177e0ef40cb3630bdbbfc8e Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 9 Feb 2016 13:33:48 +0000 Subject: [PATCH 092/413] Integrated progRAN config messages to OAI agent and created stubs for handler and destructor functions --- openair2/ENB_APP/MESSAGES/V2/progran.proto | 12 +++--- openair2/ENB_APP/enb_agent_common.c | 45 ++++++++++++++++++++++ openair2/ENB_APP/enb_agent_common.h | 15 ++++++++ openair2/ENB_APP/enb_agent_handler.c | 16 +++++++- 4 files changed, 80 insertions(+), 8 deletions(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index f1178c0f57..2bcf9bbc95 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -17,12 +17,12 @@ message progran_message { prp_stats_reply stats_reply_msg = 5; prp_sf_trigger sf_trigger_msg = 6; prp_ul_sr_info ul_sr_info_msg = 7; - prp_enb_config_request enb_config_request = 8; - prp_enb_config_reply enb_config_reply = 9; - prp_ue_config_request ue_config_request = 10; - prp_ue_config_reply ue_config_reply = 11; - prp_lc_config_request lc_config_request = 12; - prp_lc_config_reply lc_config_reply = 13; + prp_enb_config_request enb_config_request_msg = 8; + prp_enb_config_reply enb_config_reply_msg = 9; + prp_ue_config_request ue_config_request_msg = 10; + prp_ue_config_reply ue_config_reply_msg = 11; + prp_lc_config_request lc_config_request_msg = 12; + prp_lc_config_reply lc_config_reply_msg = 13; prp_dl_mac_config dl_mac_config_msg = 14; } } diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index ab9546036f..7c820bfa5c 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -261,6 +261,51 @@ int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg) { return -1; } +int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { + /* TODO: Create a reply progRAN message with the current eNB configuration */ + return 0; +} + +int enb_agent_destroy_enb_config_reply(Protocol__ProgranMessage *msg) { + /* TODO: Deallocate memory for a dynamically allocated eNB config message */ + return 0; +} + +int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { + /* TODO: Create a reply progRAN message with the current UE configurations */ + return 0; +} + +int enb_agent_destroy_ue_config_reply(Protocol__ProgranMessage *msg) { + /*TODO: Deallocate memory for a dynamically allocated UE config message */ + return 0; +} + +int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { + /* TODO: Create a reply progRAN message with the current LC configurations */ + return 0; +} + +int enb_agent_destroy_lc_config_reply(Protocol__ProgranMessage *msg) { + /* TODO: Deallocate memory for a dynamically allocated LC config message */ + return 0; +} + +int enb_agent_destroy_enb_config_request(Protocol__ProgranMessage *msg) { + /* TODO: Deallocate memory for a dynamically allocated eNB config message */ + return 0; +} + +int enb_agent_destroy_ue_config_request(Protocol__ProgranMessage *msg) { + /* TODO: Deallocate memory for a dynamically allocated UE config message */ + return 0; +} + +int enb_agent_destroy_lc_config_request(Protocol__ProgranMessage *msg) { + /* TODO: Deallocate memory for a dynamically allocated LC config message */ + return 0; +} + /* * get generic info from RAN */ diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 4762637b66..afa2179ff4 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -91,6 +91,21 @@ int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg); int enb_agent_echo_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg); +int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_destroy_enb_config_reply(Protocol__ProgranMessage *msg); + +int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_destroy_ue_config_reply(Protocol__ProgranMessage *msg); + +int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_destroy_lc_config_reply(Protocol__ProgranMessage *msg); + +int enb_agent_destroy_enb_config_request(Protocol__ProgranMessage *msg); + +int enb_agent_destroy_ue_config_request(Protocol__ProgranMessage *msg); + +int enb_agent_destroy_lc_config_request(Protocol__ProgranMessage *msg); + Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, uint8_t *data, diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 4894683723..9815732088 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -48,8 +48,14 @@ enb_agent_message_decoded_callback agent_messages_callback[][3] = { {enb_agent_mac_handle_stats, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG*/ {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG*/ {0, 0, 0}, /*PROTOCOK__PROGRAN_MESSAGE__MSG_SF_TRIGGER_MSG*/ - {0, 0, 0}, /*SR_INFO*/ - {0, 0, 0}, /*DL_MAC_CONFIG*/ + {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_UL_SR_INFO_MSG*/ + {enb_agent_enb_config_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG*/ + {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG*/ + {enb_agent_ue_config_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_UE_CONFIG_REQUEST_MSG*/ + {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG*/ + {enb_agent_lc_config_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REQUEST_MSG*/ + {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG*/ + {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG*/ }; @@ -61,6 +67,12 @@ enb_agent_message_destruction_callback message_destruction_callback[] = { enb_agent_mac_destroy_stats_reply, enb_agent_mac_destroy_sf_trigger, enb_agent_mac_destroy_sr_info, + enb_agent_destroy_enb_config_request, + enb_agent_destroy_enb_config_reply, + enb_agent_destroy_ue_config_request, + enb_agent_destroy_ue_config_reply, + enb_agent_destroy_lc_config_request, + enb_agent_destroy_lc_config_reply, enb_agent_mac_destroy_dl_config, }; From 8aff18aed5b23c2500c3a5c7cd346cf2a06de131 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 9 Feb 2016 17:53:49 +0000 Subject: [PATCH 093/413] Fixed bug with toggling the NDI for DL HARQ retransmissions --- openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index dd0a9942ac..4d353232a8 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -320,6 +320,7 @@ schedule_ue_spec_default( rballoc_sub[i] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][i]; } + // Keep the old NDI, do not toggle ndi = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; tpc = 1; @@ -562,13 +563,12 @@ schedule_ue_spec_default( rballoc_sub[i] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][i]; } - ndi = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - - // Toggle NDI for next time + // Toggle NDI LOG_D(MAC,"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", CC_id, frame, subframe, UE_id, UE_list->UE_template[CC_id][UE_id].rnti,harq_pid, UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]); - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]=1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]= 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + ndi = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; // Increase the pointer for the number of scheduled UEs num_ues_added++; From a663654418f6c39fac29af7492d2251ef33c280b Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 10 Feb 2016 13:41:56 +0000 Subject: [PATCH 094/413] Patch to get tx_queue size from RLC for the LCs of a UE --- openair2/ENB_APP/enb_agent_common.c | 7 +++++++ openair2/ENB_APP/enb_agent_common.h | 2 +- openair2/ENB_APP/enb_agent_mac.c | 8 ++++---- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 7c820bfa5c..5ddcb39868 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -393,6 +393,13 @@ int get_ue_wcqi (mid_t mod_id, mid_t ue_id) { return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].dl_cqi; } +int get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) +{ + rnti_t rnti = get_ue_crnti(mod_id,ue_id); + uint16_t frame = (uint16_t) 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; +} /* * timer primitives */ diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index afa2179ff4..784c86bf6a 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -148,7 +148,7 @@ int get_ue_phr (mid_t mod_id, mid_t ue_id); int get_ue_wcqi (mid_t mod_id, mid_t ue_id); - +int get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index df614df60c..4a62c9dcbb 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -413,9 +413,9 @@ int enb_agent_mac_stats_reply(mid_t mod_id, /* Check flag for creation of RLC buffer status report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_RLC_BS) { // TODO: Fill in the actual RLC buffer status reports - ue_report[i]->n_rlc_report = 1; // Set this to the number of LCs for this UE + ue_report[i]->n_rlc_report = 3; // Set this to the number of LCs for this UE Protocol__PrpRlcBsr ** rlc_reports; - rlc_reports = malloc(sizeof(Protocol__PrpRlcBsr) * ue_report[i]->n_rlc_report); + rlc_reports = malloc(sizeof(Protocol__PrpRlcBsr *) * ue_report[i]->n_rlc_report); if (rlc_reports == NULL) goto error; @@ -427,10 +427,10 @@ int enb_agent_mac_stats_reply(mid_t mod_id, goto error; protocol__prp_rlc_bsr__init(rlc_reports[j]); //TODO:Set logical channel id - rlc_reports[j]->lc_id = 1; + rlc_reports[j]->lc_id = j+1; rlc_reports[j]->has_lc_id = 1; //TODO:Set tx queue size in bytes - rlc_reports[j]->tx_queue_size = 10; + rlc_reports[j]->tx_queue_size = 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 = 100; From b64cb5b2501c8ee09c8417d66a935ca8b16722ca Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 10 Feb 2016 18:07:35 +0000 Subject: [PATCH 095/413] Added rank indication and timing advance indication support --- openair2/ENB_APP/enb_agent_common.c | 25 ++++ openair2/ENB_APP/enb_agent_common.h | 5 + openair2/ENB_APP/enb_agent_mac.c | 194 ++++++++++++++++------------ 3 files changed, 140 insertions(+), 84 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 5ddcb39868..eb08107dff 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -400,6 +400,31 @@ int get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_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 get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id) +{ + if((((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ta_update) > 0) + return 1; + else + return 0; +} + +int get_active_CC(mid_t mod_id, mid_t ue_id) +{ + return ((UE_list_t *)enb_ue[mod_id])->numactiveCCs[ue_id]; +} + +int get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) +{ + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + + int pCCid = UE_PCCID(mod_id,ue_id); + rnti_t rnti = 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[CC_id].rank; +} + /* * timer primitives */ diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 784c86bf6a..37d3829354 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -150,6 +150,11 @@ int get_ue_wcqi (mid_t mod_id, mid_t ue_id); int get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); +int get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id); + +int get_active_CC(mid_t mod_id, mid_t ue_id); + +int get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id); diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 4a62c9dcbb..cb5aac1a95 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -52,25 +52,25 @@ unsigned int mac_agent_registered[NUM_MAX_ENB]; AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB]; int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__ProgranMessage **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; void *buffer; int size; 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 + + //TODO: We do not deal with multiple CCs at the moment and eNB id is 0 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; - + report_config_t report_config; uint32_t ue_flags = 0; @@ -96,7 +96,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr 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 = 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); @@ -129,7 +129,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr stats_request_config_t request_config; request_config.report_type = PROTOCOL__PRP_STATS_TYPE__PRST_COMPLETE_STATS; request_config.report_frequency = PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_ONCE; - request_config.period = 0; + request_config.period = 0; request_config.config = &report_config; enb_agent_mac_stats_request(enb_id, xid, &request_config, &timer_msg); /* Create a timer */ @@ -137,7 +137,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr enb_agent_timer_args_t *timer_args; timer_args = malloc(sizeof(enb_agent_timer_args_t)); memset (timer_args, 0, sizeof(enb_agent_timer_args_t)); - timer_args->mod_id = enb_id; + timer_args->mod_id = enb_id; timer_args->msg = timer_msg; /*Convert subframes to usec time*/ usec_interval = 1000*comp_req->sf; @@ -155,7 +155,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr stats_request_config_t request_config; request_config.report_type = PROTOCOL__PRP_STATS_TYPE__PRST_COMPLETE_STATS; request_config.report_frequency = PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_ONCE; - request_config.period = 0; + request_config.period = 0; request_config.config = &report_config; enb_agent_enable_cont_mac_stats_update(enb_id, xid, &request_config); } @@ -219,14 +219,14 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr int enb_agent_mac_stats_request(mid_t mod_id, xid_t xid, - const stats_request_config_t *report_config, + const stats_request_config_t *report_config, Protocol__ProgranMessage **msg) { Protocol__PrpHeader *header; int i; - + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_STATS_REQUEST, &header) != 0) goto error; - + Protocol__PrpStatsRequest *stats_request_msg; stats_request_msg = malloc(sizeof(Protocol__PrpStatsRequest)); if(stats_request_msg == NULL) @@ -234,10 +234,10 @@ int enb_agent_mac_stats_request(mid_t mod_id, protocol__prp_stats_request__init(stats_request_msg); 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__PRP_STATS_TYPE__PRST_COMPLETE_STATS: stats_request_msg->body_case = PROTOCOL__PRP_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST; @@ -311,7 +311,7 @@ int enb_agent_mac_stats_request(mid_t mod_id, (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; (*msg)->stats_request_msg = stats_request_msg; return 0; - + error: // TODO: Need to make proper error handling if (header != NULL) @@ -337,7 +337,7 @@ int enb_agent_mac_destroy_stats_request(Protocol__ProgranMessage *msg) { free(msg->stats_request_msg); free(msg); return 0; - + error: //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; @@ -345,7 +345,7 @@ int enb_agent_mac_destroy_stats_request(Protocol__ProgranMessage *msg) { int enb_agent_mac_stats_reply(mid_t mod_id, xid_t xid, - const report_config_t *report_config, + const report_config_t *report_config, Protocol__ProgranMessage **msg) { Protocol__PrpHeader *header; int i, j, k; @@ -353,8 +353,8 @@ int enb_agent_mac_stats_reply(mid_t mod_id, int enb_id = mod_id; //eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; //UE_list_t *eNB_UE_list= &eNB->UE_list; - - + + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_STATS_REPLY, &header) != 0) goto error; @@ -371,7 +371,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, Protocol__PrpUeStatsReport **ue_report; Protocol__PrpCellStatsReport **cell_report; - + /* Allocate memory for list of UE reports */ if (report_config->nr_ue > 0) { ue_report = malloc(sizeof(Protocol__PrpUeStatsReport *) * report_config->nr_ue); @@ -402,7 +402,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, } ue_report[i]->bsr = elem; } - + /* Check flag for creation of PRH report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PRH) { // TODO: Fill in the actual power headroom value for the RNTI @@ -418,7 +418,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, rlc_reports = malloc(sizeof(Protocol__PrpRlcBsr *) * ue_report[i]->n_rlc_report); if (rlc_reports == NULL) goto error; - + // Fill the buffer status report for each logical channel of the UE // NN: see LAYER2/openair2_proc.c for rlc status for (j = 0; j < ue_report[i]->n_rlc_report; j++) { @@ -453,13 +453,13 @@ int enb_agent_mac_stats_reply(mid_t mod_id, /* Check flag for creation of MAC CE buffer status report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_MAC_CE_BS) { // TODO: Fill in the actual MAC CE buffer status report - ue_report[i]->pending_mac_ces = -1; /* Use as bitmap. Set one or more of the + ue_report[i]->pending_mac_ces = (get_MAC_CE_bitmap_TA(enb_id,i) | (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__PRP_CE_TYPE__PRPCET_ values found in stats_common.pb-c.h. See prp_ce_type in progRAN specification */ ue_report[i]->has_pending_mac_ces = 1; } - + /* Check flag for creation of DL CQI report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI) { // TODO: Fill in the actual DL CQI report for the UE based on its configuration @@ -472,7 +472,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, dl_report->sfn_sn = get_sfn_sf(enb_id); dl_report->has_sfn_sn = 1; //TODO:Set the number of DL CQI reports for this UE. One for each CC - dl_report->n_csi_report = 1; + dl_report->n_csi_report = get_active_CC(enb_id,i); //TODO:Create the actual CSI reports. Protocol__PrpDlCsi **csi_reports; csi_reports = malloc(sizeof(Protocol__PrpDlCsi *)*dl_report->n_csi_report); @@ -484,36 +484,62 @@ int enb_agent_mac_stats_reply(mid_t mod_id, goto error; protocol__prp_dl_csi__init(csi_reports[j]); //TODO: the servCellIndex for this report - csi_reports[j]->serv_cell_index = 0; + csi_reports[j]->serv_cell_index = j; csi_reports[j]->has_serv_cell_index = 1; //TODO: the rank indicator value for this cc - csi_reports[j]->ri = 1; + csi_reports[j]->ri = 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 this example we use 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 progRAN specifications - csi_reports[j]->type = PROTOCOL__PRP_CSI_TYPE__PRCSIT_P10; - csi_reports[j]->has_type = 1; - csi_reports[j]->report_case = PROTOCOL__PRP_DL_CSI__REPORT_P10CSI; - Protocol__PrpCsiP10 *csi10; - csi10 = malloc(sizeof(Protocol__PrpCsiP10)); - if (csi10 == NULL) - goto error; - protocol__prp_csi_p10__init(csi10); - //TODO: set the wideband value - // NN: this is also depends on cc_id - csi10->wb_cqi = 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; - } + csi_reports[j]->type = PROTOCOL__PRP_CSI_TYPE__PRCSIT_P10; + csi_reports[j]->has_type = 1; + csi_reports[j]->report_case = PROTOCOL__PRP_DL_CSI__REPORT_P10CSI; + if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_P10CSI){ + Protocol__PrpCsiP10 *csi10; + csi10 = malloc(sizeof(Protocol__PrpCsiP10)); + if (csi10 == NULL) + goto error; + protocol__prp_csi_p10__init(csi10); + //TODO: set the wideband value + // NN: this is also depends on cc_id + csi10->wb_cqi = 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__PRP_DL_CSI__REPORT_P11CSI){ + + } + else if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_P20CSI){ + + } + else if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_P21CSI){ + + } + else if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_A12CSI){ + + } + else if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_A22CSI){ + + } + else if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_A20CSI){ + + } + else if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_A30CSI){ + + } + else if(csi_reports[j]->report_case == PROTOCOL__PRP_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__PRP_UE_STATS_TYPE__PRUST_PBS) { //TODO: Fill in the actual paging buffer status report. For this field to be valid, the RNTI @@ -554,7 +580,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, //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__PRP_UE_STATS_TYPE__PRUST_UL_CQI) { //Fill in the full UL CQI report of the UE @@ -648,7 +674,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, /* Add list of all cell reports to the message */ stats_reply_msg->cell_report = cell_report; } - + *msg = malloc(sizeof(Protocol__ProgranMessage)); if(*msg == NULL) goto error; @@ -657,7 +683,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; (*msg)->stats_reply_msg = stats_reply_msg; return 0; - + error: // TODO: Need to make proper error handling if (header != NULL) @@ -676,7 +702,7 @@ int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg) { goto error; free(msg->stats_reply_msg->header); int i, j, k; - + Protocol__PrpStatsReply *reply = msg->stats_reply_msg; Protocol__PrpDlCqiReport *dl_report; Protocol__PrpUlCqiReport *ul_report; @@ -737,8 +763,8 @@ int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg) { } free(dl_report->csi_report[j]->a31csi->sb_cqi); break; - } - + } + free(dl_report->csi_report[j]); } free(dl_report->csi_report); @@ -773,11 +799,11 @@ int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg) { free(reply->cell_report[i]); } free(reply->cell_report); - + free(reply); free(msg); return 0; - + error: //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; @@ -796,7 +822,7 @@ int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__ProgranMes goto error; } protocol__prp_ul_sr_info__init(ul_sr_info_msg); - + ul_sr_info_msg->header = header; ul_sr_info_msg->has_sfn_sf = 1; ul_sr_info_msg->sfn_sf = get_sfn_sf(mod_id); @@ -811,7 +837,7 @@ int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__ProgranMes for (i = 0; i < ul_sr_info_msg->n_rnti; i++) { ul_sr_info_msg->rnti[i] = 1; } - + *msg = malloc(sizeof(Protocol__ProgranMessage)); if(*msg == NULL) goto error; @@ -820,7 +846,7 @@ int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__ProgranMes (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; (*msg)->ul_sr_info_msg = ul_sr_info_msg; return 0; - + error: // TODO: Need to make proper error handling if (header != NULL) @@ -863,7 +889,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran goto error; } protocol__prp_sf_trigger__init(sf_trigger_msg); - + sf_trigger_msg->header = header; sf_trigger_msg->has_sfn_sf = 1; sf_trigger_msg->sfn_sf = get_sfn_sf(mod_id); @@ -872,7 +898,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran *transmitting UEs */ sf_trigger_msg->n_dl_info = get_num_ues(mod_id); - + Protocol__PrpDlInfo **dl_info = NULL; if (sf_trigger_msg->n_dl_info > 0) { @@ -901,14 +927,14 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran dl_info[i]->has_serv_cell_index = 1; } } - + sf_trigger_msg->dl_info = dl_info; /*TODO: Fill in the number of UL reception status related info, based on the number of currently *transmitting UEs */ sf_trigger_msg->n_ul_info = get_num_ues(mod_id); - + Protocol__PrpUlInfo **ul_info = NULL; if (sf_trigger_msg->n_ul_info > 0) { @@ -926,7 +952,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran /*TODO: fill in the Tx power control command for this UE (if available)*/ ul_info[i]->tpc = 1; ul_info[i]->has_tpc = 0; - /*TODO: fill in the amount of data in bytes in the MAC SDU received in this subframe for the + /*TODO: fill in the amount of data in bytes in the MAC SDU received in this subframe for the given logical channel*/ ul_info[i]->n_ul_reception = 11; ul_info[i]->ul_reception = malloc(sizeof(uint32_t) * ul_info[i]->n_ul_reception); @@ -941,7 +967,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran ul_info[i]->has_serv_cell_index = 1; } } - + sf_trigger_msg->ul_info = ul_info; *msg = malloc(sizeof(Protocol__ProgranMessage)); @@ -952,7 +978,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; (*msg)->sf_trigger_msg = sf_trigger_msg; return 0; - + error: if (header != NULL) free(header); @@ -977,7 +1003,7 @@ int enb_agent_mac_destroy_sf_trigger(Protocol__ProgranMessage *msg) { int i; if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_SF_TRIGGER_MSG) goto error; - + free(msg->sf_trigger_msg->header); for (i = 0; i < msg->sf_trigger_msg->n_dl_info; i++) { free(msg->sf_trigger_msg->dl_info[i]->harq_status); @@ -989,7 +1015,7 @@ int enb_agent_mac_destroy_sf_trigger(Protocol__ProgranMessage *msg) { free(msg->sf_trigger_msg->ul_info); free(msg->sf_trigger_msg); free(msg); - + return 0; error: @@ -1010,11 +1036,11 @@ int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__ProgranMessage goto error; } protocol__prp_dl_mac_config__init(dl_mac_config_msg); - + dl_mac_config_msg->header = header; dl_mac_config_msg->has_sfn_sf = 1; dl_mac_config_msg->sfn_sf = get_sfn_sf(mod_id); - + *msg = malloc(sizeof(Protocol__ProgranMessage)); if(*msg == NULL) goto error; @@ -1056,7 +1082,7 @@ int enb_agent_mac_destroy_dl_config(Protocol__ProgranMessage *msg) { free(msg->dl_mac_config_msg->dl_ue_data[i]); } free(msg->dl_mac_config_msg->dl_ue_data); - + for (i = 0; i < msg->dl_mac_config_msg->n_dl_rar; i++) { dl_dci = msg->dl_mac_config_msg->dl_rar[i]->rar_dci; free(dl_dci->tbs_size); @@ -1132,7 +1158,7 @@ void enb_agent_send_sf_trigger(mid_t mod_id) { err_code_t err_code; int xid = 0; - + /*TODO: Must use a proper xid*/ err_code = enb_agent_mac_sf_trigger(mod_id, (void *) &xid, &msg); if (err_code < 0) { @@ -1161,20 +1187,20 @@ void enb_agent_send_update_mac_stats(mid_t mod_id) { int size; err_code_t err_code; int priority; - + mac_stats_updates_context_t stats_context = mac_stats_context[mod_id]; if (pthread_mutex_lock(mac_stats_context[mod_id].mutex)) { goto error; } - + /*Create a fresh report with the required flags*/ err_code = enb_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 + /*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) { @@ -1186,12 +1212,12 @@ void enb_agent_send_update_mac_stats(mid_t mod_id) { } /*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 (msg != NULL){ data=enb_agent_pack_message(msg, &size); /*Send any stats updates using the MAC channel of the eNB*/ @@ -1219,7 +1245,7 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_send_update_mac_stats = enb_agent_send_update_mac_stats; xface->enb_agent_schedule_ue_spec = schedule_ue_spec_default; - + mac_agent_registered[mod_id] = 1; agent_mac_xface[mod_id] = xface; @@ -1227,7 +1253,7 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { } int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { - + //xface->agent_ctxt = NULL; xface->enb_agent_send_sr_info = NULL; xface->enb_agent_send_sf_trigger = NULL; @@ -1236,7 +1262,7 @@ int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { mac_agent_registered[mod_id] = 0; agent_mac_xface[mod_id] = NULL; - + return 0; } @@ -1246,7 +1272,7 @@ int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { ******************************************************/ err_code_t enb_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; @@ -1258,9 +1284,9 @@ err_code_t enb_agent_init_cont_mac_stats_update(mid_t mod_id) { goto error; if (pthread_mutex_init(mac_stats_context[mod_id].mutex, NULL)) goto error;; - + return 0; - + error: return -1; } @@ -1272,7 +1298,7 @@ err_code_t enb_agent_destroy_cont_mac_stats_update(mid_t mod_id) { enb_agent_destroy_progran_message(mac_stats_context[mod_id].stats_req); enb_agent_destroy_progran_message(mac_stats_context[mod_id].prev_stats_reply); free(mac_stats_context[mod_id].mutex); - + mac_agent_registered[mod_id] = NULL; return 1; } @@ -1290,15 +1316,15 @@ err_code_t enb_agent_enable_cont_mac_stats_update(mid_t mod_id, enb_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(ENB_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); return -1; @@ -1325,5 +1351,5 @@ err_code_t enb_agent_disable_cont_mac_stats_update(mid_t mod_id) { error: LOG_E(ENB_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); return -1; - + } From cb8b6db577e8a9ab222d63c5758907610688eb3c Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 19 Feb 2016 13:37:52 +0000 Subject: [PATCH 096/413] Fixed bug in periodic reporting, where ue flags were reset --- openair2/ENB_APP/enb_agent_mac.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index cb5aac1a95..c1af558414 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -130,6 +130,18 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr request_config.report_type = PROTOCOL__PRP_STATS_TYPE__PRST_COMPLETE_STATS; request_config.report_frequency = PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_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; enb_agent_mac_stats_request(enb_id, xid, &request_config, &timer_msg); /* Create a timer */ From 258a71ffbd70bf79330c6cd1a9df4f15330d17df Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 19 Feb 2016 13:55:29 +0000 Subject: [PATCH 097/413] Fixed direction of hello message, as a reaction to controller stimulation --- openair2/ENB_APP/enb_agent_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index eb08107dff..41760733bc 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -123,7 +123,7 @@ int enb_agent_hello(mid_t mod_id, const void *params, Protocol__ProgranMessage * protocol__progran_message__init(*msg); (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; (*msg)->has_msg_dir = 1; (*msg)->hello_msg = hello_msg; return 0; From 6fc604d1820fd936a9015ea4ed80f4e6d2b912c0 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 19 Feb 2016 18:17:43 +0100 Subject: [PATCH 098/413] conflict resolve for pdcchsim.c --- openair1/SIMULATION/LTE_PHY/pdcchsim.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/pdcchsim.c b/openair1/SIMULATION/LTE_PHY/pdcchsim.c index 23557aada2..3b171ad937 100644 --- a/openair1/SIMULATION/LTE_PHY/pdcchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pdcchsim.c @@ -750,25 +750,6 @@ int main(int argc, char **argv) subframe,NUMBER_OF_OFDM_CARRIERS, PHY_vars_eNB->lte_frame_parms.Ncp,PHY_vars_eNB->lte_frame_parms.samples_per_tti,nsymb); -<<<<<<< HEAD - switch (N_RB_DL) { - case 6: - BW = 1.25; - break; - - case 25: - BW = 5.00; - break; - - case 50: - BW = 10.00; - break; - - case 100: - BW = 20.00; - break; - } - eNB2UE = new_channel_desc_scm(PHY_vars_eNB->lte_frame_parms.nb_antenna_ports_eNB, PHY_vars_UE->lte_frame_parms.nb_antennas_rx, channel_model, From 08e25bf397aad2e1db1ff655d7b185acfbed712a Mon Sep 17 00:00:00 2001 From: MKassem Date: Fri, 19 Feb 2016 14:48:50 +0000 Subject: [PATCH 099/413] Added eNB configuration message Signed-off-by: Xenofon Foukas --- openair2/ENB_APP/enb_agent_common.c | 519 +++++++++++++++++++++++++++- openair2/ENB_APP/enb_agent_common.h | 43 +++ openair2/LAYER2/MAC/extern.h | 2 + 3 files changed, 556 insertions(+), 8 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 41760733bc..38f429f562 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -36,11 +36,13 @@ #include "enb_agent_common.h" +#include "PHY/extern.h" #include "log.h" void * enb[NUM_MAX_ENB]; void * enb_ue[NUM_MAX_ENB]; +void * enb_rrc[NUM_MAX_ENB]; /* * message primitives */ @@ -261,14 +263,33 @@ int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg) { return -1; } -int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { - /* TODO: Create a reply progRAN message with the current eNB configuration */ - return 0; -} int enb_agent_destroy_enb_config_reply(Protocol__ProgranMessage *msg) { - /* TODO: Deallocate memory for a dynamically allocated eNB config message */ - return 0; + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG) + goto error; + free(msg->enb_config_reply_msg->header); + int i, j; + Protocol__PrpEnbConfigReply *reply = msg->enb_config_reply_msg; + + for(i = 0; i < reply->n_cell_config;i++){ + free(reply->cell_config[i]->mbsfn_subframe_config_rfoffset); + free(reply->cell_config[i]->mbsfn_subframe_config_rfperiod); + free(reply->cell_config[i]->mbsfn_subframe_config_sfalloc); + for(j = 0; j < reply->cell_config[i]->si_config->n_si_message;j++){ + free(reply->cell_config[i]->si_config->si_message[j]); + } + free(reply->cell_config[i]->si_config->si_message); + free(reply->cell_config[i]->si_config); + free(reply->cell_config[i]); + } + free(reply->cell_config); + free(reply); + free(msg); + + return 0; + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; } int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { @@ -292,8 +313,16 @@ int enb_agent_destroy_lc_config_reply(Protocol__ProgranMessage *msg) { } int enb_agent_destroy_enb_config_request(Protocol__ProgranMessage *msg) { - /* TODO: Deallocate memory for a dynamically allocated eNB config message */ - return 0; + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG) + goto error; + free(msg->enb_config_request_msg->header); + free(msg->enb_config_request_msg); + free(msg); + return 0; + + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; } int enb_agent_destroy_ue_config_request(Protocol__ProgranMessage *msg) { @@ -316,6 +345,7 @@ void set_enb_vars(mid_t mod_id, ran_name_t 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; @@ -425,10 +455,483 @@ int get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) return eNB_UE_stats[CC_id].rank; } + +/* + * ************************************ + * Get Messages for eNB Configuration Reply + * ************************************ + */ + +int 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 get_ra_ResponseWindowSize(mid_t mod_id, int CC_id) +{ + Enb_properties_array_t *enb_properties; + enb_properties = enb_config_get(); + return enb_properties->properties[mod_id]->rach_raResponseWindowSize[CC_id]; +} +int get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id) +{ + Enb_properties_array_t *enb_properties; + enb_properties = enb_config_get(); + return enb_properties->properties[mod_id]->rach_macContentionResolutionTimer[CC_id]; +} +int 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 == 0) + return 1; + else if (frame_parms->frame_type == 1) + return 0; + + return -1; +} +long 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 get_sib1_length(mid_t mod_id, int CC_id) +{ + return ((eNB_RRC_INST *)enb_rrc[mod_id])->carrier[CC_id].sizeof_SIB1; +} +int get_num_pdcch_symb(mid_t mod_id, int CC_id) +{ + /*TODO: add these values to some struct in MAC + LTE_UE_PDCCH *lte_ue_pdcch; + lte_ue_pdcch = mac_xface->get_lte_ue_pdcch(mod_id, CC_id, mod_id); + */ + return (PHY_vars_UE_g[mod_id][CC_id]->lte_ue_pdcch_vars[mod_id]->num_pdcch_symbols); +} + /* * timer primitives */ +/* + * ************************************ + * eNB Configuration Request and Reply + * ************************************ + */ + +int enb_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__ProgranMessage **msg) { + + Protocol__PrpHeader *header; + xid_t xid = 1; + if(prp_create_header(xid,PROTOCOL__PRP_TYPE__PRPT_GET_ENB_CONFIG_REQUEST, &header) != 0) + goto error; + + Protocol__PrpEnbConfigRequest *enb_config_request_msg; + enb_config_request_msg = malloc(sizeof(Protocol__PrpEnbConfigRequest)); + + if(enb_config_request_msg == NULL) + goto error; + + protocol__prp_enb_config_request__init(enb_config_request_msg); + enb_config_request_msg->header = header; + + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if(*msg == NULL) + goto error; + + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + (*msg)->enb_config_request_msg = enb_config_request_msg; + return 0; + + error: + // TODO: Need to make proper error handling + if (header != NULL) + free(header); + if (enb_config_request_msg != NULL) + free(enb_config_request_msg); + if(*msg != NULL) + free(*msg); + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { + + xid_t xid; + Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; + Protocol__PrpEnbConfigReply *enb_config_req_msg = input->enb_config_request_msg; + xid = (enb_config_req_msg->header)->xid; + + int i, j, k; + int cc_id = 0; + int enb_id = mod_id; + + + Protocol__PrpHeader *header; + if(prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_GET_ENB_CONFIG_REPLY, &header) != 0) + goto error; + + Protocol__PrpEnbConfigReply *enb_config_reply_msg; + enb_config_reply_msg = malloc(sizeof(Protocol__PrpEnbConfigReply)); + if(enb_config_reply_msg == NULL) + goto error; + protocol__prp_enb_config_reply__init(enb_config_reply_msg); + enb_config_reply_msg->header = header; + + enb_config_reply_msg->enb_id = mod_id; + + + enb_config_reply_msg->n_cell_config = MAX_NUM_CCs; + + Protocol__PrpCellConfig **cell_conf; + if(enb_config_reply_msg->n_cell_config > 0){ + cell_conf = malloc(sizeof(Protocol__PrpCellConfig *) * enb_config_reply_msg->n_cell_config); + if(cell_conf == NULL) + goto error; + for(i = 0; i < enb_config_reply_msg->n_cell_config; i++){ + cell_conf[i] = malloc(sizeof(Protocol__PrpCellConfig)); + protocol__prp_cell_config__init(cell_conf[i]); + //TODO: Fill in with actual value, the PCI of this cell + cell_conf[i]->phy_cell_id = 1; + cell_conf[i]->has_phy_cell_id = 1; + //TODO: Fill in with actual value, the PLMN cell id of this cell + cell_conf[i]->cell_id = get_cell_id(enb_id,i); + cell_conf[i]->has_cell_id = 1; + //TODO: Fill in with actual value, PUSCH resources in RBs for hopping + cell_conf[i]->pusch_hopping_offset = get_hopping_offset(enb_id,i); + cell_conf[i]->has_pusch_hopping_offset = 1; + //TODO: Fill in with actual value + cell_conf[i]->hopping_mode = get_hopping_mode(enb_id,i); + cell_conf[i]->has_hopping_mode = 1; + //TODO: Fill in with actual value, the number of subbands + cell_conf[i]->n_sb = get_n_SB(enb_id,i); + cell_conf[i]->has_n_sb = 1; + //TODO: Fill in with actual value, The number of resource element groups used for PHICH. One of PRPR_ + cell_conf[i]->phich_resource = get_phich_resource(enb_id,i); + cell_conf[i]->has_phich_resource = 1; + //TODO: Fill in with actual value, one of the PRPD_ values + cell_conf[i]->phich_duration = get_phich_duration(enb_id,i); + cell_conf[i]->has_phich_duration = 1; + //TODO: Fill in with actual value, See TS 36.211, section 6.9 + cell_conf[i]->init_nr_pdcch_ofdm_sym = get_num_pdcch_symb(enb_id,i); + cell_conf[i]->has_init_nr_pdcch_ofdm_sym = 1; + //TODO: Fill in with actual value + Protocol__PrpSiConfig *si_config; + si_config = malloc(sizeof(Protocol__PrpSiConfig)); + if(si_config == NULL) + goto error; + protocol__prp_si_config__init(si_config); + //TODO: Fill in with actual value, Frame number to apply the SI configuration + si_config->sfn = 1; + si_config->has_sfn = 1; + //TODO: Fill in with actual value, the length of SIB1 in bytes + si_config->sib1_length = get_sib1_length(enb_id,i); + si_config->has_sib1_length = 1; + //TODO: Fill in with actual value, Scheduling window for all SIs in SF + si_config->si_window_length = (uint32_t) get_si_window_length(enb_id,i); + si_config->has_si_window_length = 1; + //TODO: Fill in with actual value, the number of SI messages + si_config->n_si_message=1; + Protocol__PrpSiMessage **si_message; + si_message = malloc(sizeof(Protocol__PrpSiMessage *) * si_config->n_si_message); + if(si_message == NULL) + goto error; + for(j = 0; j < si_config->n_si_message; j++){ + si_message[j] = malloc(sizeof(Protocol__PrpSiMessage)); + if(si_message[j] == NULL) + goto error; + protocol__prp_si_message__init(si_message[j]); + //TODO: Fill in with actual value, Periodicity of SI msg in radio frames + si_message[j]->periodicity = 1; //SIPeriod + si_message[j]->has_periodicity = 1; + //TODO: Fill in with actual value, rhe length of the SI message in bytes + si_message[j]->length = 10; + si_message[j]->has_length = 1; + } + if(si_config->n_si_message > 0){ + si_config->si_message = si_message; + } + cell_conf[i]->si_config = si_config; + + //TODO: Fill in with actual value, the DL transmission bandwidth in RBs + cell_conf[i]->dl_bandwidth = get_N_RB_DL(enb_id,i); + cell_conf[i]->has_dl_bandwidth = 1; + //TODO: Fill in with actual value, the UL transmission bandwidth in RBs + cell_conf[i]->ul_bandwidth = get_N_RB_UL(enb_id,i); + cell_conf[i]->has_ul_bandwidth = 1; + //TODO: Fill in with actual value, one of PRUCPL values + cell_conf[i]->ul_cyclic_prefix_length = get_ul_cyclic_prefix_length(enb_id,i); + cell_conf[i]->has_ul_cyclic_prefix_length = 1; + //TODO: Fill in with actual value, one of PRUCPL values + cell_conf[i]->dl_cyclic_prefix_length = get_dl_cyclic_prefix_length(enb_id,i); + cell_conf[i]->has_dl_cyclic_prefix_length = 1; + //TODO: Fill in with actual value, number of cell specific antenna ports + cell_conf[i]->antenna_ports_count = 1; + cell_conf[i]->has_antenna_ports_count = 1; + //TODO: Fill in with actual value, one of PRDM values + cell_conf[i]->duplex_mode = get_duplex_mode(enb_id,i); + cell_conf[i]->has_duplex_mode = 1; + //TODO: Fill in with actual value, DL/UL subframe assignment. TDD only + cell_conf[i]->subframe_assignment = get_subframe_assignment(enb_id,i); + cell_conf[i]->has_subframe_assignment = 1; + //TODO: Fill in with actual value, TDD only. See TS 36.211, table 4.2.1 + cell_conf[i]->special_subframe_patterns = get_special_subframe_assignment(enb_id,i); + cell_conf[i]->has_special_subframe_patterns = 1; + //TODO: Fill in with actual value, The MBSFN radio frame period + cell_conf[i]->n_mbsfn_subframe_config_rfperiod = 5; + uint32_t *elem_rfperiod; + elem_rfperiod = (uint32_t *) malloc(sizeof(uint32_t) *cell_conf[i]->n_mbsfn_subframe_config_rfperiod); + if(elem_rfperiod == NULL) + goto error; + for(j = 0; j < cell_conf[i]->n_mbsfn_subframe_config_rfperiod; j++){ + elem_rfperiod[j] = 1; + } + cell_conf[i]->mbsfn_subframe_config_rfperiod = elem_rfperiod; + + //TODO: Fill in with actual value, The MBSFN radio frame offset + cell_conf[i]->n_mbsfn_subframe_config_rfoffset = 5; + uint32_t *elem_rfoffset; + elem_rfoffset = (uint32_t *) malloc(sizeof(uint32_t) *cell_conf[i]->n_mbsfn_subframe_config_rfoffset); + if(elem_rfoffset == NULL) + goto error; + for(j = 0; j < cell_conf[i]->n_mbsfn_subframe_config_rfoffset; j++){ + elem_rfoffset[j] = 1; + } + cell_conf[i]->mbsfn_subframe_config_rfoffset = elem_rfoffset; + + //TODO: Fill in with actual value, Bitmap indicating the MBSFN subframes + cell_conf[i]->n_mbsfn_subframe_config_sfalloc = 5; + uint32_t *elem_sfalloc; + elem_sfalloc = (uint32_t *) malloc(sizeof(uint32_t) *cell_conf[i]->n_mbsfn_subframe_config_sfalloc); + if(elem_sfalloc == NULL) + goto error; + for(j = 0; j < cell_conf[i]->n_mbsfn_subframe_config_sfalloc; j++){ + elem_sfalloc[j] = 1; + } + cell_conf[i]->mbsfn_subframe_config_sfalloc = elem_sfalloc; + + //TODO: Fill in with actual value, See TS 36.211, section 5.7.1 + cell_conf[i]->prach_config_index = get_prach_ConfigIndex(enb_id,i); + cell_conf[i]->has_prach_config_index = 1; + //TODO: Fill in with actual value, See TS 36.211, section 5.7.1 + cell_conf[i]->prach_freq_offset = get_prach_FreqOffset(enb_id,i); + cell_conf[i]->has_prach_freq_offset = 1; + //TODO: Fill in with actual value, Duration of RA response window in SF + cell_conf[i]->ra_response_window_size = get_ra_ResponseWindowSize(enb_id,i); + cell_conf[i]->has_ra_response_window_size = 1; + //TODO: Fill in with actual value, Timer used for RA + cell_conf[i]->mac_contention_resolution_timer = get_mac_ContentionResolutionTimer(enb_id,i); + cell_conf[i]->has_mac_contention_resolution_timer = 1; + //TODO: Fill in with actual value, See TS 36.321 + cell_conf[i]->max_harq_msg3tx = get_maxHARQ_Msg3Tx(enb_id,i); + cell_conf[i]->has_max_harq_msg3tx = 1; + //TODO: Fill in with actual value, See TS 36.213, section 10.1 + cell_conf[i]->n1pucch_an = get_n1pucch_an(enb_id,i); + cell_conf[i]->has_n1pucch_an = 1; + //TODO: Fill in with actual value, See TS 36.211, section 5.4 + cell_conf[i]->deltapucch_shift = get_deltaPUCCH_Shift(enb_id,i); + cell_conf[i]->has_deltapucch_shift = 1; + //TODO: Fill in with actual value, See TS 36.211, section 5.4 + cell_conf[i]->nrb_cqi = get_nRB_CQI(enb_id,i); + cell_conf[i]->has_nrb_cqi = 1; + //TODO: Fill in with actual value, See TS 36.211, table 5.5.3.3-1 and 2 + cell_conf[i]->srs_subframe_config = get_srs_SubframeConfig(enb_id,i); + cell_conf[i]->has_srs_subframe_config = 1; + //TODO: Fill in with actual value, See TS 36.211, section 5.5.3.2 + cell_conf[i]->srs_bw_config = get_srs_BandwidthConfig(enb_id,i); + cell_conf[i]->has_srs_bw_config = 1; + //TODO: Fill in with actual value, Boolean value. See TS 36.211, section 5.5.3.2. TDD only + cell_conf[i]->srs_mac_up_pts = get_srs_MaxUpPts(enb_id,i); + cell_conf[i]->has_srs_mac_up_pts = 1; + //TODO: Fill in with actual value, One of the PREQ_ values + cell_conf[i]->enable_64qam = get_enable64QAM(enb_id,i); + cell_conf[i]->has_enable_64qam = 1; + //TODO: Fill in with actual value, Carrier component index + cell_conf[i]->carrier_index = i; + cell_conf[i]->has_carrier_index = 1; + } + enb_config_reply_msg->cell_config=cell_conf; + } + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if(*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + (*msg)->enb_config_reply_msg = enb_config_reply_msg; + return 0; + + error: + // TODO: Need to make proper error handling + if (header != NULL) + free(header); + if (enb_config_reply_msg != NULL) + free(enb_config_reply_msg); + if(*msg != NULL) + free(*msg); + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + //struct enb_agent_map agent_map; enb_agent_timer_instance_t timer_instance; diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 37d3829354..07d743ecb4 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -47,6 +47,7 @@ #include "stats_common.pb-c.h" # include "enb_agent_defs.h" +#include "enb_config.h" #include "LAYER2/MAC/extern.h" #include "LAYER2/RLC/rlc.h" @@ -100,6 +101,7 @@ int enb_agent_destroy_ue_config_reply(Protocol__ProgranMessage *msg); int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); int enb_agent_destroy_lc_config_reply(Protocol__ProgranMessage *msg); +int enb_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__ProgranMessage **msg); int enb_agent_destroy_enb_config_request(Protocol__ProgranMessage *msg); int enb_agent_destroy_ue_config_request(Protocol__ProgranMessage *msg); @@ -156,6 +158,47 @@ int get_active_CC(mid_t mod_id, mid_t ue_id); int get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id); +int get_n1pucch_an(mid_t mod_id, int CC_id); + +int get_nRB_CQI(mid_t mod_id, int CC_id); + +int get_deltaPUCCH_Shift(mid_t mod_id, int CC_id); + +int get_prach_ConfigIndex(mid_t mod_id, int CC_id); + +int get_prach_FreqOffset(mid_t mod_id, int CC_id); + +int get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id); + +int get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id); + +int get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id); + +int get_cell_id(mid_t mod_id, int CC_id); + +int get_srs_BandwidthConfig(mid_t mod_id, int CC_id); + +int get_srs_SubframeConfig(mid_t mod_id, int CC_id); + +int get_srs_MaxUpPts(mid_t mod_id, int CC_id); + +int get_N_RB_DL(mid_t mod_id, int CC_id); + +int get_N_RB_UL(mid_t mod_id, int CC_id); + +int get_subframe_assignment(mid_t mod_id, int CC_id); + +int get_special_subframe_assignment(mid_t mod_id, int CC_id); + +int get_ra_ResponseWindowSize(mid_t mod_id, int CC_id); + +int get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id); + +int get_duplex_mode(mid_t mod_id, int CC_id); + +long get_si_window_length(mid_t mod_id, int CC_id); + +int get_num_pdcch_symb(mid_t mod_id, int CC_id); /******************* diff --git a/openair2/LAYER2/MAC/extern.h b/openair2/LAYER2/MAC/extern.h index ca847acf4c..2810235255 100644 --- a/openair2/LAYER2/MAC/extern.h +++ b/openair2/LAYER2/MAC/extern.h @@ -50,12 +50,14 @@ //#include "SIMULATION/simulation_defs.h" #endif //PHY_EMUL #include "PHY_INTERFACE/defs.h" +#include "RRC/LITE/defs.h" extern const uint32_t BSR_TABLE[BSR_TABLE_SIZE]; //extern uint32_t EBSR_Level[63]; extern UE_MAC_INST *UE_mac_inst; extern eNB_MAC_INST *eNB_mac_inst; +extern eNB_RRC_INST *eNB_rrc_inst; extern MAC_RLC_XFACE *Mac_rlc_xface; extern uint8_t Is_rrc_registered; From 93cf1b1df723f770e1e6fd094ff95db6bc26aad3 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Sun, 21 Feb 2016 21:39:22 +0000 Subject: [PATCH 100/413] Fixed bug in assignment of enb_config_request_message --- openair2/ENB_APP/enb_agent_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 38f429f562..a87a6be8e3 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -718,7 +718,7 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Progr xid_t xid; Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; - Protocol__PrpEnbConfigReply *enb_config_req_msg = input->enb_config_request_msg; + Protocol__PrpEnbConfigRequest *enb_config_req_msg = input->enb_config_request_msg; xid = (enb_config_req_msg->header)->xid; int i, j, k; From 7b1ee53a4e759890beeb83fa227247c3bb0b9d9f Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 22 Feb 2016 11:26:52 +0000 Subject: [PATCH 101/413] Implemented UE config message (dummy) --- openair2/ENB_APP/enb_agent_common.c | 179 +++++++++++++++++++++++++++- 1 file changed, 177 insertions(+), 2 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index a87a6be8e3..768764b152 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -293,13 +293,188 @@ int enb_agent_destroy_enb_config_reply(Protocol__ProgranMessage *msg) { } int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { - /* TODO: Create a reply progRAN message with the current UE configurations */ + + xid_t xid; + Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; + Protocol__PrpUeConfigRequest *ue_config_request_msg = input->ue_config_request_msg; + xid = (ue_config_request_msg->header)->xid; + + int i; + + Protocol__PrpHeader *header; + if(prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_GET_UE_CONFIG_REPLY, &header) != 0) + goto error; + + Protocol__PrpUeConfigReply *ue_config_reply_msg; + ue_config_reply_msg = malloc(sizeof(Protocol__PrpUeConfigReply)); + if(ue_config_reply_msg == NULL) + goto error; + protocol__prp_enb_config_reply__init(ue_config_reply_msg); + ue_config_reply_msg->header = header; + + //TODO: Fill in the actual number of UEs that are currently connected + ue_config_reply_msg->n_ue_config = 1; + + Protocol__PrpUeConfig **ue_config; + if (ue_config_reply_msg->n_ue_config > 0) { + ue_config = malloc(sizeof(Protocol__PrpUeConfig *) * ue_config_reply_msg->n_ue_config); + if (ue_config == NULL) { + goto error; + } + for (i = 0; i < ue_config_reply_msg->n_ue_config; i++) { + ue_config[i] = malloc(sizeof(Protocol__PrpUeConfig *)); + protocol__prp_ue_config__init(ue_config[i]); + //TODO: Set the RNTI of the ue with id i + ue_config[i]->rnti = 1; + ue_config[i]->has_rnti = 1; + //TODO: Set the DRX configuration (optional) + //Not supported for now, so we do not set it + + //TODO: Set the time_alignment_timer + ue_config[i]->time_alignment_timer = 1; + ue_config[i]->has_time_alignment_timer = 1; + //TODO: Set the measurement gap configuration pattern + ue_config[i]->meas_gap_config_pattern = 1; + ue_config[i]->has_meas_gap_config_pattern = 1; + //TODO: Set the measurement gap offset if applicable + ue_config[i]->meas_gap_config_sf_offset = 1; + ue_config[i]->has_meas_gap_config_sf_offset = 1; + //TODO: Set the SPS configuration (Optional) + //Not supported for noe, 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 + + //TODO: Set the transmission mode + ue_config[i]->transmission_mode = 1; + ue_config[i]->has_transmission_mode = 1; + + //TODO: Set the aggregated bit-rate of the non-gbr bearer (UL) + ue_config[i]->ue_aggregated_max_bitrate_ul = 1; + ue_config[i]->has_ue_aggregated_max_bitrate_ul = 1; + + //TODO: Set the aggregated bit-rate of the non-gbr bearer (DL) + ue_config[i]->ue_aggregated_max_bitrate_dl = 1; + ue_config[i]->has_ue_aggregated_max_bitrate_dl = 1; + + //TODO: Set the UE capabilities + Protocol__PrpUeCapabilities *capabilities; + capabilities = malloc(sizeof(Protocol__PrpUeCapabilities)); + protocol__prp_ue_capabilities__init(capabilities); + //TODO: Set half duplex (FDD operation) + capabilities->has_half_duplex = 1; + capabilities->half_duplex = 1; + //TODO: Set intra-frame hopping flag + capabilities->has_intra_sf_hopping = 1; + capabilities->intra_sf_hopping = 1; + //TODO: Set support for type 2 hopping with n_sb > 1 + capabilities->has_type2_sb_1 = 1; + capabilities->type2_sb_1 = 1; + //TODO: Set ue category + capabilities->has_ue_category = 1; + capabilities->ue_category = 1; + //TODO: Set UE support for resource allocation type 1 + capabilities->has_res_alloc_type1 = 1; + capabilities->res_alloc_type1 = 1; + //Set the capabilites to the message + ue_config[i]->capabilities = capabilities; + //TODO: Set UE transmission antenna. One of the PRUTA_* values + ue_config[i]->has_ue_transmission_antenna = 1; + ue_config[i]->ue_transmission_antenna = PROTOCOL__PRP_UE_TRANSMISSION_ANTENNA__PRUTA_OPEN_LOOP; + //TODO: Set tti bundling flag (See ts 36.321) + ue_config[i]->has_tti_bundling = 1; + ue_config[i]->tti_bundling = 1; + //TODO: Set the max HARQ retransmission for the UL + ue_config[i]->has_max_harq_tx = 1; + ue_config[i]->max_harq_tx = 1; + //TODO: Fill beta_offset_ack_index (TS 36.213) + ue_config[i]->has_beta_offset_ack_index = 1; + ue_config[i]->beta_offset_ack_index = 1; + //TODO: Fill beta_offset_ri_index (TS 36.213) + ue_config[i]->has_beta_offset_ri_index = 1; + ue_config[i]->beta_offset_ri_index = 1; + //TODO: Fill beta_offset_cqi_index (TS 36.213) + ue_config[i]->has_beta_offset_cqi_index = 1; + ue_config[i]->beta_offset_cqi_index = 1; + //TODO: Fill ack_nack_simultaneous_trans (TS 36.213) + ue_config[i]->has_ack_nack_simultaneous_trans = 1; + ue_config[i]->ack_nack_simultaneous_trans = 1; + //TODO: Fill simultaneous_ack_nack_cqi (TS 36.213) + ue_config[i]->has_simultaneous_ack_nack_cqi = 1; + ue_config[i]->simultaneous_ack_nack_cqi = 1; + //TODO: Set PRACRM_* value regarding aperiodic cqi report mode + ue_config[i]->has_aperiodic_cqi_rep_mode = 1; + ue_config[i]->aperiodic_cqi_rep_mode = PROTOCOL__PRP_APERIODIC_CQI_REPORT_MODE__PRACRM_RM12; + //TODO: Set tdd_ack_nack_feedback + ue_config[i]->has_tdd_ack_nack_feedback = 1; + ue_config[i]->tdd_ack_nack_feedback = 1; + //TODO: Set ack_nack_repetition factor + ue_config[i]->has_ack_nack_repetition_factor = 1; + ue_config[i]->ack_nack_repetition_factor = 1; + //TODO: Set extended BSR size + ue_config[i]->has_extended_bsr_size = 1; + ue_config[i]->extended_bsr_size = 1; + //TODO: Set carrier aggregation support (boolean) + ue_config[i]->has_ca_support = 1; + ue_config[i]->ca_support = 0; + //TODO: Set cross carrier scheduling support (boolean) + ue_config[i]->has_cross_carrier_sched_support = 1; + ue_config[i]->cross_carrier_sched_support = 0; + //TODO: Set index of primary cell + ue_config[i]->has_pcell_carrier_index = 1; + ue_config[i]->pcell_carrier_index = 1; + //TODO: Set secondary cells configuration + // We do not set it for now. No carrier aggregation support + + //TODO: Set deactivation timer for secondary cell + ue_config[i]->has_scell_deactivation_timer = 1; + ue_config[i]->scell_deactivation_timer = 1; + } + ue_config_reply_msg->ue_config = ue_config; + } + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if (*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + (*msg)->ue_config_reply_msg = ue_config_reply_msg; return 0; + + error: + // TODO: Need to make proper error handling + if (header != NULL) + free(header); + if (ue_config_reply_msg != NULL) + free(ue_config_reply_msg); + if(*msg != NULL) + free(*msg); + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; } int enb_agent_destroy_ue_config_reply(Protocol__ProgranMessage *msg) { - /*TODO: Deallocate memory for a dynamically allocated UE config message */ + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG) + goto error; + free(msg->ue_config_reply_msg->header); + int i, j; + Protocol__PrpUeConfigReply *reply = msg->ue_config_reply_msg; + + for(i = 0; i < reply->n_ue_config;i++){ + free(reply->ue_config[i]->capabilities); + free(reply->ue_config[i]); + } + free(reply->ue_config); + free(reply); + free(msg); + return 0; + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; } int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { From b523682af04f4a25e75c4f961c7db7d574135fe9 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 22 Feb 2016 11:55:46 +0000 Subject: [PATCH 102/413] Added support for UE state change message --- openair2/ENB_APP/MESSAGES/V2/config_common.proto | 6 ++++++ openair2/ENB_APP/MESSAGES/V2/header.proto | 3 +++ openair2/ENB_APP/MESSAGES/V2/progran.proto | 11 +++++++++++ 3 files changed, 20 insertions(+) diff --git a/openair2/ENB_APP/MESSAGES/V2/config_common.proto b/openair2/ENB_APP/MESSAGES/V2/config_common.proto index ab6e8b8c22..f7a4b1ee07 100644 --- a/openair2/ENB_APP/MESSAGES/V2/config_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/config_common.proto @@ -172,3 +172,9 @@ enum prp_qos_bearer_type { PRQBT_GBR = 1; } +enum prp_ue_state_change_type { + PRUESC_UPDATED = 0; + PRUESC_ACTIVATED = 1; + PRUESC_DEACTIVATED = 2; + PRUESC_MOVED = 3; +} \ No newline at end of file diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index be0341f132..8e6adb1fda 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -32,5 +32,8 @@ enum prp_type { //Controller command messages PRPT_DL_MAC_CONFIG = 13; + + // UE state change messages + PRPT_UE_STATE_CHANGE = 14; } diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index 2bcf9bbc95..44fffc7ead 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -24,6 +24,7 @@ message progran_message { prp_lc_config_request lc_config_request_msg = 12; prp_lc_config_reply lc_config_reply_msg = 13; prp_dl_mac_config dl_mac_config_msg = 14; + prp_ue_state_change ue_state_change_msg = 15; } } @@ -159,6 +160,16 @@ message prp_dl_mac_config { repeated prp_pdcch_ofdm_sym_count ofdm_sym = 6; // OFDM symbol count for each CC } +// +// UE state change message +// + +message prp_ue_state_change { + optional prp_header header = 1; + optional uint32 type = 2; // One of the PRUESC_* values + optional prp_ue_config config = 3; // Body of the message (based on type) +} + // Extensions of the echo request and reply // messages for carrying a latency value in ms message prp_echo_request_latency { From 1caa45ad4bef2d305484257cf928b662a5fddc10 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 22 Feb 2016 12:05:17 +0000 Subject: [PATCH 103/413] Integrated UE state messages to agent --- openair2/ENB_APP/enb_agent_common.c | 10 ++++++++++ openair2/ENB_APP/enb_agent_common.h | 2 ++ openair2/ENB_APP/enb_agent_handler.c | 2 ++ 3 files changed, 14 insertions(+) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 768764b152..b30b748424 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -487,6 +487,16 @@ int enb_agent_destroy_lc_config_reply(Protocol__ProgranMessage *msg) { return 0; } +int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { + /* TODO: Create a progRAN message with the state changes requested for the UE with RNTI rnti */ + return 0; +} + +int enb_agent_destroy_ue_state_change(Protocol__ProgranMessage *msg) { + /* TODO: Dealocate memory for a dynamically allocated UE state change message */ + return 0; +} + int enb_agent_destroy_enb_config_request(Protocol__ProgranMessage *msg) { if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG) goto error; diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 07d743ecb4..bb7b20fdb4 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -108,6 +108,8 @@ int enb_agent_destroy_ue_config_request(Protocol__ProgranMessage *msg); int enb_agent_destroy_lc_config_request(Protocol__ProgranMessage *msg); +int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change); +int enb_agent_destroy_ue_state_change(Protocol__ProgranMessage *msg); Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, uint8_t *data, diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 9815732088..2162a29314 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -56,6 +56,7 @@ enb_agent_message_decoded_callback agent_messages_callback[][3] = { {enb_agent_lc_config_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REQUEST_MSG*/ {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG*/ {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG*/ + {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG*/ }; @@ -74,6 +75,7 @@ enb_agent_message_destruction_callback message_destruction_callback[] = { enb_agent_destroy_lc_config_request, enb_agent_destroy_lc_config_reply, enb_agent_mac_destroy_dl_config, + enb_agent_destroy_ue_state_change, }; static const char *enb_agent_direction2String[] = { From 591cb51a2dff0e728a4ca8310b229f3d00ff12fc Mon Sep 17 00:00:00 2001 From: MKassem Date: Mon, 22 Feb 2016 12:03:02 +0000 Subject: [PATCH 104/413] Added sf trigger API functions Signed-off-by: Xenofon Foukas --- openair2/ENB_APP/enb_agent_common.c | 50 +++++++++++++++++++++++++++++ openair2/ENB_APP/enb_agent_common.h | 3 ++ openair2/ENB_APP/enb_agent_mac.c | 18 +++++++---- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index b30b748424..c07dcb243e 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -640,6 +640,56 @@ int get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) return eNB_UE_stats[CC_id].rank; } +int 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 = get_ue_crnti(mod_id,ue_id); + + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, pCCid, rnti); + + normalized_rx_power = eNB_UE_stats->UL_rssi[0]; + + target_rx_power = mac_xface->get_target_pusch_rx_power(mod_id,pCCid); + + 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 get_harq(mid_t mod_id,uint8_t CC_id,mid_t ue_id, int frame, uint8_t subframe, int flag_id_status) //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 = malloc(sizeof(uint8_t)); + uint8_t *round = malloc(sizeof(uint8_t)); + + uint16_t rnti = get_ue_crnti(mod_id,ue_id); + + mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&round,0); + + if(flag_id_status == 0) + return *harq_pid; + else if(flag_id_status == 1) + { + if(*round > 0) + return 1; + else + return 0; + } + return 150; +} + /* * ************************************ diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index bb7b20fdb4..f45f68ef9a 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -202,6 +202,9 @@ long get_si_window_length(mid_t mod_id, int CC_id); int get_num_pdcch_symb(mid_t mod_id, int CC_id); +int get_tpc(mid_t mod_id, mid_t ue_id); + +int get_harq(mid_t mod_id,uint8_t CC_id,mid_t ue_id, int frame, uint8_t subframe, int flag_id_status); /******************* * timer primitves diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index c1af558414..a780c0b6c8 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -926,16 +926,16 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran dl_info[i]->rnti = get_ue_crnti(mod_id, i); dl_info[i]->has_rnti = 1; /*TODO: fill in the right id of this round's HARQ process for this UE*/ - dl_info[i]->harq_process_id = 1; + dl_info[i]->harq_process_id = get_harq(mod_id,UE_PCCID(mod_id,i),i,get_current_frame(mod_id),get_current_subframe(mod_id),0); dl_info[i]->has_harq_process_id = 1; /*TODO: fill in the status of the HARQ process (2 TBs)*/ dl_info[i]->n_harq_status = 2; dl_info[i]->harq_status = malloc(sizeof(uint32_t) * dl_info[i]->n_harq_status); for (j = 0; j < dl_info[j]->n_harq_status; j++) { - dl_info[i]->harq_status[j] = PROTOCOL__PRP_HARQ_STATUS__PRHS_ACK; + dl_info[i]->harq_status[j] = get_harq(mod_id,UE_PCCID(mod_id,i),i,get_current_frame(mod_id),get_current_subframe(mod_id),1); } /*TODO: fill in the serving cell index for this UE */ - dl_info[i]->serv_cell_index = 0; + dl_info[i]->serv_cell_index = UE_PCCID(mod_id,i); dl_info[i]->has_serv_cell_index = 1; } } @@ -962,8 +962,14 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran ul_info[i]->rnti = get_ue_crnti(mod_id, i); ul_info[i]->has_rnti = 1; /*TODO: fill in the Tx power control command for this UE (if available)*/ - ul_info[i]->tpc = 1; - ul_info[i]->has_tpc = 0; + if(get_tpc(mod_id,i) != 1){ + ul_info[i]->tpc = get_tpc(mod_id,i); + ul_info[i]->has_tpc = 1; + } + else{ + ul_info[i]->tpc = get_tpc(mod_id,i); + ul_info[i]->has_tpc = 0; + } /*TODO: fill in the amount of data in bytes in the MAC SDU received in this subframe for the given logical channel*/ ul_info[i]->n_ul_reception = 11; @@ -975,7 +981,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran ul_info[i]->reception_status = PROTOCOL__PRP_RECEPTION_STATUS__PRRS_OK; ul_info[i]->has_reception_status = 1; /*TODO: fill in the serving cell index for this UE */ - ul_info[i]->serv_cell_index = 0; + ul_info[i]->serv_cell_index = UE_PCCID(mod_id,i); ul_info[i]->has_serv_cell_index = 1; } } From e6e117a567b140ea70d13dfc951fbf68056f05f4 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 22 Feb 2016 13:08:26 +0000 Subject: [PATCH 105/413] Implemented LC config reply message --- .../ENB_APP/MESSAGES/V2/config_common.proto | 2 +- openair2/ENB_APP/enb_agent_common.c | 142 ++++++++++++++++-- 2 files changed, 130 insertions(+), 14 deletions(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/config_common.proto b/openair2/ENB_APP/MESSAGES/V2/config_common.proto index f7a4b1ee07..cf07f423aa 100644 --- a/openair2/ENB_APP/MESSAGES/V2/config_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/config_common.proto @@ -158,7 +158,7 @@ message prp_lc_config { optional uint64 e_RAB_max_bitrate_UL = 6; // In bps (GBR only) optional uint64 e_RAB_max_bitrate_DL = 7; // In bps (GBR only) optional uint64 e_RAB_guaranteed_bitrate_UL = 8; // In bps (GBR only) - optional uint64 e_RAB_guranteed_bitrate_DL = 9; // In bps (GBR only) + optional uint64 e_RAB_guaranteed_bitrate_DL = 9; // In bps (GBR only) } enum prp_lc_direction { diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index c07dcb243e..eb19052476 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -322,7 +322,7 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra goto error; } for (i = 0; i < ue_config_reply_msg->n_ue_config; i++) { - ue_config[i] = malloc(sizeof(Protocol__PrpUeConfig *)); + ue_config[i] = malloc(sizeof(Protocol__PrpUeConfig)); protocol__prp_ue_config__init(ue_config[i]); //TODO: Set the RNTI of the ue with id i ue_config[i]->rnti = 1; @@ -478,13 +478,129 @@ int enb_agent_destroy_ue_config_reply(Protocol__ProgranMessage *msg) { } int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { - /* TODO: Create a reply progRAN message with the current LC configurations */ + + xid_t xid; + Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; + Protocol__PrpLcConfigRequest *lc_config_request_msg = input->lc_config_request_msg; + xid = (lc_config_request_msg->header)->xid; + + int i, j; + Protocol__PrpHeader *header; + if(prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_GET_LC_CONFIG_REPLY, &header) != 0) + goto error; + + Protocol__PrpLcConfigReply *lc_config_reply_msg; + lc_config_reply_msg = malloc(sizeof(Protocol__PrpLcConfigReply)); + if(lc_config_reply_msg == NULL) + goto error; + protocol__prp_lc_config_reply__init(lc_config_reply_msg); + lc_config_reply_msg->header = header; + + //TODO: Fill in the actual number of UEs that we are going to report LC configs about + lc_config_reply_msg->n_lc_ue_config = 1; + + Protocol__PrpLcUeConfig **lc_ue_config; + if (lc_config_reply_msg->n_lc_ue_config > 0) { + lc_ue_config = malloc(sizeof(Protocol__PrpLcUeConfig *) * lc_config_reply_msg->n_lc_ue_config); + if (lc_ue_config == NULL) { + goto error; + } + // Fill the config for each UE + for (i = 0; i < lc_config_reply_msg->n_lc_ue_config; i++) { + lc_ue_config[i] = malloc(sizeof(Protocol__PrpLcUeConfig)); + protocol__prp_lc_ue_config__init(lc_ue_config[i]); + //TODO: Set the RNTI of the UE + lc_ue_config[i]->has_rnti = 1; + lc_ue_config[i]->rnti = 1; + //TODO: Set the number of LC configurations that will be reported for this UE + lc_ue_config[i]->n_lc_config = 3; + Protocol__PrpLcConfig **lc_config; + if (lc_ue_config[i]->n_lc_config > 0) { + lc_config = malloc(sizeof(Protocol__PrpLcConfig *) * lc_ue_config[i]->n_lc_config); + if (lc_config == NULL) { + goto error; + } + for (j = 0; j < lc_ue_config[i]->n_lc_config; j++) { + lc_config[j] = malloc(sizeof(Protocol__PrpLcConfig)); + protocol__prp_lc_config__init(lc_config[j]); + //TODO: Set the LC id + lc_config[j]->has_lcid = 1; + lc_config[j]->lcid = 1; + //TODO: Set the LCG of the channel + lc_config[j]->has_lcg = 1; + lc_config[j]->lcg = 1; + //TODO: Set the LC direction + lc_config[j]->has_direction = 1; + lc_config[j]->direction = PROTOCOL__PRP_LC_DIRECTION__PRLCD_BOTH; + //TODO: Bearer type. One of PRQBT_* values + lc_config[j]->has_qos_bearer_type = 1; + lc_config[j]->qos_bearer_type = PROTOCOL__PRP_QOS_BEARER_TYPE__PRQBT_NON_GBR; + //TODO: Set the QCI defined in TS 23.203, coded as defined in TS 36.413 + // One less than the actual QCI value + lc_config[j]->has_qci = 1; + lc_config[j]->qci = 1; + if (lc_config[j]->direction == PROTOCOL__PRP_QOS_BEARER_TYPE__PRQBT_GBR) { + //TODO: Set the max bitrate (UL) + lc_config[j]->has_e_rab_max_bitrate_ul = 1; + lc_config[j]->e_rab_max_bitrate_ul = 1; + //TODO: Set the max bitrate (DL) + lc_config[j]->has_e_rab_max_bitrate_dl = 1; + lc_config[j]->e_rab_max_bitrate_dl = 1; + //TODO: Set the guaranteed bitrate (UL) + lc_config[j]->has_e_rab_guaranteed_bitrate_ul = 1; + lc_config[j]->e_rab_guaranteed_bitrate_ul = 1; + //TODO: Set the guaranteed bitrate (DL) + lc_config[j]->has_e_rab_guaranteed_bitrate_dl = 1; + lc_config[j]->e_rab_guaranteed_bitrate_dl = 1; + } + } + lc_ue_config[i]->lc_config = lc_config; + } + } // end for UE + lc_config_reply_msg->lc_ue_config = lc_ue_config; + } // lc_config_reply_msg->n_lc_ue_config > 0 + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if (*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + (*msg)->lc_config_reply_msg = lc_config_reply_msg; + return 0; + + error: + // TODO: Need to make proper error handling + if (header != NULL) + free(header); + if (lc_config_reply_msg != NULL) + free(lc_config_reply_msg); + if(*msg != NULL) + free(*msg); + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; } int enb_agent_destroy_lc_config_reply(Protocol__ProgranMessage *msg) { - /* TODO: Deallocate memory for a dynamically allocated LC config message */ + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG) + goto error; + + int i, j; + free(msg->lc_config_reply_msg->header); + for (i = 0; i < msg->lc_config_reply_msg->n_lc_ue_config; i++) { + for (j = 0; j < msg->lc_config_reply_msg->lc_ue_config[i]->n_lc_config; j++) { + free(msg->lc_config_reply_msg->lc_ue_config[i]->lc_config[j]); + } + free(msg->lc_config_reply_msg->lc_ue_config[i]->lc_config); + free(msg->lc_config_reply_msg->lc_ue_config[i]); + } + free(msg->lc_config_reply_msg->lc_ue_config); + free(msg->lc_config_reply_msg); + free(msg); return 0; + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; } int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { @@ -498,16 +614,16 @@ int enb_agent_destroy_ue_state_change(Protocol__ProgranMessage *msg) { } int enb_agent_destroy_enb_config_request(Protocol__ProgranMessage *msg) { - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG) - goto error; - free(msg->enb_config_request_msg->header); - free(msg->enb_config_request_msg); - free(msg); - return 0; - - error: - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - return -1; + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG) + goto error; + free(msg->enb_config_request_msg->header); + free(msg->enb_config_request_msg); + free(msg); + return 0; + + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; } int enb_agent_destroy_ue_config_request(Protocol__ProgranMessage *msg) { From 991e995027f42b0d2f68bc8fe7d0d6847b36b35d Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 22 Feb 2016 14:08:11 +0000 Subject: [PATCH 106/413] Changed get_harq function to provide both id and status at once --- openair2/ENB_APP/enb_agent_common.c | 29 ++++++++++++++--------------- openair2/ENB_APP/enb_agent_common.h | 3 ++- openair2/ENB_APP/enb_agent_mac.c | 8 ++++++-- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index eb19052476..51d7161b58 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -781,29 +781,28 @@ int get_tpc(mid_t mod_id, mid_t ue_id) return tpc; } -int get_harq(mid_t mod_id,uint8_t CC_id,mid_t ue_id, int frame, uint8_t subframe, int flag_id_status) //flag_id_status = 0 then id, else status +int get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, const int frame, const uint8_t subframe, int *id, int *status) //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 = malloc(sizeof(uint8_t)); - uint8_t *round = malloc(sizeof(uint8_t)); + uint8_t harq_pid; + uint8_t round; + - uint16_t rnti = get_ue_crnti(mod_id,ue_id); + uint16_t rnti = get_ue_crnti(mod_id,ue_id); - mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&round,0); + mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&round,0); - if(flag_id_status == 0) - return *harq_pid; - else if(flag_id_status == 1) - { - if(*round > 0) - return 1; - else - return 0; - } - return 150; + *id = harq_pid; + if (round > 0) { + *status = 1; + } else { + *status = 0; + } + + return 0; } diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index f45f68ef9a..6a31094417 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -204,7 +204,8 @@ int get_num_pdcch_symb(mid_t mod_id, int CC_id); int get_tpc(mid_t mod_id, mid_t ue_id); -int get_harq(mid_t mod_id,uint8_t CC_id,mid_t ue_id, int frame, uint8_t subframe, int flag_id_status); +int get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, + const int frame, const uint8_t subframe, int *id, int *status); /******************* * timer primitves diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index a780c0b6c8..dfe29bcc3e 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -926,13 +926,17 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran dl_info[i]->rnti = get_ue_crnti(mod_id, i); dl_info[i]->has_rnti = 1; /*TODO: fill in the right id of this round's HARQ process for this UE*/ - dl_info[i]->harq_process_id = get_harq(mod_id,UE_PCCID(mod_id,i),i,get_current_frame(mod_id),get_current_subframe(mod_id),0); + int harq_id; + int harq_status; + get_harq(mod_id,UE_PCCID(mod_id,i),i,get_current_frame(mod_id),get_current_subframe(mod_id),&harq_id, &harq_status); + dl_info[i]->harq_process_id = harq_id; dl_info[i]->has_harq_process_id = 1; /*TODO: fill in the status of the HARQ process (2 TBs)*/ dl_info[i]->n_harq_status = 2; dl_info[i]->harq_status = malloc(sizeof(uint32_t) * dl_info[i]->n_harq_status); for (j = 0; j < dl_info[j]->n_harq_status; j++) { - dl_info[i]->harq_status[j] = get_harq(mod_id,UE_PCCID(mod_id,i),i,get_current_frame(mod_id),get_current_subframe(mod_id),1); + // TODO: This should be different per TB + dl_info[i]->harq_status[j] = harq_status; } /*TODO: fill in the serving cell index for this UE */ dl_info[i]->serv_cell_index = UE_PCCID(mod_id,i); From 465168d2af443989cfa791bd0c6c0a71dc9f3196 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 22 Feb 2016 14:45:39 +0000 Subject: [PATCH 107/413] Integrated sf triggering to MAC layer and fixed bugs in creation of sf trigger message --- openair2/ENB_APP/enb_agent_mac.c | 8 ++++---- openair2/LAYER2/MAC/eNB_scheduler.c | 10 +++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index dfe29bcc3e..f31da89d81 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -918,7 +918,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran if(dl_info == NULL) goto error; //Fill the status of the current HARQ process for each UE - for(i = 0; i++; i < sf_trigger_msg->n_dl_info) { + for(i = 0; i < sf_trigger_msg->n_dl_info; i++) { dl_info[i] = malloc(sizeof(Protocol__PrpDlInfo)); if(dl_info[i] == NULL) goto error; @@ -934,7 +934,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran /*TODO: fill in the status of the HARQ process (2 TBs)*/ dl_info[i]->n_harq_status = 2; dl_info[i]->harq_status = malloc(sizeof(uint32_t) * dl_info[i]->n_harq_status); - for (j = 0; j < dl_info[j]->n_harq_status; j++) { + for (j = 0; j < dl_info[i]->n_harq_status; j++) { // TODO: This should be different per TB dl_info[i]->harq_status[j] = harq_status; } @@ -958,7 +958,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran if(ul_info == NULL) goto error; //Fill the reception info for each transmitting UE - for(i = 0; i++; i < sf_trigger_msg->n_ul_info) { + for(i = 0; i < sf_trigger_msg->n_ul_info; i++) { ul_info[i] = malloc(sizeof(Protocol__PrpUlInfo)); if(ul_info[i] == NULL) goto error; @@ -978,7 +978,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran given logical channel*/ ul_info[i]->n_ul_reception = 11; ul_info[i]->ul_reception = malloc(sizeof(uint32_t) * ul_info[i]->n_ul_reception); - for (j = 0; j < ul_info[j]->n_ul_reception; j++) { + for (j = 0; j < ul_info[i]->n_ul_reception; j++) { ul_info[i]->ul_reception[j] = 100; } /*TODO: Fill in the reception status for each UEs data*/ diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 54b31b6e64..a39b9efb54 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -71,6 +71,7 @@ #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 #define ENABLE_ENB_AGENT_DL_SCHEDULER +//#define DISABLE_SF_TRIGGER //#define DEBUG_HEADER_PARSING 1 //#define DEBUG_PACKET_TRACE 1 @@ -207,7 +208,14 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } - + +#ifndef DISABLE_SF_TRIGGER + //Send subframe trigger to the controller + if (mac_agent_registered[module_idP]) { + agent_mac_xface[module_idP]->enb_agent_send_sf_trigger(module_idP); + } +#endif + //if (subframeP%5 == 0) //#ifdef EXMIMO PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, 0,module_idP); From 95d51446f8a1cab7a7e14773d6ed6756020bec99 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 22 Feb 2016 15:22:21 +0000 Subject: [PATCH 108/413] Added ue_state_change stub implementation --- openair2/ENB_APP/enb_agent_common.c | 73 +++++++++++++++++++++++++-- openair2/ENB_APP/enb_agent_mac.c | 2 +- openair2/ENB_APP/enb_agent_mac_defs.h | 6 +++ 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 51d7161b58..1e7efe920a 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -604,13 +604,80 @@ int enb_agent_destroy_lc_config_reply(Protocol__ProgranMessage *msg) { } int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { - /* TODO: Create a progRAN message with the state changes requested for the UE with RNTI rnti */ - return 0; + int size; + Protocol__ProgranMessage *msg; + Protocol__PrpHeader *header; + void *data; + int priority; + err_code_t err_code; + + int xid = 0; + + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_UE_STATE_CHANGE, &header) != 0) + goto error; + + Protocol__PrpUeStateChange *ue_state_change_msg; + ue_state_change_msg = malloc(sizeof(Protocol__PrpUeStateChange)); + if(ue_state_change_msg == NULL) { + goto error; + } + protocol__prp_ue_state_change__init(ue_state_change_msg); + ue_state_change_msg->has_type = 1; + ue_state_change_msg->type = state_change; + + Protocol__PrpUeConfig *config; + config = malloc(sizeof(Protocol__PrpUeConfig)); + if (config == NULL) { + goto error; + } + protocol__prp_ue_config__init(config); + if (state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_DEACTIVATED) { + // Simply set the rnti of the UE + config->has_rnti = 1; + config->rnti = rnti; + } else if (state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_UPDATED + || state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_ACTIVATED) { + // TODO: Set the whole UE configuration message + + } else if (state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_MOVED) { + // TODO: Not supported for now. Leave blank + } + + ue_state_change_msg->config = config; + msg = malloc(sizeof(Protocol__ProgranMessage)); + if (msg == NULL) { + goto error; + } + protocol__progran_message__init(msg); + msg->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG; + msg->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + msg->ue_state_change_msg = ue_state_change_msg; + + data = enb_agent_pack_message(msg, &size); + /*Send sr info using the MAC channel of the eNB*/ + if (enb_agent_msg_send(mod_id, ENB_AGENT_DEFAULT, data, size, priority)) { + err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + goto error; + } + + LOG_D(ENB_AGENT,"sent message with size %d\n", size); + return; + error: + LOG_D(ENB_AGENT, "Could not send UE state message\n"); } int enb_agent_destroy_ue_state_change(Protocol__ProgranMessage *msg) { - /* TODO: Dealocate memory for a dynamically allocated UE state change message */ + if(msg->msg_case != PROTOCOL__PROGRAN_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 enb_agent_destroy_enb_config_request(Protocol__ProgranMessage *msg) { diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index f31da89d81..5c279958fe 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -1266,7 +1266,7 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_send_sf_trigger = enb_agent_send_sf_trigger; xface->enb_agent_send_update_mac_stats = enb_agent_send_update_mac_stats; xface->enb_agent_schedule_ue_spec = schedule_ue_spec_default; - + xface->enb_agent_notify_ue_state_change = enb_agent_ue_state_change; mac_agent_registered[mod_id] = 1; agent_mac_xface[mod_id] = xface; diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/enb_agent_mac_defs.h index 6e960cdb69..657fc94fe4 100644 --- a/openair2/ENB_APP/enb_agent_mac_defs.h +++ b/openair2/ENB_APP/enb_agent_mac_defs.h @@ -62,6 +62,12 @@ typedef struct { void (*enb_agent_schedule_ue_spec)(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, Protocol__ProgranMessage *dl_info); + + /// Notify the controller for a state change of a particular UE, by sending the proper + /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) + void (*enb_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, + uint32_t state_change); + /*TODO: Fill in with the rest of the MAC layer technology specific callbacks (UL/DL scheduling, RACH info etc)*/ } AGENT_MAC_xface; From 02686ce804ffad77c279d1d7a85ea54399701f34 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 22 Feb 2016 15:29:10 +0000 Subject: [PATCH 109/413] Added temporary notification for the deactivation of a UE in the MAC --- openair2/LAYER2/MAC/eNB_scheduler.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index a39b9efb54..774feda961 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -135,6 +135,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, if (mac_xface->get_eNB_UE_stats(module_idP, CC_id, rnti)==NULL) { 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 (mac_agent_registered[module_idP]) { + agent_mac_xface[module_idP]->enb_agent_notify_ue_state_change(module_idP, + rnti, + PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_DEACTIVATED); + } } i = next_i; } From 71f64675816923d3a8d122e62b76d0a0120908bb Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 22 Feb 2016 17:28:50 +0100 Subject: [PATCH 110/413] adaption for lte-softmodem compilation --- openair1/PHY/LTE_TRANSPORT/proto.h | 2 +- openair1/PHY/TOOLS/lte_phy_scope.c | 2 +- targets/RT/USER/lte-softmodem.c | 28 ++++++++++++++-------------- targets/RT/USER/lte-ue.c | 2 +- targets/RT/USER/sched_rx_pdsch.c | 4 +++- targets/SIMU/USER/init_lte.c | 10 +++++----- 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index bed82c0e68..416bff82c4 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -56,7 +56,7 @@ void free_eNB_dlsch(LTE_eNB_DLSCH_t *dlsch); void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch, uint8_t abstraction_flag); -/** \fn new_eNB_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint8_t abstraction_flag) +/** \fn new_eNB_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint8_t abstraction_flag, LTE_DL_FRAME_PARMS* frame_parms) \brief This function allocates structures for a particular DLSCH at eNB @returns Pointer to DLSCH to be removed @param Kmimo Kmimo factor from 36-212/36-213 diff --git a/openair1/PHY/TOOLS/lte_phy_scope.c b/openair1/PHY/TOOLS/lte_phy_scope.c index 736e3e5ed7..5efa4eee7b 100644 --- a/openair1/PHY/TOOLS/lte_phy_scope.c +++ b/openair1/PHY/TOOLS/lte_phy_scope.c @@ -491,7 +491,7 @@ void phy_scope_UE(FD_lte_phy_scope_ue *form, LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_ue->lte_frame_parms; int nsymb_ce = frame_parms->ofdm_symbol_size;//*frame_parms->symbols_per_tti; uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx; - uint8_t nb_antennas_tx = frame_parms->nb_antennas_ports_eNB; + uint8_t nb_antennas_tx = frame_parms->nb_antenna_ports_eNB; int16_t **rxsig_t; int16_t **chest_t; int16_t **chest_f; diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index baba632de1..cf1a374dae 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -2476,7 +2476,7 @@ static void get_options (int argc, char **argv) frame_parms[CC_id]->N_RB_DL = enb_properties->properties[i]->N_RB_DL[CC_id]; frame_parms[CC_id]->N_RB_UL = enb_properties->properties[i]->N_RB_DL[CC_id]; frame_parms[CC_id]->nb_antennas_tx = enb_properties->properties[i]->nb_antennas_tx[CC_id]; - frame_parms[CC_id]->nb_antennas_tx_eNB = enb_properties->properties[i]->nb_antennas_tx[CC_id]; + frame_parms[CC_id]->nb_antenna_ports_eNB = enb_properties->properties[i]->nb_antennas_tx[CC_id]; frame_parms[CC_id]->nb_antennas_rx = enb_properties->properties[i]->nb_antennas_rx[CC_id]; //} // j } @@ -2594,18 +2594,18 @@ int main( int argc, char **argv ) for (CC_id=0; CC_idframe_type = FDD; - frame_parms[CC_id]->tdd_config = 3; - frame_parms[CC_id]->tdd_config_S = 0; - frame_parms[CC_id]->N_RB_DL = 100; - frame_parms[CC_id]->N_RB_UL = 100; - frame_parms[CC_id]->Ncp = NORMAL; - frame_parms[CC_id]->Ncp_UL = NORMAL; - frame_parms[CC_id]->Nid_cell = Nid_cell; - frame_parms[CC_id]->num_MBSFN_config = 0; - frame_parms[CC_id]->nb_antennas_tx_eNB = 1; - frame_parms[CC_id]->nb_antennas_tx = 1; - frame_parms[CC_id]->nb_antennas_rx = 1; + frame_parms[CC_id]->frame_type = FDD; + frame_parms[CC_id]->tdd_config = 3; + frame_parms[CC_id]->tdd_config_S = 0; + frame_parms[CC_id]->N_RB_DL = 100; + frame_parms[CC_id]->N_RB_UL = 100; + frame_parms[CC_id]->Ncp = NORMAL; + frame_parms[CC_id]->Ncp_UL = NORMAL; + frame_parms[CC_id]->Nid_cell = Nid_cell; + frame_parms[CC_id]->num_MBSFN_config = 0; + frame_parms[CC_id]->nb_antenna_ports_eNB = 1; + frame_parms[CC_id]->nb_antennas_tx = 1; + frame_parms[CC_id]->nb_antennas_rx = 1; } for (CC_id=0; CC_idnb_antennas_tx = 1; frame_parms[CC_id]->nb_antennas_rx = 1; - frame_parms[CC_id]->nb_antennas_tx_eNB = (transmission_mode == 1) ? 1 : 2; //initial value overwritten by initial sync later + frame_parms[CC_id]->nb_antenna_ports_eNB = (transmission_mode == 1 || transmission_mode ==7) ? 1 : 2; //initial value overwritten by initial sync later } frame_parms[CC_id]->mode1_flag = (transmission_mode == 1) ? 1 : 0; diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 6293ad4264..d5bc2c8ee9 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -1636,7 +1636,7 @@ void *UE_thread(void *arg) UE->lte_frame_parms.phich_config_common.phich_duration, UE->lte_frame_parms.phich_config_common.phich_resource, UE->lte_frame_parms.Nid_cell, - UE->lte_frame_parms.nb_antennas_tx_eNB, + UE->lte_frame_parms.nb_antenna_ports_eNB, freq_offset, UE->lte_ue_common_vars.freq_offset, UE->PHY_measurements.rx_power_avg_dB[0], diff --git a/targets/RT/USER/sched_rx_pdsch.c b/targets/RT/USER/sched_rx_pdsch.c index be1ffbd752..66224bcf92 100644 --- a/targets/RT/USER/sched_rx_pdsch.c +++ b/targets/RT/USER/sched_rx_pdsch.c @@ -156,7 +156,9 @@ static void * rx_pdsch_thread(void *param) get_Qm(UE->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->mcs), UE->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->Nl, UE->lte_ue_pdcch_vars[eNB_id]->num_pdcch_symbols, - UE->frame_rx,subframe); + UE->frame_rx, + subframe, + UE->transmission_mode[eNB_id]); if ((UE->transmission_mode[eNB_id] == 5) && (UE->dlsch_ue[eNB_id][0]->harq_processes[harq_pid]->dl_power_off==0) && diff --git a/targets/SIMU/USER/init_lte.c b/targets/SIMU/USER/init_lte.c index bbb99260eb..c031d34bca 100644 --- a/targets/SIMU/USER/init_lte.c +++ b/targets/SIMU/USER/init_lte.c @@ -76,7 +76,7 @@ PHY_VARS_eNB* init_lte_eNB(LTE_DL_FRAME_PARMS *frame_parms, for (i=0; idlsch_eNB[i][j] = new_eNB_dlsch(1,NUMBER_OF_HARQ_PID_MAX,NSOFT,frame_parms->N_RB_DL,abstraction_flag); + PHY_vars_eNB->dlsch_eNB[i][j] = new_eNB_dlsch(1,NUMBER_OF_HARQ_PID_MAX,NSOFT,frame_parms->N_RB_DL,abstraction_flag,frame_parms); if (!PHY_vars_eNB->dlsch_eNB[i][j]) { LOG_E(PHY,"Can't get eNB dlsch structures for UE %d \n", i); @@ -128,11 +128,11 @@ PHY_VARS_eNB* init_lte_eNB(LTE_DL_FRAME_PARMS *frame_parms, exit(-1); } - PHY_vars_eNB->dlsch_eNB_SI = new_eNB_dlsch(1,1,NSOFT,frame_parms->N_RB_DL, abstraction_flag); + PHY_vars_eNB->dlsch_eNB_SI = new_eNB_dlsch(1,1,NSOFT,frame_parms->N_RB_DL, abstraction_flag, frame_parms); LOG_D(PHY,"eNB %d : SI %p\n",eNB_id,PHY_vars_eNB->dlsch_eNB_SI); - PHY_vars_eNB->dlsch_eNB_ra = new_eNB_dlsch(1,1,NSOFT,frame_parms->N_RB_DL, abstraction_flag); + PHY_vars_eNB->dlsch_eNB_ra = new_eNB_dlsch(1,1,NSOFT,frame_parms->N_RB_DL, abstraction_flag, frame_parms); LOG_D(PHY,"eNB %d : RA %p\n",eNB_id,PHY_vars_eNB->dlsch_eNB_ra); - PHY_vars_eNB->dlsch_eNB_MCH = new_eNB_dlsch(1,NUMBER_OF_HARQ_PID_MAX,NSOFT,frame_parms->N_RB_DL, 0); + PHY_vars_eNB->dlsch_eNB_MCH = new_eNB_dlsch(1,NUMBER_OF_HARQ_PID_MAX,NSOFT,frame_parms->N_RB_DL, 0, frame_parms); LOG_D(PHY,"eNB %d : MCH %p\n",eNB_id,PHY_vars_eNB->dlsch_eNB_MCH); @@ -253,7 +253,7 @@ void init_lte_vars(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs], (frame_parms[CC_id])->Nid_cell = Nid_cell; (frame_parms[CC_id])->nushift = (Nid_cell%6); (frame_parms[CC_id])->nb_antennas_tx = (transmission_mode == 1) ? 1 : 2; - (frame_parms[CC_id])->nb_antennas_tx_eNB = (transmission_mode == 1) ? 1 : 2; + (frame_parms[CC_id])->nb_antenna_ports_eNB = (transmission_mode == 1 || transmission_mode == 7) ? 1 : 2; (frame_parms[CC_id])->nb_antennas_rx = (transmission_mode == 1) ? 1 : 2; (frame_parms[CC_id])->mode1_flag = (transmission_mode == 1) ? 1 : 0; From 7dd05df4ea724355fa80ea620db2ccba28f8ed0f Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 23 Feb 2016 10:29:53 +0000 Subject: [PATCH 111/413] Added configuration support for local cache --- openair2/ENB_APP/enb_agent.c | 8 ++++++++ openair2/ENB_APP/enb_agent_defs.h | 1 + openair2/ENB_APP/enb_agent_extern.h | 2 ++ openair2/ENB_APP/enb_config.c | 7 ++++++- openair2/ENB_APP/enb_config.h | 1 + .../CONF/enb.band7.agent.oaisim.local_no_mme.conf | 1 + 6 files changed, 19 insertions(+), 1 deletion(-) diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index c9c42a41d9..7d2029b37f 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -52,6 +52,7 @@ enb_agent_instance_t enb_agent[NUM_MAX_ENB]; char in_ip[40]; static uint16_t in_port; +char local_cache[40]; void *send_thread(void *args); void *receive_thread(void *args); @@ -203,6 +204,13 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ /* * check the configuration */ + if (enb_properties->properties[mod_id]->enb_agent_cache != NULL) { + strncpy(local_cache, enb_properties->properties[mod_id]->enb_agent_cache, sizeof(local_cache)); + local_cache[sizeof(local_cache) - 1] = 0; + } else { + strcpy(local_cache, DEFAULT_ENB_AGENT_CACHE); + } + if (enb_properties->properties[mod_id]->enb_agent_ipv4_address != NULL) { strncpy(in_ip, enb_properties->properties[mod_id]->enb_agent_ipv4_address, sizeof(in_ip) ); in_ip[sizeof(in_ip) - 1] = 0; // terminate string diff --git a/openair2/ENB_APP/enb_agent_defs.h b/openair2/ENB_APP/enb_agent_defs.h index 020c631ff1..9d1e3f75fc 100644 --- a/openair2/ENB_APP/enb_agent_defs.h +++ b/openair2/ENB_APP/enb_agent_defs.h @@ -47,6 +47,7 @@ #define NUM_MAX_UE 2048 #define DEFAULT_ENB_AGENT_IPv4_ADDRESS "127.0.0.1" #define DEFAULT_ENB_AGENT_PORT 2210 +#define DEFAULT_ENB_AGENT_CACHE "/mnt/tmpfs" typedef enum { diff --git a/openair2/ENB_APP/enb_agent_extern.h b/openair2/ENB_APP/enb_agent_extern.h index 1ef2250483..0dd7cfb90f 100644 --- a/openair2/ENB_APP/enb_agent_extern.h +++ b/openair2/ENB_APP/enb_agent_extern.h @@ -44,6 +44,8 @@ //extern msg_context_t shared_ctxt[NUM_MAX_ENB][ENB_AGENT_MAX]; +extern char local_cache[40]; + extern AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB]; extern unsigned int mac_agent_registered[NUM_MAX_ENB]; diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index d5a70734fd..6983b8c2c6 100755 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -174,6 +174,7 @@ #define ENB_CONFIG_STRING_ENB_AGENT_INTERFACE_NAME "ENB_AGENT_INTERFACE_NAME" #define ENB_CONFIG_STRING_ENB_AGENT_IPV4_ADDRESS "ENB_AGENT_IPV4_ADDRESS" #define ENB_CONFIG_STRING_ENB_AGENT_PORT "ENB_AGENT_PORT" +#define ENB_CONFIG_STRING_ENB_AGENT_CACHE "ENB_AGENT_CACHE" #define ENB_CONFIG_STRING_RRH_GW_CONFIG "rrh_gw_config" #define ENB_CONFIG_STRING_RRH_GW_LOCAL_IF_NAME "local_if_name" @@ -325,6 +326,7 @@ static void enb_config_display(void) printf( "\tInterface name: \t%s:\n",enb_properties.properties[i]->enb_agent_interface_name); printf( "\tInterface IP Address: \t%s:\n",enb_properties.properties[i]->enb_agent_ipv4_address); printf( "\tInterface PORT: \t%d:\n\n",enb_properties.properties[i]->enb_agent_port); + printf( "\tCache directory: \t%s:\n",enb_properties.properties[i]->enb_agent_cache); #endif @@ -641,6 +643,7 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) char* enb_agent_interface_name = NULL; char* enb_agent_ipv4_address = NULL; libconfig_int enb_agent_port = 0; + char* enb_agent_cache = NULL; libconfig_int otg_ue_id = 0; char* otg_app_type = NULL; char* otg_bg_traffic = NULL; @@ -2363,6 +2366,8 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) (const char **)&enb_agent_ipv4_address) && config_setting_lookup_int(subsetting, ENB_CONFIG_STRING_ENB_AGENT_PORT, &enb_agent_port) + && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_AGENT_CACHE, + (const char **)&enb_agent_cache) ) ) { enb_properties.properties[enb_properties_index]->enb_agent_interface_name = strdup(enb_agent_interface_name); @@ -2374,7 +2379,7 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) }*/ enb_properties.properties[enb_properties_index]->enb_agent_port = enb_agent_port; - + enb_properties.properties[enb_properties_index]->enb_agent_cache = strdup(enb_agent_cache); } } diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h index 25b6c88479..2e873fdf52 100755 --- a/openair2/ENB_APP/enb_config.h +++ b/openair2/ENB_APP/enb_config.h @@ -224,6 +224,7 @@ typedef struct Enb_properties_s { char *enb_agent_interface_name; in_addr_t enb_agent_ipv4_address; tcp_udp_port_t enb_agent_port; + char *enb_agent_cache; /* Nb of RRH to connect to */ uint8_t nb_rrh_gw; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf index 045a2855a0..578a2e3f2c 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf @@ -123,6 +123,7 @@ eNBs = ENB_AGENT_INTERFACE_NAME = "eth0"; ENB_AGENT_IPV4_ADDRESS = "127.0.0.1/24"; ENB_AGENT_PORT = 2210; + ENB_AGENT_CACHE = "/mnt/tmpfs"; }; log_config : From d8cc6d95e62d5b704891f73f77c67df297a8f59a Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 23 Feb 2016 10:47:08 +0000 Subject: [PATCH 112/413] Added support for control delegation and dynamic loading of libraries --- cmake_targets/CMakeLists.txt | 13 +++++++++---- .../ENB_APP/MESSAGES/V2/control_delegation.proto | 6 ++++++ openair2/ENB_APP/MESSAGES/V2/header.proto | 3 +++ openair2/ENB_APP/MESSAGES/V2/progran.proto | 13 +++++++++++++ 4 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 openair2/ENB_APP/MESSAGES/V2/control_delegation.proto diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 49d18c80f8..85a6f35339 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -796,6 +796,7 @@ if (ENB_AGENT_SB_IF) ${PRPT_MSG_DIR}/mac_primitives.proto ${PRPT_MSG_DIR}/config_messages.proto ${PRPT_MSG_DIR}/config_common.proto + ${PRPT_MSG_DIR}/control_delegation.proto ) set(PRPT_C_DIR ${protobuf_generated_dir}/${PRPTDIR}) @@ -812,6 +813,7 @@ if (ENB_AGENT_SB_IF) ${PRPT_C_DIR}/mac_primitives.pb-c.c ${PRPT_C_DIR}/config_messages.pb-c.c ${PRPT_C_DIR}/config_common.pb-c.c + ${PRPT_C_DIR}/control_delegation.pb-c.c ) file(GLOB prpt_h ${PRPT_C_DIR}/*.h) @@ -1109,6 +1111,9 @@ add_library(L2 ${ENB_APP_SRC} ${OPENAIR2_DIR}/RRC/L2_INTERFACE/openair_rrc_L2_interface.c) +#Test for adding a shared library +add_library(alt_sched SHARED ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue_alt.c) + # L3 Libs ########################## @@ -1604,7 +1609,7 @@ target_link_libraries (lte-softmodem target_link_libraries (lte-softmodem ${LIBXML2_LIBRARIES}) -target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${option_HW_lib} ${option_TP_lib} ${XFORMS_LIBRARIES} ${PROTOBUF_LIB}) +target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${option_HW_lib} ${option_TP_lib} ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS}) target_link_libraries (lte-softmodem ${LIBBOOST_LIBRARIES}) target_link_libraries (lte-softmodem ${LIB_LMS_LIBRARIES}) @@ -1638,7 +1643,7 @@ target_link_libraries (lte-softmodem-nos1 -Wl,--end-group ) target_link_libraries (lte-softmodem-nos1 ${LIBXML2_LIBRARIES}) -target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib} ${option_TP_lib} ${XFORMS_LIBRARIES} ${PROTOBUF_LIB}) +target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib} ${option_TP_lib} ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS}) target_link_libraries (lte-softmodem-nos1 ${LIBBOOST_LIBRARIES}) target_link_libraries (lte-softmodem-nos1 ${LIB_LMS_LIBRARIES}) @@ -1770,12 +1775,12 @@ add_executable(oaisim_nos1 target_include_directories(oaisim_nos1 PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim_nos1 -Wl,--start-group - RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} + RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} -Wl,--end-group ) target_link_libraries (oaisim_nos1 ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) target_link_libraries (oaisim_nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib} ${option_TP_lib} - ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES} ${PROTOBUF_LIB}) + ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS}) #Force link with forms, regardless XFORMS option target_link_libraries (oaisim_nos1 forms) diff --git a/openair2/ENB_APP/MESSAGES/V2/control_delegation.proto b/openair2/ENB_APP/MESSAGES/V2/control_delegation.proto new file mode 100644 index 0000000000..c5ce58d3a2 --- /dev/null +++ b/openair2/ENB_APP/MESSAGES/V2/control_delegation.proto @@ -0,0 +1,6 @@ +//'syntax = "proto2";' +package protocol; + +enum prp_control_delegation_type { + PRCDT_MAC_DL_UE_SCHEDULER = 1; // DL UE scheduler delegation +} \ No newline at end of file diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index 8e6adb1fda..6ce9959104 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -35,5 +35,8 @@ enum prp_type { // UE state change messages PRPT_UE_STATE_CHANGE = 14; + + // Control delegation messages + PRPT_DELEGATE_CONTROL = 15; } diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index 44fffc7ead..6b7b784629 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -6,6 +6,7 @@ import "header.proto"; import "time_common.proto"; import "config_messages.proto"; import "controller_commands.proto"; +import "control_delegation.proto"; message progran_message { optional progran_direction msg_dir = 100; @@ -25,6 +26,7 @@ message progran_message { prp_lc_config_reply lc_config_reply_msg = 13; prp_dl_mac_config dl_mac_config_msg = 14; prp_ue_state_change ue_state_change_msg = 15; + prp_control_delegation control_delegation_msg = 16; } } @@ -170,6 +172,17 @@ message prp_ue_state_change { optional prp_ue_config config = 3; // Body of the message (based on type) } +// +// Control delegation message +// + +message prp_control_delegation { + optional prp_header header = 1; + optional uint32 delegation_type = 2; // Bitmap of PRCDT_* flags + optional bytes payload = 3; // Byte array of shared lib containing the delegated functions + repeated string name = 4; // The delegated functions names ordered based on bitmap flags +} + // Extensions of the echo request and reply // messages for carrying a latency value in ms message prp_echo_request_latency { From 25e5e3b8378aab8090e650721a0c53ef3d4a9798 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 23 Feb 2016 11:08:14 +0000 Subject: [PATCH 113/413] Added script to automatically create cache for agent --- cmake_targets/tools/make_agent_cache | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100755 cmake_targets/tools/make_agent_cache diff --git a/cmake_targets/tools/make_agent_cache b/cmake_targets/tools/make_agent_cache new file mode 100755 index 0000000000..d2eab20fc0 --- /dev/null +++ b/cmake_targets/tools/make_agent_cache @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +CACHE_DIR=/mnt/oai_agent_cache + +if [ ! -d $CACHE_DIR ]; then + echo "Creating cache dir in $CACHE_DIR" + sudo mkdir $CACHE_DIR +fi + +if grep -qs "$CACHE_DIR" /proc/mounts; then + echo "Agent cache is already mounted" +else + echo "Agent cache was not mounted" + echo "Mounting..." + sudo mount -o size=100m -t tmpfs none "$CACHE_DIR" + if [ $? -eq 0 ]; then + echo "Mount success" + else + echo "Something went wrong with the mount" + fi +fi From 46724972062357e8323b03c40cdb13967e4a35d5 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 23 Feb 2016 12:56:09 +0000 Subject: [PATCH 114/413] Added support for DL UE scheduler control delegation --- openair2/ENB_APP/enb_agent_common.c | 74 +++++++++++++++++++ openair2/ENB_APP/enb_agent_common.h | 3 + openair2/ENB_APP/enb_agent_defs.h | 2 +- openair2/ENB_APP/enb_agent_handler.c | 2 + .../enb.band7.agent.oaisim.local_no_mme.conf | 2 +- 5 files changed, 81 insertions(+), 2 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 1e7efe920a..f4f8c333d0 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -34,8 +34,12 @@ * \version 0.1 */ +#include +#include +#include #include "enb_agent_common.h" +#include "enb_agent_extern.h" #include "PHY/extern.h" #include "log.h" @@ -703,6 +707,76 @@ int enb_agent_destroy_lc_config_request(Protocol__ProgranMessage *msg) { return 0; } +// call this function to start a nanosecond-resolution timer +struct timespec timer_start(){ + struct timespec start_time; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time); + return start_time; +} + +// call this function to end a timer, returning nanoseconds elapsed as a long +long timer_end(struct timespec start_time){ + struct timespec end_time; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time); + long diffInNanos = end_time.tv_nsec - start_time.tv_nsec; + return diffInNanos; +} + +int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { + + Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; + Protocol__PrpControlDelegation *control_delegation_msg = input->control_delegation_msg; + + uint32_t delegation_type = control_delegation_msg->delegation_type; + + void *lib; + int i; + + struct timespec vartime = timer_start(); + + //Write the payload lib into a file in the cache and load the lib + char lib_name[120]; + char target[512]; + snprintf(lib_name, sizeof(lib_name), "/delegation_lib_%d.so", control_delegation_msg->header->xid); + strcpy(target, local_cache); + strcat(target, lib_name); + + FILE *f; + f = fopen(target, "wb"); + fwrite(control_delegation_msg->payload.data, control_delegation_msg->payload.len, 1, f); + fclose(f); + lib = dlopen(target, RTLD_NOW); + if (lib == NULL) { + goto error; + } + + i = 0; + //Check functions that need to be delegated + + //DL UE scheduler delegation + if (delegation_type & PROTOCOL__PRP_CONTROL_DELEGATION_TYPE__PRCDT_MAC_DL_UE_SCHEDULER) { + void *loaded_scheduler = dlsym(lib, control_delegation_msg->name[i]); + i++; + if (loaded_scheduler) { + if (mac_agent_registered[mod_id]) { + agent_mac_xface[mod_id]->enb_agent_schedule_ue_spec = loaded_scheduler; + LOG_D(ENB_APP,"Delegated control for DL UE scheduler successfully\n"); + } + } + } + long time_elapsed_nanos = timer_end(vartime); + LOG_I(ENB_AGENT, "DID IT IN %lld\n", time_elapsed_nanos); + *msg = NULL; + return 0; + + error: + return -1; +} + +int enb_agent_destroy_control_delegation(Protocol__ProgranMessage *msg) { + /*TODO: Dealocate memory for a dynamically allocated control delegation message*/ +} + /* * get generic info from RAN */ diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 6a31094417..73ce0ec788 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -111,6 +111,9 @@ int enb_agent_destroy_lc_config_request(Protocol__ProgranMessage *msg); int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change); int enb_agent_destroy_ue_state_change(Protocol__ProgranMessage *msg); +int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_destroy_control_delegation(Protocol__ProgranMessage *msg); + Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, uint8_t *data, uint32_t size); diff --git a/openair2/ENB_APP/enb_agent_defs.h b/openair2/ENB_APP/enb_agent_defs.h index 9d1e3f75fc..8d71aa2db3 100644 --- a/openair2/ENB_APP/enb_agent_defs.h +++ b/openair2/ENB_APP/enb_agent_defs.h @@ -47,7 +47,7 @@ #define NUM_MAX_UE 2048 #define DEFAULT_ENB_AGENT_IPv4_ADDRESS "127.0.0.1" #define DEFAULT_ENB_AGENT_PORT 2210 -#define DEFAULT_ENB_AGENT_CACHE "/mnt/tmpfs" +#define DEFAULT_ENB_AGENT_CACHE "/mnt/oai_agent_cache" typedef enum { diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 2162a29314..d4e5706b11 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -57,6 +57,7 @@ enb_agent_message_decoded_callback agent_messages_callback[][3] = { {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG*/ {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG*/ {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG*/ + {enb_agent_control_delegation, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_CONTROL_DELEGATION_MSG*/ }; @@ -76,6 +77,7 @@ enb_agent_message_destruction_callback message_destruction_callback[] = { enb_agent_destroy_lc_config_reply, enb_agent_mac_destroy_dl_config, enb_agent_destroy_ue_state_change, + enb_agent_destroy_control_delegation, }; static const char *enb_agent_direction2String[] = { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf index 578a2e3f2c..f95cfd9389 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf @@ -123,7 +123,7 @@ eNBs = ENB_AGENT_INTERFACE_NAME = "eth0"; ENB_AGENT_IPV4_ADDRESS = "127.0.0.1/24"; ENB_AGENT_PORT = 2210; - ENB_AGENT_CACHE = "/mnt/tmpfs"; + ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; }; log_config : From 0ec3cfdf04ab7b63aeb7a787136b86c19499ad67 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 23 Feb 2016 14:18:49 +0000 Subject: [PATCH 115/413] Added UE and LC config API function calls --- openair2/ENB_APP/enb_agent_common.c | 709 +++++++++++++++++----------- openair2/ENB_APP/enb_agent_common.h | 56 +++ openair2/LAYER2/MAC/extern.h | 2 + 3 files changed, 499 insertions(+), 268 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index f4f8c333d0..4a175c244e 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -47,6 +47,7 @@ void * enb[NUM_MAX_ENB]; void * enb_ue[NUM_MAX_ENB]; void * enb_rrc[NUM_MAX_ENB]; +void * enb_ue_rrc[NUM_MAX_ENB]; /* * message primitives */ @@ -296,170 +297,6 @@ int enb_agent_destroy_enb_config_reply(Protocol__ProgranMessage *msg) { return -1; } -int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { - - xid_t xid; - Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; - Protocol__PrpUeConfigRequest *ue_config_request_msg = input->ue_config_request_msg; - xid = (ue_config_request_msg->header)->xid; - - int i; - - Protocol__PrpHeader *header; - if(prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_GET_UE_CONFIG_REPLY, &header) != 0) - goto error; - - Protocol__PrpUeConfigReply *ue_config_reply_msg; - ue_config_reply_msg = malloc(sizeof(Protocol__PrpUeConfigReply)); - if(ue_config_reply_msg == NULL) - goto error; - protocol__prp_enb_config_reply__init(ue_config_reply_msg); - ue_config_reply_msg->header = header; - - //TODO: Fill in the actual number of UEs that are currently connected - ue_config_reply_msg->n_ue_config = 1; - - Protocol__PrpUeConfig **ue_config; - if (ue_config_reply_msg->n_ue_config > 0) { - ue_config = malloc(sizeof(Protocol__PrpUeConfig *) * ue_config_reply_msg->n_ue_config); - if (ue_config == NULL) { - goto error; - } - for (i = 0; i < ue_config_reply_msg->n_ue_config; i++) { - ue_config[i] = malloc(sizeof(Protocol__PrpUeConfig)); - protocol__prp_ue_config__init(ue_config[i]); - //TODO: Set the RNTI of the ue with id i - ue_config[i]->rnti = 1; - ue_config[i]->has_rnti = 1; - //TODO: Set the DRX configuration (optional) - //Not supported for now, so we do not set it - - //TODO: Set the time_alignment_timer - ue_config[i]->time_alignment_timer = 1; - ue_config[i]->has_time_alignment_timer = 1; - //TODO: Set the measurement gap configuration pattern - ue_config[i]->meas_gap_config_pattern = 1; - ue_config[i]->has_meas_gap_config_pattern = 1; - //TODO: Set the measurement gap offset if applicable - ue_config[i]->meas_gap_config_sf_offset = 1; - ue_config[i]->has_meas_gap_config_sf_offset = 1; - //TODO: Set the SPS configuration (Optional) - //Not supported for noe, 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 - - //TODO: Set the transmission mode - ue_config[i]->transmission_mode = 1; - ue_config[i]->has_transmission_mode = 1; - - //TODO: Set the aggregated bit-rate of the non-gbr bearer (UL) - ue_config[i]->ue_aggregated_max_bitrate_ul = 1; - ue_config[i]->has_ue_aggregated_max_bitrate_ul = 1; - - //TODO: Set the aggregated bit-rate of the non-gbr bearer (DL) - ue_config[i]->ue_aggregated_max_bitrate_dl = 1; - ue_config[i]->has_ue_aggregated_max_bitrate_dl = 1; - - //TODO: Set the UE capabilities - Protocol__PrpUeCapabilities *capabilities; - capabilities = malloc(sizeof(Protocol__PrpUeCapabilities)); - protocol__prp_ue_capabilities__init(capabilities); - //TODO: Set half duplex (FDD operation) - capabilities->has_half_duplex = 1; - capabilities->half_duplex = 1; - //TODO: Set intra-frame hopping flag - capabilities->has_intra_sf_hopping = 1; - capabilities->intra_sf_hopping = 1; - //TODO: Set support for type 2 hopping with n_sb > 1 - capabilities->has_type2_sb_1 = 1; - capabilities->type2_sb_1 = 1; - //TODO: Set ue category - capabilities->has_ue_category = 1; - capabilities->ue_category = 1; - //TODO: Set UE support for resource allocation type 1 - capabilities->has_res_alloc_type1 = 1; - capabilities->res_alloc_type1 = 1; - //Set the capabilites to the message - ue_config[i]->capabilities = capabilities; - //TODO: Set UE transmission antenna. One of the PRUTA_* values - ue_config[i]->has_ue_transmission_antenna = 1; - ue_config[i]->ue_transmission_antenna = PROTOCOL__PRP_UE_TRANSMISSION_ANTENNA__PRUTA_OPEN_LOOP; - //TODO: Set tti bundling flag (See ts 36.321) - ue_config[i]->has_tti_bundling = 1; - ue_config[i]->tti_bundling = 1; - //TODO: Set the max HARQ retransmission for the UL - ue_config[i]->has_max_harq_tx = 1; - ue_config[i]->max_harq_tx = 1; - //TODO: Fill beta_offset_ack_index (TS 36.213) - ue_config[i]->has_beta_offset_ack_index = 1; - ue_config[i]->beta_offset_ack_index = 1; - //TODO: Fill beta_offset_ri_index (TS 36.213) - ue_config[i]->has_beta_offset_ri_index = 1; - ue_config[i]->beta_offset_ri_index = 1; - //TODO: Fill beta_offset_cqi_index (TS 36.213) - ue_config[i]->has_beta_offset_cqi_index = 1; - ue_config[i]->beta_offset_cqi_index = 1; - //TODO: Fill ack_nack_simultaneous_trans (TS 36.213) - ue_config[i]->has_ack_nack_simultaneous_trans = 1; - ue_config[i]->ack_nack_simultaneous_trans = 1; - //TODO: Fill simultaneous_ack_nack_cqi (TS 36.213) - ue_config[i]->has_simultaneous_ack_nack_cqi = 1; - ue_config[i]->simultaneous_ack_nack_cqi = 1; - //TODO: Set PRACRM_* value regarding aperiodic cqi report mode - ue_config[i]->has_aperiodic_cqi_rep_mode = 1; - ue_config[i]->aperiodic_cqi_rep_mode = PROTOCOL__PRP_APERIODIC_CQI_REPORT_MODE__PRACRM_RM12; - //TODO: Set tdd_ack_nack_feedback - ue_config[i]->has_tdd_ack_nack_feedback = 1; - ue_config[i]->tdd_ack_nack_feedback = 1; - //TODO: Set ack_nack_repetition factor - ue_config[i]->has_ack_nack_repetition_factor = 1; - ue_config[i]->ack_nack_repetition_factor = 1; - //TODO: Set extended BSR size - ue_config[i]->has_extended_bsr_size = 1; - ue_config[i]->extended_bsr_size = 1; - //TODO: Set carrier aggregation support (boolean) - ue_config[i]->has_ca_support = 1; - ue_config[i]->ca_support = 0; - //TODO: Set cross carrier scheduling support (boolean) - ue_config[i]->has_cross_carrier_sched_support = 1; - ue_config[i]->cross_carrier_sched_support = 0; - //TODO: Set index of primary cell - ue_config[i]->has_pcell_carrier_index = 1; - ue_config[i]->pcell_carrier_index = 1; - //TODO: Set secondary cells configuration - // We do not set it for now. No carrier aggregation support - - //TODO: Set deactivation timer for secondary cell - ue_config[i]->has_scell_deactivation_timer = 1; - ue_config[i]->scell_deactivation_timer = 1; - } - ue_config_reply_msg->ue_config = ue_config; - } - *msg = malloc(sizeof(Protocol__ProgranMessage)); - if (*msg == NULL) - goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; - (*msg)->ue_config_reply_msg = ue_config_reply_msg; - return 0; - - error: - // TODO: Need to make proper error handling - if (header != NULL) - free(header); - if (ue_config_reply_msg != NULL) - free(ue_config_reply_msg); - if(*msg != NULL) - free(*msg); - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - return -1; -} - int enb_agent_destroy_ue_config_reply(Protocol__ProgranMessage *msg) { if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG) goto error; @@ -481,110 +318,6 @@ int enb_agent_destroy_ue_config_reply(Protocol__ProgranMessage *msg) { return -1; } -int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { - - xid_t xid; - Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; - Protocol__PrpLcConfigRequest *lc_config_request_msg = input->lc_config_request_msg; - xid = (lc_config_request_msg->header)->xid; - - int i, j; - Protocol__PrpHeader *header; - if(prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_GET_LC_CONFIG_REPLY, &header) != 0) - goto error; - - Protocol__PrpLcConfigReply *lc_config_reply_msg; - lc_config_reply_msg = malloc(sizeof(Protocol__PrpLcConfigReply)); - if(lc_config_reply_msg == NULL) - goto error; - protocol__prp_lc_config_reply__init(lc_config_reply_msg); - lc_config_reply_msg->header = header; - - //TODO: Fill in the actual number of UEs that we are going to report LC configs about - lc_config_reply_msg->n_lc_ue_config = 1; - - Protocol__PrpLcUeConfig **lc_ue_config; - if (lc_config_reply_msg->n_lc_ue_config > 0) { - lc_ue_config = malloc(sizeof(Protocol__PrpLcUeConfig *) * lc_config_reply_msg->n_lc_ue_config); - if (lc_ue_config == NULL) { - goto error; - } - // Fill the config for each UE - for (i = 0; i < lc_config_reply_msg->n_lc_ue_config; i++) { - lc_ue_config[i] = malloc(sizeof(Protocol__PrpLcUeConfig)); - protocol__prp_lc_ue_config__init(lc_ue_config[i]); - //TODO: Set the RNTI of the UE - lc_ue_config[i]->has_rnti = 1; - lc_ue_config[i]->rnti = 1; - //TODO: Set the number of LC configurations that will be reported for this UE - lc_ue_config[i]->n_lc_config = 3; - Protocol__PrpLcConfig **lc_config; - if (lc_ue_config[i]->n_lc_config > 0) { - lc_config = malloc(sizeof(Protocol__PrpLcConfig *) * lc_ue_config[i]->n_lc_config); - if (lc_config == NULL) { - goto error; - } - for (j = 0; j < lc_ue_config[i]->n_lc_config; j++) { - lc_config[j] = malloc(sizeof(Protocol__PrpLcConfig)); - protocol__prp_lc_config__init(lc_config[j]); - //TODO: Set the LC id - lc_config[j]->has_lcid = 1; - lc_config[j]->lcid = 1; - //TODO: Set the LCG of the channel - lc_config[j]->has_lcg = 1; - lc_config[j]->lcg = 1; - //TODO: Set the LC direction - lc_config[j]->has_direction = 1; - lc_config[j]->direction = PROTOCOL__PRP_LC_DIRECTION__PRLCD_BOTH; - //TODO: Bearer type. One of PRQBT_* values - lc_config[j]->has_qos_bearer_type = 1; - lc_config[j]->qos_bearer_type = PROTOCOL__PRP_QOS_BEARER_TYPE__PRQBT_NON_GBR; - //TODO: Set the QCI defined in TS 23.203, coded as defined in TS 36.413 - // One less than the actual QCI value - lc_config[j]->has_qci = 1; - lc_config[j]->qci = 1; - if (lc_config[j]->direction == PROTOCOL__PRP_QOS_BEARER_TYPE__PRQBT_GBR) { - //TODO: Set the max bitrate (UL) - lc_config[j]->has_e_rab_max_bitrate_ul = 1; - lc_config[j]->e_rab_max_bitrate_ul = 1; - //TODO: Set the max bitrate (DL) - lc_config[j]->has_e_rab_max_bitrate_dl = 1; - lc_config[j]->e_rab_max_bitrate_dl = 1; - //TODO: Set the guaranteed bitrate (UL) - lc_config[j]->has_e_rab_guaranteed_bitrate_ul = 1; - lc_config[j]->e_rab_guaranteed_bitrate_ul = 1; - //TODO: Set the guaranteed bitrate (DL) - lc_config[j]->has_e_rab_guaranteed_bitrate_dl = 1; - lc_config[j]->e_rab_guaranteed_bitrate_dl = 1; - } - } - lc_ue_config[i]->lc_config = lc_config; - } - } // end for UE - lc_config_reply_msg->lc_ue_config = lc_ue_config; - } // lc_config_reply_msg->n_lc_ue_config > 0 - *msg = malloc(sizeof(Protocol__ProgranMessage)); - if (*msg == NULL) - goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; - (*msg)->lc_config_reply_msg = lc_config_reply_msg; - - return 0; - - error: - // TODO: Need to make proper error handling - if (header != NULL) - free(header); - if (lc_config_reply_msg != NULL) - free(lc_config_reply_msg); - if(*msg != NULL) - free(*msg); - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - return -1; -} - int enb_agent_destroy_lc_config_reply(Protocol__ProgranMessage *msg) { if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG) goto error; @@ -788,6 +521,7 @@ void set_enb_vars(mid_t mod_id, ran_name_t ran){ 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]; + enb_ue_rrc[mod_id] = (void *)&UE_rrc_inst[mod_id]; break; default : goto error; @@ -1157,10 +891,449 @@ int get_num_pdcch_symb(mid_t mod_id, int CC_id) return (PHY_vars_UE_g[mod_id][CC_id]->lte_ue_pdcch_vars[mod_id]->num_pdcch_symbols); } +/* + * ************************************ + * Get Messages for UE Configuration Reply + * ************************************ + */ + +int get_time_alignment_timer(mid_t mod_id, mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->mac_MainConfig[mod_id]->timeAlignmentTimerDedicated); +} + +int get_meas_gap_config(mid_t mod_id, mid_t ue_id) +{ + if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->measGapConfig[mod_id]->present == MeasGapConfig_PR_NOTHING) + return 2; + else if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->measGapConfig[mod_id]->present == MeasGapConfig_PR_release) + return 0; + else if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->measGapConfig[mod_id]->present == MeasGapConfig_PR_setup) + return 1; + + return -1; +} + +int get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->measGapConfig[mod_id]->choice.setup.gapOffset.present); +} + +int 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 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 get_half_duplex(mid_t ue_id) +{ + 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; +} + +int get_intra_sf_hopping(mid_t ue_id) +{ + uint8_t temp = 0; + temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); + return (temp & ( 1 << (31))); +} + +int get_type2_sb_1(mid_t ue_id) +{ + uint8_t temp = 0; + temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); + return (temp & ( 1 << (11))); +} + +int get_ue_category(mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->ue_Category); +} + +int get_res_alloc_type1(mid_t ue_id) +{ + uint8_t temp = 0; + temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); + return (temp & ( 1 << (30))); +} + +int get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->antennaInfo->choice.explicitValue.transmissionMode); +} + +int get_tti_bundling(mid_t mod_id, mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->mac_MainConfig[mod_id]->ul_SCH_Config->ttiBundling); +} + +int get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->mac_MainConfig[mod_id]->ul_SCH_Config->maxHARQ_Tx); +} + +int get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->pusch_ConfigDedicated->betaOffset_ACK_Index); +} + +int get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->pusch_ConfigDedicated->betaOffset_RI_Index); +} + +int get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->pusch_ConfigDedicated->betaOffset_CQI_Index); +} + +int get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.simultaneousAckNackAndCQI); +} + +int get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->sib2[mod_id]->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission); +} + +int get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->cqi_ReportConfig->cqi_ReportModeAperiodic); +} + +int get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->pucch_ConfigDedicated->tdd_AckNackFeedbackMode); +} + +int get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) +{ + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->pucch_ConfigDedicated->ackNackRepetition.choice.setup.repetitionFactor); +} + +int get_extended_bsr_size(mid_t mod_id, mid_t ue_id) +{ + //TODO: need to double check + return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->mac_MainConfig[mod_id]->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10); +} + +int get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) +{ + if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_closedLoop) + return 2; + else if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_openLoop) + return 1; + else + return 0; +} + +int get_lcg(mid_t ue_id, mid_t lc_id) +{ + return &UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters->logicalChannelGroup; +} + +int get_direction(mid_t ue_id, mid_t lc_id) +{ + /*TODO: fill with the value for the rest of LCID*/ + + if(lc_id == CCCH | lc_id == DCCH) + return 2; + else if(lc_id == DTCH) + return 1; +} + + /* * timer primitives */ +int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { + + xid_t xid; + Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; + Protocol__PrpLcConfigRequest *lc_config_request_msg = input->lc_config_request_msg; + xid = (lc_config_request_msg->header)->xid; + + int i, j; + Protocol__PrpHeader *header; + if(prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_GET_LC_CONFIG_REPLY, &header) != 0) + goto error; + + Protocol__PrpLcConfigReply *lc_config_reply_msg; + lc_config_reply_msg = malloc(sizeof(Protocol__PrpLcConfigReply)); + if(lc_config_reply_msg == NULL) + goto error; + protocol__prp_lc_config_reply__init(lc_config_reply_msg); + lc_config_reply_msg->header = header; + + //TODO: Fill in the actual number of UEs that we are going to report LC configs about + lc_config_reply_msg->n_lc_ue_config = get_num_ues(mod_id); + + Protocol__PrpLcUeConfig **lc_ue_config; + if (lc_config_reply_msg->n_lc_ue_config > 0) { + lc_ue_config = malloc(sizeof(Protocol__PrpLcUeConfig *) * lc_config_reply_msg->n_lc_ue_config); + if (lc_ue_config == NULL) { + goto error; + } + // Fill the config for each UE + for (i = 0; i < lc_config_reply_msg->n_lc_ue_config; i++) { + lc_ue_config[i] = malloc(sizeof(Protocol__PrpLcUeConfig)); + protocol__prp_lc_ue_config__init(lc_ue_config[i]); + //TODO: Set the RNTI of the UE + lc_ue_config[i]->has_rnti = 1; + lc_ue_config[i]->rnti = get_ue_crnti(mod_id,i); + //TODO: Set the number of LC configurations that will be reported for this UE + lc_ue_config[i]->n_lc_config = 3; + Protocol__PrpLcConfig **lc_config; + if (lc_ue_config[i]->n_lc_config > 0) { + lc_config = malloc(sizeof(Protocol__PrpLcConfig *) * lc_ue_config[i]->n_lc_config); + if (lc_config == NULL) { + goto error; + } + for (j = 0; j < lc_ue_config[i]->n_lc_config; j++) { + lc_config[j] = malloc(sizeof(Protocol__PrpLcConfig)); + protocol__prp_lc_config__init(lc_config[j]); + //TODO: Set the LC id + lc_config[j]->has_lcid = 1; + lc_config[j]->lcid = j+1; + //TODO: Set the LCG of the channel + lc_config[j]->has_lcg = 1; + lc_config[j]->lcg = get_lcg(i,j+1); + //TODO: Set the LC direction + lc_config[j]->has_direction = 1; + lc_config[j]->direction = get_direction(i,j+1); + //TODO: Bearer type. One of PRQBT_* values + lc_config[j]->has_qos_bearer_type = 1; + lc_config[j]->qos_bearer_type = PROTOCOL__PRP_QOS_BEARER_TYPE__PRQBT_NON_GBR; + //TODO: Set the QCI defined in TS 23.203, coded as defined in TS 36.413 + // One less than the actual QCI value + lc_config[j]->has_qci = 1; + lc_config[j]->qci = 1; + if (lc_config[j]->direction == PROTOCOL__PRP_QOS_BEARER_TYPE__PRQBT_GBR) { + //TODO: Set the max bitrate (UL) + lc_config[j]->has_e_rab_max_bitrate_ul = 1; + lc_config[j]->e_rab_max_bitrate_ul = 1; + //TODO: Set the max bitrate (DL) + lc_config[j]->has_e_rab_max_bitrate_dl = 1; + lc_config[j]->e_rab_max_bitrate_dl = 1; + //TODO: Set the guaranteed bitrate (UL) + lc_config[j]->has_e_rab_guaranteed_bitrate_ul = 1; + lc_config[j]->e_rab_guaranteed_bitrate_ul = 1; + //TODO: Set the guaranteed bitrate (DL) + lc_config[j]->has_e_rab_guaranteed_bitrate_dl = 1; + lc_config[j]->e_rab_guaranteed_bitrate_dl = 1; + } + } + lc_ue_config[i]->lc_config = lc_config; + } + } // end for UE + lc_config_reply_msg->lc_ue_config = lc_ue_config; + } // lc_config_reply_msg->n_lc_ue_config > 0 + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if (*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + (*msg)->lc_config_reply_msg = lc_config_reply_msg; + + return 0; + + error: + // TODO: Need to make proper error handling + if (header != NULL) + free(header); + if (lc_config_reply_msg != NULL) + free(lc_config_reply_msg); + if(*msg != NULL) + free(*msg); + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +/* + * ************************************ + * UE Configuration Reply + * ************************************ + */ + +int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { + + xid_t xid; + Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; + Protocol__PrpUeConfigRequest *ue_config_request_msg = input->ue_config_request_msg; + xid = (ue_config_request_msg->header)->xid; + + int i; + + Protocol__PrpHeader *header; + if(prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_GET_UE_CONFIG_REPLY, &header) != 0) + goto error; + + Protocol__PrpUeConfigReply *ue_config_reply_msg; + ue_config_reply_msg = malloc(sizeof(Protocol__PrpUeConfigReply)); + if(ue_config_reply_msg == NULL) + goto error; + protocol__prp_ue_config_reply__init(ue_config_reply_msg); + ue_config_reply_msg->header = header; + + //TODO: Fill in the actual number of UEs that are currently connected + ue_config_reply_msg->n_ue_config = get_num_ues(mod_id); + + Protocol__PrpUeConfig **ue_config; + if (ue_config_reply_msg->n_ue_config > 0) { + ue_config = malloc(sizeof(Protocol__PrpUeConfig *) * ue_config_reply_msg->n_ue_config); + if (ue_config == NULL) { + goto error; + } + for (i = 0; i < ue_config_reply_msg->n_ue_config; i++) { + ue_config[i] = malloc(sizeof(Protocol__PrpUeConfig *)); + protocol__prp_ue_config__init(ue_config[i]); + //TODO: Set the RNTI of the ue with id i + ue_config[i]->rnti = get_ue_crnti(mod_id,i); + ue_config[i]->has_rnti = 1; + //TODO: Set the DRX configuration (optional) + //Not supported for now, so we do not set it + + //TODO: Set the time_alignment_timer + ue_config[i]->time_alignment_timer = get_time_alignment_timer(mod_id,i); + ue_config[i]->has_time_alignment_timer = 1; + //TODO: Set the measurement gap configuration pattern + ue_config[i]->meas_gap_config_pattern = get_meas_gap_config(mod_id,i); + ue_config[i]->has_meas_gap_config_pattern = 1; + //TODO: Set the measurement gap offset if applicable + ue_config[i]->meas_gap_config_sf_offset = get_meas_gap_config_offset(mod_id,i); + ue_config[i]->has_meas_gap_config_sf_offset = 1; + //TODO: Set the SPS configuration (Optional) + //Not supported for noe, 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 + + //TODO: Set the transmission mode + ue_config[i]->transmission_mode = get_ue_transmission_mode(mod_id,i); + ue_config[i]->has_transmission_mode = 1; + + //TODO: Set the aggregated bit-rate of the non-gbr bearer (UL) + ue_config[i]->ue_aggregated_max_bitrate_ul = get_ue_aggregated_max_bitrate_ul(mod_id,i); + ue_config[i]->has_ue_aggregated_max_bitrate_ul = 1; + + //TODO: Set the aggregated bit-rate of the non-gbr bearer (DL) + ue_config[i]->ue_aggregated_max_bitrate_dl = get_ue_aggregated_max_bitrate_dl(mod_id,i); + ue_config[i]->has_ue_aggregated_max_bitrate_dl = 1; + + //TODO: Set the UE capabilities + Protocol__PrpUeCapabilities *capabilities; + capabilities = malloc(sizeof(Protocol__PrpUeCapabilities)); + protocol__prp_ue_capabilities__init(capabilities); + //TODO: Set half duplex (FDD operation) + capabilities->has_half_duplex = 1; + capabilities->half_duplex = get_half_duplex(i); + //TODO: Set intra-frame hopping flag + capabilities->has_intra_sf_hopping = 1; + capabilities->intra_sf_hopping = get_intra_sf_hopping(i); + //TODO: Set support for type 2 hopping with n_sb > 1 + capabilities->has_type2_sb_1 = 1; + capabilities->type2_sb_1 = get_type2_sb_1(i); + //TODO: Set ue category + capabilities->has_ue_category = 1; + capabilities->ue_category = get_ue_category(i); + //TODO: Set UE support for resource allocation type 1 + capabilities->has_res_alloc_type1 = 1; + capabilities->res_alloc_type1 = get_res_alloc_type1(i); + //Set the capabilites to the message + ue_config[i]->capabilities = capabilities; + //TODO: Set UE transmission antenna. One of the PRUTA_* values + ue_config[i]->has_ue_transmission_antenna = 1; + ue_config[i]->ue_transmission_antenna = get_ue_transmission_antenna(mod_id,i); + //TODO: Set tti bundling flag (See ts 36.321) + ue_config[i]->has_tti_bundling = 1; + ue_config[i]->tti_bundling = get_tti_bundling(mod_id,i); + //TODO: Set the max HARQ retransmission for the UL + ue_config[i]->has_max_harq_tx = 1; + ue_config[i]->max_harq_tx = get_maxHARQ_TX(mod_id,i); + //TODO: Fill beta_offset_ack_index (TS 36.213) + ue_config[i]->has_beta_offset_ack_index = 1; + ue_config[i]->beta_offset_ack_index = get_beta_offset_ack_index(mod_id,i); + //TODO: Fill beta_offset_ri_index (TS 36.213) + ue_config[i]->has_beta_offset_ri_index = 1; + ue_config[i]->beta_offset_ri_index = get_beta_offset_ri_index(mod_id,i); + //TODO: Fill beta_offset_cqi_index (TS 36.213) + ue_config[i]->has_beta_offset_cqi_index = 1; + ue_config[i]->beta_offset_cqi_index = get_beta_offset_cqi_index(mod_id,i); + //TODO: Fill ack_nack_simultaneous_trans (TS 36.213) + ue_config[i]->has_ack_nack_simultaneous_trans = 1; + ue_config[i]->ack_nack_simultaneous_trans = get_ack_nack_simultaneous_trans(mod_id,i); + //TODO: Fill simultaneous_ack_nack_cqi (TS 36.213) + ue_config[i]->has_simultaneous_ack_nack_cqi = 1; + ue_config[i]->simultaneous_ack_nack_cqi = get_simultaneous_ack_nack_cqi(mod_id,i); + //TODO: Set PRACRM_* value regarding aperiodic cqi report mode + ue_config[i]->has_aperiodic_cqi_rep_mode = 1; + ue_config[i]->aperiodic_cqi_rep_mode = get_aperiodic_cqi_rep_mode(mod_id,i); + //TODO: Set tdd_ack_nack_feedback + ue_config[i]->has_tdd_ack_nack_feedback = 1; + ue_config[i]->tdd_ack_nack_feedback = get_tdd_ack_nack_feedback(mod_id,i); + //TODO: Set ack_nack_repetition factor + ue_config[i]->has_ack_nack_repetition_factor = 1; + ue_config[i]->ack_nack_repetition_factor = get_ack_nack_repetition_factor(mod_id,i); + //TODO: Set extended BSR size + ue_config[i]->has_extended_bsr_size = 1; + ue_config[i]->extended_bsr_size = get_extended_bsr_size(mod_id,i); + //TODO: Set carrier aggregation support (boolean) + ue_config[i]->has_ca_support = 0; + ue_config[i]->ca_support = 0; + if(ue_config[i]->has_ca_support){ + //TODO: Set cross carrier scheduling support (boolean) + ue_config[i]->has_cross_carrier_sched_support = 1; + ue_config[i]->cross_carrier_sched_support = 0; + //TODO: Set index of primary cell + ue_config[i]->has_pcell_carrier_index = 1; + ue_config[i]->pcell_carrier_index = 1; + //TODO: Set secondary cells configuration + // We do not set it for now. No carrier aggregation support + + //TODO: Set deactivation timer for secondary cell + ue_config[i]->has_scell_deactivation_timer = 1; + ue_config[i]->scell_deactivation_timer = 1; + } + } + ue_config_reply_msg->ue_config = ue_config; + } + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if (*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + (*msg)->ue_config_reply_msg = ue_config_reply_msg; + return 0; + + error: + // TODO: Need to make proper error handling + if (header != NULL) + free(header); + if (ue_config_reply_msg != NULL) + free(ue_config_reply_msg); + if(*msg != NULL) + free(*msg); + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + + /* * ************************************ * eNB Configuration Request and Reply diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 73ce0ec788..76c68437d0 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -210,6 +210,62 @@ int get_tpc(mid_t mod_id, mid_t ue_id); int get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, const int frame, const uint8_t subframe, int *id, int *status); +/* + * ************************************ + * Get Messages for UE Configuration Reply + * ************************************ + */ + +int get_time_alignment_timer(mid_t mod_id, mid_t ue_id); + +int get_meas_gap_config(mid_t mod_id, mid_t ue_id); + +int get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id); + +int get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id); + +int get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id); + +int get_half_duplex(mid_t ue_id); + +int get_intra_sf_hopping(mid_t ue_id); + +int get_type2_sb_1(mid_t ue_id); + +int get_ue_category(mid_t ue_id); + +int get_res_alloc_type1(mid_t ue_id); + +int get_ue_transmission_mode(mid_t mod_id, mid_t ue_id); + +int get_tti_bundling(mid_t mod_id, mid_t ue_id); + +int get_maxHARQ_TX(mid_t mod_id, mid_t ue_id); + +int get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id); + +int get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id); + +int get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id); + +int get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id); + +int get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id); + +int get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id); + +int get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id); + +int get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id); + +int get_extended_bsr_size(mid_t mod_id, mid_t ue_id); + +int get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id); + +int get_lcg(mid_t ue_id, mid_t lc_id); + +int get_direction(mid_t ue_id, mid_t lc_id); + /******************* * timer primitves *******************/ diff --git a/openair2/LAYER2/MAC/extern.h b/openair2/LAYER2/MAC/extern.h index 2810235255..c2a3c78741 100644 --- a/openair2/LAYER2/MAC/extern.h +++ b/openair2/LAYER2/MAC/extern.h @@ -58,6 +58,8 @@ extern const uint32_t BSR_TABLE[BSR_TABLE_SIZE]; extern UE_MAC_INST *UE_mac_inst; extern eNB_MAC_INST *eNB_mac_inst; extern eNB_RRC_INST *eNB_rrc_inst; +extern UE_RRC_INST *UE_rrc_inst; +extern UE_MAC_INST *ue_mac_inst; extern MAC_RLC_XFACE *Mac_rlc_xface; extern uint8_t Is_rrc_registered; From e1d1b0baff645e2adc4c1595511127af3517ab53 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 23 Feb 2016 17:53:43 +0000 Subject: [PATCH 116/413] Added event notification for connection of a new UE --- openair2/ENB_APP/enb_agent.c | 2 +- openair2/ENB_APP/enb_agent_common.c | 428 +++++++++++----------- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 8 + 3 files changed, 223 insertions(+), 215 deletions(-) diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index 7d2029b37f..95731d3654 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -150,7 +150,7 @@ void *receive_thread(void *args) { // check if there is something to send back to the controller if (msg != NULL){ data=enb_agent_pack_message(msg,&size); - + if (enb_agent_msg_send(d->enb_id, ENB_AGENT_DEFAULT, data, size, priority)) { err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; goto error; diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 4a175c244e..a31020881e 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -1380,220 +1380,220 @@ int enb_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__Pro int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { - xid_t xid; - Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; - Protocol__PrpEnbConfigRequest *enb_config_req_msg = input->enb_config_request_msg; - xid = (enb_config_req_msg->header)->xid; - - int i, j, k; - int cc_id = 0; - int enb_id = mod_id; - - - Protocol__PrpHeader *header; - if(prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_GET_ENB_CONFIG_REPLY, &header) != 0) - goto error; - - Protocol__PrpEnbConfigReply *enb_config_reply_msg; - enb_config_reply_msg = malloc(sizeof(Protocol__PrpEnbConfigReply)); - if(enb_config_reply_msg == NULL) - goto error; - protocol__prp_enb_config_reply__init(enb_config_reply_msg); - enb_config_reply_msg->header = header; - - enb_config_reply_msg->enb_id = mod_id; - - - enb_config_reply_msg->n_cell_config = MAX_NUM_CCs; - - Protocol__PrpCellConfig **cell_conf; - if(enb_config_reply_msg->n_cell_config > 0){ - cell_conf = malloc(sizeof(Protocol__PrpCellConfig *) * enb_config_reply_msg->n_cell_config); - if(cell_conf == NULL) - goto error; - for(i = 0; i < enb_config_reply_msg->n_cell_config; i++){ - cell_conf[i] = malloc(sizeof(Protocol__PrpCellConfig)); - protocol__prp_cell_config__init(cell_conf[i]); - //TODO: Fill in with actual value, the PCI of this cell - cell_conf[i]->phy_cell_id = 1; - cell_conf[i]->has_phy_cell_id = 1; - //TODO: Fill in with actual value, the PLMN cell id of this cell - cell_conf[i]->cell_id = get_cell_id(enb_id,i); - cell_conf[i]->has_cell_id = 1; - //TODO: Fill in with actual value, PUSCH resources in RBs for hopping - cell_conf[i]->pusch_hopping_offset = get_hopping_offset(enb_id,i); - cell_conf[i]->has_pusch_hopping_offset = 1; - //TODO: Fill in with actual value - cell_conf[i]->hopping_mode = get_hopping_mode(enb_id,i); - cell_conf[i]->has_hopping_mode = 1; - //TODO: Fill in with actual value, the number of subbands - cell_conf[i]->n_sb = get_n_SB(enb_id,i); - cell_conf[i]->has_n_sb = 1; - //TODO: Fill in with actual value, The number of resource element groups used for PHICH. One of PRPR_ - cell_conf[i]->phich_resource = get_phich_resource(enb_id,i); - cell_conf[i]->has_phich_resource = 1; - //TODO: Fill in with actual value, one of the PRPD_ values - cell_conf[i]->phich_duration = get_phich_duration(enb_id,i); - cell_conf[i]->has_phich_duration = 1; - //TODO: Fill in with actual value, See TS 36.211, section 6.9 - cell_conf[i]->init_nr_pdcch_ofdm_sym = get_num_pdcch_symb(enb_id,i); - cell_conf[i]->has_init_nr_pdcch_ofdm_sym = 1; - //TODO: Fill in with actual value - Protocol__PrpSiConfig *si_config; - si_config = malloc(sizeof(Protocol__PrpSiConfig)); - if(si_config == NULL) - goto error; - protocol__prp_si_config__init(si_config); - //TODO: Fill in with actual value, Frame number to apply the SI configuration - si_config->sfn = 1; - si_config->has_sfn = 1; - //TODO: Fill in with actual value, the length of SIB1 in bytes - si_config->sib1_length = get_sib1_length(enb_id,i); - si_config->has_sib1_length = 1; - //TODO: Fill in with actual value, Scheduling window for all SIs in SF - si_config->si_window_length = (uint32_t) get_si_window_length(enb_id,i); - si_config->has_si_window_length = 1; - //TODO: Fill in with actual value, the number of SI messages - si_config->n_si_message=1; - Protocol__PrpSiMessage **si_message; - si_message = malloc(sizeof(Protocol__PrpSiMessage *) * si_config->n_si_message); - if(si_message == NULL) - goto error; - for(j = 0; j < si_config->n_si_message; j++){ - si_message[j] = malloc(sizeof(Protocol__PrpSiMessage)); - if(si_message[j] == NULL) - goto error; - protocol__prp_si_message__init(si_message[j]); - //TODO: Fill in with actual value, Periodicity of SI msg in radio frames - si_message[j]->periodicity = 1; //SIPeriod - si_message[j]->has_periodicity = 1; - //TODO: Fill in with actual value, rhe length of the SI message in bytes - si_message[j]->length = 10; - si_message[j]->has_length = 1; - } - if(si_config->n_si_message > 0){ - si_config->si_message = si_message; - } - cell_conf[i]->si_config = si_config; - - //TODO: Fill in with actual value, the DL transmission bandwidth in RBs - cell_conf[i]->dl_bandwidth = get_N_RB_DL(enb_id,i); - cell_conf[i]->has_dl_bandwidth = 1; - //TODO: Fill in with actual value, the UL transmission bandwidth in RBs - cell_conf[i]->ul_bandwidth = get_N_RB_UL(enb_id,i); - cell_conf[i]->has_ul_bandwidth = 1; - //TODO: Fill in with actual value, one of PRUCPL values - cell_conf[i]->ul_cyclic_prefix_length = get_ul_cyclic_prefix_length(enb_id,i); - cell_conf[i]->has_ul_cyclic_prefix_length = 1; - //TODO: Fill in with actual value, one of PRUCPL values - cell_conf[i]->dl_cyclic_prefix_length = get_dl_cyclic_prefix_length(enb_id,i); - cell_conf[i]->has_dl_cyclic_prefix_length = 1; - //TODO: Fill in with actual value, number of cell specific antenna ports - cell_conf[i]->antenna_ports_count = 1; - cell_conf[i]->has_antenna_ports_count = 1; - //TODO: Fill in with actual value, one of PRDM values - cell_conf[i]->duplex_mode = get_duplex_mode(enb_id,i); - cell_conf[i]->has_duplex_mode = 1; - //TODO: Fill in with actual value, DL/UL subframe assignment. TDD only - cell_conf[i]->subframe_assignment = get_subframe_assignment(enb_id,i); - cell_conf[i]->has_subframe_assignment = 1; - //TODO: Fill in with actual value, TDD only. See TS 36.211, table 4.2.1 - cell_conf[i]->special_subframe_patterns = get_special_subframe_assignment(enb_id,i); - cell_conf[i]->has_special_subframe_patterns = 1; - //TODO: Fill in with actual value, The MBSFN radio frame period - cell_conf[i]->n_mbsfn_subframe_config_rfperiod = 5; - uint32_t *elem_rfperiod; - elem_rfperiod = (uint32_t *) malloc(sizeof(uint32_t) *cell_conf[i]->n_mbsfn_subframe_config_rfperiod); - if(elem_rfperiod == NULL) - goto error; - for(j = 0; j < cell_conf[i]->n_mbsfn_subframe_config_rfperiod; j++){ - elem_rfperiod[j] = 1; - } - cell_conf[i]->mbsfn_subframe_config_rfperiod = elem_rfperiod; - - //TODO: Fill in with actual value, The MBSFN radio frame offset - cell_conf[i]->n_mbsfn_subframe_config_rfoffset = 5; - uint32_t *elem_rfoffset; - elem_rfoffset = (uint32_t *) malloc(sizeof(uint32_t) *cell_conf[i]->n_mbsfn_subframe_config_rfoffset); - if(elem_rfoffset == NULL) - goto error; - for(j = 0; j < cell_conf[i]->n_mbsfn_subframe_config_rfoffset; j++){ - elem_rfoffset[j] = 1; - } - cell_conf[i]->mbsfn_subframe_config_rfoffset = elem_rfoffset; - - //TODO: Fill in with actual value, Bitmap indicating the MBSFN subframes - cell_conf[i]->n_mbsfn_subframe_config_sfalloc = 5; - uint32_t *elem_sfalloc; - elem_sfalloc = (uint32_t *) malloc(sizeof(uint32_t) *cell_conf[i]->n_mbsfn_subframe_config_sfalloc); - if(elem_sfalloc == NULL) - goto error; - for(j = 0; j < cell_conf[i]->n_mbsfn_subframe_config_sfalloc; j++){ - elem_sfalloc[j] = 1; - } - cell_conf[i]->mbsfn_subframe_config_sfalloc = elem_sfalloc; - - //TODO: Fill in with actual value, See TS 36.211, section 5.7.1 - cell_conf[i]->prach_config_index = get_prach_ConfigIndex(enb_id,i); - cell_conf[i]->has_prach_config_index = 1; - //TODO: Fill in with actual value, See TS 36.211, section 5.7.1 - cell_conf[i]->prach_freq_offset = get_prach_FreqOffset(enb_id,i); - cell_conf[i]->has_prach_freq_offset = 1; - //TODO: Fill in with actual value, Duration of RA response window in SF - cell_conf[i]->ra_response_window_size = get_ra_ResponseWindowSize(enb_id,i); - cell_conf[i]->has_ra_response_window_size = 1; - //TODO: Fill in with actual value, Timer used for RA - cell_conf[i]->mac_contention_resolution_timer = get_mac_ContentionResolutionTimer(enb_id,i); - cell_conf[i]->has_mac_contention_resolution_timer = 1; - //TODO: Fill in with actual value, See TS 36.321 - cell_conf[i]->max_harq_msg3tx = get_maxHARQ_Msg3Tx(enb_id,i); - cell_conf[i]->has_max_harq_msg3tx = 1; - //TODO: Fill in with actual value, See TS 36.213, section 10.1 - cell_conf[i]->n1pucch_an = get_n1pucch_an(enb_id,i); - cell_conf[i]->has_n1pucch_an = 1; - //TODO: Fill in with actual value, See TS 36.211, section 5.4 - cell_conf[i]->deltapucch_shift = get_deltaPUCCH_Shift(enb_id,i); - cell_conf[i]->has_deltapucch_shift = 1; - //TODO: Fill in with actual value, See TS 36.211, section 5.4 - cell_conf[i]->nrb_cqi = get_nRB_CQI(enb_id,i); - cell_conf[i]->has_nrb_cqi = 1; - //TODO: Fill in with actual value, See TS 36.211, table 5.5.3.3-1 and 2 - cell_conf[i]->srs_subframe_config = get_srs_SubframeConfig(enb_id,i); - cell_conf[i]->has_srs_subframe_config = 1; - //TODO: Fill in with actual value, See TS 36.211, section 5.5.3.2 - cell_conf[i]->srs_bw_config = get_srs_BandwidthConfig(enb_id,i); - cell_conf[i]->has_srs_bw_config = 1; - //TODO: Fill in with actual value, Boolean value. See TS 36.211, section 5.5.3.2. TDD only - cell_conf[i]->srs_mac_up_pts = get_srs_MaxUpPts(enb_id,i); - cell_conf[i]->has_srs_mac_up_pts = 1; - //TODO: Fill in with actual value, One of the PREQ_ values - cell_conf[i]->enable_64qam = get_enable64QAM(enb_id,i); - cell_conf[i]->has_enable_64qam = 1; - //TODO: Fill in with actual value, Carrier component index - cell_conf[i]->carrier_index = i; - cell_conf[i]->has_carrier_index = 1; - } - enb_config_reply_msg->cell_config=cell_conf; - } - *msg = malloc(sizeof(Protocol__ProgranMessage)); - if(*msg == NULL) - goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; - (*msg)->enb_config_reply_msg = enb_config_reply_msg; - return 0; - - error: - // TODO: Need to make proper error handling - if (header != NULL) - free(header); - if (enb_config_reply_msg != NULL) - free(enb_config_reply_msg); - if(*msg != NULL) - free(*msg); - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - return -1; + xid_t xid; + Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; + Protocol__PrpEnbConfigRequest *enb_config_req_msg = input->enb_config_request_msg; + xid = (enb_config_req_msg->header)->xid; + + int i, j, k; + int cc_id = 0; + int enb_id = mod_id; + + Protocol__PrpHeader *header; + if(prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_GET_ENB_CONFIG_REPLY, &header) != 0) + goto error; + + Protocol__PrpEnbConfigReply *enb_config_reply_msg; + enb_config_reply_msg = malloc(sizeof(Protocol__PrpEnbConfigReply)); + if(enb_config_reply_msg == NULL) + goto error; + protocol__prp_enb_config_reply__init(enb_config_reply_msg); + enb_config_reply_msg->header = header; + + enb_config_reply_msg->enb_id = mod_id; + + + enb_config_reply_msg->n_cell_config = MAX_NUM_CCs; + + Protocol__PrpCellConfig **cell_conf; + if(enb_config_reply_msg->n_cell_config > 0){ + cell_conf = malloc(sizeof(Protocol__PrpCellConfig *) * enb_config_reply_msg->n_cell_config); + if(cell_conf == NULL) + goto error; + for(i = 0; i < enb_config_reply_msg->n_cell_config; i++){ + cell_conf[i] = malloc(sizeof(Protocol__PrpCellConfig)); + protocol__prp_cell_config__init(cell_conf[i]); + //TODO: Fill in with actual value, the PCI of this cell + cell_conf[i]->phy_cell_id = 1; + cell_conf[i]->has_phy_cell_id = 1; + //TODO: Fill in with actual value, the PLMN cell id of this cell + cell_conf[i]->cell_id = get_cell_id(enb_id,i); + cell_conf[i]->has_cell_id = 1; + //TODO: Fill in with actual value, PUSCH resources in RBs for hopping + cell_conf[i]->pusch_hopping_offset = get_hopping_offset(enb_id,i); + cell_conf[i]->has_pusch_hopping_offset = 1; + //TODO: Fill in with actual value + cell_conf[i]->hopping_mode = get_hopping_mode(enb_id,i); + cell_conf[i]->has_hopping_mode = 1; + //TODO: Fill in with actual value, the number of subbands + cell_conf[i]->n_sb = get_n_SB(enb_id,i); + cell_conf[i]->has_n_sb = 1; + //TODO: Fill in with actual value, The number of resource element groups used for PHICH. One of PRPR_ + cell_conf[i]->phich_resource = get_phich_resource(enb_id,i); + cell_conf[i]->has_phich_resource = 1; + //TODO: Fill in with actual value, one of the PRPD_ values + cell_conf[i]->phich_duration = get_phich_duration(enb_id,i); + cell_conf[i]->has_phich_duration = 1; + //TODO: Fill in with actual value, See TS 36.211, section 6.9 + cell_conf[i]->init_nr_pdcch_ofdm_sym = get_num_pdcch_symb(enb_id,i); + cell_conf[i]->has_init_nr_pdcch_ofdm_sym = 1; + //TODO: Fill in with actual value + Protocol__PrpSiConfig *si_config; + si_config = malloc(sizeof(Protocol__PrpSiConfig)); + if(si_config == NULL) + goto error; + protocol__prp_si_config__init(si_config); + //TODO: Fill in with actual value, Frame number to apply the SI configuration + si_config->sfn = 1; + si_config->has_sfn = 1; + //TODO: Fill in with actual value, the length of SIB1 in bytes + si_config->sib1_length = get_sib1_length(enb_id,i); + si_config->has_sib1_length = 1; + //TODO: Fill in with actual value, Scheduling window for all SIs in SF + si_config->si_window_length = (uint32_t) get_si_window_length(enb_id,i); + si_config->has_si_window_length = 1; + //TODO: Fill in with actual value, the number of SI messages + si_config->n_si_message=1; + Protocol__PrpSiMessage **si_message; + si_message = malloc(sizeof(Protocol__PrpSiMessage *) * si_config->n_si_message); + if(si_message == NULL) + goto error; + for(j = 0; j < si_config->n_si_message; j++){ + si_message[j] = malloc(sizeof(Protocol__PrpSiMessage)); + if(si_message[j] == NULL) + goto error; + protocol__prp_si_message__init(si_message[j]); + //TODO: Fill in with actual value, Periodicity of SI msg in radio frames + si_message[j]->periodicity = 1; //SIPeriod + si_message[j]->has_periodicity = 1; + //TODO: Fill in with actual value, rhe length of the SI message in bytes + si_message[j]->length = 10; + si_message[j]->has_length = 1; + } + if(si_config->n_si_message > 0){ + si_config->si_message = si_message; + } + cell_conf[i]->si_config = si_config; + + //TODO: Fill in with actual value, the DL transmission bandwidth in RBs + cell_conf[i]->dl_bandwidth = get_N_RB_DL(enb_id,i); + cell_conf[i]->has_dl_bandwidth = 1; + //TODO: Fill in with actual value, the UL transmission bandwidth in RBs + cell_conf[i]->ul_bandwidth = get_N_RB_UL(enb_id,i); + cell_conf[i]->has_ul_bandwidth = 1; + //TODO: Fill in with actual value, one of PRUCPL values + cell_conf[i]->ul_cyclic_prefix_length = get_ul_cyclic_prefix_length(enb_id,i); + cell_conf[i]->has_ul_cyclic_prefix_length = 1; + //TODO: Fill in with actual value, one of PRUCPL values + cell_conf[i]->dl_cyclic_prefix_length = get_dl_cyclic_prefix_length(enb_id,i); + cell_conf[i]->has_dl_cyclic_prefix_length = 1; + //TODO: Fill in with actual value, number of cell specific antenna ports + cell_conf[i]->antenna_ports_count = 1; + cell_conf[i]->has_antenna_ports_count = 1; + //TODO: Fill in with actual value, one of PRDM values + cell_conf[i]->duplex_mode = get_duplex_mode(enb_id,i); + cell_conf[i]->has_duplex_mode = 1; + //TODO: Fill in with actual value, DL/UL subframe assignment. TDD only + cell_conf[i]->subframe_assignment = get_subframe_assignment(enb_id,i); + cell_conf[i]->has_subframe_assignment = 1; + //TODO: Fill in with actual value, TDD only. See TS 36.211, table 4.2.1 + cell_conf[i]->special_subframe_patterns = get_special_subframe_assignment(enb_id,i); + cell_conf[i]->has_special_subframe_patterns = 1; + //TODO: Fill in with actual value, The MBSFN radio frame period + cell_conf[i]->n_mbsfn_subframe_config_rfperiod = 5; + uint32_t *elem_rfperiod; + elem_rfperiod = (uint32_t *) malloc(sizeof(uint32_t) *cell_conf[i]->n_mbsfn_subframe_config_rfperiod); + if(elem_rfperiod == NULL) + goto error; + for(j = 0; j < cell_conf[i]->n_mbsfn_subframe_config_rfperiod; j++){ + elem_rfperiod[j] = 1; + } + cell_conf[i]->mbsfn_subframe_config_rfperiod = elem_rfperiod; + + //TODO: Fill in with actual value, The MBSFN radio frame offset + cell_conf[i]->n_mbsfn_subframe_config_rfoffset = 5; + uint32_t *elem_rfoffset; + elem_rfoffset = (uint32_t *) malloc(sizeof(uint32_t) *cell_conf[i]->n_mbsfn_subframe_config_rfoffset); + if(elem_rfoffset == NULL) + goto error; + for(j = 0; j < cell_conf[i]->n_mbsfn_subframe_config_rfoffset; j++){ + elem_rfoffset[j] = 1; + } + cell_conf[i]->mbsfn_subframe_config_rfoffset = elem_rfoffset; + + //TODO: Fill in with actual value, Bitmap indicating the MBSFN subframes + cell_conf[i]->n_mbsfn_subframe_config_sfalloc = 5; + uint32_t *elem_sfalloc; + elem_sfalloc = (uint32_t *) malloc(sizeof(uint32_t) *cell_conf[i]->n_mbsfn_subframe_config_sfalloc); + if(elem_sfalloc == NULL) + goto error; + for(j = 0; j < cell_conf[i]->n_mbsfn_subframe_config_sfalloc; j++){ + elem_sfalloc[j] = 1; + } + cell_conf[i]->mbsfn_subframe_config_sfalloc = elem_sfalloc; + + //TODO: Fill in with actual value, See TS 36.211, section 5.7.1 + cell_conf[i]->prach_config_index = get_prach_ConfigIndex(enb_id,i); + cell_conf[i]->has_prach_config_index = 1; + //TODO: Fill in with actual value, See TS 36.211, section 5.7.1 + cell_conf[i]->prach_freq_offset = get_prach_FreqOffset(enb_id,i); + cell_conf[i]->has_prach_freq_offset = 1; + //TODO: Fill in with actual value, Duration of RA response window in SF + cell_conf[i]->ra_response_window_size = get_ra_ResponseWindowSize(enb_id,i); + cell_conf[i]->has_ra_response_window_size = 1; + //TODO: Fill in with actual value, Timer used for RA + cell_conf[i]->mac_contention_resolution_timer = get_mac_ContentionResolutionTimer(enb_id,i); + cell_conf[i]->has_mac_contention_resolution_timer = 1; + //TODO: Fill in with actual value, See TS 36.321 + cell_conf[i]->max_harq_msg3tx = get_maxHARQ_Msg3Tx(enb_id,i); + cell_conf[i]->has_max_harq_msg3tx = 1; + //TODO: Fill in with actual value, See TS 36.213, section 10.1 + cell_conf[i]->n1pucch_an = get_n1pucch_an(enb_id,i); + cell_conf[i]->has_n1pucch_an = 1; + //TODO: Fill in with actual value, See TS 36.211, section 5.4 + cell_conf[i]->deltapucch_shift = get_deltaPUCCH_Shift(enb_id,i); + cell_conf[i]->has_deltapucch_shift = 1; + //TODO: Fill in with actual value, See TS 36.211, section 5.4 + cell_conf[i]->nrb_cqi = get_nRB_CQI(enb_id,i); + cell_conf[i]->has_nrb_cqi = 1; + //TODO: Fill in with actual value, See TS 36.211, table 5.5.3.3-1 and 2 + cell_conf[i]->srs_subframe_config = get_srs_SubframeConfig(enb_id,i); + cell_conf[i]->has_srs_subframe_config = 1; + //TODO: Fill in with actual value, See TS 36.211, section 5.5.3.2 + cell_conf[i]->srs_bw_config = get_srs_BandwidthConfig(enb_id,i); + cell_conf[i]->has_srs_bw_config = 1; + //TODO: Fill in with actual value, Boolean value. See TS 36.211, section 5.5.3.2. TDD only + cell_conf[i]->srs_mac_up_pts = get_srs_MaxUpPts(enb_id,i); + cell_conf[i]->has_srs_mac_up_pts = 1; + //TODO: Fill in with actual value, One of the PREQ_ values + cell_conf[i]->enable_64qam = get_enable64QAM(enb_id,i); + cell_conf[i]->has_enable_64qam = 1; + //TODO: Fill in with actual value, Carrier component index + cell_conf[i]->carrier_index = i; + cell_conf[i]->has_carrier_index = 1; + } + enb_config_reply_msg->cell_config=cell_conf; + } + *msg = malloc(sizeof(Protocol__ProgranMessage)); + if(*msg == NULL) + goto error; + protocol__progran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + (*msg)->enb_config_reply_msg = enb_config_reply_msg; + + return 0; + + error: + // TODO: Need to make proper error handling + if (header != NULL) + free(header); + if (enb_config_reply_msg != NULL) + free(enb_config_reply_msg); + if(*msg != NULL) + free(*msg); + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 493ff11d33..34ac1caa86 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -56,6 +56,8 @@ #include "RRC/LITE/extern.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" +#include "enb_agent_extern.h" + //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" @@ -255,6 +257,12 @@ void rx_sdu( } else LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d Added user with rnti %x => UE %d\n", enb_mod_idP,CC_idP,frameP,eNB->common_channels[CC_idP].RA_template[ii].rnti,UE_id); + //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future + if (mac_agent_registered[enb_mod_idP]) { + agent_mac_xface[enb_mod_idP]->enb_agent_notify_ue_state_change(enb_mod_idP, + eNB->common_channels[CC_idP].RA_template[ii].rnti, + PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_ACTIVATED); + } } else { LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3 from already registered UE %d: length %d, offset %d\n", enb_mod_idP,CC_idP,frameP,UE_id,rx_lengths[i],payload_ptr-sduP); From 00b158829fd7db9b2a3d3fbf999d82937968757f Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 23 Feb 2016 17:57:22 +0000 Subject: [PATCH 117/413] Fixed bug in UE configuration message --- openair2/ENB_APP/enb_agent_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index a31020881e..b1633bea38 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -1197,7 +1197,7 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra goto error; } for (i = 0; i < ue_config_reply_msg->n_ue_config; i++) { - ue_config[i] = malloc(sizeof(Protocol__PrpUeConfig *)); + ue_config[i] = malloc(sizeof(Protocol__PrpUeConfig)); protocol__prp_ue_config__init(ue_config[i]); //TODO: Set the RNTI of the ue with id i ue_config[i]->rnti = get_ue_crnti(mod_id,i); From a637957c7c3e047bc7aa63b47348a5eea1cb07d8 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 24 Feb 2016 12:46:22 +0000 Subject: [PATCH 118/413] Moved UE activation notification to RRC --- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 8 -------- openair2/RRC/LITE/rrc_eNB.c | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 34ac1caa86..493ff11d33 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -56,8 +56,6 @@ #include "RRC/LITE/extern.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" -#include "enb_agent_extern.h" - //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" @@ -257,12 +255,6 @@ void rx_sdu( } else LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d Added user with rnti %x => UE %d\n", enb_mod_idP,CC_idP,frameP,eNB->common_channels[CC_idP].RA_template[ii].rnti,UE_id); - //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future - if (mac_agent_registered[enb_mod_idP]) { - agent_mac_xface[enb_mod_idP]->enb_agent_notify_ue_state_change(enb_mod_idP, - eNB->common_channels[CC_idP].RA_template[ii].rnti, - PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_ACTIVATED); - } } else { LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d CCCH: Received Msg3 from already registered UE %d: length %d, offset %d\n", enb_mod_idP,CC_idP,frameP,UE_id,rx_lengths[i],payload_ptr-sduP); diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 1d0b5f2902..4d5d390d0d 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -99,6 +99,8 @@ #include "SIMULATION/TOOLS/defs.h" // for taus +#include "enb_agent_extern.h" + //#define XER_PRINT #ifdef PHY_EMUL @@ -4093,6 +4095,12 @@ rrc_eNB_decode_dcch( ue_context_p, &ul_dcch_msg->message.choice.c1.choice.rrcConnectionSetupComplete.criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8); ue_context_p->ue_context.Status = RRC_CONNECTED; + //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future + if (mac_agent_registered[ctxt_pP->eNB_index]) { + agent_mac_xface[ctxt_pP->eNB_index]->enb_agent_notify_ue_state_change(ctxt_pP->eNB_index, + ue_context_p->ue_id_rnti, + PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_ACTIVATED); + } LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_CONNECTED \n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); } From 906e90727e091bf3055d84166b1477163ce919c3 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 24 Feb 2016 12:47:24 +0000 Subject: [PATCH 119/413] Fixed LC config reporting based on existing LCs --- openair2/ENB_APP/enb_agent_common.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index b1633bea38..ec4f70abe9 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -43,6 +43,9 @@ #include "PHY/extern.h" #include "log.h" +#include "RRC/LITE/extern.h" +#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" + void * enb[NUM_MAX_ENB]; void * enb_ue[NUM_MAX_ENB]; @@ -375,7 +378,8 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) } else if (state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_UPDATED || state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_ACTIVATED) { // TODO: Set the whole UE configuration message - + config->has_rnti = 1; + config->rnti = rnti; } else if (state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_MOVED) { // TODO: Not supported for now. Leave blank } @@ -1039,7 +1043,11 @@ int get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) int get_lcg(mid_t ue_id, mid_t lc_id) { - return &UE_mac_inst[ue_id].logicalChannelConfig[lc_id]->ul_SpecificParameters->logicalChannelGroup; + 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 get_direction(mid_t ue_id, mid_t lc_id) @@ -1093,7 +1101,16 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Progra lc_ue_config[i]->has_rnti = 1; lc_ue_config[i]->rnti = get_ue_crnti(mod_id,i); //TODO: Set the number of LC configurations that will be reported for this UE - lc_ue_config[i]->n_lc_config = 3; + //Set this according to the current state of the UE. This is only a temporary fix + int status = 0; + status = mac_eNB_get_rrc_status(mod_id, get_ue_crnti(mod_id, i)); + if (status < RRC_CONNECTED) { + lc_ue_config[i]->n_lc_config = 0; + } else if (status == RRC_CONNECTED) { + lc_ue_config[i]->n_lc_config = 1; + } else { + lc_ue_config[i]->n_lc_config = 3; + } Protocol__PrpLcConfig **lc_config; if (lc_ue_config[i]->n_lc_config > 0) { lc_config = malloc(sizeof(Protocol__PrpLcConfig *) * lc_ue_config[i]->n_lc_config); From fffb682f7a92c91ecbb6de8071528dfccfbfbc42 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 24 Feb 2016 14:38:44 +0000 Subject: [PATCH 120/413] Added continuous update support --- openair2/ENB_APP/enb_agent_mac.c | 52 ++++++++++++++++++----------- openair2/LAYER2/MAC/eNB_scheduler.c | 1 + 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 5c279958fe..0c68c4b80c 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -168,6 +168,18 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr request_config.report_type = PROTOCOL__PRP_STATS_TYPE__PRST_COMPLETE_STATS; request_config.report_frequency = PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_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; enb_agent_enable_cont_mac_stats_update(enb_id, xid, &request_config); } @@ -1204,44 +1216,46 @@ void enb_agent_send_sf_trigger(mid_t mod_id) { void enb_agent_send_update_mac_stats(mid_t mod_id) { - Protocol__ProgranMessage *current_report, *msg; + Protocol__ProgranMessage *current_report = NULL, *msg; void *data; int size; err_code_t err_code; int priority; mac_stats_updates_context_t stats_context = mac_stats_context[mod_id]; - + if (pthread_mutex_lock(mac_stats_context[mod_id].mutex)) { goto error; } - /*Create a fresh report with the required flags*/ - err_code = enb_agent_mac_handle_stats(mod_id, (void *) mac_stats_context[mod_id].stats_req, ¤t_report); - if (err_code < 0) { - goto error; + if (mac_stats_context[mod_id].cont_update == 1) { + + /*Create a fresh report with the required flags*/ + err_code = enb_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) { */ - /*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 = enb_agent_generate_diff_mac_stats_report(current_report, mac_stats_context[mod_id].prev_stats_reply); */ - msg = enb_agent_generate_diff_mac_stats_report(current_report, mac_stats_context[mod_id].prev_stats_reply); - - /*Destroy the old stats*/ - enb_agent_destroy_progran_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; + /* /\*Destroy the old stats*\/ */ + /* enb_agent_destroy_progran_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 (msg != NULL){ - data=enb_agent_pack_message(msg, &size); + if (current_report != NULL){ + data=enb_agent_pack_message(current_report, &size); /*Send any stats updates using the MAC channel of the eNB*/ if (enb_agent_msg_send(mod_id, ENB_AGENT_MAC, data, size, priority)) { err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 774feda961..e2423e2c10 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -219,6 +219,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, //Send subframe trigger to the controller if (mac_agent_registered[module_idP]) { agent_mac_xface[module_idP]->enb_agent_send_sf_trigger(module_idP); + agent_mac_xface[module_idP]->enb_agent_send_update_mac_stats(module_idP); } #endif From f84568e1714edb263d982dc73a628861f4378d0c Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 24 Feb 2016 14:40:03 +0000 Subject: [PATCH 121/413] Bug fix when checking for the LCG of an LC --- openair2/ENB_APP/enb_agent_common.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index ec4f70abe9..c567a78b6c 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -1053,8 +1053,7 @@ int get_lcg(mid_t ue_id, mid_t lc_id) int get_direction(mid_t ue_id, mid_t lc_id) { /*TODO: fill with the value for the rest of LCID*/ - - if(lc_id == CCCH | lc_id == DCCH) + if(lc_id == DCCH | lc_id == DCCH1) return 2; else if(lc_id == DTCH) return 1; @@ -1124,8 +1123,11 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Progra lc_config[j]->has_lcid = 1; lc_config[j]->lcid = j+1; //TODO: Set the LCG of the channel - lc_config[j]->has_lcg = 1; - lc_config[j]->lcg = get_lcg(i,j+1); + int lcg = get_lcg(i, j+1); + if (lcg >= 0 && lcg <= 3) { + lc_config[j]->has_lcg = 1; + lc_config[j]->lcg = get_lcg(i,j+1); + } //TODO: Set the LC direction lc_config[j]->has_direction = 1; lc_config[j]->direction = get_direction(i,j+1); From 4c7d1e03819ca7331d16f35b290188c3a0fc021a Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 24 Feb 2016 17:31:13 +0000 Subject: [PATCH 122/413] Added support for indication of a UE state in both RRC_CONNECTED and RRC_RECONFIGURED STATES --- openair2/RRC/LITE/rrc_eNB.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 4d5d390d0d..adaf50d62e 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -4013,6 +4013,12 @@ rrc_eNB_decode_dcch( LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_RECONFIGURED \n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future + if (mac_agent_registered[ctxt_pP->eNB_index]) { + agent_mac_xface[ctxt_pP->eNB_index]->enb_agent_notify_ue_state_change(ctxt_pP->eNB_index, + ue_context_p->ue_id_rnti, + PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_UPDATED); + } } #if defined(ENABLE_USE_MME) @@ -4095,14 +4101,14 @@ rrc_eNB_decode_dcch( ue_context_p, &ul_dcch_msg->message.choice.c1.choice.rrcConnectionSetupComplete.criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8); ue_context_p->ue_context.Status = RRC_CONNECTED; - //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future - if (mac_agent_registered[ctxt_pP->eNB_index]) { - agent_mac_xface[ctxt_pP->eNB_index]->enb_agent_notify_ue_state_change(ctxt_pP->eNB_index, - ue_context_p->ue_id_rnti, - PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_ACTIVATED); - } LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_CONNECTED \n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future + if (mac_agent_registered[ctxt_pP->eNB_index]) { + agent_mac_xface[ctxt_pP->eNB_index]->enb_agent_notify_ue_state_change(ctxt_pP->eNB_index, + ue_context_p->ue_id_rnti, + PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_ACTIVATED); + } } } From a5fd6187706a65a94fd3b8a0afa231d3c7f13aaa Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 24 Feb 2016 17:33:49 +0000 Subject: [PATCH 123/413] Fixed bug of wrong rnti value when finding it using the UE id --- openair2/ENB_APP/enb_agent_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index c567a78b6c..d971b67fac 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -586,7 +586,7 @@ int get_num_ues (mid_t mod_id){ int get_ue_crnti (mid_t mod_id, mid_t ue_id){ - return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].crnti; + return UE_RNTI(mod_id, ue_id); } int get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid) { From 9bbc22f496cdf92b4731de68ad2b57b34403a3e3 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 24 Feb 2016 18:28:32 +0000 Subject: [PATCH 124/413] Added UE state change message support --- openair2/ENB_APP/enb_agent_common.c | 636 +++++++++++++++++++++------- 1 file changed, 489 insertions(+), 147 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index d971b67fac..835c4664d4 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -45,12 +45,11 @@ #include "RRC/LITE/extern.h" #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]; -void * enb_ue_rrc[NUM_MAX_ENB]; /* * message primitives */ @@ -343,70 +342,6 @@ int enb_agent_destroy_lc_config_reply(Protocol__ProgranMessage *msg) { return -1; } -int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { - int size; - Protocol__ProgranMessage *msg; - Protocol__PrpHeader *header; - void *data; - int priority; - err_code_t err_code; - - int xid = 0; - - if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_UE_STATE_CHANGE, &header) != 0) - goto error; - - Protocol__PrpUeStateChange *ue_state_change_msg; - ue_state_change_msg = malloc(sizeof(Protocol__PrpUeStateChange)); - if(ue_state_change_msg == NULL) { - goto error; - } - protocol__prp_ue_state_change__init(ue_state_change_msg); - ue_state_change_msg->has_type = 1; - ue_state_change_msg->type = state_change; - - Protocol__PrpUeConfig *config; - config = malloc(sizeof(Protocol__PrpUeConfig)); - if (config == NULL) { - goto error; - } - protocol__prp_ue_config__init(config); - if (state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_DEACTIVATED) { - // Simply set the rnti of the UE - config->has_rnti = 1; - config->rnti = rnti; - } else if (state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_UPDATED - || state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_ACTIVATED) { - // TODO: Set the whole UE configuration message - config->has_rnti = 1; - config->rnti = rnti; - } else if (state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_MOVED) { - // TODO: Not supported for now. Leave blank - } - - ue_state_change_msg->config = config; - msg = malloc(sizeof(Protocol__ProgranMessage)); - if (msg == NULL) { - goto error; - } - protocol__progran_message__init(msg); - msg->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG; - msg->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; - msg->ue_state_change_msg = ue_state_change_msg; - - data = enb_agent_pack_message(msg, &size); - /*Send sr info using the MAC channel of the eNB*/ - if (enb_agent_msg_send(mod_id, ENB_AGENT_DEFAULT, data, size, priority)) { - err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; - goto error; - } - - LOG_D(ENB_AGENT,"sent message with size %d\n", size); - return; - error: - LOG_D(ENB_AGENT, "Could not send UE state message\n"); -} - int enb_agent_destroy_ue_state_change(Protocol__ProgranMessage *msg) { if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG) goto error; @@ -525,7 +460,6 @@ void set_enb_vars(mid_t mod_id, ran_name_t ran){ 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]; - enb_ue_rrc[mod_id] = (void *)&UE_rrc_inst[mod_id]; break; default : goto error; @@ -901,26 +835,60 @@ int get_num_pdcch_symb(mid_t mod_id, int CC_id) * ************************************ */ + int get_time_alignment_timer(mid_t mod_id, mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->mac_MainConfig[mod_id]->timeAlignmentTimerDedicated); + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = get_ue_crnti(mod_id,ue_id); + + LOG_I(ENB_APP,"The value of rntiP is %d\n",rntiP); + 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; } int get_meas_gap_config(mid_t mod_id, mid_t ue_id) { - if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->measGapConfig[mod_id]->present == MeasGapConfig_PR_NOTHING) - return 2; - else if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->measGapConfig[mod_id]->present == MeasGapConfig_PR_release) - return 0; - else if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->measGapConfig[mod_id]->present == MeasGapConfig_PR_setup) - return 1; + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = get_ue_crnti(mod_id,ue_id); - return -1; + LOG_I(ENB_APP,"The value of rntiP is %d\n",rntiP); + 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_NOTHING) + return 2; + else if (ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_release) + return 0; + else if(ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_setup) + return 1; + } + } + else + return -1; } int get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->measGapConfig[mod_id]->choice.setup.gapOffset.present); + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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){ + return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present; + } + } + else + return -1; } int get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id) @@ -935,110 +903,250 @@ int get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id) int get_half_duplex(mid_t ue_id) { - 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; + //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; } int get_intra_sf_hopping(mid_t ue_id) { - uint8_t temp = 0; - temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); - return (temp & ( 1 << (31))); + //TODO:Get proper value + //temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); + //return (0 & ( 1 << (31))); } int get_type2_sb_1(mid_t ue_id) { - uint8_t temp = 0; - temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); - return (temp & ( 1 << (11))); + //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))); } int get_ue_category(mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->ue_Category); + //TODO:Get proper value + //return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->ue_Category); } int get_res_alloc_type1(mid_t ue_id) { - uint8_t temp = 0; - temp = (((UE_RRC_INST *)enb_ue_rrc[ue_id])->UECap->UE_EUTRA_Capability->featureGroupIndicators->buf); - return (temp & ( 1 << (30))); + //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))); } int get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->antennaInfo->choice.explicitValue.transmissionMode); + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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; } int get_tti_bundling(mid_t mod_id, mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->mac_MainConfig[mod_id]->ul_SCH_Config->ttiBundling); + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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; } int get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->mac_MainConfig[mod_id]->ul_SCH_Config->maxHARQ_Tx); + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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; + } + } + else + return -1; } int get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->pusch_ConfigDedicated->betaOffset_ACK_Index); + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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; } int get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->pusch_ConfigDedicated->betaOffset_RI_Index); + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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; } int get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->pusch_ConfigDedicated->betaOffset_CQI_Index); + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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; } int get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.simultaneousAckNackAndCQI); + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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 get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->sib2[mod_id]->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission); + return (&eNB_rrc_inst[mod_id])->carrier[0].sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission; } int get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->cqi_ReportConfig->cqi_ReportModeAperiodic); + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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; + } + } + else + return -1; } int get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->pucch_ConfigDedicated->tdd_AckNackFeedbackMode); + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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; } int get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) { - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->pucch_ConfigDedicated->ackNackRepetition.choice.setup.repetitionFactor); + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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; } int get_extended_bsr_size(mid_t mod_id, mid_t ue_id) { //TODO: need to double check - return (((UE_RRC_INST *)enb_ue_rrc[ue_id])->mac_MainConfig[mod_id]->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10); + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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){ + return ue_context_p->ue_context.mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10; + } + } + } + return -1; } int get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) { - if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_closedLoop) - return 2; - else if(((UE_RRC_INST *)enb_ue_rrc[ue_id])->physicalConfigDedicated[mod_id]->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup == AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_openLoop) - return 1; + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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 0; + return -1; } int get_lcg(mid_t ue_id, mid_t lc_id) @@ -1059,6 +1167,207 @@ int get_direction(mid_t ue_id, mid_t lc_id) return 1; } +int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { + int size; + Protocol__ProgranMessage *msg; + Protocol__PrpHeader *header; + void *data; + int priority; + err_code_t err_code; + + int xid = 0; + + if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_UE_STATE_CHANGE, &header) != 0) + goto error; + + Protocol__PrpUeStateChange *ue_state_change_msg; + ue_state_change_msg = malloc(sizeof(Protocol__PrpUeStateChange)); + if(ue_state_change_msg == NULL) { + goto error; + } + protocol__prp_ue_state_change__init(ue_state_change_msg); + ue_state_change_msg->has_type = 1; + ue_state_change_msg->type = state_change; + + Protocol__PrpUeConfig *config; + config = malloc(sizeof(Protocol__PrpUeConfig)); + if (config == NULL) { + goto error; + } + protocol__prp_ue_config__init(config); + if (state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_DEACTIVATED) { + // Simply set the rnti of the UE + config->has_rnti = 1; + config->rnti = rnti; + } else if (state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_UPDATED + || state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_ACTIVATED) { + int i =find_UE_id(mod_id,rnti); + config->has_rnti = 1; + config->rnti = rnti; + LOG_I(ENB_APP,"The value of i is %d\n",i); + LOG_I(ENB_APP,"The value of rnto is %d\n",rnti); + //TODO: Set the time_alignment_timer + if(get_time_alignment_timer(mod_id,i) != -1){ + config->time_alignment_timer = get_time_alignment_timer(mod_id,i); + config->has_time_alignment_timer = 1; + } + //TODO: Set the measurement gap configuration pattern + if(get_meas_gap_config(mod_id,i) != -1){ + config->meas_gap_config_pattern = get_meas_gap_config(mod_id,i); + config->has_meas_gap_config_pattern = 1; + } + //TODO: Set the measurement gap offset if applicable + if(get_meas_gap_config_offset(mod_id,i) != -1){ + config->meas_gap_config_sf_offset = 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 noe, 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 + + //TODO: Set the transmission mode + if(get_ue_transmission_mode(mod_id,i) != -1){ + config->transmission_mode = get_ue_transmission_mode(mod_id,i); + config->has_transmission_mode = 1; + } + + //TODO: Set the aggregated bit-rate of the non-gbr bearer (UL) + config->ue_aggregated_max_bitrate_ul = get_ue_aggregated_max_bitrate_ul(mod_id,i); + config->has_ue_aggregated_max_bitrate_ul = 1; + + //TODO: Set the aggregated bit-rate of the non-gbr bearer (DL) + config->ue_aggregated_max_bitrate_dl = get_ue_aggregated_max_bitrate_dl(mod_id,i); + config->has_ue_aggregated_max_bitrate_dl = 1; + + //TODO: Set the UE capabilities + Protocol__PrpUeCapabilities *c_capabilities; + c_capabilities = malloc(sizeof(Protocol__PrpUeCapabilities)); + protocol__prp_ue_capabilities__init(c_capabilities); + //TODO: Set half duplex (FDD operation) + c_capabilities->has_half_duplex = 1; + c_capabilities->half_duplex = 1;//get_half_duplex(i); + //TODO: Set intra-frame hopping flag + c_capabilities->has_intra_sf_hopping = 1; + c_capabilities->intra_sf_hopping = 1;//get_intra_sf_hopping(i); + //TODO: Set support for type 2 hopping with n_sb > 1 + c_capabilities->has_type2_sb_1 = 1; + c_capabilities->type2_sb_1 = 1;//get_type2_sb_1(i); + //TODO: Set ue category + c_capabilities->has_ue_category = 1; + c_capabilities->ue_category = 1;//get_ue_category(i); + //TODO: Set UE support for resource allocation type 1 + c_capabilities->has_res_alloc_type1 = 1; + c_capabilities->res_alloc_type1 = 1;//get_res_alloc_type1(i); + //Set the capabilites to the message + config->capabilities = c_capabilities; + //TODO: Set UE transmission antenna. One of the PRUTA_* values + if(get_ue_transmission_antenna(mod_id,i) != -1){ + config->has_ue_transmission_antenna = 1; + config->ue_transmission_antenna = get_ue_transmission_antenna(mod_id,i); + } + //TODO: Set tti bundling flag (See ts 36.321) + if(get_tti_bundling(mod_id,i) != -1){ + config->has_tti_bundling = 1; + config->tti_bundling = get_tti_bundling(mod_id,i); + } + //TODO: Set the max HARQ retransmission for the UL + if(get_maxHARQ_TX(mod_id,i) != -1){ + config->has_max_harq_tx = 1; + config->max_harq_tx = get_maxHARQ_TX(mod_id,i); + } + //TODO: Fill beta_offset_ack_index (TS 36.213) + if(get_beta_offset_ack_index(mod_id,i) != -1){ + config->has_beta_offset_ack_index = 1; + config->beta_offset_ack_index = get_beta_offset_ack_index(mod_id,i); + } + //TODO: Fill beta_offset_ri_index (TS 36.213) + if(get_beta_offset_ri_index(mod_id,i) != -1){ + config->has_beta_offset_ri_index = 1; + config->beta_offset_ri_index = get_beta_offset_ri_index(mod_id,i); + } + //TODO: Fill beta_offset_cqi_index (TS 36.213) + if(get_beta_offset_cqi_index(mod_id,i) != -1){ + config->has_beta_offset_cqi_index = 1; + config->beta_offset_cqi_index = get_beta_offset_cqi_index(mod_id,i); + } + //TODO: Fill ack_nack_simultaneous_trans (TS 36.213) + if(get_ack_nack_simultaneous_trans(mod_id,i) != -1){ + config->has_ack_nack_simultaneous_trans = 1; + config->ack_nack_simultaneous_trans = get_ack_nack_simultaneous_trans(mod_id,i); + } + //TODO: Fill simultaneous_ack_nack_cqi (TS 36.213) + if(get_simultaneous_ack_nack_cqi(mod_id,i) != -1){ + config->has_simultaneous_ack_nack_cqi = 1; + config->simultaneous_ack_nack_cqi = get_simultaneous_ack_nack_cqi(mod_id,i); + } + //TODO: Set PRACRM_* value regarding aperiodic cqi report mode + if(get_aperiodic_cqi_rep_mode(mod_id,i) != -1){ + config->has_aperiodic_cqi_rep_mode = 1; + config->aperiodic_cqi_rep_mode = get_aperiodic_cqi_rep_mode(mod_id,i); + } + //TODO: Set tdd_ack_nack_feedback + if(get_tdd_ack_nack_feedback != -1){ + config->has_tdd_ack_nack_feedback = 1; + config->tdd_ack_nack_feedback = get_tdd_ack_nack_feedback(mod_id,i); + } + //TODO: Set ack_nack_repetition factor + if(get_ack_nack_repetition_factor != -1){ + config->has_ack_nack_repetition_factor = 1; + config->ack_nack_repetition_factor = get_ack_nack_repetition_factor(mod_id,i); + } + //TODO: Set extended BSR size + if(get_extended_bsr_size != -1){ + config->has_extended_bsr_size = 1; + config->extended_bsr_size = get_extended_bsr_size(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 index of primary cell + config->has_pcell_carrier_index = 1; + config->pcell_carrier_index = 1; + //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 = 1; + config->scell_deactivation_timer = 1; + } + } else if (state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_MOVED) { + // TODO: Not supported for now. Leave blank + } + + ue_state_change_msg->config = config; + msg = malloc(sizeof(Protocol__ProgranMessage)); + if (msg == NULL) { + goto error; + } + protocol__progran_message__init(msg); + msg->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG; + msg->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + msg->ue_state_change_msg = ue_state_change_msg; + + data = enb_agent_pack_message(msg, &size); + /*Send sr info using the MAC channel of the eNB*/ + if (enb_agent_msg_send(mod_id, ENB_AGENT_DEFAULT, data, size, priority)) { + err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + goto error; + } + + LOG_D(ENB_AGENT,"sent message with size %d\n", size); + return; + error: + LOG_D(ENB_AGENT, "Could not send UE state message\n"); +} /* * timer primitives @@ -1225,14 +1534,20 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra //Not supported for now, so we do not set it //TODO: Set the time_alignment_timer - ue_config[i]->time_alignment_timer = get_time_alignment_timer(mod_id,i); - ue_config[i]->has_time_alignment_timer = 1; + if(get_time_alignment_timer(mod_id,i) != -1){ + ue_config[i]->time_alignment_timer = get_time_alignment_timer(mod_id,i); + ue_config[i]->has_time_alignment_timer = 1; + } //TODO: Set the measurement gap configuration pattern - ue_config[i]->meas_gap_config_pattern = get_meas_gap_config(mod_id,i); - ue_config[i]->has_meas_gap_config_pattern = 1; + if(get_meas_gap_config(mod_id,i) != -1){ + ue_config[i]->meas_gap_config_pattern = get_meas_gap_config(mod_id,i); + ue_config[i]->has_meas_gap_config_pattern = 1; + } //TODO: Set the measurement gap offset if applicable - ue_config[i]->meas_gap_config_sf_offset = get_meas_gap_config_offset(mod_id,i); - ue_config[i]->has_meas_gap_config_sf_offset = 1; + if(get_meas_gap_config_offset(mod_id,i) != -1){ + ue_config[i]->meas_gap_config_sf_offset = get_meas_gap_config_offset(mod_id,i); + ue_config[i]->has_meas_gap_config_sf_offset = 1; + } //TODO: Set the SPS configuration (Optional) //Not supported for noe, so we do not set it @@ -1243,8 +1558,10 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra //We do not set it for now //TODO: Set the transmission mode - ue_config[i]->transmission_mode = get_ue_transmission_mode(mod_id,i); - ue_config[i]->has_transmission_mode = 1; + if(get_ue_transmission_mode(mod_id,i) != -1){ + ue_config[i]->transmission_mode = get_ue_transmission_mode(mod_id,i); + ue_config[i]->has_transmission_mode = 1; + } //TODO: Set the aggregated bit-rate of the non-gbr bearer (UL) ue_config[i]->ue_aggregated_max_bitrate_ul = get_ue_aggregated_max_bitrate_ul(mod_id,i); @@ -1260,57 +1577,81 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra protocol__prp_ue_capabilities__init(capabilities); //TODO: Set half duplex (FDD operation) capabilities->has_half_duplex = 1; - capabilities->half_duplex = get_half_duplex(i); + capabilities->half_duplex = 1;//get_half_duplex(i); //TODO: Set intra-frame hopping flag capabilities->has_intra_sf_hopping = 1; - capabilities->intra_sf_hopping = get_intra_sf_hopping(i); + capabilities->intra_sf_hopping = 1;//get_intra_sf_hopping(i); //TODO: Set support for type 2 hopping with n_sb > 1 capabilities->has_type2_sb_1 = 1; - capabilities->type2_sb_1 = get_type2_sb_1(i); + capabilities->type2_sb_1 = 1;//get_type2_sb_1(i); //TODO: Set ue category capabilities->has_ue_category = 1; - capabilities->ue_category = get_ue_category(i); + capabilities->ue_category = 1;//get_ue_category(i); //TODO: Set UE support for resource allocation type 1 capabilities->has_res_alloc_type1 = 1; - capabilities->res_alloc_type1 = get_res_alloc_type1(i); + capabilities->res_alloc_type1 = 1;//get_res_alloc_type1(i); //Set the capabilites to the message ue_config[i]->capabilities = capabilities; //TODO: Set UE transmission antenna. One of the PRUTA_* values - ue_config[i]->has_ue_transmission_antenna = 1; - ue_config[i]->ue_transmission_antenna = get_ue_transmission_antenna(mod_id,i); + if(get_ue_transmission_antenna(mod_id,i) != -1){ + ue_config[i]->has_ue_transmission_antenna = 1; + ue_config[i]->ue_transmission_antenna = get_ue_transmission_antenna(mod_id,i); + } //TODO: Set tti bundling flag (See ts 36.321) - ue_config[i]->has_tti_bundling = 1; - ue_config[i]->tti_bundling = get_tti_bundling(mod_id,i); + if(get_tti_bundling(mod_id,i) != -1){ + ue_config[i]->has_tti_bundling = 1; + ue_config[i]->tti_bundling = get_tti_bundling(mod_id,i); + } //TODO: Set the max HARQ retransmission for the UL - ue_config[i]->has_max_harq_tx = 1; - ue_config[i]->max_harq_tx = get_maxHARQ_TX(mod_id,i); + if(get_maxHARQ_TX(mod_id,i) != -1){ + ue_config[i]->has_max_harq_tx = 1; + ue_config[i]->max_harq_tx = get_maxHARQ_TX(mod_id,i); + } //TODO: Fill beta_offset_ack_index (TS 36.213) - ue_config[i]->has_beta_offset_ack_index = 1; - ue_config[i]->beta_offset_ack_index = get_beta_offset_ack_index(mod_id,i); + if(get_beta_offset_ack_index(mod_id,i) != -1){ + ue_config[i]->has_beta_offset_ack_index = 1; + ue_config[i]->beta_offset_ack_index = get_beta_offset_ack_index(mod_id,i); + } //TODO: Fill beta_offset_ri_index (TS 36.213) - ue_config[i]->has_beta_offset_ri_index = 1; - ue_config[i]->beta_offset_ri_index = get_beta_offset_ri_index(mod_id,i); + if(get_beta_offset_ri_index(mod_id,i) != -1){ + ue_config[i]->has_beta_offset_ri_index = 1; + ue_config[i]->beta_offset_ri_index = get_beta_offset_ri_index(mod_id,i); + } //TODO: Fill beta_offset_cqi_index (TS 36.213) - ue_config[i]->has_beta_offset_cqi_index = 1; - ue_config[i]->beta_offset_cqi_index = get_beta_offset_cqi_index(mod_id,i); + if(get_beta_offset_cqi_index(mod_id,i) != -1){ + ue_config[i]->has_beta_offset_cqi_index = 1; + ue_config[i]->beta_offset_cqi_index = get_beta_offset_cqi_index(mod_id,i); + } //TODO: Fill ack_nack_simultaneous_trans (TS 36.213) - ue_config[i]->has_ack_nack_simultaneous_trans = 1; - ue_config[i]->ack_nack_simultaneous_trans = get_ack_nack_simultaneous_trans(mod_id,i); + if(get_ack_nack_simultaneous_trans(mod_id,i) != -1){ + ue_config[i]->has_ack_nack_simultaneous_trans = 1; + ue_config[i]->ack_nack_simultaneous_trans = get_ack_nack_simultaneous_trans(mod_id,i); + } //TODO: Fill simultaneous_ack_nack_cqi (TS 36.213) - ue_config[i]->has_simultaneous_ack_nack_cqi = 1; - ue_config[i]->simultaneous_ack_nack_cqi = get_simultaneous_ack_nack_cqi(mod_id,i); + if(get_simultaneous_ack_nack_cqi(mod_id,i) != -1){ + ue_config[i]->has_simultaneous_ack_nack_cqi = 1; + ue_config[i]->simultaneous_ack_nack_cqi = get_simultaneous_ack_nack_cqi(mod_id,i); + } //TODO: Set PRACRM_* value regarding aperiodic cqi report mode - ue_config[i]->has_aperiodic_cqi_rep_mode = 1; - ue_config[i]->aperiodic_cqi_rep_mode = get_aperiodic_cqi_rep_mode(mod_id,i); + if(get_aperiodic_cqi_rep_mode(mod_id,i) != -1){ + ue_config[i]->has_aperiodic_cqi_rep_mode = 1; + ue_config[i]->aperiodic_cqi_rep_mode = get_aperiodic_cqi_rep_mode(mod_id,i); + } //TODO: Set tdd_ack_nack_feedback - ue_config[i]->has_tdd_ack_nack_feedback = 1; - ue_config[i]->tdd_ack_nack_feedback = get_tdd_ack_nack_feedback(mod_id,i); + if(get_tdd_ack_nack_feedback != -1){ + ue_config[i]->has_tdd_ack_nack_feedback = 1; + ue_config[i]->tdd_ack_nack_feedback = get_tdd_ack_nack_feedback(mod_id,i); + } //TODO: Set ack_nack_repetition factor - ue_config[i]->has_ack_nack_repetition_factor = 1; - ue_config[i]->ack_nack_repetition_factor = get_ack_nack_repetition_factor(mod_id,i); + if(get_ack_nack_repetition_factor != -1){ + ue_config[i]->has_ack_nack_repetition_factor = 1; + ue_config[i]->ack_nack_repetition_factor = get_ack_nack_repetition_factor(mod_id,i); + } //TODO: Set extended BSR size - ue_config[i]->has_extended_bsr_size = 1; - ue_config[i]->extended_bsr_size = get_extended_bsr_size(mod_id,i); + if(get_extended_bsr_size != -1){ + ue_config[i]->has_extended_bsr_size = 1; + ue_config[i]->extended_bsr_size = get_extended_bsr_size(mod_id,i); + } //TODO: Set carrier aggregation support (boolean) ue_config[i]->has_ca_support = 0; ue_config[i]->ca_support = 0; @@ -1843,3 +2184,4 @@ err_code_t enb_agent_restart_timer(uint32_t *timer_id){ } */ + From 24785b3a61e59ed7d06cbf28dd17a96b7009668a Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 25 Feb 2016 01:06:04 +0000 Subject: [PATCH 125/413] Fixed bugs in API function calls for UE config --- openair2/ENB_APP/enb_agent_common.c | 232 +++++++++++++++------------- 1 file changed, 121 insertions(+), 111 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 835c4664d4..6122789d6e 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -852,43 +852,46 @@ int get_time_alignment_timer(mid_t mod_id, mid_t ue_id) return -1; } -int 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 = get_ue_crnti(mod_id,ue_id); +int 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 = get_ue_crnti(mod_id,ue_id); - LOG_I(ENB_APP,"The value of rntiP is %d\n",rntiP); - 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_NOTHING) - return 2; - else if (ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_release) - return 0; - else if(ue_context_p->ue_context.measGapConfig->present == MeasGapConfig_PR_setup) - return 1; - } + 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__PRP_MEAS_GAP_CONFIG_PATTERN__PRMGCP_GP1; + } else if (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present == MeasGapConfig__setup__gapOffset_PR_gp1) { + return PROTOCOL__PRP_MEAS_GAP_CONFIG_PATTERN__PRMGCP_GP2; + } else { + return PROTOCOL__PRP_MEAS_GAP_CONFIG_PATTERN__PRMGCP_OFF; } - else - return -1; + } + } + } + return -1; } -int 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 = 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){ - return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present; - } - } - else - return -1; +int 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 = 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 get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id) @@ -974,20 +977,17 @@ int get_tti_bundling(mid_t mod_id, mid_t ue_id) return -1; } -int get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) -{ - struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = 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; - } - } - else - return -1; +int get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) { + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint32_t rntiP = 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 get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) @@ -1059,21 +1059,18 @@ int 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 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 = 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; - } - } - else - return -1; +int 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 = 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 get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) @@ -1109,22 +1106,23 @@ int get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) return -1; } -int 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 = get_ue_crnti(mod_id,ue_id); +int 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 = 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){ - return ue_context_p->ue_context.mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10; - } - } + 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; + } + } + } + return -1; } int get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) @@ -1217,9 +1215,10 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) config->has_meas_gap_config_pattern = 1; } //TODO: Set the measurement gap offset if applicable - if(get_meas_gap_config_offset(mod_id,i) != -1){ - config->meas_gap_config_sf_offset = get_meas_gap_config_offset(mod_id,i); - config->has_meas_gap_config_sf_offset = 1; + if(config->has_meas_gap_config_pattern == 1 && + config->meas_gap_config_pattern != PROTOCOL__PRP_MEAS_GAP_CONFIG_PATTERN__PRMGCP_OFF) { + config->meas_gap_config_sf_offset = 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 noe, so we do not set it @@ -1308,20 +1307,25 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) //TODO: Set PRACRM_* value regarding aperiodic cqi report mode if(get_aperiodic_cqi_rep_mode(mod_id,i) != -1){ config->has_aperiodic_cqi_rep_mode = 1; - config->aperiodic_cqi_rep_mode = get_aperiodic_cqi_rep_mode(mod_id,i); + int mode = get_aperiodic_cqi_rep_mode(mod_id,i); + if (mode > 4) { + config->aperiodic_cqi_rep_mode = PROTOCOL__PRP_APERIODIC_CQI_REPORT_MODE__PRACRM_NONE; + } else { + config->aperiodic_cqi_rep_mode = mode; + } } //TODO: Set tdd_ack_nack_feedback - if(get_tdd_ack_nack_feedback != -1){ + if(get_tdd_ack_nack_feedback(mod_id, i) != -1){ config->has_tdd_ack_nack_feedback = 1; config->tdd_ack_nack_feedback = get_tdd_ack_nack_feedback(mod_id,i); } //TODO: Set ack_nack_repetition factor - if(get_ack_nack_repetition_factor != -1){ + if(get_ack_nack_repetition_factor(mod_id, i) != -1){ config->has_ack_nack_repetition_factor = 1; config->ack_nack_repetition_factor = get_ack_nack_repetition_factor(mod_id,i); } //TODO: Set extended BSR size - if(get_extended_bsr_size != -1){ + if(get_extended_bsr_size(mod_id, i) != -1){ config->has_extended_bsr_size = 1; config->extended_bsr_size = get_extended_bsr_size(mod_id,i); } @@ -1544,10 +1548,11 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra ue_config[i]->has_meas_gap_config_pattern = 1; } //TODO: Set the measurement gap offset if applicable - if(get_meas_gap_config_offset(mod_id,i) != -1){ - ue_config[i]->meas_gap_config_sf_offset = get_meas_gap_config_offset(mod_id,i); - ue_config[i]->has_meas_gap_config_sf_offset = 1; - } + if(ue_config[i]->has_meas_gap_config_pattern == 1 && + ue_config[i]->meas_gap_config_pattern != PROTOCOL__PRP_MEAS_GAP_CONFIG_PATTERN__PRMGCP_OFF) { + ue_config[i]->meas_gap_config_sf_offset = get_meas_gap_config_offset(mod_id,i); + ue_config[i]->has_meas_gap_config_sf_offset = 1; + } //TODO: Set the SPS configuration (Optional) //Not supported for noe, so we do not set it @@ -1635,39 +1640,44 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra //TODO: Set PRACRM_* value regarding aperiodic cqi report mode if(get_aperiodic_cqi_rep_mode(mod_id,i) != -1){ ue_config[i]->has_aperiodic_cqi_rep_mode = 1; - ue_config[i]->aperiodic_cqi_rep_mode = get_aperiodic_cqi_rep_mode(mod_id,i); + int mode = get_aperiodic_cqi_rep_mode(mod_id,i); + if (mode > 4) { + ue_config[i]->aperiodic_cqi_rep_mode = PROTOCOL__PRP_APERIODIC_CQI_REPORT_MODE__PRACRM_NONE; + } else { + ue_config[i]->aperiodic_cqi_rep_mode = mode; } + } //TODO: Set tdd_ack_nack_feedback - if(get_tdd_ack_nack_feedback != -1){ - ue_config[i]->has_tdd_ack_nack_feedback = 1; - ue_config[i]->tdd_ack_nack_feedback = get_tdd_ack_nack_feedback(mod_id,i); - } + if(get_tdd_ack_nack_feedback(mod_id, i) != -1){ + ue_config[i]->has_tdd_ack_nack_feedback = 1; + ue_config[i]->tdd_ack_nack_feedback = get_tdd_ack_nack_feedback(mod_id,i); + } //TODO: Set ack_nack_repetition factor - if(get_ack_nack_repetition_factor != -1){ - ue_config[i]->has_ack_nack_repetition_factor = 1; - ue_config[i]->ack_nack_repetition_factor = get_ack_nack_repetition_factor(mod_id,i); - } + if(get_ack_nack_repetition_factor(mod_id, i) != -1){ + ue_config[i]->has_ack_nack_repetition_factor = 1; + ue_config[i]->ack_nack_repetition_factor = get_ack_nack_repetition_factor(mod_id,i); + } //TODO: Set extended BSR size - if(get_extended_bsr_size != -1){ - ue_config[i]->has_extended_bsr_size = 1; - ue_config[i]->extended_bsr_size = get_extended_bsr_size(mod_id,i); - } + if(get_extended_bsr_size(mod_id, i) != -1){ + ue_config[i]->has_extended_bsr_size = 1; + ue_config[i]->extended_bsr_size = get_extended_bsr_size(mod_id,i); + } //TODO: Set carrier aggregation support (boolean) ue_config[i]->has_ca_support = 0; ue_config[i]->ca_support = 0; if(ue_config[i]->has_ca_support){ - //TODO: Set cross carrier scheduling support (boolean) - ue_config[i]->has_cross_carrier_sched_support = 1; - ue_config[i]->cross_carrier_sched_support = 0; - //TODO: Set index of primary cell - ue_config[i]->has_pcell_carrier_index = 1; - ue_config[i]->pcell_carrier_index = 1; - //TODO: Set secondary cells configuration - // We do not set it for now. No carrier aggregation support - - //TODO: Set deactivation timer for secondary cell - ue_config[i]->has_scell_deactivation_timer = 1; - ue_config[i]->scell_deactivation_timer = 1; + //TODO: Set cross carrier scheduling support (boolean) + ue_config[i]->has_cross_carrier_sched_support = 1; + ue_config[i]->cross_carrier_sched_support = 0; + //TODO: Set index of primary cell + ue_config[i]->has_pcell_carrier_index = 1; + ue_config[i]->pcell_carrier_index = 1; + //TODO: Set secondary cells configuration + // We do not set it for now. No carrier aggregation support + + //TODO: Set deactivation timer for secondary cell + ue_config[i]->has_scell_deactivation_timer = 1; + ue_config[i]->scell_deactivation_timer = 1; } } ue_config_reply_msg->ue_config = ue_config; From 197726ce61c45a2f2acdaed046cf221cb4a7ee09 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 25 Feb 2016 13:55:19 +0000 Subject: [PATCH 126/413] Fixed memory leaks in sf and mac config messages --- openair2/ENB_APP/enb_agent_mac.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 0c68c4b80c..7be6e6ba12 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -1041,10 +1041,12 @@ int enb_agent_mac_destroy_sf_trigger(Protocol__ProgranMessage *msg) { free(msg->sf_trigger_msg->header); for (i = 0; i < msg->sf_trigger_msg->n_dl_info; i++) { free(msg->sf_trigger_msg->dl_info[i]->harq_status); + free(msg->sf_trigger_msg->dl_info[i]); } free(msg->sf_trigger_msg->dl_info); for (i = 0; i < msg->sf_trigger_msg->n_ul_info; i++) { - free(msg->sf_trigger_msg->ul_info[i]->reception_status); + free(msg->sf_trigger_msg->ul_info[i]->ul_reception); + free(msg->sf_trigger_msg->ul_info[i]); } free(msg->sf_trigger_msg->ul_info); free(msg->sf_trigger_msg); @@ -1143,6 +1145,8 @@ int enb_agent_mac_destroy_dl_config(Protocol__ProgranMessage *msg) { free(msg->dl_mac_config_msg->ofdm_sym[i]); } free(msg->dl_mac_config_msg->ofdm_sym); + free(msg->dl_mac_config_msg); + free(msg); return 0; From f47f596a1ff3ddf4fad0c45873b1683bd4fc96be Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 26 Feb 2016 13:31:13 +0000 Subject: [PATCH 127/413] Added support for liblfds7 --- cmake_targets/CMakeLists.txt | 26 +- .../liblfds700/build/gcc_and_gnumake/Makefile | 168 +++ .../build/gcc_kbuild_and_gnumake/Kbuild | 76 ++ .../build/gcc_kbuild_and_gnumake/Makefile | 14 + .../liblfds700.def | 69 ++ .../sdk_for_windows_7_and_gnumake/makefile | 114 ++ .../liblfds700.def | 69 ++ .../liblfds700.sln | 46 + .../liblfds700.vcxproj | 705 +++++++++++ .../liblfds700.vcxproj.filters | 279 +++++ .../liblfds700.vcxproj.user | 4 + .../driver_entry.c | 1 + .../liblfds700.def | 69 ++ .../liblfds700.sln | 46 + .../liblfds700.vcxproj | 733 ++++++++++++ .../liblfds700.vcxproj.filters | 279 +++++ .../liblfds700.vcxproj.user | 4 + .../driver_entry.c | 1 + .../liblfds700.def | 69 ++ .../liblfds700.sln | 59 + .../liblfds700.vcxproj | 1054 +++++++++++++++++ .../liblfds700.vcxproj.filters | 279 +++++ .../liblfds700.vcxproj.user | 4 + .../liblfds700/build/wdk_7.1/dirs | 3 + ..._entry_renamed_to_avoid_compiler_warning.c | 23 + .../liblfds700/build/wdk_7.1/liblfds700.def | 69 ++ .../readme_before_win_kernel_build.txt | 32 + ...me_before_win_kernel_dynamic_lib_build.bat | 22 + ...nme_before_win_kernel_static_lib_build.bat | 21 + .../liblfds700/build/wdk_7.1/sources.dynamic | 62 + .../liblfds700/build/wdk_7.1/sources.static | 60 + .../liblfds7.0.0/liblfds700/inc/liblfds700.h | 31 + .../lfds700_btree_addonly_unbalanced.h | 113 ++ .../inc/liblfds700/lfds700_freelist.h | 54 + .../inc/liblfds700/lfds700_hash_addonly.h | 127 ++ ...fds700_list_addonly_ordered_singlylinked.h | 85 ++ ...s700_list_addonly_singlylinked_unordered.h | 90 ++ .../liblfds700/inc/liblfds700/lfds700_misc.h | 192 +++ ...ds700_porting_abstraction_layer_compiler.h | 478 ++++++++ ...rting_abstraction_layer_operating_system.h | 133 +++ ...s700_porting_abstraction_layer_processor.h | 544 +++++++++ .../liblfds700/inc/liblfds700/lfds700_queue.h | 60 + ...ue_bounded_singleconsumer_singleproducer.h | 59 + .../inc/liblfds700/lfds700_ringbuffer.h | 69 ++ .../liblfds700/inc/liblfds700/lfds700_stack.h | 55 + ...lfds700_btree_addonly_unbalanced_cleanup.c | 117 ++ .../lfds700_btree_addonly_unbalanced_get.c | 467 ++++++++ .../lfds700_btree_addonly_unbalanced_init.c | 32 + .../lfds700_btree_addonly_unbalanced_insert.c | 156 +++ ...fds700_btree_addonly_unbalanced_internal.h | 23 + .../lfds700_btree_addonly_unbalanced_query.c | 121 ++ .../lfds700_freelist_cleanup.c | 36 + .../lfds700_freelist/lfds700_freelist_init.c | 27 + .../lfds700_freelist_internal.h | 5 + .../lfds700_freelist/lfds700_freelist_pop.c | 52 + .../lfds700_freelist/lfds700_freelist_push.c | 42 + .../lfds700_freelist/lfds700_freelist_query.c | 123 ++ .../lfds700_hash_addonly_cleanup.c | 61 + .../lfds700_hash_addonly_get.c | 37 + .../lfds700_hash_addonly_init.c | 54 + .../lfds700_hash_addonly_insert.c | 62 + .../lfds700_hash_addonly_internal.h | 5 + .../lfds700_hash_addonly_iterate.c | 58 + .../lfds700_hash_addonly_query.c | 112 ++ ...ist_addonly_ordered_singlylinked_cleanup.c | 37 + ...00_list_addonly_ordered_singlylinked_get.c | 29 + ...0_list_addonly_ordered_singlylinked_init.c | 37 + ...list_addonly_ordered_singlylinked_insert.c | 134 +++ ...st_addonly_ordered_singlylinked_internal.h | 5 + ..._list_addonly_ordered_singlylinked_query.c | 121 ++ ...t_addonly_singlylinked_unordered_cleanup.c | 37 + ..._list_addonly_singlylinked_unordered_get.c | 29 + ...list_addonly_singlylinked_unordered_init.c | 35 + ...st_addonly_singlylinked_unordered_insert.c | 193 +++ ..._addonly_singlylinked_unordered_internal.h | 5 + ...ist_addonly_singlylinked_unordered_query.c | 121 ++ .../src/lfds700_misc/lfds700_misc_cleanup.c | 15 + .../src/lfds700_misc/lfds700_misc_globals.c | 11 + .../src/lfds700_misc/lfds700_misc_init.c | 53 + .../src/lfds700_misc/lfds700_misc_internal.h | 10 + .../src/lfds700_misc/lfds700_misc_prng.c | 144 +++ .../src/lfds700_misc/lfds700_misc_query.c | 48 + .../src/lfds700_queue/lfds700_queue_cleanup.c | 48 + .../src/lfds700_queue/lfds700_queue_dequeue.c | 109 ++ .../src/lfds700_queue/lfds700_queue_enqueue.c | 74 ++ .../src/lfds700_queue/lfds700_queue_init.c | 43 + .../lfds700_queue/lfds700_queue_internal.h | 14 + .../src/lfds700_queue/lfds700_queue_query.c | 126 ++ ...ed_singleconsumer_singleproducer_cleanup.c | 30 + ...ed_singleconsumer_singleproducer_dequeue.c | 42 + ...ed_singleconsumer_singleproducer_enqueue.c | 39 + ...unded_singleconsumer_singleproducer_init.c | 63 + ...d_singleconsumer_singleproducer_internal.h | 5 + ...nded_singleconsumer_singleproducer_query.c | 70 ++ .../lfds700_ringbuffer_cleanup.c | 86 ++ .../lfds700_ringbuffer_init.c | 51 + .../lfds700_ringbuffer_internal.h | 5 + .../lfds700_ringbuffer_query.c | 72 ++ .../lfds700_ringbuffer_read.c | 44 + .../lfds700_ringbuffer_write.c | 78 ++ .../src/lfds700_stack/lfds700_stack_cleanup.c | 36 + .../src/lfds700_stack/lfds700_stack_init.c | 27 + .../lfds700_stack/lfds700_stack_internal.h | 5 + .../src/lfds700_stack/lfds700_stack_pop.c | 52 + .../src/lfds700_stack/lfds700_stack_push.c | 42 + .../src/lfds700_stack/lfds700_stack_query.c | 123 ++ .../liblfds700/src/liblfds700_internal.h | 93 ++ .../test/build/gcc_and_gnumake/Makefile | 129 ++ .../sdk_for_windows_7_and_gnumake/makefile | 106 ++ .../visual_studio_professional_2012/test.sln | 67 ++ .../test.vcxproj | 554 +++++++++ .../test.vcxproj.filters | 216 ++++ .../test.vcxproj.user | 4 + .../LFDS/liblfds7.0.0/test/src/internal.h | 157 +++ .../UTIL/LFDS/liblfds7.0.0/test/src/main.c | 135 +++ .../UTIL/LFDS/liblfds7.0.0/test/src/misc.c | 191 +++ .../test_lfds700_btree_addonly_unbalanced.c | 32 + ...ds700_btree_addonly_unbalanced_alignment.c | 64 + ...tree_addonly_unbalanced_random_adds_fail.c | 319 +++++ ...nbalanced_random_adds_fail_and_overwrite.c | 140 +++ ...addonly_unbalanced_random_adds_overwrite.c | 322 +++++ .../test/src/test_lfds700_freelist.c | 33 + .../src/test_lfds700_freelist_alignment.c | 43 + .../test/src/test_lfds700_freelist_popping.c | 205 ++++ ...est_lfds700_freelist_popping_and_pushing.c | 319 +++++ .../test/src/test_lfds700_freelist_pushing.c | 246 ++++ ...ds700_freelist_rapid_popping_and_pushing.c | 216 ++++ .../test/src/test_lfds700_hash_addonly.c | 33 + .../src/test_lfds700_hash_addonly_alignment.c | 40 + .../src/test_lfds700_hash_addonly_iterate.c | 224 ++++ ...st_lfds700_hash_addonly_random_adds_fail.c | 314 +++++ ...h_addonly_random_adds_fail_and_overwrite.c | 137 +++ ...ds700_hash_addonly_random_adds_overwrite.c | 388 ++++++ ...fds700_list_addonly_ordered_singlylinked.c | 31 + ...t_addonly_ordered_singlylinked_alignment.c | 58 + ...addonly_ordered_singlylinked_new_ordered.c | 278 +++++ ...red_singlylinked_new_ordered_with_cursor.c | 366 ++++++ ...s700_list_addonly_singlylinked_unordered.c | 32 + ...addonly_singlylinked_unordered_alignment.c | 61 + ...addonly_singlylinked_unordered_new_after.c | 254 ++++ ...t_addonly_singlylinked_unordered_new_end.c | 229 ++++ ...addonly_singlylinked_unordered_new_start.c | 229 ++++ ...lfds700_porting_abstraction_layer_atomic.c | 33 + ...700_porting_abstraction_layer_atomic_cas.c | 176 +++ ...00_porting_abstraction_layer_atomic_dcas.c | 177 +++ ...orting_abstraction_layer_atomic_exchange.c | 333 ++++++ .../test/src/test_lfds700_queue.c | 35 + .../test/src/test_lfds700_queue_alignment.c | 55 + ...ue_bounded_singleconsumer_singleproducer.c | 25 + ..._singleconsumer_singleproducer_dequeuing.c | 61 + ..._singleconsumer_singleproducer_enqueuing.c | 59 + ...r_singleproducer_enqueuing_and_dequeuing.c | 260 ++++ .../test/src/test_lfds700_queue_dequeuing.c | 215 ++++ .../test/src/test_lfds700_queue_enqueuing.c | 239 ++++ ...st_lfds700_queue_enqueuing_and_dequeuing.c | 250 ++++ ..._queue_enqueuing_and_dequeuing_with_free.c | 241 ++++ ...uing_with_malloc_and_dequeuing_with_free.c | 208 ++++ ...s700_queue_rapid_enqueuing_and_dequeuing.c | 264 +++++ .../test/src/test_lfds700_ringbuffer.c | 31 + .../src/test_lfds700_ringbuffer_reading.c | 217 ++++ ...t_lfds700_ringbuffer_reading_and_writing.c | 261 ++++ .../src/test_lfds700_ringbuffer_writing.c | 272 +++++ .../test/src/test_lfds700_stack.c | 33 + .../test/src/test_lfds700_stack_alignment.c | 43 + .../test/src/test_lfds700_stack_popping.c | 202 ++++ .../test_lfds700_stack_popping_and_pushing.c | 316 +++++ .../test/src/test_lfds700_stack_pushing.c | 251 ++++ ..._lfds700_stack_rapid_popping_and_pushing.c | 217 ++++ ...g_abstraction_layer_get_logical_core_ids.c | 245 ++++ ...rting_abstraction_layer_operating_system.h | 82 ++ ...t_porting_abstraction_layer_thread_start.c | 336 ++++++ ...st_porting_abstraction_layer_thread_wait.c | 69 ++ .../LFDS/liblfds7.0.0/test/src/util_cmdline.c | 184 +++ .../LFDS/liblfds7.0.0/test/src/util_cmdline.h | 69 ++ .../test/src/util_memory_helpers.c | 75 ++ .../test/src/util_memory_helpers.h | 5 + .../test/src/util_thread_starter.c | 151 +++ .../test/src/util_thread_starter.h | 41 + 178 files changed, 22480 insertions(+), 4 deletions(-) create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/gcc_and_gnumake/Makefile create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/gcc_kbuild_and_gnumake/Kbuild create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/gcc_kbuild_and_gnumake/Makefile create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/sdk_for_windows_7_and_gnumake/liblfds700.def create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/sdk_for_windows_7_and_gnumake/makefile create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.def create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.sln create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.vcxproj create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.vcxproj.filters create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.vcxproj.user create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/driver_entry.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.def create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.sln create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.vcxproj create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.vcxproj.filters create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.vcxproj.user create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/driver_entry.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.def create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.sln create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.vcxproj create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.vcxproj.filters create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.vcxproj.user create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/dirs create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/driver_entry_renamed_to_avoid_compiler_warning.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/liblfds700.def create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/readme_before_win_kernel_build.txt create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/runme_before_win_kernel_dynamic_lib_build.bat create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/runme_before_win_kernel_static_lib_build.bat create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/sources.dynamic create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/sources.static create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_btree_addonly_unbalanced.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_freelist.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_hash_addonly.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_list_addonly_ordered_singlylinked.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_list_addonly_singlylinked_unordered.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_misc.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_porting_abstraction_layer_compiler.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_porting_abstraction_layer_operating_system.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_porting_abstraction_layer_processor.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_queue.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_queue_bounded_singleconsumer_singleproducer.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_ringbuffer.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_stack.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_cleanup.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_get.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_init.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_insert.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_internal.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_query.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_cleanup.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_init.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_internal.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_pop.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_push.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_query.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_cleanup.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_get.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_init.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_insert.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_internal.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_iterate.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_query.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_cleanup.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_get.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_init.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_insert.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_internal.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_query.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_cleanup.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_get.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_init.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_insert.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_internal.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_query.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_cleanup.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_globals.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_init.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_internal.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_prng.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_query.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_cleanup.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_dequeue.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_enqueue.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_init.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_internal.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_query.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_cleanup.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_dequeue.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_enqueue.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_init.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_internal.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_query.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_cleanup.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_init.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_internal.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_query.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_read.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_write.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_cleanup.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_init.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_internal.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_pop.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_push.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_query.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/liblfds700_internal.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/build/gcc_and_gnumake/Makefile create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/build/sdk_for_windows_7_and_gnumake/makefile create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.sln create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.vcxproj create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.vcxproj.filters create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.vcxproj.user create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/internal.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/main.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/misc.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_alignment.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_random_adds_fail.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_random_adds_fail_and_overwrite.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_random_adds_overwrite.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_alignment.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_popping.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_popping_and_pushing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_pushing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_rapid_popping_and_pushing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_alignment.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_iterate.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_random_adds_fail.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_random_adds_fail_and_overwrite.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_random_adds_overwrite.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked_alignment.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked_new_ordered.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked_new_ordered_with_cursor.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_alignment.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_new_after.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_new_end.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_new_start.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic_cas.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic_dcas.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic_exchange.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_alignment.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer_dequeuing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing_and_dequeuing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_dequeuing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing_and_dequeuing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing_and_dequeuing_with_free.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing_with_malloc_and_dequeuing_with_free.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_rapid_enqueuing_and_dequeuing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer_reading.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer_reading_and_writing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer_writing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_alignment.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_popping.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_popping_and_pushing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_pushing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_rapid_popping_and_pushing.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_get_logical_core_ids.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_operating_system.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_thread_start.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_thread_wait.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_cmdline.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_cmdline.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_memory_helpers.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_memory_helpers.h create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_thread_starter.c create mode 100644 openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_thread_starter.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 85a6f35339..e4b027958d 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -757,6 +757,7 @@ include_directories("${OPENAIR_DIR}/targets/ARCH/EXMIMO/DEFS") include_directories("${OPENAIR2_DIR}/ENB_APP") 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") include_directories("${OPENAIR2_DIR}/UTIL/MEM") include_directories("${OPENAIR2_DIR}/UTIL/LISTS") include_directories("${OPENAIR2_DIR}/UTIL/FIFO") @@ -1475,6 +1476,23 @@ add_library(LFDS ${lfds}/lfds611_abstraction/lfds611_abstraction_malloc.c ) +set(lfds7 ${OPENAIR2_DIR}/UTIL/LFDS/liblfds7.0.0/liblfds700/src/) +file(GLOB lfds7_queue ${lfds7}/lfds700_queue/*.c) +file(GLOB lfds7_ring ${lfds7}/lfds700_ringbuffer/*.c) +file(GLOB lfds7_qbss ${lfds7}/lfds700_queue_bounded_singleconsumer_singleproducer/*.c) +file(GLOB lfds7_stack ${lfds7}/lfds700_stack/*.c) +file(GLOB lfds7_freelist ${lfds7}/lfds700_freelist/*.c) +file(GLOB lfds7_btree ${lfds7}/lfds700_btree_addonly_unbalanced/*.c) +file(GLOB lfds7_hash ${lfds7}/lfds700_hash_addonly/*.c) +file(GLOB lfds7_ordered_list ${lfds7}/lfds700_list_addonly_ordered_singlylinked/*.c) +file(GLOB lfds7_unordered_list ${lfds7}/lfds700_list_addonly_singlylinked_unordered/*.c) +file(GLOB lfds7_misc ${lfds7}/lfds700_misc/*.c) + +include_directories(${lfds7}) +add_library(LFDS7 + ${lfds7_queue} ${lfds7_ring} ${lfds7_qbss} ${lfds7_stack} ${lfds7_freelist} ${lfds7_btree} ${lfds7_hash} ${lfds7_ordered_list} ${lfds7_unordered_list} ${lfds7_misc} +) + # Simulation library ########################## add_library(SIMU @@ -1604,7 +1622,7 @@ add_executable(lte-softmodem target_link_libraries (lte-softmodem -Wl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} + RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} LFDS7 -Wl,--end-group ) @@ -1639,7 +1657,7 @@ add_executable(lte-softmodem-nos1 ) target_link_libraries (lte-softmodem-nos1 -Wl,--start-group - RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} + RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} LFDS7 -Wl,--end-group ) target_link_libraries (lte-softmodem-nos1 ${LIBXML2_LIBRARIES}) @@ -1775,7 +1793,7 @@ add_executable(oaisim_nos1 target_include_directories(oaisim_nos1 PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim_nos1 -Wl,--start-group - RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} + RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} LFDS7 -Wl,--end-group ) target_link_libraries (oaisim_nos1 ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) @@ -1796,7 +1814,7 @@ foreach(myExe dlsim ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim syn ${XFORMS_SOURCE} ) target_link_libraries (${myExe} - -Wl,--start-group SIMU UTIL SCHED_LIB PHY LFDS ${ITTI_LIB} -Wl,--end-group + -Wl,--start-group SIMU UTIL SCHED_LIB PHY LFDS ${ITTI_LIB} LFDS7 -Wl,--end-group pthread m rt ${CONFIG_LIBRARIES} ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ) endforeach(myExe) diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/gcc_and_gnumake/Makefile b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/gcc_and_gnumake/Makefile new file mode 100644 index 0000000000..27e4d91df3 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/gcc_and_gnumake/Makefile @@ -0,0 +1,168 @@ +##### paths ##### +BINDIR := ../../bin +INCDIR := ../../inc +OBJDIR := ../../obj +SRCDIR := ../../src + +##### misc ##### +QUIETLY := 1>/dev/null 2>/dev/null +VERSION_NUMBER := 1 +MINOR_NUMBER := 0 +RELEASE_NUMBER := 0 + +##### sources, objects and libraries ##### +BINNAME := liblfds700 +ARFILENAME := $(BINNAME).a +ARPATHNAME := $(BINDIR)/$(ARFILENAME) +SOBASENAME := $(BINNAME).so +SONAME := $(SOBASENAME).$(VERSION_NUMBER) +SOFILENAME := $(SONAME).$(MINOR_NUMBER).$(RELEASE_NUMBER) +SOPATHNAME := $(BINDIR)/$(SOFILENAME) +INCNAME := $(INCDIR)/$(BINNAME).h +SRCDIRS := lfds700_btree_addonly_unbalanced lfds700_freelist lfds700_hash_addonly lfds700_list_addonly_ordered_singlylinked lfds700_list_addonly_singlylinked_unordered lfds700_misc lfds700_queue lfds700_queue_bounded_singleconsumer_singleproducer lfds700_ringbuffer lfds700_stack +SOURCES := lfds700_hash_addonly_cleanup.c lfds700_hash_addonly_get.c lfds700_hash_addonly_init.c lfds700_hash_addonly_insert.c lfds700_hash_addonly_iterate.c lfds700_hash_addonly_query.c \ + lfds700_list_addonly_ordered_singlylinked_cleanup.c lfds700_list_addonly_ordered_singlylinked_get.c lfds700_list_addonly_ordered_singlylinked_init.c lfds700_list_addonly_ordered_singlylinked_insert.c lfds700_list_addonly_ordered_singlylinked_query.c \ + lfds700_list_addonly_singlylinked_unordered_cleanup.c lfds700_list_addonly_singlylinked_unordered_get.c lfds700_list_addonly_singlylinked_unordered_init.c lfds700_list_addonly_singlylinked_unordered_insert.c lfds700_list_addonly_singlylinked_unordered_query.c \ + lfds700_btree_addonly_unbalanced_cleanup.c lfds700_btree_addonly_unbalanced_get.c lfds700_btree_addonly_unbalanced_init.c lfds700_btree_addonly_unbalanced_insert.c lfds700_btree_addonly_unbalanced_query.c \ + lfds700_freelist_cleanup.c lfds700_freelist_init.c lfds700_freelist_pop.c lfds700_freelist_push.c lfds700_freelist_query.c \ + lfds700_misc_cleanup.c lfds700_misc_globals.c lfds700_misc_init.c lfds700_misc_prng.c lfds700_misc_query.c \ + lfds700_queue_cleanup.c lfds700_queue_dequeue.c lfds700_queue_enqueue.c lfds700_queue_init.c lfds700_queue_query.c \ + lfds700_queue_bounded_singleconsumer_singleproducer_cleanup.c lfds700_queue_bounded_singleconsumer_singleproducer_dequeue.c lfds700_queue_bounded_singleconsumer_singleproducer_enqueue.c lfds700_queue_bounded_singleconsumer_singleproducer_init.c lfds700_queue_bounded_singleconsumer_singleproducer_query.c \ + lfds700_ringbuffer_cleanup.c lfds700_ringbuffer_init.c lfds700_ringbuffer_query.c lfds700_ringbuffer_read.c lfds700_ringbuffer_write.c \ + lfds700_stack_cleanup.c lfds700_stack_init.c lfds700_stack_pop.c lfds700_stack_push.c lfds700_stack_query.c +OBJECTS := $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(SOURCES))) +SYSLIBS := + +##### default paths fix up ##### +CPATH := $(subst : ,:,$(SRCDIR):$(INCDIR)) + +##### tools ##### +MAKE := make +MFLAGS := + +DG := gcc +DGFLAGS := -MM -std=gnu89 + +CC := gcc +CFBASE := -c -fno-strict-aliasing -std=gnu89 -Wall -Werror -Wno-unknown-pragmas -Wno-unused-but-set-variable -Wno-unused-variable +CFCOV := -O0 -ggdb -DCOVERAGE -fprofile-arcs -ftest-coverage +CFDBG := -O0 -ggdb -D_DEBUG +CFPROF := -O0 -ggdb -DPROF -pg +CFREL := -O2 -DNDEBUG -finline-functions +CFTSAN := -O0 -ggdb -DTSAN -fsanitize=thread -fPIC +CFBARE := -ffreestanding -nodefaultlibs -nostdinc -nostdlib + +AR := ar +AFLAGS := -rcs + +LD := gcc +LFBASE := -pthread -shared -std=gnu89 -Wl,-soname,$(SONAME) -o $(SOPATHNAME) -Wall -Werror +LFCOV := -O0 -fprofile-arcs -ftest-coverage +LFDBG := -O0 -ggdb +LFPROF := -O0 -pg +LFREL := -O2 -s -finline-functions +LFTSAN := -O0 -fsanitize=thread -fPIC +LFBARE := -ffreestanding -nodefaultlibs -nostdinc -nostdlib + +##### CPU variants ##### +GCCARCH := native +CFBASE += -march=$(GCCARCH) + +##### build variants ##### +ifeq ($(findstring so,$(MAKECMDGOALS)),so) + CFBASE += -fPIC +endif + +CFLAGS += $(CFBASE) +LFLAGS += $(LFBASE) + +ifeq ($(MAKECMDGOALS),) + CFLAGS += $(CFDBG) + LFLAGS += $(LFDBG) +endif + +ifeq ($(findstring cov,$(MAKECMDGOALS)),cov) + CFLAGS += $(CFCOV) + LFLAGS += $(LFCOV) + SYSLIBS += -lgcov +endif + +ifeq ($(findstring dbg,$(MAKECMDGOALS)),dbg) + CFLAGS += $(CFDBG) + LFLAGS += $(LFDBG) +endif + +ifeq ($(findstring prof,$(MAKECMDGOALS)),prof) + CFLAGS += $(CFPROF) + LFLAGS += $(LFPROF) +endif + +ifeq ($(findstring rel,$(MAKECMDGOALS)),rel) + CFLAGS += $(CFREL) + LFLAGS += $(LFREL) +endif + +ifeq ($(findstring tsan,$(MAKECMDGOALS)),tsan) + CFLAGS += $(CFTSAN) + LFLAGS += $(LFTSAN) +endif + +ifeq ($(findstring b_,$(MAKECMDGOALS)),b_) + CFLAGS += $(CFBARE) + LFLAGS += $(CFBARE) +endif + +##### search paths ##### +vpath %.c $(patsubst %,$(SRCDIR)/%:,$(SRCDIRS)) + +##### implicit rules ##### +$(OBJDIR)/%.o : %.c + $(DG) $(DGFLAGS) $< >$(OBJDIR)/$*.d + $(CC) $(CFLAGS) -o $@ $< + +##### explicit rules ##### +$(ARPATHNAME) : $(OBJECTS) + $(AR) $(AFLAGS) $(ARPATHNAME) $(OBJECTS) + +$(SOPATHNAME) : $(OBJECTS) + $(LD) $(LFLAGS) $(OBJECTS) -o $(SOPATHNAME) + @ln -fs $(SOFILENAME) $(BINDIR)/$(SONAME) + @ln -fs $(SOFILENAME) $(BINDIR)/$(SOBASENAME) + +##### phony ##### +.PHONY : clean bare_ar_cov bare_ar_dbg bare_ar_prof bare_ar_rel bare_ar_tsan bare_so_cov bare_so_dbg bare_so_prof bare_so_rel bare_so_tsan hosted_ar_cov hosted_ar_dbg hosted_ar_prof hosted_ar_rel hosted_ar_tsan hosted_so_cov hosted_so_dbg hosted_so_prof hosted_so_rel hosted_so_tsan + +clean : + @rm -f $(BINDIR)/* $(OBJDIR)/* + +bare_ar_cov : $(ARPATHNAME) # bare, archive (.a), coverage +bare_ar_dbg : $(ARPATHNAME) # bare, archive (.a), debug +bare_ar_prof : $(ARPATHNAME) # bare, archive (.a), profiling +bare_ar_rel : $(ARPATHNAME) # bare, archive (.a), release +bare_ar_tsan : $(ARPATHNAME) # bare, archive (.a), thread sanitizer + +bare_so_cov : $(SOPATHNAME) # bare, shared (.so), coverage +bare_so_dbg : $(SOPATHNAME) # bare, shared (.so), debug +bare_so_prof : $(SOPATHNAME) # bare, shared (.so), profiling +bare_so_rel : $(SOPATHNAME) # bare, shared (.so), release +bare_so_tsan : $(SOPATHNAME) # bare, shared (.so), thread sanitizer + +hosted_ar_cov : $(ARPATHNAME) # hosted implementation, archive (.a), coverage +hosted_ar_dbg : $(ARPATHNAME) # hosted implementation, archive (.a), debug +hosted_ar_prof : $(ARPATHNAME) # hosted implementation, archive (.a), profiling +hosted_ar_rel : $(ARPATHNAME) # hosted implementation, archive (.a), release +hosted_ar_tsan : $(ARPATHNAME) # hosted implementation, archive (.a), thread sanitizer + +hosted_so_cov : $(SOPATHNAME) # hosted implementation, shared (.so), coverage +hosted_so_dbg : $(SOPATHNAME) # hosted implementation, shared (.so), debug +hosted_so_prof : $(SOPATHNAME) # hosted implementation, shared (.so), profiling +hosted_so_rel : $(SOPATHNAME) # hosted implementation, shared (.so), release +hosted_so_tsan : $(SOPATHNAME) # hosted implementation, shared (.so), thread sanitizer + +##### dependencies ##### +-include $(DEPENDS) + +##### notes ##### +# TRD : we use -std=gnu89 for C++ style comments +# hosted implementation differs from bare simply in that ends up being included + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/gcc_kbuild_and_gnumake/Kbuild b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/gcc_kbuild_and_gnumake/Kbuild new file mode 100644 index 0000000000..1ae6b36240 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/gcc_kbuild_and_gnumake/Kbuild @@ -0,0 +1,76 @@ +lib-y := + +lib-y += ../../src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_cleanup.o +lib-y += ../../src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_get.o +lib-y += ../../src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_init.o +lib-y += ../../src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_insert.o +lib-y += ../../src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_query.o + +lib-y += ../../src/lfds700_freelist/lfds700_freelist_cleanup.o +lib-y += ../../src/lfds700_freelist/lfds700_freelist_init.o +lib-y += ../../src/lfds700_freelist/lfds700_freelist_pop.o +lib-y += ../../src/lfds700_freelist/lfds700_freelist_push.o +lib-y += ../../src/lfds700_freelist/lfds700_freelist_query.o + +lib-y += ../../src/lfds700_hash_addonly/lfds700_hash_addonly_cleanup.o +lib-y += ../../src/lfds700_hash_addonly/lfds700_hash_addonly_get.o +lib-y += ../../src/lfds700_hash_addonly/lfds700_hash_addonly_init.o +lib-y += ../../src/lfds700_hash_addonly/lfds700_hash_addonly_insert.o +lib-y += ../../src/lfds700_hash_addonly/lfds700_hash_addonly_iterate.o +lib-y += ../../src/lfds700_hash_addonly/lfds700_hash_addonly_query.o + +lib-y += ../../src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_cleanup.o +lib-y += ../../src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_get.o +lib-y += ../../src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_init.o +lib-y += ../../src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_insert.o +lib-y += ../../src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_query.o + +lib-y += ../../src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_cleanup.o +lib-y += ../../src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_get.o +lib-y += ../../src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_init.o +lib-y += ../../src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_insert.o +lib-y += ../../src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_query.o + +lib-y += ../../src/lfds700_misc/lfds700_misc_cleanup.o +lib-y += ../../src/lfds700_misc/lfds700_misc_globals.o +lib-y += ../../src/lfds700_misc/lfds700_misc_init.o +lib-y += ../../src/lfds700_misc/lfds700_misc_prng.o +lib-y += ../../src/lfds700_misc/lfds700_misc_query.o + +lib-y += ../../src/lfds700_queue/lfds700_queue_cleanup.o +lib-y += ../../src/lfds700_queue/lfds700_queue_dequeue.o +lib-y += ../../src/lfds700_queue/lfds700_queue_enqueue.o +lib-y += ../../src/lfds700_queue/lfds700_queue_init.o +lib-y += ../../src/lfds700_queue/lfds700_queue_query.o + +lib-y += ../../src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_cleanup.o +lib-y += ../../src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_dequeue.o +lib-y += ../../src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_enqueue.o +lib-y += ../../src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_init.o +lib-y += ../../src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_query.o + +lib-y += ../../src/lfds700_ringbuffer/lfds700_ringbuffer_cleanup.o +lib-y += ../../src/lfds700_ringbuffer/lfds700_ringbuffer_init.o +lib-y += ../../src/lfds700_ringbuffer/lfds700_ringbuffer_query.o +lib-y += ../../src/lfds700_ringbuffer/lfds700_ringbuffer_read.o +lib-y += ../../src/lfds700_ringbuffer/lfds700_ringbuffer_write.o + +lib-y += ../../src/lfds700_stack/lfds700_stack_cleanup.o +lib-y += ../../src/lfds700_stack/lfds700_stack_init.o +lib-y += ../../src/lfds700_stack/lfds700_stack_pop.o +lib-y += ../../src/lfds700_stack/lfds700_stack_push.o +lib-y += ../../src/lfds700_stack/lfds700_stack_query.o + +libs-y := ../../bin/ + +ccflags-y := -I$(src)/../../inc +ccflags-y += -I$(src)/../../inc/liblfds700 +ccflags-y += -D_KERNEL_MODE +ccflags-y += -fno-strict-aliasing +ccflags-y += -std=gnu89 +ccflags-y += -Wall +ccflags-y += -Werror +ccflags-y += -Wno-unknown-pragmas +ccflags-y += -Wno-unused-but-set-variable +ccflags-y += -Wno-unused-variable + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/gcc_kbuild_and_gnumake/Makefile b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/gcc_kbuild_and_gnumake/Makefile new file mode 100644 index 0000000000..d6de5f4b5d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/gcc_kbuild_and_gnumake/Makefile @@ -0,0 +1,14 @@ +default: + $(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) + +clean: + $(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) clean + find ../../src/ -name "*.o" -type f -delete + +help: + $(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) help + +modules: + $(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) modules + + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/sdk_for_windows_7_and_gnumake/liblfds700.def b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/sdk_for_windows_7_and_gnumake/liblfds700.def new file mode 100644 index 0000000000..583ce35dbd --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/sdk_for_windows_7_and_gnumake/liblfds700.def @@ -0,0 +1,69 @@ +EXPORTS + +lfds700_btree_au_init_valid_on_current_logical_core = lfds700_btree_au_init_valid_on_current_logical_core +lfds700_btree_au_cleanup = lfds700_btree_au_cleanup +lfds700_btree_au_insert = lfds700_btree_au_insert +lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position = lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position +lfds700_btree_au_get_by_absolute_position = lfds700_btree_au_get_by_absolute_position +lfds700_btree_au_get_by_relative_position = lfds700_btree_au_get_by_relative_position +lfds700_btree_au_get_by_key = lfds700_btree_au_get_by_key +lfds700_btree_au_query = lfds700_btree_au_query + +lfds700_freelist_init_valid_on_current_logical_core = lfds700_freelist_init_valid_on_current_logical_core +lfds700_freelist_cleanup = lfds700_freelist_cleanup +lfds700_freelist_push = lfds700_freelist_push +lfds700_freelist_pop = lfds700_freelist_pop +lfds700_freelist_query = lfds700_freelist_query + +lfds700_hash_a_init_valid_on_current_logical_core = lfds700_hash_a_init_valid_on_current_logical_core +lfds700_hash_a_cleanup = lfds700_hash_a_cleanup +lfds700_hash_a_insert = lfds700_hash_a_insert +lfds700_hash_a_get_by_key = lfds700_hash_a_get_by_key +lfds700_hash_a_iterate_init = lfds700_hash_a_iterate_init +lfds700_hash_a_iterate = lfds700_hash_a_iterate +lfds700_hash_a_query = lfds700_hash_a_query + +lfds700_list_aos_init_valid_on_current_logical_core = lfds700_list_aos_init_valid_on_current_logical_core +lfds700_list_aos_cleanup = lfds700_list_aos_cleanup +lfds700_list_aos_insert = lfds700_list_aos_insert +lfds700_list_aos_get_by_key = lfds700_list_aos_get_by_key +lfds700_list_aos_query = lfds700_list_aos_query + +lfds700_list_asu_init_valid_on_current_logical_core = lfds700_list_asu_init_valid_on_current_logical_core +lfds700_list_asu_cleanup = lfds700_list_asu_cleanup +lfds700_list_asu_insert_at_position = lfds700_list_asu_insert_at_position +lfds700_list_asu_insert_at_start = lfds700_list_asu_insert_at_start +lfds700_list_asu_insert_at_end = lfds700_list_asu_insert_at_end +lfds700_list_asu_insert_after_element = lfds700_list_asu_insert_after_element +lfds700_list_asu_get_by_key = lfds700_list_asu_get_by_key +lfds700_list_asu_query = lfds700_list_asu_query + +lfds700_misc_library_init_valid_on_current_logical_core = lfds700_misc_library_init_valid_on_current_logical_core +lfds700_misc_library_cleanup = lfds700_misc_library_cleanup +lfds700_misc_prng_init = lfds700_misc_prng_init +lfds700_misc_query = lfds700_misc_query + +lfds700_queue_init_valid_on_current_logical_core = lfds700_queue_init_valid_on_current_logical_core +lfds700_queue_cleanup = lfds700_queue_cleanup +lfds700_queue_enqueue = lfds700_queue_enqueue +lfds700_queue_dequeue = lfds700_queue_dequeue +lfds700_queue_query = lfds700_queue_query + +lfds700_queue_bss_init_valid_on_current_logical_core = lfds700_queue_bss_init_valid_on_current_logical_core +lfds700_queue_bss_cleanup = lfds700_queue_bss_cleanup +lfds700_queue_bss_enqueue = lfds700_queue_bss_enqueue +lfds700_queue_bss_dequeue = lfds700_queue_bss_dequeue +lfds700_queue_bss_query = lfds700_queue_bss_query + +lfds700_ringbuffer_init_valid_on_current_logical_core = lfds700_ringbuffer_init_valid_on_current_logical_core +lfds700_ringbuffer_cleanup = lfds700_ringbuffer_cleanup +lfds700_ringbuffer_read = lfds700_ringbuffer_read +lfds700_ringbuffer_write = lfds700_ringbuffer_write +lfds700_ringbuffer_query = lfds700_ringbuffer_query + +lfds700_stack_init_valid_on_current_logical_core = lfds700_stack_init_valid_on_current_logical_core +lfds700_stack_cleanup = lfds700_stack_cleanup +lfds700_stack_push = lfds700_stack_push +lfds700_stack_pop = lfds700_stack_pop +lfds700_stack_query = lfds700_stack_query + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/sdk_for_windows_7_and_gnumake/makefile b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/sdk_for_windows_7_and_gnumake/makefile new file mode 100644 index 0000000000..7b257c9277 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/sdk_for_windows_7_and_gnumake/makefile @@ -0,0 +1,114 @@ +##### paths ##### +BINDIR := ..\..\bin +INCDIR := ..\..\inc +OBJDIR := ..\..\obj +SRCDIR := ..\..\src + +##### misc ##### +QUIETLY := 1>nul 2>nul +NULL := +SPACE := $(NULL) # TRD : with a trailing space + +##### sources, objects and libraries ##### +BINNAME := liblfds700 +LIB_BINARY := $(BINDIR)\$(BINNAME).lib +DLL_BINARY := $(BINDIR)\$(BINNAME).dll +SRCDIRS := lfds700_btree_addonly_unbalanced lfds700_freelist lfds700_hash_addonly lfds700_list_addonly_ordered_singlylinked lfds700_list_addonly_singlylinked_unordered lfds700_misc lfds700_queue lfds700_queue_bounded_singleconsumer_singleproducer lfds700_ringbuffer lfds700_stack +SOURCES := lfds700_hash_addonly_cleanup.c lfds700_hash_addonly_get.c lfds700_hash_addonly_init.c lfds700_hash_addonly_insert.c lfds700_hash_addonly_iterate.c lfds700_hash_addonly_query.c \ + lfds700_list_addonly_ordered_singlylinked_cleanup.c lfds700_list_addonly_ordered_singlylinked_get.c lfds700_list_addonly_ordered_singlylinked_init.c lfds700_list_addonly_ordered_singlylinked_insert.c lfds700_list_addonly_ordered_singlylinked_query.c \ + lfds700_list_addonly_singlylinked_unordered_cleanup.c lfds700_list_addonly_singlylinked_unordered_get.c lfds700_list_addonly_singlylinked_unordered_init.c lfds700_list_addonly_singlylinked_unordered_insert.c lfds700_list_addonly_singlylinked_unordered_query.c \ + lfds700_btree_addonly_unbalanced_cleanup.c lfds700_btree_addonly_unbalanced_get.c lfds700_btree_addonly_unbalanced_init.c lfds700_btree_addonly_unbalanced_insert.c lfds700_btree_addonly_unbalanced_query.c \ + lfds700_freelist_cleanup.c lfds700_freelist_init.c lfds700_freelist_pop.c lfds700_freelist_push.c lfds700_freelist_query.c \ + lfds700_misc_cleanup.c lfds700_misc_globals.c lfds700_misc_init.c lfds700_misc_prng.c lfds700_misc_query.c \ + lfds700_queue_cleanup.c lfds700_queue_dequeue.c lfds700_queue_enqueue.c lfds700_queue_init.c lfds700_queue_query.c \ + lfds700_queue_bounded_singleconsumer_singleproducer_cleanup.c lfds700_queue_bounded_singleconsumer_singleproducer_dequeue.c lfds700_queue_bounded_singleconsumer_singleproducer_enqueue.c lfds700_queue_bounded_singleconsumer_singleproducer_init.c lfds700_queue_bounded_singleconsumer_singleproducer_query.c \ + lfds700_ringbuffer_cleanup.c lfds700_ringbuffer_init.c lfds700_ringbuffer_query.c lfds700_ringbuffer_read.c lfds700_ringbuffer_write.c \ + lfds700_stack_cleanup.c lfds700_stack_init.c lfds700_stack_pop.c lfds700_stack_push.c lfds700_stack_query.c +OBJECTS := $(patsubst %.c,$(OBJDIR)/%.obj,$(notdir $(SOURCES))) +SYSLIBS := kernel32.lib + +##### default paths fix up ##### +INCDIRS := $(patsubst %,%;,$(INCDIR)) +INCLUDE += $(subst $(SPACE),,$(INCDIRS)) + +##### tools ##### +MAKE := make +MFLAGS := + +CC := cl +CBASE := /c "-I$(SRCDIR)" "/Fd$(BINDIR)\$(BINNAME).pdb" /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN /DUNICODE /D_UNICODE /DUNICODE /nologo /W4 /wd 4068 /WX +CFREL := /DNDEBUG /Ox +CFDBG := /D_DEBUG /Gm /Od /Zi + +AR := lib +AFLAGS := /nologo /subsystem:console /verbose /wx + +LD := link +LFBASE := /def:$(BINNAME).def /dll /nodefaultlib /nologo /nxcompat /subsystem:console /wx +LFREL := /incremental:no +LFDBG := /debug "/pdb:$(BINDIR)\$(BINNAME).pdb" + +##### variants ##### +CFLAGS := $(CBASE) $(CFDBG) /MTd +ASFLAGS := $(ASBASE) $(ASDBG) +LFLAGS := $(LFBASE) $(LFDBG) +CLIB := libcmtd.lib + +ifeq ($(MAKECMDGOALS),librel) + CFLAGS := $(CBASE) $(CFREL) /MT + ASFLAGS := $(ASBASE) $(ASREL) + LFLAGS := $(LFBASE) $(LFREL) + CLIB := libcmt.lib +endif + +ifeq ($(MAKECMDGOALS),libdbg) + CFLAGS := $(CBASE) $(CFDBG) /MTd + ASFLAGS := $(ASBASE) $(ASDBG) + LFLAGS := $(LFBASE) $(LFDBG) + CLIB := libcmtd.lib +endif + +ifeq ($(MAKECMDGOALS),dllrel) + CFLAGS := $(CBASE) $(CFREL) /MD + ASFLAGS := $(ASBASE) $(ASREL) + LFLAGS := $(LFBASE) $(LFREL) + CLIB := msvcrt.lib +endif + +ifeq ($(MAKECMDGOALS),dlldbg) + CFLAGS := $(CBASE) $(CFDBG) /MDd + ASFLAGS := $(ASBASE) $(ASDBG) + LFLAGS := $(LFBASE) $(LFDBG) + CLIB := msvcrtd.lib +endif + +##### search paths ##### +vpath %.c $(patsubst %,$(SRCDIR)/%;,$(SRCDIRS)) + +##### implicit rules ##### +$(OBJDIR)/%.obj : %.c + $(CC) $(CFLAGS) "/Fo$@" $< + +##### explicit rules ##### +$(LIB_BINARY) : $(OBJECTS) + $(AR) $(AFLAGS) $(OBJECTS) /out:$(LIB_BINARY) + +$(DLL_BINARY) : $(OBJECTS) + $(LD) $(LFLAGS) $(CLIB) $(SYSLIBS) $(OBJECTS) /out:$(DLL_BINARY) + +##### phony ##### +.PHONY : clean librel libdbg dllrel dlldbg + +clean : + @erase /Q $(BINDIR)\$(BINNAME).* $(OBJDIR)\*.obj $(QUIETLY) + +dlldbg : $(DLL_BINARY) +dllrel : $(DLL_BINARY) + +libdbg : $(LIB_BINARY) +librel : $(LIB_BINARY) + +##### notes ##### +# /wd 4068 : turn off "unknown pragma" warning + + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.def b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.def new file mode 100644 index 0000000000..583ce35dbd --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.def @@ -0,0 +1,69 @@ +EXPORTS + +lfds700_btree_au_init_valid_on_current_logical_core = lfds700_btree_au_init_valid_on_current_logical_core +lfds700_btree_au_cleanup = lfds700_btree_au_cleanup +lfds700_btree_au_insert = lfds700_btree_au_insert +lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position = lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position +lfds700_btree_au_get_by_absolute_position = lfds700_btree_au_get_by_absolute_position +lfds700_btree_au_get_by_relative_position = lfds700_btree_au_get_by_relative_position +lfds700_btree_au_get_by_key = lfds700_btree_au_get_by_key +lfds700_btree_au_query = lfds700_btree_au_query + +lfds700_freelist_init_valid_on_current_logical_core = lfds700_freelist_init_valid_on_current_logical_core +lfds700_freelist_cleanup = lfds700_freelist_cleanup +lfds700_freelist_push = lfds700_freelist_push +lfds700_freelist_pop = lfds700_freelist_pop +lfds700_freelist_query = lfds700_freelist_query + +lfds700_hash_a_init_valid_on_current_logical_core = lfds700_hash_a_init_valid_on_current_logical_core +lfds700_hash_a_cleanup = lfds700_hash_a_cleanup +lfds700_hash_a_insert = lfds700_hash_a_insert +lfds700_hash_a_get_by_key = lfds700_hash_a_get_by_key +lfds700_hash_a_iterate_init = lfds700_hash_a_iterate_init +lfds700_hash_a_iterate = lfds700_hash_a_iterate +lfds700_hash_a_query = lfds700_hash_a_query + +lfds700_list_aos_init_valid_on_current_logical_core = lfds700_list_aos_init_valid_on_current_logical_core +lfds700_list_aos_cleanup = lfds700_list_aos_cleanup +lfds700_list_aos_insert = lfds700_list_aos_insert +lfds700_list_aos_get_by_key = lfds700_list_aos_get_by_key +lfds700_list_aos_query = lfds700_list_aos_query + +lfds700_list_asu_init_valid_on_current_logical_core = lfds700_list_asu_init_valid_on_current_logical_core +lfds700_list_asu_cleanup = lfds700_list_asu_cleanup +lfds700_list_asu_insert_at_position = lfds700_list_asu_insert_at_position +lfds700_list_asu_insert_at_start = lfds700_list_asu_insert_at_start +lfds700_list_asu_insert_at_end = lfds700_list_asu_insert_at_end +lfds700_list_asu_insert_after_element = lfds700_list_asu_insert_after_element +lfds700_list_asu_get_by_key = lfds700_list_asu_get_by_key +lfds700_list_asu_query = lfds700_list_asu_query + +lfds700_misc_library_init_valid_on_current_logical_core = lfds700_misc_library_init_valid_on_current_logical_core +lfds700_misc_library_cleanup = lfds700_misc_library_cleanup +lfds700_misc_prng_init = lfds700_misc_prng_init +lfds700_misc_query = lfds700_misc_query + +lfds700_queue_init_valid_on_current_logical_core = lfds700_queue_init_valid_on_current_logical_core +lfds700_queue_cleanup = lfds700_queue_cleanup +lfds700_queue_enqueue = lfds700_queue_enqueue +lfds700_queue_dequeue = lfds700_queue_dequeue +lfds700_queue_query = lfds700_queue_query + +lfds700_queue_bss_init_valid_on_current_logical_core = lfds700_queue_bss_init_valid_on_current_logical_core +lfds700_queue_bss_cleanup = lfds700_queue_bss_cleanup +lfds700_queue_bss_enqueue = lfds700_queue_bss_enqueue +lfds700_queue_bss_dequeue = lfds700_queue_bss_dequeue +lfds700_queue_bss_query = lfds700_queue_bss_query + +lfds700_ringbuffer_init_valid_on_current_logical_core = lfds700_ringbuffer_init_valid_on_current_logical_core +lfds700_ringbuffer_cleanup = lfds700_ringbuffer_cleanup +lfds700_ringbuffer_read = lfds700_ringbuffer_read +lfds700_ringbuffer_write = lfds700_ringbuffer_write +lfds700_ringbuffer_query = lfds700_ringbuffer_query + +lfds700_stack_init_valid_on_current_logical_core = lfds700_stack_init_valid_on_current_logical_core +lfds700_stack_cleanup = lfds700_stack_cleanup +lfds700_stack_push = lfds700_stack_push +lfds700_stack_pop = lfds700_stack_pop +lfds700_stack_query = lfds700_stack_query + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.sln b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.sln new file mode 100644 index 0000000000..b52c44e46f --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblfds700", "liblfds700.vcxproj", "{1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug DLL|Win32 = Debug DLL|Win32 + Debug DLL|x64 = Debug DLL|x64 + Debug LIB|Win32 = Debug LIB|Win32 + Debug LIB|x64 = Debug LIB|x64 + Release DLL|Win32 = Release DLL|Win32 + Release DLL|x64 = Release DLL|x64 + Release LIB|Win32 = Release LIB|Win32 + Release LIB|x64 = Release LIB|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|Win32.ActiveCfg = Debug DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|Win32.Build.0 = Debug DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|Win32.Deploy.0 = Debug DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|x64.ActiveCfg = Debug DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|x64.Build.0 = Debug DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|x64.Deploy.0 = Debug DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|Win32.ActiveCfg = Debug LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|Win32.Build.0 = Debug LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|Win32.Deploy.0 = Debug LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|x64.ActiveCfg = Debug LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|x64.Build.0 = Debug LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|x64.Deploy.0 = Debug LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|Win32.ActiveCfg = Release DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|Win32.Build.0 = Release DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|Win32.Deploy.0 = Release DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|x64.ActiveCfg = Release DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|x64.Build.0 = Release DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|x64.Deploy.0 = Release DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|Win32.ActiveCfg = Release LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|Win32.Build.0 = Release LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|Win32.Deploy.0 = Release LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|x64.ActiveCfg = Release LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|x64.Build.0 = Release LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|x64.Deploy.0 = Release LIB|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.vcxproj b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.vcxproj new file mode 100644 index 0000000000..3d4bf6364f --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.vcxproj @@ -0,0 +1,705 @@ + + + + + Debug DLL + Win32 + + + Debug DLL + x64 + + + Debug LIB + Win32 + + + Debug LIB + x64 + + + Release DLL + Win32 + + + Release DLL + x64 + + + Release LIB + Win32 + + + Release LIB + x64 + + + + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0} + Win32Proj + + + + StaticLibrary + true + v110 + + + DynamicLibrary + true + v110 + + + StaticLibrary + true + v110 + + + DynamicLibrary + true + v110 + + + StaticLibrary + false + v110 + true + + + DynamicLibrary + false + v110 + true + + + StaticLibrary + false + v110 + true + + + DynamicLibrary + false + v110 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + + + MachineX86 + true + Windows + + + true + + + MachineX86 + + + Console + + + false + true + + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + + + MachineX86 + true + Console + kernel32.lib;msvcrtd.lib + + + true + true + liblfds700.def + true + NoErrorReport + true + + + true + + + MachineX86 + + + Console + + + false + true + + + true + + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + false + + + true + Windows + + + true + + + MachineX64 + + + Console + + + false + true + + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + false + + + true + Console + true + true + liblfds700.def + true + false + NoErrorReport + kernel32.lib;msvcrtd.lib + true + + + true + + + MachineX64 + + + Console + + + false + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreaded + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + + + MachineX86 + true + Windows + true + true + + + true + + + MachineX86 + + + Console + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreadedDLL + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + + + MachineX86 + false + Console + true + true + kernel32.lib;msvcrt.lib + + + true + true + liblfds700.def + NoErrorReport + + + true + + + MachineX86 + + + Console + true + + + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreaded + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + + + true + Windows + true + true + + + true + + + MachineX64 + + + Console + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreadedDLL + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + + + false + Console + true + true + true + true + liblfds700.def + NoErrorReport + kernel32.lib;msvcrt.lib + + + true + + + MachineX64 + + + Console + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.vcxproj.filters b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.vcxproj.filters new file mode 100644 index 0000000000..5ec0bea579 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.vcxproj.filters @@ -0,0 +1,279 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {258be429-7dac-4999-b995-753aa2f0c505} + + + {469abf8e-47d8-4678-bd66-7c7e65c5f52e} + + + {62ee141b-2acb-4555-b016-7be20a57f2bf} + + + {19c73b0f-25e0-4166-9093-427f1dfb4f70} + + + {00eb30fe-e638-4c2b-8ca1-1f09c4a0ed45} + + + {400ae4e9-2281-4549-b918-59d1a27a2d07} + + + {0b1fafc3-817b-4c18-8eb1-121884e3a29b} + + + {bcbadc74-1748-4696-aad7-7fdbe5614624} + + + {c45194af-7b41-4c28-bc0e-1095ec347664} + + + {6250c4d5-ac8e-4c28-93de-0954c5bed1cb} + + + {3ac93721-1d81-49e4-9581-dbc12ace5c0c} + + + + + Header Files + + + Source Files\lfds700_freelist + + + Source Files\lfds700_queue + + + Source Files\lfds700_stack + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_misc + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + + + Source Files\lfds700_freelist + + + Source Files\lfds700_freelist + + + Source Files\lfds700_freelist + + + Source Files\lfds700_freelist + + + Source Files\lfds700_freelist + + + Source Files\lfds700_queue + + + Source Files\lfds700_queue + + + Source Files\lfds700_queue + + + Source Files\lfds700_queue + + + Source Files\lfds700_queue + + + Source Files\lfds700_stack + + + Source Files\lfds700_stack + + + Source Files\lfds700_stack + + + Source Files\lfds700_stack + + + Source Files\lfds700_stack + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_misc + + + Source Files\lfds700_misc + + + Source Files\lfds700_misc + + + Source Files\lfds700_misc + + + Source Files\lfds700_misc + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + \ No newline at end of file diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.vcxproj.user b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.vcxproj.user new file mode 100644 index 0000000000..7cbb3216ad --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012/liblfds700.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/driver_entry.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/driver_entry.c new file mode 100644 index 0000000000..9ea5612e54 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/driver_entry.c @@ -0,0 +1 @@ +#include diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.def b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.def new file mode 100644 index 0000000000..583ce35dbd --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.def @@ -0,0 +1,69 @@ +EXPORTS + +lfds700_btree_au_init_valid_on_current_logical_core = lfds700_btree_au_init_valid_on_current_logical_core +lfds700_btree_au_cleanup = lfds700_btree_au_cleanup +lfds700_btree_au_insert = lfds700_btree_au_insert +lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position = lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position +lfds700_btree_au_get_by_absolute_position = lfds700_btree_au_get_by_absolute_position +lfds700_btree_au_get_by_relative_position = lfds700_btree_au_get_by_relative_position +lfds700_btree_au_get_by_key = lfds700_btree_au_get_by_key +lfds700_btree_au_query = lfds700_btree_au_query + +lfds700_freelist_init_valid_on_current_logical_core = lfds700_freelist_init_valid_on_current_logical_core +lfds700_freelist_cleanup = lfds700_freelist_cleanup +lfds700_freelist_push = lfds700_freelist_push +lfds700_freelist_pop = lfds700_freelist_pop +lfds700_freelist_query = lfds700_freelist_query + +lfds700_hash_a_init_valid_on_current_logical_core = lfds700_hash_a_init_valid_on_current_logical_core +lfds700_hash_a_cleanup = lfds700_hash_a_cleanup +lfds700_hash_a_insert = lfds700_hash_a_insert +lfds700_hash_a_get_by_key = lfds700_hash_a_get_by_key +lfds700_hash_a_iterate_init = lfds700_hash_a_iterate_init +lfds700_hash_a_iterate = lfds700_hash_a_iterate +lfds700_hash_a_query = lfds700_hash_a_query + +lfds700_list_aos_init_valid_on_current_logical_core = lfds700_list_aos_init_valid_on_current_logical_core +lfds700_list_aos_cleanup = lfds700_list_aos_cleanup +lfds700_list_aos_insert = lfds700_list_aos_insert +lfds700_list_aos_get_by_key = lfds700_list_aos_get_by_key +lfds700_list_aos_query = lfds700_list_aos_query + +lfds700_list_asu_init_valid_on_current_logical_core = lfds700_list_asu_init_valid_on_current_logical_core +lfds700_list_asu_cleanup = lfds700_list_asu_cleanup +lfds700_list_asu_insert_at_position = lfds700_list_asu_insert_at_position +lfds700_list_asu_insert_at_start = lfds700_list_asu_insert_at_start +lfds700_list_asu_insert_at_end = lfds700_list_asu_insert_at_end +lfds700_list_asu_insert_after_element = lfds700_list_asu_insert_after_element +lfds700_list_asu_get_by_key = lfds700_list_asu_get_by_key +lfds700_list_asu_query = lfds700_list_asu_query + +lfds700_misc_library_init_valid_on_current_logical_core = lfds700_misc_library_init_valid_on_current_logical_core +lfds700_misc_library_cleanup = lfds700_misc_library_cleanup +lfds700_misc_prng_init = lfds700_misc_prng_init +lfds700_misc_query = lfds700_misc_query + +lfds700_queue_init_valid_on_current_logical_core = lfds700_queue_init_valid_on_current_logical_core +lfds700_queue_cleanup = lfds700_queue_cleanup +lfds700_queue_enqueue = lfds700_queue_enqueue +lfds700_queue_dequeue = lfds700_queue_dequeue +lfds700_queue_query = lfds700_queue_query + +lfds700_queue_bss_init_valid_on_current_logical_core = lfds700_queue_bss_init_valid_on_current_logical_core +lfds700_queue_bss_cleanup = lfds700_queue_bss_cleanup +lfds700_queue_bss_enqueue = lfds700_queue_bss_enqueue +lfds700_queue_bss_dequeue = lfds700_queue_bss_dequeue +lfds700_queue_bss_query = lfds700_queue_bss_query + +lfds700_ringbuffer_init_valid_on_current_logical_core = lfds700_ringbuffer_init_valid_on_current_logical_core +lfds700_ringbuffer_cleanup = lfds700_ringbuffer_cleanup +lfds700_ringbuffer_read = lfds700_ringbuffer_read +lfds700_ringbuffer_write = lfds700_ringbuffer_write +lfds700_ringbuffer_query = lfds700_ringbuffer_query + +lfds700_stack_init_valid_on_current_logical_core = lfds700_stack_init_valid_on_current_logical_core +lfds700_stack_cleanup = lfds700_stack_cleanup +lfds700_stack_push = lfds700_stack_push +lfds700_stack_pop = lfds700_stack_pop +lfds700_stack_query = lfds700_stack_query + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.sln b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.sln new file mode 100644 index 0000000000..b52c44e46f --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblfds700", "liblfds700.vcxproj", "{1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug DLL|Win32 = Debug DLL|Win32 + Debug DLL|x64 = Debug DLL|x64 + Debug LIB|Win32 = Debug LIB|Win32 + Debug LIB|x64 = Debug LIB|x64 + Release DLL|Win32 = Release DLL|Win32 + Release DLL|x64 = Release DLL|x64 + Release LIB|Win32 = Release LIB|Win32 + Release LIB|x64 = Release LIB|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|Win32.ActiveCfg = Debug DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|Win32.Build.0 = Debug DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|Win32.Deploy.0 = Debug DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|x64.ActiveCfg = Debug DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|x64.Build.0 = Debug DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|x64.Deploy.0 = Debug DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|Win32.ActiveCfg = Debug LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|Win32.Build.0 = Debug LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|Win32.Deploy.0 = Debug LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|x64.ActiveCfg = Debug LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|x64.Build.0 = Debug LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|x64.Deploy.0 = Debug LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|Win32.ActiveCfg = Release DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|Win32.Build.0 = Release DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|Win32.Deploy.0 = Release DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|x64.ActiveCfg = Release DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|x64.Build.0 = Release DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|x64.Deploy.0 = Release DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|Win32.ActiveCfg = Release LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|Win32.Build.0 = Release LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|Win32.Deploy.0 = Release LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|x64.ActiveCfg = Release LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|x64.Build.0 = Release LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|x64.Deploy.0 = Release LIB|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.vcxproj b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.vcxproj new file mode 100644 index 0000000000..f19ead0c18 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.vcxproj @@ -0,0 +1,733 @@ + + + + + Debug DLL + Win32 + + + Debug DLL + x64 + + + Debug LIB + Win32 + + + Debug LIB + x64 + + + Release DLL + Win32 + + + Release DLL + x64 + + + Release LIB + Win32 + + + Release LIB + x64 + + + + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0} + Win32Proj + + + + StaticLibrary + true + WindowsKernelModeDriver8.0 + + + DynamicLibrary + true + WindowsKernelModeDriver8.0 + + + StaticLibrary + true + WindowsKernelModeDriver8.0 + + + DynamicLibrary + true + WindowsKernelModeDriver8.0 + + + StaticLibrary + false + WindowsKernelModeDriver8.0 + true + + + DynamicLibrary + false + WindowsKernelModeDriver8.0 + true + + + StaticLibrary + false + WindowsKernelModeDriver8.0 + true + + + DynamicLibrary + false + WindowsKernelModeDriver8.0 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath); + $(WDKContentRoot)lib\$(DDKSpec)\KM\$(DDKPlatform);$(LibraryPath); + + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath); + $(WDKContentRoot)lib\$(DDKSpec)\KM\$(DDKPlatform);$(LibraryPath); + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath); + $(WDKContentRoot)lib\$(DDKSpec)\KM\$(DDKPlatform);$(LibraryPath); + + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath); + $(WDKContentRoot)lib\$(DDKSpec)\KM\$(DDKPlatform);$(LibraryPath); + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath); + $(WDKContentRoot)lib\$(DDKSpec)\KM\$(DDKPlatform);$(LibraryPath); + + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath); + $(WDKContentRoot)lib\$(DDKSpec)\KM\$(DDKPlatform);$(LibraryPath); + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath); + $(WDKContentRoot)lib\$(DDKSpec)\KM\$(DDKPlatform);$(LibraryPath); + + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath); + $(WDKContentRoot)lib\$(DDKSpec)\KM\$(DDKPlatform);$(LibraryPath); + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + /kernel %(AdditionalOptions) + + + MachineX86 + true + Windows + + + true + + + MachineX86 + + + Native + + + false + true + + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + /kernel %(AdditionalOptions) + + + MachineX86 + true + Native + kernel32.lib;msvcrtd.lib + + + true + true + liblfds700.def + true + NoErrorReport + true + WDM + + + true + + + MachineX86 + + + Console + + + false + true + + + true + + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + false + /kernel %(AdditionalOptions) + + + true + Windows + + + true + + + MachineX64 + + + Native + + + false + true + + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + false + /kernel %(AdditionalOptions) + + + true + Native + true + true + liblfds700.def + true + false + NoErrorReport + kernel32.lib;msvcrtd.lib + true + WDM + + + true + + + MachineX64 + + + Console + + + false + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreaded + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + /kernel %(AdditionalOptions) + + + MachineX86 + true + Windows + true + true + + + true + + + MachineX86 + + + Native + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreadedDLL + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + /kernel %(AdditionalOptions) + + + MachineX86 + false + Native + true + true + kernel32.lib;msvcrt.lib + + + true + true + liblfds700.def + NoErrorReport + WDM + + + true + + + MachineX86 + + + Console + true + + + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreaded + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + /kernel %(AdditionalOptions) + + + true + Windows + true + true + + + true + + + MachineX64 + + + Native + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreadedDLL + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + /kernel %(AdditionalOptions) + + + false + Native + true + true + true + true + liblfds700.def + NoErrorReport + kernel32.lib;msvcrt.lib + WDM + + + true + + + MachineX64 + + + Console + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.vcxproj.filters b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.vcxproj.filters new file mode 100644 index 0000000000..978f8ec1c9 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.vcxproj.filters @@ -0,0 +1,279 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {258be429-7dac-4999-b995-753aa2f0c505} + + + {469abf8e-47d8-4678-bd66-7c7e65c5f52e} + + + {62ee141b-2acb-4555-b016-7be20a57f2bf} + + + {19c73b0f-25e0-4166-9093-427f1dfb4f70} + + + {00eb30fe-e638-4c2b-8ca1-1f09c4a0ed45} + + + {6250c4d5-ac8e-4c28-93de-0954c5bed1cb} + + + {400ae4e9-2281-4549-b918-59d1a27a2d07} + + + {c45194af-7b41-4c28-bc0e-1095ec347664} + + + {8b3cbb5c-7436-429f-9b72-bae1f4721746} + + + {bcbadc74-1748-4696-aad7-7fdbe5614624} + + + {0b1fafc3-817b-4c18-8eb1-121884e3a29b} + + + + + Header Files + + + Source Files\lfds700_freelist + + + Source Files\lfds700_stack + + + Source Files\lfds700_queue + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_misc + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_ringbuffer + + + + + Source Files\lfds700_freelist + + + Source Files\lfds700_freelist + + + Source Files\lfds700_freelist + + + Source Files\lfds700_freelist + + + Source Files\lfds700_freelist + + + Source Files\lfds700_stack + + + Source Files\lfds700_stack + + + Source Files\lfds700_stack + + + Source Files\lfds700_stack + + + Source Files\lfds700_stack + + + Source Files\lfds700_queue + + + Source Files\lfds700_queue + + + Source Files\lfds700_queue + + + Source Files\lfds700_queue + + + Source Files\lfds700_queue + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_misc + + + Source Files\lfds700_misc + + + Source Files\lfds700_misc + + + Source Files\lfds700_misc + + + Source Files\lfds700_misc + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_ringbuffer + + + \ No newline at end of file diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.vcxproj.user b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.vcxproj.user new file mode 100644 index 0000000000..7cbb3216ad --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2012_and_wdk_8.0/liblfds700.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/driver_entry.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/driver_entry.c new file mode 100644 index 0000000000..9ea5612e54 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/driver_entry.c @@ -0,0 +1 @@ +#include diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.def b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.def new file mode 100644 index 0000000000..583ce35dbd --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.def @@ -0,0 +1,69 @@ +EXPORTS + +lfds700_btree_au_init_valid_on_current_logical_core = lfds700_btree_au_init_valid_on_current_logical_core +lfds700_btree_au_cleanup = lfds700_btree_au_cleanup +lfds700_btree_au_insert = lfds700_btree_au_insert +lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position = lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position +lfds700_btree_au_get_by_absolute_position = lfds700_btree_au_get_by_absolute_position +lfds700_btree_au_get_by_relative_position = lfds700_btree_au_get_by_relative_position +lfds700_btree_au_get_by_key = lfds700_btree_au_get_by_key +lfds700_btree_au_query = lfds700_btree_au_query + +lfds700_freelist_init_valid_on_current_logical_core = lfds700_freelist_init_valid_on_current_logical_core +lfds700_freelist_cleanup = lfds700_freelist_cleanup +lfds700_freelist_push = lfds700_freelist_push +lfds700_freelist_pop = lfds700_freelist_pop +lfds700_freelist_query = lfds700_freelist_query + +lfds700_hash_a_init_valid_on_current_logical_core = lfds700_hash_a_init_valid_on_current_logical_core +lfds700_hash_a_cleanup = lfds700_hash_a_cleanup +lfds700_hash_a_insert = lfds700_hash_a_insert +lfds700_hash_a_get_by_key = lfds700_hash_a_get_by_key +lfds700_hash_a_iterate_init = lfds700_hash_a_iterate_init +lfds700_hash_a_iterate = lfds700_hash_a_iterate +lfds700_hash_a_query = lfds700_hash_a_query + +lfds700_list_aos_init_valid_on_current_logical_core = lfds700_list_aos_init_valid_on_current_logical_core +lfds700_list_aos_cleanup = lfds700_list_aos_cleanup +lfds700_list_aos_insert = lfds700_list_aos_insert +lfds700_list_aos_get_by_key = lfds700_list_aos_get_by_key +lfds700_list_aos_query = lfds700_list_aos_query + +lfds700_list_asu_init_valid_on_current_logical_core = lfds700_list_asu_init_valid_on_current_logical_core +lfds700_list_asu_cleanup = lfds700_list_asu_cleanup +lfds700_list_asu_insert_at_position = lfds700_list_asu_insert_at_position +lfds700_list_asu_insert_at_start = lfds700_list_asu_insert_at_start +lfds700_list_asu_insert_at_end = lfds700_list_asu_insert_at_end +lfds700_list_asu_insert_after_element = lfds700_list_asu_insert_after_element +lfds700_list_asu_get_by_key = lfds700_list_asu_get_by_key +lfds700_list_asu_query = lfds700_list_asu_query + +lfds700_misc_library_init_valid_on_current_logical_core = lfds700_misc_library_init_valid_on_current_logical_core +lfds700_misc_library_cleanup = lfds700_misc_library_cleanup +lfds700_misc_prng_init = lfds700_misc_prng_init +lfds700_misc_query = lfds700_misc_query + +lfds700_queue_init_valid_on_current_logical_core = lfds700_queue_init_valid_on_current_logical_core +lfds700_queue_cleanup = lfds700_queue_cleanup +lfds700_queue_enqueue = lfds700_queue_enqueue +lfds700_queue_dequeue = lfds700_queue_dequeue +lfds700_queue_query = lfds700_queue_query + +lfds700_queue_bss_init_valid_on_current_logical_core = lfds700_queue_bss_init_valid_on_current_logical_core +lfds700_queue_bss_cleanup = lfds700_queue_bss_cleanup +lfds700_queue_bss_enqueue = lfds700_queue_bss_enqueue +lfds700_queue_bss_dequeue = lfds700_queue_bss_dequeue +lfds700_queue_bss_query = lfds700_queue_bss_query + +lfds700_ringbuffer_init_valid_on_current_logical_core = lfds700_ringbuffer_init_valid_on_current_logical_core +lfds700_ringbuffer_cleanup = lfds700_ringbuffer_cleanup +lfds700_ringbuffer_read = lfds700_ringbuffer_read +lfds700_ringbuffer_write = lfds700_ringbuffer_write +lfds700_ringbuffer_query = lfds700_ringbuffer_query + +lfds700_stack_init_valid_on_current_logical_core = lfds700_stack_init_valid_on_current_logical_core +lfds700_stack_cleanup = lfds700_stack_cleanup +lfds700_stack_push = lfds700_stack_push +lfds700_stack_pop = lfds700_stack_pop +lfds700_stack_query = lfds700_stack_query + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.sln b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.sln new file mode 100644 index 0000000000..1cc19a8e23 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.sln @@ -0,0 +1,59 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.40629.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblfds700", "liblfds700.vcxproj", "{1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug DLL|ARM = Debug DLL|ARM + Debug DLL|Win32 = Debug DLL|Win32 + Debug DLL|x64 = Debug DLL|x64 + Debug LIB|ARM = Debug LIB|ARM + Debug LIB|Win32 = Debug LIB|Win32 + Debug LIB|x64 = Debug LIB|x64 + Release DLL|ARM = Release DLL|ARM + Release DLL|Win32 = Release DLL|Win32 + Release DLL|x64 = Release DLL|x64 + Release LIB|ARM = Release LIB|ARM + Release LIB|Win32 = Release LIB|Win32 + Release LIB|x64 = Release LIB|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|ARM.ActiveCfg = Debug DLL|ARM + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|ARM.Build.0 = Debug DLL|ARM + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|Win32.ActiveCfg = Debug DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|Win32.Build.0 = Debug DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|Win32.Deploy.0 = Debug DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|x64.ActiveCfg = Debug DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|x64.Build.0 = Debug DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|x64.Deploy.0 = Debug DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|ARM.ActiveCfg = Debug LIB|ARM + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|ARM.Build.0 = Debug LIB|ARM + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|Win32.ActiveCfg = Debug LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|Win32.Build.0 = Debug LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|Win32.Deploy.0 = Debug LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|x64.ActiveCfg = Debug LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|x64.Build.0 = Debug LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|x64.Deploy.0 = Debug LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|ARM.ActiveCfg = Release DLL|ARM + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|ARM.Build.0 = Release DLL|ARM + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|Win32.ActiveCfg = Release DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|Win32.Build.0 = Release DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|Win32.Deploy.0 = Release DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|x64.ActiveCfg = Release DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|x64.Build.0 = Release DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|x64.Deploy.0 = Release DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|ARM.ActiveCfg = Release LIB|ARM + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|ARM.Build.0 = Release LIB|ARM + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|Win32.ActiveCfg = Release LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|Win32.Build.0 = Release LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|Win32.Deploy.0 = Release LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|x64.ActiveCfg = Release LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|x64.Build.0 = Release LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|x64.Deploy.0 = Release LIB|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.vcxproj b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.vcxproj new file mode 100644 index 0000000000..e67a540e37 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.vcxproj @@ -0,0 +1,1054 @@ + + + + + Debug DLL + ARM + + + Debug DLL + Win32 + + + Debug DLL + x64 + + + Debug LIB + ARM + + + Debug LIB + Win32 + + + Debug LIB + x64 + + + Release DLL + ARM + + + Release DLL + Win32 + + + Release DLL + x64 + + + Release LIB + ARM + + + Release LIB + Win32 + + + Release LIB + x64 + + + + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0} + Win32Proj + + + + StaticLibrary + true + WindowsKernelModeDriver8.1 + + + StaticLibrary + true + WindowsKernelModeDriver8.1 + + + DynamicLibrary + true + WindowsKernelModeDriver8.1 + + + DynamicLibrary + true + WindowsKernelModeDriver8.1 + + + StaticLibrary + true + WindowsKernelModeDriver8.1 + + + DynamicLibrary + true + WindowsKernelModeDriver8.1 + + + StaticLibrary + false + WindowsKernelModeDriver8.1 + true + + + StaticLibrary + false + WindowsKernelModeDriver8.1 + true + + + DynamicLibrary + false + WindowsKernelModeDriver8.1 + true + + + DynamicLibrary + false + WindowsKernelModeDriver8.1 + true + + + StaticLibrary + false + WindowsKernelModeDriver8.1 + true + + + DynamicLibrary + false + WindowsKernelModeDriver8.1 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath);$(WDKContentRoot)include\km\;$(WDKContentRoot)include\wdf\kmdf\1.11\ + $(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(WDKContentRoot)lib\wdf\kmdf\x86\ + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath) + $(WDKContentRoot)lib\$(DDKSpec)\KM\$(DDKPlatform);$(LibraryPath) + + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath);$(WDKContentRoot)include\km\;$(WDKContentRoot)include\wdf\kmdf\1.11\ + $(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(WDKContentRoot)lib\wdf\kmdf\x86\ + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath) + $(WDKContentRoot)lib\$(DDKSpec)\KM\$(DDKPlatform);$(LibraryPath) + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(MSBuildToolsPath);$(MSBuildFrameworkToolsPath);$(MSBuild_ExecutablePath);$(VC_LibraryPath_ARM); + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath);$(WDKContentRoot)include\km\;$(WDKContentRoot)include\wdf\kmdf\1.11\ + $(VCInstallDir)lib\amd64;$(VCInstallDir)atlmfc\lib\amd64;$(WindowsSDK_LibraryPath_x64);;$(WDKContentRoot)lib\wdf\kmdf\x64\ + + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath);$(WDKContentRoot)include\km\;$(WDKContentRoot)include\wdf\kmdf\1.11\ + $(VCInstallDir)lib\amd64;$(VCInstallDir)atlmfc\lib\amd64;$(WindowsSDK_LibraryPath_x64);;$(WDKContentRoot)lib\wdf\kmdf\x64\ + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath);$(WDKContentRoot)include\km\;$(WDKContentRoot)include\wdf\kmdf\1.11\ + $(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(WDKContentRoot)lib\wdf\kmdf\x86\ + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath) + $(WDKContentRoot)lib\$(DDKSpec)\KM\$(DDKPlatform);$(LibraryPath) + + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath);$(WDKContentRoot)include\km\;$(WDKContentRoot)include\wdf\kmdf\1.11\ + $(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSDK_LibraryPath_x86);$(WDKContentRoot)lib\wdf\kmdf\x86\ + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath) + $(WDKContentRoot)lib\$(DDKSpec)\KM\$(DDKPlatform);$(LibraryPath) + + + true + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath);$(WDKContentRoot)include\km\;$(WDKContentRoot)include\wdf\kmdf\1.11\ + $(VCInstallDir)lib\amd64;$(VCInstallDir)atlmfc\lib\amd64;$(WindowsSDK_LibraryPath_x64);;$(WDKContentRoot)lib\wdf\kmdf\x64\ + + + + + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + $(ProjectDir);$(IncludePath);$(WDKContentRoot)include\km\;$(WDKContentRoot)include\wdf\kmdf\1.11\ + $(VCInstallDir)lib\amd64;$(VCInstallDir)atlmfc\lib\amd64;$(WindowsSDK_LibraryPath_x64);;$(WDKContentRoot)lib\wdf\kmdf\x64\ + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + /kernel %(AdditionalOptions) + + + MachineX86 + true + Windows + + + true + + + MachineX86 + + + Native + + + false + true + + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + /kernel %(AdditionalOptions) + + + true + Windows + + + true + + + MachineARM + + + Native + + + false + true + + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + /kernel %(AdditionalOptions) + + + MachineX86 + true + Native + kernel32.lib;msvcrtd.lib + + + true + true + liblfds700.def + true + NoErrorReport + true + WDM + + + true + + + MachineX86 + + + Console + + + false + true + + + true + + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + /kernel %(AdditionalOptions) + + + true + Native + kernel32.lib;msvcrtd.lib + + + true + true + liblfds700.def + true + NoErrorReport + true + WDM + + + + true + + + MachineX86 + + + Console + + + false + true + + + true + + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + false + /kernel %(AdditionalOptions) + + + true + Windows + + + true + + + MachineX64 + + + Native + + + false + true + + + + + WIN32;_DEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Debug";%(PreprocessorDefinitions) + + + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + false + true + + + + + + + true + false + false + false + true + CompileAsC + true + None + true + false + 4068 + false + /kernel %(AdditionalOptions) + + + true + Native + true + true + liblfds700.def + true + false + NoErrorReport + kernel32.lib;msvcrtd.lib + true + WDM + + + true + + + MachineX64 + + + Console + + + false + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreaded + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + /kernel %(AdditionalOptions) + + + MachineX86 + true + Windows + true + true + + + true + + + MachineX86 + + + Native + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreaded + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + /kernel %(AdditionalOptions) + + + true + Windows + true + true + + + true + + + MachineARM + + + Native + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreadedDLL + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + /kernel %(AdditionalOptions) + + + MachineX86 + false + Native + true + true + kernel32.lib;msvcrt.lib + + + true + true + liblfds700.def + NoErrorReport + WDM + + + true + + + MachineX86 + + + Console + true + + + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreadedDLL + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + /kernel %(AdditionalOptions) + + + false + Native + true + true + kernel32.lib;msvcrt.lib + + + true + true + liblfds700.def + NoErrorReport + WDM + + + + true + + + MachineX86 + + + Console + true + + + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreaded + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + /kernel %(AdditionalOptions) + + + true + Windows + true + true + + + true + + + MachineX64 + + + Native + true + + + + + WIN32;NDEBUG;_LIB;LFDS700_BUILD_TYPE_STRING="Release";%(PreprocessorDefinitions) + + + MultiThreadedDLL + Level4 + None + false + false + true + true + AnySuitable + true + Speed + true + false + false + + + + + + + false + + + false + false + CompileAsC + true + None + true + 4068 + true + /kernel %(AdditionalOptions) + + + false + Native + true + true + true + true + liblfds700.def + NoErrorReport + kernel32.lib;msvcrt.lib + WDM + + + true + + + MachineX64 + + + Console + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.vcxproj.filters b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.vcxproj.filters new file mode 100644 index 0000000000..978f8ec1c9 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.vcxproj.filters @@ -0,0 +1,279 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {258be429-7dac-4999-b995-753aa2f0c505} + + + {469abf8e-47d8-4678-bd66-7c7e65c5f52e} + + + {62ee141b-2acb-4555-b016-7be20a57f2bf} + + + {19c73b0f-25e0-4166-9093-427f1dfb4f70} + + + {00eb30fe-e638-4c2b-8ca1-1f09c4a0ed45} + + + {6250c4d5-ac8e-4c28-93de-0954c5bed1cb} + + + {400ae4e9-2281-4549-b918-59d1a27a2d07} + + + {c45194af-7b41-4c28-bc0e-1095ec347664} + + + {8b3cbb5c-7436-429f-9b72-bae1f4721746} + + + {bcbadc74-1748-4696-aad7-7fdbe5614624} + + + {0b1fafc3-817b-4c18-8eb1-121884e3a29b} + + + + + Header Files + + + Source Files\lfds700_freelist + + + Source Files\lfds700_stack + + + Source Files\lfds700_queue + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Header Files\liblfds700 + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_misc + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_ringbuffer + + + + + Source Files\lfds700_freelist + + + Source Files\lfds700_freelist + + + Source Files\lfds700_freelist + + + Source Files\lfds700_freelist + + + Source Files\lfds700_freelist + + + Source Files\lfds700_stack + + + Source Files\lfds700_stack + + + Source Files\lfds700_stack + + + Source Files\lfds700_stack + + + Source Files\lfds700_stack + + + Source Files\lfds700_queue + + + Source Files\lfds700_queue + + + Source Files\lfds700_queue + + + Source Files\lfds700_queue + + + Source Files\lfds700_queue + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_hash_addonly + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_list_addonly_ordered_singlylinked + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_btree_addonly_unbalanced + + + Source Files\lfds700_misc + + + Source Files\lfds700_misc + + + Source Files\lfds700_misc + + + Source Files\lfds700_misc + + + Source Files\lfds700_misc + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_queue_bounded_singleconsumer_singleproducer + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_list_addonly_singlylinked_unordered + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_ringbuffer + + + Source Files\lfds700_ringbuffer + + + \ No newline at end of file diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.vcxproj.user b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.vcxproj.user new file mode 100644 index 0000000000..7cbb3216ad --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/visual_studio_professional_2013_and_wdk_8.1/liblfds700.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/dirs b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/dirs new file mode 100644 index 0000000000..64e002cc57 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/dirs @@ -0,0 +1,3 @@ +DIRS = single_dir_for_windows_kernel + + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/driver_entry_renamed_to_avoid_compiler_warning.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/driver_entry_renamed_to_avoid_compiler_warning.c new file mode 100644 index 0000000000..09d7acb7fc --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/driver_entry_renamed_to_avoid_compiler_warning.c @@ -0,0 +1,23 @@ +#include "liblfds700_internal.h" + + + + + +/****************************************************************************/ +DRIVER_INITIALIZE DriverEntry; + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +NTSTATUS DriverEntry( struct _DRIVER_OBJECT *DriverObject, PUNICODE_STRING RegistryPath ) +{ + return( STATUS_SUCCESS ); +} + +#pragma warning( default : 4100 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/liblfds700.def b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/liblfds700.def new file mode 100644 index 0000000000..583ce35dbd --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/liblfds700.def @@ -0,0 +1,69 @@ +EXPORTS + +lfds700_btree_au_init_valid_on_current_logical_core = lfds700_btree_au_init_valid_on_current_logical_core +lfds700_btree_au_cleanup = lfds700_btree_au_cleanup +lfds700_btree_au_insert = lfds700_btree_au_insert +lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position = lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position +lfds700_btree_au_get_by_absolute_position = lfds700_btree_au_get_by_absolute_position +lfds700_btree_au_get_by_relative_position = lfds700_btree_au_get_by_relative_position +lfds700_btree_au_get_by_key = lfds700_btree_au_get_by_key +lfds700_btree_au_query = lfds700_btree_au_query + +lfds700_freelist_init_valid_on_current_logical_core = lfds700_freelist_init_valid_on_current_logical_core +lfds700_freelist_cleanup = lfds700_freelist_cleanup +lfds700_freelist_push = lfds700_freelist_push +lfds700_freelist_pop = lfds700_freelist_pop +lfds700_freelist_query = lfds700_freelist_query + +lfds700_hash_a_init_valid_on_current_logical_core = lfds700_hash_a_init_valid_on_current_logical_core +lfds700_hash_a_cleanup = lfds700_hash_a_cleanup +lfds700_hash_a_insert = lfds700_hash_a_insert +lfds700_hash_a_get_by_key = lfds700_hash_a_get_by_key +lfds700_hash_a_iterate_init = lfds700_hash_a_iterate_init +lfds700_hash_a_iterate = lfds700_hash_a_iterate +lfds700_hash_a_query = lfds700_hash_a_query + +lfds700_list_aos_init_valid_on_current_logical_core = lfds700_list_aos_init_valid_on_current_logical_core +lfds700_list_aos_cleanup = lfds700_list_aos_cleanup +lfds700_list_aos_insert = lfds700_list_aos_insert +lfds700_list_aos_get_by_key = lfds700_list_aos_get_by_key +lfds700_list_aos_query = lfds700_list_aos_query + +lfds700_list_asu_init_valid_on_current_logical_core = lfds700_list_asu_init_valid_on_current_logical_core +lfds700_list_asu_cleanup = lfds700_list_asu_cleanup +lfds700_list_asu_insert_at_position = lfds700_list_asu_insert_at_position +lfds700_list_asu_insert_at_start = lfds700_list_asu_insert_at_start +lfds700_list_asu_insert_at_end = lfds700_list_asu_insert_at_end +lfds700_list_asu_insert_after_element = lfds700_list_asu_insert_after_element +lfds700_list_asu_get_by_key = lfds700_list_asu_get_by_key +lfds700_list_asu_query = lfds700_list_asu_query + +lfds700_misc_library_init_valid_on_current_logical_core = lfds700_misc_library_init_valid_on_current_logical_core +lfds700_misc_library_cleanup = lfds700_misc_library_cleanup +lfds700_misc_prng_init = lfds700_misc_prng_init +lfds700_misc_query = lfds700_misc_query + +lfds700_queue_init_valid_on_current_logical_core = lfds700_queue_init_valid_on_current_logical_core +lfds700_queue_cleanup = lfds700_queue_cleanup +lfds700_queue_enqueue = lfds700_queue_enqueue +lfds700_queue_dequeue = lfds700_queue_dequeue +lfds700_queue_query = lfds700_queue_query + +lfds700_queue_bss_init_valid_on_current_logical_core = lfds700_queue_bss_init_valid_on_current_logical_core +lfds700_queue_bss_cleanup = lfds700_queue_bss_cleanup +lfds700_queue_bss_enqueue = lfds700_queue_bss_enqueue +lfds700_queue_bss_dequeue = lfds700_queue_bss_dequeue +lfds700_queue_bss_query = lfds700_queue_bss_query + +lfds700_ringbuffer_init_valid_on_current_logical_core = lfds700_ringbuffer_init_valid_on_current_logical_core +lfds700_ringbuffer_cleanup = lfds700_ringbuffer_cleanup +lfds700_ringbuffer_read = lfds700_ringbuffer_read +lfds700_ringbuffer_write = lfds700_ringbuffer_write +lfds700_ringbuffer_query = lfds700_ringbuffer_query + +lfds700_stack_init_valid_on_current_logical_core = lfds700_stack_init_valid_on_current_logical_core +lfds700_stack_cleanup = lfds700_stack_cleanup +lfds700_stack_push = lfds700_stack_push +lfds700_stack_pop = lfds700_stack_pop +lfds700_stack_query = lfds700_stack_query + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/readme_before_win_kernel_build.txt b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/readme_before_win_kernel_build.txt new file mode 100644 index 0000000000..1481c8d08a --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/readme_before_win_kernel_build.txt @@ -0,0 +1,32 @@ +The Windows kernel build environment is primitive and has a number +of severe limitations; in particular, all source files must be in +one directory and it is not possible to choose the output binary type +(static or dynamic library) from the build command line; rather, +a string has to be modified in a text file used by the build (!) + +To deal with these limitations, it is necessary for a Windows kernel +build to run a batch file prior to building. + +There are two batch files, one for static library builds and the other +for dynamic library builds. + +They are both idempotent; you can run them as often as you like and +switch between them as often as you want. It's all fine; whenever +you run one of them, it will take you from whatever state you were +previously in, into the state you want to be in. + +Both batch files copy all the sources file into a single directory, +"/src/single_dir_for_windows_kernel/". + +The static library batch file will then copy "/sources.static" into +"/src/single_dir_for_windows_kernel/", which will cause a static +library to be built. + +The dynamic library batch file will then copy "/sources.dynamic" into +"/src/single_dir_for_windows_kernel/", which will cause a dynamic +library to be built. It will also copy "src/driver_entry.c" into +"/src/single_dir_for_windows_kernel/", since the linker requires +the DriverEntry function to exist for dynamic libraries, even +though it's not used. + + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/runme_before_win_kernel_dynamic_lib_build.bat b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/runme_before_win_kernel_dynamic_lib_build.bat new file mode 100644 index 0000000000..ff6fc8a1f3 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/runme_before_win_kernel_dynamic_lib_build.bat @@ -0,0 +1,22 @@ +@echo off +rmdir /q /s single_dir_for_windows_kernel 1>nul 2>nul +mkdir single_dir_for_windows_kernel 1>nul 2>nul + +copy /y ..\..\src\lfds700_btree_addonly_unbalanced\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_freelist\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_hash_addonly\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_list_addonly_ordered_singlylinked\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_list_addonly_singlylinked_unordered\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_misc\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_queue\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_queue_bounded_singleconsumer_singleproducer\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_ringbuffer\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_stack\* single_dir_for_windows_kernel\ 1>nul 2>nul + +copy /y ..\..\src\liblfds700_internal.h single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y driver_entry_renamed_to_avoid_compiler_warning.c single_dir_for_windows_kernel\driver_entry.c 1>nul 2>nul +copy /y sources.dynamic single_dir_for_windows_kernel\sources 1>nul 2>nul + +echo Windows kernel dynamic library build directory structure created. +echo (Note the effects of this batch file are idempotent). + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/runme_before_win_kernel_static_lib_build.bat b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/runme_before_win_kernel_static_lib_build.bat new file mode 100644 index 0000000000..81c35e99c8 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/runme_before_win_kernel_static_lib_build.bat @@ -0,0 +1,21 @@ +@echo off +rmdir /q /s single_dir_for_windows_kernel 1>nul 2>nul +mkdir single_dir_for_windows_kernel 1>nul 2>nul + +copy /y ..\..\src\lfds700_btree_addonly_unbalanced\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_freelist\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_hash_addonly\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_list_addonly_ordered_singlylinked\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_list_addonly_singlylinked_unordered\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_misc\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_queue\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_queue_bounded_singleconsumer_singleproducer\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_ringbuffer\* single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y ..\..\src\lfds700_stack\* single_dir_for_windows_kernel\ 1>nul 2>nul + +copy /y ..\..\src\liblfds700_internal.h single_dir_for_windows_kernel\ 1>nul 2>nul +copy /y sources.static single_dir_for_windows_kernel\sources 1>nul 2>nul + +echo Windows kernel static library build directory structure created. +echo (Note the effects of this batch file are idempotent). + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/sources.dynamic b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/sources.dynamic new file mode 100644 index 0000000000..b0d241f85f --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/sources.dynamic @@ -0,0 +1,62 @@ +MSC_WARNING_LEVEL = /WX /wd4127 /W4 +DLLDEF = ../liblfds700.def +TARGETNAME = liblfds700 +TARGETPATH = ../../../bin/ +TARGETTYPE = EXPORT_DRIVER +UMTYPE = nt +USER_C_FLAGS = /D_KERNEL_MODE + +INCLUDES = ../../../inc/ +SOURCES = lfds700_hash_addonly_cleanup.c \ + lfds700_hash_addonly_get.c \ + lfds700_hash_addonly_init.c \ + lfds700_hash_addonly_insert.c \ + lfds700_hash_addonly_iterate.c \ + lfds700_hash_addonly_query.c \ + lfds700_list_addonly_ordered_singlylinked_cleanup.c \ + lfds700_list_addonly_ordered_singlylinked_get.c \ + lfds700_list_addonly_ordered_singlylinked_init.c \ + lfds700_list_addonly_ordered_singlylinked_insert.c \ + lfds700_list_addonly_ordered_singlylinked_query.c \ + lfds700_list_addonly_singlylinked_unordered_cleanup.c \ + lfds700_list_addonly_singlylinked_unordered_get.c \ + lfds700_list_addonly_singlylinked_unordered_init.c \ + lfds700_list_addonly_singlylinked_unordered_insert.c \ + lfds700_list_addonly_singlylinked_unordered_query.c \ + lfds700_btree_addonly_unbalanced_cleanup.c \ + lfds700_btree_addonly_unbalanced_get.c \ + lfds700_btree_addonly_unbalanced_init.c \ + lfds700_btree_addonly_unbalanced_insert.c \ + lfds700_btree_addonly_unbalanced_query.c \ + lfds700_freelist_cleanup.c \ + lfds700_freelist_init.c \ + lfds700_freelist_pop.c \ + lfds700_freelist_push.c \ + lfds700_freelist_query.c \ + lfds700_misc_cleanup.c \ + lfds700_misc_globals.c \ + lfds700_misc_init.c \ + lfds700_misc_prng.c \ + lfds700_misc_query.c \ + lfds700_queue_cleanup.c \ + lfds700_queue_dequeue.c \ + lfds700_queue_enqueue.c \ + lfds700_queue_init.c \ + lfds700_queue_query.c \ + lfds700_queue_bounded_singleconsumer_singleproducer_cleanup.c \ + lfds700_queue_bounded_singleconsumer_singleproducer_dequeue.c \ + lfds700_queue_bounded_singleconsumer_singleproducer_enqueue.c \ + lfds700_queue_bounded_singleconsumer_singleproducer_init.c \ + lfds700_queue_bounded_singleconsumer_singleproducer_query.c \ + lfds700_ringbuffer_cleanup.c \ + lfds700_ringbuffer_init.c \ + lfds700_ringbuffer_query.c \ + lfds700_ringbuffer_read.c \ + lfds700_ringbuffer_write.c \ + lfds700_stack_cleanup.c \ + lfds700_stack_init.c \ + lfds700_stack_pop.c \ + lfds700_stack_push.c \ + lfds700_stack_query.c \ + driver_entry.c + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/sources.static b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/sources.static new file mode 100644 index 0000000000..401b381c7d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/build/wdk_7.1/sources.static @@ -0,0 +1,60 @@ +MSC_WARNING_LEVEL = /WX /wd4127 /W4 +TARGETNAME = liblfds700 +TARGETPATH = ../../../bin/ +TARGETTYPE = DRIVER_LIBRARY +UMTYPE = nt +USER_C_FLAGS = /D_KERNEL_MODE + +INCLUDES = ../../../inc/ +SOURCES = lfds700_hash_addonly_cleanup.c \ + lfds700_hash_addonly_get.c \ + lfds700_hash_addonly_init.c \ + lfds700_hash_addonly_insert.c \ + lfds700_hash_addonly_iterate.c \ + lfds700_hash_addonly_query.c \ + lfds700_list_addonly_ordered_singlylinked_cleanup.c \ + lfds700_list_addonly_ordered_singlylinked_get.c \ + lfds700_list_addonly_ordered_singlylinked_init.c \ + lfds700_list_addonly_ordered_singlylinked_insert.c \ + lfds700_list_addonly_ordered_singlylinked_query.c \ + lfds700_list_addonly_singlylinked_unordered_cleanup.c \ + lfds700_list_addonly_singlylinked_unordered_get.c \ + lfds700_list_addonly_singlylinked_unordered_init.c \ + lfds700_list_addonly_singlylinked_unordered_insert.c \ + lfds700_list_addonly_singlylinked_unordered_query.c \ + lfds700_btree_addonly_unbalanced_cleanup.c \ + lfds700_btree_addonly_unbalanced_get.c \ + lfds700_btree_addonly_unbalanced_init.c \ + lfds700_btree_addonly_unbalanced_insert.c \ + lfds700_btree_addonly_unbalanced_query.c \ + lfds700_freelist_cleanup.c \ + lfds700_freelist_init.c \ + lfds700_freelist_pop.c \ + lfds700_freelist_push.c \ + lfds700_freelist_query.c \ + lfds700_misc_cleanup.c \ + lfds700_misc_globals.c \ + lfds700_misc_init.c \ + lfds700_misc_prng.c \ + lfds700_misc_query.c \ + lfds700_queue_cleanup.c \ + lfds700_queue_dequeue.c \ + lfds700_queue_enqueue.c \ + lfds700_queue_init.c \ + lfds700_queue_query.c \ + lfds700_queue_bounded_singleconsumer_singleproducer_cleanup.c \ + lfds700_queue_bounded_singleconsumer_singleproducer_dequeue.c \ + lfds700_queue_bounded_singleconsumer_singleproducer_enqueue.c \ + lfds700_queue_bounded_singleconsumer_singleproducer_init.c \ + lfds700_queue_bounded_singleconsumer_singleproducer_query.c \ + lfds700_ringbuffer_cleanup.c \ + lfds700_ringbuffer_init.c \ + lfds700_ringbuffer_query.c \ + lfds700_ringbuffer_read.c \ + lfds700_ringbuffer_write.c \ + lfds700_stack_cleanup.c \ + lfds700_stack_init.c \ + lfds700_stack_pop.c \ + lfds700_stack_push.c \ + lfds700_stack_query.c + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700.h new file mode 100644 index 0000000000..fdda50cefb --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700.h @@ -0,0 +1,31 @@ +#ifndef LIBLFDS700_H + + /***** defines *****/ + #define LIBLFDS700_H + + /***** pragmas on *****/ + #pragma warning( disable : 4324 ) // TRD : 4324 disables MSVC warnings for structure alignment padding due to alignment specifiers + + #pragma prefast( disable : 28113 28182 28183, "blah" ) + + /***** includes *****/ + #include "liblfds700/lfds700_porting_abstraction_layer_compiler.h" + #include "liblfds700/lfds700_porting_abstraction_layer_operating_system.h" + #include "liblfds700/lfds700_porting_abstraction_layer_processor.h" + + #include "liblfds700/lfds700_misc.h" // TRD : everything after depends on misc + #include "liblfds700/lfds700_btree_addonly_unbalanced.h" // TRD : hash_addonly depends on btree_addonly_unbalanced + #include "liblfds700/lfds700_freelist.h" + #include "liblfds700/lfds700_hash_addonly.h" + #include "liblfds700/lfds700_list_addonly_ordered_singlylinked.h" + #include "liblfds700/lfds700_list_addonly_singlylinked_unordered.h" + #include "liblfds700/lfds700_queue.h" + #include "liblfds700/lfds700_queue_bounded_singleconsumer_singleproducer.h" + #include "liblfds700/lfds700_ringbuffer.h" + #include "liblfds700/lfds700_stack.h" + + /***** pragmas off *****/ + #pragma warning( default : 4324 ) + +#endif + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_btree_addonly_unbalanced.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_btree_addonly_unbalanced.h new file mode 100644 index 0000000000..bdc63a4273 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_btree_addonly_unbalanced.h @@ -0,0 +1,113 @@ +/***** defines *****/ +#define LFDS700_BTREE_AU_GET_KEY_FROM_ELEMENT( btree_au_element ) ( (btree_au_element).key ) +#define LFDS700_BTREE_AU_SET_KEY_IN_ELEMENT( btree_au_element, new_key ) ( (btree_au_element).key = (void *) (lfds700_pal_uint_t) (new_key) ) +#define LFDS700_BTREE_AU_GET_VALUE_FROM_ELEMENT( btree_au_element ) ( LFDS700_MISC_BARRIER_LOAD, (btree_au_element).value ) +#define LFDS700_BTREE_AU_SET_VALUE_IN_ELEMENT( btree_au_element, new_value ) { void *local_new_value = (void *) (lfds700_pal_uint_t) (new_value); LFDS700_PAL_ATOMIC_EXCHANGE( &(btree_au_element).value, &local_new_value ); } +#define LFDS700_BTREE_AU_GET_USER_STATE_FROM_STATE( btree_au_state ) ( (btree_au_state).user_state ) + +/***** enums *****/ +enum lfds700_btree_au_absolute_position +{ + LFDS700_BTREE_AU_ABSOLUTE_POSITION_ROOT, + LFDS700_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE, + LFDS700_BTREE_AU_ABSOLUTE_POSITION_LARGEST_IN_TREE +}; + +enum lfds700_btree_au_existing_key +{ + LFDS700_BTREE_AU_EXISTING_KEY_OVERWRITE, + LFDS700_BTREE_AU_EXISTING_KEY_FAIL +}; + +enum lfds700_btree_au_insert_result +{ + LFDS700_BTREE_AU_INSERT_RESULT_FAILURE_EXISTING_KEY, + LFDS700_BTREE_AU_INSERT_RESULT_SUCCESS_OVERWRITE, + LFDS700_BTREE_AU_INSERT_RESULT_SUCCESS +}; + +enum lfds700_btree_au_relative_position +{ + LFDS700_BTREE_AU_RELATIVE_POSITION_UP, + LFDS700_BTREE_AU_RELATIVE_POSITION_LEFT, + LFDS700_BTREE_AU_RELATIVE_POSITION_RIGHT, + LFDS700_BTREE_AU_RELATIVE_POSITION_SMALLEST_ELEMENT_BELOW_CURRENT_ELEMENT, + LFDS700_BTREE_AU_RELATIVE_POSITION_LARGEST_ELEMENT_BELOW_CURRENT_ELEMENT, + LFDS700_BTREE_AU_RELATIVE_POSITION_NEXT_SMALLER_ELEMENT_IN_ENTIRE_TREE, + LFDS700_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE +}; + +enum lfds700_btree_au_query +{ + LFDS700_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, + LFDS700_BTREE_AU_QUERY_SINGLETHREADED_VALIDATE +}; + +/***** structs *****/ +struct lfds700_btree_au_element +{ + struct lfds700_btree_au_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile left, + *volatile right, + *volatile up; + + void LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile value; + + void LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *key; +}; + +struct lfds700_btree_au_state +{ + struct lfds700_btree_au_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile root; + + int LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + (*key_compare_function)( void const *new_key, void const *existing_key ); + + enum lfds700_btree_au_existing_key + existing_key; + + void + *user_state; +}; + +/***** public prototypes *****/ +void lfds700_btree_au_init_valid_on_current_logical_core( struct lfds700_btree_au_state *baus, + int (*key_compare_function)(void const *new_key, void const *existing_key), + enum lfds700_btree_au_existing_key existing_key, + void *user_state ); + // TRD : used in conjunction with the #define LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE + +void lfds700_btree_au_cleanup( struct lfds700_btree_au_state *baus, + void (*element_cleanup_callback)(struct lfds700_btree_au_state *baus, struct lfds700_btree_au_element *baue) ); + +enum lfds700_btree_au_insert_result lfds700_btree_au_insert( struct lfds700_btree_au_state *baus, + struct lfds700_btree_au_element *baue, + struct lfds700_btree_au_element **existing_baue, + struct lfds700_misc_prng_state *ps ); + // TRD : if a link collides with an existing key and existing_baue is non-NULL, existing_baue is set to the existing element + +int lfds700_btree_au_get_by_key( struct lfds700_btree_au_state *baus, + void *key, + struct lfds700_btree_au_element **baue ); + +int lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position( struct lfds700_btree_au_state *baus, + struct lfds700_btree_au_element **baue, + enum lfds700_btree_au_absolute_position absolute_position, + enum lfds700_btree_au_relative_position relative_position ); + // TRD : if *baue is NULL, we get the element at position, otherwise we move from *baue according to direction + +int lfds700_btree_au_get_by_absolute_position( struct lfds700_btree_au_state *baus, + struct lfds700_btree_au_element **baue, + enum lfds700_btree_au_absolute_position absolute_position ); + +int lfds700_btree_au_get_by_relative_position( struct lfds700_btree_au_element **baue, + enum lfds700_btree_au_relative_position relative_position ); + +void lfds700_btree_au_query( struct lfds700_btree_au_state *baus, + enum lfds700_btree_au_query query_type, + void *query_input, + void *query_output ); + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_freelist.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_freelist.h new file mode 100644 index 0000000000..6a89386c5d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_freelist.h @@ -0,0 +1,54 @@ +/***** defines *****/ +#define LFDS700_FREELIST_GET_KEY_FROM_ELEMENT( freelist_element ) ( (freelist_element).key ) +#define LFDS700_FREELIST_SET_KEY_IN_ELEMENT( freelist_element, new_key ) ( (freelist_element).key = (void *) (lfds700_pal_uint_t) (new_key) ) +#define LFDS700_FREELIST_GET_VALUE_FROM_ELEMENT( freelist_element ) ( (freelist_element).value ) +#define LFDS700_FREELIST_SET_VALUE_IN_ELEMENT( freelist_element, new_value ) ( (freelist_element).value = (void *) (lfds700_pal_uint_t) (new_value) ) +#define LFDS700_FREELIST_GET_USER_STATE_FROM_STATE( freelist_state ) ( (freelist_state).user_state ) + +/***** enums *****/ +enum lfds700_freelist_query +{ + LFDS700_FREELIST_QUERY_SINGLETHREADED_GET_COUNT, + LFDS700_FREELIST_QUERY_SINGLETHREADED_VALIDATE +}; + +/***** structures *****/ +struct lfds700_freelist_element +{ + struct lfds700_freelist_element + *volatile next; + + void + *key, + *value; +}; + +struct lfds700_freelist_state +{ + struct lfds700_freelist_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile top[PAC_SIZE]; + + void LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *user_state; +}; + +/***** public prototypes *****/ +void lfds700_freelist_init_valid_on_current_logical_core( struct lfds700_freelist_state *fs, void *user_state ); + // TRD : used in conjunction with the #define LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE + +void lfds700_freelist_cleanup( struct lfds700_freelist_state *fs, + void (*element_cleanup_callback)(struct lfds700_freelist_state *fs, struct lfds700_freelist_element *fe) ); + +void lfds700_freelist_push( struct lfds700_freelist_state *fs, + struct lfds700_freelist_element *fe, + struct lfds700_misc_prng_state *ps ); + +int lfds700_freelist_pop( struct lfds700_freelist_state *fs, + struct lfds700_freelist_element **fe, + struct lfds700_misc_prng_state *ps ); + +void lfds700_freelist_query( struct lfds700_freelist_state *fs, + enum lfds700_freelist_query query_type, + void *query_input, + void *query_output ); + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_hash_addonly.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_hash_addonly.h new file mode 100644 index 0000000000..f7962db9e0 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_hash_addonly.h @@ -0,0 +1,127 @@ +/***** defines *****/ +#define LFDS700_HASH_A_GET_KEY_FROM_ELEMENT( hash_a_element ) ( (hash_a_element).key ) +#define LFDS700_HASH_A_SET_KEY_IN_ELEMENT( hash_a_element, new_key ) ( (hash_a_element).key = (void *) (lfds700_pal_uint_t) (new_key) ) +#define LFDS700_HASH_A_GET_VALUE_FROM_ELEMENT( hash_a_element ) ( LFDS700_MISC_BARRIER_LOAD, (hash_a_element).value ) +#define LFDS700_HASH_A_SET_VALUE_IN_ELEMENT( hash_a_element, new_value ) { void *local_new_value = (void *) (lfds700_pal_uint_t) (new_value); LFDS700_PAL_ATOMIC_EXCHANGE( &(hash_a_element).value, &local_new_value ); } +#define LFDS700_HASH_A_GET_USER_STATE_FROM_STATE( hash_a_state ) ( (hash_a_state).user_state ) + +#define LFDS700_HASH_A_32BIT_HASH_FUNCTION( data, data_length_in_bytes, hash ) { \ + lfds700_pal_uint_t \ + loop; \ + \ + for( loop = 0 ; loop < (data_length_in_bytes) ; loop++ ) \ + { \ + (hash) += *( (char unsigned *) (data) + loop ); \ + (hash) += ((hash) << 10); \ + (hash) ^= ((hash) >> 6); \ + } \ + \ + (hash) += ((hash) << 3); \ + (hash) ^= ((hash) >> 11); \ + (hash) += ((hash) << 15); \ + } + /* TRD : this is the Jenkins one-at-a-time hash + it produces a 32 bit hash + http://en.wikipedia.org/wiki/Jenkins_hash_function + + we ourselves do *not* initialize the value of *hash, so that + our caller has the option to call us multiple times, each + time with for example a different member of a struct, which is + then hashed into the existing, built-up-so-far hash value, and + so build up a quality hash + */ + +/***** enums *****/ +enum lfds700_hash_a_existing_key +{ + LFDS700_HASH_A_EXISTING_KEY_OVERWRITE, + LFDS700_HASH_A_EXISTING_KEY_FAIL +}; + +enum lfds700_hash_a_insert_result +{ + LFDS700_HASH_A_PUT_RESULT_FAILURE_EXISTING_KEY, + LFDS700_HASH_A_PUT_RESULT_SUCCESS_OVERWRITE, + LFDS700_HASH_A_PUT_RESULT_SUCCESS +}; + +enum lfds700_hash_a_query +{ + LFDS700_HASH_A_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, + LFDS700_HASH_A_QUERY_SINGLETHREADED_VALIDATE +}; + +/***** structs *****/ +struct lfds700_hash_a_element +{ + struct lfds700_btree_au_element + baue; + + void + *key; + + void LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile value; +}; + +struct lfds700_hash_a_iterate +{ + struct lfds700_btree_au_element + *baue; + + struct lfds700_btree_au_state + *baus, + *baus_end; +}; + +struct lfds700_hash_a_state +{ + enum lfds700_hash_a_existing_key + existing_key; + + int + (*key_compare_function)( void const *new_key, void const *existing_key ); + + lfds700_pal_uint_t + array_size; + + struct lfds700_btree_au_state + *baus_array; + + void + (*element_cleanup_callback)( struct lfds700_hash_a_state *has, struct lfds700_hash_a_element *hae ), + (*key_hash_function)( void const *key, lfds700_pal_uint_t *hash ), + *user_state; +}; + +/***** public prototypes *****/ +void lfds700_hash_a_init_valid_on_current_logical_core( struct lfds700_hash_a_state *has, + struct lfds700_btree_au_state *baus_array, + lfds700_pal_uint_t array_size, + int (*key_compare_function)(void const *new_key, void const *existing_key), + void (*key_hash_function)(void const *key, lfds700_pal_uint_t *hash), + enum lfds700_hash_a_existing_key existing_key, + void *user_state ); + // TRD : used in conjunction with the #define LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE + +void lfds700_hash_a_cleanup( struct lfds700_hash_a_state *has, + void (*element_cleanup_function)(struct lfds700_hash_a_state *has, struct lfds700_hash_a_element *hae) ); + +enum lfds700_hash_a_insert_result lfds700_hash_a_insert( struct lfds700_hash_a_state *has, + struct lfds700_hash_a_element *hae, + struct lfds700_hash_a_element **existing_hae, + struct lfds700_misc_prng_state *ps ); + // TRD : if existing_value is not NULL and the key exists, existing_value is set to the value of the existing key + +int lfds700_hash_a_get_by_key( struct lfds700_hash_a_state *has, + void *key, + struct lfds700_hash_a_element **hae ); + +void lfds700_hash_a_iterate_init( struct lfds700_hash_a_state *has, struct lfds700_hash_a_iterate *hai ); +int lfds700_hash_a_iterate( struct lfds700_hash_a_iterate *hai, struct lfds700_hash_a_element **hae ); + +void lfds700_hash_a_query( struct lfds700_hash_a_state *has, + enum lfds700_hash_a_query query_type, + void *query_input, + void *query_output ); + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_list_addonly_ordered_singlylinked.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_list_addonly_ordered_singlylinked.h new file mode 100644 index 0000000000..dffab0aa6b --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_list_addonly_ordered_singlylinked.h @@ -0,0 +1,85 @@ +/***** defines *****/ +#define LFDS700_LIST_AOS_GET_START( list_aos_state ) ( LFDS700_MISC_BARRIER_LOAD, (list_aos_state).start->next ) +#define LFDS700_LIST_AOS_GET_NEXT( list_aos_element ) ( LFDS700_MISC_BARRIER_LOAD, (list_aos_element).next ) +#define LFDS700_LIST_AOS_GET_START_AND_THEN_NEXT( list_aos_state, pointer_to_list_aos_element ) ( (pointer_to_list_aos_element) == NULL ? ( (pointer_to_list_aos_element) = LFDS700_LIST_AOS_GET_START(list_aos_state) ) : ( (pointer_to_list_aos_element) = LFDS700_LIST_AOS_GET_NEXT(*(pointer_to_list_aos_element)) ) ) +#define LFDS700_LIST_AOS_GET_KEY_FROM_ELEMENT( list_aos_element ) ( (list_aos_element).key ) +#define LFDS700_LIST_AOS_SET_KEY_IN_ELEMENT( list_aos_element, new_key ) ( (list_aos_element).key = (void *) (lfds700_pal_uint_t) (new_key) ) +#define LFDS700_LIST_AOS_GET_VALUE_FROM_ELEMENT( list_aos_element ) ( LFDS700_MISC_BARRIER_LOAD, (list_aos_element).value ) +#define LFDS700_LIST_AOS_SET_VALUE_IN_ELEMENT( list_aos_element, new_value ) { void *local_new_value = (void *) (lfds700_pal_uint_t) (new_value); LFDS700_PAL_ATOMIC_EXCHANGE( &(list_aos_element).value, &local_new_value ); } +#define LFDS700_LIST_AOS_GET_USER_STATE_FROM_STATE( list_aos_state ) ( (list_aos_state).user_state ) + +/***** enums *****/ +enum lfds700_list_aos_existing_key +{ + LFDS700_LIST_AOS_EXISTING_KEY_OVERWRITE, + LFDS700_LIST_AOS_EXISTING_KEY_FAIL +}; + +enum lfds700_list_aos_insert_result +{ + LFDS700_LIST_AOS_INSERT_RESULT_FAILURE_EXISTING_KEY, + LFDS700_LIST_AOS_INSERT_RESULT_SUCCESS_OVERWRITE, + LFDS700_LIST_AOS_INSERT_RESULT_SUCCESS +}; + +enum lfds700_list_aos_query +{ + LFDS700_LIST_AOS_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, + LFDS700_LIST_AOS_QUERY_SINGLETHREADED_VALIDATE +}; + +/***** structures *****/ +struct lfds700_list_aos_element +{ + struct lfds700_list_aos_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile next; + + void LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile value; + + void LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *key; +}; + +struct lfds700_list_aos_state +{ + struct lfds700_list_aos_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile start; + + struct lfds700_list_aos_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + dummy_element; + + int LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + (*key_compare_function)( void const *new_key, void const *existing_key ); + + enum lfds700_list_aos_existing_key + existing_key; + + void + *user_state; +}; + +/***** public prototypes *****/ +void lfds700_list_aos_init_valid_on_current_logical_core( struct lfds700_list_aos_state *laoss, + int (*key_compare_function)(void const *new_key, void const *existing_key), + enum lfds700_list_aos_existing_key existing_key, + void *user_state ); + // TRD : used in conjunction with the #define LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE + +void lfds700_list_aos_cleanup( struct lfds700_list_aos_state *laoss, + void (*element_cleanup_callback)(struct lfds700_list_aos_state *laoss, struct lfds700_list_aos_element *laose) ); + +enum lfds700_list_aos_insert_result lfds700_list_aos_insert( struct lfds700_list_aos_state *laoss, + struct lfds700_list_aos_element *laose, + struct lfds700_list_aos_element **existing_laose, + struct lfds700_misc_prng_state *ps ); + +int lfds700_list_aos_get_by_key( struct lfds700_list_aos_state *laoss, + void *key, + struct lfds700_list_aos_element **laose ); + +void lfds700_list_aos_query( struct lfds700_list_aos_state *laoss, + enum lfds700_list_aos_query query_type, + void *query_input, + void *query_output ); + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_list_addonly_singlylinked_unordered.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_list_addonly_singlylinked_unordered.h new file mode 100644 index 0000000000..38d21511a1 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_list_addonly_singlylinked_unordered.h @@ -0,0 +1,90 @@ +/***** defines *****/ +#define LFDS700_LIST_ASU_GET_START( list_asu_state ) ( LFDS700_MISC_BARRIER_LOAD, (list_asu_state).start->next ) +#define LFDS700_LIST_ASU_GET_NEXT( list_asu_element ) ( LFDS700_MISC_BARRIER_LOAD, (list_asu_element).next ) +#define LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT( list_asu_state, pointer_to_list_asu_element ) ( (pointer_to_list_asu_element) == NULL ? ( (pointer_to_list_asu_element) = LFDS700_LIST_ASU_GET_START(list_asu_state) ) : ( (pointer_to_list_asu_element) = LFDS700_LIST_ASU_GET_NEXT(*(pointer_to_list_asu_element)) ) ) +#define LFDS700_LIST_ASU_GET_KEY_FROM_ELEMENT( list_asu_element ) ( (list_asu_element).key ) +#define LFDS700_LIST_ASU_SET_KEY_IN_ELEMENT( list_asu_element, new_key ) ( (list_asu_element).key = (void *) (lfds700_pal_uint_t) (new_key) ) +#define LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( list_asu_element ) ( LFDS700_MISC_BARRIER_LOAD, (list_asu_element).value ) +#define LFDS700_LIST_ASU_SET_VALUE_IN_ELEMENT( list_asu_element, new_value ) { void *local_new_value = (void *) (lfds700_pal_uint_t) (new_value); LFDS700_PAL_ATOMIC_EXCHANGE( &(list_asu_element).value, &local_new_value ); } +#define LFDS700_LIST_ASU_GET_USER_STATE_FROM_STATE( list_asu_state ) ( (list_asu_state).user_state ) + +/***** enums *****/ +enum lfds700_list_asu_position +{ + LFDS700_LIST_ASU_POSITION_START, + LFDS700_LIST_ASU_POSITION_END, + LFDS700_LIST_ASU_POSITION_AFTER +}; + +enum lfds700_list_asu_query +{ + LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, + LFDS700_LIST_ASU_QUERY_SINGLETHREADED_VALIDATE +}; + +/***** structures *****/ +struct lfds700_list_asu_element +{ + struct lfds700_list_asu_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile next; + + void LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile value; + + void LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *key; +}; + +struct lfds700_list_asu_state +{ + struct lfds700_list_asu_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile end, + *volatile start; + + struct lfds700_list_asu_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + dummy_element; + + int LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + (*key_compare_function)( void const *new_key, void const *existing_key ); + + void + *user_state; +}; + +/***** public prototypes *****/ +void lfds700_list_asu_init_valid_on_current_logical_core( struct lfds700_list_asu_state *lasus, + int (*key_compare_function)(void const *new_key, void const *existing_key), + void *user_state ); + // TRD : used in conjunction with the #define LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE + +void lfds700_list_asu_cleanup( struct lfds700_list_asu_state *lasus, + void (*element_cleanup_callback)(struct lfds700_list_asu_state *lasus, struct lfds700_list_asu_element *lasue) ); + +void lfds700_list_asu_insert_at_position( struct lfds700_list_asu_state *lasus, + struct lfds700_list_asu_element *lasue, + struct lfds700_list_asu_element *lasue_predecessor, + enum lfds700_list_asu_position position, + struct lfds700_misc_prng_state *ps ); + +void lfds700_list_asu_insert_at_start( struct lfds700_list_asu_state *lasus, + struct lfds700_list_asu_element *lasue, + struct lfds700_misc_prng_state *ps ); + +void lfds700_list_asu_insert_at_end( struct lfds700_list_asu_state *lasus, + struct lfds700_list_asu_element *lasue, + struct lfds700_misc_prng_state *ps ); + +void lfds700_list_asu_insert_after_element( struct lfds700_list_asu_state *lasus, + struct lfds700_list_asu_element *lasue, + struct lfds700_list_asu_element *lasue_predecessor, + struct lfds700_misc_prng_state *ps ); + +int lfds700_list_asu_get_by_key( struct lfds700_list_asu_state *lasus, + void *key, + struct lfds700_list_asu_element **lasue ); + +void lfds700_list_asu_query( struct lfds700_list_asu_state *lasus, + enum lfds700_list_asu_query query_type, + void *query_input, + void *query_output ); + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_misc.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_misc.h new file mode 100644 index 0000000000..014f72dac5 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_misc.h @@ -0,0 +1,192 @@ +/***** defines *****/ +#define LFDS700_MISC_VERSION_STRING "7.0.0" +#define LFDS700_MISC_VERSION_INTEGER 700 + +#ifndef NULL + #define NULL ( (void *) 0 ) +#endif + +#define POINTER 0 +#define COUNTER 1 +#define PAC_SIZE 2 + +#define LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE 0 +#define LFDS700_MISC_PRNG_MAX ( (lfds700_pal_uint_t) -1 ) +#define LFDS700_MISC_DELIBERATELY_CRASH { char *c = 0; *c = 0; } +#define LFDS700_MISC_PRNG_SEED 0x0a34655d34c092feULL + /* TRD : from an on-line hardware RNG, using atmospheric noise + the URL eblow will generate another 16 random hex digits (e.g. a 64-bit number) and is + the RNG used to generate the number above (0x0a34655d34c092fe) + http://www.random.org/integers/?num=16&min=0&max=15&col=1&base=16&format=plain&rnd=new + + this seed is a fixed seed which is used for the slow, high quality PRNG, + which in turn is used when thread start to generate a single high quality seed + for the fast, low quality PRNG used for the CAS exponential backoff + */ + +#if( LFDS700_PAL_ALIGN_SINGLE_POINTER == 4 ) // TRD : any 32-bit platform + // TRD : PRNG is a 32-bit xorshift, numbers suggested by George Marsaglia, in his paper http://www.jstatsoft.org/v08/i14/paper + #define LFDS700_MISC_PRNG_GENERATE( pointer_to_lfds700_misc_prng_state ) ( (pointer_to_lfds700_misc_prng_state)->prng_state ^= (pointer_to_lfds700_misc_prng_state)->prng_state >> 13, (pointer_to_lfds700_misc_prng_state)->prng_state ^= (pointer_to_lfds700_misc_prng_state)->prng_state << 17, (pointer_to_lfds700_misc_prng_state)->prng_state ^= (pointer_to_lfds700_misc_prng_state)->prng_state >> 5 ) +#endif + +#if( LFDS700_PAL_ALIGN_SINGLE_POINTER == 8 ) // TRD : any 64-bit platform + // TRD : PRNG is 64-bit xorshift (xorshift64*), from Sebastiano Vigna (vigna at acm dot org), http://creativecommons.org/publicdomain/zero/1.0/ + #define LFDS700_MISC_PRNG_GENERATE( pointer_to_lfds700_misc_prng_state ) ( (pointer_to_lfds700_misc_prng_state)->prng_state ^= (pointer_to_lfds700_misc_prng_state)->prng_state >> 12, (pointer_to_lfds700_misc_prng_state)->prng_state ^= (pointer_to_lfds700_misc_prng_state)->prng_state << 25, (pointer_to_lfds700_misc_prng_state)->prng_state ^= (pointer_to_lfds700_misc_prng_state)->prng_state >> 27, (pointer_to_lfds700_misc_prng_state)->prng_state *= 2685821657736338717LL ) +#endif + +#if( !defined LFDS700_PAL_ATOMIC_CAS ) + #define LFDS700_PAL_NO_ATOMIC_CAS + + // TRD : lfds700_pal_atom_t volatile *destination, lfds700_pal_atom_t *compare, lfds700_pal_atom_t new_destination, enum lfds700_misc_cas_strength cas_strength, char unsigned result + + #define LFDS700_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \ + { \ + LFDS700_PAL_ASSERT( !"LFDS700_PAL_ATOMIC_CAS not implemented for this platform." ); \ + LFDS700_MISC_DELIBERATELY_CRASH; \ + (result) = (char unsigned) 1; \ + } +#endif + +#if( !defined LFDS700_PAL_ATOMIC_DWCAS ) + #define LFDS700_PAL_NO_ATOMIC_DWCAS + + // TRD : lfds700_pal_atom_t volatile (*destination)[2], lfds700_pal_atom_t (*compare)[2], lfds700_pal_atom_t (*new_destination)[2], enum lfds700_misc_cas_strength cas_strength, unsigned char result + + #define LFDS700_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \ + { \ + LFDS700_PAL_ASSERT( !"LFDS700_PAL_ATOMIC_DWCAS not implemented for this platform." ); \ + LFDS700_MISC_DELIBERATELY_CRASH; \ + (result) = (char unsigned) 1; \ + } +#endif + +#if( !defined LFDS700_PAL_ATOMIC_EXCHANGE ) + #define LFDS700_PAL_NO_ATOMIC_EXCHANGE + // TRD : lfds700_pal_atom_t volatile *destination, lfds700_pal_atom_t *exchange + #define LFDS700_PAL_ATOMIC_EXCHANGE( pointer_to_destination, pointer_to_exchange ) \ + { \ + LFDS700_PAL_ASSERT( !"LFDS700_PAL_ATOMIC_EXCHANGE not implemented for this platform." ); \ + LFDS700_MISC_DELIBERATELY_CRASH; \ + } +#endif + +#if( defined LFDS700_PAL_NO_COMPILER_BARRIERS ) + #define LFDS700_MISC_BARRIER_LOAD ( LFDS700_PAL_BARRIER_PROCESSOR_LOAD ) + #define LFDS700_MISC_BARRIER_STORE ( LFDS700_PAL_BARRIER_PROCESSOR_STORE ) + #define LFDS700_MISC_BARRIER_FULL ( LFDS700_PAL_BARRIER_PROCESSOR_FULL ) +#else + #define LFDS700_MISC_BARRIER_LOAD ( LFDS700_PAL_BARRIER_COMPILER_LOAD, LFDS700_PAL_BARRIER_PROCESSOR_LOAD, LFDS700_PAL_BARRIER_COMPILER_LOAD ) + #define LFDS700_MISC_BARRIER_STORE ( LFDS700_PAL_BARRIER_COMPILER_STORE, LFDS700_PAL_BARRIER_PROCESSOR_STORE, LFDS700_PAL_BARRIER_COMPILER_STORE ) + #define LFDS700_MISC_BARRIER_FULL ( LFDS700_PAL_BARRIER_COMPILER_FULL, LFDS700_PAL_BARRIER_PROCESSOR_FULL, LFDS700_PAL_BARRIER_COMPILER_FULL ) +#endif + +#define LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE LFDS700_MISC_BARRIER_LOAD + +#if( defined LFDS700_PAL_NO_ATOMIC_CAS ) + #define LFDS700_MISC_ATOMIC_SUPPORT_CAS 0 +#else + #define LFDS700_MISC_ATOMIC_SUPPORT_CAS 1 +#endif + +#if( defined LFDS700_PAL_NO_ATOMIC_DWCAS ) + #define LFDS700_MISC_ATOMIC_SUPPORT_DWCAS 0 +#else + #define LFDS700_MISC_ATOMIC_SUPPORT_DWCAS 1 +#endif + +#if( defined LFDS700_PAL_NO_ATOMIC_EXCHANGE ) + #define LFDS700_MISC_ATOMIC_SUPPORT_EXCHANGE 0 +#else + #define LFDS700_MISC_ATOMIC_SUPPORT_EXCHANGE 1 +#endif + +/***** enums *****/ +enum lfds700_misc_cas_strength +{ + // TRD : yes, weak is 1 (one) - blame GCC! + LFDS700_MISC_CAS_STRENGTH_WEAK = 1, + LFDS700_MISC_CAS_STRENGTH_STRONG = 0 +}; + +enum lfds700_misc_validity +{ + LFDS700_MISC_VALIDITY_VALID, + LFDS700_MISC_VALIDITY_INVALID_LOOP, + LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS, + LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS, + LFDS700_MISC_VALIDITY_INVALID_TEST_DATA, + LFDS700_MISC_VALIDITY_INVALID_ORDER +}; + +enum lfds700_misc_flag +{ + LFDS700_MISC_FLAG_LOWERED, + LFDS700_MISC_FLAG_RAISED +}; + +enum lfds700_misc_query +{ + LFDS700_MISC_QUERY_GET_EXPONENTIAL_BACKOFF_TIMESLOT_LENGTH_IN_LOOP_ITERATIONS_FOR_CAS, + LFDS700_MISC_QUERY_SET_EXPONENTIAL_BACKOFF_TIMESLOT_LENGTH_IN_LOOP_ITERATIONS_FOR_CAS, + LFDS700_MISC_QUERY_GET_EXPONENTIAL_BACKOFF_TIMESLOT_LENGTH_IN_LOOP_ITERATIONS_FOR_DWCAS, + LFDS700_MISC_QUERY_SET_EXPONENTIAL_BACKOFF_TIMESLOT_LENGTH_IN_LOOP_ITERATIONS_FOR_DWCAS, + LFDS700_MISC_QUERY_GET_BUILD_AND_VERSION_STRING +}; + +/***** struct *****/ +struct lfds700_misc_globals +{ + lfds700_pal_atom_t + exponential_backoff_timeslot_length_in_loop_iterations_for_cas, + exponential_backoff_timeslot_length_in_loop_iterations_for_dwcas; +}; + +struct lfds700_misc_prng_state +{ + lfds700_pal_uint_t + prng_state; + + // TRD : here to be on the same cache-line as prng_state, and so all are obtained from one cache-line read + lfds700_pal_atom_t + local_copy_of_global_exponential_backoff_timeslot_length_in_loop_iterations_for_cas, + local_copy_of_global_exponential_backoff_timeslot_length_in_loop_iterations_for_dwcas; +}; + +struct lfds700_misc_validation_info +{ + lfds700_pal_uint_t + min_elements, + max_elements; +}; + +/***** externs *****/ +extern struct lfds700_misc_globals + lfds700_misc_globals; + +/***** public prototypes *****/ +void lfds700_misc_library_init_valid_on_current_logical_core( void ); + // TRD : used in conjunction with the #define LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE +void lfds700_misc_library_cleanup( void ); + +static LFDS700_PAL_INLINE void lfds700_misc_force_store( void ); + +void lfds700_misc_prng_init( struct lfds700_misc_prng_state *ps ); + +void lfds700_misc_query( enum lfds700_misc_query query_type, void *query_input, void *query_output ); + +/***** public in-line functions *****/ +#pragma prefast( disable : 28112, "blah" ) + +static LFDS700_PAL_INLINE void lfds700_misc_force_store() +{ + lfds700_pal_uint_t + exchange = 0; + + lfds700_pal_atom_t volatile LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + destination; + + LFDS700_PAL_ATOMIC_EXCHANGE( &destination, &exchange ); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_porting_abstraction_layer_compiler.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_porting_abstraction_layer_compiler.h new file mode 100644 index 0000000000..c628ddd03a --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_porting_abstraction_layer_compiler.h @@ -0,0 +1,478 @@ +/****************************************************************************/ +#if( defined __GNUC__ ) + // TRD : makes checking GCC versions much tidier + #define LFDS700_PAL_GCC_VERSION ( __GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__ ) +#endif + + + + + +/****************************************************************************/ +#if( defined _MSC_VER && _MSC_VER >= 1400 ) + + /* TRD : MSVC 8.0 and greater + + _MSC_VER indicates Microsoft C compiler and version + - __declspec(align) requires 7.1 (1310) + - __nop requires 8.0 (1400) + - _ReadBarrier requires 8.0 (1400) + - _WriteBarrier requires 8.0 (1400) + - _ReadWriteBarrier requires 7.1 (1310) + - _InterlockedCompareExchangePointer requires 8.0 (1400) + - _InterlockedExchange requires 7.1 (1310) + - _InterlockedExchangePointer requires 8.0 (1400) + - _InterlockedCompareExchange64 requires 8.0 (1400) (seems to, docs unclear) + - _InterlockedCompareExchange128 requires 9.0 (1500) + + load/store barriers are mandatory for liblfds, which means the earliest viable version of MSCV is 1400 + strictly we could get away with 1310 and use _ReadWriteBarrier, but the difference between 1310 and 1400 is small, so WTH + + _InterlockedCompareExchange128 is needed on 64-bit platforms to provide DWCAS, but DWCAS is not mandatory, + so we check against the compiler version - remember, any unimplemented atomic will be masked by its dummy define, + so everything will compile - it just means you can't use data structures which require that atomic + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_COMPILER + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_compiler.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_COMPILER + + #define LFDS700_PAL_COMPILER_STRING "MSVC" + + #define LFDS700_PAL_ALIGN(alignment) __declspec( align(alignment) ) + #define LFDS700_PAL_INLINE __forceinline + + #define LFDS700_PAL_BARRIER_COMPILER_LOAD _ReadBarrier() + #define LFDS700_PAL_BARRIER_COMPILER_STORE _WriteBarrier() + #define LFDS700_PAL_BARRIER_COMPILER_FULL _ReadWriteBarrier() + + /* TRD : there are four processors to consider; + + . ARM32 (32 bit, CAS, DWCAS) (defined _M_ARM) + . Itanium (64 bit, CAS) (defined _M_IA64) + . x64 (64 bit, CAS, DWCAS) (defined _M_X64 || defined _M_AMD64) + . x86 (32 bit, CAS, DWCAS) (defined _M_IX86) + + can't find any indications of 64-bit ARM support yet + + ARM has better intrinsics than the others, as there are no-fence variants + + in theory we also have to deal with 32-bit Windows on a 64-bit platform, + and I presume we'd see the compiler properly indicate this in its macros, + but this would require that we use 32-bit atomics on the 64-bit platforms, + while keeping 64-bit cache line lengths and so on, and this is just so + wierd a thing to do these days that it's not supported + + note that _InterlockedCompareExchangePointer performs CAS on all processors + however, it is documented as being available for x86 when in fact it is not + so we have to #if for processor type and use the length specific intrinsics + */ + + #if( defined _M_ARM ) + #define LFDS700_PAL_BARRIER_PROCESSOR_LOAD __dmb( _ARM_BARRIER_ISH ) + #define LFDS700_PAL_BARRIER_PROCESSOR_STORE __dmb( _ARM_BARRIER_ISHST ) + #define LFDS700_PAL_BARRIER_PROCESSOR_FULL __dmb( _ARM_BARRIER_ISH ) + + #define LFDS700_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \ + { \ + lfds700_pal_atom_t \ + original_compare; \ + \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \ + /* TRD : new_destination can be any value in its range */ \ + /* TRD : cas_strength can be any value in its range */ \ + /* TRD : result can be any value in its range */ \ + \ + original_compare = (lfds700_pal_atom_t) *(pointer_to_compare); \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + *(lfds700_pal_atom_t *) (pointer_to_compare) = (lfds700_pal_atom_t) _InterlockedCompareExchange_nf( (long volatile *) (pointer_to_destination), (long) (new_destination), (long) *(pointer_to_compare) ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + \ + result = (char unsigned) ( original_compare == (lfds700_pal_atom_t) *(pointer_to_compare) ); \ + } + + #define LFDS700_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \ + { \ + __int64 \ + original_compare; \ + \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_new_destination) != NULL ); */ \ + /* TRD : cas_strength can be any value in its range */ \ + /* TRD : result can be any value in its range */ \ + \ + original_compare = *(__int64 *) (pointer_to_compare); \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + *(__int64 *) (pointer_to_compare) = _InterlockedCompareExchange64_nf( (__int64 volatile *) (pointer_to_destination), *(__int64 *) (pointer_to_new_destination), *(__int64 *) (pointer_to_compare) ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + \ + result = (char unsigned) ( *(__int64 *) (pointer_to_compare) == original_compare ); \ + } + + #define LFDS700_PAL_ATOMIC_EXCHANGE( pointer_to_destination, pointer_to_exchange ) \ + { \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_exchange) != NULL ); */ \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + *(lfds700_pal_atom_t *) (pointer_to_exchange) = (lfds700_pal_atom_t) _InterlockedExchange_nf( (int long volatile *) (pointer_to_destination), (int long) *(pointer_to_exchange) ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + } + #endif + + #if( defined _M_IA64 ) + #define LFDS700_PAL_BARRIER_PROCESSOR_LOAD __mf() + #define LFDS700_PAL_BARRIER_PROCESSOR_STORE __mf() + #define LFDS700_PAL_BARRIER_PROCESSOR_FULL __mf() + + #define LFDS700_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \ + { \ + lfds700_pal_atom_t \ + original_compare; \ + \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \ + /* TRD : new_destination can be any value in its range */ \ + /* TRD : cas_strength can be any value in its range */ \ + /* TRD : result can be any value in its range */ \ + \ + original_compare = (lfds700_pal_atom_t) *(pointer_to_compare); \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + *(lfds700_pal_atom_t *) (pointer_to_compare) = (lfds700_pal_atom_t) _InterlockedCompareExchange64_acq( (__int64 volatile *) (pointer_to_destination), (__int64) (new_destination), (__int64) *(pointer_to_compare) ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + \ + result = (char unsigned) ( original_compare == (lfds700_pal_atom_t) *(pointer_to_compare) ); \ + } + + #define LFDS700_PAL_ATOMIC_EXCHANGE( pointer_to_destination, pointer_to_exchange ) \ + { \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_exchange) != NULL ); */ \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + *(lfds700_pal_atom_t *) (pointer_to_exchange) = (lfds700_pal_atom_t) _InterlockedExchange64_acq( (__int64 volatile *) (pointer_to_destination), (__int64) *(pointer_to_exchange) ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + } + #endif + + #if( defined _M_X64 || defined _M_AMD64 ) + #define LFDS700_PAL_BARRIER_PROCESSOR_LOAD _mm_lfence() + #define LFDS700_PAL_BARRIER_PROCESSOR_STORE _mm_sfence() + #define LFDS700_PAL_BARRIER_PROCESSOR_FULL _mm_mfence() + + #define LFDS700_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \ + { \ + lfds700_pal_atom_t \ + original_compare; \ + \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \ + /* TRD : new_destination can be any value in its range */ \ + /* TRD : cas_strength can be any value in its range */ \ + /* TRD : result can be any value in its range */ \ + \ + original_compare = (lfds700_pal_atom_t) *(pointer_to_compare); \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + *(lfds700_pal_atom_t *) (pointer_to_compare) = (lfds700_pal_atom_t) _InterlockedCompareExchange64( (__int64 volatile *) (pointer_to_destination), (__int64) (new_destination), (__int64) *(pointer_to_compare) ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + \ + result = (char unsigned) ( original_compare == (lfds700_pal_atom_t) *(pointer_to_compare) ); \ + } + + #if( _MSC_VER >= 1500 ) + #define LFDS700_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \ + { \ + /* LFDS700_PAL_ASSERT( (pointer_to_new_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \ + /* TRD : cas_strength can be any value in its range */ \ + /* TRD : result can be any value in its range */ \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + result = (char unsigned) _InterlockedCompareExchange128( (__int64 volatile *) (pointer_to_destination), (__int64) (pointer_to_new_destination[1]), (__int64) (pointer_to_new_destination[0]), (__int64 *) (pointer_to_compare) ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + } + #endif + + #define LFDS700_PAL_ATOMIC_EXCHANGE( pointer_to_destination, pointer_to_exchange ) \ + { \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_exchange) != NULL ); */ \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + *(lfds700_pal_atom_t *) (pointer_to_exchange) = (lfds700_pal_atom_t) _InterlockedExchangePointer( (void * volatile *) (pointer_to_destination), (void *) *(pointer_to_exchange) ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + } + #endif + + #if( defined _M_IX86 ) + #define LFDS700_PAL_BARRIER_PROCESSOR_LOAD lfds700_misc_force_store() + #define LFDS700_PAL_BARRIER_PROCESSOR_STORE lfds700_misc_force_store() + #define LFDS700_PAL_BARRIER_PROCESSOR_FULL lfds700_misc_force_store() + + #define LFDS700_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \ + { \ + lfds700_pal_atom_t \ + original_compare; \ + \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \ + /* TRD : new_destination can be any value in its range */ \ + /* TRD : cas_strength can be any value in its range */ \ + /* TRD : result can be any value in its range */ \ + \ + original_compare = (lfds700_pal_atom_t) *(pointer_to_compare); \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + *(lfds700_pal_atom_t *) (pointer_to_compare) = (lfds700_pal_atom_t) _InterlockedCompareExchange( (long volatile *) (pointer_to_destination), (long) (new_destination), (long) *(pointer_to_compare) ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + \ + result = (char unsigned) ( original_compare == (lfds700_pal_atom_t) *(pointer_to_compare) ); \ + } + + #define LFDS700_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \ + { \ + __int64 \ + original_compare; \ + \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_new_destination) != NULL ); */ \ + /* TRD : cas_strength can be any value in its range */ \ + /* TRD : result can be any value in its range */ \ + \ + original_compare = *(__int64 *) (pointer_to_compare); \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + *(__int64 *) (pointer_to_compare) = _InterlockedCompareExchange64( (__int64 volatile *) (pointer_to_destination), *(__int64 *) (pointer_to_new_destination), *(__int64 *) (pointer_to_compare) ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + \ + result = (char unsigned) ( *(__int64 *) (pointer_to_compare) == original_compare ); \ + } + + #define LFDS700_PAL_ATOMIC_EXCHANGE( pointer_to_destination, pointer_to_exchange ) \ + { \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_exchange) != NULL ); */ \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + *(lfds700_pal_atom_t *) (pointer_to_exchange) = (lfds700_pal_atom_t) _InterlockedExchange( (int long volatile *) (pointer_to_destination), (int long) *(pointer_to_exchange) ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + } + #endif + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && LFDS700_PAL_GCC_VERSION >= 412 && LFDS700_PAL_GCC_VERSION < 473 ) + + /* TRD : GCC 4.1.2 up to 4.7.3 + + __GNUC__ indicates GCC + LFDS700_PAL_GCC_VERSION indicates which version + - __sync_synchronize requires 4.1.2 + + GCC 4.1.2 introduced the __sync_*() atomic intrinsics + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_COMPILER + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_compiler.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_COMPILER + + #define LFDS700_PAL_COMPILER_STRING "GCC < 4.7.3" + + #define LFDS700_PAL_ALIGN(alignment) __attribute__( (aligned(alignment)) ) + #define LFDS700_PAL_INLINE inline + + static LFDS700_PAL_INLINE void lfds700_pal_barrier_compiler( void ) + { + __asm__ __volatile__ ( "" : : : "memory" ); + } + + #define LFDS700_PAL_BARRIER_COMPILER_LOAD lfds700_pal_barrier_compiler() + #define LFDS700_PAL_BARRIER_COMPILER_STORE lfds700_pal_barrier_compiler() + #define LFDS700_PAL_BARRIER_COMPILER_FULL lfds700_pal_barrier_compiler() + + #define LFDS700_PAL_BARRIER_PROCESSOR_LOAD __sync_synchronize() + #define LFDS700_PAL_BARRIER_PROCESSOR_STORE __sync_synchronize() + #define LFDS700_PAL_BARRIER_PROCESSOR_FULL __sync_synchronize() + + #define LFDS700_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \ + { \ + lfds700_pal_atom_t \ + original_compare; \ + \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \ + /* TRD : new_destination can be any value in its range */ \ + /* TRD : cas_strength can be any value in its range */ \ + /* TRD : result can be any value in its range */ \ + \ + original_compare = (lfds700_pal_atom_t) *(pointer_to_compare); \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + *(pointer_to_compare) = __sync_val_compare_and_swap( pointer_to_destination, *(pointer_to_compare), new_destination ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + \ + result = (unsigned char) ( original_compare == (lfds700_pal_atom_t) *(pointer_to_compare) ); \ + } + + // TRD : ARM and x86 have DWCAS which we can get via GCC intrinsics + #if( defined __arm__ || defined __i686__ || defined __i586__ || defined __i486__ ) + #define LFDS700_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \ + { \ + int long long unsigned \ + original_destination; \ + \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_new_destination) != NULL ); */ \ + /* TRD : cas_strength can be any value in its range */ \ + /* TRD : result can be any value in its range */ \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + original_destination = __sync_val_compare_and_swap( (int long long unsigned volatile *) (pointer_to_destination), *(int long long unsigned *) (pointer_to_compare), *(int long long unsigned *) (pointer_to_new_destination) ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + \ + result = (char unsigned) ( original_destination == *(int long long unsigned *) (pointer_to_compare) ); \ + \ + *(int long long unsigned *) (pointer_to_compare) = original_destination; \ + } + #endif + + #define LFDS700_PAL_ATOMIC_EXCHANGE( pointer_to_destination, pointer_to_exchange ) \ + { \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_exchange) != NULL ); */ \ + \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + *( (lfds700_pal_atom_t *) pointer_to_exchange) = (lfds700_pal_atom_t) __sync_lock_test_and_set( pointer_to_destination, *(pointer_to_exchange) ); \ + LFDS700_PAL_BARRIER_COMPILER_FULL; \ + } + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && LFDS700_PAL_GCC_VERSION >= 473 ) + + /* TRD : GCC 4.7.3 and greater + + __GNUC__ indicates GCC + LFDS700_PAL_GCC_VERSION indicates which version + - __atomic_thread_fence requires 4.7.3 + + GCC 4.7.3 introduced the better __atomic*() atomic intrinsics + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_COMPILER + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_compiler.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_COMPILER + + #define LFDS700_PAL_COMPILER_STRING "GCC >= 4.7.3" + + #define LFDS700_PAL_ALIGN(alignment) __attribute__( (aligned(alignment)) ) + #define LFDS700_PAL_INLINE inline + + // TRD : GCC >= 4.7.3 compiler barriers are built into the intrinsics + #define LFDS700_PAL_NO_COMPILER_BARRIERS + + #define LFDS700_PAL_BARRIER_PROCESSOR_LOAD __atomic_thread_fence( __ATOMIC_ACQUIRE ) + #define LFDS700_PAL_BARRIER_PROCESSOR_STORE __atomic_thread_fence( __ATOMIC_RELEASE ) + #define LFDS700_PAL_BARRIER_PROCESSOR_FULL __atomic_thread_fence( __ATOMIC_ACQ_REL ) + + #define LFDS700_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \ + { \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \ + /* TRD : new_destination can be any value in its range */ \ + /* TRD : cas_strength can be any value in its range */ \ + /* TRD : result can be any value in its range */ \ + \ + result = (char unsigned) __atomic_compare_exchange_n( pointer_to_destination, (void *) (pointer_to_compare), (new_destination), (cas_strength), __ATOMIC_RELAXED, __ATOMIC_RELAXED ); \ + } + + // TRD : ARM and x86 have DWCAS which we can get via GCC intrinsics + #if( defined __arm__ || defined __i686__ || defined __i586__ || defined __i486__ ) + #define LFDS700_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \ + { \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_new_destination) != NULL ); */ \ + /* TRD : cas_strength can be any value in its range */ \ + /* TRD : result can be any value in its range */ \ + \ + (result) = (char unsigned) __atomic_compare_exchange_n( (int long long unsigned volatile *) (pointer_to_destination), (int long long unsigned *) (pointer_to_compare), *(int long long unsigned *) (pointer_to_new_destination), (cas_strength), __ATOMIC_RELAXED, __ATOMIC_RELAXED ); \ + } + #endif + + #if( defined __x86_64__ ) + /* TRD : __GNUC__ indicates GCC + - __asm__ requires GCC + - __volatile__ requires GCC + __x86_64__ indicates x64 + - cmpxchg16b requires x64 + + On 64 bit platforms, unsigned long long int is 64 bit, so we must manually use cmpxchg16b, + as __sync_val_compare_and_swap() will only emit cmpxchg8b + */ + + // TRD : lfds700_pal_atom_t volatile (*destination)[2], lfds700_pal_atom_t (*compare)[2], lfds700_pal_atom_t (*new_destination)[2], enum lfds700_misc_cas_strength cas_strength, char unsigned result + + #define LFDS700_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \ + { \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_new_destination) != NULL ); */ \ + /* TRD : cas_strength can be any value in its range */ \ + /* TRD : result can be any value in its range */ \ + \ + (result) = 0; \ + \ + __asm__ __volatile__ \ + ( \ + "lock;" /* make cmpxchg16b atomic */ \ + "cmpxchg16b %0;" /* cmpxchg16b sets ZF on success */ \ + "setz %3;" /* if ZF set, set result to 1 */ \ + \ + /* output */ \ + : "+m" (*pointer_to_destination), "+a" ((pointer_to_compare)[0]), "+d" ((pointer_to_compare)[1]), "=q" (result) \ + \ + /* input */ \ + : "b" ((pointer_to_new_destination)[0]), "c" ((pointer_to_new_destination)[1]) \ + \ + /* clobbered */ \ + : "cc", "memory" \ + ); \ + } + #endif + + #define LFDS700_PAL_ATOMIC_EXCHANGE( pointer_to_destination, pointer_to_exchange ) \ + { \ + /* LFDS700_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ + /* LFDS700_PAL_ASSERT( (pointer_to_exchange) != NULL ); */ \ + \ + *(pointer_to_exchange) = __atomic_exchange_n( (pointer_to_destination), *(pointer_to_exchange), __ATOMIC_RELAXED ); \ + } + +#endif + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_porting_abstraction_layer_operating_system.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_porting_abstraction_layer_operating_system.h new file mode 100644 index 0000000000..0c1eba628a --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_porting_abstraction_layer_operating_system.h @@ -0,0 +1,133 @@ +/****************************************************************************/ +#if( defined _MSC_VER ) + /* TRD : MSVC compiler + + an unfortunately necessary hack for MSVC + MSVC only defines __STDC__ if /Za is given, where /Za turns off MSVC C extensions - + which prevents Windows header files from compiling. + */ + + #define __STDC__ 1 + #define __STDC_HOSTED__ 1 +#endif + + + + + +/****************************************************************************/ +#if( defined _MSC_VER && _MSC_VER >= 1400 && __STDC_HOSTED__ == 1 && !defined _KERNEL_MODE ) + + // TRD : MSVC + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_OPERATING_SYSTEM + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_operating_system.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_OPERATING_SYSTEM + + #include + + #define LFDS700_PAL_OS_STRING "Windows" + #define LFDS700_PAL_ASSERT( expression ) assert( expression ) + +#endif + + + + + +/****************************************************************************/ +#if( defined _MSC_VER && _MSC_VER >= 1400 && defined __STDC_HOSTED__ && __STDC_HOSTED__ == 1 && defined _WIN32 && defined _KERNEL_MODE ) + + // TRD : MSVC, Windows kernel-mode + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_OPERATING_SYSTEM + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_operating_system.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_OPERATING_SYSTEM + + #include + #include + + #define LFDS700_PAL_OS_STRING "Windows" + #define LFDS700_PAL_ASSERT( expression ) assert( expression ) + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && __STDC_HOSTED__ == 1 && !(defined __linux__ && defined _KERNEL_MODE) ) + + // TRD : GCC, hosted implementation (except for Linux kernel mode) + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_OPERATING_SYSTEM + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_operating_system.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_OPERATING_SYSTEM + + #include + + #define LFDS700_PAL_OS_STRING "Embedded (hosted)" + #define LFDS700_PAL_ASSERT( expression ) assert( expression ) + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && __STDC_HOSTED__ == 0 ) + + // TRD : GCC, freestanding or bare implementation + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_OPERATING_SYSTEM + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_operating_system.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_OPERATING_SYSTEM + + #define LFDS700_PAL_OS_STRING "Embedded (freestanding/bare)" + #define LFDS700_PAL_ASSERT( expression ) + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __linux__ && defined _KERNEL_MODE ) + + // TRD : GCC, Linux kernel-mode + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_OPERATING_SYSTEM + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_operating_system.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_OPERATING_SYSTEM + + #include + + #define LFDS700_PAL_OS_STRING "Linux" + #define LFDS700_PAL_ASSERT( expression ) BUG_ON( expression ) + +#endif + + + + + +/****************************************************************************/ +#if( !defined LFDS700_PAL_PORTING_ABSTRACTION_LAYER_OPERATING_SYSTEM ) + + #error No matching porting abstraction layer in lfds700_porting_abstraction_layer_operating_system.h + +#endif + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_porting_abstraction_layer_processor.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_porting_abstraction_layer_processor.h new file mode 100644 index 0000000000..1e81c0eae2 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_porting_abstraction_layer_processor.h @@ -0,0 +1,544 @@ +/****************************************************************************/ +#if( defined _MSC_VER && _MSC_VER >= 1400 && defined _M_IX86 ) + + /* TRD : MSVC, x86 + x86 is CAS, so isolation is cache-line length + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long unsigned lfds700_pal_atom_t; + typedef int long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "x86" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 4 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 8 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 32 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 32 + +#endif + + + + + +/****************************************************************************/ +#if( defined _MSC_VER && _MSC_VER >= 1400 && (defined _M_X64 || defined _M_AMD64) ) + + /* TRD : MSVC, x64 + x64 is CAS, so isolation is cache-line length + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long long unsigned lfds700_pal_atom_t; + typedef int long long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "x64" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 8 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 16 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 64 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 64 + +#endif + + + + + +/****************************************************************************/ +#if( defined _MSC_VER && _MSC_VER >= 1400 && defined _M_IA64 ) + + /* TRD : MSVC, Itanium + IA64 is CAS, so isolation is cache-line length + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long long unsigned lfds700_pal_atom_t; + typedef int long long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "IA64" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 8 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 16 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 64 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 64 + +#endif + + + + + + /****************************************************************************/ +#if( defined _MSC_VER && _MSC_VER >= 1400 && defined _M_ARM ) + + /* TRD : MSVC, 32-bit ARM + + ARM is LL/SC and uses a reservation granule of 8 to 2048 bytes + so the isolation value used here is worst-case - be sure to set + this correctly, otherwise structures are painfully large + */ + +#ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR +#error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h +#endif + +#define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long unsigned lfds700_pal_atom_t; + typedef int long unsigned lfds700_pal_uint_t; + +#define LFDS700_PAL_PROCESSOR_STRING "ARM (32-bit)" + +#define LFDS700_PAL_ALIGN_SINGLE_POINTER 4 +#define LFDS700_PAL_ALIGN_DOUBLE_POINTER 8 + +#define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 32 +#define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 2048 + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __arm__ ) + + /* TRD : GCC, 32-bit ARM + + ARM is LL/SC and uses a reservation granule of 8 to 2048 bytes + so the isolation value used here is worst-case - be sure to set + this correctly, otherwise structures are painfully large + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long unsigned lfds700_pal_atom_t; + typedef int long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "ARM (32-bit)" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 4 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 8 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 32 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 2048 + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __aarch64__ ) + + /* TRD : GCC, 64-bit ARM + + ARM is LL/SC and uses a reservation granule of 8 to 2048 bytes + so the isolation value used here is worst-case - be sure to set + this correctly, otherwise structures are painfully large + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long long unsigned lfds700_pal_atom_t; + typedef int long long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "ARM (64-bit)" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 8 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 16 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 64 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 2048 + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && (defined __i686__ || defined __i586__ || defined __i486__) ) + + /* TRD : GCC, x86 + + x86 is CAS, so isolation is cache-line length + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long unsigned lfds700_pal_atom_t; + typedef int long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "x86" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 4 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 8 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 32 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 32 + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __x86_64__ ) + + /* TRD : GCC, x86 + + x64 is CAS, so isolation is cache-line length + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long long unsigned lfds700_pal_atom_t; + typedef int long long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "x64" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 8 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 16 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 64 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 64 + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __alpha__ ) + + /* TRD : GCC, alpha + + alpha is LL/SC, but there is only one reservation per processor, + so the isolation value used here is cache-line length + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long unsigned lfds700_pal_atom_t; + typedef int long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "alpha" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 8 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 16 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 32 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 64 + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __ia64__ ) + + /* TRD : GCC, Itanium + + Itanium is CAS, so isolation is cache-line length + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long long unsigned lfds700_pal_atom_t; + typedef int long long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "IA64" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 8 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 16 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 64 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 64 + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __mips__ ) + + /* TRD : GCC, MIPS (32-bit) + + MIPS is LL/SC, but there is only one reservation per processor, + so the isolation value used here is cache-line length + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long unsigned lfds700_pal_atom_t; + typedef int long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "MIPS (32-bit)" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 4 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 8 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 32 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 32 + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __mips64 ) + + /* TRD : GCC, MIPS (64-bit) + + MIPS is LL/SC, but there is only one reservation per processor, + so the isolation value used here is cache-line length + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long long unsigned lfds700_pal_atom_t; + typedef int long long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "MIPS (64-bit)" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 8 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 16 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 64 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 64 + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __ppc__ ) + + /* TRD : GCC, POWERPC (32-bit) + + POWERPC is LL/SC and uses a reservation granule but I can't find + canonical documentation for its size - 128 bytes seems to be the + largest value I've found + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long unsigned lfds700_pal_atom_t; + typedef int long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "POWERPC (32-bit)" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 4 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 8 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 32 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 128 + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __ppc64__ ) + + /* TRD : GCC, POWERPC (64-bit) + + POWERPC is LL/SC and uses a reservation granule but I can't find + canonical documentation for its size - 128 bytes seems to be the + largest value I've found + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long long unsigned lfds700_pal_atom_t; + typedef int long long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "POWERPC (64-bit)" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 8 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 16 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 64 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 128 + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __sparc__ && !defined __sparc_v9__ ) + + /* TRD : GCC, SPARC (32-bit) + + SPARC is CAS, so isolation is cache-line length + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long unsigned lfds700_pal_atom_t; + typedef int long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "SPARC (32-bit)" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 4 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 8 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 32 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 32 + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __sparc__ && defined __sparc_v9__ ) + + /* TRD : GCC, SPARC (64-bit) + + SPARC is CAS, so isolation is cache-line length + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long long unsigned lfds700_pal_atom_t; + typedef int long long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "SPARC (64-bit)" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 8 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 16 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 64 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 64 + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __m68k__ ) + + /* TRD : GCC, 680x0 + + 680x0 is CAS, so isolation is cache-line length + */ + + #ifdef LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + #error More than one porting abstraction layer matches the current platform in lfds700_porting_abstraction_layer_processor.h + #endif + + #define LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR + + typedef int long unsigned lfds700_pal_atom_t; + typedef int long unsigned lfds700_pal_uint_t; + + #define LFDS700_PAL_PROCESSOR_STRING "680x0" + + #define LFDS700_PAL_ALIGN_SINGLE_POINTER 4 + #define LFDS700_PAL_ALIGN_DOUBLE_POINTER 8 + + #define LFDS700_PAL_CACHE_LINE_LENGTH_IN_BYTES 32 + #define LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES 32 + +#endif + + + + + +/****************************************************************************/ +#if( !defined LFDS700_PAL_PORTING_ABSTRACTION_LAYER_PROCESSOR ) + + #error No matching porting abstraction layer in lfds700_porting_abstraction_layer_processor.h + +#endif + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_queue.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_queue.h new file mode 100644 index 0000000000..025b0673e9 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_queue.h @@ -0,0 +1,60 @@ +/***** defines *****/ +#define LFDS700_QUEUE_GET_KEY_FROM_ELEMENT( queue_element ) ( (queue_element).key ) +#define LFDS700_QUEUE_SET_KEY_IN_ELEMENT( queue_element, new_key ) ( (queue_element).key = (void *) (lfds700_pal_uint_t) (new_key) ) +#define LFDS700_QUEUE_GET_VALUE_FROM_ELEMENT( queue_element ) ( (queue_element).value ) +#define LFDS700_QUEUE_SET_VALUE_IN_ELEMENT( queue_element, new_value ) ( (queue_element).value = (void *) (lfds700_pal_uint_t) (new_value) ) +#define LFDS700_QUEUE_GET_USER_STATE_FROM_STATE( queue_state ) ( (queue_state).user_state ) + +/***** enums *****/ +enum lfds700_queue_query +{ + LFDS700_QUEUE_QUERY_SINGLETHREADED_GET_COUNT, + LFDS700_QUEUE_QUERY_SINGLETHREADED_VALIDATE +}; + +/***** structures *****/ +struct lfds700_queue_element +{ + struct lfds700_queue_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile next[PAC_SIZE]; + + void LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *key; + + void + *value; +}; + +struct lfds700_queue_state +{ + struct lfds700_queue_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile enqueue[PAC_SIZE], + *volatile dequeue[PAC_SIZE]; + + void LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *user_state; +}; + +/***** public prototypes *****/ +void lfds700_queue_init_valid_on_current_logical_core( struct lfds700_queue_state *qs, + struct lfds700_queue_element *qe_dummy, + struct lfds700_misc_prng_state *ps, + void *user_state ); + // TRD : used in conjunction with the #define LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE + +void lfds700_queue_cleanup( struct lfds700_queue_state *qs, + void (*element_cleanup_callback)(struct lfds700_queue_state *qs, struct lfds700_queue_element *qe, enum lfds700_misc_flag dummy_element_flag) ); + +void lfds700_queue_enqueue( struct lfds700_queue_state *qs, + struct lfds700_queue_element *qe, + struct lfds700_misc_prng_state *ps ); + +int lfds700_queue_dequeue( struct lfds700_queue_state *qs, + struct lfds700_queue_element **qe, + struct lfds700_misc_prng_state *ps ); + +void lfds700_queue_query( struct lfds700_queue_state *qs, + enum lfds700_queue_query query_type, + void *query_input, + void *query_output ); + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_queue_bounded_singleconsumer_singleproducer.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_queue_bounded_singleconsumer_singleproducer.h new file mode 100644 index 0000000000..3b090e1d45 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_queue_bounded_singleconsumer_singleproducer.h @@ -0,0 +1,59 @@ +/***** defines *****/ +#define LFDS700_QUEUE_BSS_GET_USER_STATE_FROM_STATE( queue_bss_state ) ( (queue_bss_state).user_state ) + +/***** enums *****/ +enum lfds700_queue_bss_query +{ + LFDS700_QUEUE_BSS_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, + LFDS700_QUEUE_BSS_QUERY_VALIDATE +}; + +/***** structures *****/ +struct lfds700_queue_bss_element +{ + void + *volatile key, + *volatile value; +}; + +struct lfds700_queue_bss_state +{ + lfds700_pal_uint_t + number_elements, + mask; + + lfds700_pal_uint_t volatile + read_index, + write_index; + + struct lfds700_queue_bss_element + *element_array; + + void + *user_state; +}; + +/***** public prototypes *****/ +void lfds700_queue_bss_init_valid_on_current_logical_core( struct lfds700_queue_bss_state *qbsss, + struct lfds700_queue_bss_element *element_array, + lfds700_pal_uint_t number_elements, + void *user_state ); + // TRD : number_elements must be a positive integer power of 2 + // TRD : used in conjunction with the #define LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE + +void lfds700_queue_bss_cleanup( struct lfds700_queue_bss_state *qbsss, + void (*element_cleanup_callback)(struct lfds700_queue_bss_state *qbsss, void *key, void *value) ); + +int lfds700_queue_bss_enqueue( struct lfds700_queue_bss_state *qbsss, + void *key, + void *value ); + +int lfds700_queue_bss_dequeue( struct lfds700_queue_bss_state *qbsss, + void **key, + void **value ); + +void lfds700_queue_bss_query( struct lfds700_queue_bss_state *qbsss, + enum lfds700_queue_bss_query query_type, + void *query_input, + void *query_output ); + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_ringbuffer.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_ringbuffer.h new file mode 100644 index 0000000000..fbb21d2be4 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_ringbuffer.h @@ -0,0 +1,69 @@ +/***** enums *****/ +#define LFDS700_RINGBUFFER_GET_USER_STATE_FROM_STATE( ringbuffer_state ) ( (ringbuffer_state).user_state ) + +/***** enums *****/ +enum lfds700_ringbuffer_query +{ + LFDS700_RINGBUFFER_QUERY_SINGLETHREADED_GET_COUNT, + LFDS700_RINGBUFFER_QUERY_SINGLETHREADED_VALIDATE +}; + +/***** structures *****/ +struct lfds700_ringbuffer_element +{ + struct lfds700_freelist_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + fe; + + struct lfds700_queue_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + qe; + + struct lfds700_queue_element + *qe_use; // TRD : hack for 7.0.0; we need a new queue with no dummy element + + void + *key, + *value; +}; + +struct lfds700_ringbuffer_state +{ + struct lfds700_freelist_state LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + fs; + + struct lfds700_queue_state LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + qs; + + void + (*element_cleanup_callback)( struct lfds700_ringbuffer_state *rs, void *key, void *value, enum lfds700_misc_flag unread_flag ), + *user_state; +}; + +/***** public prototypes *****/ +void lfds700_ringbuffer_init_valid_on_current_logical_core( struct lfds700_ringbuffer_state *rs, + struct lfds700_ringbuffer_element *re_array_inc_dummy, + lfds700_pal_uint_t number_elements, + struct lfds700_misc_prng_state *ps, + void *user_state ); + // TRD : used in conjunction with the #define LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE + +void lfds700_ringbuffer_cleanup( struct lfds700_ringbuffer_state *rs, + void (*element_cleanup_callback)(struct lfds700_ringbuffer_state *rs, void *key, void *value, enum lfds700_misc_flag unread_flag) ); + +int lfds700_ringbuffer_read( struct lfds700_ringbuffer_state *rs, + void **key, + void **value, + struct lfds700_misc_prng_state *ps ); + +void lfds700_ringbuffer_write( struct lfds700_ringbuffer_state *rs, + void *key, + void *value, + enum lfds700_misc_flag *overwrite_occurred_flag, + void **overwritten_key, + void **overwritten_value, + struct lfds700_misc_prng_state *ps ); + +void lfds700_ringbuffer_query( struct lfds700_ringbuffer_state *rs, + enum lfds700_ringbuffer_query query_type, + void *query_input, + void *query_output ); + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_stack.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_stack.h new file mode 100644 index 0000000000..3faed80308 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/inc/liblfds700/lfds700_stack.h @@ -0,0 +1,55 @@ +/***** defines *****/ +#define LFDS700_STACK_GET_KEY_FROM_ELEMENT( stack_element ) ( (stack_element).key ) +#define LFDS700_STACK_SET_KEY_IN_ELEMENT( stack_element, new_key ) ( (stack_element).key = (void *) (lfds700_pal_uint_t) (new_key) ) +#define LFDS700_STACK_GET_VALUE_FROM_ELEMENT( stack_element ) ( (stack_element).value ) +#define LFDS700_STACK_SET_VALUE_IN_ELEMENT( stack_element, new_value ) ( (stack_element).value = (void *) (lfds700_pal_uint_t) (new_value) ) +#define LFDS700_STACK_GET_USER_STATE_FROM_STATE( stack_state ) ( (stack_state).user_state ) + +/***** enums *****/ +enum lfds700_stack_query +{ + LFDS700_STACK_QUERY_SINGLETHREADED_GET_COUNT, + LFDS700_STACK_QUERY_SINGLETHREADED_VALIDATE +}; + +/***** structures *****/ +struct lfds700_stack_element +{ + struct lfds700_stack_element + *volatile next; + + void + *key, + *value; +}; + +struct lfds700_stack_state +{ + struct lfds700_stack_element LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *volatile top[PAC_SIZE]; + + void LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + *user_state; +}; + +/***** public prototypes *****/ +void lfds700_stack_init_valid_on_current_logical_core( struct lfds700_stack_state *ss, void *user_state ); + // TRD : used in conjunction with the #define LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE + +void lfds700_stack_cleanup( struct lfds700_stack_state *ss, + void (*element_cleanup_callback)(struct lfds700_stack_state *ss, struct lfds700_stack_element *se) ); + +void lfds700_stack_push( struct lfds700_stack_state *ss, + struct lfds700_stack_element *se, + struct lfds700_misc_prng_state *ps ); + +int lfds700_stack_pop( struct lfds700_stack_state *ss, + struct lfds700_stack_element **se, + struct lfds700_misc_prng_state *ps ); + +void lfds700_stack_query( struct lfds700_stack_state *ss, + enum lfds700_stack_query query_type, + void *query_input, + void *query_output ); + + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_cleanup.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_cleanup.c new file mode 100644 index 0000000000..2927c98628 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_cleanup.c @@ -0,0 +1,117 @@ +/***** includes *****/ +#include "lfds700_btree_addonly_unbalanced_internal.h" + + + + + +/****************************************************************************/ +void lfds700_btree_au_cleanup( struct lfds700_btree_au_state *baus, + void (*element_cleanup_callback)(struct lfds700_btree_au_state *baus, struct lfds700_btree_au_element *baue) ) +{ + enum lfds700_btree_au_delete_action + delete_action = LFDS700_BTREE_AU_DELETE_SELF; // TRD : to remove compiler warning + + struct lfds700_btree_au_element + *baue; + + struct lfds700_btree_au_element + *temp; + + LFDS700_PAL_ASSERT( baus != NULL ); + // TRD : element_delete_function can be NULL + + /* TRD : we're not lock-free now, so delete at will + but be iterative, so can be used in kernels (where there's little stack) + and be performant, since the user may be + creating/destroying many of these trees + also remember the user may be deallocating user data + so we cannot visit an element twice + + we start at the root and iterate till we go to NULL + if the element has zero children, we delete it and move up to its parent + if the element has one child, we delete it, move its child into its place, and continue from its child + if the element has two children, we move left + + the purpose of this is to minimize walking around the tree + to prevent visiting an element twice + while also minimizing code complexity + */ + + if( element_cleanup_callback == NULL ) + return; + + LFDS700_MISC_BARRIER_LOAD; + + lfds700_btree_au_get_by_absolute_position( baus, &baue, LFDS700_BTREE_AU_ABSOLUTE_POSITION_ROOT ); + + while( baue != NULL ) + { + if( baue->left == NULL and baue->right == NULL ) + delete_action = LFDS700_BTREE_AU_DELETE_SELF; + + if( baue->left != NULL and baue->right == NULL ) + delete_action = LFDS700_BTREE_AU_DELETE_SELF_REPLACE_WITH_LEFT_CHILD; + + if( baue->left == NULL and baue->right != NULL ) + delete_action = LFDS700_BTREE_AU_DELETE_SELF_REPLACE_WITH_RIGHT_CHILD; + + if( baue->left != NULL and baue->right != NULL ) + delete_action = LFDS700_BTREE_AU_DELETE_MOVE_LEFT; + + switch( delete_action ) + { + case LFDS700_BTREE_AU_DELETE_SELF: + // TRD : if we have a parent (we could be root) set his point to us to NULL + if( baue->up != NULL ) + { + if( baue->up->left == baue ) + baue->up->left = NULL; + if( baue->up->right == baue ) + baue->up->right = NULL; + } + + temp = baue; + lfds700_btree_au_get_by_relative_position( &baue, LFDS700_BTREE_AU_RELATIVE_POSITION_UP ); + element_cleanup_callback( baus, temp ); + break; + + case LFDS700_BTREE_AU_DELETE_SELF_REPLACE_WITH_LEFT_CHILD: + baue->left->up = baue->up; + if( baue->up != NULL ) + { + if( baue->up->left == baue ) + baue->up->left = baue->left; + if( baue->up->right == baue ) + baue->up->right = baue->left; + } + + temp = baue; + lfds700_btree_au_get_by_relative_position( &baue, LFDS700_BTREE_AU_RELATIVE_POSITION_LEFT ); + element_cleanup_callback( baus, temp ); + break; + + case LFDS700_BTREE_AU_DELETE_SELF_REPLACE_WITH_RIGHT_CHILD: + baue->right->up = baue->up; + if( baue->up != NULL ) + { + if( baue->up->left == baue ) + baue->up->left = baue->right; + if( baue->up->right == baue ) + baue->up->right = baue->right; + } + + temp = baue; + lfds700_btree_au_get_by_relative_position( &baue, LFDS700_BTREE_AU_RELATIVE_POSITION_RIGHT ); + element_cleanup_callback( baus, temp ); + break; + + case LFDS700_BTREE_AU_DELETE_MOVE_LEFT: + lfds700_btree_au_get_by_relative_position( &baue, LFDS700_BTREE_AU_RELATIVE_POSITION_LEFT ); + break; + } + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_get.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_get.c new file mode 100644 index 0000000000..8a2cdf93e8 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_get.c @@ -0,0 +1,467 @@ +/***** includes *****/ +#include "lfds700_btree_addonly_unbalanced_internal.h" + +/***** private prototypes *****/ +static void lfds700_btree_au_internal_inorder_walk_from_largest_get_next_smallest_element( struct lfds700_btree_au_element **baue ); +static void lfds700_btree_au_internal_inorder_walk_from_smallest_get_next_largest_element( struct lfds700_btree_au_element **baue ); + + + + + +/****************************************************************************/ +int lfds700_btree_au_get_by_key( struct lfds700_btree_au_state *baus, + void *key, + struct lfds700_btree_au_element **baue ) +{ + int + compare_result = !0, + rv = 1; + + LFDS700_PAL_ASSERT( baus != NULL ); + // TRD : key can be NULL + LFDS700_PAL_ASSERT( baue != NULL ); + + LFDS700_MISC_BARRIER_LOAD; + + *baue = baus->root; + + LFDS700_MISC_BARRIER_LOAD; + + while( *baue != NULL and compare_result != 0 ) + { + compare_result = baus->key_compare_function( key, (*baue)->key ); + + if( compare_result < 0 ) + { + *baue = (*baue)->left; + LFDS700_MISC_BARRIER_LOAD; + } + + if( compare_result > 0 ) + { + *baue = (*baue)->right; + LFDS700_MISC_BARRIER_LOAD; + } + } + + if( *baue == NULL ) + rv = 0; + + return( rv ); +} + + + + + +/****************************************************************************/ +int lfds700_btree_au_get_by_absolute_position( struct lfds700_btree_au_state *baus, struct lfds700_btree_au_element **baue, enum lfds700_btree_au_absolute_position absolute_position ) +{ + int + rv = 1; + + LFDS700_PAL_ASSERT( baus != NULL ); + LFDS700_PAL_ASSERT( baue != NULL ); + // TRD : absolute_position can be any value in its range + + LFDS700_MISC_BARRIER_LOAD; + + *baue = baus->root; + + LFDS700_MISC_BARRIER_LOAD; + + switch( absolute_position ) + { + case LFDS700_BTREE_AU_ABSOLUTE_POSITION_ROOT: + break; + + case LFDS700_BTREE_AU_ABSOLUTE_POSITION_LARGEST_IN_TREE: + if( *baue != NULL ) + while( (*baue)->right != NULL ) + { + *baue = (*baue)->right; + LFDS700_MISC_BARRIER_LOAD; + } + break; + + case LFDS700_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE: + if( *baue != NULL ) + while( (*baue)->left != NULL ) + { + *baue = (*baue)->left; + LFDS700_MISC_BARRIER_LOAD; + } + break; + } + + if( *baue == NULL ) + rv = 0; + + return( rv ); +} + + + + + +/****************************************************************************/ +int lfds700_btree_au_get_by_relative_position( struct lfds700_btree_au_element **baue, enum lfds700_btree_au_relative_position relative_position ) +{ + int + rv = 1; + + LFDS700_PAL_ASSERT( baue != NULL ); + // TRD : relative_position can baue any value in its range + + if( *baue == NULL ) + return( 0 ); + + LFDS700_MISC_BARRIER_LOAD; + + switch( relative_position ) + { + case LFDS700_BTREE_AU_RELATIVE_POSITION_UP: + *baue = (*baue)->up; + // TRD : no load barrier - up already existed, so is known to be safely propagated + break; + + case LFDS700_BTREE_AU_RELATIVE_POSITION_LEFT: + *baue = (*baue)->left; + LFDS700_MISC_BARRIER_LOAD; + break; + + case LFDS700_BTREE_AU_RELATIVE_POSITION_RIGHT: + *baue = (*baue)->right; + LFDS700_MISC_BARRIER_LOAD; + break; + + case LFDS700_BTREE_AU_RELATIVE_POSITION_SMALLEST_ELEMENT_BELOW_CURRENT_ELEMENT: + *baue = (*baue)->left; + if( *baue != NULL ) + { + LFDS700_MISC_BARRIER_LOAD; + while( (*baue)->right != NULL ) + { + *baue = (*baue)->right; + LFDS700_MISC_BARRIER_LOAD; + } + } + break; + + case LFDS700_BTREE_AU_RELATIVE_POSITION_LARGEST_ELEMENT_BELOW_CURRENT_ELEMENT: + *baue = (*baue)->right; + if( *baue != NULL ) + { + LFDS700_MISC_BARRIER_LOAD; + while( (*baue)->left != NULL ) + { + *baue = (*baue)->left; + LFDS700_MISC_BARRIER_LOAD; + } + } + break; + + case LFDS700_BTREE_AU_RELATIVE_POSITION_NEXT_SMALLER_ELEMENT_IN_ENTIRE_TREE: + lfds700_btree_au_internal_inorder_walk_from_largest_get_next_smallest_element( baue ); + break; + + case LFDS700_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE: + lfds700_btree_au_internal_inorder_walk_from_smallest_get_next_largest_element( baue ); + break; + } + + if( *baue == NULL ) + rv = 0; + + return( rv ); +} + + + + + +/****************************************************************************/ +static void lfds700_btree_au_internal_inorder_walk_from_largest_get_next_smallest_element( struct lfds700_btree_au_element **baue ) +{ + enum lfds700_btree_au_move + action = LFDS700_BTREE_AU_MOVE_INVALID; + + enum lfds700_misc_flag + finished_flag = LFDS700_MISC_FLAG_LOWERED, + load_finished_flag = LFDS700_MISC_FLAG_LOWERED; + + struct lfds700_btree_au_element + *left = NULL, + *right = NULL, + *up = NULL, + *up_left = NULL, + *up_right = NULL; + + LFDS700_PAL_ASSERT( baue != NULL ); + + /* TRD : from any given element, the next smallest element is; + 1. if we have a left, it's the largest element on the right branch of our left child + 2. if we don't have a left, and we're on the right of our parent, then it's our parent + 3. if we don't have a left, and we're on the left of our parent or we have no parent, + iterative up the tree until we find the first child who is on the right of its parent; then it's the parent + */ + + /* TRD : we need to ensure the variables we use to decide our action are self-consistent + to do this, we make local copies of them all + then, if they are all not NULL, we can know they cannot change and we can continue + if however any of them are NULL, they could have changed while we were reading + and so our variables could be non-self-consistent + to check for this, we issue another processor read barrier + and then compare our local variables with the values in the tree + if they all match, then we know our variable set is self-consistent + (even though it may now be wrong - but we will discover this when we try the atomic operation) + */ + + LFDS700_MISC_BARRIER_LOAD; + + while( load_finished_flag == LFDS700_MISC_FLAG_LOWERED ) + { + left = (*baue)->left; + right = (*baue)->right; + up = (*baue)->up; + if( up != NULL ) + { + up_left = (*baue)->up->left; + up_right = (*baue)->up->right; + } + + if( left != NULL and right != NULL and (up == NULL or (up != NULL and up_left != NULL and up_right != NULL)) ) + break; + + LFDS700_MISC_BARRIER_LOAD; + + if( left == (*baue)->left and right == (*baue)->right and (up == NULL or (up != NULL and up == (*baue)->up and up_left == (*baue)->up->left and up_right == (*baue)->up->right)) ) + load_finished_flag = LFDS700_MISC_FLAG_RAISED; + } + + if( left != NULL ) + action = LFDS700_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD; + + if( left == NULL and up != NULL and up_right == *baue ) + action = LFDS700_BTREE_AU_MOVE_GET_PARENT; + + if( (left == NULL and up == NULL) or (up != NULL and up_left == *baue and left == NULL) ) + action = LFDS700_BTREE_AU_MOVE_MOVE_UP_TREE; + + switch( action ) + { + case LFDS700_BTREE_AU_MOVE_INVALID: + case LFDS700_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD: + // TRD : eliminates a compiler warning + break; + + case LFDS700_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD: + *baue = left; + if( *baue != NULL ) + { + LFDS700_MISC_BARRIER_LOAD; + while( (*baue)->right != NULL ) + { + *baue = (*baue)->right; + LFDS700_MISC_BARRIER_LOAD; + } + } + break; + + case LFDS700_BTREE_AU_MOVE_GET_PARENT: + *baue = up; + break; + + case LFDS700_BTREE_AU_MOVE_MOVE_UP_TREE: + while( finished_flag == LFDS700_MISC_FLAG_LOWERED ) + { + load_finished_flag = LFDS700_MISC_FLAG_LOWERED; + + while( load_finished_flag == LFDS700_MISC_FLAG_LOWERED ) + { + up = (*baue)->up; + if( up != NULL ) + up_left = (*baue)->up->left; + + if( up == NULL or (up != NULL and up_left != NULL) ) + break; + + LFDS700_MISC_BARRIER_LOAD; + + if( up == (*baue)->up and up_left == (*baue)->up->left ) + load_finished_flag = LFDS700_MISC_FLAG_RAISED; + } + + if( *baue != NULL and up != NULL and *baue == up_left ) + *baue = up; + else + finished_flag = LFDS700_MISC_FLAG_RAISED; + } + + *baue = up; + + /* + + while( *baue != NULL and (*baue)->up != NULL and *baue == (*baue)->up->left ) + *baue = (*baue)->up; + + *baue = (*baue)->up; + + */ + break; + } + + return; +} + + + + + +/****************************************************************************/ +static void lfds700_btree_au_internal_inorder_walk_from_smallest_get_next_largest_element( struct lfds700_btree_au_element **baue ) +{ + enum lfds700_btree_au_move + action = LFDS700_BTREE_AU_MOVE_INVALID; + + enum lfds700_misc_flag + finished_flag = LFDS700_MISC_FLAG_LOWERED, + load_finished_flag = LFDS700_MISC_FLAG_LOWERED; + + struct lfds700_btree_au_element + *left = NULL, + *right = NULL, + *up = NULL, + *up_left = NULL, + *up_right = NULL; + + LFDS700_PAL_ASSERT( baue != NULL ); + + /* TRD : from any given element, the next largest element is; + 1. if we have a right, it's the smallest element on the left branch of our right child + 2. if we don't have a right, and we're on the left of our parent, then it's our parent + 3. if we don't have a right, and we're on the right of our parent or we have no parent, + iterate up the tree until we find the first child who is on the left of its parent; then it's the parent + */ + + LFDS700_MISC_BARRIER_LOAD; + + while( load_finished_flag == LFDS700_MISC_FLAG_LOWERED ) + { + left = (*baue)->left; + right = (*baue)->right; + up = (*baue)->up; + if( up != NULL ) + { + up_left = (*baue)->up->left; + up_right = (*baue)->up->right; + } + + if( left != NULL and right != NULL and (up == NULL or (up != NULL and up_left != NULL and up_right != NULL)) ) + break; + + LFDS700_MISC_BARRIER_LOAD; + + if( left == (*baue)->left and right == (*baue)->right and (up == NULL or (up != NULL and up == (*baue)->up and up_left == (*baue)->up->left and up_right == (*baue)->up->right)) ) + load_finished_flag = LFDS700_MISC_FLAG_RAISED; + } + + if( right != NULL ) + action = LFDS700_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD; + + if( right == NULL and up != NULL and up_left == *baue ) + action = LFDS700_BTREE_AU_MOVE_GET_PARENT; + + if( (right == NULL and up == NULL) or (up != NULL and up_right == *baue and right == NULL) ) + action = LFDS700_BTREE_AU_MOVE_MOVE_UP_TREE; + + switch( action ) + { + case LFDS700_BTREE_AU_MOVE_INVALID: + case LFDS700_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD: + // TRD : remove compiler warning + break; + + case LFDS700_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD: + *baue = right; + if( *baue != NULL ) + { + LFDS700_MISC_BARRIER_LOAD; + while( (*baue)->left != NULL ) + { + *baue = (*baue)->left; + LFDS700_MISC_BARRIER_LOAD; + } + } + break; + + case LFDS700_BTREE_AU_MOVE_GET_PARENT: + *baue = up; + break; + + case LFDS700_BTREE_AU_MOVE_MOVE_UP_TREE: + while( finished_flag == LFDS700_MISC_FLAG_LOWERED ) + { + load_finished_flag = LFDS700_MISC_FLAG_LOWERED; + + while( load_finished_flag == LFDS700_MISC_FLAG_LOWERED ) + { + up = (*baue)->up; + if( up != NULL ) + up_right = (*baue)->up->right; + + if( up == NULL or (up != NULL and up_right != NULL) ) + break; + + LFDS700_MISC_BARRIER_LOAD; + + if( up == (*baue)->up and up_right == (*baue)->up->right ) + load_finished_flag = LFDS700_MISC_FLAG_RAISED; + } + + if( *baue != NULL and up != NULL and *baue == up_right ) + *baue = up; + else + finished_flag = LFDS700_MISC_FLAG_RAISED; + } + + *baue = up; + + /* + + while( *baue != NULL and (*baue)->up != NULL and *baue == (*baue)->up->right ) + *baue = (*baue)->up; + + *baue = (*baue)->up; + + */ + break; + } + + return; +} + + + + + +/****************************************************************************/ +int lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position( struct lfds700_btree_au_state *baus, struct lfds700_btree_au_element **baue, enum lfds700_btree_au_absolute_position absolute_position, enum lfds700_btree_au_relative_position relative_position ) +{ + int + rv; + + LFDS700_PAL_ASSERT( baus != NULL ); + LFDS700_PAL_ASSERT( baue != NULL ); + // TRD: absolute_position can be any value in its range + // TRD: relative_position can be any value in its range + + if( *baue == NULL ) + rv = lfds700_btree_au_get_by_absolute_position( baus, baue, absolute_position ); + else + rv = lfds700_btree_au_get_by_relative_position( baue, relative_position ); + + return( rv ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_init.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_init.c new file mode 100644 index 0000000000..7dd0efd6c0 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_init.c @@ -0,0 +1,32 @@ +/***** includes *****/ +#include "lfds700_btree_addonly_unbalanced_internal.h" + + + + + +/****************************************************************************/ +void lfds700_btree_au_init_valid_on_current_logical_core( struct lfds700_btree_au_state *baus, + int (*key_compare_function)(void const *new_key, void const *existing_key), + enum lfds700_btree_au_existing_key existing_key, + void *user_state ) +{ + LFDS700_PAL_ASSERT( baus != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &baus->root % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &baus->key_compare_function % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( key_compare_function != NULL ); + // TRD : existing_key can be any value in its range + // TRD : user_state can be NULL + + baus->root = NULL; + baus->key_compare_function = key_compare_function; + baus->existing_key = existing_key; + baus->user_state = user_state; + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_insert.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_insert.c new file mode 100644 index 0000000000..8808177a4c --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_insert.c @@ -0,0 +1,156 @@ +/***** includes *****/ +#include "lfds700_btree_addonly_unbalanced_internal.h" + + + + + +/****************************************************************************/ +enum lfds700_btree_au_insert_result lfds700_btree_au_insert( struct lfds700_btree_au_state *baus, + struct lfds700_btree_au_element *baue, + struct lfds700_btree_au_element **existing_baue, + struct lfds700_misc_prng_state *ps ) +{ + char unsigned + result = 0; + + int + compare_result = 0; + + lfds700_pal_uint_t + backoff_iteration = LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE; + + struct lfds700_btree_au_element + *volatile compare = NULL, + *volatile baue_next = NULL, + *volatile baue_parent = NULL, + *volatile baue_temp; + + LFDS700_PAL_ASSERT( baus != NULL ); + LFDS700_PAL_ASSERT( baue != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &baue->left % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &baue->right % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &baue->up % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &baue->value % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &baue->key % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + // TRD : existing_baue can be NULL + LFDS700_PAL_ASSERT( ps != NULL ); + + /* TRD : we follow a normal search for the insert node and which side to insert + + the difference is that insertion may fail because someone else inserts + there before we do + + in this case, we resume searching for the insert node from the node + we were attempting to insert upon + + (if we attempted to insert the root node and this failed, i.e. we thought + the tree was empty but then it wasn't, then we start searching from the + new root) + */ + + baue->up = baue->left = baue->right = NULL; + + LFDS700_MISC_BARRIER_LOAD; + + baue_temp = baus->root; + + LFDS700_MISC_BARRIER_LOAD; + + while( result == 0 ) + { + // TRD : first we find where to insert + while( baue_temp != NULL ) + { + compare_result = baus->key_compare_function( baue->key, baue_temp->key ); + + if( compare_result == 0 ) + { + if( existing_baue != NULL ) + *existing_baue = baue_temp; + + switch( baus->existing_key ) + { + case LFDS700_BTREE_AU_EXISTING_KEY_OVERWRITE: + LFDS700_BTREE_AU_SET_VALUE_IN_ELEMENT( *baue_temp, baue->value ); + return( LFDS700_BTREE_AU_INSERT_RESULT_SUCCESS_OVERWRITE ); + break; + + case LFDS700_BTREE_AU_EXISTING_KEY_FAIL: + return( LFDS700_BTREE_AU_INSERT_RESULT_FAILURE_EXISTING_KEY ); + break; + } + } + + if( compare_result < 0 ) + baue_next = baue_temp->left; + + if( compare_result > 0 ) + baue_next = baue_temp->right; + + baue_parent = baue_temp; + baue_temp = baue_next; + if( baue_temp != NULL ) + LFDS700_MISC_BARRIER_LOAD; + } + + /* TRD : second, we actually insert + + at this point baue_temp has come to NULL + and baue_parent is the element to insert at + and result of the last compare indicates + the direction of insertion + + it may be that another tree has already inserted an element with + the same key as ourselves, or other elements which mean our position + is now wrong + + in this case, it is either inserted in the position we're trying + to insert in now, in which case our insert will fail + + or, similarly, other elements will have come in where we are, + and our insert will fail + */ + + if( baue_parent == NULL ) + { + compare = NULL; + baue->up = baus->root; + LFDS700_MISC_BARRIER_STORE; + LFDS700_PAL_ATOMIC_CAS_WITH_BACKOFF( &baus->root, &compare, baue, LFDS700_MISC_CAS_STRENGTH_WEAK, result, backoff_iteration, ps ); + + if( result == 0 ) + baue_temp = baus->root; + } + + if( baue_parent != NULL ) + { + if( compare_result <= 0 ) + { + compare = NULL; + baue->up = baue_parent; + LFDS700_MISC_BARRIER_STORE; + LFDS700_PAL_ATOMIC_CAS_WITH_BACKOFF( &baue_parent->left, &compare, baue, LFDS700_MISC_CAS_STRENGTH_WEAK, result, backoff_iteration, ps ); + } + + if( compare_result > 0 ) + { + compare = NULL; + baue->up = baue_parent; + LFDS700_MISC_BARRIER_STORE; + LFDS700_PAL_ATOMIC_CAS_WITH_BACKOFF( &baue_parent->right, &compare, baue, LFDS700_MISC_CAS_STRENGTH_WEAK, result, backoff_iteration, ps ); + } + + // TRD : if the insert fails, resume searching at the insert node + if( result == 0 ) + baue_temp = baue_parent; + } + } + + // TRD : if we get to here, we added (not failed or overwrite on exist) a new element + if( existing_baue != NULL ) + *existing_baue = NULL; + + return( LFDS700_BTREE_AU_INSERT_RESULT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_internal.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_internal.h new file mode 100644 index 0000000000..54149bac99 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_internal.h @@ -0,0 +1,23 @@ +/***** the library-wide header file *****/ +#include "../liblfds700_internal.h" + +/***** enums *****/ +enum lfds700_btree_au_move +{ + LFDS700_BTREE_AU_MOVE_INVALID, + LFDS700_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD, + LFDS700_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD, + LFDS700_BTREE_AU_MOVE_GET_PARENT, + LFDS700_BTREE_AU_MOVE_MOVE_UP_TREE +}; + +enum lfds700_btree_au_delete_action +{ + LFDS700_BTREE_AU_DELETE_SELF, + LFDS700_BTREE_AU_DELETE_SELF_REPLACE_WITH_LEFT_CHILD, + LFDS700_BTREE_AU_DELETE_SELF_REPLACE_WITH_RIGHT_CHILD, + LFDS700_BTREE_AU_DELETE_MOVE_LEFT +}; + +/***** private prototypes *****/ + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_query.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_query.c new file mode 100644 index 0000000000..dce9587929 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_btree_addonly_unbalanced/lfds700_btree_addonly_unbalanced_query.c @@ -0,0 +1,121 @@ +/***** includes *****/ +#include "lfds700_btree_addonly_unbalanced_internal.h" + +/***** private prototypes *****/ +static void lfds700_btree_au_internal_validate( struct lfds700_btree_au_state *abs, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_btree_au_validity ); + + + + + +/****************************************************************************/ +void lfds700_btree_au_query( struct lfds700_btree_au_state *baus, enum lfds700_btree_au_query query_type, void *query_input, void *query_output ) +{ + LFDS700_PAL_ASSERT( baus != NULL ); + // TRD : query_type can be any value in its range + + LFDS700_MISC_BARRIER_LOAD; + + switch( query_type ) + { + case LFDS700_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT: + { + struct lfds700_btree_au_element + *baue = NULL; + + LFDS700_PAL_ASSERT( query_input == NULL ); + LFDS700_PAL_ASSERT( query_output != NULL ); + + *(lfds700_pal_uint_t *) query_output = 0; + + while( lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position(baus, &baue, LFDS700_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE, LFDS700_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE) ) + ( *(lfds700_pal_uint_t *) query_output )++; + } + break; + + case LFDS700_BTREE_AU_QUERY_SINGLETHREADED_VALIDATE: + // TRD : query_input can be NULL + LFDS700_PAL_ASSERT( query_output != NULL ); + + lfds700_btree_au_internal_validate( baus, (struct lfds700_misc_validation_info *) query_input, (enum lfds700_misc_validity *) query_output ); + break; + } + + return; +} + + + + + +/****************************************************************************/ +static void lfds700_btree_au_internal_validate( struct lfds700_btree_au_state *baus, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_btree_au_validity ) +{ + lfds700_pal_uint_t + number_elements_from_query_tree = 0, + number_elements_from_walk = 0; + + struct lfds700_btree_au_element + *baue = NULL, + *baue_prev = NULL; + + LFDS700_PAL_ASSERT( baus!= NULL ); + // TRD : vi can be NULL + LFDS700_PAL_ASSERT( lfds700_btree_au_validity != NULL ); + + *lfds700_btree_au_validity = LFDS700_MISC_VALIDITY_VALID; + + /* TRD : validation is performed by; + + performing an in-order walk + we should see every element is larger than the preceeding element + we count elements as we go along (visited elements, that is) + and check our tally equals the expected count + */ + + LFDS700_MISC_BARRIER_LOAD; + + while( lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position(baus, &baue, LFDS700_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE, LFDS700_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE) ) + { + // TRD : baue_prev should always be smaller than or equal to baue + if( baue_prev != NULL ) + if( baus->key_compare_function(baue_prev->key, baue->key) > 0 ) + { + *lfds700_btree_au_validity = LFDS700_MISC_VALIDITY_INVALID_ORDER; + return; + } + + baue_prev = baue; + number_elements_from_walk++; + } + + if( *lfds700_btree_au_validity == LFDS700_MISC_VALIDITY_VALID ) + { + lfds700_btree_au_query( (struct lfds700_btree_au_state *) baus, LFDS700_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &number_elements_from_query_tree ); + + if( number_elements_from_walk > number_elements_from_query_tree ) + *lfds700_btree_au_validity = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + + if( number_elements_from_walk < number_elements_from_query_tree ) + *lfds700_btree_au_validity = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + } + + /* TRD : now check for expected number of elements + vi can be NULL, in which case we do not check + we know we don't have a loop from our earlier check + */ + + if( *lfds700_btree_au_validity == LFDS700_MISC_VALIDITY_VALID and vi != NULL ) + { + lfds700_btree_au_query( (struct lfds700_btree_au_state *) baus, LFDS700_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &number_elements_from_query_tree ); + + if( number_elements_from_query_tree < vi->min_elements ) + *lfds700_btree_au_validity = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( number_elements_from_query_tree > vi->max_elements ) + *lfds700_btree_au_validity = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_cleanup.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_cleanup.c new file mode 100644 index 0000000000..f7a088a39a --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_cleanup.c @@ -0,0 +1,36 @@ +/***** includes *****/ +#include "lfds700_freelist_internal.h" + + + + + +/****************************************************************************/ +void lfds700_freelist_cleanup( struct lfds700_freelist_state *fs, + void (*element_cleanup_callback)(struct lfds700_freelist_state *fs, struct lfds700_freelist_element *fe) ) +{ + struct lfds700_freelist_element + *fe, + *fe_temp; + + LFDS700_PAL_ASSERT( fs != NULL ); + // TRD : element_cleanup_callback can be NULL + + LFDS700_MISC_BARRIER_LOAD; + + if( element_cleanup_callback != NULL ) + { + fe = fs->top[POINTER]; + + while( fe != NULL ) + { + fe_temp = fe; + fe = fe->next; + + element_cleanup_callback( fs, fe_temp ); + } + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_init.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_init.c new file mode 100644 index 0000000000..fcacd1b32f --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_init.c @@ -0,0 +1,27 @@ +/***** includes *****/ +#include "lfds700_freelist_internal.h" + + + + + +/****************************************************************************/ +void lfds700_freelist_init_valid_on_current_logical_core( struct lfds700_freelist_state *fs, void *user_state ) +{ + LFDS700_PAL_ASSERT( fs != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) fs->top % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &fs->user_state % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + // TRD : user_state can be NULL + + fs->top[POINTER] = NULL; + fs->top[COUNTER] = 0; + + fs->user_state = user_state; + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_internal.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_internal.h new file mode 100644 index 0000000000..7a7d541804 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_internal.h @@ -0,0 +1,5 @@ +/***** the library wide include file *****/ +#include "../liblfds700_internal.h" + +/***** private prototypes *****/ + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_pop.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_pop.c new file mode 100644 index 0000000000..c0a3545d91 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_pop.c @@ -0,0 +1,52 @@ +/***** includes *****/ +#include "lfds700_freelist_internal.h" + + + + + +/****************************************************************************/ +int lfds700_freelist_pop( struct lfds700_freelist_state *fs, struct lfds700_freelist_element **fe, struct lfds700_misc_prng_state *ps ) +{ + char unsigned + result; + + lfds700_pal_uint_t + backoff_iteration = LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE; + + struct lfds700_freelist_element LFDS700_PAL_ALIGN(LFDS700_PAL_ALIGN_DOUBLE_POINTER) + *new_top[PAC_SIZE], + *volatile original_top[PAC_SIZE]; + + LFDS700_PAL_ASSERT( fs != NULL ); + LFDS700_PAL_ASSERT( fe != NULL ); + LFDS700_PAL_ASSERT( ps != NULL ); + + LFDS700_PAL_BARRIER_PROCESSOR_LOAD; + + original_top[COUNTER] = fs->top[COUNTER]; + original_top[POINTER] = fs->top[POINTER]; + + do + { + if( original_top[POINTER] == NULL ) + { + *fe = NULL; + return( 0 ); + } + + new_top[COUNTER] = original_top[COUNTER] + 1; + new_top[POINTER] = original_top[POINTER]->next; + + LFDS700_PAL_ATOMIC_DWCAS_WITH_BACKOFF( &fs->top, original_top, new_top, LFDS700_MISC_CAS_STRENGTH_WEAK, result, backoff_iteration, ps ); + + if( result != 1 ) + LFDS700_PAL_BARRIER_PROCESSOR_LOAD; + } + while( result != 1 ); + + *fe = original_top[POINTER]; + + return( 1 ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_push.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_push.c new file mode 100644 index 0000000000..67fe38dadb --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_push.c @@ -0,0 +1,42 @@ +/***** includes *****/ +#include "lfds700_freelist_internal.h" + + + + + +/****************************************************************************/ +void lfds700_freelist_push( struct lfds700_freelist_state *fs, struct lfds700_freelist_element *fe, struct lfds700_misc_prng_state *ps ) +{ + char unsigned + result; + + lfds700_pal_uint_t + backoff_iteration = LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE; + + struct lfds700_freelist_element LFDS700_PAL_ALIGN(LFDS700_PAL_ALIGN_DOUBLE_POINTER) + *new_top[PAC_SIZE], + *volatile original_top[PAC_SIZE]; + + LFDS700_PAL_ASSERT( fs != NULL ); + LFDS700_PAL_ASSERT( fe != NULL ); + LFDS700_PAL_ASSERT( ps != NULL ); + + new_top[POINTER] = fe; + + original_top[COUNTER] = fs->top[COUNTER]; + original_top[POINTER] = fs->top[POINTER]; + + do + { + new_top[COUNTER] = original_top[COUNTER] + 1; + fe->next = original_top[POINTER]; + + LFDS700_PAL_BARRIER_PROCESSOR_STORE; + LFDS700_PAL_ATOMIC_DWCAS_WITH_BACKOFF( &fs->top, original_top, new_top, LFDS700_MISC_CAS_STRENGTH_WEAK, result, backoff_iteration, ps ); + } + while( result != 1 ); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_query.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_query.c new file mode 100644 index 0000000000..43b8bc263d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_freelist/lfds700_freelist_query.c @@ -0,0 +1,123 @@ +/***** includes *****/ +#include "lfds700_freelist_internal.h" + +/***** private prototypes *****/ +static void lfds700_freelist_internal_freelist_validate( struct lfds700_freelist_state *fs, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_freelist_validity ); + + + + + +/****************************************************************************/ +void lfds700_freelist_query( struct lfds700_freelist_state *fs, enum lfds700_freelist_query query_type, void *query_input, void *query_output ) +{ + struct lfds700_freelist_element + *fe; + + LFDS700_PAL_ASSERT( fs != NULL ); + // TRD : query_type can be any value in its range + + LFDS700_MISC_BARRIER_LOAD; + + switch( query_type ) + { + case LFDS700_FREELIST_QUERY_SINGLETHREADED_GET_COUNT: + LFDS700_PAL_ASSERT( query_input == NULL ); + LFDS700_PAL_ASSERT( query_output != NULL ); + + *(lfds700_pal_uint_t *) query_output = 0; + + fe = (struct lfds700_freelist_element *) fs->top[POINTER]; + + while( fe != NULL ) + { + ( *(lfds700_pal_uint_t *) query_output )++; + fe = (struct lfds700_freelist_element *) fe->next; + } + break; + + case LFDS700_FREELIST_QUERY_SINGLETHREADED_VALIDATE: + // TRD : query_input can be NULL + LFDS700_PAL_ASSERT( query_output != NULL ); + + lfds700_freelist_internal_freelist_validate( fs, (struct lfds700_misc_validation_info *) query_input, (enum lfds700_misc_validity *) query_output ); + break; + } + + return; +} + + + + + +/****************************************************************************/ +static void lfds700_freelist_internal_freelist_validate( struct lfds700_freelist_state *fs, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_freelist_validity ) +{ + lfds700_pal_uint_t + number_elements = 0; + + struct lfds700_freelist_element + *fe_slow, + *fe_fast; + + LFDS700_PAL_ASSERT( fs != NULL ); + // TRD : vi can be NULL + LFDS700_PAL_ASSERT( lfds700_freelist_validity != NULL ); + + *lfds700_freelist_validity = LFDS700_MISC_VALIDITY_VALID; + + fe_slow = fe_fast = (struct lfds700_freelist_element *) fs->top[POINTER]; + + /* TRD : first, check for a loop + we have two pointers + both of which start at the top of the freelist + we enter a loop + and on each iteration + we advance one pointer by one element + and the other by two + + we exit the loop when both pointers are NULL + (have reached the end of the freelist) + + or + + if we fast pointer 'sees' the slow pointer + which means we have a loop + */ + + if( fe_slow != NULL ) + do + { + fe_slow = fe_slow->next; + + if( fe_fast != NULL ) + fe_fast = fe_fast->next; + + if( fe_fast != NULL ) + fe_fast = fe_fast->next; + } + while( fe_slow != NULL and fe_fast != fe_slow ); + + if( fe_fast != NULL and fe_slow != NULL and fe_fast == fe_slow ) + *lfds700_freelist_validity = LFDS700_MISC_VALIDITY_INVALID_LOOP; + + /* TRD : now check for expected number of elements + vi can be NULL, in which case we do not check + we know we don't have a loop from our earlier check + */ + + if( *lfds700_freelist_validity == LFDS700_MISC_VALIDITY_VALID and vi != NULL ) + { + lfds700_freelist_query( fs, LFDS700_FREELIST_QUERY_SINGLETHREADED_GET_COUNT, NULL, (void *) &number_elements ); + + if( number_elements < vi->min_elements ) + *lfds700_freelist_validity = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( number_elements > vi->max_elements ) + *lfds700_freelist_validity = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_cleanup.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_cleanup.c new file mode 100644 index 0000000000..af88b19179 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_cleanup.c @@ -0,0 +1,61 @@ +/***** includes *****/ +#include "lfds700_hash_addonly_internal.h" + +/***** private prototypes*****/ +static void btree_au_element_cleanup_function( struct lfds700_btree_au_state *baus, struct lfds700_btree_au_element *baue ); + + + + + +/****************************************************************************/ +void lfds700_hash_a_cleanup( struct lfds700_hash_a_state *has, + void (*element_cleanup_callback)(struct lfds700_hash_a_state *has, struct lfds700_hash_a_element *hae) ) +{ + lfds700_pal_uint_t + loop; + + LFDS700_PAL_ASSERT( has != NULL ); + // TRD : element_cleanup_callback can be NULL + + if( element_cleanup_callback == NULL ) + return; + + LFDS700_MISC_BARRIER_LOAD; + + has->element_cleanup_callback = element_cleanup_callback; + + for( loop = 0 ; loop < has->array_size ; loop++ ) + lfds700_btree_au_cleanup( has->baus_array+loop, btree_au_element_cleanup_function ); + + return; +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static void btree_au_element_cleanup_function( struct lfds700_btree_au_state *baus, struct lfds700_btree_au_element *baue ) +{ + struct lfds700_hash_a_state + *has; + + struct lfds700_hash_a_element + *hae; + + LFDS700_PAL_ASSERT( baus != NULL ); + LFDS700_PAL_ASSERT( baue != NULL ); + + hae = (struct lfds700_hash_a_element *) LFDS700_BTREE_AU_GET_VALUE_FROM_ELEMENT( *baue ); + has = (struct lfds700_hash_a_state *) LFDS700_BTREE_AU_GET_USER_STATE_FROM_STATE( *baus ); + + has->element_cleanup_callback( has, hae ); + + return; +} + +#pragma warning( default : 4100 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_get.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_get.c new file mode 100644 index 0000000000..8d010664ab --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_get.c @@ -0,0 +1,37 @@ +/***** includes *****/ +#include "lfds700_hash_addonly_internal.h" + + + + + +/****************************************************************************/ +int lfds700_hash_a_get_by_key( struct lfds700_hash_a_state *has, + void *key, + struct lfds700_hash_a_element **hae ) +{ + int + rv; + + lfds700_pal_uint_t + hash = 0; + + struct lfds700_btree_au_element + *baue; + + LFDS700_PAL_ASSERT( has != NULL ); + // TRD : key can be NULL + LFDS700_PAL_ASSERT( hae != NULL ); + + has->key_hash_function( key, &hash ); + + rv = lfds700_btree_au_get_by_key( has->baus_array + (hash % has->array_size), key, &baue ); + + if( rv == 1 ) + *hae = LFDS700_BTREE_AU_GET_VALUE_FROM_ELEMENT( *baue ); + else + *hae = NULL; + + return( rv ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_init.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_init.c new file mode 100644 index 0000000000..022024ce27 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_init.c @@ -0,0 +1,54 @@ +/***** includes *****/ +#include "lfds700_hash_addonly_internal.h" + + + + + +/****************************************************************************/ +void lfds700_hash_a_init_valid_on_current_logical_core( struct lfds700_hash_a_state *has, + struct lfds700_btree_au_state *baus_array, + lfds700_pal_uint_t array_size, + int (*key_compare_function)(void const *new_key, void const *existing_key), + void (*key_hash_function)(void const *key, lfds700_pal_uint_t *hash), + enum lfds700_hash_a_existing_key existing_key, + void *user_state ) +{ + enum lfds700_btree_au_existing_key + btree_au_existing_key = LFDS700_BTREE_AU_EXISTING_KEY_OVERWRITE; // TRD : for compiler warning + + lfds700_pal_uint_t + loop; + + LFDS700_PAL_ASSERT( has != NULL ); + LFDS700_PAL_ASSERT( baus_array != NULL ); + LFDS700_PAL_ASSERT( array_size > 0 ); + LFDS700_PAL_ASSERT( key_compare_function != NULL ); + LFDS700_PAL_ASSERT( key_hash_function != NULL ); + // TRD : existing_key can be any value in its range + // TRD : user_state can be NULL + + has->array_size = array_size; + has->key_compare_function = key_compare_function; + has->key_hash_function = key_hash_function; + has->existing_key = existing_key; + has->baus_array = baus_array; + has->user_state = user_state; + + if( has->existing_key == LFDS700_HASH_A_EXISTING_KEY_OVERWRITE ) + btree_au_existing_key = LFDS700_BTREE_AU_EXISTING_KEY_OVERWRITE; + + if( has->existing_key == LFDS700_HASH_A_EXISTING_KEY_FAIL ) + btree_au_existing_key = LFDS700_BTREE_AU_EXISTING_KEY_FAIL; + + // TRD : since the addonly_hash atomic counts, if that flag is set, the btree_addonly_unbalanceds don't have to + for( loop = 0 ; loop < array_size ; loop++ ) + lfds700_btree_au_init_valid_on_current_logical_core( has->baus_array+loop, key_compare_function, btree_au_existing_key, user_state ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_insert.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_insert.c new file mode 100644 index 0000000000..25df3e7f93 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_insert.c @@ -0,0 +1,62 @@ +/***** includes *****/ +#include "lfds700_hash_addonly_internal.h" + + + + + +/****************************************************************************/ +enum lfds700_hash_a_insert_result lfds700_hash_a_insert( struct lfds700_hash_a_state *has, + struct lfds700_hash_a_element *hae, + struct lfds700_hash_a_element **existing_hae, + struct lfds700_misc_prng_state *ps ) +{ + enum lfds700_hash_a_insert_result + apr = LFDS700_HASH_A_PUT_RESULT_SUCCESS; + + enum lfds700_btree_au_insert_result + alr; + + lfds700_pal_uint_t + hash = 0; + + struct lfds700_btree_au_element + *existing_baue; + + LFDS700_PAL_ASSERT( has != NULL ); + LFDS700_PAL_ASSERT( hae != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &hae->value % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + // TRD : existing_hae can be NULL + LFDS700_PAL_ASSERT( ps != NULL ); + + // TRD : alignment checks + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &hae->baue % LFDS700_PAL_ALIGN_SINGLE_POINTER == 0 ); + + has->key_hash_function( hae->key, &hash ); + + LFDS700_BTREE_AU_SET_KEY_IN_ELEMENT( hae->baue, hae->key ); + LFDS700_BTREE_AU_SET_VALUE_IN_ELEMENT( hae->baue, hae ); + + alr = lfds700_btree_au_insert( has->baus_array + (hash % has->array_size), &hae->baue, &existing_baue, ps ); + + switch( alr ) + { + case LFDS700_BTREE_AU_INSERT_RESULT_FAILURE_EXISTING_KEY: + if( existing_hae != NULL ) + *existing_hae = LFDS700_BTREE_AU_GET_VALUE_FROM_ELEMENT( *existing_baue ); + + apr = LFDS700_HASH_A_PUT_RESULT_FAILURE_EXISTING_KEY; + break; + + case LFDS700_BTREE_AU_INSERT_RESULT_SUCCESS_OVERWRITE: + apr = LFDS700_HASH_A_PUT_RESULT_SUCCESS_OVERWRITE; + break; + + case LFDS700_BTREE_AU_INSERT_RESULT_SUCCESS: + apr = LFDS700_HASH_A_PUT_RESULT_SUCCESS; + break; + } + + return( apr ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_internal.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_internal.h new file mode 100644 index 0000000000..7a7d541804 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_internal.h @@ -0,0 +1,5 @@ +/***** the library wide include file *****/ +#include "../liblfds700_internal.h" + +/***** private prototypes *****/ + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_iterate.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_iterate.c new file mode 100644 index 0000000000..3e06be3f90 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_iterate.c @@ -0,0 +1,58 @@ +/***** includes *****/ +#include "lfds700_hash_addonly_internal.h" + + + + + +/****************************************************************************/ +void lfds700_hash_a_iterate_init( struct lfds700_hash_a_state *has, struct lfds700_hash_a_iterate *hai ) +{ + LFDS700_PAL_ASSERT( has != NULL ); + LFDS700_PAL_ASSERT( hai != NULL ); + + hai->baus = has->baus_array; + hai->baus_end = has->baus_array + has->array_size; + hai->baue = NULL; + + return; +} + + + + + +/****************************************************************************/ +int lfds700_hash_a_iterate( struct lfds700_hash_a_iterate *hai, struct lfds700_hash_a_element **hae ) +{ + enum lfds700_misc_flag + finished_flag = LFDS700_MISC_FLAG_LOWERED; + + int + rv = 0; + + LFDS700_PAL_ASSERT( hai != NULL ); + LFDS700_PAL_ASSERT( hae != NULL ); + + while( finished_flag == LFDS700_MISC_FLAG_LOWERED ) + { + lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position( hai->baus, &hai->baue, LFDS700_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE, LFDS700_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE ); + + if( hai->baue != NULL ) + { + *hae = LFDS700_BTREE_AU_GET_VALUE_FROM_ELEMENT( *hai->baue ); + finished_flag = LFDS700_MISC_FLAG_RAISED; + rv = 1; + } + + if( hai->baue == NULL ) + if( ++hai->baus == hai->baus_end ) + { + *hae = NULL; + finished_flag = LFDS700_MISC_FLAG_RAISED; + } + } + + return( rv ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_query.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_query.c new file mode 100644 index 0000000000..9d89a8838d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_hash_addonly/lfds700_hash_addonly_query.c @@ -0,0 +1,112 @@ +/***** includes *****/ +#include "lfds700_hash_addonly_internal.h" + +/***** private prototypes *****/ +static void lfds700_hash_a_internal_validate( struct lfds700_hash_a_state *has, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_hash_a_validity ); + + + + + +/****************************************************************************/ +void lfds700_hash_a_query( struct lfds700_hash_a_state *has, enum lfds700_hash_a_query query_type, void *query_input, void *query_output ) +{ + LFDS700_PAL_ASSERT( has != NULL ); + // TRD : query_type can be any value in its range + + LFDS700_MISC_BARRIER_LOAD; + + switch( query_type ) + { + case LFDS700_HASH_A_QUERY_GET_POTENTIALLY_INACCURATE_COUNT: + { + struct lfds700_hash_a_iterate + ai; + + struct lfds700_hash_a_element + *hae; + + LFDS700_PAL_ASSERT( query_input == NULL ); + LFDS700_PAL_ASSERT( query_output != NULL ); + + *(lfds700_pal_uint_t *) query_output = 0; + + lfds700_hash_a_iterate_init( has, &ai ); + + while( lfds700_hash_a_iterate(&ai, &hae) ) + ( *(lfds700_pal_uint_t *) query_output )++; + } + break; + + case LFDS700_HASH_A_QUERY_SINGLETHREADED_VALIDATE: + // TRD: query_input can be any value in its range + LFDS700_PAL_ASSERT( query_output != NULL ); + + lfds700_hash_a_internal_validate( has, (struct lfds700_misc_validation_info *) query_input, (enum lfds700_misc_validity *) query_output ); + break; + } + + return; +} + + + + + +/****************************************************************************/ +static void lfds700_hash_a_internal_validate( struct lfds700_hash_a_state *has, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_hash_a_validity ) +{ + lfds700_pal_uint_t + lfds700_hash_a_total_number_elements = 0, + lfds700_btree_au_total_number_elements = 0, + number_elements; + + lfds700_pal_uint_t + loop; + + LFDS700_PAL_ASSERT( has!= NULL ); + // TRD : vi can be NULL + LFDS700_PAL_ASSERT( lfds700_hash_a_validity != NULL ); + + /* TRD : validate every btree_addonly_unbalanced in the addonly_hash + sum elements in each btree_addonly_unbalanced + check matches expected element counts (if vi is provided) + */ + + *lfds700_hash_a_validity = LFDS700_MISC_VALIDITY_VALID; + + for( loop = 0 ; *lfds700_hash_a_validity == LFDS700_MISC_VALIDITY_VALID and loop < has->array_size ; loop++ ) + lfds700_btree_au_query( has->baus_array+loop, LFDS700_BTREE_AU_QUERY_SINGLETHREADED_VALIDATE, NULL, (void *) lfds700_hash_a_validity ); + + if( *lfds700_hash_a_validity == LFDS700_MISC_VALIDITY_VALID ) + { + for( loop = 0 ; loop < has->array_size ; loop++ ) + { + lfds700_btree_au_query( has->baus_array+loop, LFDS700_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void *) &number_elements ); + lfds700_btree_au_total_number_elements += number_elements; + } + + // TRD : first, check btree_addonly_unbalanced total vs the addonly_hash total + lfds700_hash_a_query( has, LFDS700_HASH_A_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &lfds700_hash_a_total_number_elements ); + + // TRD : the btree_addonly_unbalanceds are assumed to speak the truth + if( lfds700_hash_a_total_number_elements < lfds700_btree_au_total_number_elements ) + *lfds700_hash_a_validity = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + + if( lfds700_hash_a_total_number_elements > lfds700_btree_au_total_number_elements ) + *lfds700_hash_a_validity = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + // TRD : second, if we're still valid and vi is provided, check the btree_addonly_unbalanced total against vi + if( *lfds700_hash_a_validity == LFDS700_MISC_VALIDITY_VALID and vi != NULL ) + { + if( lfds700_btree_au_total_number_elements < vi->min_elements ) + *lfds700_hash_a_validity = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( lfds700_btree_au_total_number_elements > vi->max_elements ) + *lfds700_hash_a_validity = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + } + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_cleanup.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_cleanup.c new file mode 100644 index 0000000000..580fa9b3ac --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_cleanup.c @@ -0,0 +1,37 @@ +/***** includes *****/ +#include "lfds700_list_addonly_ordered_singlylinked_internal.h" + + + + + +/****************************************************************************/ +void lfds700_list_aos_cleanup( struct lfds700_list_aos_state *laoss, + void (*element_cleanup_callback)(struct lfds700_list_aos_state *laoss, struct lfds700_list_aos_element *laose) ) +{ + struct lfds700_list_aos_element + *laose, + *temp; + + LFDS700_PAL_ASSERT( laoss != NULL ); + // TRD : element_cleanup_callback can be NULL + + LFDS700_MISC_BARRIER_LOAD; + + if( element_cleanup_callback == NULL ) + return; + + laose = LFDS700_LIST_AOS_GET_START( *laoss ); + + while( laose != NULL ) + { + temp = laose; + + laose = LFDS700_LIST_AOS_GET_NEXT( *laose ); + + element_cleanup_callback( laoss, temp ); + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_get.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_get.c new file mode 100644 index 0000000000..9d4cab5e53 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_get.c @@ -0,0 +1,29 @@ +/***** includes *****/ +#include "lfds700_list_addonly_ordered_singlylinked_internal.h" + + + + + +/****************************************************************************/ +int lfds700_list_aos_get_by_key( struct lfds700_list_aos_state *laoss, + void *key, + struct lfds700_list_aos_element **laose ) +{ + int + cr = !0, + rv = 1; + + LFDS700_PAL_ASSERT( laoss != NULL ); + LFDS700_PAL_ASSERT( key != NULL ); + LFDS700_PAL_ASSERT( laose != NULL ); + + while( cr != 0 and LFDS700_LIST_AOS_GET_START_AND_THEN_NEXT(*laoss, *laose) ) + cr = laoss->key_compare_function( key, (*laose)->key ); + + if( *laose == NULL ) + rv = 0; + + return( rv ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_init.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_init.c new file mode 100644 index 0000000000..4c92835ce5 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_init.c @@ -0,0 +1,37 @@ +/***** includes *****/ +#include "lfds700_list_addonly_ordered_singlylinked_internal.h" + + + + + +/****************************************************************************/ +void lfds700_list_aos_init_valid_on_current_logical_core( struct lfds700_list_aos_state *laoss, + int (*key_compare_function)(void const *new_key, void const *existing_key), + enum lfds700_list_aos_existing_key existing_key, + void *user_state ) +{ + LFDS700_PAL_ASSERT( laoss != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &laoss->start % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &laoss->dummy_element % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &laoss->key_compare_function % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( key_compare_function != NULL ); + // TRD : existing_key can be any value in its range + // TRD : user_state can be NULL + + // TRD : dummy start element - makes code easier when you can always use ->next + laoss->start = &laoss->dummy_element; + + laoss->start->next = NULL; + laoss->start->value = NULL; + laoss->key_compare_function = key_compare_function; + laoss->existing_key = existing_key; + laoss->user_state = user_state; + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_insert.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_insert.c new file mode 100644 index 0000000000..9beead4e1d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_insert.c @@ -0,0 +1,134 @@ +/***** includes *****/ +#include "lfds700_list_addonly_ordered_singlylinked_internal.h" + + + + + +/****************************************************************************/ +enum lfds700_list_aos_insert_result lfds700_list_aos_insert( struct lfds700_list_aos_state *laoss, + struct lfds700_list_aos_element *laose, + struct lfds700_list_aos_element **existing_laose, + struct lfds700_misc_prng_state *ps ) +{ + char unsigned + result; + + enum lfds700_misc_flag + finished_flag = LFDS700_MISC_FLAG_LOWERED; + + int + compare_result = 0; + + lfds700_pal_uint_t + backoff_iteration = LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE; + + struct lfds700_list_aos_element + *volatile laose_temp = NULL, + *volatile laose_trailing; + + LFDS700_PAL_ASSERT( laoss != NULL ); + LFDS700_PAL_ASSERT( laose != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &laose->next % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &laose->value % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &laose->key % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + // TRD : existing_laose can be NULL + LFDS700_PAL_ASSERT( ps != NULL ); + + /* TRD : imagine a list, sorted small to large + + we arrive at an element + we obtain its next pointer + we check we are greater than the current element and smaller than the next element + this means we have found the correct location to insert + we try to CAS ourselves in; in the meantime, + someone else has *aready* swapped in an element which is smaller than we are + + e.g. + + the list is { 1, 10 } and we are the value 5 + + we arrive at 1; we check the next element and see it is 10 + so we are larger than the current element and smaller than the next + we are in the correct location to insert and we go to insert... + + in the meantime, someone else with the value 3 comes along + he too finds this is the correct location and inserts before we do + the list is now { 1, 3, 10 } and we are trying to insert now after + 1 and before 3! + + our insert CAS fails, because the next pointer of 1 has changed aready; + but we see we are in the wrong location - we need to move forward an + element + */ + + LFDS700_MISC_BARRIER_LOAD; + + /* TRD : we need to begin with the leading dummy element + as the element to be inserted + may be smaller than all elements in the list + */ + + laose_trailing = laoss->start; + laose_temp = laoss->start->next; + + while( finished_flag == LFDS700_MISC_FLAG_LOWERED ) + { + if( laose_temp == NULL ) + compare_result = -1; + + if( laose_temp != NULL ) + { + LFDS700_MISC_BARRIER_LOAD; + compare_result = laoss->key_compare_function( laose->key, laose_temp->key ); + } + + if( compare_result == 0 ) + { + if( existing_laose != NULL ) + *existing_laose = laose_temp; + + switch( laoss->existing_key ) + { + case LFDS700_LIST_AOS_EXISTING_KEY_OVERWRITE: + LFDS700_LIST_AOS_SET_VALUE_IN_ELEMENT( *laose_temp, laose->value ); + return( LFDS700_LIST_AOS_INSERT_RESULT_SUCCESS_OVERWRITE ); + break; + + case LFDS700_LIST_AOS_EXISTING_KEY_FAIL: + return( LFDS700_LIST_AOS_INSERT_RESULT_FAILURE_EXISTING_KEY ); + break; + } + + finished_flag = LFDS700_MISC_FLAG_RAISED; + } + + if( compare_result < 0 ) + { + laose->next = laose_temp; + LFDS700_MISC_BARRIER_STORE; + LFDS700_PAL_ATOMIC_CAS_WITH_BACKOFF( &laose_trailing->next, &laose->next, laose, LFDS700_MISC_CAS_STRENGTH_WEAK, result, backoff_iteration, ps ); + + if( result == 1 ) + finished_flag = LFDS700_MISC_FLAG_RAISED; + else + // TRD : if we fail to link, someone else has linked and so we need to redetermine our position is correct + laose_temp = laose_trailing->next; + } + + if( compare_result > 0 ) + { + // TRD : move trailing along by one element + laose_trailing = laose_trailing->next; + + /* TRD : set temp as the element after trailing + if the new element we're linking is larger than all elements in the list, + laose_temp will now go to NULL and we'll link at the end + */ + laose_temp = laose_trailing->next; + } + } + + return( LFDS700_LIST_AOS_INSERT_RESULT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_internal.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_internal.h new file mode 100644 index 0000000000..7a7d541804 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_internal.h @@ -0,0 +1,5 @@ +/***** the library wide include file *****/ +#include "../liblfds700_internal.h" + +/***** private prototypes *****/ + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_query.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_query.c new file mode 100644 index 0000000000..a1d990ab79 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_ordered_singlylinked/lfds700_list_addonly_ordered_singlylinked_query.c @@ -0,0 +1,121 @@ +/***** includes *****/ +#include "lfds700_list_addonly_ordered_singlylinked_internal.h" + +/***** private prototypes *****/ +static void lfds700_list_aos_internal_validate( struct lfds700_list_aos_state *laoss, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_list_aos_validity ); + + + + + +/****************************************************************************/ +void lfds700_list_aos_query( struct lfds700_list_aos_state *laoss, enum lfds700_list_aos_query query_type, void *query_input, void *query_output ) +{ + LFDS700_PAL_ASSERT( laoss != NULL ); + // TRD : query_type can be any value in its range + + LFDS700_MISC_BARRIER_LOAD; + + switch( query_type ) + { + case LFDS700_LIST_AOS_QUERY_GET_POTENTIALLY_INACCURATE_COUNT: + { + struct lfds700_list_aos_element + *laose = NULL; + + LFDS700_PAL_ASSERT( query_input == NULL ); + LFDS700_PAL_ASSERT( query_output != NULL ); + + *(lfds700_pal_uint_t *) query_output = 0; + + while( LFDS700_LIST_AOS_GET_START_AND_THEN_NEXT(*laoss, laose) ) + ( *(lfds700_pal_uint_t *) query_output )++; + } + break; + + case LFDS700_LIST_AOS_QUERY_SINGLETHREADED_VALIDATE: + // TRD : query_input can be NULL + LFDS700_PAL_ASSERT( query_output != NULL ); + + lfds700_list_aos_internal_validate( laoss, (struct lfds700_misc_validation_info *) query_input, (enum lfds700_misc_validity *) query_output ); + break; + } + + return; +} + + + + + + +/****************************************************************************/ +static void lfds700_list_aos_internal_validate( struct lfds700_list_aos_state *laoss, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_list_aos_validity ) +{ + lfds700_pal_uint_t + number_elements = 0; + + struct lfds700_list_aos_element + *laose_fast, + *laose_slow; + + LFDS700_PAL_ASSERT( laoss!= NULL ); + // TRD : vi can be NULL + LFDS700_PAL_ASSERT( lfds700_list_aos_validity != NULL ); + + *lfds700_list_aos_validity = LFDS700_MISC_VALIDITY_VALID; + + laose_slow = laose_fast = laoss->start->next; + + /* TRD : first, check for a loop + we have two pointers + both of which start at the start of the list + we enter a loop + and on each iteration + we advance one pointer by one element + and the other by two + + we exit the loop when both pointers are NULL + (have reached the end of the queue) + + or + + if we fast pointer 'sees' the slow pointer + which means we have a loop + */ + + if( laose_slow != NULL ) + do + { + laose_slow = laose_slow->next; + + if( laose_fast != NULL ) + laose_fast = laose_fast->next; + + if( laose_fast != NULL ) + laose_fast = laose_fast->next; + } + while( laose_slow != NULL and laose_fast != laose_slow ); + + if( laose_fast != NULL and laose_slow != NULL and laose_fast == laose_slow ) + *lfds700_list_aos_validity = LFDS700_MISC_VALIDITY_INVALID_LOOP; + + /* TRD : now check for expected number of elements + vi can be NULL, in which case we do not check + we know we don't have a loop from our earlier check + */ + + if( *lfds700_list_aos_validity == LFDS700_MISC_VALIDITY_VALID and vi != NULL ) + { + lfds700_list_aos_query( laoss, LFDS700_LIST_AOS_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &number_elements ); + + if( number_elements < vi->min_elements ) + *lfds700_list_aos_validity = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( number_elements > vi->max_elements ) + *lfds700_list_aos_validity = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_cleanup.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_cleanup.c new file mode 100644 index 0000000000..ef19ce1f86 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_cleanup.c @@ -0,0 +1,37 @@ +/***** includes *****/ +#include "lfds700_list_addonly_singlylinked_unordered_internal.h" + + + + + +/****************************************************************************/ +void lfds700_list_asu_cleanup( struct lfds700_list_asu_state *lasus, + void (*element_cleanup_callback)(struct lfds700_list_asu_state *lasus, struct lfds700_list_asu_element *lasue) ) +{ + struct lfds700_list_asu_element + *lasue, + *temp; + + LFDS700_PAL_ASSERT( lasus != NULL ); + // TRD : element_cleanup_callback can be NULL + + LFDS700_MISC_BARRIER_LOAD; + + if( element_cleanup_callback == NULL ) + return; + + lasue = LFDS700_LIST_ASU_GET_START( *lasus ); + + while( lasue != NULL ) + { + temp = lasue; + + lasue = LFDS700_LIST_ASU_GET_NEXT( *lasue ); + + element_cleanup_callback( lasus, temp ); + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_get.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_get.c new file mode 100644 index 0000000000..ae99ebfca4 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_get.c @@ -0,0 +1,29 @@ +/***** includes *****/ +#include "lfds700_list_addonly_singlylinked_unordered_internal.h" + + + + + +/****************************************************************************/ +int lfds700_list_asu_get_by_key( struct lfds700_list_asu_state *lasus, + void *key, + struct lfds700_list_asu_element **lasue ) +{ + int + cr = !0, + rv = 1; + + LFDS700_PAL_ASSERT( lasus != NULL ); + LFDS700_PAL_ASSERT( key != NULL ); + LFDS700_PAL_ASSERT( lasue != NULL ); + + while( cr != 0 and LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*lasus, *lasue) ) + cr = lasus->key_compare_function( key, (*lasue)->key ); + + if( *lasue == NULL ) + rv = 0; + + return( rv ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_init.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_init.c new file mode 100644 index 0000000000..78b0d8eae6 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_init.c @@ -0,0 +1,35 @@ +/***** includes *****/ +#include "lfds700_list_addonly_singlylinked_unordered_internal.h" + + + + + +/****************************************************************************/ +void lfds700_list_asu_init_valid_on_current_logical_core( struct lfds700_list_asu_state *lasus, + int (*key_compare_function)(void const *new_key, void const *existing_key), + void *user_state ) +{ + LFDS700_PAL_ASSERT( lasus != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasus->end % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasus->start % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasus->dummy_element % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasus->key_compare_function % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + // TRD : key_compare_function can be NULL + // TRD : user_state can be NULL + + // TRD : dummy start element - makes code easier when you can always use ->next + lasus->start = lasus->end = &lasus->dummy_element; + + lasus->start->next = NULL; + lasus->start->value = NULL; + lasus->key_compare_function = key_compare_function; + lasus->user_state = user_state; + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_insert.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_insert.c new file mode 100644 index 0000000000..ce2ee825aa --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_insert.c @@ -0,0 +1,193 @@ +/***** includes *****/ +#include "lfds700_list_addonly_singlylinked_unordered_internal.h" + + + + + +/****************************************************************************/ +void lfds700_list_asu_insert_at_position( struct lfds700_list_asu_state *lasus, + struct lfds700_list_asu_element *lasue, + struct lfds700_list_asu_element *lasue_predecessor, + enum lfds700_list_asu_position position, + struct lfds700_misc_prng_state *ps ) +{ + LFDS700_PAL_ASSERT( lasus != NULL ); + LFDS700_PAL_ASSERT( lasue != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasue->next % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasue->value % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasue->key % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + // TRD : lasue_predecessor asserted in the switch + // TRD : position can be any value in its range + LFDS700_PAL_ASSERT( ps != NULL ); + + switch( position ) + { + case LFDS700_LIST_ASU_POSITION_START: + lfds700_list_asu_insert_at_start( lasus, lasue, ps ); + break; + + case LFDS700_LIST_ASU_POSITION_END: + lfds700_list_asu_insert_at_end( lasus, lasue, ps ); + break; + + case LFDS700_LIST_ASU_POSITION_AFTER: + lfds700_list_asu_insert_after_element( lasus, lasue, lasue_predecessor, ps ); + break; + } + + return; +} + + + + + +/****************************************************************************/ +void lfds700_list_asu_insert_at_start( struct lfds700_list_asu_state *lasus, + struct lfds700_list_asu_element *lasue, + struct lfds700_misc_prng_state *ps ) +{ + char unsigned + result; + + lfds700_pal_uint_t + backoff_iteration = LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE; + + LFDS700_PAL_ASSERT( lasus != NULL ); + LFDS700_PAL_ASSERT( lasue != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasue->next % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasue->value % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasue->key % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( ps != NULL ); + + LFDS700_MISC_BARRIER_LOAD; + + lasue->next = lasus->start->next; + + do + { + LFDS700_MISC_BARRIER_STORE; + LFDS700_PAL_ATOMIC_CAS_WITH_BACKOFF( &lasus->start->next, &lasue->next, lasue, LFDS700_MISC_CAS_STRENGTH_WEAK, result, backoff_iteration, ps ); + } + while( result != 1 ); + + return; +} + + + + + +/****************************************************************************/ +void lfds700_list_asu_insert_at_end( struct lfds700_list_asu_state *lasus, + struct lfds700_list_asu_element *lasue, + struct lfds700_misc_prng_state *ps ) +{ + char unsigned + result; + + enum lfds700_misc_flag + finished_flag = LFDS700_MISC_FLAG_LOWERED; + + lfds700_pal_uint_t + backoff_iteration = LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE; + + struct lfds700_list_asu_element LFDS700_PAL_ALIGN(LFDS700_PAL_ALIGN_SINGLE_POINTER) + *compare; + + struct lfds700_list_asu_element + *volatile lasue_next, + *volatile lasue_end; + + LFDS700_PAL_ASSERT( lasus != NULL ); + LFDS700_PAL_ASSERT( lasue != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasue->next % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasue->value % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasue->key % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( ps != NULL ); + + /* TRD : begin by assuming end is correctly pointing to the final element + try to link (comparing for next being NULL) + if we fail, move down list till we find last element + and retry + when successful, update end to ourselves + + note there's a leading dummy element + so lasus->end always points to an element + */ + + LFDS700_MISC_BARRIER_LOAD; + + lasue->next = NULL; + lasue_end = lasus->end; + + while( finished_flag == LFDS700_MISC_FLAG_LOWERED ) + { + compare = NULL; + + LFDS700_MISC_BARRIER_STORE; + LFDS700_PAL_ATOMIC_CAS_WITH_BACKOFF( &lasue_end->next, &compare, lasue, LFDS700_MISC_CAS_STRENGTH_STRONG, result, backoff_iteration, ps ); + + if( result == 1 ) + finished_flag = LFDS700_MISC_FLAG_RAISED; + else + { + lasue_end = compare; + lasue_next = LFDS700_LIST_ASU_GET_NEXT( *lasue_end ); + + while( lasue_next != NULL ) + { + lasue_end = lasue_next; + lasue_next = LFDS700_LIST_ASU_GET_NEXT( *lasue_end ); + } + } + } + + lasus->end = lasue; + + return; +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +void lfds700_list_asu_insert_after_element( struct lfds700_list_asu_state *lasus, + struct lfds700_list_asu_element *lasue, + struct lfds700_list_asu_element *lasue_predecessor, + struct lfds700_misc_prng_state *ps ) +{ + char unsigned + result; + + lfds700_pal_uint_t + backoff_iteration = LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE; + + LFDS700_PAL_ASSERT( lasus != NULL ); + LFDS700_PAL_ASSERT( lasue != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasue->next % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasue->value % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &lasue->key % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( lasue_predecessor != NULL ); + LFDS700_PAL_ASSERT( ps != NULL ); + + LFDS700_MISC_BARRIER_LOAD; + + lasue->next = lasue_predecessor->next; + + do + { + LFDS700_MISC_BARRIER_STORE; + LFDS700_PAL_ATOMIC_CAS_WITH_BACKOFF( &lasue_predecessor->next, &lasue->next, lasue, LFDS700_MISC_CAS_STRENGTH_WEAK, result, backoff_iteration, ps ); + } + while( result != 1 ); + + return; +} + +#pragma warning( default : 4100 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_internal.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_internal.h new file mode 100644 index 0000000000..7a7d541804 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_internal.h @@ -0,0 +1,5 @@ +/***** the library wide include file *****/ +#include "../liblfds700_internal.h" + +/***** private prototypes *****/ + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_query.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_query.c new file mode 100644 index 0000000000..0adf5a8032 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_list_addonly_singlylinked_unordered/lfds700_list_addonly_singlylinked_unordered_query.c @@ -0,0 +1,121 @@ +/***** includes *****/ +#include "lfds700_list_addonly_singlylinked_unordered_internal.h" + +/***** private prototypes *****/ +static void lfds700_list_asu_internal_validate( struct lfds700_list_asu_state *lasus, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_list_asu_validity ); + + + + + +/****************************************************************************/ +void lfds700_list_asu_query( struct lfds700_list_asu_state *lasus, enum lfds700_list_asu_query query_type, void *query_input, void *query_output ) +{ + LFDS700_PAL_ASSERT( lasus != NULL ); + // TRD : query_type can be any value in its range + + LFDS700_MISC_BARRIER_LOAD; + + switch( query_type ) + { + case LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT: + { + struct lfds700_list_asu_element + *lasue = NULL; + + LFDS700_PAL_ASSERT( query_input == NULL ); + LFDS700_PAL_ASSERT( query_output != NULL ); + + *(lfds700_pal_uint_t *) query_output = 0; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*lasus, lasue) ) + ( *(lfds700_pal_uint_t *) query_output )++; + } + break; + + case LFDS700_LIST_ASU_QUERY_SINGLETHREADED_VALIDATE: + // TRD : query_input can be NULL + LFDS700_PAL_ASSERT( query_output != NULL ); + + lfds700_list_asu_internal_validate( lasus, (struct lfds700_misc_validation_info *) query_input, (enum lfds700_misc_validity *) query_output ); + break; + } + + return; +} + + + + + + +/****************************************************************************/ +static void lfds700_list_asu_internal_validate( struct lfds700_list_asu_state *lasus, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_list_asu_validity ) +{ + lfds700_pal_uint_t + number_elements = 0; + + struct lfds700_list_asu_element + *lasue_fast, + *lasue_slow; + + LFDS700_PAL_ASSERT( lasus!= NULL ); + // TRD : vi can be NULL + LFDS700_PAL_ASSERT( lfds700_list_asu_validity != NULL ); + + *lfds700_list_asu_validity = LFDS700_MISC_VALIDITY_VALID; + + lasue_slow = lasue_fast = lasus->start->next; + + /* TRD : first, check for a loop + we have two pointers + both of which start at the start of the list + we enter a loop + and on each iteration + we advance one pointer by one element + and the other by two + + we exit the loop when both pointers are NULL + (have reached the end of the queue) + + or + + if we fast pointer 'sees' the slow pointer + which means we have a loop + */ + + if( lasue_slow != NULL ) + do + { + lasue_slow = lasue_slow->next; + + if( lasue_fast != NULL ) + lasue_fast = lasue_fast->next; + + if( lasue_fast != NULL ) + lasue_fast = lasue_fast->next; + } + while( lasue_slow != NULL and lasue_fast != lasue_slow ); + + if( lasue_fast != NULL and lasue_slow != NULL and lasue_fast == lasue_slow ) + *lfds700_list_asu_validity = LFDS700_MISC_VALIDITY_INVALID_LOOP; + + /* TRD : now check for expected number of elements + vi can be NULL, in which case we do not check + we know we don't have a loop from our earlier check + */ + + if( *lfds700_list_asu_validity == LFDS700_MISC_VALIDITY_VALID and vi != NULL ) + { + lfds700_list_asu_query( lasus, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &number_elements ); + + if( number_elements < vi->min_elements ) + *lfds700_list_asu_validity = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( number_elements > vi->max_elements ) + *lfds700_list_asu_validity = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_cleanup.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_cleanup.c new file mode 100644 index 0000000000..d93c95db0f --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_cleanup.c @@ -0,0 +1,15 @@ +/***** includes *****/ +#include "lfds700_misc_internal.h" + + + + + +/****************************************************************************/ +void lfds700_misc_library_cleanup( void ) +{ + // TRD : we do nuuuuuuthin' + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_globals.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_globals.c new file mode 100644 index 0000000000..af2826675a --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_globals.c @@ -0,0 +1,11 @@ +/***** includes *****/ +#include "lfds700_misc_internal.h" + + + + + +/****************************************************************************/ +struct lfds700_misc_globals + lfds700_misc_globals; + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_init.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_init.c new file mode 100644 index 0000000000..32685077bf --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_init.c @@ -0,0 +1,53 @@ +/***** includes *****/ +#include "lfds700_misc_internal.h" + + + + + +/****************************************************************************/ +void lfds700_misc_library_init_valid_on_current_logical_core() +{ + /* TRD : the PRNG arrangement is that each thread has its own state, for a maximum-speed PRNG, where output + quality is second consideration to performance + + on 64-bit platforms this is xorshift64*, on 32-bit platforms, an unadorned xorshift32 + + the seed for each thread however comes from a single, global, maximum-quality PRNG, where quality of + output is the primary consideration + + for this, I'm using a xorshift1024* + + since the generation from this global PRNG state is not thread safe, but is still quick in + thread start-up terms, I run a little spin-lock around it + + regarding the seed for this high quality PRNG; it is customary to use time(), but this has a number of + drawbacks; + + 1. liblfds would depend on time() (currently it does not depend on a hosted implementation of standard library) + 2. the output from time may only be 32 bit, and even when it isn't, the top 32 bits are currently all zero... + 3. many threads can begin in the same second; I'd need to add in their thread number, + which means I'd need to *get* their thread number... + + as such, I've decided to use a *fixed* 64-bit seed for the high-quality PRNG; this seed is run + through the MurmerHash3 avalanche phase to generate successive 64-bit values, which populate + the 1024 state of xorshift1024* + + if you have access to a high-frequency clock (often 64-bit), you can use this for the seed + (don't use it for the per-thread PRNG, unless you know the clock can be read without a context switch) + + murmurhash3 code from here; http://xorshift.di.unimi.it/murmurhash3.c + */ + + lfds700_misc_prng_internal_big_slow_high_quality_init( LFDS700_MISC_PRNG_SEED ); + + lfds700_misc_globals.exponential_backoff_timeslot_length_in_loop_iterations_for_cas = EXPONENTIAL_BACKOFF_TIMESLOT_LENGTH_IN_INCS_FOR_CAS; + lfds700_misc_globals.exponential_backoff_timeslot_length_in_loop_iterations_for_dwcas = EXPONENTIAL_BACKOFF_TIMESLOT_LENGTH_IN_INCS_FOR_DWCAS; + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_internal.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_internal.h new file mode 100644 index 0000000000..9ed927efc9 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_internal.h @@ -0,0 +1,10 @@ +/***** the library wide include file *****/ +#include "../liblfds700_internal.h" + +/***** defines *****/ +#define EXPONENTIAL_BACKOFF_TIMESLOT_LENGTH_IN_INCS_FOR_CAS 8 +#define EXPONENTIAL_BACKOFF_TIMESLOT_LENGTH_IN_INCS_FOR_DWCAS 16 + +/***** private prototypes *****/ +void lfds700_misc_prng_internal_big_slow_high_quality_init( int long long unsigned seed ); + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_prng.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_prng.c new file mode 100644 index 0000000000..84ae25fe71 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_prng.c @@ -0,0 +1,144 @@ +/***** includes *****/ +#include "lfds700_misc_internal.h" + +/***** defines *****/ +#define LFDS700_PRNG_STATE_SIZE 16 + +/***** struct *****/ +struct lfds700_misc_prng_big_slow_high_quality_state +{ + lfds700_pal_atom_t LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + xorshift1024star_spinlock; + + // TRD : must be a 32 bit signed int + int + xorshift1024star_index; + + int long long unsigned + xorshift1024star_state[LFDS700_PRNG_STATE_SIZE]; +}; + +/***** locals *****/ +struct lfds700_misc_prng_big_slow_high_quality_state + pbshqs; + +/***** private prototypes *****/ +static void lfds700_misc_prng_internal_hash_murmurhash3( int long long unsigned *murmurhash3_state ); +static void lfds700_misc_prng_internal_big_slow_high_quality_generate( struct lfds700_misc_prng_big_slow_high_quality_state *ps, lfds700_pal_uint_t *random_value ); + + + + + +/****************************************************************************/ +void lfds700_misc_prng_init( struct lfds700_misc_prng_state *ps ) +{ + LFDS700_PAL_ASSERT( ps != NULL ); + + /* TRD : we use the big, slow, high quality PRNG to generate the initial value + for the small, fast, low qulity PRNG, which is used in exponential backoff + + we need the load barrier to catch any changes to the backoff periods + */ + + lfds700_misc_prng_internal_big_slow_high_quality_generate( &pbshqs, &ps->prng_state ); + + LFDS700_MISC_BARRIER_LOAD; + + ps->local_copy_of_global_exponential_backoff_timeslot_length_in_loop_iterations_for_cas = lfds700_misc_globals.exponential_backoff_timeslot_length_in_loop_iterations_for_cas; + ps->local_copy_of_global_exponential_backoff_timeslot_length_in_loop_iterations_for_dwcas = lfds700_misc_globals.exponential_backoff_timeslot_length_in_loop_iterations_for_dwcas; + + return; +} + + + + + +/****************************************************************************/ +void lfds700_misc_prng_internal_big_slow_high_quality_init( int long long unsigned seed ) +{ + lfds700_pal_uint_t + loop; + + LFDS700_PAL_ASSERT( seed != 0 ); // TRD : a 0 seed causes all zeros in the entropy state, so is forbidden + + pbshqs.xorshift1024star_spinlock = LFDS700_MISC_FLAG_LOWERED; + + for( loop = 0 ; loop < LFDS700_PRNG_STATE_SIZE ; loop++ ) + { + lfds700_misc_prng_internal_hash_murmurhash3( &seed ); + pbshqs.xorshift1024star_state[loop] = seed; + } + + pbshqs.xorshift1024star_index = 0; + + return; +} + + + + + +/****************************************************************************/ +static void lfds700_misc_prng_internal_hash_murmurhash3( int long long unsigned *murmurhash3_state ) +{ + LFDS700_PAL_ASSERT( murmurhash3_state != NULL ); + + *murmurhash3_state ^= *murmurhash3_state >> 33; + *murmurhash3_state *= 0xff51afd7ed558ccdULL; + *murmurhash3_state ^= *murmurhash3_state >> 33; + *murmurhash3_state *= 0xc4ceb9fe1a85ec53ULL; + *murmurhash3_state ^= *murmurhash3_state >> 33; + + return; +} + + + + + +/****************************************************************************/ +static void lfds700_misc_prng_internal_big_slow_high_quality_generate( struct lfds700_misc_prng_big_slow_high_quality_state *ps, lfds700_pal_uint_t *random_value ) +{ + char unsigned + result; + + int long long unsigned + xs_temp_one, + xs_temp_two; + + lfds700_pal_atom_t + compare = LFDS700_MISC_FLAG_LOWERED, + exchange = LFDS700_MISC_FLAG_LOWERED; + + LFDS700_PAL_ASSERT( ps != NULL ); + LFDS700_PAL_ASSERT( random_value != NULL ); + + // TRD : this is single-threaded code, on a per-state basis + do + { + compare = LFDS700_MISC_FLAG_LOWERED; + LFDS700_PAL_ATOMIC_CAS( &ps->xorshift1024star_spinlock, &compare, (lfds700_pal_atom_t) LFDS700_MISC_FLAG_RAISED, LFDS700_MISC_CAS_STRENGTH_STRONG, result ); + } + while( result == 0 ); + + // TRD : xorshift1024* code from here; http://xorshift.di.unimi.it/xorshift1024star.c + + xs_temp_one = ps->xorshift1024star_state[ ps->xorshift1024star_index ]; + ps->xorshift1024star_index = ( ps->xorshift1024star_index + 1 ) & 15; + xs_temp_two = ps->xorshift1024star_state[ ps->xorshift1024star_index ]; + + xs_temp_two ^= xs_temp_two << 31; + xs_temp_two ^= xs_temp_two >> 11; + xs_temp_one ^= xs_temp_one >> 30; + + ps->xorshift1024star_state[ ps->xorshift1024star_index ] = xs_temp_one ^ xs_temp_two; + + *random_value = (lfds700_pal_uint_t) ( ps->xorshift1024star_state[ ps->xorshift1024star_index ] * 1181783497276652981LL ); + + LFDS700_PAL_ATOMIC_EXCHANGE( &ps->xorshift1024star_spinlock, &exchange ); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_query.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_query.c new file mode 100644 index 0000000000..fd3595d86a --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_misc/lfds700_misc_query.c @@ -0,0 +1,48 @@ +/***** includes *****/ +#include "lfds700_misc_internal.h" + + + + + +/****************************************************************************/ +void lfds700_misc_query( enum lfds700_misc_query query_type, void *query_input, void *query_output ) +{ + // TRD : query type can be any value in its range + // TRD : query_input can be NULL in some cases + // TRD : query_outputput can be NULL in some cases + + switch( query_type ) + { + case LFDS700_MISC_QUERY_GET_EXPONENTIAL_BACKOFF_TIMESLOT_LENGTH_IN_LOOP_ITERATIONS_FOR_CAS: + *(lfds700_pal_atom_t *) query_output = lfds700_misc_globals.exponential_backoff_timeslot_length_in_loop_iterations_for_cas; + break; + + case LFDS700_MISC_QUERY_SET_EXPONENTIAL_BACKOFF_TIMESLOT_LENGTH_IN_LOOP_ITERATIONS_FOR_CAS: + LFDS700_PAL_ATOMIC_EXCHANGE( &lfds700_misc_globals.exponential_backoff_timeslot_length_in_loop_iterations_for_cas, (lfds700_pal_atom_t *) query_input ); + break; + + case LFDS700_MISC_QUERY_GET_EXPONENTIAL_BACKOFF_TIMESLOT_LENGTH_IN_LOOP_ITERATIONS_FOR_DWCAS: + *(lfds700_pal_atom_t *) query_output = lfds700_misc_globals.exponential_backoff_timeslot_length_in_loop_iterations_for_dwcas; + break; + + case LFDS700_MISC_QUERY_SET_EXPONENTIAL_BACKOFF_TIMESLOT_LENGTH_IN_LOOP_ITERATIONS_FOR_DWCAS: + LFDS700_PAL_ATOMIC_EXCHANGE( &lfds700_misc_globals.exponential_backoff_timeslot_length_in_loop_iterations_for_dwcas, (lfds700_pal_atom_t *) query_input ); + break; + + case LFDS700_MISC_QUERY_GET_BUILD_AND_VERSION_STRING: + { + char static const + * const build_and_version_string = "liblfds " LFDS700_MISC_VERSION_STRING " (" BUILD_TYPE_STRING ", " LFDS700_PAL_OS_STRING ", " MODE_TYPE_STRING ", " LFDS700_PAL_PROCESSOR_STRING ", " LFDS700_PAL_COMPILER_STRING ")"; + + LFDS700_PAL_ASSERT( query_input == NULL ); + LFDS700_PAL_ASSERT( query_output != NULL ); + + *(char const **) query_output = build_and_version_string; + } + break; + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_cleanup.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_cleanup.c new file mode 100644 index 0000000000..f2da905dbe --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_cleanup.c @@ -0,0 +1,48 @@ +/***** includes *****/ +#include "lfds700_queue_internal.h" + + + + + +/****************************************************************************/ +void lfds700_queue_cleanup( struct lfds700_queue_state *qs, + void (*element_cleanup_callback)(struct lfds700_queue_state *qs, struct lfds700_queue_element *qe, enum lfds700_misc_flag dummy_element_flag) ) +{ + struct lfds700_queue_element + *qe; + + void + *value; + + LFDS700_PAL_ASSERT( qs != NULL ); + // TRD : element_cleanup_callback can be NULL + + LFDS700_MISC_BARRIER_LOAD; + + if( element_cleanup_callback != NULL ) + { + while( qs->dequeue[POINTER] != qs->enqueue[POINTER] ) + { + // TRD : trailing dummy element, so the first real value is in the next element + value = qs->dequeue[POINTER]->next[POINTER]->value; + + // TRD : user is given back *an* element, but not the one his user data was in + qe = qs->dequeue[POINTER]; + + // TRD : remove the element from queue + qs->dequeue[POINTER] = qs->dequeue[POINTER]->next[POINTER]; + + // TRD : write value into the qe we're going to give the user + qe->value = value; + + element_cleanup_callback( qs, qe, LFDS700_MISC_FLAG_LOWERED ); + } + + // TRD : and now the final element + element_cleanup_callback( qs, (struct lfds700_queue_element *) qs->dequeue[POINTER], LFDS700_MISC_FLAG_RAISED ); + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_dequeue.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_dequeue.c new file mode 100644 index 0000000000..853c585039 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_dequeue.c @@ -0,0 +1,109 @@ +/***** includes *****/ +#include "lfds700_queue_internal.h" + + + + + +/****************************************************************************/ +int lfds700_queue_dequeue( struct lfds700_queue_state *qs, + struct lfds700_queue_element **qe, + struct lfds700_misc_prng_state *ps ) +{ + char unsigned + result = 0, + unwanted_result; + + enum lfds700_queue_queue_state + state = LFDS700_QUEUE_QUEUE_STATE_UNKNOWN; + + int + rv = 1, + finished_flag = LFDS700_MISC_FLAG_LOWERED; + + lfds700_pal_uint_t + backoff_iteration = LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE; + + struct lfds700_queue_element LFDS700_PAL_ALIGN(LFDS700_PAL_ALIGN_DOUBLE_POINTER) + *dequeue[PAC_SIZE], + *enqueue[PAC_SIZE], + *next[PAC_SIZE]; + + void + *key = NULL, + *value = NULL; + + LFDS700_PAL_ASSERT( qs != NULL ); + LFDS700_PAL_ASSERT( qe != NULL ); + LFDS700_PAL_ASSERT( ps != NULL ); + + LFDS700_MISC_BARRIER_LOAD; + + do + { + dequeue[COUNTER] = qs->dequeue[COUNTER]; + dequeue[POINTER] = qs->dequeue[POINTER]; + + enqueue[COUNTER] = qs->enqueue[COUNTER]; + enqueue[POINTER] = qs->enqueue[POINTER]; + + next[COUNTER] = qs->dequeue[POINTER]->next[COUNTER]; + next[POINTER] = qs->dequeue[POINTER]->next[POINTER]; + + LFDS700_MISC_BARRIER_LOAD; + + if( dequeue[COUNTER] == qs->dequeue[COUNTER] and dequeue[POINTER] == qs->dequeue[POINTER] ) + { + if( enqueue[POINTER] == dequeue[POINTER] and next[POINTER] == NULL ) + state = LFDS700_QUEUE_QUEUE_STATE_EMPTY; + + if( enqueue[POINTER] == dequeue[POINTER] and next[POINTER] != NULL ) + state = LFDS700_QUEUE_QUEUE_STATE_ENQUEUE_OUT_OF_PLACE; + + if( enqueue[POINTER] != dequeue[POINTER] ) + state = LFDS700_QUEUE_QUEUE_STATE_ATTEMPT_DEQUEUE; + + switch( state ) + { + case LFDS700_QUEUE_QUEUE_STATE_UNKNOWN: + // TRD : eliminates compiler warning + break; + + case LFDS700_QUEUE_QUEUE_STATE_EMPTY: + rv = 0; + *qe = NULL; + finished_flag = LFDS700_MISC_FLAG_RAISED; + break; + + case LFDS700_QUEUE_QUEUE_STATE_ENQUEUE_OUT_OF_PLACE: + next[COUNTER] = enqueue[COUNTER] + 1; + LFDS700_MISC_BARRIER_STORE; + LFDS700_PAL_ATOMIC_DWCAS( qs->enqueue, enqueue, next, LFDS700_MISC_CAS_STRENGTH_WEAK, unwanted_result ); + break; + + case LFDS700_QUEUE_QUEUE_STATE_ATTEMPT_DEQUEUE: + key = next[POINTER]->key; + value = next[POINTER]->value; + + next[COUNTER] = dequeue[COUNTER] + 1; + LFDS700_MISC_BARRIER_STORE; + LFDS700_PAL_ATOMIC_DWCAS_WITH_BACKOFF( qs->dequeue, dequeue, next, LFDS700_MISC_CAS_STRENGTH_WEAK, result, backoff_iteration, ps ); + + if( result == 1 ) + finished_flag = LFDS700_MISC_FLAG_RAISED; + break; + } + } + } + while( finished_flag == LFDS700_MISC_FLAG_LOWERED ); + + if( result == 1 ) + { + *qe = dequeue[POINTER]; + (*qe)->key = key; + (*qe)->value = value; + } + + return( rv ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_enqueue.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_enqueue.c new file mode 100644 index 0000000000..07df84d851 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_enqueue.c @@ -0,0 +1,74 @@ +/***** includes *****/ +#include "lfds700_queue_internal.h" + + + + + +/****************************************************************************/ +void lfds700_queue_enqueue( struct lfds700_queue_state *qs, + struct lfds700_queue_element *qe, + struct lfds700_misc_prng_state *ps ) +{ + char unsigned + result = 0, + unwanted_result; + + lfds700_pal_uint_t + backoff_iteration = LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE; + + struct lfds700_queue_element LFDS700_PAL_ALIGN(LFDS700_PAL_ALIGN_DOUBLE_POINTER) + *volatile enqueue[PAC_SIZE], + *new_enqueue[PAC_SIZE], + *volatile next[PAC_SIZE]; + + LFDS700_PAL_ASSERT( qs != NULL ); + LFDS700_PAL_ASSERT( qe != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) qe->next % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &qe->key % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( ps != NULL ); + + qe->next[COUNTER] = (struct lfds700_queue_element *) LFDS700_MISC_PRNG_GENERATE( ps ); + qe->next[POINTER] = NULL; + + new_enqueue[POINTER] = qe; + + LFDS700_MISC_BARRIER_LOAD; + + do + { + enqueue[COUNTER] = qs->enqueue[COUNTER]; + enqueue[POINTER] = qs->enqueue[POINTER]; + + next[COUNTER] = qs->enqueue[POINTER]->next[COUNTER]; + next[POINTER] = qs->enqueue[POINTER]->next[POINTER]; + + LFDS700_MISC_BARRIER_LOAD; + + if( qs->enqueue[COUNTER] == enqueue[COUNTER] and qs->enqueue[POINTER] == enqueue[POINTER] ) + { + if( next[POINTER] == NULL ) + { + new_enqueue[COUNTER] = next[COUNTER] + 1; + LFDS700_MISC_BARRIER_STORE; + LFDS700_PAL_ATOMIC_DWCAS_WITH_BACKOFF( enqueue[POINTER]->next, next, new_enqueue, LFDS700_MISC_CAS_STRENGTH_WEAK, result, backoff_iteration, ps ); + } + else + { + next[COUNTER] = enqueue[COUNTER] + 1; + LFDS700_MISC_BARRIER_STORE; + // TRD : strictly, this is a weak CAS, but we do an extra iteration of the main loop on a fake failure, so we set it to be strong + LFDS700_PAL_ATOMIC_DWCAS( qs->enqueue, enqueue, next, LFDS700_MISC_CAS_STRENGTH_STRONG, unwanted_result ); + } + } + } + while( result != 1 ); + + new_enqueue[COUNTER] = enqueue[COUNTER] + 1; + LFDS700_MISC_BARRIER_STORE; + // TRD : move enqueue along; only a weak CAS as the dequeue will solve this if its out of place + LFDS700_PAL_ATOMIC_DWCAS( qs->enqueue, enqueue, new_enqueue, LFDS700_MISC_CAS_STRENGTH_WEAK, unwanted_result ); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_init.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_init.c new file mode 100644 index 0000000000..15f4e64d8d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_init.c @@ -0,0 +1,43 @@ +/***** includes *****/ +#include "lfds700_queue_internal.h" + + + + + +/****************************************************************************/ +void lfds700_queue_init_valid_on_current_logical_core( struct lfds700_queue_state *qs, struct lfds700_queue_element *qe_dummy, struct lfds700_misc_prng_state *ps, void *user_state ) +{ + LFDS700_PAL_ASSERT( qs != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &qs->enqueue % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &qs->dequeue % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &qs->user_state % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( qe_dummy != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) qe_dummy->next % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &qe_dummy->key % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( ps != NULL ); + // TRD : user_state can be UNLL + + /* TRD : qe_dummy is a dummy element, needed for init + the qs->enqueue and qs->dequeue counters do not need to be initialized + but it does no harm to do so, and stops a valgrind complaint + */ + + qs->enqueue[POINTER] = qe_dummy; + qs->enqueue[COUNTER] = (struct lfds700_queue_element *) 0; + qs->dequeue[POINTER] = qe_dummy; + qs->dequeue[COUNTER] = (struct lfds700_queue_element *) 0; + + qe_dummy->next[POINTER] = NULL; + qe_dummy->next[COUNTER] = (struct lfds700_queue_element *) LFDS700_MISC_PRNG_GENERATE( ps ); + qe_dummy->value = NULL; + + qs->user_state = user_state; + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_internal.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_internal.h new file mode 100644 index 0000000000..81c9b69f48 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_internal.h @@ -0,0 +1,14 @@ +/***** the library wide include file *****/ +#include "../liblfds700_internal.h" + +/***** enums *****/ +enum lfds700_queue_queue_state +{ + LFDS700_QUEUE_QUEUE_STATE_UNKNOWN, + LFDS700_QUEUE_QUEUE_STATE_EMPTY, + LFDS700_QUEUE_QUEUE_STATE_ENQUEUE_OUT_OF_PLACE, + LFDS700_QUEUE_QUEUE_STATE_ATTEMPT_DEQUEUE +}; + +/***** private prototypes *****/ + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_query.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_query.c new file mode 100644 index 0000000000..15b4307ff2 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue/lfds700_queue_query.c @@ -0,0 +1,126 @@ +/***** includes *****/ +#include "lfds700_queue_internal.h" + +/***** private prototypes *****/ +static void lfds700_queue_internal_validate( struct lfds700_queue_state *qs, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_queue_validity ); + + + + + +/****************************************************************************/ +void lfds700_queue_query( struct lfds700_queue_state *qs, enum lfds700_queue_query query_type, void *query_input, void *query_output ) +{ + struct lfds700_queue_element + *qe; + + LFDS700_MISC_BARRIER_LOAD; + + LFDS700_PAL_ASSERT( qs != NULL ); + // TRD : query_type can be any value in its range + + switch( query_type ) + { + case LFDS700_QUEUE_QUERY_SINGLETHREADED_GET_COUNT: + LFDS700_PAL_ASSERT( query_input == NULL ); + LFDS700_PAL_ASSERT( query_output != NULL ); + + *(lfds700_pal_uint_t *) query_output = 0; + + qe = (struct lfds700_queue_element *) qs->dequeue[POINTER]; + + while( qe != NULL ) + { + ( *(lfds700_pal_uint_t *) query_output )++; + qe = (struct lfds700_queue_element *) qe->next[POINTER]; + } + + // TRD : remember there is a dummy element in the queue + ( *(lfds700_pal_uint_t *) query_output )--; + break; + + case LFDS700_QUEUE_QUERY_SINGLETHREADED_VALIDATE: + // TRD : query_input can be NULL + LFDS700_PAL_ASSERT( query_output != NULL ); + + lfds700_queue_internal_validate( qs, (struct lfds700_misc_validation_info *) query_input, (enum lfds700_misc_validity *) query_output ); + break; + } + + return; +} + + + + + +/****************************************************************************/ +static void lfds700_queue_internal_validate( struct lfds700_queue_state *qs, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_queue_validity ) +{ + lfds700_pal_uint_t + number_elements = 0; + + struct lfds700_queue_element + *qe_fast, + *qe_slow; + + LFDS700_PAL_ASSERT( qs != NULL ); + // TRD : vi can be NULL + LFDS700_PAL_ASSERT( lfds700_queue_validity != NULL ); + + *lfds700_queue_validity = LFDS700_MISC_VALIDITY_VALID; + + qe_slow = qe_fast = (struct lfds700_queue_element *) qs->dequeue[POINTER]; + + /* TRD : first, check for a loop + we have two pointers + both of which start at the dequeue end of the queue + we enter a loop + and on each iteration + we advance one pointer by one element + and the other by two + + we exit the loop when both pointers are NULL + (have reached the end of the queue) + + or + + if we fast pointer 'sees' the slow pointer + which means we have a loop + */ + + if( qe_slow != NULL ) + do + { + qe_slow = qe_slow->next[POINTER]; + + if( qe_fast != NULL ) + qe_fast = qe_fast->next[POINTER]; + + if( qe_fast != NULL ) + qe_fast = qe_fast->next[POINTER]; + } + while( qe_slow != NULL and qe_fast != qe_slow ); + + if( qe_fast != NULL and qe_slow != NULL and qe_fast == qe_slow ) + *lfds700_queue_validity = LFDS700_MISC_VALIDITY_INVALID_LOOP; + + /* TRD : now check for expected number of elements + vi can be NULL, in which case we do not check + we know we don't have a loop from our earlier check + */ + + if( *lfds700_queue_validity == LFDS700_MISC_VALIDITY_VALID and vi != NULL ) + { + lfds700_queue_query( qs, LFDS700_QUEUE_QUERY_SINGLETHREADED_GET_COUNT, NULL, (void *) &number_elements ); + + if( number_elements < vi->min_elements ) + *lfds700_queue_validity = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( number_elements > vi->max_elements ) + *lfds700_queue_validity = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_cleanup.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_cleanup.c new file mode 100644 index 0000000000..2b157bd973 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_cleanup.c @@ -0,0 +1,30 @@ +/***** includes *****/ +#include "lfds700_queue_bounded_singleconsumer_singleproducer_internal.h" + + + + + +/****************************************************************************/ +void lfds700_queue_bss_cleanup( struct lfds700_queue_bss_state *qbsss, + void (*element_cleanup_callback)(struct lfds700_queue_bss_state *qbsss, void *key, void *value) ) +{ + int long long unsigned + loop; + + struct lfds700_queue_bss_element + *qbsse; + + LFDS700_PAL_ASSERT( qbsss != NULL ); + // TRD : element_cleanup_callback can be NULL + + if( element_cleanup_callback != NULL ) + for( loop = qbsss->read_index ; loop < qbsss->read_index + qbsss->number_elements ; loop++ ) + { + qbsse = qbsss->element_array + (loop % qbsss->number_elements); + element_cleanup_callback( qbsss, qbsse->key, qbsse->value ); + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_dequeue.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_dequeue.c new file mode 100644 index 0000000000..28f735f610 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_dequeue.c @@ -0,0 +1,42 @@ +/***** includes *****/ +#include "lfds700_queue_bounded_singleconsumer_singleproducer_internal.h" + + + + + +/****************************************************************************/ +int lfds700_queue_bss_dequeue( struct lfds700_queue_bss_state *qbsss, void **key, void **value ) +{ + int + rv = 0; + + struct lfds700_queue_bss_element + *qbsse; + + LFDS700_PAL_ASSERT( qbsss != NULL ); + // TRD : key can be NULL + // TRD : value can be NULL + + LFDS700_MISC_BARRIER_LOAD; + + if( qbsss->read_index != qbsss->write_index ) + { + qbsse = qbsss->element_array + qbsss->read_index; + + if( key != NULL ) + *key = qbsse->key; + + if( value != NULL ) + *value = qbsse->value; + + qbsss->read_index = (qbsss->read_index + 1) & qbsss->mask; + + LFDS700_MISC_BARRIER_STORE; + + rv = 1; + } + + return( rv ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_enqueue.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_enqueue.c new file mode 100644 index 0000000000..c74091a23e --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_enqueue.c @@ -0,0 +1,39 @@ +/***** includes *****/ +#include "lfds700_queue_bounded_singleconsumer_singleproducer_internal.h" + + + + + +/****************************************************************************/ +int lfds700_queue_bss_enqueue( struct lfds700_queue_bss_state *qbsss, void *key, void *value ) +{ + int + rv = 0; + + struct lfds700_queue_bss_element + *qbsse; + + LFDS700_PAL_ASSERT( qbsss != NULL ); + // TRD : key can be NULL + // TRD : value can be NULL + + LFDS700_MISC_BARRIER_LOAD; + + if( ( (qbsss->write_index+1) & qbsss->mask ) != qbsss->read_index ) + { + qbsse = qbsss->element_array + qbsss->write_index; + + qbsse->key = key; + qbsse->value = value; + + LFDS700_MISC_BARRIER_STORE; + + qbsss->write_index = (qbsss->write_index + 1) & qbsss->mask; + + rv = 1; + } + + return( rv ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_init.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_init.c new file mode 100644 index 0000000000..9127fef443 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_init.c @@ -0,0 +1,63 @@ +/***** includes *****/ +#include "lfds700_queue_bounded_singleconsumer_singleproducer_internal.h" + + + + + +/****************************************************************************/ +void lfds700_queue_bss_init_valid_on_current_logical_core( struct lfds700_queue_bss_state *qbsss, + struct lfds700_queue_bss_element *element_array, + lfds700_pal_uint_t number_elements, + void *user_state ) +{ + LFDS700_PAL_ASSERT( qbsss != NULL ); + LFDS700_PAL_ASSERT( element_array != NULL ); + LFDS700_PAL_ASSERT( number_elements >= 2 ); + LFDS700_PAL_ASSERT( ( number_elements & (number_elements-1) ) == 0 ); // TRD : number_elements must be a positive integer power of 2 + // TRD : user_state can be NULL + + /* TRD : the use of mask and the restriction on a power of two + upon the number of elements bears some remark + + in this queue, there are a fixed number of elements + we have a read index and a write index + when we write, and thre is space to write, we increment the write index + (if no space to write, we just return) + when we read, and there are elements to be read, we after reading increment the read index + (if no elements to read, we just return) + the problem is - how do we handle wrap around? + e.g. when I write, but my write index is now equal to the number of elements + the usual solution is to modulus the write index by the nunmber of elements + problem is modulus is slow + there is a better way + first, we restrict the number of elements to be a power of two + so imagine we have a 64-bit system and we set the number of elements to be 2^64 + this gives us a bit pattern of 1000 0000 0000 0000 (...etc, lots of zeros) + now (just roll with this for a bit) subtract one from this + this gives us a mask (on a two's compliment machine) + 0111 1111 1111 1111 (...etc, lots of ones) + so what we do now, when we increment an index (think of the write index as the example) + we bitwise and it with the mask + now think about thwt happens + all the numbers up to 2^64 will be unchanged - their MSB is never set, and we and with all the other bits + but when we finally hit 2^64 and need to roll over... bingo! + we drop MSB (which we finally have) and have the value 0! + this is exactly what we want + bitwise and is much faster than modulus + */ + + qbsss->number_elements = number_elements; + qbsss->mask = qbsss->number_elements - 1; + qbsss->read_index = 0; + qbsss->write_index = 0; + qbsss->element_array = element_array; + qbsss->user_state = user_state; + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_internal.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_internal.h new file mode 100644 index 0000000000..7a7d541804 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_internal.h @@ -0,0 +1,5 @@ +/***** the library wide include file *****/ +#include "../liblfds700_internal.h" + +/***** private prototypes *****/ + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_query.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_query.c new file mode 100644 index 0000000000..aabcae23f3 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_queue_bounded_singleconsumer_singleproducer/lfds700_queue_bounded_singleconsumer_singleproducer_query.c @@ -0,0 +1,70 @@ +/***** includes *****/ +#include "lfds700_queue_bounded_singleconsumer_singleproducer_internal.h" + +/***** private prototypes *****/ +static void lfds700_queue_bss_internal_validate( struct lfds700_queue_bss_state *qbsss, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_validity ); + + + + + +/****************************************************************************/ +void lfds700_queue_bss_query( struct lfds700_queue_bss_state *qbsss, enum lfds700_queue_bss_query query_type, void *query_input, void *query_output ) +{ + LFDS700_PAL_ASSERT( qbsss != NULL ); + // TRD : query_type can be any value in its range + + switch( query_type ) + { + case LFDS700_QUEUE_BSS_QUERY_GET_POTENTIALLY_INACCURATE_COUNT: + LFDS700_PAL_ASSERT( query_input == NULL ); + LFDS700_PAL_ASSERT( query_output != NULL ); + + LFDS700_MISC_BARRIER_LOAD; + + *(lfds700_pal_uint_t *) query_output = +( qbsss->write_index - qbsss->read_index ); + if( qbsss->read_index > qbsss->write_index ) + *(lfds700_pal_uint_t *) query_output = qbsss->number_elements - *(lfds700_pal_uint_t *) query_output; + break; + + case LFDS700_QUEUE_BSS_QUERY_VALIDATE: + // TRD : query_input can be NULL + LFDS700_PAL_ASSERT( query_output != NULL ); + + lfds700_queue_bss_internal_validate( qbsss, (struct lfds700_misc_validation_info *) query_input, (enum lfds700_misc_validity *) query_output ); + break; + } + + return; +} + + + + + +/****************************************************************************/ +static void lfds700_queue_bss_internal_validate( struct lfds700_queue_bss_state *qbsss, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_validity ) +{ + LFDS700_PAL_ASSERT( qbsss != NULL ); + // TRD : vi can be NULL + LFDS700_PAL_ASSERT( lfds700_validity != NULL ); + + *lfds700_validity = LFDS700_MISC_VALIDITY_VALID; + + if( vi != NULL ) + { + lfds700_pal_uint_t + number_elements; + + lfds700_queue_bss_query( qbsss, LFDS700_QUEUE_BSS_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void *) &number_elements ); + + if( number_elements < vi->min_elements ) + *lfds700_validity = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( number_elements > vi->max_elements ) + *lfds700_validity = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_cleanup.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_cleanup.c new file mode 100644 index 0000000000..447c93041e --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_cleanup.c @@ -0,0 +1,86 @@ +/***** includes *****/ +#include "lfds700_ringbuffer_internal.h" + +/***** private prototypes *****/ +static void lfds700_ringbuffer_internal_queue_element_cleanup_callback( struct lfds700_queue_state *qs, struct lfds700_queue_element *qe, enum lfds700_misc_flag dummy_element_flag ); +static void lfds700_ringbuffer_internal_freelist_element_cleanup_callback( struct lfds700_freelist_state *fs, struct lfds700_freelist_element *fe ); + + + + + +/****************************************************************************/ +void lfds700_ringbuffer_cleanup( struct lfds700_ringbuffer_state *rs, + void (*element_cleanup_callback)(struct lfds700_ringbuffer_state *rs, void *key, void *value, enum lfds700_misc_flag unread_flag) ) +{ + LFDS700_PAL_ASSERT( rs != NULL ); + // TRD : element_cleanup_callback can be NULL + + if( element_cleanup_callback != NULL ) + { + rs->element_cleanup_callback = element_cleanup_callback; + lfds700_queue_cleanup( &rs->qs, lfds700_ringbuffer_internal_queue_element_cleanup_callback ); + lfds700_freelist_cleanup( &rs->fs, lfds700_ringbuffer_internal_freelist_element_cleanup_callback ); + } + + return; +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static void lfds700_ringbuffer_internal_queue_element_cleanup_callback( struct lfds700_queue_state *qs, struct lfds700_queue_element *qe, enum lfds700_misc_flag dummy_element_flag ) +{ + struct lfds700_ringbuffer_element + *re; + + struct lfds700_ringbuffer_state + *rs; + + LFDS700_PAL_ASSERT( qs != NULL ); + LFDS700_PAL_ASSERT( qe != NULL ); + // TRD : dummy_element can be any value in its range + + rs = (struct lfds700_ringbuffer_state *) LFDS700_QUEUE_GET_USER_STATE_FROM_STATE( *qs ); + re = (struct lfds700_ringbuffer_element *) LFDS700_QUEUE_GET_VALUE_FROM_ELEMENT( *qe ); + + if( dummy_element_flag == LFDS700_MISC_FLAG_LOWERED ) + rs->element_cleanup_callback( rs, re->key, re->value, LFDS700_MISC_FLAG_RAISED ); + + return; +} + +#pragma warning( default : 4100 ) + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static void lfds700_ringbuffer_internal_freelist_element_cleanup_callback( struct lfds700_freelist_state *fs, struct lfds700_freelist_element *fe ) +{ + struct lfds700_ringbuffer_element + *re; + + struct lfds700_ringbuffer_state + *rs; + + LFDS700_PAL_ASSERT( fs != NULL ); + LFDS700_PAL_ASSERT( fe != NULL ); + + rs = (struct lfds700_ringbuffer_state *) LFDS700_FREELIST_GET_USER_STATE_FROM_STATE( *fs ); + re = (struct lfds700_ringbuffer_element *) LFDS700_FREELIST_GET_VALUE_FROM_ELEMENT( *fe ); + + rs->element_cleanup_callback( rs, re->key, re->value, LFDS700_MISC_FLAG_LOWERED ); + + return; +} + +#pragma warning( default : 4100 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_init.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_init.c new file mode 100644 index 0000000000..a6cd1e3616 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_init.c @@ -0,0 +1,51 @@ +/***** includes *****/ +#include "lfds700_ringbuffer_internal.h" + + + + + +/****************************************************************************/ +void lfds700_ringbuffer_init_valid_on_current_logical_core( struct lfds700_ringbuffer_state *rs, + struct lfds700_ringbuffer_element *re_array_inc_dummy, + lfds700_pal_uint_t number_elements, + struct lfds700_misc_prng_state *ps, + void *user_state ) +{ + lfds700_pal_uint_t + loop; + + LFDS700_PAL_ASSERT( rs != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &rs->fs % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &rs->qs % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( re_array_inc_dummy != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &re_array_inc_dummy[0].fe % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &re_array_inc_dummy[0].qe % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( number_elements >= 2 ); + LFDS700_PAL_ASSERT( ps != NULL ); + // TRD : user_state can be NULL + + rs->user_state = user_state; + + re_array_inc_dummy[0].qe_use = &re_array_inc_dummy[0].qe; + + lfds700_freelist_init_valid_on_current_logical_core( &rs->fs, rs ); + lfds700_queue_init_valid_on_current_logical_core( &rs->qs, &re_array_inc_dummy[0].qe, ps, rs ); + + for( loop = 1 ; loop < number_elements ; loop++ ) + { + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &re_array_inc_dummy[loop].fe % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &re_array_inc_dummy[loop].qe % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + + re_array_inc_dummy[loop].qe_use = &re_array_inc_dummy[loop].qe; + LFDS700_FREELIST_SET_VALUE_IN_ELEMENT( re_array_inc_dummy[loop].fe, &re_array_inc_dummy[loop] ); + lfds700_freelist_push( &rs->fs, &re_array_inc_dummy[loop].fe, ps ); + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_internal.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_internal.h new file mode 100644 index 0000000000..7a7d541804 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_internal.h @@ -0,0 +1,5 @@ +/***** the library wide include file *****/ +#include "../liblfds700_internal.h" + +/***** private prototypes *****/ + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_query.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_query.c new file mode 100644 index 0000000000..58b7b3a9cb --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_query.c @@ -0,0 +1,72 @@ +/***** includes *****/ +#include "lfds700_ringbuffer_internal.h" + +/***** private prototypes *****/ +static void lfds700_ringbuffer_internal_validate( struct lfds700_ringbuffer_state *rs, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_queue_validity, enum lfds700_misc_validity *lfds700_freelist_validity ); + + + +/****************************************************************************/ +void lfds700_ringbuffer_query( struct lfds700_ringbuffer_state *rs, enum lfds700_ringbuffer_query query_type, void *query_input, void *query_output ) +{ + LFDS700_PAL_ASSERT( rs != NULL ); + // TRD : query_type can be any value in its range + + LFDS700_MISC_BARRIER_LOAD; + + switch( query_type ) + { + case LFDS700_RINGBUFFER_QUERY_SINGLETHREADED_GET_COUNT: + LFDS700_PAL_ASSERT( query_input == NULL ); + LFDS700_PAL_ASSERT( query_output != NULL ); + + lfds700_queue_query( &rs->qs, LFDS700_QUEUE_QUERY_SINGLETHREADED_GET_COUNT, NULL, query_output ); + break; + + case LFDS700_RINGBUFFER_QUERY_SINGLETHREADED_VALIDATE: + // TRD : query_input can be NULL + LFDS700_PAL_ASSERT( query_output != NULL ); + + lfds700_ringbuffer_internal_validate( rs, (struct lfds700_misc_validation_info *) query_input, (enum lfds700_misc_validity *) query_output, ((enum lfds700_misc_validity *) query_output)+1 ); + break; + } + + return; +} + + + + + +/****************************************************************************/ +static void lfds700_ringbuffer_internal_validate( struct lfds700_ringbuffer_state *rs, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_queue_validity, enum lfds700_misc_validity *lfds700_freelist_validity ) +{ + LFDS700_PAL_ASSERT( rs != NULL ); + // TRD : vi can be NULL + LFDS700_PAL_ASSERT( lfds700_queue_validity != NULL ); + LFDS700_PAL_ASSERT( lfds700_freelist_validity != NULL ); + + if( vi == NULL ) + { + lfds700_queue_query( &rs->qs, LFDS700_QUEUE_QUERY_SINGLETHREADED_VALIDATE, NULL, lfds700_queue_validity ); + lfds700_freelist_query( &rs->fs, LFDS700_FREELIST_QUERY_SINGLETHREADED_VALIDATE, NULL, lfds700_freelist_validity ); + } + + if( vi != NULL ) + { + struct lfds700_misc_validation_info + freelist_vi, + queue_vi; + + queue_vi.min_elements = 0; + freelist_vi.min_elements = 0; + queue_vi.max_elements = vi->max_elements; + freelist_vi.max_elements = vi->max_elements; + + lfds700_queue_query( &rs->qs, LFDS700_QUEUE_QUERY_SINGLETHREADED_VALIDATE, &queue_vi, lfds700_queue_validity ); + lfds700_freelist_query( &rs->fs, LFDS700_FREELIST_QUERY_SINGLETHREADED_VALIDATE, &freelist_vi, lfds700_freelist_validity ); + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_read.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_read.c new file mode 100644 index 0000000000..42dbe189e2 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_read.c @@ -0,0 +1,44 @@ +/***** includes *****/ +#include "lfds700_ringbuffer_internal.h" + + + + + +/****************************************************************************/ +int lfds700_ringbuffer_read( struct lfds700_ringbuffer_state *rs, + void **key, + void **value, + struct lfds700_misc_prng_state *ps ) +{ + int + rv; + + struct lfds700_queue_element + *qe; + + struct lfds700_ringbuffer_element + *re; + + LFDS700_PAL_ASSERT( rs != NULL ); + // TRD : key can be NULL + // TRD : value can be NULL + LFDS700_PAL_ASSERT( ps != NULL ); + + rv = lfds700_queue_dequeue( &rs->qs, &qe, ps ); + + if( rv == 1 ) + { + re = LFDS700_QUEUE_GET_VALUE_FROM_ELEMENT( *qe ); + re->qe_use = (struct lfds700_queue_element *) qe; + if( key != NULL ) + *key = re->key; + if( value != NULL ) + *value = re->value; + LFDS700_FREELIST_SET_VALUE_IN_ELEMENT( re->fe, re ); + lfds700_freelist_push( &rs->fs, &re->fe, ps ); + } + + return( rv ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_write.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_write.c new file mode 100644 index 0000000000..a16a8686c1 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_ringbuffer/lfds700_ringbuffer_write.c @@ -0,0 +1,78 @@ +/***** includes *****/ +#include "lfds700_ringbuffer_internal.h" + + + + + +/****************************************************************************/ +void lfds700_ringbuffer_write( struct lfds700_ringbuffer_state *rs, + void *key, + void *value, + enum lfds700_misc_flag *overwrite_occurred_flag, + void **overwritten_key, + void **overwritten_value, + struct lfds700_misc_prng_state *ps ) +{ + int + rv = 0; + + struct lfds700_freelist_element + *fe; + + struct lfds700_queue_element + *qe; + + struct lfds700_ringbuffer_element + *re = NULL; + + LFDS700_PAL_ASSERT( rs != NULL ); + // TRD : key can be NULL + // TRD : value can be NULL + // TRD : overwrite_occurred_flag can be NULL + // TRD : overwritten_key can be NULL + // TRD : overwritten_value can be NULL + LFDS700_PAL_ASSERT( ps != NULL ); + + if( overwrite_occurred_flag != NULL ) + *overwrite_occurred_flag = LFDS700_MISC_FLAG_LOWERED; + + do + { + rv = lfds700_freelist_pop( &rs->fs, &fe, ps ); + + if( rv == 1 ) + re = LFDS700_FREELIST_GET_VALUE_FROM_ELEMENT( *fe ); + + if( rv == 0 ) + { + // TRD : the queue can return empty as well - remember, we're lock-free; anything could have happened since the previous instruction + rv = lfds700_queue_dequeue( &rs->qs, &qe, ps ); + + if( rv == 1 ) + { + re = LFDS700_QUEUE_GET_VALUE_FROM_ELEMENT( *qe ); + re->qe_use = (struct lfds700_queue_element *) qe; + + if( overwrite_occurred_flag != NULL ) + *overwrite_occurred_flag = LFDS700_MISC_FLAG_RAISED; + + if( overwritten_key != NULL ) + *overwritten_key = re->key; + + if( overwritten_value != NULL ) + *overwritten_value = re->value; + } + } + } + while( rv == 0 ); + + re->key = key; + re->value = value; + + LFDS700_QUEUE_SET_VALUE_IN_ELEMENT( *re->qe_use, re ); + lfds700_queue_enqueue( &rs->qs, re->qe_use, ps ); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_cleanup.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_cleanup.c new file mode 100644 index 0000000000..efcebf3543 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_cleanup.c @@ -0,0 +1,36 @@ +/***** includes *****/ +#include "lfds700_stack_internal.h" + + + + + +/****************************************************************************/ +void lfds700_stack_cleanup( struct lfds700_stack_state *ss, + void (*element_cleanup_callback)(struct lfds700_stack_state *ss, struct lfds700_stack_element *se) ) +{ + struct lfds700_stack_element + *se, + *se_temp; + + LFDS700_PAL_ASSERT( ss != NULL ); + // TRD : element_cleanup_callback can be NULL + + LFDS700_MISC_BARRIER_LOAD; + + if( element_cleanup_callback != NULL ) + { + se = ss->top[POINTER]; + + while( se != NULL ) + { + se_temp = se; + se = se->next; + + element_cleanup_callback( ss, se_temp ); + } + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_init.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_init.c new file mode 100644 index 0000000000..745017c029 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_init.c @@ -0,0 +1,27 @@ +/***** includes *****/ +#include "lfds700_stack_internal.h" + + + + + +/****************************************************************************/ +void lfds700_stack_init_valid_on_current_logical_core( struct lfds700_stack_state *ss, void *user_state ) +{ + LFDS700_PAL_ASSERT( ss != NULL ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) ss->top % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + LFDS700_PAL_ASSERT( (lfds700_pal_uint_t) &ss->user_state % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ); + // TRD : user_state can be NULL + + ss->top[POINTER] = NULL; + ss->top[COUNTER] = 0; + + ss->user_state = user_state; + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_internal.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_internal.h new file mode 100644 index 0000000000..7a7d541804 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_internal.h @@ -0,0 +1,5 @@ +/***** the library wide include file *****/ +#include "../liblfds700_internal.h" + +/***** private prototypes *****/ + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_pop.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_pop.c new file mode 100644 index 0000000000..3cae2e563e --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_pop.c @@ -0,0 +1,52 @@ +/***** includes *****/ +#include "lfds700_stack_internal.h" + + + + + +/****************************************************************************/ +int lfds700_stack_pop( struct lfds700_stack_state *ss, struct lfds700_stack_element **se, struct lfds700_misc_prng_state *ps ) +{ + char unsigned + result; + + lfds700_pal_uint_t + backoff_iteration = LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE; + + struct lfds700_stack_element LFDS700_PAL_ALIGN(LFDS700_PAL_ALIGN_DOUBLE_POINTER) + *new_top[PAC_SIZE], + *volatile original_top[PAC_SIZE]; + + LFDS700_PAL_ASSERT( ss != NULL ); + LFDS700_PAL_ASSERT( se != NULL ); + LFDS700_PAL_ASSERT( ps != NULL ); + + LFDS700_PAL_BARRIER_PROCESSOR_LOAD; + + original_top[COUNTER] = ss->top[COUNTER]; + original_top[POINTER] = ss->top[POINTER]; + + do + { + if( original_top[POINTER] == NULL ) + { + *se = NULL; + return( 0 ); + } + + new_top[COUNTER] = original_top[COUNTER] + 1; + new_top[POINTER] = original_top[POINTER]->next; + + LFDS700_PAL_ATOMIC_DWCAS_WITH_BACKOFF( &ss->top, original_top, new_top, LFDS700_MISC_CAS_STRENGTH_WEAK, result, backoff_iteration, ps ); + + if( result != 1 ) + LFDS700_PAL_BARRIER_PROCESSOR_LOAD; + } + while( result != 1 ); + + *se = original_top[POINTER]; + + return( 1 ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_push.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_push.c new file mode 100644 index 0000000000..ff84c5ed55 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_push.c @@ -0,0 +1,42 @@ +/***** includes *****/ +#include "lfds700_stack_internal.h" + + + + + +/****************************************************************************/ +void lfds700_stack_push( struct lfds700_stack_state *ss, struct lfds700_stack_element *se, struct lfds700_misc_prng_state *ps ) +{ + char unsigned + result; + + lfds700_pal_uint_t + backoff_iteration = LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE; + + struct lfds700_stack_element LFDS700_PAL_ALIGN(LFDS700_PAL_ALIGN_DOUBLE_POINTER) + *new_top[PAC_SIZE], + *volatile original_top[PAC_SIZE]; + + LFDS700_PAL_ASSERT( ss != NULL ); + LFDS700_PAL_ASSERT( se != NULL ); + LFDS700_PAL_ASSERT( ps != NULL ); + + new_top[POINTER] = se; + + original_top[COUNTER] = ss->top[COUNTER]; + original_top[POINTER] = ss->top[POINTER]; + + do + { + new_top[COUNTER] = original_top[COUNTER] + 1; + se->next = original_top[POINTER]; + + LFDS700_PAL_BARRIER_PROCESSOR_STORE; + LFDS700_PAL_ATOMIC_DWCAS_WITH_BACKOFF( &ss->top, original_top, new_top, LFDS700_MISC_CAS_STRENGTH_WEAK, result, backoff_iteration, ps ); + } + while( result != 1 ); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_query.c b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_query.c new file mode 100644 index 0000000000..b9abdf9f2d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/lfds700_stack/lfds700_stack_query.c @@ -0,0 +1,123 @@ +/***** includes *****/ +#include "lfds700_stack_internal.h" + +/***** private prototypes *****/ +static void lfds700_stack_internal_stack_validate( struct lfds700_stack_state *ss, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_stack_validity ); + + + + + +/****************************************************************************/ +void lfds700_stack_query( struct lfds700_stack_state *ss, enum lfds700_stack_query query_type, void *query_input, void *query_output ) +{ + struct lfds700_stack_element + *se; + + LFDS700_MISC_BARRIER_LOAD; + + LFDS700_PAL_ASSERT( ss != NULL ); + // TRD : query_type can be any value in its range + + switch( query_type ) + { + case LFDS700_STACK_QUERY_SINGLETHREADED_GET_COUNT: + LFDS700_PAL_ASSERT( query_input == NULL ); + LFDS700_PAL_ASSERT( query_output != NULL ); + + *(lfds700_pal_uint_t *) query_output = 0; + + se = (struct lfds700_stack_element *) ss->top[POINTER]; + + while( se != NULL ) + { + ( *(lfds700_pal_uint_t *) query_output )++; + se = (struct lfds700_stack_element *) se->next; + } + break; + + case LFDS700_STACK_QUERY_SINGLETHREADED_VALIDATE: + // TRD : query_input can be NULL + LFDS700_PAL_ASSERT( query_output != NULL ); + + lfds700_stack_internal_stack_validate( ss, (struct lfds700_misc_validation_info *) query_input, (enum lfds700_misc_validity *) query_output ); + break; + } + + return; +} + + + + + +/****************************************************************************/ +static void lfds700_stack_internal_stack_validate( struct lfds700_stack_state *ss, struct lfds700_misc_validation_info *vi, enum lfds700_misc_validity *lfds700_stack_validity ) +{ + lfds700_pal_uint_t + number_elements = 0; + + struct lfds700_stack_element + *se_fast, + *se_slow; + + LFDS700_PAL_ASSERT( ss != NULL ); + // TRD : vi can be NULL + LFDS700_PAL_ASSERT( lfds700_stack_validity != NULL ); + + *lfds700_stack_validity = LFDS700_MISC_VALIDITY_VALID; + + se_slow = se_fast = (struct lfds700_stack_element *) ss->top[POINTER]; + + /* TRD : first, check for a loop + we have two pointers + both of which start at the top of the stack + we enter a loop + and on each iteration + we advance one pointer by one element + and the other by two + + we exit the loop when both pointers are NULL + (have reached the end of the stack) + + or + + if we fast pointer 'sees' the slow pointer + which means we have a loop + */ + + if( se_slow != NULL ) + do + { + se_slow = se_slow->next; + + if( se_fast != NULL ) + se_fast = se_fast->next; + + if( se_fast != NULL ) + se_fast = se_fast->next; + } + while( se_slow != NULL and se_fast != se_slow ); + + if( se_fast != NULL and se_slow != NULL and se_fast == se_slow ) + *lfds700_stack_validity = LFDS700_MISC_VALIDITY_INVALID_LOOP; + + /* TRD : now check for expected number of elements + vi can be NULL, in which case we do not check + we know we don't have a loop from our earlier check + */ + + if( *lfds700_stack_validity == LFDS700_MISC_VALIDITY_VALID and vi != NULL ) + { + lfds700_stack_query( ss, LFDS700_STACK_QUERY_SINGLETHREADED_GET_COUNT, NULL, (void *) &number_elements ); + + if( number_elements < vi->min_elements ) + *lfds700_stack_validity = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( number_elements > vi->max_elements ) + *lfds700_stack_validity = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/liblfds700_internal.h b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/liblfds700_internal.h new file mode 100644 index 0000000000..fdd8c363eb --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/liblfds700/src/liblfds700_internal.h @@ -0,0 +1,93 @@ +/***** public prototypes *****/ +#include "../inc/liblfds700.h" + +/***** defines *****/ +#define and && +#define or || + +#define NO_FLAGS 0x0 + +#define LFDS700_ABSTRACTION_BACKOFF_LIMIT (0x1 << 10) + +#if( defined _KERNEL_MODE ) + #define MODE_TYPE_STRING "kernel-mode" +#endif + +#if( !defined _KERNEL_MODE ) + #define MODE_TYPE_STRING "user-mode" +#endif + +#if( defined NDEBUG && !defined COVERAGE && !defined TSAN ) + #define BUILD_TYPE_STRING "release" +#endif + +#if( !defined NDEBUG && !defined COVERAGE && !defined TSAN ) + #define BUILD_TYPE_STRING "debug" +#endif + +#if( !defined NDEBUG && defined COVERAGE && !defined TSAN ) + #define BUILD_TYPE_STRING "coverage" +#endif + +#if( !defined NDEBUG && !defined COVERAGE && defined TSAN ) + #define BUILD_TYPE_STRING "threadsanitizer" +#endif + +// TRD : lfds700_pal_atom_t volatile *destination, lfds700_pal_atom_t *compare, lfds700_pal_atom_t new_destination, enum lfds700_misc_cas_strength cas_strength, char unsigned result, lfds700_pal_uint_t *backoff_iteration +#define LFDS700_PAL_ATOMIC_CAS_WITH_BACKOFF( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result, backoff_iteration, ps ) \ +{ \ + LFDS700_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ); \ + \ + if( result == 0 ) \ + { \ + lfds700_pal_uint_t \ + endloop; \ + \ + lfds700_pal_uint_t volatile \ + loop; \ + \ + if( (backoff_iteration) == LFDS700_ABSTRACTION_BACKOFF_LIMIT ) \ + (backoff_iteration) = LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE; \ + \ + if( (backoff_iteration) == LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE ) \ + (backoff_iteration) = 1; \ + else \ + { \ + endloop = ( LFDS700_MISC_PRNG_GENERATE(ps) % (backoff_iteration) ) * ps->local_copy_of_global_exponential_backoff_timeslot_length_in_loop_iterations_for_cas; \ + for( loop = 0 ; loop < endloop ; loop++ ); \ + } \ + \ + (backoff_iteration) <<= 1; \ + } \ +} + +// TRD : lfds700_pal_atom_t volatile (*destination)[2], lfds700_pal_atom_t (*compare)[2], lfds700_pal_atom_t (*new_destination)[2], enum lfds700_misc_cas_strength cas_strength, char unsigned result, lfds700_pal_uint_t *backoff_iteration +#define LFDS700_PAL_ATOMIC_DWCAS_WITH_BACKOFF( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result, backoff_iteration, ps ) \ +{ \ + LFDS700_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ); \ + \ + if( result == 0 ) \ + { \ + lfds700_pal_uint_t \ + endloop; \ + \ + lfds700_pal_uint_t volatile \ + loop; \ + \ + if( (backoff_iteration) == LFDS700_ABSTRACTION_BACKOFF_LIMIT ) \ + (backoff_iteration) = LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE; \ + \ + if( (backoff_iteration) == LFDS700_MISC_ABSTRACTION_BACKOFF_INITIAL_VALUE ) \ + (backoff_iteration) = 1; \ + else \ + { \ + endloop = ( LFDS700_MISC_PRNG_GENERATE(ps) % (backoff_iteration) ) * ps->local_copy_of_global_exponential_backoff_timeslot_length_in_loop_iterations_for_dwcas; \ + for( loop = 0 ; loop < endloop ; loop++ ); \ + } \ + \ + (backoff_iteration) <<= 1; \ + } \ +} + +/***** library-wide prototypes *****/ + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/build/gcc_and_gnumake/Makefile b/openair2/UTIL/LFDS/liblfds7.0.0/test/build/gcc_and_gnumake/Makefile new file mode 100644 index 0000000000..489e5b19e5 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/build/gcc_and_gnumake/Makefile @@ -0,0 +1,129 @@ +##### paths ##### +BINDIR := ../../bin +OBJDIR := ../../obj +SRCDIR := ../../src +LIBINCDIRS := ../../../liblfds700/inc/ +LIBBINDIRS := ../../../liblfds700/bin/ + +##### misc ##### +QUIETLY := 1>nul 2>nul + +##### sources, objects and libraries ##### +BINNAME := test +BINARY := $(BINDIR)/$(BINNAME) +SRCDIRS := . +SOURCES := main.c misc.c \ + test_lfds700_btree_addonly_unbalanced.c test_lfds700_btree_addonly_unbalanced_alignment.c test_lfds700_btree_addonly_unbalanced_random_adds_fail.c test_lfds700_btree_addonly_unbalanced_random_adds_fail_and_overwrite.c test_lfds700_btree_addonly_unbalanced_random_adds_overwrite.c \ + test_lfds700_freelist.c test_lfds700_freelist_alignment.c test_lfds700_freelist_popping.c test_lfds700_freelist_popping_and_pushing.c test_lfds700_freelist_pushing.c test_lfds700_freelist_rapid_popping_and_pushing.c \ + test_lfds700_hash_addonly.c test_lfds700_hash_addonly_alignment.c test_lfds700_hash_addonly_iterate.c test_lfds700_hash_addonly_random_adds_fail.c test_lfds700_hash_addonly_random_adds_fail_and_overwrite.c test_lfds700_hash_addonly_random_adds_overwrite.c \ + test_lfds700_list_addonly_ordered_singlylinked.c test_lfds700_list_addonly_ordered_singlylinked_alignment.c test_lfds700_list_addonly_ordered_singlylinked_new_ordered.c test_lfds700_list_addonly_ordered_singlylinked_new_ordered_with_cursor.c \ + test_lfds700_list_addonly_singlylinked_unordered.c test_lfds700_list_addonly_singlylinked_unordered_alignment.c test_lfds700_list_addonly_singlylinked_unordered_new_after.c test_lfds700_list_addonly_singlylinked_unordered_new_end.c test_lfds700_list_addonly_singlylinked_unordered_new_start.c \ + test_lfds700_porting_abstraction_layer_atomic.c test_lfds700_porting_abstraction_layer_atomic_cas.c test_lfds700_porting_abstraction_layer_atomic_dcas.c test_lfds700_porting_abstraction_layer_atomic_exchange.c \ + test_lfds700_queue.c test_lfds700_queue_alignment.c test_lfds700_queue_dequeuing.c test_lfds700_queue_enqueuing.c test_lfds700_queue_enqueuing_and_dequeuing.c test_lfds700_queue_enqueuing_and_dequeuing_with_free.c test_lfds700_queue_enqueuing_with_malloc_and_dequeuing_with_free.c test_lfds700_queue_rapid_enqueuing_and_dequeuing.c \ + test_lfds700_queue_bounded_singleconsumer_singleproducer.c test_lfds700_queue_bounded_singleconsumer_singleproducer_dequeuing.c test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing.c test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing_and_dequeuing.c \ + test_lfds700_ringbuffer.c test_lfds700_ringbuffer_reading.c test_lfds700_ringbuffer_reading_and_writing.c test_lfds700_ringbuffer_writing.c \ + test_lfds700_stack.c test_lfds700_stack_alignment.c test_lfds700_stack_popping.c test_lfds700_stack_popping_and_pushing.c test_lfds700_stack_pushing.c test_lfds700_stack_rapid_popping_and_pushing.c \ + test_porting_abstraction_layer_get_logical_core_ids.c test_porting_abstraction_layer_thread_start.c test_porting_abstraction_layer_thread_wait.c \ + util_cmdline.c util_memory_helpers.c util_thread_starter.c +OBJECTS := $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(SOURCES))) +SYSLIBS := -lm -lpthread -lrt +USRLIBS := -llfds700 + +##### default paths ##### +CPATH += $(LIBINCDIRS) +LIBRARY_PATH += $(LIBBINDIRS) +export CPATH +export LIBRARY_PATH + +##### tools ##### +MAKE := make +MFLAGS := + +DG := gcc +DGFLAGS := -MM -std=gnu89 + +CC := gcc +CFBASE := -c -pthread -std=gnu89 -Wall -Wno-unknown-pragmas +CFCOV := -O0 -ggdb -DCOVERAGE -fprofile-arcs -ftest-coverage +CFDBG := -O0 -ggdb -D_DEBUG +CFPROF := -O0 -ggdb -DPROF -pg +CFREL := -O2 -DNDEBUG -finline-functions -Wno-strict-aliasing +CFTSAN := -O0 -ggdb -DTSAN -fsanitize=thread -fPIE + +LD := gcc +LFBASE := -pthread -std=gnu89 -Wall -Werror +LFCOV := -O0 -fprofile-arcs -ftest-coverage +LFDBG := -O0 -ggdb +LFPROF := -O0 -pg +LFREL := -O2 -s -finline-functions +LFTSAN := -O0 -fsanitize=thread -pie + +PROF := gprof +PFBASE := -b -p -Q $(BINARY) gmon.out + +##### variants and libnuma check ##### +CFLAGS += $(CFBASE) +LFLAGS += $(LFBASE) + +ifeq ($(MAKECMDGOALS),) + CFLAGS += $(CFDBG) + LFLAGS += $(LFDBG) +endif + +ifeq ($(MAKECMDGOALS),cov) + CFLAGS += $(CFCOV) + LFLAGS += $(LFCOV) + SYSLIBS += -lgcov +endif + +ifeq ($(MAKECMDGOALS),dbg) + CFLAGS += $(CFDBG) + LFLAGS += $(LFDBG) +endif + +ifeq ($(MAKECMDGOALS),prof) + CFLAGS += $(CFPROF) + LFLAGS += $(LFPROF) +endif + +ifeq ($(MAKECMDGOALS),rel) + CFLAGS += $(CFREL) + LFLAGS += $(LFREL) +endif + +ifeq ($(MAKECMDGOALS),tsan) + CFLAGS += $(CFTSAN) + LFLAGS += $(LFTSAN) +endif + +##### search paths ##### +vpath %.c $(patsubst %,$(SRCDIR)/%:,$(SRCDIRS)) + +##### implicit rules ##### +$(OBJDIR)/%.o : %.c + $(DG) $(DGFLAGS) $< >$(OBJDIR)/$*.d + $(CC) $(CFLAGS) -o $@ $< + +##### explicit rules ##### +$(BINARY) : $(OBJECTS) + $(LD) -o $(BINARY) $(LFLAGS) $(OBJECTS) $(USRLIBS) $(SYSLIBS) + chmod +x $(BINARY) + +##### phony ##### +.PHONY : clean cov dbg prof rel tsan + +clean : + @rm -f $(BINDIR)/$(BINNAME) $(OBJDIR)/*.o $(OBJDIR)/*.d $(OBJDIR)/*.gcno + +cov : $(BINARY) +dbg : $(BINARY) +prof : $(BINARY) +rel : $(BINARY) +tsan : $(BINARY) + +genprof : + @$(PROF) $(PFBASE) + +##### dependencies ##### +-include $(DEPENDS) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/build/sdk_for_windows_7_and_gnumake/makefile b/openair2/UTIL/LFDS/liblfds7.0.0/test/build/sdk_for_windows_7_and_gnumake/makefile new file mode 100644 index 0000000000..c54d16635b --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/build/sdk_for_windows_7_and_gnumake/makefile @@ -0,0 +1,106 @@ +##### paths ##### +BINDIR := ..\..\bin +OBJDIR := ..\..\obj +SRCDIR := ..\..\src + +##### misc ##### +QUIETLY := 1>nul 2>nul +NULL := +SPACE := $(NULL) # TRD : necessary trailing space after the close bracket + +##### sources, objects and libraries ##### +BINNAME := test +BINARY := $(BINDIR)\$(BINNAME).exe +SRCDIRS := . +SOURCES := main.c misc.c \ + test_lfds700_btree_addonly_unbalanced.c test_lfds700_btree_addonly_unbalanced_alignment.c test_lfds700_btree_addonly_unbalanced_random_adds_fail.c test_lfds700_btree_addonly_unbalanced_random_adds_fail_and_overwrite.c test_lfds700_btree_addonly_unbalanced_random_adds_overwrite.c \ + test_lfds700_freelist.c test_lfds700_freelist_alignment.c test_lfds700_freelist_popping.c test_lfds700_freelist_popping_and_pushing.c test_lfds700_freelist_pushing.c test_lfds700_freelist_rapid_popping_and_pushing.c \ + test_lfds700_hash_addonly.c test_lfds700_hash_addonly_alignment.c test_lfds700_hash_addonly_iterate.c test_lfds700_hash_addonly_random_adds_fail.c test_lfds700_hash_addonly_random_adds_fail_and_overwrite.c test_lfds700_hash_addonly_random_adds_overwrite.c \ + test_lfds700_list_addonly_ordered_singlylinked.c test_lfds700_list_addonly_ordered_singlylinked_alignment.c test_lfds700_list_addonly_ordered_singlylinked_new_ordered.c test_lfds700_list_addonly_ordered_singlylinked_new_ordered_with_cursor.c \ + test_lfds700_list_addonly_singlylinked_unordered.c test_lfds700_list_addonly_singlylinked_unordered_alignment.c test_lfds700_list_addonly_singlylinked_unordered_new_after.c test_lfds700_list_addonly_singlylinked_unordered_new_end.c test_lfds700_list_addonly_singlylinked_unordered_new_start.c \ + test_lfds700_porting_abstraction_layer_atomic.c test_lfds700_porting_abstraction_layer_atomic_cas.c test_lfds700_porting_abstraction_layer_atomic_dcas.c test_lfds700_porting_abstraction_layer_atomic_exchange.c \ + test_lfds700_queue.c test_lfds700_queue_alignment.c test_lfds700_queue_dequeuing.c test_lfds700_queue_enqueuing.c test_lfds700_queue_enqueuing_and_dequeuing.c test_lfds700_queue_enqueuing_and_dequeuing_with_free.c test_lfds700_queue_enqueuing_with_malloc_and_dequeuing_with_free.c test_lfds700_queue_rapid_enqueuing_and_dequeuing.c \ + test_lfds700_queue_bounded_singleconsumer_singleproducer.c test_lfds700_queue_bounded_singleconsumer_singleproducer_dequeuing.c test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing.c test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing_and_dequeuing.c \ + test_lfds700_ringbuffer.c test_lfds700_ringbuffer_reading.c test_lfds700_ringbuffer_reading_and_writing.c test_lfds700_ringbuffer_writing.c \ + test_lfds700_stack.c test_lfds700_stack_alignment.c test_lfds700_stack_popping.c test_lfds700_stack_popping_and_pushing.c test_lfds700_stack_pushing.c test_lfds700_stack_rapid_popping_and_pushing.c \ + test_porting_abstraction_layer_get_logical_core_ids.c test_porting_abstraction_layer_thread_start.c test_porting_abstraction_layer_thread_wait.c \ + util_cmdline.c util_memory_helpers.c util_thread_starter.c +OBJECTS := $(patsubst %.c,$(OBJDIR)/%.obj,$(notdir $(SOURCES))) +RESFILE := $(patsubst %.rc,$(OBJDIR)/%.res,$(notdir $(RCFILE))) +SYSLIBS := kernel32.lib +EXTLIBS := +USRLIBS := ../../../liblfds700/bin/liblfds700.lib + +##### default paths fix up ##### +INCLUDE += ;../../../../liblfds700/inc/ +LIB += ;../../../../liblfds700/bin/ + +##### tools ##### +MAKE := make +MFLAGS := + +CC := cl +CFBASE := /c /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN /DUNICODE /D_UNICODE /DUNICODE "/Fd$(BINDIR)\$(BINNAME).pdb" /nologo /W4 /WX +CFREL := /DNDEBUG /Ox +CFDBG := /D_DEBUG /Od /Gm /Zi + +LD := link +LFBASE := /nologo /subsystem:console /nodefaultlib /nxcompat /wx +LFREL := /incremental:no +LFDBG := /debug "/pdb:$(BINDIR)\$(BINNAME).pdb" + +##### variants ##### +CFLAGS := $(CFBASE) $(CFDBG) /MTd +LFLAGS := $(LFBASE) $(LFDBG) +CLIB := libcmtd.lib + +ifeq ($(MAKECMDGOALS),librel) + CFLAGS := $(CFBASE) $(CFREL) /MT + LFLAGS := $(LFBASE) $(LFREL) + CLIB := libcmt.lib +endif + +ifeq ($(MAKECMDGOALS),libdbg) + CFLAGS := $(CFBASE) $(CFDBG) /MTd + LFLAGS := $(LFBASE) $(LFDBG) + CLIB := libcmtd.lib +endif + +ifeq ($(MAKECMDGOALS),dllrel) + CFLAGS := $(CFBASE) $(CFREL) /MD + LFLAGS := $(LFBASE) $(LFREL) + CLIB := msvcrt.lib +endif + +ifeq ($(MAKECMDGOALS),dlldbg) + CFLAGS := $(CFBASE) $(CFDBG) /MDd + LFLAGS := $(LFBASE) $(LFDBG) + CLIB := msvcrtd.lib +endif + +##### search paths ##### +vpath %.c $(patsubst %,$(SRCDIR)/%;,$(SRCDIRS)) + +##### implicit rules ##### +$(OBJDIR)/%.obj : %.c + $(CC) $(CFLAGS) "/Fo$@" $< + +##### explicit rules ##### +$(BINARY) : $(OBJECTS) $(USRLIBS) + $(LD) $(LFLAGS) $(CLIB) $(SYSLIBS) $(EXTLIBS) $(USRLIBS) $(OBJECTS) /out:$(BINARY) + +##### phony ##### +.PHONY : clean librel libdbg dllrel dlldbg + +clean : + @erase /Q $(OBJDIR)\*.obj $(OBJDIR)\*.res $(BINDIR)\$(BINNAME).* $(QUIETLY) + +dlldbg : $(BINARY) +dllrel : $(BINARY) + +libdbg : $(BINARY) +librel : $(BINARY) + +##### notes ##### +# TRD : we fix up the default paths because cl and link require an extra argument per additional path, which is ugly as hell + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.sln b/openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.sln new file mode 100644 index 0000000000..cc8727482f --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.sln @@ -0,0 +1,67 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}" + ProjectSection(ProjectDependencies) = postProject + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0} = {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblfds700", "..\..\..\liblfds700\build\visual_studio_professional_2012\liblfds700.vcxproj", "{1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug DLL|Win32 = Debug DLL|Win32 + Debug DLL|x64 = Debug DLL|x64 + Debug LIB|Win32 = Debug LIB|Win32 + Debug LIB|x64 = Debug LIB|x64 + Release DLL|Win32 = Release DLL|Win32 + Release DLL|x64 = Release DLL|x64 + Release LIB|Win32 = Release LIB|Win32 + Release LIB|x64 = Release LIB|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Debug DLL|Win32.ActiveCfg = Debug DLL|Win32 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Debug DLL|Win32.Build.0 = Debug DLL|Win32 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Debug DLL|Win32.Deploy.0 = Debug DLL|Win32 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Debug DLL|x64.ActiveCfg = Debug DLL|x64 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Debug DLL|x64.Build.0 = Debug DLL|x64 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Debug DLL|x64.Deploy.0 = Debug DLL|x64 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Debug LIB|Win32.ActiveCfg = Debug LIB|Win32 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Debug LIB|Win32.Build.0 = Debug LIB|Win32 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Debug LIB|Win32.Deploy.0 = Debug LIB|Win32 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Debug LIB|x64.ActiveCfg = Debug LIB|x64 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Debug LIB|x64.Build.0 = Debug LIB|x64 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Debug LIB|x64.Deploy.0 = Debug LIB|x64 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Release DLL|Win32.ActiveCfg = Release DLL|Win32 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Release DLL|Win32.Build.0 = Release DLL|Win32 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Release DLL|Win32.Deploy.0 = Release DLL|Win32 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Release DLL|x64.ActiveCfg = Release DLL|x64 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Release DLL|x64.Build.0 = Release DLL|x64 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Release DLL|x64.Deploy.0 = Release DLL|x64 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Release LIB|Win32.ActiveCfg = Release LIB|Win32 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Release LIB|Win32.Build.0 = Release LIB|Win32 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Release LIB|Win32.Deploy.0 = Release LIB|Win32 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Release LIB|x64.ActiveCfg = Release LIB|x64 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Release LIB|x64.Build.0 = Release LIB|x64 + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43}.Release LIB|x64.Deploy.0 = Release LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|Win32.ActiveCfg = Debug DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|Win32.Build.0 = Debug DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|x64.ActiveCfg = Debug DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug DLL|x64.Build.0 = Debug DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|Win32.ActiveCfg = Debug LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|Win32.Build.0 = Debug LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|x64.ActiveCfg = Debug LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Debug LIB|x64.Build.0 = Debug LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|Win32.ActiveCfg = Release DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|Win32.Build.0 = Release DLL|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|x64.ActiveCfg = Release DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release DLL|x64.Build.0 = Release DLL|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|Win32.ActiveCfg = Release LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|Win32.Build.0 = Release LIB|Win32 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|x64.ActiveCfg = Release LIB|x64 + {1E5D7D09-94F2-455D-AE5E-6C7F4C96BCE0}.Release LIB|x64.Build.0 = Release LIB|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.vcxproj b/openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.vcxproj new file mode 100644 index 0000000000..3fbf8d78ee --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.vcxproj @@ -0,0 +1,554 @@ + + + + + Debug DLL + Win32 + + + Debug DLL + x64 + + + Debug LIB + Win32 + + + Debug LIB + x64 + + + Release DLL + Win32 + + + Release DLL + x64 + + + Release LIB + Win32 + + + Release LIB + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {1e5d7d09-94f2-455d-ae5e-6c7f4c96bce0} + + + + {A6BA3A68-A1D4-4C07-A0D5-7EAE73272A43} + Win32Proj + + + + Application + true + v110 + + + Application + true + v110 + + + Application + true + v110 + + + Application + true + v110 + + + Application + false + v110 + + + Application + false + v110 + + + Application + false + v110 + + + Application + false + v110 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + false + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + false + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + false + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + false + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + false + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + false + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + false + $(ProjectDir)..\..\bin\$(Platform) $(Configuration)\ + $(ProjectDir)..\..\obj\$(Platform) $(Configuration)\ + + + + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + true + false + false + false + false + NoExtensions + false + false + false + true + CompileAsC + None + ..\liblfds700\inc;%(AdditionalIncludeDirectories) + true + + + MachineX86 + true + Console + true + + + + + kernel32.lib;%(AdditionalDependencies) + + + + + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + true + false + false + false + false + NoExtensions + false + false + false + true + CompileAsC + None + ..\liblfds700\inc;%(AdditionalIncludeDirectories) + true + + + MachineX86 + true + Console + true + + + + + kernel32.lib;%(AdditionalDependencies) + + + + + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + true + false + false + false + false + NotSet + false + false + false + true + CompileAsC + None + true + false + + + true + Console + true + + + kernel32.lib;%(AdditionalDependencies) + + + + + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + ProgramDatabase + Disabled + false + false + true + true + true + true + true + false + false + false + false + NotSet + false + false + false + true + CompileAsC + None + true + false + + + true + Console + true + + + kernel32.lib;%(AdditionalDependencies) + + + true + + + + + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level4 + None + false + false + false + false + CompileAsC + true + + + true + AnySuitable + true + Speed + true + true + true + true + false + true + true + false + false + false + None + + + MachineX86 + false + Console + true + true + true + true + NoErrorReport + kernel32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + + + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level4 + None + false + false + false + false + CompileAsC + true + + + true + AnySuitable + true + Speed + true + true + true + true + false + true + true + false + false + false + None + + + MachineX86 + false + Console + true + true + true + true + NoErrorReport + kernel32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + + + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level4 + None + false + false + false + false + CompileAsC + true + + + true + AnySuitable + true + Speed + true + true + true + true + false + true + true + false + false + false + None + + + false + Console + true + true + true + true + NoErrorReport + kernel32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + + + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Level4 + None + false + false + false + false + CompileAsC + true + + + true + AnySuitable + true + Speed + true + true + true + true + false + true + true + false + false + false + None + + + false + Console + true + true + true + true + NoErrorReport + kernel32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + + + + \ No newline at end of file diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.vcxproj.filters b/openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.vcxproj.filters new file mode 100644 index 0000000000..69da4b9836 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.vcxproj.filters @@ -0,0 +1,216 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.vcxproj.user b/openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.vcxproj.user new file mode 100644 index 0000000000..7cbb3216ad --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/build/visual_studio_professional_2012/test.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/internal.h b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/internal.h new file mode 100644 index 0000000000..14bf02c74c --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/internal.h @@ -0,0 +1,157 @@ +/***** includes *****/ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../liblfds700/inc/liblfds700.h" +#include "test_porting_abstraction_layer_operating_system.h" + +/***** defines *****/ +#define and && +#define or || + +#define NO_FLAGS 0x0 + +#define BITS_PER_BYTE 8 + +#define TEST_DURATION_IN_SECONDS 5 +#define TIME_LOOP_COUNT 10000 +#define REDUCED_TIME_LOOP_COUNT 1000 +#define NUMBER_OF_NANOSECONDS_IN_ONE_SECOND 1000000000LLU +#define ONE_MEGABYTE_IN_BYTES (1024 * 1024) +#define DEFAULT_TEST_MEMORY_IN_MEGABYTES 512U +#define TEST_PAL_DEFAULT_NUMA_NODE_ID 0 +#define LFDS700_TEST_VERSION_STRING "7.0.0" +#define LFDS700_TEST_VERSION_INTEGER 700 + +#if( defined _KERNEL_MODE ) + #define MODE_TYPE_STRING "kernel-mode" +#endif + +#if( !defined _KERNEL_MODE ) + #define MODE_TYPE_STRING "user-mode" +#endif + +#if( defined NDEBUG && !defined COVERAGE && !defined TSAN ) + #define BUILD_TYPE_STRING "release" +#endif + +#if( !defined NDEBUG && !defined COVERAGE && !defined TSAN ) + #define BUILD_TYPE_STRING "debug" +#endif + +#if( !defined NDEBUG && defined COVERAGE && !defined TSAN ) + #define BUILD_TYPE_STRING "coverage" +#endif + +#if( !defined NDEBUG && !defined COVERAGE && defined TSAN ) + #define BUILD_TYPE_STRING "threadsanitizer" +#endif + +/***** enums *****/ +enum flag +{ + LOWERED, + RAISED +}; + +/***** structs *****/ +struct test_pal_logical_processor +{ + lfds700_pal_uint_t + logical_processor_number, + windows_logical_processor_group_number; + + struct lfds700_list_asu_element + lasue; +}; + +/***** prototypes *****/ +int main( int argc, char **argv ); + +void internal_display_test_name( char *format_string, ... ); +void internal_display_test_result( lfds700_pal_uint_t number_name_dvs_pairs, ... ); +void internal_display_data_structure_validity( enum lfds700_misc_validity dvs ); +void internal_show_version( void ); +void internal_logical_core_id_element_cleanup_callback( struct lfds700_list_asu_state *lasus, struct lfds700_list_asu_element *lasue ); + +int test_pal_thread_start( test_pal_thread_state_t *thread_state, struct test_pal_logical_processor *lp, test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state), void *thread_user_state ); +void test_pal_thread_wait( test_pal_thread_state_t thread_state ); +void test_pal_get_logical_core_ids( struct lfds700_list_asu_state *lasus ); + +void test_lfds700_pal_atomic( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_pal_atomic_cas( struct lfds700_list_asu_state *list_of_logical_processors ); + void test_lfds700_pal_atomic_dwcas( struct lfds700_list_asu_state *list_of_logical_processors ); + void test_lfds700_pal_atomic_exchange( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + +void test_lfds700_hash_a( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_hash_a_alignment( void ); + void test_lfds700_hash_a_fail_and_overwrite_on_existing_key( void ); + void test_lfds700_hash_a_random_adds_fail_on_existing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_hash_a_random_adds_overwrite_on_existing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_hash_a_iterate( void ); + +void test_lfds700_list_aos( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_list_aos_alignment( void ); + void test_lfds700_list_aos_new_ordered( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_list_aos_new_ordered_with_cursor( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + +void test_lfds700_list_asu( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_list_asu_alignment( void ); + void test_lfds700_list_asu_new_start( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_list_asu_new_end( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_list_asu_new_after( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + +void test_lfds700_btree_au( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_btree_au_alignment( void ); + void test_lfds700_btree_au_fail_and_overwrite_on_existing_key( void ); + void test_lfds700_btree_au_random_adds_fail_on_existing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_btree_au_random_adds_overwrite_on_existing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + +void test_lfds700_freelist( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_freelist_alignment( void ); + void test_lfds700_freelist_popping( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_freelist_pushing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_freelist_popping_and_pushing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_freelist_rapid_popping_and_pushing( struct lfds700_list_asu_state *list_of_logical_processors ); + void test_lfds700_freelist_pushing_array( void ); + +void test_lfds700_queue( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_queue_alignment( void ); + void test_lfds700_queue_enqueuing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_queue_dequeuing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_queue_enqueuing_and_dequeuing( struct lfds700_list_asu_state *list_of_logical_processors ); + void test_lfds700_queue_rapid_enqueuing_and_dequeuing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_queue_enqueuing_and_dequeuing_with_free( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_queue_enqueuing_with_malloc_and_dequeuing_with_free( struct lfds700_list_asu_state *list_of_logical_processors ); + +void test_lfds700_queue_bss( struct lfds700_list_asu_state *list_of_logical_processors ); + void test_lfds700_queue_bss_enqueuing( void ); + void test_lfds700_queue_bss_dequeuing( void ); + void test_lfds700_queue_bss_enqueuing_and_dequeuing( struct lfds700_list_asu_state *list_of_logical_processors ); + +void test_lfds700_ringbuffer( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_ringbuffer_reading( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_ringbuffer_reading_and_writing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_ringbuffer_writing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + +void test_lfds700_stack( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_stack_alignment( void ); + void test_lfds700_stack_pushing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_stack_popping( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_stack_popping_and_pushing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ); + void test_lfds700_stack_rapid_popping_and_pushing( struct lfds700_list_asu_state *list_of_logical_processors ); + void test_lfds700_stack_pushing_array( void ); + +/***** late includes *****/ +#include "util_cmdline.h" +#include "util_memory_helpers.h" +#include "util_thread_starter.h" + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/main.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/main.c new file mode 100644 index 0000000000..fa6afc8747 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/main.c @@ -0,0 +1,135 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +int main( int argc, char **argv ) +{ + enum flag + run_flag = LOWERED, + show_error_flag = LOWERED, + show_help_flag = LOWERED, + show_version_flag = LOWERED; + + int + rv; + + lfds700_pal_uint_t + loop, + iterations = 1, + memory_in_megabytes = DEFAULT_TEST_MEMORY_IN_MEGABYTES; + + struct lfds700_list_asu_state + list_of_logical_processors; + + struct util_cmdline_state + cs; + + union util_cmdline_arg_data + *arg_data; + + assert( argc >= 1 ); + assert( argv != NULL ); + + lfds700_misc_library_init_valid_on_current_logical_core(); + + util_cmdline_init( &cs ); + + util_cmdline_add_arg( &cs, 'h', LIBCOMMON_CMDLINE_ARG_TYPE_FLAG ); + util_cmdline_add_arg( &cs, 'i', LIBCOMMON_CMDLINE_ARG_TYPE_INTEGER ); + util_cmdline_add_arg( &cs, 'm', LIBCOMMON_CMDLINE_ARG_TYPE_INTEGER ); + util_cmdline_add_arg( &cs, 'r', LIBCOMMON_CMDLINE_ARG_TYPE_FLAG ); + util_cmdline_add_arg( &cs, 'v', LIBCOMMON_CMDLINE_ARG_TYPE_FLAG ); + + rv = util_cmdline_process_args( &cs, argc, argv ); + + if( rv == 0 ) + show_error_flag = RAISED; + + if( rv == 1 ) + { + util_cmdline_get_arg_data( &cs, 'h', &arg_data ); + if( arg_data != NULL ) + show_help_flag = RAISED; + + util_cmdline_get_arg_data( &cs, 'i', &arg_data ); + if( arg_data != NULL ) + iterations = (lfds700_pal_uint_t) arg_data->integer.integer; + + util_cmdline_get_arg_data( &cs, 'm', &arg_data ); + if( arg_data != NULL ) + memory_in_megabytes = (lfds700_pal_uint_t) arg_data->integer.integer; + + util_cmdline_get_arg_data( &cs, 'r', &arg_data ); + if( arg_data != NULL ) + run_flag = RAISED; + + util_cmdline_get_arg_data( &cs, 'v', &arg_data ); + if( arg_data != NULL ) + show_version_flag = RAISED; + } + + util_cmdline_cleanup( &cs ); + + if( argc == 1 or (run_flag == LOWERED and show_version_flag == LOWERED) ) + show_help_flag = RAISED; + + if( show_error_flag == RAISED ) + { + printf( "\nInvalid arguments. Sorry - it's a simple parser, so no clues.\n" + "-h or run with no args to see the help text.\n" ); + + return( EXIT_SUCCESS ); + } + + if( show_help_flag == RAISED ) + { + printf( "test -h -i [n] -m [n] -r -v\n" + " -h : help\n" + " -i [n] : number of iterations (default : 1)\n" + " -m [n] : memory for tests, in mb (default : %u)\n" + " -r : run (causes test to run; present so no args gives help)\n" + " -v : version\n", DEFAULT_TEST_MEMORY_IN_MEGABYTES ); + + return( EXIT_SUCCESS ); + } + + if( show_version_flag == RAISED ) + { + internal_show_version(); + return( EXIT_SUCCESS ); + } + + if( run_flag == RAISED ) + { + test_pal_get_logical_core_ids( &list_of_logical_processors ); + + for( loop = 0 ; loop < (lfds700_pal_uint_t) iterations ; loop++ ) + { + printf( "\n" + "Test Iteration %02llu\n" + "=================\n", (int long long unsigned) (loop+1) ); + + test_lfds700_pal_atomic( &list_of_logical_processors, memory_in_megabytes ); + test_lfds700_btree_au( &list_of_logical_processors, memory_in_megabytes ); + test_lfds700_freelist( &list_of_logical_processors, memory_in_megabytes ); + test_lfds700_hash_a( &list_of_logical_processors, memory_in_megabytes ); + test_lfds700_list_aos( &list_of_logical_processors, memory_in_megabytes ); + test_lfds700_list_asu( &list_of_logical_processors, memory_in_megabytes ); + test_lfds700_queue( &list_of_logical_processors, memory_in_megabytes ); + test_lfds700_queue_bss( &list_of_logical_processors ); + test_lfds700_ringbuffer( &list_of_logical_processors, memory_in_megabytes ); + test_lfds700_stack( &list_of_logical_processors, memory_in_megabytes ); + } + + lfds700_list_asu_cleanup( &list_of_logical_processors, internal_logical_core_id_element_cleanup_callback ); + } + + lfds700_misc_library_cleanup(); + + return( EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/misc.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/misc.c new file mode 100644 index 0000000000..4fa794f68d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/misc.c @@ -0,0 +1,191 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +void internal_display_test_name( char *format_string, ... ) +{ + va_list + va; + + assert( format_string != NULL ); + + va_start( va, format_string ); + + vprintf( format_string, va ); + + printf( "..." ); + + va_end( va ); + + fflush( stdout ); + + return; +} + + + + + +/****************************************************************************/ +void internal_display_test_result( lfds700_pal_uint_t number_name_dvs_pairs, ... ) +{ + char + *name; + + enum flag + passed_flag = RAISED; + + enum lfds700_misc_validity + dvs; + + lfds700_pal_uint_t + loop; + + va_list + va; + + // TRD : number_name_dvs_pairs can be any value in its range + + va_start( va, number_name_dvs_pairs ); + + for( loop = 0 ; loop < number_name_dvs_pairs ; loop++ ) + { + name = va_arg( va, char * ); + dvs = va_arg( va, enum lfds700_misc_validity ); + + if( dvs != LFDS700_MISC_VALIDITY_VALID ) + { + passed_flag = LOWERED; + break; + } + } + + va_end( va ); + + if( passed_flag == RAISED ) + puts( "passed" ); + + if( passed_flag == LOWERED ) + { + printf( "failed (" ); + + va_start( va, number_name_dvs_pairs ); + + for( loop = 0 ; loop < number_name_dvs_pairs ; loop++ ) + { + name = va_arg( va, char * ); + dvs = va_arg( va, enum lfds700_misc_validity ); + + printf( "%s ", name ); + internal_display_data_structure_validity( dvs ); + + if( loop+1 < number_name_dvs_pairs ) + printf( ", " ); + } + + va_end( va ); + + printf( ")\n" ); + + /* TRD : quick hack + the whole test programme needs rewriting + and for now I just want to make it so we + exit with failure upon any test failing + */ + + exit( EXIT_FAILURE ); + } + + return; +} + + + + + +/****************************************************************************/ +void internal_display_data_structure_validity( enum lfds700_misc_validity dvs ) +{ + char + *string = NULL; + + switch( dvs ) + { + case LFDS700_MISC_VALIDITY_VALID: + string = "valid"; + break; + + case LFDS700_MISC_VALIDITY_INVALID_LOOP: + string = "invalid - loop detected"; + break; + + case LFDS700_MISC_VALIDITY_INVALID_ORDER: + string = "invalid - invalid order detected"; + break; + + case LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS: + string = "invalid - missing elements"; + break; + + case LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS: + string = "invalid - additional elements"; + break; + + case LFDS700_MISC_VALIDITY_INVALID_TEST_DATA: + string = "invalid - invalid test data"; + break; + } + + printf( "%s", string ); + + return; +} + + + + + +/****************************************************************************/ +void internal_show_version() +{ + char const + *version_and_build_string; + + printf( "test %s (%s, %s) (" __DATE__ " " __TIME__ ")\n", LFDS700_TEST_VERSION_STRING, BUILD_TYPE_STRING, MODE_TYPE_STRING ); + + lfds700_misc_query( LFDS700_MISC_QUERY_GET_BUILD_AND_VERSION_STRING, NULL, (void **) &version_and_build_string ); + + printf( "%s\n", version_and_build_string ); + + return; +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +void internal_logical_core_id_element_cleanup_callback( struct lfds700_list_asu_state *lasus, struct lfds700_list_asu_element *lasue ) +{ + struct test_pal_logical_processor + *lp; + + assert( lasus != NULL ); + assert( lasue != NULL ); + + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + + util_aligned_free( lp ); + + return; +} + +#pragma warning( default : 4100 ) + + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced.c new file mode 100644 index 0000000000..55b94ca5bb --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced.c @@ -0,0 +1,32 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_btree_au( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + if( LFDS700_MISC_ATOMIC_SUPPORT_CAS and LFDS700_MISC_ATOMIC_SUPPORT_EXCHANGE ) + { + printf( "\n" + "Binary Tree (add-only, unbalanced) Tests\n" + "========================================\n" ); + + test_lfds700_btree_au_alignment(); + test_lfds700_btree_au_fail_and_overwrite_on_existing_key(); + test_lfds700_btree_au_random_adds_fail_on_existing( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_btree_au_random_adds_overwrite_on_existing( list_of_logical_processors, memory_in_megabytes ); + } + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_alignment.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_alignment.c new file mode 100644 index 0000000000..ecdaf29adb --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_alignment.c @@ -0,0 +1,64 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_btree_au_alignment() +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + /* TRD : these are compile time checks + but we do them here because this is a test programme + and it should indicate issues to users when it is *run*, + not when it is compiled, because a compile error normally + indicates a problem with the code itself and so is misleading + */ + + internal_display_test_name( "Alignment" ); + + + + // TRD : struct lfds700_btree_au_element + if( offsetof(struct lfds700_btree_au_element,up) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_btree_au_element,left) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_btree_au_element,right) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_btree_au_element,key) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_btree_au_element,value) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_btree_au_element,key) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + + + // TRD : struct lfds700_btree_au_state + if( offsetof(struct lfds700_btree_au_state,root) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_btree_au_state,key_compare_function) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + + + // TRD : print the test result + internal_display_test_result( 1, "btree_au", dvs ); + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_random_adds_fail.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_random_adds_fail.c new file mode 100644 index 0000000000..ae043a0669 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_random_adds_fail.c @@ -0,0 +1,319 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_element +{ + struct lfds700_btree_au_element + baue; + + lfds700_pal_uint_t + key; +}; + +struct test_state +{ + lfds700_pal_uint_t + insert_fail_count, + number_elements; + + struct lfds700_btree_au_state + *baus; + + struct test_element + *element_array; +}; + +/***** private prototypes *****/ +static int key_compare_function( void const *new_value, void const *value_in_tree ); +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_adding( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_btree_au_random_adds_fail_on_existing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + actual_sum_insert_failure_count, + expected_sum_insert_failure_count, + index = 0, + *key_count_array, + loop, + number_elements, + number_logical_processors, + random_value, + subloop; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_btree_au_element + *baue = NULL; + + struct lfds700_btree_au_state + baus; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + void + *key; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we create a single btree_au + we generate 10k elements per thread (one per logical processor) in an array + we set a random number in each element, which is the key + random numbers are generated are from 0 to 5000, so we must have some duplicates + (we don't use value, so we always pass in a NULL for that when we insert) + + each thread loops, adds those elements into the btree, and counts the total number of insert fails + (we don't count on a per value basis because of the performance hit - we'll be TLBing all the time) + this test has the btree_au set to fail on add, so duplicates should be eliminated + + we then merge the per-thread arrays + + we should find in the tree one of every value, and the sum of the counts of each value (beyond the + first value, which was inserted) in the merged arrays should equal the sum of the insert fails from + each thread + + we check the count of unique values in the merged array and use that when calling the btree_au validation function + + we in-order walk and check that what we have in the tree matches what we have in the merged array + and then check the fail counts + */ + + internal_display_test_name( "Random adds and walking (fail on existing key)" ); + + lfds700_misc_prng_init( &ps ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_btree_au_init_valid_on_current_logical_core( &baus, key_compare_function, LFDS700_BTREE_AU_EXISTING_KEY_FAIL, NULL ); + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors ); + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->baus = &baus; + (ts+loop)->element_array = util_aligned_malloc( sizeof(struct test_element) * number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + (ts+loop)->number_elements = number_elements; + (ts+loop)->insert_fail_count = 0; + + for( subloop = 0 ; subloop < number_elements ; subloop++ ) + { + random_value = LFDS700_MISC_PRNG_GENERATE( &ps ); + ((ts+loop)->element_array+subloop)->key = (lfds700_pal_uint_t) floor( (number_elements/2) * ((double) random_value / (double) LFDS700_MISC_PRNG_MAX) ); + } + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_adding, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + /* TRD : now for validation + make an array equal to number_elements, set all to 0 + iterate over every per-thread array, counting the number of each value into this array + so we can know how many elements ought to have failed to be inserted + as well as being able to work out the actual number of elements which should be present in the btree, for the btree validation call + */ + + key_count_array = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_elements ); + for( loop = 0 ; loop < number_elements ; loop++ ) + *(key_count_array+loop) = 0; + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + for( subloop = 0 ; subloop < number_elements ; subloop++ ) + ( *(key_count_array+( (ts+loop)->element_array+subloop)->key) )++; + + // TRD : first, btree validation function + vi.min_elements = number_elements; + + for( loop = 0 ; loop < number_elements ; loop++ ) + if( *(key_count_array+loop) == 0 ) + vi.min_elements--; + + vi.max_elements = vi.min_elements; + + lfds700_btree_au_query( &baus, LFDS700_BTREE_AU_QUERY_SINGLETHREADED_VALIDATE, (void *) &vi, (void *) &dvs ); + + /* TRD : now check the sum of per-thread insert failures + is what it should be, which is the sum of key_count_array, + but with every count minus one (for the single succesful insert) + and where elements of 0 are ignored (i.e. do not have -1 applied) + */ + + expected_sum_insert_failure_count = 0; + + for( loop = 0 ; loop < number_elements ; loop++ ) + if( *(key_count_array+loop) != 0 ) + expected_sum_insert_failure_count += *(key_count_array+loop) - 1; + + actual_sum_insert_failure_count = 0; + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + actual_sum_insert_failure_count += (ts+loop)->insert_fail_count; + + if( expected_sum_insert_failure_count != actual_sum_insert_failure_count ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + /* TRD : now compared the combined array and an in-order walk of the tree + ignoring array elements with the value 0, we should find an exact match + */ + + if( dvs == LFDS700_MISC_VALIDITY_VALID ) + { + // TRD : in-order walk over btree_au and check key_count_array matches + while( dvs == LFDS700_MISC_VALIDITY_VALID and lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position(&baus, &baue, LFDS700_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE, LFDS700_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE) ) + { + key = LFDS700_BTREE_AU_GET_KEY_FROM_ELEMENT( *baue ); + + while( *(key_count_array+index) == 0 ) + index++; + + if( index++ != (lfds700_pal_uint_t) key ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + } + } + + // TRD : cleanup + free( key_count_array ); + + lfds700_btree_au_cleanup( &baus, NULL ); + + // TRD : cleanup + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + util_aligned_free( (ts+loop)->element_array ); + + free( ts ); + + // TRD : print the test result + internal_display_test_result( 1, "btree_au", dvs ); + + return; +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static int key_compare_function( void const *new_key, void const *key_in_tree ) +{ + int + cr = 0; + + // TRD : key_new can be any value in its range + // TRD : key_in_tree can be any value in its range + + if( (lfds700_pal_uint_t) new_key < (lfds700_pal_uint_t) key_in_tree ) + cr = -1; + + if( (lfds700_pal_uint_t) new_key > (lfds700_pal_uint_t) key_in_tree ) + cr = 1; + + return( cr ); +} + +#pragma warning( default : 4100 ) + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_adding( void *util_thread_starter_thread_state ) +{ + enum lfds700_btree_au_insert_result + alr; + + lfds700_pal_uint_t + index = 0; + + struct test_state + *ts; + + struct lfds700_misc_prng_state + ps; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + while( index < ts->number_elements ) + { + LFDS700_BTREE_AU_SET_KEY_IN_ELEMENT( (ts->element_array+index)->baue, (ts->element_array+index)->key ); + LFDS700_BTREE_AU_SET_VALUE_IN_ELEMENT( (ts->element_array+index)->baue, 0 ); + alr = lfds700_btree_au_insert( ts->baus, &(ts->element_array+index)->baue, NULL, &ps ); + + if( alr == LFDS700_BTREE_AU_INSERT_RESULT_FAILURE_EXISTING_KEY ) + ts->insert_fail_count++; + + index++; + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_random_adds_fail_and_overwrite.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_random_adds_fail_and_overwrite.c new file mode 100644 index 0000000000..4c638c8600 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_random_adds_fail_and_overwrite.c @@ -0,0 +1,140 @@ +/***** includes *****/ +#include "internal.h" + +/***** private prototypes *****/ +static int key_compare_function( void const *new_value, void const *value_in_tree ); + + + + + +/****************************************************************************/ +void test_lfds700_btree_au_fail_and_overwrite_on_existing_key() +{ + enum lfds700_btree_au_insert_result + alr; + + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + struct lfds700_btree_au_element + baue_one, + baue_two, + *existing_baue; + + struct lfds700_btree_au_state + baus; + + struct lfds700_misc_prng_state + ps; + + void + *value; + + /* TRD : the random_adds tests with fail and overwrite don't (can't, not in a performant manner) + test that the fail and/or overwrite of user data has *actually* happened - they use the + return value from the link function call, rather than empirically observing the final + state of the tree + + as such, we now have a couple of single threaded tests where we check that the user data + value really is being modified (or not modified, as the case may be) + */ + + internal_display_test_name( "Fail and overwrite on existing key" ); + + lfds700_misc_prng_init( &ps ); + + /* TRD : so, we make a tree which is fail on existing + add one element, with a known user data + we then try to add the same key again, with a different user data + the call should fail, and then we get the element by its key + and check its user data is unchanged + (and confirm the failed link returned the correct existing_baue) + that's the first test done + */ + + lfds700_btree_au_init_valid_on_current_logical_core( &baus, key_compare_function, LFDS700_BTREE_AU_EXISTING_KEY_FAIL, NULL ); + + LFDS700_BTREE_AU_SET_KEY_IN_ELEMENT( baue_one, 0 ); + LFDS700_BTREE_AU_SET_VALUE_IN_ELEMENT( baue_one, 1 ); + alr = lfds700_btree_au_insert( &baus, &baue_one, NULL, &ps ); + + if( alr != LFDS700_BTREE_AU_INSERT_RESULT_SUCCESS ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + LFDS700_BTREE_AU_SET_KEY_IN_ELEMENT( baue_two, 0 ); + LFDS700_BTREE_AU_SET_VALUE_IN_ELEMENT( baue_two, 2 ); + alr = lfds700_btree_au_insert( &baus, &baue_two, &existing_baue, &ps ); + + if( alr != LFDS700_BTREE_AU_INSERT_RESULT_FAILURE_EXISTING_KEY ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( existing_baue != &baue_one ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + value = LFDS700_BTREE_AU_GET_VALUE_FROM_ELEMENT( *existing_baue ); + + if( (void *) (lfds700_pal_uint_t) value != (void *) (lfds700_pal_uint_t) 1 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + lfds700_btree_au_cleanup( &baus, NULL ); + + /* TRD : second test, make a tree which is overwrite on existing + add one element, with a known user data + we then try to add the same key again, with a different user data + the call should succeed, and then we get the element by its key + and check its user data is changed + (and confirm the failed link returned the correct existing_baue) + that's the secondtest done + */ + + lfds700_btree_au_init_valid_on_current_logical_core( &baus, key_compare_function, LFDS700_BTREE_AU_EXISTING_KEY_OVERWRITE, NULL ); + + LFDS700_BTREE_AU_SET_KEY_IN_ELEMENT( baue_one, 0 ); + LFDS700_BTREE_AU_SET_VALUE_IN_ELEMENT( baue_one, 1 ); + alr = lfds700_btree_au_insert( &baus, &baue_one, NULL, &ps ); + + if( alr != LFDS700_BTREE_AU_INSERT_RESULT_SUCCESS ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + LFDS700_BTREE_AU_SET_KEY_IN_ELEMENT( baue_two, 0 ); + LFDS700_BTREE_AU_SET_VALUE_IN_ELEMENT( baue_two, 2 ); + alr = lfds700_btree_au_insert( &baus, &baue_two, NULL, &ps ); + + if( alr != LFDS700_BTREE_AU_INSERT_RESULT_SUCCESS_OVERWRITE ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + lfds700_btree_au_cleanup( &baus, NULL ); + + // TRD : print the test result + internal_display_test_result( 1, "btree_au", dvs ); + + return; +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static int key_compare_function( void const *new_key, void const *key_in_tree ) +{ + int + cr = 0; + + // TRD : key_new can be any value in its range + // TRD : key_in_tree can be any value in its range + + if( (lfds700_pal_uint_t) new_key < (lfds700_pal_uint_t) key_in_tree ) + cr = -1; + + if( (lfds700_pal_uint_t) new_key > (lfds700_pal_uint_t) key_in_tree ) + cr = 1; + + return( cr ); +} + +#pragma warning( default : 4100 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_random_adds_overwrite.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_random_adds_overwrite.c new file mode 100644 index 0000000000..c9b162128b --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_btree_addonly_unbalanced_random_adds_overwrite.c @@ -0,0 +1,322 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_element +{ + struct lfds700_btree_au_element + baue; + + lfds700_pal_uint_t + key; +}; + +struct test_state +{ + lfds700_pal_uint_t + insert_existing_count, + number_elements; + + struct lfds700_btree_au_state + *baus; + + struct test_element + *element_array; +}; + +/***** private prototypes *****/ +static int key_compare_function( void const *new_value, void const *value_in_tree ); +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_adding( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_btree_au_random_adds_overwrite_on_existing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + actual_sum_insert_existing_count, + expected_sum_insert_existing_count, + index = 0, + *key_count_array, + loop, + number_elements, + number_logical_processors, + random_value, + subloop; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_btree_au_element + *baue = NULL; + + struct lfds700_btree_au_state + baus; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + void + *key; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we create a single btree_au + we generate 10k elements per thread (one per logical processor) in an array + we set a random number in each element, which is the key + random numbers are generated are from 0 to 5000, so we must have some duplicates + (we don't use value, so we always pass in a NULL for that when we insert) + + each thread loops, adds those elements into the btree, and counts the total number of insert fails + (we don't count on a per value basis because of the performance hit - we'll be TLBing all the time) + this test has the btree_au set to overwrite on add, so duplicates should be eliminated + + we then merge the per-thread arrays + + we should find in the tree one of every value, and the sum of the counts of each value (beyond the + first value, which was inserted) in the merged arrays should equal the sum of the existing_baues returned + from each thread when they inserted and found an existing element + + we check the count of unique values in the merged array and use that when calling the btree_au validation function + + we in-order walk and check that what we have in the tree matches what we have in the merged array + and then check the fail counts + */ + + internal_display_test_name( "Random adds and walking (overwrite on existing key)" ); + + lfds700_misc_prng_init( &ps ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_btree_au_init_valid_on_current_logical_core( &baus, key_compare_function, LFDS700_BTREE_AU_EXISTING_KEY_OVERWRITE, NULL ); + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors ); + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->baus = &baus; + (ts+loop)->element_array = util_aligned_malloc( sizeof(struct test_element) * number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + (ts+loop)->number_elements = number_elements; + (ts+loop)->insert_existing_count = 0; + + for( subloop = 0 ; subloop < number_elements ; subloop++ ) + { + random_value = LFDS700_MISC_PRNG_GENERATE( &ps ); + ((ts+loop)->element_array+subloop)->key = (lfds700_pal_uint_t) floor( (number_elements/2) * ((double) random_value / (double) LFDS700_MISC_PRNG_MAX) ); + } + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_adding, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + /* TRD : now for validation + make an array equal to number_elements, set all to 0 + iterate over every per-thread array, counting the number of each value into this array + so we can know how many elements ought to have failed to be inserted + as well as being able to work out the actual number of elements which should be present in the btree, for the btree validation call + */ + + key_count_array = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_elements ); + for( loop = 0 ; loop < number_elements ; loop++ ) + *(key_count_array+loop) = 0; + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + for( subloop = 0 ; subloop < number_elements ; subloop++ ) + ( *(key_count_array+( (ts+loop)->element_array+subloop)->key) )++; + + // TRD : first, btree validation function + vi.min_elements = number_elements; + + for( loop = 0 ; loop < number_elements ; loop++ ) + if( *(key_count_array+loop) == 0 ) + vi.min_elements--; + + vi.max_elements = vi.min_elements; + + lfds700_btree_au_query( &baus, LFDS700_BTREE_AU_QUERY_SINGLETHREADED_VALIDATE, (void *) &vi, (void *) &dvs ); + + /* TRD : now check the sum of per-thread insert failures + is what it should be, which is the sum of key_count_array, + but with every count minus one (for the single succesful insert) + and where elements of 0 are ignored (i.e. do not have -1 applied) + */ + + expected_sum_insert_existing_count = 0; + + for( loop = 0 ; loop < number_elements ; loop++ ) + if( *(key_count_array+loop) != 0 ) + expected_sum_insert_existing_count += *(key_count_array+loop) - 1; + + actual_sum_insert_existing_count = 0; + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + actual_sum_insert_existing_count += (ts+loop)->insert_existing_count; + + if( expected_sum_insert_existing_count != actual_sum_insert_existing_count ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + /* TRD : now compared the combined array and an in-order walk of the tree + ignoring array elements with the value 0, we should find an exact match + */ + + if( dvs == LFDS700_MISC_VALIDITY_VALID ) + { + // TRD : in-order walk over btree_au and check key_count_array matches + while( dvs == LFDS700_MISC_VALIDITY_VALID and lfds700_btree_au_get_by_absolute_position_and_then_by_relative_position(&baus, &baue, LFDS700_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE, LFDS700_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE) ) + { + key = LFDS700_BTREE_AU_GET_KEY_FROM_ELEMENT( *baue ); + + while( *(key_count_array+index) == 0 ) + index++; + + if( index++ != (lfds700_pal_uint_t) key ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + } + } + + // TRD : cleanup + free( key_count_array ); + + lfds700_btree_au_cleanup( &baus, NULL ); + + // TRD : cleanup + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + util_aligned_free( (ts+loop)->element_array ); + + free( ts ); + + // TRD : print the test result + internal_display_test_result( 1, "btree_au", dvs ); + + return; +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static int key_compare_function( void const *new_key, void const *key_in_tree ) +{ + int + cr = 0; + + // TRD : key_new can be any value in its range + // TRD : key_in_tree can be any value in its range + + if( (lfds700_pal_uint_t) new_key < (lfds700_pal_uint_t) key_in_tree ) + cr = -1; + + if( (lfds700_pal_uint_t) new_key > (lfds700_pal_uint_t) key_in_tree ) + cr = 1; + + return( cr ); +} + +#pragma warning( default : 4100 ) + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_adding( void *util_thread_starter_thread_state ) +{ + enum lfds700_btree_au_insert_result + alr; + + lfds700_pal_uint_t + index = 0; + + struct test_state + *ts; + + struct lfds700_btree_au_element + *existing_baue; + + struct lfds700_misc_prng_state + ps; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + while( index < ts->number_elements ) + { + LFDS700_BTREE_AU_SET_KEY_IN_ELEMENT( (ts->element_array+index)->baue, (ts->element_array+index)->key ); + LFDS700_BTREE_AU_SET_VALUE_IN_ELEMENT( (ts->element_array+index)->baue, 0 ); + alr = lfds700_btree_au_insert( ts->baus, &(ts->element_array+index)->baue, &existing_baue, &ps ); + + if( alr == LFDS700_BTREE_AU_INSERT_RESULT_SUCCESS_OVERWRITE ) + ts->insert_existing_count++; + + index++; + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist.c new file mode 100644 index 0000000000..1968ae7167 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist.c @@ -0,0 +1,33 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_freelist( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + if( LFDS700_MISC_ATOMIC_SUPPORT_DWCAS ) + { + printf( "\n" + "Freelist Tests\n" + "==============\n" ); + + test_lfds700_freelist_alignment(); + test_lfds700_freelist_popping( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_freelist_pushing( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_freelist_popping_and_pushing( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_freelist_rapid_popping_and_pushing( list_of_logical_processors ); + } + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_alignment.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_alignment.c new file mode 100644 index 0000000000..885ecbf8c4 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_alignment.c @@ -0,0 +1,43 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_freelist_alignment() +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + /* TRD : these are compile time checks + but we do them here because this is a test programme + and it should indicate issues to users when it is *run*, + not when it is compiled, because a compile error normally + indicates a problem with the code itself and so is misleading + */ + + internal_display_test_name( "Alignment" ); + + + + // TRD : struct lfds700_freelist_state + if( offsetof(struct lfds700_freelist_state,top) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_freelist_state,user_state) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + + + // TRD : print the test result + internal_display_test_result( 1, "freelist", dvs ); + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_popping.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_popping.c new file mode 100644 index 0000000000..6dcbd0847a --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_popping.c @@ -0,0 +1,205 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + struct lfds700_freelist_state + *fs; +}; + +struct test_element +{ + struct lfds700_freelist_element + fe; + + enum flag + popped_flag; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_freelist_popping( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_elements, + number_logical_processors; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_freelist_state + fs; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_misc_validation_info + vi = { 0, 0 }; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te_array; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we create a freelist with 1,000,000 elements + + the creation function runs in a single thread and creates + and pushes those elements onto the freelist + + each element contains a void pointer to the container test element + + we then run one thread per CPU + where each thread loops, popping as quickly as possible + each test element has a flag which indicates it has been popped + + the threads run till the source freelist is empty + + we then check the test elements + every element should have been popped + + then tidy up + + we have no extra code for CAS/GC as we're only popping + */ + + internal_display_test_name( "Popping" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + lfds700_freelist_init_valid_on_current_logical_core( &fs, NULL ); + + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / sizeof(struct test_element); + + te_array = util_aligned_malloc( sizeof(struct test_element) * number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_elements ; loop++ ) + { + (te_array+loop)->popped_flag = LOWERED; + LFDS700_FREELIST_SET_VALUE_IN_ELEMENT( (te_array+loop)->fe, te_array+loop ); + lfds700_freelist_push( &fs, &(te_array+loop)->fe, &ps ); + } + + ts = util_aligned_malloc( sizeof(struct test_state) * number_logical_processors, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + (ts+loop)->fs = &fs; + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_popping, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + lfds700_freelist_query( &fs, LFDS700_FREELIST_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + // TRD : now we check each element has popped_flag set to RAISED + for( loop = 0 ; loop < number_elements ; loop++ ) + if( (te_array+loop)->popped_flag == LOWERED ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + // TRD : cleanup + lfds700_freelist_cleanup( &fs, NULL ); + util_aligned_free( ts ); + util_aligned_free( te_array ); + + // TRD : print the test result + internal_display_test_result( 1, "freelist", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping( void *util_thread_starter_thread_state ) +{ + struct lfds700_freelist_element + *fe; + + struct lfds700_misc_prng_state + ps; + + struct test_element + *te; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + while( lfds700_freelist_pop(ts->fs, &fe, &ps) ) + { + te = LFDS700_FREELIST_GET_VALUE_FROM_ELEMENT( *fe ); + te->popped_flag = RAISED; + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_popping_and_pushing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_popping_and_pushing.c new file mode 100644 index 0000000000..8c411151d3 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_popping_and_pushing.c @@ -0,0 +1,319 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_element; + +struct test_state +{ + struct lfds700_freelist_state + fs_thread_local, + *fs; + + lfds700_pal_uint_t + number_elements; + + struct test_element + *fs_thread_local_te_array; +}; + +struct test_element +{ + struct lfds700_freelist_element + fe, + thread_local_fe; + + lfds700_pal_uint_t + datum; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping_and_pushing_start_popping( void *util_thread_starter_thread_state ); +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping_and_pushing_start_pushing( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_freelist_popping_and_pushing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs; + + lfds700_pal_uint_t + loop, + number_elements, + number_logical_processors, + subloop; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_freelist_state + fs; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te_array; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we have two threads per CPU + the threads loop for ten seconds + the first thread pushes 10000 elements then pops 10000 elements + the second thread pops 10000 elements then pushes 10000 elements + all pushes and pops go onto the single main freelist + with a per-thread local freelist to store the pops + + after time is up, all threads push what they have remaining onto + the main freelist + + we then validate the main freelist + */ + + internal_display_test_name( "Popping and pushing (%d seconds)", TEST_DURATION_IN_SECONDS ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors * 2 ); + + lfds700_freelist_init_valid_on_current_logical_core( &fs, NULL ); + + // TRD : we allocate half the total elements here, and half again later, which is why *2 above, but not here + te_array = util_aligned_malloc( sizeof(struct test_element) * number_elements * number_logical_processors, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + // TRD : initial elements in the main freelist so the popping threads can start immediately + for( loop = 0 ; loop < number_elements * number_logical_processors ; loop++ ) + { + (te_array+loop)->datum = loop; + LFDS700_FREELIST_SET_VALUE_IN_ELEMENT( (te_array+loop)->fe, te_array+loop ); + lfds700_freelist_push( &fs, &(te_array+loop)->fe, &ps ); + } + + ts = util_aligned_malloc( sizeof(struct test_state) * number_logical_processors * 2, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + // TRD : first set of threads (poppers) + (ts+loop)->fs = &fs; + (ts+loop)->number_elements = number_elements; + lfds700_freelist_init_valid_on_current_logical_core( &(ts+loop)->fs_thread_local, NULL ); + + // TRD : second set of threads (pushers - who need elements in their per-thread freelists) + (ts+loop+number_logical_processors)->fs = &fs; + (ts+loop+number_logical_processors)->number_elements = number_elements; + lfds700_freelist_init_valid_on_current_logical_core( &(ts+loop+number_logical_processors)->fs_thread_local, NULL ); + + // TRD : fill the pushing thread freelists + (ts+loop+number_logical_processors)->fs_thread_local_te_array = util_aligned_malloc( sizeof(struct test_element) * number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( subloop = 0 ; subloop < number_elements ; subloop++ ) + { + ((ts+loop+number_logical_processors)->fs_thread_local_te_array+subloop)->datum = loop; + LFDS700_FREELIST_SET_VALUE_IN_ELEMENT( ((ts+loop+number_logical_processors)->fs_thread_local_te_array+subloop)->thread_local_fe, (ts+loop+number_logical_processors)->fs_thread_local_te_array+subloop ); + lfds700_freelist_push( &(ts+loop+number_logical_processors)->fs_thread_local, &((ts+loop+number_logical_processors)->fs_thread_local_te_array+subloop)->thread_local_fe, &ps ); + } + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors * 2 ); + + util_thread_starter_new( &tts, number_logical_processors * 2 ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_popping_and_pushing_start_popping, ts+loop ); + util_thread_starter_start( tts, &thread_handles[loop+number_logical_processors], loop+number_logical_processors, lp, thread_popping_and_pushing_start_pushing, ts+loop+number_logical_processors ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors * 2 ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + vi.min_elements = vi.max_elements = number_elements * number_logical_processors * 2; + + lfds700_freelist_query( &fs, LFDS700_FREELIST_QUERY_SINGLETHREADED_VALIDATE, (void *) &vi, (void *) &dvs ); + + lfds700_freelist_cleanup( &fs, NULL ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + lfds700_freelist_cleanup( &(ts+loop)->fs_thread_local, NULL ); + lfds700_freelist_cleanup( &(ts+loop+number_logical_processors)->fs_thread_local, NULL ); + util_aligned_free( (ts+loop+number_logical_processors)->fs_thread_local_te_array ); + } + + util_aligned_free( ts ); + + util_aligned_free( te_array ); + + // TRD : print the test result + internal_display_test_result( 1, "freelist", dvs ); + + return; +} + + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping_and_pushing_start_popping( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + count; + + struct lfds700_freelist_element + *fe; + + struct lfds700_misc_prng_state + ps; + + struct util_thread_starter_thread_state + *tsts; + + struct test_state + *ts; + + time_t + start_time; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + start_time = time( NULL ); + + while( time(NULL) < start_time + TEST_DURATION_IN_SECONDS ) + { + count = 0; + + while( count < ts->number_elements ) + if( lfds700_freelist_pop(ts->fs, &fe, &ps) ) + { + // TRD : we do nothing with the test data, so there'ss no GET or SET here + lfds700_freelist_push( &ts->fs_thread_local, fe, &ps ); + count++; + } + + // TRD : return our local freelist to the main freelist + while( lfds700_freelist_pop(&ts->fs_thread_local, &fe, &ps) ) + lfds700_freelist_push( ts->fs, fe, &ps ); + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping_and_pushing_start_pushing( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + count; + + struct lfds700_freelist_element + *fe; + + struct lfds700_misc_prng_state + ps; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + time_t + start_time; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + start_time = time( NULL ); + + while( time(NULL) < start_time + TEST_DURATION_IN_SECONDS ) + { + // TRD : return our local freelist to the main freelist + while( lfds700_freelist_pop(&ts->fs_thread_local, &fe, &ps) ) + lfds700_freelist_push( ts->fs, fe, &ps ); + + count = 0; + + while( count < ts->number_elements ) + if( lfds700_freelist_pop(ts->fs, &fe, &ps) ) + { + lfds700_freelist_push( &ts->fs_thread_local, fe, &ps ); + count++; + } + } + + // TRD : now push whatever we have in our local freelist + while( lfds700_freelist_pop(&ts->fs_thread_local, &fe, &ps) ) + lfds700_freelist_push( ts->fs, fe, &ps ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_pushing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_pushing.c new file mode 100644 index 0000000000..0e756c5e2d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_pushing.c @@ -0,0 +1,246 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + lfds700_pal_uint_t + number_elements, + thread_number; + + struct lfds700_freelist_state + *fs; + + struct test_element + *te_array; +}; + +struct test_element +{ + struct lfds700_freelist_element + fe; + + lfds700_pal_uint_t + datum, + thread_number; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_pushing( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_freelist_pushing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_elements, + number_logical_processors, + *per_thread_counters; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_freelist_element + *fe; + + struct lfds700_freelist_state + fs; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te, + *first_te = NULL; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we create an empty freelist + + we then create one thread per CPU, where each thread + pushes 100,000 elements each as quickly as possible to the freelist + + the data pushed is a counter and a thread ID + + the threads exit when the freelist is full + + we then validate the freelist; + + checking that the counts increment on a per unique ID basis + and that the number of elements we pop equals 100,000 per thread + (since each element has an incrementing counter which is + unique on a per unique ID basis, we can know we didn't lose + any elements) + */ + + internal_display_test_name( "Pushing" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors ); + + // TRD : the main freelist + lfds700_freelist_init_valid_on_current_logical_core( &fs, NULL ); + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->fs = &fs; + (ts+loop)->thread_number = loop; + (ts+loop)->number_elements = number_elements; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_pushing, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + per_thread_counters = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + *(per_thread_counters+loop) = number_elements - 1; + + vi.min_elements = vi.max_elements = number_elements * number_logical_processors; + + lfds700_freelist_query( &fs, LFDS700_STACK_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + while( dvs == LFDS700_MISC_VALIDITY_VALID and lfds700_freelist_pop(&fs, &fe, &ps) ) + { + te = LFDS700_FREELIST_GET_VALUE_FROM_ELEMENT( *fe ); + + if( first_te == NULL ) + first_te = te; + + if( te->thread_number >= number_logical_processors ) + { + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + break; + } + + if( te->datum > per_thread_counters[te->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + + if( te->datum < per_thread_counters[te->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( te->datum == per_thread_counters[te->thread_number] ) + per_thread_counters[te->thread_number]--; + } + + // TRD : clean up + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + util_aligned_free( (ts+loop)->te_array ); + + free( per_thread_counters ); + + free( ts ); + + lfds700_freelist_cleanup( &fs, NULL ); + + // TRD : print the test result + internal_display_test_result( 1, "freelist", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_pushing( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + loop; + + struct lfds700_misc_prng_state + ps; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_BARRIER_LOAD; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + ts->te_array = util_aligned_malloc( sizeof(struct test_element) * ts->number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < ts->number_elements ; loop++ ) + { + (ts->te_array+loop)->thread_number = ts->thread_number; + (ts->te_array+loop)->datum = loop; + } + + util_thread_starter_ready_and_wait( tsts ); + + for( loop = 0 ; loop < ts->number_elements ; loop++ ) + { + LFDS700_FREELIST_SET_VALUE_IN_ELEMENT( (ts->te_array+loop)->fe, ts->te_array+loop ); + lfds700_freelist_push( ts->fs, &(ts->te_array+loop)->fe, &ps ); + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_rapid_popping_and_pushing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_rapid_popping_and_pushing.c new file mode 100644 index 0000000000..15a0f9fd69 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_freelist_rapid_popping_and_pushing.c @@ -0,0 +1,216 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + struct lfds700_freelist_state + *fs; +}; + +struct test_element +{ + struct lfds700_freelist_element + fe; + + lfds700_pal_uint_t + datum; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_rapid_popping_and_pushing( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_freelist_rapid_popping_and_pushing( struct lfds700_list_asu_state *list_of_logical_processors ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_logical_processors; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_freelist_state + fs; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_misc_validation_info + vi = { 0, 0 }; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te_array; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + + /* TRD : in these tests there is a fundamental antagonism between + how much checking/memory clean up that we do and the + likelyhood of collisions between threads in their lock-free + operations + + the lock-free operations are very quick; if we do anything + much at all between operations, we greatly reduce the chance + of threads colliding + + so we have some tests which do enough checking/clean up that + they can tell the freelist is valid and don't leak memory + and here, this test now is one of those which does minimal + checking - in fact, the nature of the test is that you can't + do any real checking - but goes very quickly + + what we do is create a small freelist and then run one thread + per CPU, where each thread simply pushes and then immediately + pops + + the test runs for ten seconds + + after the test is done, the only check we do is to traverse + the freelist, checking for loops and ensuring the number of + elements is correct + */ + + internal_display_test_name( "Rapid popping and pushing (10 seconds)" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + lfds700_freelist_init_valid_on_current_logical_core( &fs, NULL ); + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + (ts+loop)->fs = &fs; + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + // TRD : we need one element per thread + te_array = util_aligned_malloc( sizeof(struct test_element) * number_logical_processors, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + LFDS700_FREELIST_SET_VALUE_IN_ELEMENT( (te_array+loop)->fe, te_array+loop ); + lfds700_freelist_push( &fs, &(te_array+loop)->fe, &ps ); + } + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_rapid_popping_and_pushing, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + vi.min_elements = vi.max_elements = number_logical_processors; + + lfds700_freelist_query( &fs, LFDS700_STACK_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + lfds700_freelist_cleanup( &fs, NULL ); + + util_aligned_free( te_array ); + + free( ts ); + + // TRD : print the test result + internal_display_test_result( 1, "freelist", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_rapid_popping_and_pushing( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + time_loop = 0; + + struct lfds700_freelist_element + *fe; + + struct lfds700_misc_prng_state + ps; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + time_t + current_time, + start_time; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + current_time = start_time = time( NULL ); + + while( current_time < start_time + TEST_DURATION_IN_SECONDS ) + { + lfds700_freelist_pop( ts->fs, &fe, &ps ); + lfds700_freelist_push( ts->fs, fe, &ps ); + + if( time_loop++ == TIME_LOOP_COUNT ) + { + time_loop = 0; + time( ¤t_time ); + } + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly.c new file mode 100644 index 0000000000..eeb98727c5 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly.c @@ -0,0 +1,33 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_hash_a( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + if( LFDS700_MISC_ATOMIC_SUPPORT_CAS ) + { + printf( "\n" + "Hash (add-only) Tests\n" + "=====================\n" ); + + test_lfds700_hash_a_alignment(); + test_lfds700_hash_a_fail_and_overwrite_on_existing_key(); + test_lfds700_hash_a_random_adds_fail_on_existing( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_hash_a_random_adds_overwrite_on_existing( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_hash_a_iterate(); + } + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_alignment.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_alignment.c new file mode 100644 index 0000000000..2d0a0a5b8e --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_alignment.c @@ -0,0 +1,40 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_hash_a_alignment() +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + /* TRD : these are compile time checks + but we do them here because this is a test programme + and it should indicate issues to users when it is *run*, + not when it is compiled, because a compile error normally + indicates a problem with the code itself and so is misleading + */ + + internal_display_test_name( "Alignment" ); + + + + // TRD : struct lfds700_hash_a_element + if( offsetof(struct lfds700_hash_a_element,value) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + + + // TRD : print the test result + internal_display_test_result( 1, "freelist", dvs ); + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_iterate.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_iterate.c new file mode 100644 index 0000000000..cf4899e31b --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_iterate.c @@ -0,0 +1,224 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_element +{ + struct lfds700_btree_au_element + baue; + + lfds700_pal_uint_t + datum; +}; + +struct test_state +{ + enum lfds700_misc_flag + error_flag; + + struct lfds700_hash_a_state + *has; + + struct test_element + *element_array; +}; + +/***** private prototypes *****/ +static int key_compare_function( void const *new_key, void const *existing_key ); +static void key_hash_function( void const *key, lfds700_pal_uint_t *hash ); + + + + + +/****************************************************************************/ +void test_lfds700_hash_a_iterate( void ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + *counter_array, + loop; + + struct lfds700_hash_a_element + *hae; + + struct lfds700_hash_a_iterate + hai; + + struct lfds700_hash_a_state + has; + + struct lfds700_hash_a_element + *element_array; + + struct lfds700_btree_au_state + *baus; + + struct lfds700_misc_prng_state + ps; + + void + *value; + + /* TRD : single-threaded test + we create a single hash_a + we populate with 1000 elements + where key and value is the number of the element (e.g. 0 to 999) + we then allocate 1000 counters, init to 0 + we then iterate + we increment each element as we see it in the iterate + if any are missing or seen more than once, problemo! + + we do this once with a table of 10, to ensure each table has (or almost certainly has) something in + and then a second tiem with a table of 10000, to ensure some empty tables exist + */ + + internal_display_test_name( "Iterate" ); + + lfds700_misc_prng_init( &ps ); + + element_array = util_aligned_malloc( sizeof(struct lfds700_hash_a_element) * 1000, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + counter_array = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * 1000 ); + + // TRD : first time around + baus = util_aligned_malloc( sizeof(struct lfds700_btree_au_state) * 10, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lfds700_hash_a_init_valid_on_current_logical_core( &has, baus, 10, key_compare_function, key_hash_function, LFDS700_HASH_A_EXISTING_KEY_FAIL, NULL ); + + for( loop = 0 ; loop < 1000 ; loop++ ) + { + LFDS700_HASH_A_SET_KEY_IN_ELEMENT( *(element_array+loop), loop ); + LFDS700_HASH_A_SET_VALUE_IN_ELEMENT( *(element_array+loop), loop ); + lfds700_hash_a_insert( &has, element_array+loop, NULL, &ps ); + } + + for( loop = 0 ; loop < 1000 ; loop++ ) + *(counter_array+loop) = 0; + + lfds700_hash_a_iterate_init( &has, &hai ); + + while( dvs == LFDS700_MISC_VALIDITY_VALID and lfds700_hash_a_iterate(&hai, &hae) ) + { + value = LFDS700_HASH_A_GET_VALUE_FROM_ELEMENT( *hae ); + ( *(counter_array + (lfds700_pal_uint_t) value) )++; + } + + if( dvs == LFDS700_MISC_VALIDITY_VALID ) + for( loop = 0 ; loop < 1000 ; loop++ ) + { + if( *(counter_array+loop) > 1 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + + if( *(counter_array+loop) == 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + } + + lfds700_hash_a_cleanup( &has, NULL ); + + util_aligned_free( baus ); + + // TRD : second time around + if( dvs == LFDS700_MISC_VALIDITY_VALID ) + { + baus = util_aligned_malloc( sizeof(struct lfds700_btree_au_state) * 10000, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lfds700_hash_a_init_valid_on_current_logical_core( &has, baus, 10000, key_compare_function, key_hash_function, LFDS700_HASH_A_EXISTING_KEY_FAIL, NULL ); + + for( loop = 0 ; loop < 1000 ; loop++ ) + { + LFDS700_HASH_A_SET_KEY_IN_ELEMENT( *(element_array+loop), loop ); + LFDS700_HASH_A_SET_VALUE_IN_ELEMENT( *(element_array+loop), loop ); + lfds700_hash_a_insert( &has, element_array+loop, NULL, &ps ); + } + + for( loop = 0 ; loop < 1000 ; loop++ ) + *(counter_array+loop) = 0; + + lfds700_hash_a_iterate_init( &has, &hai ); + + while( dvs == LFDS700_MISC_VALIDITY_VALID and lfds700_hash_a_iterate(&hai, &hae) ) + { + value = LFDS700_HASH_A_GET_VALUE_FROM_ELEMENT( *hae ); + ( *(counter_array + (lfds700_pal_uint_t) value ) )++; + } + + if( dvs == LFDS700_MISC_VALIDITY_VALID ) + for( loop = 0 ; loop < 1000 ; loop++ ) + { + if( *(counter_array+loop) > 1 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + + if( *(counter_array+loop) == 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + } + + lfds700_hash_a_cleanup( &has, NULL ); + + util_aligned_free( baus ); + } + + // TRD : cleanup + util_aligned_free( element_array ); + free( counter_array ); + + // TRD : print the test result + internal_display_test_result( 1, "hash_a", dvs ); + + return; +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static int key_compare_function( void const *new_key, void const *existing_key ) +{ + int + cr = 0; + + // TRD : new_key can be NULL (i.e. 0) + // TRD : existing_key can be NULL (i.e. 0) + + if( (lfds700_pal_uint_t) new_key < (lfds700_pal_uint_t) existing_key ) + cr = -1; + + if( (lfds700_pal_uint_t) new_key > (lfds700_pal_uint_t) existing_key ) + cr = 1; + + return( cr ); +} + +#pragma warning( default : 4100 ) + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static void key_hash_function( void const *key, lfds700_pal_uint_t *hash ) +{ + // TRD : key can be NULL + assert( hash != NULL ); + + *hash = 0; + + /* TRD : this function iterates over the user data + and we are using the void pointer AS user data + so here we need to pass in the addy of value + */ + + LFDS700_HASH_A_32BIT_HASH_FUNCTION( (void *) &key, sizeof(lfds700_pal_uint_t), *hash ); + + return; +} + +#pragma warning( default : 4100 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_random_adds_fail.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_random_adds_fail.c new file mode 100644 index 0000000000..5d36e47a31 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_random_adds_fail.c @@ -0,0 +1,314 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_element +{ + struct lfds700_hash_a_element + hae; + + lfds700_pal_uint_t + datum, + key; +}; + +struct test_state +{ + enum flag + error_flag; + + lfds700_pal_uint_t + number_elements_per_thread; + + struct lfds700_hash_a_state + *has; + + struct test_element + *element_array; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_adding( void *util_thread_starter_thread_state ); +static int key_compare_function( void const *new_key, void const *existing_key ); +static void key_hash_function( void const *key, lfds700_pal_uint_t *hash ); + + + + + +/****************************************************************************/ +void test_lfds700_hash_a_random_adds_fail_on_existing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_elements_per_thread, + number_elements_total, + number_logical_processors, + offset, + temp, + value; + + struct lfds700_hash_a_element + *hae; + + struct lfds700_hash_a_state + has; + + struct lfds700_list_asu_element + *lasue = NULL; + + struct lfds700_btree_au_state + *baus; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *element_array; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we create a single hash_a + we generate 100k elements per thread (with one thread per logical processor) in an array + each element is unique + we randomly sort the elements + then each thread loops, adds those elements into the hash_a + we check that each datum inserts okay - failure will occur on non-unique data, i.e. two identical keys + we should have no failures + we then call the hash_a validation function + then using the hash_a get() we check all the elements we added are present + */ + + internal_display_test_name( "Random adds and get (fail on existing key)" ); + + lfds700_misc_prng_init( &ps ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + baus = util_aligned_malloc( sizeof(struct lfds700_btree_au_state) * 1000, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lfds700_hash_a_init_valid_on_current_logical_core( &has, baus, 1000, key_compare_function, key_hash_function, LFDS700_HASH_A_EXISTING_KEY_FAIL, NULL ); + + number_elements_per_thread = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors ); + number_elements_total = number_elements_per_thread * number_logical_processors; + + // TRD : created an ordered list of unique numbers + element_array = util_aligned_malloc( sizeof(struct test_element) * number_elements_total, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_elements_total ; loop++ ) + { + (element_array+loop)->key = loop; + // TRD : + number_elements just to make it different to the key + (element_array+loop)->datum = loop + number_elements_total; + } + + for( loop = 0 ; loop < number_elements_total ; loop++ ) + { + offset = LFDS700_MISC_PRNG_GENERATE( &ps ); + offset %= number_elements_total; + temp = (element_array + offset)->key; + (element_array + offset)->key = (element_array + loop)->key; + (element_array + loop)->key = temp; + } + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->has = &has; + (ts+loop)->element_array = element_array + number_elements_per_thread*loop; + (ts+loop)->error_flag = LOWERED; + (ts+loop)->number_elements_per_thread = number_elements_per_thread; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_adding, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + // TRD : now for validation + vi.min_elements = vi.max_elements = number_elements_total; + lfds700_hash_a_query( &has, LFDS700_HASH_A_QUERY_SINGLETHREADED_VALIDATE, (void *) &vi, (void *) &dvs ); + + /* TRD : now we attempt to lfds700_hash_a_get_by_key() for every element in number_array + any failure to find is an error + we also check we've obtained the correct element + */ + + for( loop = 0 ; dvs == LFDS700_MISC_VALIDITY_VALID and loop < number_elements_total ; loop++ ) + if( 0 == lfds700_hash_a_get_by_key(&has, (void *) (ts->element_array+loop)->key, &hae) ) + dvs = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + else + { + value = (lfds700_pal_uint_t) LFDS700_HASH_A_GET_VALUE_FROM_ELEMENT( *hae ); + if( (ts->element_array+loop)->datum != value ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + } + + // TRD : just check error_flags weren't raised + if( dvs == LFDS700_MISC_VALIDITY_VALID ) + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + if( (ts+loop)->error_flag == RAISED ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + // TRD : cleanup + lfds700_hash_a_cleanup( &has, NULL ); + + util_aligned_free( baus ); + + free( ts ); + + util_aligned_free( element_array ); + + // TRD : print the test result + internal_display_test_result( 1, "hash_a", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_adding( void *util_thread_starter_thread_state ) +{ + enum lfds700_hash_a_insert_result + apr; + + lfds700_pal_uint_t + index = 0; + + struct test_state + *ts; + + struct lfds700_misc_prng_state + ps; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + while( index < ts->number_elements_per_thread ) + { + LFDS700_HASH_A_SET_KEY_IN_ELEMENT( (ts->element_array+index)->hae, (ts->element_array+index)->key ); + LFDS700_HASH_A_SET_VALUE_IN_ELEMENT( (ts->element_array+index)->hae, (ts->element_array+index)->datum ); + apr = lfds700_hash_a_insert( ts->has, &(ts->element_array+index)->hae, NULL, &ps ); + + if( apr == LFDS700_HASH_A_PUT_RESULT_FAILURE_EXISTING_KEY ) + ts->error_flag = RAISED; + + index++; + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static int key_compare_function( void const *new_key, void const *existing_key ) +{ + int + cr = 0; + + // TRD : new_key can be NULL (i.e. 0) + // TRD : existing_key can be NULL (i.e. 0) + + if( (lfds700_pal_uint_t) new_key < (lfds700_pal_uint_t) existing_key ) + cr = -1; + + if( (lfds700_pal_uint_t) new_key > (lfds700_pal_uint_t) existing_key ) + cr = 1; + + return( cr ); +} + +#pragma warning( default : 4100 ) + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static void key_hash_function( void const *key, lfds700_pal_uint_t *hash ) +{ + // TRD : key can be NULL + assert( hash != NULL ); + + *hash = 0; + + /* TRD : this function iterates over the user data + and we are using the void pointer *as* key data + so here we need to pass in the addy of key + */ + + LFDS700_HASH_A_32BIT_HASH_FUNCTION( (void *) &key, sizeof(lfds700_pal_uint_t), *hash ); + + return; +} + +#pragma warning( default : 4100 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_random_adds_fail_and_overwrite.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_random_adds_fail_and_overwrite.c new file mode 100644 index 0000000000..cc18900273 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_random_adds_fail_and_overwrite.c @@ -0,0 +1,137 @@ +/***** includes *****/ +#include "internal.h" + +/***** private prototypes *****/ +static int key_compare_function( void const *new_value, void const *value_in_tree ); +static void key_hash_function( void const *key, lfds700_pal_uint_t *hash ); + + + + + +/****************************************************************************/ +void test_lfds700_hash_a_fail_and_overwrite_on_existing_key() +{ + enum lfds700_hash_a_insert_result + apr; + + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + struct lfds700_hash_a_element + hae_one, + hae_two; + + struct lfds700_hash_a_state + has; + + struct lfds700_btree_au_state + *baus; + + struct lfds700_misc_prng_state + ps; + + internal_display_test_name( "Fail and overwrite on existing key" ); + + lfds700_misc_prng_init( &ps ); + + baus = util_aligned_malloc( sizeof(struct lfds700_btree_au_state) * 10, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + // TRD : fail on overwrite + lfds700_hash_a_init_valid_on_current_logical_core( &has, baus, 10, key_compare_function, key_hash_function, LFDS700_HASH_A_EXISTING_KEY_FAIL, NULL ); + + LFDS700_HASH_A_SET_KEY_IN_ELEMENT( hae_one, 1 ); + LFDS700_HASH_A_SET_VALUE_IN_ELEMENT( hae_one, 0 ); + apr = lfds700_hash_a_insert( &has, &hae_one, NULL, &ps ); + + if( apr != LFDS700_HASH_A_PUT_RESULT_SUCCESS ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + LFDS700_HASH_A_SET_KEY_IN_ELEMENT( hae_two, 1 ); + LFDS700_HASH_A_SET_VALUE_IN_ELEMENT( hae_two, 1 ); + apr = lfds700_hash_a_insert( &has, &hae_two, NULL, &ps ); + + if( apr != LFDS700_HASH_A_PUT_RESULT_FAILURE_EXISTING_KEY ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + lfds700_hash_a_cleanup( &has, NULL ); + + // TRD : success on overwrite + lfds700_hash_a_init_valid_on_current_logical_core( &has, baus, 10, key_compare_function, key_hash_function, LFDS700_HASH_A_EXISTING_KEY_OVERWRITE, NULL ); + + LFDS700_HASH_A_SET_KEY_IN_ELEMENT( hae_one, 1 ); + LFDS700_HASH_A_SET_VALUE_IN_ELEMENT( hae_one, 1 ); + apr = lfds700_hash_a_insert( &has, &hae_one, NULL, &ps ); + + if( apr != LFDS700_HASH_A_PUT_RESULT_SUCCESS ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + LFDS700_HASH_A_SET_KEY_IN_ELEMENT( hae_two, 1 ); + LFDS700_HASH_A_SET_VALUE_IN_ELEMENT( hae_two, 1 ); + apr = lfds700_hash_a_insert( &has, &hae_two, NULL, &ps ); + + if( apr != LFDS700_HASH_A_PUT_RESULT_SUCCESS_OVERWRITE ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + lfds700_hash_a_cleanup( &has, NULL ); + + util_aligned_free( baus ); + + // TRD : print the test result + internal_display_test_result( 1, "hash_a", dvs ); + + return; +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static int key_compare_function( void const *new_key, void const *key_in_tree ) +{ + int + cr = 0; + + // TRD : key_new can be any value in its range + // TRD : key_in_tree can be any value in its range + + if( (lfds700_pal_uint_t) new_key < (lfds700_pal_uint_t) key_in_tree ) + cr = -1; + + if( (lfds700_pal_uint_t) new_key > (lfds700_pal_uint_t) key_in_tree ) + cr = 1; + + return( cr ); +} + +#pragma warning( default : 4100 ) + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static void key_hash_function( void const *key, lfds700_pal_uint_t *hash ) +{ + // TRD : key can be NULL + assert( hash != NULL ); + + *hash = 0; + + /* TRD : this function iterates over the user data + and we are using the void pointer *as* key data + so here we need to pass in the addy of key + */ + + LFDS700_HASH_A_32BIT_HASH_FUNCTION( (void *) &key, sizeof(lfds700_pal_uint_t), *hash ); + + return; +} + +#pragma warning( default : 4100 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_random_adds_overwrite.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_random_adds_overwrite.c new file mode 100644 index 0000000000..29c5fae865 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_hash_addonly_random_adds_overwrite.c @@ -0,0 +1,388 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_element +{ + struct lfds700_hash_a_element + hae; + + lfds700_pal_uint_t + key; +}; + +struct test_state +{ + lfds700_pal_uint_t + number_elements_per_thread, + overwrite_count; + + struct lfds700_hash_a_state + *has; + + struct test_element + *element_array; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_adding( void *util_thread_starter_thread_state ); +static int key_compare_function( void const *new_key, void const *existing_key ); +static void key_hash_function( void const *key, lfds700_pal_uint_t *hash ); +static int qsort_and_bsearch_key_compare_function( void const *e1, void const *e2 ); + + + + + +/****************************************************************************/ +void test_lfds700_hash_a_random_adds_overwrite_on_existing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + int + rv; + + lfds700_pal_uint_t + actual_sum_overwrite_existing_count, + expected_sum_overwrite_existing_count, + *key_count_array, + loop, + number_elements_per_thread, + number_elements_total, + number_logical_processors, + random_value; + + struct lfds700_hash_a_iterate + hai; + + struct lfds700_hash_a_element + *hae; + + struct lfds700_hash_a_state + has; + + struct lfds700_list_asu_element + *lasue = NULL; + + struct lfds700_btree_au_state + *baus; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *element_array; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + void + *key_pointer, + *key; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we create a single hash_a + we generate n elements per thread + each element contains a key value, which is set to a random value + (we don't use value, so it's just set to 0) + the threads then run, putting + the threads count their number of overwrite hits + once the threads are done, then we + count the number of each key + from this we figure out the min/max element for hash_a validation, so we call validation + we check the sum of overwrites for each thread is what it should be + then using the hash_a get() we check all the elements we expect are present + and then we iterate over the hash_a + checking we see each key once + */ + + internal_display_test_name( "Random adds, get and iterate (overwrite on existing key)" ); + + lfds700_misc_prng_init( &ps ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + baus = util_aligned_malloc( sizeof(struct lfds700_btree_au_state) * 1000, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lfds700_hash_a_init_valid_on_current_logical_core( &has, baus, 1000, key_compare_function, key_hash_function, LFDS700_HASH_A_EXISTING_KEY_OVERWRITE, NULL ); + + // TRD : we divide by 2 beccause we have to allocate a second array of this size later + number_elements_per_thread = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors ) / 2; + number_elements_total = number_elements_per_thread * number_logical_processors; + + // TRD : created an ordered list of unique numbers + element_array = util_aligned_malloc( sizeof(struct test_element) * number_elements_total, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_elements_total ; loop++ ) + { + random_value = LFDS700_MISC_PRNG_GENERATE( &ps ); + (element_array+loop)->key = (lfds700_pal_uint_t) floor( (number_elements_total/2) * ((double) random_value / (double) LFDS700_MISC_PRNG_MAX) ); + } + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->has = &has; + (ts+loop)->element_array = element_array + number_elements_per_thread*loop; + (ts+loop)->overwrite_count = 0; + (ts+loop)->number_elements_per_thread = number_elements_per_thread; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_adding, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + // TRD : now for validation + key_count_array = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_elements_total ); + for( loop = 0 ; loop < number_elements_total ; loop++ ) + *(key_count_array+loop) = 0; + + for( loop = 0 ; loop < number_elements_total ; loop++ ) + ( *(key_count_array + (element_array+loop)->key) )++; + + vi.min_elements = number_elements_total; + + for( loop = 0 ; loop < number_elements_total ; loop++ ) + if( *(key_count_array+loop) == 0 ) + vi.min_elements--; + + vi.max_elements = vi.min_elements; + + lfds700_hash_a_query( &has, LFDS700_HASH_A_QUERY_SINGLETHREADED_VALIDATE, (void *) &vi, (void *) &dvs ); + + expected_sum_overwrite_existing_count = 0; + + for( loop = 0 ; loop < number_elements_total ; loop++ ) + if( *(key_count_array+loop) != 0 ) + expected_sum_overwrite_existing_count += *(key_count_array+loop) - 1; + + actual_sum_overwrite_existing_count = 0; + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + actual_sum_overwrite_existing_count += (ts+loop)->overwrite_count; + + if( expected_sum_overwrite_existing_count != actual_sum_overwrite_existing_count ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + // TRD : now loop over the expected array and check we can get() every element + for( loop = 0 ; loop < number_elements_total ; loop++ ) + if( *(key_count_array+loop) > 0 ) + { + rv = lfds700_hash_a_get_by_key( &has, (void *) loop, &hae ); + + if( rv != 1 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + } + + /* TRD : now iterate, checking we find every element and no others + to do this in a timely manner, we need to qsort() the key values + and use bsearch() to check for items in the array + */ + + for( loop = 0 ; loop < number_elements_total ; loop++ ) + if( *(key_count_array+loop) != 0 ) + *(key_count_array+loop) = loop; + else + *(key_count_array+loop) = 0; + + qsort( key_count_array, number_elements_total, sizeof(lfds700_pal_uint_t), qsort_and_bsearch_key_compare_function ); + + lfds700_hash_a_iterate_init( &has, &hai ); + + while( dvs == LFDS700_MISC_VALIDITY_VALID and lfds700_hash_a_iterate(&hai, &hae) ) + { + key = LFDS700_HASH_A_GET_KEY_FROM_ELEMENT( *hae ); + + key_pointer = bsearch( &key, key_count_array, number_elements_total, sizeof(lfds700_pal_uint_t), qsort_and_bsearch_key_compare_function ); + + if( key_pointer == NULL ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + } + + // TRD : cleanup + lfds700_hash_a_cleanup( &has, NULL ); + + util_aligned_free( baus ); + + free( ts ); + + util_aligned_free( element_array ); + + free( key_count_array ); + + // TRD : print the test result + internal_display_test_result( 1, "hash_a", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_adding( void *util_thread_starter_thread_state ) +{ + enum lfds700_hash_a_insert_result + apr; + + lfds700_pal_uint_t + index = 0; + + struct test_state + *ts; + + struct lfds700_misc_prng_state + ps; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + while( index < ts->number_elements_per_thread ) + { + LFDS700_HASH_A_SET_KEY_IN_ELEMENT( (ts->element_array+index)->hae, (ts->element_array+index)->key ); + LFDS700_HASH_A_SET_VALUE_IN_ELEMENT( (ts->element_array+index)->hae, 0 ); + apr = lfds700_hash_a_insert( ts->has, &(ts->element_array+index)->hae, NULL, &ps ); + + if( apr == LFDS700_HASH_A_PUT_RESULT_SUCCESS_OVERWRITE ) + ts->overwrite_count++; + + index++; + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static int key_compare_function( void const *new_key, void const *existing_key ) +{ + int + cr = 0; + + // TRD : new_key can be NULL (i.e. 0) + // TRD : existing_key can be NULL (i.e. 0) + + if( (lfds700_pal_uint_t) new_key < (lfds700_pal_uint_t) existing_key ) + cr = -1; + + if( (lfds700_pal_uint_t) new_key > (lfds700_pal_uint_t) existing_key ) + cr = 1; + + return( cr ); +} + +#pragma warning( default : 4100 ) + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static void key_hash_function( void const *key, lfds700_pal_uint_t *hash ) +{ + // TRD : key can be NULL + assert( hash != NULL ); + + *hash = 0; + + /* TRD : this function iterates over the user data + and we are using the void pointer *as* key data + so here we need to pass in the addy of key + */ + + LFDS700_HASH_A_32BIT_HASH_FUNCTION( (void *) &key, sizeof(lfds700_pal_uint_t), *hash ); + + return; +} + +#pragma warning( default : 4100 ) + + + + + +/****************************************************************************/ +static int qsort_and_bsearch_key_compare_function( void const *e1, void const *e2 ) +{ + int + cr = 0; + + lfds700_pal_uint_t + s1, + s2; + + s1 = *(lfds700_pal_uint_t *) e1; + s2 = *(lfds700_pal_uint_t *) e2; + + if( s1 > s2 ) + cr = 1; + + if( s1 < s2 ) + cr = -1; + + return( cr ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked.c new file mode 100644 index 0000000000..5720aa2428 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked.c @@ -0,0 +1,31 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_list_aos( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + if( LFDS700_MISC_ATOMIC_SUPPORT_CAS ) + { + printf( "\n" + "List (add-only, ordered, singly-linked) Tests\n" + "=============================================\n" ); + + test_lfds700_list_aos_alignment(); + test_lfds700_list_aos_new_ordered( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_list_aos_new_ordered_with_cursor( list_of_logical_processors, memory_in_megabytes ); + } + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked_alignment.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked_alignment.c new file mode 100644 index 0000000000..7726346366 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked_alignment.c @@ -0,0 +1,58 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_list_aos_alignment() +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + /* TRD : these are compile time checks + but we do them here because this is a test programme + and it should indicate issues to users when it is *run*, + not when it is compiled, because a compile error normally + indicates a problem with the code itself and so is misleading + */ + + internal_display_test_name( "Alignment" ); + + + + // TRD : struct lfds700_list_aos_element + if( offsetof(struct lfds700_list_aos_element,next) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_list_aos_element,value) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_list_aos_element,key) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + + + // TRD : struct lfds700_list_asu_state + if( offsetof(struct lfds700_list_aos_state,start) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_list_aos_state,dummy_element) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_list_aos_state,key_compare_function) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + + + // TRD : print the test result + internal_display_test_result( 1, "list_aos", dvs ); + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked_new_ordered.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked_new_ordered.c new file mode 100644 index 0000000000..3a392b33bd --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked_new_ordered.c @@ -0,0 +1,278 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_element +{ + struct lfds700_list_aos_element + laose; + + lfds700_pal_uint_t + element_number, + thread_number; +}; + +struct test_state +{ + lfds700_pal_uint_t + number_elements_per_thread; + + struct lfds700_list_aos_state + *laoss; + + struct test_element + *element_array; +}; + +/***** private prototypes *****/ +static int new_ordered_compare_function( void const *value_new, void const *value_in_list ); +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION new_ordered_thread( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_list_aos_new_ordered( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + expected_element_number, + number_elements_per_thread, + number_elements_total, + number_logical_processors, + offset, + temp; + + struct lfds700_list_aos_element + *laose = NULL; + + struct lfds700_list_asu_element + *lasue = NULL; + + struct lfds700_list_aos_state + laoss; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct test_element + *element_array, + *element; + + struct test_state + *ts; + + struct util_thread_starter_state + *tts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : run one thread per logical processor + we have a single array of 10k elements per thread + this is set to be randomly ordered (but with contigious numbers from 0 to n) + we give 10k to each thread (a pointer into the array at the correct point) + which then loops through that array + calling lfds700_list_aos_insert_element_by_position( LFDS700_LIST_AOS_POSITION_ORDERED ) + verification should show list is sorted + */ + + internal_display_test_name( "New ordered" ); + + lfds700_misc_prng_init( &ps ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_list_aos_init_valid_on_current_logical_core( &laoss, new_ordered_compare_function, LFDS700_LIST_AOS_INSERT_RESULT_FAILURE_EXISTING_KEY, NULL ); + + /* TRD : create randomly ordered number array with unique elements + + unique isn't necessary - the list will sort anyway - but + it permits slightly better validation + */ + + number_elements_per_thread = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors ); + + // TRD : or the test takes a looooooong time... + if( number_elements_per_thread > 10000 ) + number_elements_per_thread = 10000; + + number_elements_total = number_elements_per_thread * number_logical_processors; + + element_array = util_aligned_malloc( sizeof(struct test_element) * number_elements_total, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_elements_total ; loop++ ) + (element_array+loop)->element_number = loop; + + for( loop = 0 ; loop < number_elements_total ; loop++ ) + { + offset = LFDS700_MISC_PRNG_GENERATE( &ps ); + offset %= number_elements_total; + temp = (element_array + offset)->element_number; + (element_array + offset)->element_number = (element_array + loop)->element_number; + (element_array + loop)->element_number = temp; + } + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->laoss = &laoss; + (ts+loop)->element_array = element_array + (loop*number_elements_per_thread); + (ts+loop)->number_elements_per_thread = number_elements_per_thread; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, new_ordered_thread, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + free( ts ); + + /* TRD : validate the resultant list + iterate over the list + we expect to find the list is sorted, + which means that element_number will + increment from zero + */ + + LFDS700_MISC_BARRIER_LOAD; + + vi.min_elements = vi.max_elements = number_elements_total; + + lfds700_list_aos_query( &laoss, LFDS700_LIST_AOS_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + if( dvs == LFDS700_MISC_VALIDITY_VALID ) + { + expected_element_number = 0; + + // TRD : traverse the list and check combined_data_array matches + while( dvs == LFDS700_MISC_VALIDITY_VALID and LFDS700_LIST_AOS_GET_START_AND_THEN_NEXT(laoss, laose) ) + { + element = LFDS700_LIST_AOS_GET_VALUE_FROM_ELEMENT( *laose ); + + if( element->element_number != expected_element_number++ ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + } + } + + lfds700_list_aos_cleanup( &laoss, NULL ); + + util_aligned_free( element_array ); + + internal_display_test_result( 1, "list_aos", dvs ); + + return; +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static int new_ordered_compare_function( void const *value_new, void const *value_in_list ) +{ + int + cr = 0; + + struct test_element + *e1, + *e2; + + // TRD : value_new can be any value in its range + // TRD : value_in_list can be any value in its range + + e1 = (struct test_element *) value_new; + e2 = (struct test_element *) value_in_list; + + if( e1->element_number < e2->element_number ) + cr = -1; + + if( e1->element_number > e2->element_number ) + cr = 1; + + return( cr ); +} + +#pragma warning( default : 4100 ) + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION new_ordered_thread( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + loop; + + struct lfds700_misc_prng_state + ps; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + for( loop = 0 ; loop < ts->number_elements_per_thread ; loop++ ) + { + LFDS700_LIST_AOS_SET_KEY_IN_ELEMENT( (ts->element_array+loop)->laose, ts->element_array+loop ); + LFDS700_LIST_AOS_SET_VALUE_IN_ELEMENT( (ts->element_array+loop)->laose, ts->element_array+loop ); + lfds700_list_aos_insert( ts->laoss, &(ts->element_array+loop)->laose, NULL, &ps ); + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked_new_ordered_with_cursor.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked_new_ordered_with_cursor.c new file mode 100644 index 0000000000..42e0ebc7a5 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_ordered_singlylinked_new_ordered_with_cursor.c @@ -0,0 +1,366 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_element +{ + struct lfds700_list_aos_element + laose; + + lfds700_pal_uint_t + element_number, + thread_number; +}; + +struct test_state +{ + enum flag + error_flag; + + lfds700_pal_uint_t + number_elements_per_thread; + + struct lfds700_list_aos_state + *laoss; + + struct test_element + *element_array; +}; + +/***** private prototypes *****/ +static int new_ordered_with_cursor_compare_function( void const *value_new, void const *value_in_list ); +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION new_ordered_with_cursor_insert_thread( void *util_thread_starter_thread_state ); +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION new_ordered_with_cursor_cursor_thread( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_list_aos_new_ordered_with_cursor( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_elements_per_thread, + number_elements_total, + number_logical_processors, + offset, + temp; + + struct lfds700_list_aos_state + laoss; + + struct lfds700_list_asu_element + *lasue = NULL; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *element_array; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : run two threads per logical processor + + the test runs for 10 seconds + + the first thread loops over a pre-set list of random numbers + continually adding them using ordered insert + + the second thread keeps iterating over the list, checking that + each element is larger than its predecessor + */ + + internal_display_test_name( "New ordered with cursor (%d seconds)", TEST_DURATION_IN_SECONDS ); + + lfds700_misc_prng_init( &ps ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_list_aos_init_valid_on_current_logical_core( &laoss, new_ordered_with_cursor_compare_function, LFDS700_LIST_AOS_INSERT_RESULT_FAILURE_EXISTING_KEY, NULL ); + + /* TRD : create randomly ordered number array with unique elements + + unique isn't necessary - the list will sort anyway - but + it permits slightly better validation + */ + + number_elements_per_thread = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors ); + + // TRD : or the test takes a looooooong time... + if( number_elements_per_thread > 1000 ) + number_elements_per_thread = 1000; + + number_elements_total = number_elements_per_thread * number_logical_processors; + + element_array = util_aligned_malloc( sizeof(struct test_element) * number_elements_total, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_elements_total ; loop++ ) + (element_array+loop)->element_number = loop; + + for( loop = 0 ; loop < number_elements_total ; loop++ ) + { + offset = LFDS700_MISC_PRNG_GENERATE( &ps ); + offset %= number_elements_total; + temp = (element_array + offset)->element_number; + (element_array + offset)->element_number = (element_array + loop)->element_number; + (element_array + loop)->element_number = temp; + } + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors * 2 ); + + // TRD : the insert threads + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->laoss = &laoss; + (ts+loop)->element_array = element_array + number_elements_per_thread*loop; + (ts+loop)->error_flag = LOWERED; + (ts+loop)->number_elements_per_thread = number_elements_per_thread; + } + + // TRD : the cursor threads + for( loop = number_logical_processors ; loop < number_logical_processors * 2 ; loop++ ) + { + (ts+loop)->laoss = &laoss; + (ts+loop)->element_array = NULL; + (ts+loop)->error_flag = LOWERED; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors * 2 ); + + util_thread_starter_new( &tts, number_logical_processors * 2 ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, new_ordered_with_cursor_insert_thread, ts+loop ); + util_thread_starter_start( tts, &thread_handles[loop+number_logical_processors], loop+number_logical_processors, lp, new_ordered_with_cursor_cursor_thread, ts+loop+number_logical_processors ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors * 2 ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + /* TRD : validate the resultant list + + the cursor threads were checking for orderedness + if that failed, they raise their error_flag + so validate the list, then check error_flags + */ + + LFDS700_MISC_BARRIER_LOAD; + + vi.min_elements = vi.max_elements = number_elements_total; + + lfds700_list_aos_query( &laoss, LFDS700_LIST_AOS_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + if( dvs == LFDS700_MISC_VALIDITY_VALID ) + for( loop = number_logical_processors ; loop < number_logical_processors * 2 ; loop++ ) + if( (ts+loop)->error_flag == RAISED ) + dvs = LFDS700_MISC_VALIDITY_INVALID_ORDER; + + lfds700_list_aos_cleanup( &laoss, NULL ); + + util_aligned_free( element_array ); + + free( ts ); + + internal_display_test_result( 1, "list_aos", dvs ); + + return; +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static int new_ordered_with_cursor_compare_function( void const *value_new, void const *value_in_list ) +{ + int + cr = 0; + + struct test_element + *e1, + *e2; + + // TRD : value_new can be any value in its range + // TRD : value_in_list can be any value in its range + + e1 = (struct test_element *) value_new; + e2 = (struct test_element *) value_in_list; + + if( e1->element_number < e2->element_number ) + cr = -1; + + if( e1->element_number > e2->element_number ) + cr = 1; + + return( cr ); +} + +#pragma warning( default : 4100 ) + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION new_ordered_with_cursor_insert_thread( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + loop; + + struct lfds700_misc_prng_state + ps; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_BARRIER_LOAD; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + for( loop = 0 ; loop < ts->number_elements_per_thread ; loop++ ) + { + LFDS700_LIST_AOS_SET_KEY_IN_ELEMENT( (ts->element_array+loop)->laose, ts->element_array+loop ); + LFDS700_LIST_AOS_SET_VALUE_IN_ELEMENT( (ts->element_array+loop)->laose, ts->element_array+loop ); + lfds700_list_aos_insert( ts->laoss, &(ts->element_array+loop)->laose, NULL, &ps ); + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION new_ordered_with_cursor_cursor_thread( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + prev_element_number; + + lfds700_pal_uint_t + time_loop = 0; + + struct lfds700_list_aos_element + *laose; + + struct test_element + *element; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + time_t + current_time, + start_time; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + util_thread_starter_ready_and_wait( tsts ); + + current_time = start_time = time( NULL ); + + while( current_time < start_time + TEST_DURATION_IN_SECONDS ) + { + prev_element_number = 0; + + laose = LFDS700_LIST_AOS_GET_START( *ts->laoss ); + + // TRD : we may get start before any element has been added to the list + if( laose == NULL ) + continue; + + element = LFDS700_LIST_AOS_GET_VALUE_FROM_ELEMENT( *laose ); + + if( element->element_number < prev_element_number ) + ts->error_flag = RAISED; + + prev_element_number = element->element_number; + + laose = LFDS700_LIST_AOS_GET_NEXT( *laose ); + + while( laose != NULL ) + { + element = LFDS700_LIST_AOS_GET_VALUE_FROM_ELEMENT( *laose ); + + if( element->element_number <= prev_element_number ) + ts->error_flag = RAISED; + + prev_element_number = element->element_number; + + laose = LFDS700_LIST_AOS_GET_NEXT( *laose ); + } + + if( time_loop++ == REDUCED_TIME_LOOP_COUNT ) + { + time_loop = 0; + time( ¤t_time ); + } + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered.c new file mode 100644 index 0000000000..37c37f2529 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered.c @@ -0,0 +1,32 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_list_asu( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + if( LFDS700_MISC_ATOMIC_SUPPORT_CAS ) + { + printf( "\n" + "List (add-only, singly-linked, unordered) Tests\n" + "===============================================\n" ); + + test_lfds700_list_asu_alignment(); + test_lfds700_list_asu_new_start( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_list_asu_new_end( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_list_asu_new_after( list_of_logical_processors, memory_in_megabytes ); + } + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_alignment.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_alignment.c new file mode 100644 index 0000000000..43f451d4bf --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_alignment.c @@ -0,0 +1,61 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_list_asu_alignment() +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + /* TRD : these are compile time checks + but we do them here because this is a test programme + and it should indicate issues to users when it is *run*, + not when it is compiled, because a compile error normally + indicates a problem with the code itself and so is misleading + */ + + internal_display_test_name( "Alignment" ); + + + + // TRD : struct lfds700_list_asu_element + if( offsetof(struct lfds700_list_asu_element,next) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_list_asu_element,value) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_list_asu_element,key) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + + + // TRD : struct lfds700_list_asu_state + if( offsetof(struct lfds700_list_asu_state,end) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_list_asu_state,start) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_list_asu_state,dummy_element) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_list_asu_state,key_compare_function) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + + + // TRD : print the test result + internal_display_test_result( 1, "list_asu", dvs ); + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_new_after.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_new_after.c new file mode 100644 index 0000000000..5dcd6954aa --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_new_after.c @@ -0,0 +1,254 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_element +{ + struct lfds700_list_asu_element + lasue; + + lfds700_pal_uint_t + element_number, + thread_number; +}; + +struct test_state +{ + lfds700_pal_uint_t + number_elements; + + struct lfds700_list_asu_state + *lasus; + + struct test_element + *element_array; + + struct lfds700_list_asu_element + *first_element; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION new_after_thread( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_list_asu_new_after( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_elements, + number_logical_processors, + *per_thread_counters, + subloop; + + struct lfds700_list_asu_element + *lasue, + first_element; + + struct lfds700_list_asu_state + lasus; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *element_array, + *element; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : run one thread per logical processor + run for 250k elements + we put a single first element into the list and + each thread loops, calling lfds700_list_asu_new_element_by_position( LFDS700_LIST_ASU_POSITION_AFTER ), + inserting after the single first element + data element contain s thread_number and element_number + verification should show element_number decreasing on a per thread basis + */ + + internal_display_test_name( "New after" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + lfds700_list_asu_init_valid_on_current_logical_core( &lasus, NULL, NULL ); + + LFDS700_LIST_ASU_SET_KEY_IN_ELEMENT( first_element, NULL ); + LFDS700_LIST_ASU_SET_VALUE_IN_ELEMENT( first_element, NULL ); + lfds700_list_asu_insert_at_position( &lasus, &first_element, NULL, LFDS700_LIST_ASU_POSITION_START, &ps ); + + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors ); + + element_array = util_aligned_malloc( sizeof(struct test_element) * number_logical_processors * number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + for( subloop = 0 ; subloop < number_elements ; subloop++ ) + { + (element_array+(loop*number_elements)+subloop)->thread_number = loop; + (element_array+(loop*number_elements)+subloop)->element_number = subloop; + } + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + {\ + (ts+loop)->lasus = &lasus; + (ts+loop)->element_array = element_array + (loop*number_elements); + (ts+loop)->first_element = &first_element; + (ts+loop)->number_elements = number_elements; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, new_after_thread, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + free( ts ); + + /* TRD : validate the resultant list + iterate over each element + we expect to find element numbers increment on a per thread basis + */ + + LFDS700_MISC_BARRIER_LOAD; + + vi.min_elements = vi.max_elements = number_elements * number_logical_processors + 1; + + lfds700_list_asu_query( &lasus, LFDS700_LIST_ASU_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + per_thread_counters = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + *(per_thread_counters+loop) = number_elements - 1; + + /* TRD : we have a leading element, after which all inserts occurred + we need to get past that element for validation + this is why we're not using lfds700_list_asu_get_start_and_then_next() + */ + + lasue = LFDS700_LIST_ASU_GET_START( lasus ); + + lasue = LFDS700_LIST_ASU_GET_NEXT( *lasue ); + + while( dvs == LFDS700_MISC_VALIDITY_VALID and lasue != NULL ) + { + element = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + + if( element->thread_number >= number_logical_processors ) + { + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + break; + } + + if( element->element_number < per_thread_counters[element->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( element->element_number > per_thread_counters[element->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + + if( element->element_number == per_thread_counters[element->thread_number] ) + per_thread_counters[element->thread_number]--; + + lasue = LFDS700_LIST_ASU_GET_NEXT( *lasue ); + } + + free( per_thread_counters ); + + lfds700_list_asu_cleanup( &lasus, NULL ); + + util_aligned_free( element_array ); + + internal_display_test_result( 1, "list_asu", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION new_after_thread( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + loop; + + struct lfds700_misc_prng_state + ps; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + for( loop = 0 ; loop < ts->number_elements ; loop++ ) + { + LFDS700_LIST_ASU_SET_KEY_IN_ELEMENT( (ts->element_array+loop)->lasue, ts->element_array+loop ); + LFDS700_LIST_ASU_SET_VALUE_IN_ELEMENT( (ts->element_array+loop)->lasue, ts->element_array+loop ); + lfds700_list_asu_insert_at_position( ts->lasus, &(ts->element_array+loop)->lasue, ts->first_element, LFDS700_LIST_ASU_POSITION_AFTER, &ps ); + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_new_end.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_new_end.c new file mode 100644 index 0000000000..c6c66d007c --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_new_end.c @@ -0,0 +1,229 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_element +{ + struct lfds700_list_asu_element + lasue; + + lfds700_pal_uint_t + element_number, + thread_number; +}; + +struct test_state +{ + lfds700_pal_uint_t + number_elements; + + struct lfds700_list_asu_state + *lasus; + + struct test_element + *element_array; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION new_end_thread( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_list_asu_new_end( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_elements, + number_logical_processors, + *per_thread_counters, + subloop; + + struct lfds700_list_asu_element + *lasue = NULL; + + struct lfds700_list_asu_state + lasus; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *element_array, + *element; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : run one thread per logical processor + run for 250k elements + each thread loops, calling lfds700_list_asu_new_element_by_position( LFDS700_LIST_ASU_POSITION_END ) + data element contain a thread_number and element_number + verification should show element_number increasing on a per thread basis + */ + + internal_display_test_name( "New end" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_list_asu_init_valid_on_current_logical_core( &lasus, NULL, NULL ); + + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors ); + + element_array = util_aligned_malloc( sizeof(struct test_element) * number_logical_processors * number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + for( subloop = 0 ; subloop < number_elements ; subloop++ ) + { + (element_array+(loop*number_elements)+subloop)->thread_number = loop; + (element_array+(loop*number_elements)+subloop)->element_number = subloop; + } + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->lasus = &lasus; + (ts+loop)->element_array = element_array + (loop*number_elements); + (ts+loop)->number_elements = number_elements; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, new_end_thread, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + free( ts ); + + /* TRD : validate the resultant list + iterate over each element + we expect to find element numbers increment on a per thread basis + */ + + LFDS700_MISC_BARRIER_LOAD; + + vi.min_elements = vi.max_elements = number_elements * number_logical_processors; + + lfds700_list_asu_query( &lasus, LFDS700_LIST_ASU_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + per_thread_counters = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + *(per_thread_counters+loop) = 0; + + lasue = NULL; + + while( dvs == LFDS700_MISC_VALIDITY_VALID and LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(lasus, lasue) ) + { + element = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + + if( element->thread_number >= number_logical_processors ) + { + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + break; + } + + if( element->element_number > per_thread_counters[element->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( element->element_number < per_thread_counters[element->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + + if( element->element_number == per_thread_counters[element->thread_number] ) + per_thread_counters[element->thread_number]++; + } + + free( per_thread_counters ); + + lfds700_list_asu_cleanup( &lasus, NULL ); + + util_aligned_free( element_array ); + + internal_display_test_result( 1, "list_asu", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION new_end_thread( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + loop; + + struct lfds700_misc_prng_state + ps; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + for( loop = 0 ; loop < ts->number_elements ; loop++ ) + { + LFDS700_LIST_ASU_SET_KEY_IN_ELEMENT( (ts->element_array+loop)->lasue, ts->element_array+loop ); + LFDS700_LIST_ASU_SET_VALUE_IN_ELEMENT( (ts->element_array+loop)->lasue, ts->element_array+loop ); + lfds700_list_asu_insert_at_position( ts->lasus, &(ts->element_array+loop)->lasue, NULL, LFDS700_LIST_ASU_POSITION_END, &ps ); + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_new_start.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_new_start.c new file mode 100644 index 0000000000..f4244e2a12 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_list_addonly_singlylinked_unordered_new_start.c @@ -0,0 +1,229 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_element +{ + struct lfds700_list_asu_element + lasue; + + lfds700_pal_uint_t + element_number, + thread_number; +}; + +struct test_state +{ + lfds700_pal_uint_t + number_elements; + + struct lfds700_list_asu_state + *lasus; + + struct test_element + *element_array; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION new_start_thread( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_list_asu_new_start( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_elements, + number_logical_processors, + *per_thread_counters, + subloop; + + struct lfds700_list_asu_element + *lasue = NULL; + + struct lfds700_list_asu_state + lasus; + + struct lfds700_misc_validation_info + vi; + + struct test_element + *element_array, + *element; + + struct test_state + *ts; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : run one thread per logical processor + run for 250k elements + each thread loops, calling lfds700_list_asu_new_element_by_position( LFDS700_LIST_ASU_POSITION_START ) + data element contain s thread_number and element_number + verification should show element_number decreasing on a per thread basis + */ + + internal_display_test_name( "New start" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_list_asu_init_valid_on_current_logical_core( &lasus, NULL, NULL ); + + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors ); + + element_array = util_aligned_malloc( sizeof(struct test_element) * number_logical_processors * number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + for( subloop = 0 ; subloop < number_elements ; subloop++ ) + { + (element_array+(loop*number_elements)+subloop)->thread_number = loop; + (element_array+(loop*number_elements)+subloop)->element_number = subloop; + } + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->lasus = &lasus; + (ts+loop)->element_array = element_array + (loop*number_elements); + (ts+loop)->number_elements = number_elements; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, new_start_thread, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + free( ts ); + + LFDS700_MISC_BARRIER_LOAD; + + /* TRD : validate the resultant list + iterate over each element + we expect to find element numbers increment on a per thread basis + */ + + vi.min_elements = vi.max_elements = number_elements * number_logical_processors; + + lfds700_list_asu_query( &lasus, LFDS700_LIST_ASU_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + per_thread_counters = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + *(per_thread_counters+loop) = number_elements - 1; + + lasue = NULL; + + while( dvs == LFDS700_MISC_VALIDITY_VALID and LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(lasus, lasue) ) + { + element = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + + if( element->thread_number >= number_logical_processors ) + { + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + break; + } + + if( element->element_number < per_thread_counters[element->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( element->element_number > per_thread_counters[element->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + + if( element->element_number == per_thread_counters[element->thread_number] ) + per_thread_counters[element->thread_number]--; + } + + free( per_thread_counters ); + + lfds700_list_asu_cleanup( &lasus, NULL ); + + util_aligned_free( element_array ); + + internal_display_test_result( 1, "list_asu", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION new_start_thread( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + loop; + + struct lfds700_misc_prng_state + ps; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + for( loop = 0 ; loop < ts->number_elements ; loop++ ) + { + LFDS700_LIST_ASU_SET_KEY_IN_ELEMENT( (ts->element_array+loop)->lasue, ts->element_array+loop ); + LFDS700_LIST_ASU_SET_VALUE_IN_ELEMENT( (ts->element_array+loop)->lasue, ts->element_array+loop ); + lfds700_list_asu_insert_at_position( ts->lasus, &(ts->element_array+loop)->lasue, NULL, LFDS700_LIST_ASU_POSITION_START, &ps ); + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic.c new file mode 100644 index 0000000000..2f733909a7 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic.c @@ -0,0 +1,33 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_pal_atomic( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + printf( "\n" + "Abstraction Atomic Tests\n" + "========================\n" ); + + if( LFDS700_MISC_ATOMIC_SUPPORT_CAS ) + test_lfds700_pal_atomic_cas( list_of_logical_processors ); + + if( LFDS700_MISC_ATOMIC_SUPPORT_DWCAS ) + test_lfds700_pal_atomic_dwcas( list_of_logical_processors ); + + if( LFDS700_MISC_ATOMIC_SUPPORT_EXCHANGE ) + test_lfds700_pal_atomic_exchange( list_of_logical_processors, memory_in_megabytes ); + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic_cas.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic_cas.c new file mode 100644 index 0000000000..543528d99c --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic_cas.c @@ -0,0 +1,176 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_lfds700_pal_atomic_cas_state +{ + lfds700_pal_uint_t + local_counter; + + lfds700_pal_atom_t volatile + *shared_counter; +}; + +/***** private prototyps *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_cas( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_pal_atomic_cas( struct lfds700_list_asu_state *list_of_logical_processors ) +{ + lfds700_pal_atom_t volatile LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + shared_counter; + + lfds700_pal_uint_t + local_total = 0; + + lfds700_pal_uint_t + loop, + number_logical_processors; + + struct lfds700_list_asu_element + *lasue; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_lfds700_pal_atomic_cas_state + *atcs; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + + /* TRD : here we test pal_cas + + we run one thread per CPU + we use pal_cas() to increment a shared counter + every time a thread successfully increments the counter, + it increments a thread local counter + the threads run for ten seconds + after the threads finish, we total the local counters + they should equal the shared counter + */ + + internal_display_test_name( "Atomic CAS" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + shared_counter = 0; + + atcs = util_malloc_wrapper( sizeof(struct test_lfds700_pal_atomic_cas_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (atcs+loop)->shared_counter = &shared_counter; + (atcs+loop)->local_counter = 0; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_cas, atcs+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + // TRD : results + LFDS700_MISC_BARRIER_LOAD; + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + local_total += (atcs+loop)->local_counter; + + if( local_total == shared_counter ) + puts( "passed" ); + + if( local_total != shared_counter ) + { + puts( "failed" ); + exit( EXIT_FAILURE ); + } + + // TRD : cleanup + free( atcs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_cas( void *util_thread_starter_thread_state ) +{ + char unsigned + result; + + lfds700_pal_uint_t + loop = 0; + + lfds700_pal_atom_t LFDS700_PAL_ALIGN(LFDS700_PAL_ALIGN_SINGLE_POINTER) + exchange, + compare; + + struct test_lfds700_pal_atomic_cas_state + *atcs; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_BARRIER_LOAD; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + atcs = (struct test_lfds700_pal_atomic_cas_state *) tsts->thread_user_state; + + util_thread_starter_ready_and_wait( tsts ); + + while( loop++ < 10000000 ) + { + compare = *atcs->shared_counter; + + do + { + exchange = compare + 1; + LFDS700_PAL_ATOMIC_CAS( atcs->shared_counter, &compare, exchange, LFDS700_MISC_CAS_STRENGTH_WEAK, result ); + } + while( result == 0 ); + + atcs->local_counter++; + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic_dcas.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic_dcas.c new file mode 100644 index 0000000000..4973e73770 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic_dcas.c @@ -0,0 +1,177 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_lfds700_pal_atomic_dwcas_state +{ + lfds700_pal_uint_t + local_counter; + + lfds700_pal_atom_t volatile + (*shared_counter)[2]; +}; + +/***** private prototyps *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_dwcas( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_pal_atomic_dwcas( struct lfds700_list_asu_state *list_of_logical_processors ) +{ + lfds700_pal_uint_t + local_total = 0, + loop, + number_logical_processors; + + lfds700_pal_atom_t volatile LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + shared_counter[2] = { 0, 0 }; + + struct lfds700_list_asu_element + *lasue; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_lfds700_pal_atomic_dwcas_state + *atds; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + + /* TRD : here we test pal_dwcas + + we run one thread per CPU + we use pal_dwcas() to increment a shared counter + every time a thread successfully increments the counter, + it increments a thread local counter + the threads run for ten seconds + after the threads finish, we total the local counters + they should equal the shared counter + */ + + internal_display_test_name( "Atomic DWCAS" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + atds = util_malloc_wrapper( sizeof(struct test_lfds700_pal_atomic_dwcas_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (atds+loop)->shared_counter = &shared_counter; + (atds+loop)->local_counter = 0; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_dwcas, atds+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + // TRD : results + LFDS700_MISC_BARRIER_LOAD; + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + local_total += (atds+loop)->local_counter; + + if( local_total == shared_counter[0] ) + puts( "passed" ); + + if( local_total != shared_counter[0] ) + { + printf( "%llu != %llu\n", (int long long unsigned) local_total, (int long long unsigned) shared_counter[0] ); + puts( "failed" ); + exit( EXIT_FAILURE ); + } + + // TRD : cleanup + free( atds ); + + return; +} + +#pragma warning( disable : 4702 ) + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_dwcas( void *util_thread_starter_thread_state ) +{ + char unsigned + result; + + lfds700_pal_uint_t + loop = 0; + + lfds700_pal_atom_t LFDS700_PAL_ALIGN(LFDS700_PAL_ALIGN_DOUBLE_POINTER) + exchange[2], + compare[2]; + + struct test_lfds700_pal_atomic_dwcas_state + *atds; + + struct util_thread_starter_thread_state + *tsts; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + atds = (struct test_lfds700_pal_atomic_dwcas_state *) tsts->thread_user_state; + + LFDS700_MISC_BARRIER_LOAD; + + util_thread_starter_ready_and_wait( tsts ); + + while( loop++ < 10000000 ) + { + compare[0] = (*atds->shared_counter)[0]; + compare[1] = (*atds->shared_counter)[1]; + + do + { + exchange[0] = compare[0] + 1; + exchange[1] = compare[1]; + LFDS700_PAL_ATOMIC_DWCAS( atds->shared_counter, compare, exchange, LFDS700_MISC_CAS_STRENGTH_WEAK, result ); + } + while( result == 0 ); + + atds->local_counter++; + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic_exchange.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic_exchange.c new file mode 100644 index 0000000000..ba6366e524 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_porting_abstraction_layer_atomic_exchange.c @@ -0,0 +1,333 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + lfds700_pal_uint_t + counter, + *counter_array, + number_elements, + number_logical_processors; + + lfds700_pal_uint_t volatile + *shared_exchange; +}; + +/***** private prototyps *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_exchange( void *util_thread_starter_thread_state ); +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_atomic_exchange( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_pal_atomic_exchange( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum flag + atomic_exchange_success_flag = RAISED, + exchange_success_flag = RAISED; + + lfds700_pal_uint_t + loop, + *merged_counter_arrays, + number_elements, + number_logical_processors, + subloop; + + lfds700_pal_uint_t volatile LFDS700_PAL_ALIGN(LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES) + exchange; + + struct lfds700_list_asu_element + *lasue; + + struct test_state + *ts; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : here we test pal_atomic_exchange + + we have one thread per logical core + there is one variable which every thread will exchange to/from + we know the number of logical cores + the threads have a counter each, which begins with their logical core number plus one + (plus one because the exchange counter begins with 0 already in place) + (e.g. thread 0 begins with its counter at 1, thread 1 begins with its counter at 2, etc) + + there is an array per thread of 1 million elements, each a counter, set to 0 + + when running, each thread increments its counter by the number of threads + the threads busy loop, exchanging + every time aa thread pulls a number off the central, shared exchange variable, + it increments the counter for that variable in its thread-local counter array + + (we're not using a global array, because we'd have to be atomic in our increments, + which is a slow-down we don't want) + + at the end, we merge all the counter arrays and if the frequency for a counter is a value + other than 1, the exchange was not atomic + + we perform the test twice, once with pal_atomic_exchange, once with a non-atomic exchange + + we expect the atomic to pass and the non-atomic to fail + */ + + internal_display_test_name( "Atomic exchange" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(lfds700_pal_uint_t) * (number_logical_processors + 1) ); + + merged_counter_arrays = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_elements ); + + for( loop = 0 ; loop < number_elements ; loop++ ) + *(merged_counter_arrays+loop) = 0; + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->counter = loop + 1; + (ts+loop)->counter_array = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_elements ); + for( subloop = 0 ; subloop < number_elements ; subloop++ ) + *((ts+loop)->counter_array+subloop) = 0; + (ts+loop)->number_logical_processors = number_logical_processors; + (ts+loop)->shared_exchange = &exchange; + (ts+loop)->number_elements = number_elements; + } + + exchange = 0; + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + // TRD : non-atomic + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_exchange, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + LFDS700_MISC_BARRIER_LOAD; + + for( loop = 0 ; loop < number_elements ; loop++ ) + for( subloop = 0 ; subloop < number_logical_processors ; subloop++ ) + *(merged_counter_arrays+loop) += *( (ts+subloop)->counter_array+loop ); + + /* TRD : the worker threads exit when their per-thread counter exceeds 1,000,000 + as such the final number_logical_processors numbers are not read + we could change the threads to exit when the number they read exceeds 1,000,000 + but then we'd need an if() in their work-loop, + and we need to go as fast as possible + */ + + for( loop = 0 ; loop < number_elements - number_logical_processors ; loop++ ) + if( *(merged_counter_arrays+loop) != 1 ) + exchange_success_flag = LOWERED; + + // TRD : now for atomic exchange - we need to re-init the data structures + + for( loop = 0 ; loop < number_elements ; loop++ ) + *(merged_counter_arrays+loop) = 0; + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + for( subloop = 0 ; subloop < number_elements ; subloop++ ) + *((ts+loop)->counter_array+subloop) = 0; + + exchange = 0; + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_atomic_exchange, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + for( loop = 0 ; loop < number_elements ; loop++ ) + for( subloop = 0 ; subloop < number_logical_processors ; subloop++ ) + *(merged_counter_arrays+loop) += *( (ts+subloop)->counter_array+loop ); + + for( loop = 0 ; loop < number_elements - number_logical_processors ; loop++ ) + if( *(merged_counter_arrays+loop) != 1 ) + atomic_exchange_success_flag = LOWERED; + + // TRD : cleanup + free( merged_counter_arrays ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + free( (ts+loop)->counter_array ); + + util_thread_starter_delete( tts ); + free( thread_handles ); + free( ts ); + + /* TRD : results + + on a single core, atomic and non-atomic exchange should both work + + if we find our non-atomic test passes, then we can't really say anything + about whether or not the atomic test is really working + */ + + LFDS700_MISC_BARRIER_LOAD; + + if( number_logical_processors == 1 ) + { + if( exchange_success_flag == RAISED and atomic_exchange_success_flag == RAISED ) + puts( "passed" ); + + if( exchange_success_flag != RAISED or atomic_exchange_success_flag != RAISED ) + puts( "failed (atomic and non-atomic both failed)" ); + } + + if( number_logical_processors >= 2 ) + { + if( atomic_exchange_success_flag == RAISED and exchange_success_flag == LOWERED ) + puts( "passed" ); + + if( atomic_exchange_success_flag == RAISED and exchange_success_flag == RAISED ) + puts( "indeterminate (atomic and non-atomic both passed)" ); + + if( atomic_exchange_success_flag == LOWERED ) + { + puts( "failed (atomic failed)" ); + exit( EXIT_FAILURE ); + } + } + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_exchange( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + local_counter, + exchange; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_BARRIER_LOAD; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + util_thread_starter_ready_and_wait( tsts ); + + local_counter = ts->counter; + + while( local_counter < ts->number_elements ) + { + exchange = *ts->shared_exchange; + *ts->shared_exchange = local_counter; + + ( *(ts->counter_array + exchange) )++; + + local_counter += ts->number_logical_processors; + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_atomic_exchange( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + local_counter, + exchange; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_BARRIER_LOAD; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + util_thread_starter_ready_and_wait( tsts ); + + local_counter = ts->counter; + + while( local_counter < ts->number_elements ) + { + exchange = local_counter; + + LFDS700_PAL_ATOMIC_EXCHANGE( ts->shared_exchange, &exchange ); + + ( *(ts->counter_array + exchange) )++; + + local_counter += ts->number_logical_processors; + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue.c new file mode 100644 index 0000000000..8e41b01b5d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue.c @@ -0,0 +1,35 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_queue( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + if( LFDS700_MISC_ATOMIC_SUPPORT_DWCAS ) + { + printf( "\n" + "Queue Tests\n" + "===========\n" ); + + test_lfds700_queue_alignment(); + test_lfds700_queue_enqueuing( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_queue_dequeuing( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_queue_enqueuing_and_dequeuing( list_of_logical_processors ); + test_lfds700_queue_rapid_enqueuing_and_dequeuing( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_queue_enqueuing_and_dequeuing_with_free( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_queue_enqueuing_with_malloc_and_dequeuing_with_free( list_of_logical_processors ); + } + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_alignment.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_alignment.c new file mode 100644 index 0000000000..6f723825ea --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_alignment.c @@ -0,0 +1,55 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_queue_alignment() +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + /* TRD : these are compile time checks + but we do them here because this is a test programme + and it should indicate issues to users when it is *run*, + not when it is compiled, because a compile error normally + indicates a problem with the code itself and so is misleading + */ + + internal_display_test_name( "Alignment" ); + + + + // TRD : struct lfds700_queue_element + if( offsetof(struct lfds700_queue_element,next) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_queue_element,key) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + + + // TRD : struct lfds700_queue_state + if( offsetof(struct lfds700_queue_state,enqueue) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_queue_state,dequeue) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_queue_state,user_state) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + + + // TRD : print the test result + internal_display_test_result( 1, "queue", dvs ); + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer.c new file mode 100644 index 0000000000..4c660ab3e1 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer.c @@ -0,0 +1,25 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +void test_lfds700_queue_bss( struct lfds700_list_asu_state *list_of_logical_processors ) +{ + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + printf( "\n" + "Queue (bounded, single consumer, single producer) Tests\n" + "=======================================================\n" ); + + // TRD : no alignment checks are required for queue_bss + test_lfds700_queue_bss_enqueuing(); + test_lfds700_queue_bss_dequeuing(); + test_lfds700_queue_bss_enqueuing_and_dequeuing( list_of_logical_processors ); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer_dequeuing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer_dequeuing.c new file mode 100644 index 0000000000..971555c443 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer_dequeuing.c @@ -0,0 +1,61 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +void test_lfds700_queue_bss_dequeuing() +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop; + + struct lfds700_queue_bss_element + element_array[128]; + + struct lfds700_queue_bss_state + qs; + + struct lfds700_misc_validation_info + vi; + + void + *value; + + /* TRD : create an empty queue + enqueue 128 elements + then dequeue the elements, in the same thread - we're API testing + it's a single producer queue, so we just do this in our current thread + since we're enqueuing and dequeuing in the same thread, + + */ + + internal_display_test_name( "Dequeuing" ); + + lfds700_queue_bss_init_valid_on_current_logical_core( &qs, element_array, 128, NULL ); + + for( loop = 0 ; loop < 127 ; loop++ ) + lfds700_queue_bss_enqueue( &qs, NULL, (void *) loop ); + + for( loop = 0 ; loop < 127 ; loop++ ) + { + lfds700_queue_bss_dequeue( &qs, NULL, &value ); + if( (lfds700_pal_uint_t) value != 127 - loop ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + } + + vi.min_elements = vi.max_elements = 0; + + lfds700_queue_bss_query( &qs, LFDS700_QUEUE_BSS_QUERY_VALIDATE, &vi, &dvs ); + + lfds700_queue_bss_cleanup( &qs, NULL ); + + internal_display_test_result( 1, "queue_bss", dvs ); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing.c new file mode 100644 index 0000000000..807337864a --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing.c @@ -0,0 +1,59 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +void test_lfds700_queue_bss_enqueuing() +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + int + rv; + + lfds700_pal_uint_t + loop; + + struct lfds700_queue_bss_element + element_array[128]; + + struct lfds700_queue_bss_state + qs; + + struct lfds700_misc_validation_info + vi; + + /* TRD : create an empty queue + enqueue 128 elements + it's a single producer queue, so we just do this in our current thread + it's an API test + */ + + internal_display_test_name( "Enqueuing" ); + + lfds700_queue_bss_init_valid_on_current_logical_core( &qs, element_array, 128, NULL ); + + for( loop = 0 ; loop < 127 ; loop++ ) + if( 1 != lfds700_queue_bss_enqueue(&qs, NULL, (void *) loop) ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + // TRD : at this point enqueuing one more should return 0 + rv = lfds700_queue_bss_enqueue( &qs, NULL, (void *) loop ); + + if( rv != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + vi.min_elements = vi.max_elements = 127; + + lfds700_queue_bss_query( &qs, LFDS700_QUEUE_BSS_QUERY_VALIDATE, &vi, &dvs ); + + lfds700_queue_bss_cleanup( &qs, NULL ); + + internal_display_test_result( 1, "queue_bss", dvs ); + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing_and_dequeuing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing_and_dequeuing.c new file mode 100644 index 0000000000..ad218609fd --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing_and_dequeuing.c @@ -0,0 +1,260 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + enum flag + error_flag; + + struct lfds700_queue_bss_state + *qs; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_enqueuer( void *util_thread_starter_thread_state ); +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_dequeuer( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_queue_bss_enqueuing_and_dequeuing( struct lfds700_list_asu_state *list_of_logical_processors ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_logical_processors, + subloop; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_queue_bss_element + element_array[4]; + + struct lfds700_queue_bss_state + qs; + + struct test_pal_logical_processor + *lp, + *lp_first; + + struct util_thread_starter_state + *tts; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + + /* TRD : so, this is the real test + problem is, because we use memory barriers only + and we only support one producer and one consumer + we need to ensure these threads are on different physical cores + if they're on the same core, the code would work even without memory barriers + + problem is, in the test application, we only know the *number* of logical cores + obtaining topology information adds a great deal of complexity to the test app + and makes porting much harder + + so, we know how many logical cores there are; my thought is to partially + permutate over them - we always run the producer on core 0, but we iterate + over the other logical cores, running the test once each time, with the + consumer being run on core 0, then core 1, then core 2, etc + + (we run on core 0 for the single-cpu case; it's redundent, since a single + logical core running both producer and consumer will work, but otherwise + we have to skip the test, which is confusing for the user) + + the test is one thread enqueuing and one thread dequeuing for two seconds + */ + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + internal_display_test_name( "Enqueuing and dequeuing (%d seconds)", number_logical_processors * 2 ); + + ts = util_malloc_wrapper( sizeof(struct test_state) * 2 ); + + for( loop = 0 ; loop < 2 ; loop++ ) + { + (ts+loop)->qs = &qs; + (ts+loop)->error_flag = LOWERED; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * 2 ); + + /* TRD : producer always on core 0 + iterate over the other cores with consumer + */ + + lasue = LFDS700_LIST_ASU_GET_START( *list_of_logical_processors ); + lp_first = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + + while( lasue != NULL ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + + lfds700_queue_bss_init_valid_on_current_logical_core( &qs, element_array, 4, NULL ); + + util_thread_starter_new( &tts, 2 ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + util_thread_starter_start( tts, &thread_handles[0], 0, lp_first, thread_enqueuer, ts ); + util_thread_starter_start( tts, &thread_handles[1], 1, lp, thread_dequeuer, ts+1 ); + + util_thread_starter_run( tts ); + + for( subloop = 0 ; subloop < 2 ; subloop++ ) + test_pal_thread_wait( thread_handles[subloop] ); + + util_thread_starter_delete( tts ); + + LFDS700_MISC_BARRIER_LOAD; + + lfds700_queue_bss_cleanup( &qs, NULL ); + + lasue = LFDS700_LIST_ASU_GET_NEXT( *lasue ); + } + + if( (ts+1)->error_flag == RAISED ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + free( thread_handles ); + + free( ts ); + + internal_display_test_result( 1, "queue_bss", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_enqueuer( void *util_thread_starter_thread_state ) +{ + int + rv; + + lfds700_pal_uint_t + datum = 0, + time_loop = 0; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + time_t + current_time, + start_time; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + util_thread_starter_ready_and_wait( tsts ); + + current_time = start_time = time( NULL ); + + while( current_time < start_time + 2 ) + { + rv = lfds700_queue_bss_enqueue( ts->qs, NULL, (void *) datum ); + + if( rv == 1 ) + if( ++datum == 4 ) + datum = 0; + + if( time_loop++ == TIME_LOOP_COUNT ) + { + time_loop = 0; + time( ¤t_time ); + } + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_dequeuer( void *util_thread_starter_thread_state ) +{ + int + rv; + + lfds700_pal_uint_t + datum, + expected_datum = 0, + time_loop = 0; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + time_t + current_time, + start_time; + + LFDS700_MISC_BARRIER_LOAD; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + util_thread_starter_ready_and_wait( tsts ); + + current_time = start_time = time( NULL ); + + while( current_time < start_time + 2 ) + { + rv = lfds700_queue_bss_dequeue( ts->qs, NULL, (void *) &datum ); + + if( rv == 1 ) + { + if( datum != expected_datum ) + ts->error_flag = RAISED; + + if( ++expected_datum == 4 ) + expected_datum = 0; + } + + if( time_loop++ == TIME_LOOP_COUNT ) + { + time_loop = 0; + time( ¤t_time ); + } + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_dequeuing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_dequeuing.c new file mode 100644 index 0000000000..74f271d320 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_dequeuing.c @@ -0,0 +1,215 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + enum flag + error_flag; + + struct lfds700_queue_state + *qs; +}; + +struct test_element +{ + struct lfds700_queue_element + qe; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_simple_dequeuer( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_queue_dequeuing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_elements_with_dummy_element, + number_elements_without_dummy_element, + number_logical_processors; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_queue_state + qs; + + struct lfds700_misc_validation_info + vi = { 0, 0 }; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te_array; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : create a queue, add 1,000,000 elements + + use a single thread to enqueue every element + each elements user data is an incrementing counter + + then run one thread per CPU + where each busy-works dequeuing + + when an element is dequeued, we check (on a per-thread basis) the + value dequeued is greater than the element previously dequeued + + note we have no variation in the test for CAS+GC vs DWCAS + this is because all we do is dequeue + what we actually want to stress test is the queue + not CAS + so it's better to let the dequeue run as fast as possible + */ + + internal_display_test_name( "Dequeuing" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + number_elements_with_dummy_element = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / sizeof(struct test_element); + number_elements_without_dummy_element = number_elements_with_dummy_element - 1; + + te_array = util_aligned_malloc( sizeof(struct test_element) * number_elements_with_dummy_element, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lfds700_queue_init_valid_on_current_logical_core( &qs, &(te_array + number_elements_without_dummy_element)->qe, &ps, NULL ); + + for( loop = 0 ; loop < number_elements_without_dummy_element ; loop++ ) + { + LFDS700_QUEUE_SET_VALUE_IN_ELEMENT( (te_array+loop)->qe, loop ); + lfds700_queue_enqueue( &qs, &(te_array+loop)->qe, &ps ); + } + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->qs = &qs; + (ts+loop)->error_flag = LOWERED; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_simple_dequeuer, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + // TRD : check queue is empty + lfds700_queue_query( &qs, LFDS700_QUEUE_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + // TRD : check for raised error flags + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + if( (ts+loop)->error_flag == RAISED ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + free( ts ); + + util_aligned_free( te_array ); + + lfds700_queue_cleanup( &qs, NULL ); + + internal_display_test_result( 1, "queue", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_simple_dequeuer( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + *prev_value, + *value; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_queue_element + *qe; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + lfds700_queue_dequeue( ts->qs, &qe, &ps ); + prev_value = LFDS700_QUEUE_GET_VALUE_FROM_ELEMENT( *qe ); + + util_thread_starter_ready_and_wait( tsts ); + + while( lfds700_queue_dequeue(ts->qs, &qe, &ps) ) + { + value = LFDS700_QUEUE_GET_VALUE_FROM_ELEMENT( *qe ); + + if( value <= prev_value ) + ts->error_flag = RAISED; + + prev_value = value; + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing.c new file mode 100644 index 0000000000..89ccf30fcb --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing.c @@ -0,0 +1,239 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + lfds700_pal_uint_t + number_elements, + thread_number; + + struct lfds700_queue_state + *qs; + + struct test_element + *te_array; +}; + +struct test_element +{ + struct lfds700_queue_element + qe; + + lfds700_pal_uint_t + counter, + thread_number; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_simple_enqueuer( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_queue_enqueuing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + *per_thread_counters, + loop, + number_elements, + number_logical_processors; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_queue_element + dummy_qe, + *qe; + + struct lfds700_queue_state + qs; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : create an empty queue + then run one thread per CPU + where each thread busy-works, enqueuing elements from a freelist (one local freelist per thread) + until 100000 elements are enqueued, per thread + each element's void pointer of user data is a struct containing thread number and element number + where element_number is a thread-local counter starting at 0 + + when we're done, we check that all the elements are present + and increment on a per-thread basis + */ + + internal_display_test_name( "Enqueuing" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors ); + + lfds700_queue_init_valid_on_current_logical_core( &qs, &dummy_qe, &ps, NULL ); + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->qs = &qs; + (ts+loop)->thread_number = loop; + (ts+loop)->number_elements = number_elements; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_simple_enqueuer, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + /* TRD : first, validate the queue + + then dequeue + we expect to find element numbers increment on a per thread basis + */ + + vi.min_elements = vi.max_elements = number_elements * number_logical_processors; + + lfds700_queue_query( &qs, LFDS700_QUEUE_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + per_thread_counters = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + *(per_thread_counters+loop) = 0; + + while( dvs == LFDS700_MISC_VALIDITY_VALID and lfds700_queue_dequeue(&qs, &qe, &ps) ) + { + te = LFDS700_QUEUE_GET_VALUE_FROM_ELEMENT( *qe ); + + if( te->thread_number >= number_logical_processors ) + { + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + break; + } + + if( te->counter > per_thread_counters[te->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( te->counter < per_thread_counters[te->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + + if( te->counter == per_thread_counters[te->thread_number] ) + per_thread_counters[te->thread_number]++; + } + + free( per_thread_counters ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + util_aligned_free( (ts+loop)->te_array ); + + free( ts ); + + lfds700_queue_cleanup( &qs, NULL ); + + internal_display_test_result( 1, "queue", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_simple_enqueuer( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + loop; + + struct lfds700_misc_prng_state + ps; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + ts->te_array = util_aligned_malloc( sizeof(struct test_element) * ts->number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < ts->number_elements ; loop++ ) + { + (ts->te_array+loop)->thread_number = ts->thread_number; + (ts->te_array+loop)->counter = loop; + } + + util_thread_starter_ready_and_wait( tsts ); + + for( loop = 0 ; loop < ts->number_elements ; loop++ ) + { + LFDS700_QUEUE_SET_VALUE_IN_ELEMENT( (ts->te_array+loop)->qe, ts->te_array+loop ); + lfds700_queue_enqueue( ts->qs, &(ts->te_array+loop)->qe, &ps ); + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing_and_dequeuing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing_and_dequeuing.c new file mode 100644 index 0000000000..1469635fd4 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing_and_dequeuing.c @@ -0,0 +1,250 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + enum flag + error_flag; + + lfds700_pal_uint_t + counter, + number_logical_processors, + *per_thread_counters, + thread_number; + + struct lfds700_queue_state + *qs; +}; + +struct test_element +{ + struct lfds700_queue_element + qe, + *qe_use; + + lfds700_pal_uint_t + counter, + thread_number; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_enqueuer_and_dequeuer( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_queue_enqueuing_and_dequeuing( struct lfds700_list_asu_state *list_of_logical_processors ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_logical_processors, + subloop; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_queue_state + qs; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te_array; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : qt can be any value in its range + + /* TRD : create a queue with one element per thread + each thread constly dequeues and enqueues from that one queue + where when enqueuing sets in the element + its thread number and counter + and when dequeuing, checks the thread number and counter + against previously seen counter for that thread + where it should always see a higher number + */ + + internal_display_test_name( "Enqueuing and dequeuing (%d seconds)", TEST_DURATION_IN_SECONDS ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + te_array = util_aligned_malloc( sizeof(struct test_element) * (number_logical_processors+1), LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lfds700_queue_init_valid_on_current_logical_core( &qs, &(te_array+number_logical_processors)->qe, &ps, NULL ); + + // TRD : we assume the test will iterate at least once (or we'll have a false negative) + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (te_array+loop)->thread_number = loop; + (te_array+loop)->counter = 0; + LFDS700_QUEUE_SET_VALUE_IN_ELEMENT( (te_array+loop)->qe, te_array+loop ); + lfds700_queue_enqueue( &qs, &(te_array+loop)->qe, &ps ); + } + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->qs = &qs; + (ts+loop)->thread_number = loop; + (ts+loop)->counter = 0; + (ts+loop)->error_flag = LOWERED; + (ts+loop)->per_thread_counters = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_logical_processors ); + (ts+loop)->number_logical_processors = number_logical_processors; + + for( subloop = 0 ; subloop < number_logical_processors ; subloop++ ) + *((ts+loop)->per_thread_counters+subloop) = 0; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_enqueuer_and_dequeuer, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + vi.min_elements = vi.max_elements = number_logical_processors; + + lfds700_queue_query( &qs, LFDS700_QUEUE_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + if( (ts+loop)->error_flag == RAISED ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + free( (ts+loop)->per_thread_counters ); + + util_aligned_free( te_array ); + + free( ts ); + + lfds700_queue_cleanup( &qs, NULL ); + + internal_display_test_result( 1, "queue", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_enqueuer_and_dequeuer( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + time_loop = 0; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_queue_element + *qe; + + struct test_element + *te; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + time_t + current_time, + start_time; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + current_time = start_time = time( NULL ); + + while( current_time < start_time + TEST_DURATION_IN_SECONDS ) + { + lfds700_queue_dequeue( ts->qs, &qe, &ps ); + te = LFDS700_QUEUE_GET_VALUE_FROM_ELEMENT( *qe ); + + if( te->thread_number >= ts->number_logical_processors ) + ts->error_flag = RAISED; + else + { + if( te->counter < ts->per_thread_counters[te->thread_number] ) + ts->error_flag = RAISED; + + if( te->counter >= ts->per_thread_counters[te->thread_number] ) + ts->per_thread_counters[te->thread_number] = te->counter+1; + } + + te->thread_number = ts->thread_number; + te->counter = ++ts->counter; + + LFDS700_QUEUE_SET_VALUE_IN_ELEMENT( *qe, te ); + lfds700_queue_enqueue( ts->qs, qe, &ps ); + + if( time_loop++ == TIME_LOOP_COUNT ) + { + time_loop = 0; + time( ¤t_time ); + } + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing_and_dequeuing_with_free.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing_and_dequeuing_with_free.c new file mode 100644 index 0000000000..21be07052d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing_and_dequeuing_with_free.c @@ -0,0 +1,241 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + lfds700_pal_uint_t + number_of_elements_per_thread; + + struct lfds700_queue_state + *qs; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_enqueue_dequeuer_with_free( void *util_thread_starter_thread_state ); +static void queue_element_cleanup_callback( struct lfds700_queue_state *qs, struct lfds700_queue_element *qe, enum lfds700_misc_flag dummy_element_flag ); + + + + + +/****************************************************************************/ +void test_lfds700_queue_enqueuing_and_dequeuing_with_free( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_elements, + number_logical_processors, + number_of_elements_per_thread; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_queue_element + *qe; + + struct lfds700_queue_state + qs; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct test_state + *ts; + + struct util_thread_starter_state + *tts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : the M&Q queue supports free()ing queue elements after they've been dequeued + we need to test this + we spawn one thread per logical core + there's one master queue which all threads work on + we create one freelist per thread + and allocate as many queue elements as we can (no payload) + - but note each allocate is its own malloc() + each freelist receives an equal share (i.e. we get the mallocs out of the way) + each thread enqueues as rapidly as possible + and dequeues as rapidly as possible + (i.e. each thread loops, doing an enqueue and a dequeue) + when the dequeue is done, the element is free()ed + */ + + internal_display_test_name( "Enqueuing and dequeuing with free" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct lfds700_freelist_element) + sizeof(struct lfds700_queue_element) ); + number_of_elements_per_thread = number_elements / number_logical_processors; + qe = util_aligned_malloc( sizeof(struct lfds700_queue_element), (lfds700_pal_uint_t) LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + lfds700_queue_init_valid_on_current_logical_core( &qs, qe, &ps, NULL ); + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->qs = &qs; + (ts+loop)->number_of_elements_per_thread = number_of_elements_per_thread; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_enqueue_dequeuer_with_free, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + vi.min_elements = 0; + vi.max_elements = 0; + + lfds700_queue_query( &qs, LFDS700_QUEUE_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + lfds700_queue_cleanup( &qs, queue_element_cleanup_callback ); + + free( ts ); + + internal_display_test_result( 1, "queue", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_enqueue_dequeuer_with_free( void *util_thread_starter_thread_state ) +{ + enum flag + finished_flag = LOWERED; + + lfds700_pal_uint_t + loop; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_freelist_element + *fe, + *fe_array; + + struct lfds700_freelist_state + fs; + + struct lfds700_queue_element + *qe; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + lfds700_freelist_init_valid_on_current_logical_core( &fs, NULL ); + + fe_array = util_malloc_wrapper( sizeof(struct lfds700_freelist_element) * ts->number_of_elements_per_thread ); + + for( loop = 0 ; loop < ts->number_of_elements_per_thread ; loop++ ) + { + qe = util_aligned_malloc( sizeof(struct lfds700_queue_element), LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + LFDS700_FREELIST_SET_VALUE_IN_ELEMENT( fe_array[loop], qe ); + lfds700_freelist_push( &fs, &fe_array[loop], &ps ); + } + + util_thread_starter_ready_and_wait( tsts ); + + while( finished_flag == LOWERED ) + { + loop = 0; + while( loop++ < 1000 and lfds700_freelist_pop(&fs, &fe, &ps) ) + { + qe = LFDS700_FREELIST_GET_VALUE_FROM_ELEMENT( *fe ); + lfds700_queue_enqueue( ts->qs, qe, &ps ); + } + + if( loop < 1000 ) + finished_flag = RAISED; + + loop = 0; + while( loop++ < 1000 and lfds700_queue_dequeue(ts->qs, &qe, &ps) ) + util_aligned_free( qe ); + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + lfds700_freelist_cleanup( &fs, NULL ); + + free( fe_array ); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static void queue_element_cleanup_callback( struct lfds700_queue_state *qs, struct lfds700_queue_element *qe, enum lfds700_misc_flag dummy_element_flag ) +{ + assert( qs != NULL ); + assert( qe != NULL ); + // TRD : dummy_element_flag can be any value in its range + + util_aligned_free( qe ); + + return; +} + +#pragma warning( default : 4100 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing_with_malloc_and_dequeuing_with_free.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing_with_malloc_and_dequeuing_with_free.c new file mode 100644 index 0000000000..0f0fa7f081 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_enqueuing_with_malloc_and_dequeuing_with_free.c @@ -0,0 +1,208 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + struct lfds700_queue_state + *qs; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_enqueuer_with_malloc_and_dequeuer_with_free( void *util_thread_starter_thread_state ); +static void queue_element_cleanup_callback( struct lfds700_queue_state *qs, struct lfds700_queue_element *qe, enum lfds700_misc_flag dummy_element_flag ); + + + + + +/****************************************************************************/ +void test_lfds700_queue_enqueuing_with_malloc_and_dequeuing_with_free( struct lfds700_list_asu_state *list_of_logical_processors ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_logical_processors; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_queue_element + *qe; + + struct lfds700_queue_state + qs; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : qt can be any value in its range + + /* TRD : one thread per logical core + each thread loops for ten seconds + mallocs and enqueues 1k elements, then dequeues and frees 1k elements + */ + + internal_display_test_name( "Enqueuing with malloc dequeuing with free (%d seconds)", TEST_DURATION_IN_SECONDS ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + qe = util_aligned_malloc( sizeof(struct lfds700_queue_element), LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lfds700_queue_init_valid_on_current_logical_core( &qs, qe, &ps, NULL ); + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + (ts+loop)->qs = &qs; + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_enqueuer_with_malloc_and_dequeuer_with_free, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + vi.min_elements = vi.max_elements = 0; + + lfds700_queue_query( &qs, LFDS700_QUEUE_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + free( ts ); + + lfds700_queue_cleanup( &qs, queue_element_cleanup_callback ); + + internal_display_test_result( 1, "queue", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_enqueuer_with_malloc_and_dequeuer_with_free( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + loop, + time_loop = 0; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_queue_element + *qe; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + time_t + current_time, + start_time; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + current_time = start_time = time( NULL ); + + while( current_time < start_time + TEST_DURATION_IN_SECONDS ) + { + for( loop = 0 ; loop < 1000 ; loop++ ) + { + qe = util_aligned_malloc( sizeof(struct lfds700_queue_element), LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + lfds700_queue_enqueue( ts->qs, qe, &ps ); + } + + for( loop = 0 ; loop < 1000 ; loop++ ) + { + lfds700_queue_dequeue( ts->qs, &qe, &ps ); + util_aligned_free( qe ); + } + + if( time_loop++ == REDUCED_TIME_LOOP_COUNT ) + { + time_loop = 0; + time( ¤t_time ); + } + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +static void queue_element_cleanup_callback( struct lfds700_queue_state *qs, struct lfds700_queue_element *qe, enum lfds700_misc_flag dummy_element_flag ) +{ + assert( qs != NULL ); + assert( qe != NULL ); + // TRD : dummy_element_flag can be any value in its range + + util_aligned_free( qe ); + + return; +} + +#pragma warning( default : 4100 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_rapid_enqueuing_and_dequeuing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_rapid_enqueuing_and_dequeuing.c new file mode 100644 index 0000000000..ec3963a336 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_queue_rapid_enqueuing_and_dequeuing.c @@ -0,0 +1,264 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + lfds700_pal_uint_t + counter, + thread_number; + + struct lfds700_queue_state + *qs; +}; + +struct test_element +{ + struct lfds700_queue_element + qe, + *qe_use; + + lfds700_pal_uint_t + counter, + thread_number; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_rapid_enqueuer_and_dequeuer( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_queue_rapid_enqueuing_and_dequeuing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_elements_with_dummy_element, + number_elements_without_dummy_element, + number_logical_processors, + *per_thread_counters; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_queue_element + *qe; + + struct lfds700_misc_validation_info + vi; + + struct lfds700_queue_state + qs; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te_array, + *te; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we create a single queue with 50,000 elements + we don't want too many elements, so we ensure plenty of element re-use + each thread simply loops dequeuing and enqueuing + where the user data indicates thread number and an increment counter + vertification is that the counter increments on a per-thread basis + */ + + internal_display_test_name( "Rapid enqueuing and dequeuing (%d seconds)", TEST_DURATION_IN_SECONDS ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + number_elements_with_dummy_element = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / sizeof(struct test_element); + + if( number_elements_with_dummy_element > (10000 * number_logical_processors) + 1 ) + number_elements_with_dummy_element = (10000 * number_logical_processors) + 1; + + number_elements_without_dummy_element = number_elements_with_dummy_element - 1; + + vi.min_elements = number_elements_without_dummy_element; + vi.max_elements = number_elements_without_dummy_element; + + te_array = util_aligned_malloc( sizeof(struct test_element) * number_elements_with_dummy_element, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lfds700_queue_init_valid_on_current_logical_core( &qs, &(te_array+number_elements_without_dummy_element)->qe, &ps, NULL ); + + // TRD : we assume the test will iterate at least once (or we'll have a false negative) + for( loop = 0 ; loop < number_elements_without_dummy_element ; loop++ ) + { + (te_array+loop)->thread_number = loop; + (te_array+loop)->counter = 0; + LFDS700_QUEUE_SET_VALUE_IN_ELEMENT( (te_array+loop)->qe, te_array+loop ); + lfds700_queue_enqueue( &qs, &(te_array+loop)->qe, &ps ); + } + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->qs = &qs; + (ts+loop)->thread_number = loop; + (ts+loop)->counter = 0; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_rapid_enqueuer_and_dequeuer, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + lfds700_queue_query( &qs, LFDS700_QUEUE_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + // TRD : now check results + per_thread_counters = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + *(per_thread_counters+loop) = 0; + + while( dvs == LFDS700_MISC_VALIDITY_VALID and lfds700_queue_dequeue(&qs, &qe, &ps) ) + { + te = LFDS700_QUEUE_GET_VALUE_FROM_ELEMENT( *qe ); + + if( te->thread_number >= number_logical_processors ) + { + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + break; + } + + if( per_thread_counters[te->thread_number] == 0 ) + per_thread_counters[te->thread_number] = te->counter; + + if( te->counter > per_thread_counters[te->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( te->counter < per_thread_counters[te->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + + if( te->counter == per_thread_counters[te->thread_number] ) + per_thread_counters[te->thread_number]++; + } + + free( per_thread_counters ); + + lfds700_queue_cleanup( &qs, NULL ); + + util_aligned_free( te_array ); + + free( ts ); + + internal_display_test_result( 1, "queue", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_rapid_enqueuer_and_dequeuer( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + time_loop = 0; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_queue_element + *qe; + + struct test_element + *te; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + time_t + current_time, + start_time; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + current_time = start_time = time( NULL ); + + while( current_time < start_time + TEST_DURATION_IN_SECONDS ) + { + lfds700_queue_dequeue( ts->qs, &qe, &ps ); + te = LFDS700_QUEUE_GET_VALUE_FROM_ELEMENT( *qe ); + + te->thread_number = ts->thread_number; + te->counter = ts->counter++; + + LFDS700_QUEUE_SET_VALUE_IN_ELEMENT( *qe, te ); + lfds700_queue_enqueue( ts->qs, qe, &ps ); + + if( time_loop++ == TIME_LOOP_COUNT ) + { + time_loop = 0; + time( ¤t_time ); + } + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer.c new file mode 100644 index 0000000000..0a7de0761b --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer.c @@ -0,0 +1,31 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_ringbuffer( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + if( LFDS700_MISC_ATOMIC_SUPPORT_DWCAS ) + { + printf( "\n" + "Ringbuffer Tests\n" + "================\n" ); + + test_lfds700_ringbuffer_reading( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_ringbuffer_reading_and_writing( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_ringbuffer_writing( list_of_logical_processors, memory_in_megabytes ); + } + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer_reading.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer_reading.c new file mode 100644 index 0000000000..00d378992e --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer_reading.c @@ -0,0 +1,217 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + enum flag + error_flag; + + lfds700_pal_uint_t + read_count; + + struct lfds700_ringbuffer_state + *rs; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_simple_reader( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_ringbuffer_reading( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs[2] = { LFDS700_MISC_VALIDITY_VALID, LFDS700_MISC_VALIDITY_VALID }; + + lfds700_pal_uint_t + loop, + number_elements_with_dummy_element, + number_elements_without_dummy_element, + number_logical_processors, + total_read = 0; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_ringbuffer_element + *re_array; + + struct lfds700_ringbuffer_state + rs; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we create a single ringbuffer + with 1,000,000 elements + we populate the ringbuffer, where the + user data is an incrementing counter + + we create one thread per CPU + where each thread busy-works, + reading until the ringbuffer is empty + + each thread keep track of the number of reads it manages + and that each user data it reads is greater than the + previous user data that was read + */ + + internal_display_test_name( "Reading" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + number_elements_with_dummy_element = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / sizeof(struct lfds700_ringbuffer_element); + number_elements_without_dummy_element = number_elements_with_dummy_element - 1; + + vi.min_elements = 0; + vi.max_elements = number_elements_without_dummy_element; + + re_array = util_aligned_malloc( sizeof(struct lfds700_ringbuffer_element) * number_elements_with_dummy_element, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lfds700_ringbuffer_init_valid_on_current_logical_core( &rs, re_array, number_elements_with_dummy_element, &ps, NULL ); + + // TRD : init the ringbuffer contents for the test + for( loop = 0 ; loop < number_elements_without_dummy_element ; loop++ ) + lfds700_ringbuffer_write( &rs, NULL, (void *) (size_t) loop, NULL, NULL, NULL, &ps ); + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->rs = &rs; + (ts+loop)->read_count = 0; + (ts+loop)->error_flag = LOWERED; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_simple_reader, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + lfds700_ringbuffer_query( &rs, LFDS700_RINGBUFFER_QUERY_SINGLETHREADED_VALIDATE, (void *) &vi, (void *) dvs ); + + // TRD : check for raised error flags + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + if( (ts+loop)->error_flag == RAISED ) + dvs[0] = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + // TRD : check thread reads total to 1,000,000 + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + total_read += (ts+loop)->read_count; + + if( total_read < number_elements_without_dummy_element ) + dvs[0] = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( total_read > number_elements_without_dummy_element ) + dvs[0] = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + + free( ts ); + + lfds700_ringbuffer_cleanup( &rs, NULL ); + + util_aligned_free( re_array ); + + internal_display_test_result( 2, "queue", dvs[0], "freelist", dvs[1] ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_simple_reader( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + *prev_value, + *value; + + struct lfds700_misc_prng_state + ps; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + lfds700_ringbuffer_read( ts->rs, NULL, (void **) &prev_value, &ps ); + ts->read_count++; + + util_thread_starter_ready_and_wait( tsts ); + + while( lfds700_ringbuffer_read(ts->rs, NULL, (void **) &value, &ps) ) + { + if( value <= prev_value ) + ts->error_flag = RAISED; + + prev_value = value; + + ts->read_count++; + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer_reading_and_writing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer_reading_and_writing.c new file mode 100644 index 0000000000..152c331892 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer_reading_and_writing.c @@ -0,0 +1,261 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + enum flag + error_flag; + + lfds700_pal_uint_t + counter, + number_logical_processors, + *per_thread_counters, + thread_number; + + struct lfds700_ringbuffer_state + *rs; +}; + +struct test_element +{ + lfds700_pal_uint_t + datum, + thread_number; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_reader_writer( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_ringbuffer_reading_and_writing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs[2] = { LFDS700_MISC_VALIDITY_VALID, LFDS700_MISC_VALIDITY_VALID }; + + lfds700_pal_uint_t + loop, + number_elements_with_dummy_element, + number_elements_without_dummy_element, + number_logical_processors, + subloop; + + test_pal_thread_state_t + *thread_handles; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_ringbuffer_element + *re_array; + + struct lfds700_ringbuffer_state + rs; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te_array; + + struct test_state + *ts; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we create a single ringbuffer + with 100,000 elements + the ringbuffers starts empty + + we create one thread per CPU + where each thread busy-works writing + and then immediately reading + for ten seconds + + the user data in each written element is a combination + of the thread number and the counter + + while a thread runs, it keeps track of the + counters for the other threads and throws an error + if it sees the number stay the same or decrease + */ + + internal_display_test_name( "Reading and writing (%d seconds)", TEST_DURATION_IN_SECONDS ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + number_elements_with_dummy_element = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) + sizeof(struct lfds700_ringbuffer_element) ); + number_elements_without_dummy_element = number_elements_with_dummy_element - 1; + + vi.min_elements = 0; + vi.max_elements = number_elements_without_dummy_element; + + re_array = util_aligned_malloc( sizeof(struct lfds700_ringbuffer_element) * number_elements_with_dummy_element, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lfds700_ringbuffer_init_valid_on_current_logical_core( &rs, re_array, number_elements_with_dummy_element, &ps, NULL ); + + te_array = util_malloc_wrapper( sizeof(struct test_element) * number_elements_without_dummy_element ); + + // TRD : populate the ringbuffer + for( loop = 0 ; loop < number_elements_without_dummy_element ; loop++ ) + { + te_array[loop].thread_number = 0; + te_array[loop].datum = (lfds700_pal_uint_t) -1 ; + lfds700_ringbuffer_write( &rs, NULL, &te_array[loop], NULL, NULL, NULL, &ps ); + } + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->rs = &rs; + (ts+loop)->thread_number = loop; + (ts+loop)->counter = 0; + (ts+loop)->number_logical_processors = number_logical_processors; + (ts+loop)->error_flag = LOWERED; + (ts+loop)->per_thread_counters = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_logical_processors ); + + for( subloop = 0 ; subloop < number_logical_processors ; subloop++ ) + *((ts+loop)->per_thread_counters+subloop) = 0; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_reader_writer, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + lfds700_ringbuffer_query( &rs, LFDS700_RINGBUFFER_QUERY_SINGLETHREADED_VALIDATE, (void *) &vi, (void *) dvs ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + if( (ts+loop)->error_flag == RAISED ) + dvs[0] = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + free( (ts+loop)->per_thread_counters ); + + free( ts ); + + lfds700_ringbuffer_cleanup( &rs, NULL ); + + util_aligned_free( re_array ); + + free( te_array ); + + internal_display_test_result( 2, "queue", dvs[0], "freelist", dvs[1] ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_reader_writer( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + time_loop = 0; + + struct lfds700_misc_prng_state + ps; + + struct test_element + *te; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + time_t + current_time, + start_time; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + current_time = start_time = time( NULL ); + + while( current_time < start_time + TEST_DURATION_IN_SECONDS ) + { + lfds700_ringbuffer_read( ts->rs, NULL, (void **) &te, &ps ); + + if( te->thread_number >= ts->number_logical_processors ) + ts->error_flag = RAISED; + else + { + if( te->datum < ts->per_thread_counters[te->thread_number] ) + ts->error_flag = RAISED; + + if( te->datum >= ts->per_thread_counters[te->thread_number] ) + ts->per_thread_counters[te->thread_number] = te->datum+1; + } + + te->thread_number = ts->thread_number; + te->datum = ts->counter++; + + lfds700_ringbuffer_write( ts->rs, NULL, te, NULL, NULL, NULL, &ps ); + + if( time_loop++ == TIME_LOOP_COUNT ) + { + time_loop = 0; + time( ¤t_time ); + } + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer_writing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer_writing.c new file mode 100644 index 0000000000..702aabc58d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_ringbuffer_writing.c @@ -0,0 +1,272 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_element +{ + lfds700_pal_uint_t + thread_number, + datum; +}; + +struct test_state +{ + lfds700_pal_uint_t + thread_number, + write_count; + + struct test_element + te; + + struct lfds700_ringbuffer_state + *rs; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_simple_writer( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_ringbuffer_writing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs[2] = { LFDS700_MISC_VALIDITY_VALID, LFDS700_MISC_VALIDITY_VALID }; + + lfds700_pal_uint_t + loop, + number_elements_with_dummy_element, + number_elements_without_dummy_element, + number_logical_processors, + *per_thread_counters; + + test_pal_thread_state_t + *thread_handles; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_ringbuffer_element + *re_array; + + struct lfds700_ringbuffer_state + rs; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te, + *te_array; + + struct test_state + *ts; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we create a single ringbuffer + with n elements + we create n test elements + which are thread_number/counter pairs + init them to safe values + and fully populate the ringbuffer + + we create one thread per CPU + where each thread busy-works writing + for ten seconds; each thread has one extra element + which it uses for the first write and after that + it uses the element it picks up from overwriting + + the user data in each written element is a combination + of the thread number and the counter + + after the threads are complete, we validate by + checking the user data counters increment on a per thread + basis + */ + + internal_display_test_name( "Writing (%d seconds)", TEST_DURATION_IN_SECONDS ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + number_elements_with_dummy_element = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) + sizeof(struct lfds700_ringbuffer_element) ); + number_elements_without_dummy_element = number_elements_with_dummy_element - 1; + + vi.min_elements = number_elements_without_dummy_element; + vi.max_elements = number_elements_without_dummy_element; + + re_array = util_aligned_malloc( sizeof(struct lfds700_ringbuffer_element) * number_elements_with_dummy_element, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lfds700_ringbuffer_init_valid_on_current_logical_core( &rs, re_array, number_elements_with_dummy_element, &ps, NULL ); + + te_array = util_malloc_wrapper( sizeof(struct lfds700_ringbuffer_element) * number_elements_without_dummy_element ); + + // TRD : init the test elements and write them into the ringbuffer + for( loop = 0 ; loop < number_elements_without_dummy_element ; loop++ ) + { + te_array[loop].thread_number = 0; + te_array[loop].datum = 0; + lfds700_ringbuffer_write( &rs, NULL, &te_array[loop], NULL, NULL, NULL, &ps ); + } + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->rs = &rs; + (ts+loop)->thread_number = loop; + (ts+loop)->write_count = 0; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_simple_writer, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + // TRD : now check results + per_thread_counters = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + *(per_thread_counters+loop) = 0; + + lfds700_ringbuffer_query( &rs, LFDS700_RINGBUFFER_QUERY_SINGLETHREADED_VALIDATE, &vi, dvs ); + + while( dvs[0] == LFDS700_MISC_VALIDITY_VALID and dvs[1] == LFDS700_MISC_VALIDITY_VALID and lfds700_ringbuffer_read(&rs, NULL, (void **) &te, &ps) ) + { + if( te->thread_number >= number_logical_processors ) + { + dvs[0] = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + break; + } + + if( per_thread_counters[te->thread_number] == 0 ) + per_thread_counters[te->thread_number] = te->datum; + + if( te->datum < per_thread_counters[te->thread_number] ) + dvs[0] = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + + if( te->datum >= per_thread_counters[te->thread_number] ) + per_thread_counters[te->thread_number] = te->datum+1; + } + + free( per_thread_counters ); + + lfds700_ringbuffer_cleanup( &rs, NULL ); + + free( ts ); + + util_aligned_free( re_array ); + + free( te_array ); + + internal_display_test_result( 2, "queue", dvs[0], "freelist", dvs[1] ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_simple_writer( void *util_thread_starter_thread_state ) +{ + enum lfds700_misc_flag + overwrite_occurred_flag; + + lfds700_pal_uint_t + time_loop = 0; + + struct lfds700_misc_prng_state + ps; + + struct test_element + *te; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + time_t + current_time, + start_time; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + ts->te.thread_number = 0; + ts->te.datum = 0; + + lfds700_ringbuffer_write( ts->rs, NULL, &ts->te, &overwrite_occurred_flag, NULL, (void **) &te, &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + current_time = start_time = time( NULL ); + + while( current_time < start_time + TEST_DURATION_IN_SECONDS ) + { + te->thread_number = ts->thread_number; + te->datum = ts->write_count++; + + lfds700_ringbuffer_write( ts->rs, NULL, te, &overwrite_occurred_flag, NULL, (void **) &te, &ps ); + + if( time_loop++ == TIME_LOOP_COUNT ) + { + time_loop = 0; + time( ¤t_time ); + } + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack.c new file mode 100644 index 0000000000..af3a37512a --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack.c @@ -0,0 +1,33 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_stack( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + if( LFDS700_MISC_ATOMIC_SUPPORT_DWCAS ) + { + printf( "\n" + "Stack Tests\n" + "===========\n" ); + + test_lfds700_stack_alignment(); + test_lfds700_stack_popping( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_stack_pushing( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_stack_popping_and_pushing( list_of_logical_processors, memory_in_megabytes ); + test_lfds700_stack_rapid_popping_and_pushing( list_of_logical_processors ); + } + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_alignment.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_alignment.c new file mode 100644 index 0000000000..7add41bd48 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_alignment.c @@ -0,0 +1,43 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#pragma warning( disable : 4127 ) // TRD : disables MSVC warning for condition expressions being const + +void test_lfds700_stack_alignment() +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + /* TRD : these are compile time checks + but we do them here because this is a test programme + and it should indicate issues to users when it is *run*, + not when it is compiled, because a compile error normally + indicates a problem with the code itself and so is misleading + */ + + internal_display_test_name( "Alignment" ); + + + + // TRD : struct lfds700_stack_state + if( offsetof(struct lfds700_stack_state,top) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + if( offsetof(struct lfds700_stack_state,user_state) % LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES != 0 ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + + + // TRD : print the test result + internal_display_test_result( 1, "stack", dvs ); + + return; +} + +#pragma warning( default : 4127 ) + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_popping.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_popping.c new file mode 100644 index 0000000000..461730604c --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_popping.c @@ -0,0 +1,202 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + struct lfds700_stack_state + *ss; +}; + +struct test_element +{ + struct lfds700_stack_element + se; + + enum flag + popped_flag; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_stack_popping( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_elements, + number_logical_processors; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_stack_state + ss; + + struct lfds700_misc_validation_info + vi = { 0, 0 }; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te_array; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we create a stack + + we then populate the stack with 1,000,000 elements + each void pointer of data points to the containing test element + + we then run one thread per CPU + where each thread loops, popping as quickly as possible + upon popping, a flag is set in the containing test element + + the threads run till the source stack is empty + + we then check the poppged flag, all should be raised + + then tidy up + + no CAS+GC code, as we only pop + */ + + internal_display_test_name( "Popping" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + lfds700_stack_init_valid_on_current_logical_core( &ss, NULL ); + + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / sizeof(struct test_element) ; + + te_array = util_aligned_malloc( sizeof(struct test_element) * number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_elements ; loop++ ) + { + (te_array+loop)->popped_flag = LOWERED; + LFDS700_STACK_SET_VALUE_IN_ELEMENT( (te_array+loop)->se, te_array+loop ); + lfds700_stack_push( &ss, &(te_array+loop)->se, &ps ); + } + + ts = util_aligned_malloc( sizeof(struct test_state) * number_logical_processors, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + (ts+loop)->ss = &ss; + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_popping, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + lfds700_stack_query( &ss, LFDS700_STACK_QUERY_SINGLETHREADED_VALIDATE, &vi, (void *) &dvs ); + + // TRD : now we check each element has popped_flag set to RAISED + for( loop = 0 ; loop < number_elements ; loop++ ) + if( (te_array+loop)->popped_flag == LOWERED ) + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + + // TRD : cleanup + lfds700_stack_cleanup( &ss, NULL ); + util_aligned_free( te_array ); + util_aligned_free( ts ); + + // TRD : print the test result + internal_display_test_result( 1, "stack", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping( void *util_thread_starter_thread_state ) +{ + struct lfds700_misc_prng_state + ps; + + struct lfds700_stack_element + *se; + + struct test_element + *te; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + while( lfds700_stack_pop(ts->ss, &se, &ps) ) + { + te = LFDS700_STACK_GET_VALUE_FROM_ELEMENT( *se ); + te->popped_flag = RAISED; + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_popping_and_pushing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_popping_and_pushing.c new file mode 100644 index 0000000000..03c3254c77 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_popping_and_pushing.c @@ -0,0 +1,316 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_element; + +struct test_state +{ + lfds700_pal_uint_t + number_elements; + + struct lfds700_stack_state + *ss, + ss_thread_local; + + struct test_element + *ss_thread_local_te_array; +}; + +struct test_element +{ + struct lfds700_stack_element + se, + thread_local_se; + + lfds700_pal_uint_t + datum; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping_and_pushing_start_popping( void *util_thread_starter_thread_state ); +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping_and_pushing_start_pushing( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_stack_popping_and_pushing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_elements, + number_logical_processors, + subloop; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_stack_state + ss; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te_array; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we have two threads per CPU + the threads loop for ten seconds + the first thread pushes 10000 elements then pops 10000 elements + the second thread pops 10000 elements then pushes 10000 elements + all pushes and pops go onto the single main stack + + after time is up, all threads push what they have remaining onto + the main stack + + we then validate the main stack + */ + + internal_display_test_name( "Popping and pushing (%d seconds)", TEST_DURATION_IN_SECONDS ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors * 2 ); + + lfds700_stack_init_valid_on_current_logical_core( &ss, NULL ); + + te_array = util_aligned_malloc( sizeof(struct test_element) * number_elements * number_logical_processors, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + // TRD : some initial elements so the pushing threads can start immediately + for( loop = 0 ; loop < number_elements * number_logical_processors ; loop++ ) + { + (te_array+loop)->datum = loop; + LFDS700_STACK_SET_VALUE_IN_ELEMENT( (te_array+loop)->se, te_array+loop ); + lfds700_stack_push( &ss, &(te_array+loop)->se, &ps ); + } + + ts = util_aligned_malloc( sizeof(struct test_state) * number_logical_processors * 2, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + // TRD : first set of threads + (ts+loop)->ss = &ss; + (ts+loop)->number_elements = number_elements; + lfds700_stack_init_valid_on_current_logical_core( &(ts+loop)->ss_thread_local, NULL ); + + // TRD : second set of threads + (ts+loop+number_logical_processors)->ss = &ss; + (ts+loop+number_logical_processors)->number_elements = number_elements; + lfds700_stack_init_valid_on_current_logical_core( &(ts+loop+number_logical_processors)->ss_thread_local, NULL ); + + // TRD : fill the pushing thread stacks + (ts+loop+number_logical_processors)->ss_thread_local_te_array = util_aligned_malloc( sizeof(struct test_element) * number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( subloop = 0 ; subloop < number_elements ; subloop++ ) + { + ((ts+loop+number_logical_processors)->ss_thread_local_te_array+subloop)->datum = loop; + LFDS700_STACK_SET_VALUE_IN_ELEMENT( ((ts+loop+number_logical_processors)->ss_thread_local_te_array+subloop)->thread_local_se, (ts+loop+number_logical_processors)->ss_thread_local_te_array+subloop ); + lfds700_stack_push( &(ts+loop+number_logical_processors)->ss_thread_local, &((ts+loop+number_logical_processors)->ss_thread_local_te_array+subloop)->thread_local_se, &ps ); + } + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors * 2 ); + + util_thread_starter_new( &tts, number_logical_processors * 2 ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_popping_and_pushing_start_popping, ts+loop ); + util_thread_starter_start( tts, &thread_handles[loop+number_logical_processors], loop+number_logical_processors, lp, thread_popping_and_pushing_start_pushing, ts+loop+number_logical_processors ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors * 2 ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + vi.min_elements = vi.max_elements = number_elements * number_logical_processors * 2; + + lfds700_stack_query( &ss, LFDS700_STACK_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + lfds700_stack_cleanup( &ss, NULL ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + lfds700_stack_cleanup( &(ts+loop)->ss_thread_local, NULL ); + lfds700_stack_cleanup( &(ts+loop+number_logical_processors)->ss_thread_local, NULL ); + util_aligned_free( (ts+loop+number_logical_processors)->ss_thread_local_te_array ); + } + + util_aligned_free( ts ); + + util_aligned_free( te_array ); + + // TRD : print the test result + internal_display_test_result( 1, "stack", dvs ); + + return; +} + + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping_and_pushing_start_popping( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + count; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_stack_element + *se; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + time_t + start_time; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + start_time = time( NULL ); + + while( time(NULL) < start_time + TEST_DURATION_IN_SECONDS ) + { + count = 0; + + while( count < ts->number_elements ) + if( lfds700_stack_pop(ts->ss, &se, &ps) ) + { + lfds700_stack_push( &ts->ss_thread_local, se, &ps ); + count++; + } + + // TRD : return our local stack to the main stack + while( lfds700_stack_pop(&ts->ss_thread_local, &se, &ps) ) + lfds700_stack_push( ts->ss, se, &ps ); + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_popping_and_pushing_start_pushing( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + count; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_stack_element + *se; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + time_t + start_time; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + start_time = time( NULL ); + + while( time(NULL) < start_time + TEST_DURATION_IN_SECONDS ) + { + // TRD : return our local stack to the main stack + while( lfds700_stack_pop(&ts->ss_thread_local, &se, &ps) ) + lfds700_stack_push( ts->ss, se, &ps ); + + count = 0; + + while( count < ts->number_elements ) + if( lfds700_stack_pop(ts->ss, &se, &ps) ) + { + lfds700_stack_push( &ts->ss_thread_local, se, &ps ); + count++; + } + } + + // TRD : now push whatever we have in our local stack + while( lfds700_stack_pop(&ts->ss_thread_local, &se, &ps) ) + lfds700_stack_push( ts->ss, se, &ps ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_pushing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_pushing.c new file mode 100644 index 0000000000..bdf2b9b640 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_pushing.c @@ -0,0 +1,251 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + lfds700_pal_uint_t + number_elements, + thread_number; + + struct lfds700_stack_state + *ss; + + struct test_element + *te_array; +}; + +struct test_element +{ + struct lfds700_stack_element + se; + + lfds700_pal_uint_t + datum, + thread_number; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_pushing( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_stack_pushing( struct lfds700_list_asu_state *list_of_logical_processors, lfds700_pal_uint_t memory_in_megabytes ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_elements, + number_logical_processors, + *per_thread_counters; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_stack_element + *se; + + struct lfds700_stack_state + ss; + + struct lfds700_misc_validation_info + vi; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te, + *first_te = NULL; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : memory_in_megabytes can be any value in its range + + /* TRD : we create an empty stack + + we then create one thread per CPU, where each thread + pushes 100,000 elements each as quickly as possible to the stack + (the threads themselves alloc these elements, to obtain NUMA closeness) + + the data pushed is a counter and a thread ID + + the threads exit when the stack is full + + we then validate the stack; + + checking that the counts increment on a per unique ID basis + and that the number of elements we pop equals 100,000 per thread + (since each element has an incrementing counter which is + unique on a per unique ID basis, we can know we didn't lose + any elements) + + there's no CAS+GC code, as we only push + */ + + internal_display_test_name( "Pushing" ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + number_elements = ( memory_in_megabytes * ONE_MEGABYTE_IN_BYTES ) / ( sizeof(struct test_element) * number_logical_processors ); + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + // TRD : the main stack + lfds700_stack_init_valid_on_current_logical_core( &ss, NULL ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + (ts+loop)->ss = &ss; + (ts+loop)->thread_number = loop; + (ts+loop)->number_elements = number_elements; + } + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_pushing, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + // TRD : the stack is now fully pushed; time to verify + per_thread_counters = util_malloc_wrapper( sizeof(lfds700_pal_uint_t) * number_logical_processors ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + *(per_thread_counters+loop) = number_elements - 1; + + vi.min_elements = vi.max_elements = number_elements * number_logical_processors; + + lfds700_stack_query( &ss, LFDS700_STACK_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + while( dvs == LFDS700_MISC_VALIDITY_VALID and lfds700_stack_pop(&ss, &se, &ps) ) + { + te = LFDS700_STACK_GET_VALUE_FROM_ELEMENT( *se ); + + if( first_te == NULL ) + first_te = te; + + if( te->thread_number >= number_logical_processors ) + { + dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA; + break; + } + + if( te->datum > per_thread_counters[te->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS; + + if( te->datum < per_thread_counters[te->thread_number] ) + dvs = LFDS700_MISC_VALIDITY_INVALID_MISSING_ELEMENTS; + + if( te->datum == per_thread_counters[te->thread_number] ) + per_thread_counters[te->thread_number]--; + } + + // TRD : clean up + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + util_aligned_free( (ts+loop)->te_array ); + + free( per_thread_counters ); + + free( ts ); + + lfds700_stack_cleanup( &ss, NULL ); + + // TRD : print the test result + internal_display_test_result( 1, "stack", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_pushing( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + loop; + + struct lfds700_misc_prng_state + ps; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + // TRD : alloc local 100,000 elements + ts->te_array = util_aligned_malloc( sizeof(struct test_element) * ts->number_elements, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < ts->number_elements ; loop++ ) + { + (ts->te_array+loop)->thread_number = ts->thread_number; + (ts->te_array+loop)->datum = loop; + } + + util_thread_starter_ready_and_wait( tsts ); + + for( loop = 0 ; loop < ts->number_elements ; loop++ ) + { + LFDS700_STACK_SET_VALUE_IN_ELEMENT( (ts->te_array+loop)->se, ts->te_array+loop ); + lfds700_stack_push( ts->ss, &(ts->te_array+loop)->se, &ps ); + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_rapid_popping_and_pushing.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_rapid_popping_and_pushing.c new file mode 100644 index 0000000000..d771457c86 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_lfds700_stack_rapid_popping_and_pushing.c @@ -0,0 +1,217 @@ +/***** includes *****/ +#include "internal.h" + +/***** structs *****/ +struct test_state +{ + struct lfds700_stack_state + *ss; +}; + +struct test_element +{ + struct lfds700_stack_element + se; + + lfds700_pal_uint_t + datum; +}; + +/***** private prototypes *****/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_rapid_popping_and_pushing( void *util_thread_starter_thread_state ); + + + + + +/****************************************************************************/ +void test_lfds700_stack_rapid_popping_and_pushing( struct lfds700_list_asu_state *list_of_logical_processors ) +{ + enum lfds700_misc_validity + dvs = LFDS700_MISC_VALIDITY_VALID; + + lfds700_pal_uint_t + loop, + number_logical_processors; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_list_asu_element + *lasue; + + struct lfds700_stack_state + ss; + + struct lfds700_misc_validation_info + vi = { 0, 0 }; + + struct test_pal_logical_processor + *lp; + + struct util_thread_starter_state + *tts; + + struct test_element + *te_array; + + struct test_state + *ts; + + test_pal_thread_state_t + *thread_handles; + + assert( list_of_logical_processors != NULL ); + // TRD : st can be any value in its range + + /* TRD : in these tests there is a fundamental antagonism between + how much checking/memory clean up that we do and the + likelyhood of collisions between threads in their lock-free + operations + + the lock-free operations are very quick; if we do anything + much at all between operations, we greatly reduce the chance + of threads colliding + + so we have some tests which do enough checking/clean up that + they can tell the stack is valid and don't leak memory + and here, this test now is one of those which does minimal + checking - in fact, the nature of the test is that you can't + do any real checking - but goes very quickly + + what we do is create a small stack and then run one thread + per CPU, where each thread simply pushes and then immediately + pops + + the test runs for ten seconds + + after the test is done, the only check we do is to traverse + the stack, checking for loops and ensuring the number of + elements is correct + */ + + internal_display_test_name( "Rapid popping and pushing (%d seconds)", TEST_DURATION_IN_SECONDS ); + + lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors ); + + lfds700_misc_prng_init( &ps ); + + ts = util_malloc_wrapper( sizeof(struct test_state) * number_logical_processors ); + + lfds700_stack_init_valid_on_current_logical_core( &ss, NULL ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + (ts+loop)->ss = &ss; + + thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * number_logical_processors ); + + // TRD : we need one element per thread + te_array = util_aligned_malloc( sizeof(struct test_element) * number_logical_processors, LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + { + LFDS700_STACK_SET_VALUE_IN_ELEMENT( (te_array+loop)->se, te_array+loop ); + lfds700_stack_push( &ss, &(te_array+loop)->se, &ps ); + } + + util_thread_starter_new( &tts, number_logical_processors ); + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + loop = 0; + lasue = NULL; + + while( LFDS700_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) ) + { + lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue ); + util_thread_starter_start( tts, &thread_handles[loop], loop, lp, thread_rapid_popping_and_pushing, ts+loop ); + loop++; + } + + util_thread_starter_run( tts ); + + for( loop = 0 ; loop < number_logical_processors ; loop++ ) + test_pal_thread_wait( thread_handles[loop] ); + + util_thread_starter_delete( tts ); + + free( thread_handles ); + + LFDS700_MISC_BARRIER_LOAD; + + vi.min_elements = vi.max_elements = number_logical_processors; + + lfds700_stack_query( &ss, LFDS700_STACK_QUERY_SINGLETHREADED_VALIDATE, &vi, &dvs ); + + lfds700_stack_cleanup( &ss, NULL ); + + util_aligned_free( te_array ); + + free( ts ); + + // TRD : print the test result + internal_display_test_result( 1, "stack", dvs ); + + return; +} + + + + + +/****************************************************************************/ +static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_rapid_popping_and_pushing( void *util_thread_starter_thread_state ) +{ + lfds700_pal_uint_t + time_loop = 0; + + struct lfds700_misc_prng_state + ps; + + struct lfds700_stack_element + *se; + + struct test_state + *ts; + + struct util_thread_starter_thread_state + *tsts; + + time_t + current_time, + start_time; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + + assert( util_thread_starter_thread_state != NULL ); + + tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state; + ts = (struct test_state *) tsts->thread_user_state; + + lfds700_misc_prng_init( &ps ); + + util_thread_starter_ready_and_wait( tsts ); + + current_time = start_time = time( NULL ); + + while( current_time < start_time + TEST_DURATION_IN_SECONDS ) + { + lfds700_stack_pop( ts->ss, &se, &ps ); + lfds700_stack_push( ts->ss, se, &ps ); + + if( time_loop++ == TIME_LOOP_COUNT ) + { + time_loop = 0; + time( ¤t_time ); + } + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return( (test_pal_thread_return_t) EXIT_SUCCESS ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_get_logical_core_ids.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_get_logical_core_ids.c new file mode 100644 index 0000000000..eb62c5b4cc --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_get_logical_core_ids.c @@ -0,0 +1,245 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#if( defined _WIN32 && !defined _KERNEL_MODE && NTDDI_VERSION >= NTDDI_WIN7 ) + + /* TRD : _WIN32 indicates 64-bit or 32-bit Windows + !_KERNEL_MODE indicates Windows user-mode + NTDDI_VERSION indicates Windows version + - GetLogicalProcessorInformationEx requires Windows 7 + */ + + #ifdef TEST_PAL_GET_LOGICAL_CORE_IDS + #error More than one porting abstraction layer matches current platform in test_porting_abstraction_layer_get_logical_core_ids.c + #endif + + #define TEST_PAL_GET_LOGICAL_CORE_IDS + + void test_pal_get_logical_core_ids( struct lfds700_list_asu_state *lasus ) + { + BOOL + rv; + + DWORD + loop, + number_slpie, + slpie_length = 0; + + lfds700_pal_uint_t + bitmask, + logical_processor_number, + windows_logical_processor_group_number; + + struct lfds700_misc_prng_state + ps; + + struct test_pal_logical_processor + *lp; + + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX + *slpie = NULL; + + assert( lasus != NULL ); + + lfds700_misc_prng_init( &ps ); + + lfds700_list_asu_init_valid_on_current_logical_core( lasus, NULL, NULL ); + + rv = GetLogicalProcessorInformationEx( RelationGroup, slpie, &slpie_length ); + slpie = malloc( slpie_length ); + rv = GetLogicalProcessorInformationEx( RelationGroup, slpie, &slpie_length ); + number_slpie = slpie_length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX); + + for( loop = 0 ; loop < number_slpie ; loop++ ) + if( (slpie+loop)->Relationship == RelationGroup ) + for( windows_logical_processor_group_number = 0 ; windows_logical_processor_group_number < (slpie+loop)->Group.ActiveGroupCount ; windows_logical_processor_group_number++ ) + for( logical_processor_number = 0 ; logical_processor_number < sizeof(KAFFINITY) * BITS_PER_BYTE ; logical_processor_number++ ) + { + bitmask = (lfds700_pal_uint_t) 1 << logical_processor_number; + + // TRD : if we've found a processor for this group, add it to the list + if( (slpie+loop)->Group.GroupInfo[windows_logical_processor_group_number].ActiveProcessorMask & bitmask ) + { + lp = util_aligned_malloc( sizeof(struct test_pal_logical_processor), LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lp->logical_processor_number = logical_processor_number; + lp->windows_logical_processor_group_number = windows_logical_processor_group_number; + + LFDS700_LIST_ASU_SET_VALUE_IN_ELEMENT( lp->lasue, lp ); + lfds700_list_asu_insert_at_start( lasus, &lp->lasue, &ps ); + } + } + + free( slpie ); + + return; + } + +#endif + + + + + +/****************************************************************************/ +#if( defined _WIN32 && !defined _KERNEL_MODE && NTDDI_VERSION >= NTDDI_WINXP && NTDDI_VERSION < NTDDI_WIN7 ) + + /* TRD : _WIN32 indicates 64-bit or 32-bit Windows + !_KERNEL_MODE indicates Windows user-mode + NTDDI_VERSION indicates Windows version + - GetLogicalProcessorInformation requires XP SP3 + */ + + #ifdef TEST_PAL_GET_LOGICAL_CORE_IDS + #error More than one porting abstraction layer matches current platform in test_porting_abstraction_layer_get_logical_core_ids.c + #endif + + #define TEST_PAL_GET_LOGICAL_CORE_IDS + + void test_pal_get_logical_core_ids( struct lfds700_list_asu_state *lasus ) + { + DWORD + slpi_length = 0; + + lfds700_pal_uint_t + number_slpi, + loop; + + struct lfds700_misc_prng_state + ps; + + struct test_pal_logical_processor + *lp; + + SYSTEM_LOGICAL_PROCESSOR_INFORMATION + *slpi = NULL; + + ULONG_PTR + mask; + + assert( lasus != NULL ); + + lfds700_misc_prng_init( &ps ); + + lfds700_list_asu_init_valid_on_current_logical_core( lasus, NULL, NULL ); + + *number_logical_processors = 0; + + GetLogicalProcessorInformation( slpi, &slpi_length ); + slpi = malloc( slpi_length ); + GetLogicalProcessorInformation( slpi, &slpi_length ); + number_slpi = slpi_length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); + + for( loop = 0 ; loop < number_slpi ; loop++ ) + if( (slpi+loop)->Relationship == RelationProcessorCore ) + for( logical_processor_number = 0 ; logical_processor_number < sizeof(ULONG_PTR) * BITS_PER_BYTE ; logical_processor_number++ ) + { + bitmask = 1 << logical_processor_number; + + if( (slpi+loop)->ProcessorMask & bitmask ) + { + lp = util_aligned_malloc( sizeof(struct test_pal_logical_processor), LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lp->logical_processor_number = logical_processor_number; + lp->windows_logical_processor_group_number = 0; + + LFDS700_LIST_ASU_SET_VALUE_IN_ELEMENT( lp->lasue, lp ); + lfds700_list_asu_insert_at_start( lasus, &lp->lasue, &ps ); + } + + free( slpi ); + + return; + } + +#endif + + + + + +/****************************************************************************/ +#if( defined __linux__ ) + + /* TRD : __linux__ indicates Linux + __STDC__ indicates Standard Library + __STDC_HOSTED__ indicates Standard Library hosted implementation + - fopen requires a Standard Library hosted environment + - setbuf requires a Standard Library hosted environment + - fgets requires a Standard Library hosted environment + - sscanf requires a Standard Library hosted environment + - fclose requires a Standard Library hosted environment + */ + + #ifdef TEST_PAL_GET_LOGICAL_CORE_IDS + #error More than one porting abstraction layer matches current platform in test_porting_abstraction_layer_get_logical_core_ids.c + #endif + + #define TEST_PAL_GET_LOGICAL_CORE_IDS + + void test_pal_get_logical_core_ids( struct lfds700_list_asu_state *lasus ) + { + char + diskbuffer[BUFSIZ], + string[1024]; + + FILE + *diskfile; + + int long long unsigned + logical_processor_number; + + struct lfds700_misc_prng_state + ps; + + struct test_pal_logical_processor + *lp; + + assert( lasus != NULL ); + + lfds700_misc_prng_init( &ps ); + + lfds700_list_asu_init_valid_on_current_logical_core( lasus, NULL, NULL ); + + diskfile = fopen( "/proc/cpuinfo", "r" ); + + if( diskfile != NULL ) + { + setbuf( diskfile, diskbuffer ); + + while( NULL != fgets(string, 1024, diskfile) ) + if( 1 == sscanf(string, "processor : %llu", &logical_processor_number) ) + { + lp = util_aligned_malloc( sizeof(struct test_pal_logical_processor), LFDS700_PAL_ATOMIC_ISOLATION_IN_BYTES ); + + lp->logical_processor_number = (lfds700_pal_uint_t) logical_processor_number; + lp->windows_logical_processor_group_number = 0; + + LFDS700_LIST_ASU_SET_VALUE_IN_ELEMENT( lp->lasue, lp ); + lfds700_list_asu_insert_at_start( lasus, &lp->lasue, &ps ); + } + + fclose( diskfile ); + } + + return; + } + +#endif + + + + + +/****************************************************************************/ +#if( !defined TEST_PAL_GET_LOGICAL_CORE_IDS ) + + #error test_pal_get_logical_core_ids() not implemented for this platform. + +#endif + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_operating_system.h b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_operating_system.h new file mode 100644 index 0000000000..1c0ab03eee --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_operating_system.h @@ -0,0 +1,82 @@ +/****************************************************************************/ +#if( defined _MSC_VER ) + /* TRD : MSVC compiler + + an unfortunately necessary hack for MSVC + MSVC only defines __STDC__ if /Za is given, where /Za turns off MSVC C extensions - + which prevents Windows header files from compiling. + */ + + #define __STDC__ 1 + #define __STDC_HOSTED__ 1 +#endif + +#if( defined __linux__ ) + #define _GNU_SOURCE + #include +#endif + + + + + +/****************************************************************************/ +#if( defined _MSC_VER && _MSC_VER >= 1310 && NTDDI_VERSION >= NTDDI_WINXP && defined _WIN32 ) + + #ifdef TEST_PAL_PORTING_ABSTRACTION_LAYER + #error More than one porting abstraction layer matches current platform. + #endif + + #define TEST_PAL_PORTING_ABSTRACTION_LAYER + + #define TEST_PAL_OS_STRING "Windows" + + #include + + typedef HANDLE test_pal_thread_state_t; + typedef DWORD test_pal_thread_return_t; + + #define TEST_PAL_CALLING_CONVENTION WINAPI + +#endif + + + + + +/****************************************************************************/ +#if( defined __GNUC__ && defined __linux__ && _POSIX_THREADS > 0 ) + + #ifdef TEST_PAL_PORTING_ABSTRACTION_LAYER + #error More than one porting abstraction layer matches current platform. + #endif + + #define TEST_PAL_PORTING_ABSTRACTION_LAYER + + #define TEST_PAL_OS_STRING "Linux" + + #define _GNU_SOURCE + + #include + #include + #include + #include + + typedef pthread_t test_pal_thread_state_t; + typedef void * test_pal_thread_return_t; + + #define TEST_PAL_CALLING_CONVENTION + +#endif + + + + + +/****************************************************************************/ +#if( !defined TEST_PAL_PORTING_ABSTRACTION_LAYER ) + + #error No matching porting abstraction layer in test_porting_abstraction_layer_operating_system.h + +#endif + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_thread_start.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_thread_start.c new file mode 100644 index 0000000000..83a09814aa --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_thread_start.c @@ -0,0 +1,336 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#if( defined _WIN32 && !defined _KERNEL_MODE && NTDDI_VERSION >= NTDDI_WIN7 ) + + /* TRD : _WIN32 indicates 32-bit or 64-bit Windows + !_KERNEL_MODE indicates Windows user-mode + NTDDI_VERSION indicates Windows version + - GetCurrentProcess requires XP + - InitializeProcThreadAttributeList requires Windows 7 + - CreateRemoteThreadEx requires Windows 7 + */ + + #ifdef TEST_PAL_THREAD_START + #error More than one porting abstraction layer matches the current platform in test_porting_abstraction_layer_thread_start.c + #endif + + #define TEST_PAL_THREAD_START + + int test_pal_thread_start( test_pal_thread_state_t *thread_state, + struct test_pal_logical_processor *lp, + test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state), + void *thread_user_state ) + { + BOOL + brv; + + DWORD + thread_id; + + GROUP_AFFINITY + ga; + + int + rv = 0; + + LPPROC_THREAD_ATTRIBUTE_LIST + attribute_list; + + SIZE_T + attribute_list_length; + + assert( thread_state != NULL ); + assert( lp != NULL ); + assert( thread_function != NULL ); + // TRD : thread_user_state can be NULL + + /* TRD : here we're using CreateRemoteThreadEx() to start a thread in our own process + we do this because as a function, it allows us to specify processor and processor group affinity in the create call + */ + + brv = InitializeProcThreadAttributeList( NULL, 1, 0, &attribute_list_length ); + attribute_list = malloc( attribute_list_length ); + brv = InitializeProcThreadAttributeList( attribute_list, 1, 0, &attribute_list_length ); + + ga.Mask = ( (KAFFINITY) 1 << lp->logical_processor_number ); + ga.Group = (WORD) lp->windows_logical_processor_group_number; + memset( ga.Reserved, 0, sizeof(WORD) * 3 ); + + brv = UpdateProcThreadAttribute( attribute_list, 0, PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY, &ga, sizeof(GROUP_AFFINITY), NULL, NULL ); + *thread_state = CreateRemoteThreadEx( GetCurrentProcess(), NULL, 0, thread_function, thread_user_state, NO_FLAGS, attribute_list, &thread_id ); + + DeleteProcThreadAttributeList( attribute_list ); + free( attribute_list ); + + if( *thread_state != NULL ) + rv = 1; + + return( rv ); + } + +#endif + + + + + +/****************************************************************************/ +#if( defined _WIN32 && !defined _KERNEL_MODE && NTDDI_VERSION >= NTDDI_WINXP && NTDDI_VERSION < NTDDI_WIN7 ) + + /* TRD : _WIN32 indicates 64-bit or 32-bit Windows + NTDDI_VERSION indicates Windows version + - CreateThread requires XP + - SetThreadAffinityMask requires XP + - ResumeThread requires XP + */ + + #ifdef TEST_PAL_THREAD_START + #error More than one porting abstraction layer matches the current platform in test_porting_abstraction_layer_thread_start.c + #endif + + #define TEST_PAL_THREAD_START + + int test_pal_thread_start( test_pal_thread_state_t *thread_state, + struct test_pal_logical_processor *lp, + test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state), + void *thread_user_state ) + { + int + rv = 0; + + DWORD + thread_id; + + DWORD_PTR + affinity_mask, + result; + + assert( thread_state != NULL ); + assert( lp != NULL ); + assert( thread_function != NULL ); + // TRD : thread_user_state can be NULL + + /* TRD : Vista and earlier do not support processor groups + as such, there is a single implicit processor group + also, there's no support for actually starting a thread in its correct NUMA node / logical processor + so we make the best of it; we start suspended, set the affinity, and then resume + the thread itself internally is expected to be making allocs from the correct NUMA node + */ + + *thread_state = CreateThread( NULL, 0, thread_function, thread_user_state, CREATE_SUSPENDED, &thread_id ); + + affinity_mask = (DWORD_PTR) (1 << lp->logical_processor_number); + + SetThreadAffinityMask( *thread_state, affinity_mask ); + + ResumeThread( *thread_state ); + + if( *thread_state != NULL ) + rv = 1; + + return( rv ); + } + +#endif + + + + + +/****************************************************************************/ +#if( defined __linux__ && _POSIX_THREADS > 0 ) + + /* TRD : __linux__ indicates Linux + - gettid requires Linux + - sched_setaffinity requires Linux + _POSIX_THREADS indicates POSIX threads + - pthread_create requires POSIX + */ + + #ifdef TEST_PAL_THREAD_START + #error More than one porting abstraction layer matches the current platform in test_porting_abstraction_layer_thread_start.c + #endif + + #define TEST_PAL_THREAD_START + + /***** structs *****/ + struct test_pal_internal_thread_state + { + struct test_pal_logical_processor + lp; + + test_pal_thread_return_t + (TEST_PAL_CALLING_CONVENTION *thread_function)( void *thread_user_state ); + + void + *thread_user_state; + }; + + /***** prototypes *****/ + test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state ); + + /****************************************************************************/ + int test_pal_thread_start( test_pal_thread_state_t *thread_state, + struct test_pal_logical_processor *lp, + test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state), + void *thread_user_state ) + { + int + rv; + + struct test_pal_internal_thread_state + *its; + + /* TRD : this implementation works on Linux only as it uses sched_setaffinity(), which is Linux specific + although I cannot currently test, I believe this function also works on Android + + this implementation exists because the pthreads function for setting thread affinity, + pthread_attr_setaffinity_np(), works on Linux, but not Android + */ + + assert( thread_state != NULL ); + assert( lp != NULL ); + assert( thread_function != NULL ); + // TRD : thread_user_state can be NULL + + its = malloc( sizeof(struct test_pal_internal_thread_state) ); + + its->lp = *lp; + its->thread_function = thread_function; + its->thread_user_state = thread_user_state; + + rv = pthread_create( thread_state, NULL, test_pal_internal_thread_function, its ); + + if( rv == 0 ) + rv = 1; + + return( rv ); + } + + /****************************************************************************/ + test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state ) + { + cpu_set_t + cpuset; + + pid_t + tid; + + struct test_pal_internal_thread_state + *its; + + test_pal_thread_return_t + rv; + + assert( thread_user_state != NULL ); + + /* TRD : the APIs under Linux/POSIX for setting thread affinity are in a mess + pthreads offers pthread_attr_setaffinity_np(), which glibc supports, + but which is not supported by Android + Linux offers sched_setaffinity(), but this needs a *thread pid*, + and the only API to get a thread pid is gettid(), which works for + and only for *the calling thread* + + so we come to this - a wrapper thread function, which is the function used + when starting a thread; this calls gettid() and then sched_setaffinity(), + and then calls into the actual thread function + + generally shaking my head in disbelief at this point + */ + + assert( thread_user_state != NULL ); + + its = (struct test_pal_internal_thread_state *) thread_user_state; + + CPU_ZERO( &cpuset ); + CPU_SET( its->lp.logical_processor_number, &cpuset ); + + tid = syscall( SYS_gettid ); + + sched_setaffinity( tid, sizeof(cpu_set_t), &cpuset ); + + rv = its->thread_function( its->thread_user_state ); + + free( its ); + + return( rv ); + } + +#endif + + + + + +/****************************************************************************/ +#if( !defined __linux__ && _POSIX_THREADS > 0 ) + + /* TRD : !__linux__ indicates not Linux + _POSIX_THREADS indicates POSIX threads + - pthread_attr_init requires POSIX + - pthread_attr_setaffinity_np requires POSIX + - pthread_create requires POSIX + - pthread_attr_destroy requires POSIX + */ + + #ifdef TEST_PAL_THREAD_START + #error More than one porting abstraction layer matches the current platform in test_porting_abstraction_layer_thread_start.c + #endif + + #define TEST_PAL_THREAD_START + + int test_pal_thread_start( test_pal_thread_state_t *thread_state, + struct test_pal_logical_processor *lp, + test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state), + void *thread_user_state ) + { + int + rv = 0, + rv_create; + + cpu_set_t + cpuset; + + pthread_attr_t + attr; + + assert( thread_state != NULL ); + assert( lp != NULL ); + assert( thread_function != NULL ); + // TRD : thread_user_state can be NULL + + pthread_attr_init( &attr ); + + CPU_ZERO( &cpuset ); + CPU_SET( lp->logical_processor_number, &cpuset ); + pthread_attr_setaffinity_np( &attr, sizeof(cpuset), &cpuset ); + + rv_create = pthread_create( thread_state, &attr, thread_function, thread_user_state ); + + if( rv_create == 0 ) + rv = 1; + + pthread_attr_destroy( &attr ); + + return( rv ); + } + +#endif + + + + + +/****************************************************************************/ +#if( !defined TEST_PAL_THREAD_START ) + + #error test_pal_thread_start() not implemented for this platform. + +#endif + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_thread_wait.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_thread_wait.c new file mode 100644 index 0000000000..bd4a8c01f7 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/test_porting_abstraction_layer_thread_wait.c @@ -0,0 +1,69 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +#if( defined _WIN32 && NTDDI_VERSION >= NTDDI_WINXP ) + + /* TRD : _WIN32 indicates 32-bit or 64-bit Windows + NTDDI_VERSION indicates Windows version + - WaitForSingleObject requires XP + */ + + #ifdef TEST_PAL_THREAD_WAIT + #error More than one porting abstraction layer matches current platform in test_porting_abstraction_layer_thread_wait.c + #endif + + #define TEST_PAL_THREAD_WAIT + + void test_pal_thread_wait( test_pal_thread_state_t thread_state ) + { + WaitForSingleObject( thread_state, INFINITE ); + + return; + } + +#endif + + + + + +/****************************************************************************/ +#if( _POSIX_THREADS > 0 ) + + /* TRD : POSIX threads + + _POSIX_THREADS indicates POSIX threads + - pthread_join requires POSIX + */ + + #ifdef TEST_PAL_THREAD_WAIT + #error More than one porting abstraction layer matches current platform in test_porting_abstraction_layer_thread_wait.c + #endif + + #define TEST_PAL_THREAD_WAIT + + void test_pal_thread_wait( test_pal_thread_state_t thread_state ) + { + pthread_join( thread_state, NULL ); + + return; + } + +#endif + + + + + +/****************************************************************************/ +#if( !defined TEST_PAL_THREAD_WAIT ) + + #error test_pal_thread_wait() not implemented for this platform. + +#endif + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_cmdline.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_cmdline.c new file mode 100644 index 0000000000..9173d607c9 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_cmdline.c @@ -0,0 +1,184 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +void util_cmdline_init( struct util_cmdline_state *cs ) +{ + lfds700_pal_uint_t + loop; + + assert( cs != NULL ); + + for( loop = 0 ; loop < NUMBER_OF_LOWERCASE_LETTERS_IN_LATIN_ALPHABET ; loop++ ) + { + cs->args[loop].arg_type = LIBCOMMON_CMDLINE_ARG_TYPE_UNSET; + cs->args[loop].processed_flag = LOWERED; + } + + return; +} + + + + + +/****************************************************************************/ +#pragma warning( disable : 4100 ) + +void util_cmdline_cleanup( struct util_cmdline_state *cs ) +{ + assert( cs != NULL ); + + return; +} + +#pragma warning( default : 4100 ) + + + + + +/****************************************************************************/ +void util_cmdline_add_arg( struct util_cmdline_state *cs, char arg_letter, enum util_cmdline_arg_type arg_type ) +{ + lfds700_pal_uint_t + index; + + assert( cs != NULL ); + assert( arg_letter >= 'a' and arg_letter <= 'z' ); + // TRD : arg_type can be any value in its range + + index = arg_letter - 'a'; + + cs->args[index].arg_type = arg_type; + + if( arg_type == LIBCOMMON_CMDLINE_ARG_TYPE_FLAG ) + cs->args[index].arg_data.flag.flag = LOWERED; + + return; +} + + + + + +/****************************************************************************/ +int util_cmdline_process_args( struct util_cmdline_state *cs, int argc, char **argv ) +{ + char + *arg; + + int + arg_letter, + cc, + loop, + rv = 1; + + lfds700_pal_uint_t + index; + + assert( cs != NULL ); + assert( argc >= 1 ); + assert( argv != NULL ); + + for( loop = 1 ; loop < argc ; loop++ ) + { + arg = *(argv+loop); + + switch( *arg ) + { + case '-': + arg_letter = tolower( *(arg+1) ); + + if( arg_letter >= 'a' and arg_letter <= 'z' ) + { + index = arg_letter - 'a'; + + switch( cs->args[index].arg_type ) + { + case LIBCOMMON_CMDLINE_ARG_TYPE_INTEGER_RANGE: + if( loop+1 >= argc ) + rv = 0; + + if( loop+1 < argc ) + { + cc = sscanf( *(argv+loop+1), "%llu-%llu", &cs->args[index].arg_data.integer_range.integer_start, &cs->args[index].arg_data.integer_range.integer_end ); + + if( cc != 2 ) + rv = 0; + + if( cc == 2 ) + { + cs->args[index].processed_flag = RAISED; + loop++; + } + } + break; + + case LIBCOMMON_CMDLINE_ARG_TYPE_INTEGER: + if( loop+1 >= argc ) + rv = 0; + + if( loop+1 < argc ) + { + cc = sscanf( *(argv+loop+1), "%llu", &cs->args[index].arg_data.integer.integer ); + + if( cc != 1 ) + rv = 0; + + if( cc == 1 ) + { + cs->args[index].processed_flag = RAISED; + loop++; + } + } + break; + + case LIBCOMMON_CMDLINE_ARG_TYPE_FLAG: + cs->args[index].arg_data.flag.flag = RAISED; + cs->args[index].processed_flag = RAISED; + break; + + case LIBCOMMON_CMDLINE_ARG_TYPE_UNSET: + break; + } + } + break; + + default: + rv = 0; + break; + } + } + + return( rv ); +} + + + + + +/****************************************************************************/ +void util_cmdline_get_arg_data( struct util_cmdline_state *cs, char arg_letter, union util_cmdline_arg_data **arg_data ) +{ + lfds700_pal_uint_t + index; + + assert( cs != NULL ); + assert( arg_letter >= 'a' and arg_letter <= 'z' ); + assert( arg_data != NULL ); + + index = arg_letter - 'a'; + + if( cs->args[index].processed_flag == RAISED ) + *arg_data = &cs->args[index].arg_data; + else + *arg_data = NULL; + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_cmdline.h b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_cmdline.h new file mode 100644 index 0000000000..a19b073499 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_cmdline.h @@ -0,0 +1,69 @@ +/***** defines *****/ +#define NUMBER_OF_LOWERCASE_LETTERS_IN_LATIN_ALPHABET 26 + +/***** enums *****/ +enum util_cmdline_arg_type +{ + LIBCOMMON_CMDLINE_ARG_TYPE_INTEGER_RANGE, + LIBCOMMON_CMDLINE_ARG_TYPE_INTEGER, + LIBCOMMON_CMDLINE_ARG_TYPE_FLAG, + LIBCOMMON_CMDLINE_ARG_TYPE_UNSET +}; + +/***** structs *****/ +struct util_cmdline_arg_integer_range +{ + int long long unsigned + integer_start, + integer_end; +}; + +struct util_cmdline_arg_integer +{ + int long long unsigned + integer; +}; + +struct util_cmdline_arg_flag +{ + enum flag + flag; +}; + +union util_cmdline_arg_data +{ + struct util_cmdline_arg_integer_range + integer_range; + + struct util_cmdline_arg_integer + integer; + + struct util_cmdline_arg_flag + flag; +}; + +struct util_cmdline_arg_letter_and_data +{ + enum util_cmdline_arg_type + arg_type; + + enum flag + processed_flag; + + union util_cmdline_arg_data + arg_data; +}; + +struct util_cmdline_state +{ + struct util_cmdline_arg_letter_and_data + args[NUMBER_OF_LOWERCASE_LETTERS_IN_LATIN_ALPHABET]; +}; + +/***** public protoypes *****/ +void util_cmdline_init( struct util_cmdline_state *cs ); +void util_cmdline_cleanup( struct util_cmdline_state *cs ); +void util_cmdline_add_arg( struct util_cmdline_state *cs, char arg_letter, enum util_cmdline_arg_type arg_type ); +int util_cmdline_process_args( struct util_cmdline_state *cs, int argc, char **argv ); +void util_cmdline_get_arg_data( struct util_cmdline_state *cs, char arg_letter, union util_cmdline_arg_data **arg_data ); + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_memory_helpers.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_memory_helpers.c new file mode 100644 index 0000000000..3d4c0e79f4 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_memory_helpers.c @@ -0,0 +1,75 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +void *util_aligned_malloc( lfds700_pal_uint_t size, lfds700_pal_uint_t align_in_bytes ) +{ + lfds700_pal_uint_t + offset; + + void + *memory, + *original_memory; + + // TRD : size can be any value in its range + // TRD : align_in_bytes can be any value in its range + + /* TRD : helper function to provide aligned allocations + no porting required + */ + + original_memory = memory = util_malloc_wrapper( size + sizeof(void *) + align_in_bytes ); + + if( memory != NULL ) + { + memory = (void **) memory + 1; + offset = align_in_bytes - (lfds700_pal_uint_t) memory % align_in_bytes; + memory = (char unsigned *) memory + offset; + *( (void **) memory - 1 ) = original_memory; + } + + return( memory ); +} + + + + + +/****************************************************************************/ +void util_aligned_free( void *memory ) +{ + assert( memory != NULL ); + + // TRD : the "void *" stored above memory points to the root of the allocation + free( *( (void **) memory - 1 ) ); + + return; +} + + + + + +/****************************************************************************/ +void *util_malloc_wrapper( lfds700_pal_uint_t size ) +{ + void + *memory; + + // TRD : size can be any value in its range + + memory = malloc( size ); + + if( memory == NULL ) + { + puts( "malloc() failed, exiting." ); + exit( EXIT_FAILURE ); + } + + return( memory ); +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_memory_helpers.h b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_memory_helpers.h new file mode 100644 index 0000000000..8341a1f2e3 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_memory_helpers.h @@ -0,0 +1,5 @@ +/***** public prototypes *****/ +void *util_aligned_malloc( lfds700_pal_uint_t size, lfds700_pal_uint_t align_in_bytes ); +void util_aligned_free( void *memory ); +void *util_malloc_wrapper( lfds700_pal_uint_t size ); + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_thread_starter.c b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_thread_starter.c new file mode 100644 index 0000000000..c008fa2c5d --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_thread_starter.c @@ -0,0 +1,151 @@ +/***** includes *****/ +#include "internal.h" + + + + + +/****************************************************************************/ +void util_thread_starter_new( struct util_thread_starter_state **tts, lfds700_pal_uint_t number_threads ) +{ + lfds700_pal_uint_t + loop; + + assert( tts != NULL ); + // TRD : number_threads cam be any value in its range + + *tts = util_malloc_wrapper( sizeof(struct util_thread_starter_state) ); + + (*tts)->tsts = util_malloc_wrapper( sizeof(struct util_thread_starter_thread_state) * number_threads ); + (*tts)->thread_start_flag = LOWERED; + (*tts)->number_thread_states = number_threads; + + for( loop = 0 ; loop < number_threads ; loop++ ) + { + ((*tts)->tsts+loop)->thread_ready_flag = LOWERED; + ((*tts)->tsts+loop)->thread_start_flag = &(*tts)->thread_start_flag; + } + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return; +} + + + + + +/****************************************************************************/ +void util_thread_starter_start( struct util_thread_starter_state *tts, + test_pal_thread_state_t *thread_state, + lfds700_pal_uint_t thread_number, + struct test_pal_logical_processor *lp, + test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)( void *thread_user_state ), + void *thread_user_state ) +{ + assert( tts != NULL ); + assert( thread_state != NULL ); + assert( lp != NULL ); + assert( thread_function != NULL ); + // TRD : thread_user_state can be NULL + + (tts->tsts+thread_number)->thread_user_state = thread_user_state; + + util_thread_start_wrapper( thread_state, lp, thread_function, tts->tsts+thread_number ); + + // TRD : wait for the thread to indicate it is ready and waiting + while( (tts->tsts+thread_number)->thread_ready_flag == LOWERED ); + + return; +} + + + + + +/****************************************************************************/ +void util_thread_starter_ready_and_wait( struct util_thread_starter_thread_state *tsts ) +{ + assert( tsts != NULL ); + + tsts->thread_ready_flag = RAISED; + + LFDS700_MISC_BARRIER_FULL; + + // TRD : threads here are all looping, so we don't need to force a store + + while( *tsts->thread_start_flag == LOWERED ) + LFDS700_MISC_BARRIER_LOAD; + + return; +} + + + + + +/****************************************************************************/ +void util_thread_starter_run( struct util_thread_starter_state *tts ) +{ + assert( tts != NULL ); + + /* TRD : all threads at this point are ready to go + as we wait for their ready flag immediately after their spawn + */ + + tts->thread_start_flag = RAISED; + + LFDS700_MISC_BARRIER_STORE; + + lfds700_misc_force_store(); + + return; +} + + + + + +/****************************************************************************/ +void util_thread_starter_delete( struct util_thread_starter_state *tts ) +{ + assert( tts != NULL ); + + free( tts->tsts ); + + free( tts ); + + return; +} + + + + + +/****************************************************************************/ +void util_thread_start_wrapper( test_pal_thread_state_t *thread_state, + struct test_pal_logical_processor *lp, + test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state), + void *thread_user_state ) +{ + int + rv; + + assert( thread_state != NULL ); + assert( lp != NULL ); + assert( thread_function != NULL ); + // TRD : thread_user_state can be NULL + + rv = test_pal_thread_start( thread_state, lp, thread_function, thread_user_state ); + + if( rv == 0 ) + { + puts( "test_pal_thread_start() failed." ); + exit( EXIT_FAILURE ); + } + + return; +} + diff --git a/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_thread_starter.h b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_thread_starter.h new file mode 100644 index 0000000000..5587edf1c0 --- /dev/null +++ b/openair2/UTIL/LFDS/liblfds7.0.0/test/src/util_thread_starter.h @@ -0,0 +1,41 @@ +/***** structs *****/ +struct util_thread_starter_thread_state +{ + // TRD : must be volatile or the compiler optimizes it away into a single load + enum flag volatile + thread_ready_flag, + *thread_start_flag; + + void + *thread_user_state; +}; + +struct util_thread_starter_state +{ + enum flag volatile + thread_start_flag; + + lfds700_pal_uint_t + number_thread_states; + + struct util_thread_starter_thread_state + *tsts; +}; + +/***** prototypes *****/ +void util_thread_starter_new( struct util_thread_starter_state **tts, lfds700_pal_uint_t number_threads ); +void util_thread_starter_start( struct util_thread_starter_state *tts, + test_pal_thread_state_t *thread_state, + lfds700_pal_uint_t thread_number, + struct test_pal_logical_processor *lp, + test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)( void *thread_user_state ), + void *thread_user_state ); +void util_thread_starter_ready_and_wait( struct util_thread_starter_thread_state *tsts ); +void util_thread_starter_run( struct util_thread_starter_state *tts ); +void util_thread_starter_delete( struct util_thread_starter_state *tts ); + +void util_thread_start_wrapper( test_pal_thread_state_t *thread_state, + struct test_pal_logical_processor *lp, + test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state), + void *thread_user_state ); + From a8d646b10894d99ce7d28ea55328e9824741a1e9 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 26 Feb 2016 17:30:54 +0000 Subject: [PATCH 128/413] Added agent support for remote scheduler --- cmake_targets/CMakeLists.txt | 5 +- openair2/ENB_APP/enb_agent.c | 5 + openair2/ENB_APP/enb_agent_handler.c | 7 +- openair2/ENB_APP/enb_agent_mac.c | 62 ++++++++ openair2/ENB_APP/enb_agent_mac.h | 8 + openair2/ENB_APP/enb_agent_mac_defs.h | 8 +- .../MAC/eNB_agent_scheduler_dataplane.c | 2 +- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 14 +- .../MAC/eNB_agent_scheduler_dlsch_ue_remote.c | 142 ++++++++++++++++++ .../MAC/eNB_agent_scheduler_dlsch_ue_remote.h | 76 ++++++++++ openair2/LAYER2/MAC/eNB_scheduler.c | 74 ++++----- openair2/LAYER2/MAC/enb_agent_mac_proto.h | 5 +- 12 files changed, 343 insertions(+), 65 deletions(-) create mode 100644 openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c create mode 100644 openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index e4b027958d..18eaf0f8b6 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1099,7 +1099,8 @@ set (MAC_SRC ${MAC_DIR}/config.c ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue.c ${MAC_DIR}/eNB_agent_scheduler_dataplane.c - ) + ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue_remote.c + ) set (ENB_APP_SRC ${OPENAIR2_DIR}/ENB_APP/enb_app.c @@ -1113,7 +1114,7 @@ add_library(L2 ${OPENAIR2_DIR}/RRC/L2_INTERFACE/openair_rrc_L2_interface.c) #Test for adding a shared library -add_library(alt_sched SHARED ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue_alt.c) +#add_library(alt_sched SHARED ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue_alt.c) # L3 Libs ########################## diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index 95731d3654..a21e2f8e16 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -276,6 +276,11 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ */ enb_agent_init_timer(); + + /* + * Initialize the mac agent + */ + enb_agent_init_mac_agent(mod_id); /* * start the enb agent task for tx and interaction with the underlying network function diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index d4e5706b11..721b3678f8 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -55,7 +55,7 @@ enb_agent_message_decoded_callback agent_messages_callback[][3] = { {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG*/ {enb_agent_lc_config_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REQUEST_MSG*/ {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG*/ - {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG*/ + {enb_agent_mac_handle_dl_mac_config, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG*/ {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG*/ {enb_agent_control_delegation, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_CONTROL_DELEGATION_MSG*/ @@ -116,10 +116,9 @@ Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, err_code = ((*agent_messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1])(mod_id, (void *) decoded_message, &reply_message)); if ( err_code < 0 ){ goto error; + } else if (err_code == 1) { //If err_code > 1, we do not want to dispose the message yet + protocol__progran_message__free_unpacked(decoded_message, NULL); } - - protocol__progran_message__free_unpacked(decoded_message, NULL); - return reply_message; error: diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 7be6e6ba12..fa190bbf29 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -42,6 +42,8 @@ #include "LAYER2/MAC/proto.h" #include "LAYER2/MAC/enb_agent_mac_proto.h" +#include "liblfds700.h" + #include "log.h" @@ -51,6 +53,13 @@ unsigned int mac_agent_registered[NUM_MAX_ENB]; /*Array containing the Agent-MAC interfaces*/ AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB]; +/* Ringbuffer related structs used for maintaining the dl mac config messages */ +//message_queue_t *dl_mac_config_queue; +struct lfds700_misc_prng_state ps[NUM_MAX_ENB]; +struct lfds700_ringbuffer_element *dl_mac_config_array[NUM_MAX_ENB]; +struct lfds700_ringbuffer_state ringbuffer_state[NUM_MAX_ENB]; + + int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg){ // TODO: Must deal with sanitization of input @@ -1154,6 +1163,56 @@ int enb_agent_mac_destroy_dl_config(Protocol__ProgranMessage *msg) { return -1; } +void enb_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__ProgranMessage **msg) { + + struct lfds700_misc_prng_state ls; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + lfds700_misc_prng_init(&ls); + + if (lfds700_ringbuffer_read(&ringbuffer_state[mod_id], NULL, (void **) msg, &ls) == 0) { + *msg = NULL; + } +} + +int enb_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { + + struct lfds700_misc_prng_state ls; + enum lfds700_misc_flag overwrite_occurred_flag; + Protocol__ProgranMessage *overwritten_dl_config; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + lfds700_misc_prng_init(&ls); + + lfds700_ringbuffer_write( &ringbuffer_state[mod_id], + NULL, + (void *) params, + &overwrite_occurred_flag, + NULL, + (void **)&overwritten_dl_config, + &ls); + + if (overwrite_occurred_flag == LFDS700_MISC_FLAG_RAISED) { + // Delete unmanaged dl_config + enb_agent_mac_destroy_dl_config(overwritten_dl_config); + } + *msg = NULL; + return 2; + + error: + *msg = NULL; + return -1; +} + +void enb_agent_init_mac_agent(mid_t mod_id) { + lfds700_misc_library_init_valid_on_current_logical_core(); + lfds700_misc_prng_init(&ps[mod_id]); + int num_elements = RINGBUFFER_SIZE + 1; + //Allow RINGBUFFER_SIZE messages to be stored in the ringbuffer at any time + dl_mac_config_array[mod_id] = malloc( sizeof(struct lfds700_ringbuffer_element) * num_elements); + lfds700_ringbuffer_init_valid_on_current_logical_core( &ringbuffer_state[mod_id], dl_mac_config_array[mod_id], num_elements, &ps[mod_id], NULL ); +} + /*********************************************** * eNB agent - technology mac API implementation ***********************************************/ @@ -1284,6 +1343,7 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_send_sf_trigger = enb_agent_send_sf_trigger; xface->enb_agent_send_update_mac_stats = enb_agent_send_update_mac_stats; xface->enb_agent_schedule_ue_spec = schedule_ue_spec_default; + xface->enb_agent_get_pending_dl_mac_config = enb_agent_get_pending_dl_mac_config; xface->enb_agent_notify_ue_state_change = enb_agent_ue_state_change; mac_agent_registered[mod_id] = 1; @@ -1299,6 +1359,8 @@ int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_send_sf_trigger = NULL; xface->enb_agent_send_update_mac_stats = NULL; xface->enb_agent_schedule_ue_spec = NULL; + xface->enb_agent_get_pending_dl_mac_config = NULL; + xface->enb_agent_notify_ue_state_change = NULL; mac_agent_registered[mod_id] = 0; agent_mac_xface[mod_id] = NULL; diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index 221d76e57f..2a8f4c3a40 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -76,6 +76,9 @@ typedef struct stats_request_config_s{ report_config_t *config; } stats_request_config_t; +/* Initialization function for the agent structures etc */ +void enb_agent_init_mac_agent(mid_t mod_id); + int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); int enb_agent_mac_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__ProgranMessage **msg); @@ -98,6 +101,8 @@ int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__ProgranMessage int enb_agent_mac_destroy_dl_config(Protocol__ProgranMessage *msg); +int enb_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); + /********************************** * eNB agent - technology mac API @@ -113,6 +118,9 @@ void enb_agent_send_sf_trigger(mid_t mod_id); /// based on the stats request configuration void enb_agent_send_update_mac_stats(mid_t mod_id); +/// Provide to the scheduler a pending dl_mac_config message +void enb_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__ProgranMessage **msg); + /*Register technology specific interface callbacks*/ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface); diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/enb_agent_mac_defs.h index 657fc94fe4..c5a3204f0c 100644 --- a/openair2/ENB_APP/enb_agent_mac_defs.h +++ b/openair2/ENB_APP/enb_agent_mac_defs.h @@ -42,6 +42,8 @@ #include "progran.pb-c.h" #include "header.pb-c.h" +#define RINGBUFFER_SIZE 100 + /* ENB AGENT-MAC Interface */ typedef struct { //msg_context_t *agent_ctxt; @@ -56,11 +58,15 @@ typedef struct { /// based on the stats request configuration void (*enb_agent_send_update_mac_stats)(mid_t mod_id); + /// Provide to the scheduler a pending dl_mac_config message + void (*enb_agent_get_pending_dl_mac_config)(mid_t mod_id, + Protocol__ProgranMessage **msg); + /// Run the UE DL scheduler and fill the Protocol__ProgranMessage. Assumes that /// dl_info is already initialized as prp_dl_mac_config and fills the /// prp_dl_data part of it void (*enb_agent_schedule_ue_spec)(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__ProgranMessage *dl_info); + int *mbsfn_flag, Protocol__ProgranMessage **dl_info); /// Notify the controller for a state change of a particular UE, by sending the proper diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c index 04efcb44ad..a1bd039dff 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c @@ -69,7 +69,7 @@ void apply_dl_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, - Protocol__ProgranMessage *dl_scheduling_info) { + const Protocol__ProgranMessage *dl_scheduling_info) { Protocol__PrpDlMacConfig *mac_config = dl_scheduling_info->dl_mac_config_msg; diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index 4d353232a8..5031867394 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -64,6 +64,7 @@ #include "header.pb-c.h" #include "progran.pb-c.h" +#include "enb_agent_mac.h" #include "SIMULATION/TOOLS/defs.h" // for taus @@ -80,7 +81,7 @@ schedule_ue_spec_default( uint32_t frame, uint32_t subframe, int *mbsfn_flag, - Protocol__ProgranMessage *dl_info + Protocol__ProgranMessage **dl_info ) //------------------------------------------------------------------------------ { @@ -126,11 +127,12 @@ schedule_ue_spec_default( uint8_t ue_has_transmission = 0; uint32_t ndi; - + enb_agent_mac_create_empty_dl_config(mod_id, dl_info); + if (UE_list->head==-1) { return; } - + start_meas(&eNB->schedule_dlsch); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_IN); @@ -763,10 +765,10 @@ schedule_ue_spec_default( } // CC_id loop // Add all the dl_data elements to the progran message - dl_info->dl_mac_config_msg->n_dl_ue_data = num_ues_added; - dl_info->dl_mac_config_msg->dl_ue_data = (Protocol__PrpDlData **) malloc(sizeof(Protocol__PrpDlData *) * num_ues_added); + (*dl_info)->dl_mac_config_msg->n_dl_ue_data = num_ues_added; + (*dl_info)->dl_mac_config_msg->dl_ue_data = (Protocol__PrpDlData **) malloc(sizeof(Protocol__PrpDlData *) * num_ues_added); for (i = 0; i < num_ues_added; i++) { - dl_info->dl_mac_config_msg->dl_ue_data[i] = dl_data[i]; + (*dl_info)->dl_mac_config_msg->dl_ue_data[i] = dl_data[i]; } stop_meas(&eNB->schedule_dlsch); diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c new file mode 100644 index 0000000000..1818a64087 --- /dev/null +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c @@ -0,0 +1,142 @@ +/******************************************************************************* + 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ + +/*! \file eNB_agent_scheduler_dlsch_ue_remote.c + * \brief procedures related to remote scheduling in the DLSCH transport channel + * \author Xenofon Foukas + * \date 2016 + * \email: x.foukas@sms.ed.ac.uk + * \version 0.1 + * @ingroup _mac + + */ + +#include "eNB_agent_scheduler_dlsch_ue_remote.h" + +struct DlMacConfigHead queue_head; + +int queue_initialized = 0; + +void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, + int *mbsfn_flag, Protocol__ProgranMessage **dl_info) { + + if (queue_initialized) { + TAILQ_INIT(&queue_head); + queue_initialized = 1; + } + + dl_mac_config_element_t *dl_config_elem; + + int diff; + + // First we check to see if we have a scheduling decision for this sfn_sf already in our queue + while(queue_head.tqh_first != NULL) { + dl_config_elem = queue_head.tqh_first; + diff = get_sf_difference(mod_id, dl_config_elem->dl_info->dl_mac_config_msg->sfn_sf); + // Check if this decision is for now, for a later or a previous subframe + if ( diff == 0) { // Now + TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs); + *dl_info = dl_config_elem->dl_info; + free(dl_config_elem); + return; + } else if (diff < 0) { //previous subframe , delete message and free memory + TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs); + enb_agent_mac_destroy_dl_config(dl_config_elem->dl_info); + free(dl_config_elem); + } else { // next subframe, nothing to do now + enb_agent_create_empty_dl_config(mod_id, dl_info); + return; + } + } + + //Done with the local cache. Now we need to check if something new arrived + enb_agent_get_pending_dl_mac_config(mod_id, dl_info); + while (*dl_info != NULL) { + + diff = get_sf_difference(mod_id, (*dl_info)->dl_mac_config_msg->sfn_sf); + if (diff == 0) { // Got a command for this sfn_sf + return; + } else if (diff < 0) { + enb_agent_mac_destroy_dl_config(*dl_info); + } else { // Intended for future subframe. Store it in local cache + dl_mac_config_element_t *e = malloc(sizeof(dl_mac_config_element_t)); + TAILQ_INSERT_TAIL(&queue_head, e, configs); + enb_agent_create_empty_dl_config(mod_id, dl_info); + // No need to look for another. Messages arrive ordered + return; + } + enb_agent_get_pending_dl_mac_config(mod_id, dl_info); + } + + // We found no pending command, so we will simply pass an empty one + enb_agent_create_empty_dl_config(mod_id, dl_info); +} + +int get_sf_difference(mid_t mod_id, uint16_t sfn_sf) { + int diff_in_subframes; + + uint16_t current_frame = get_current_system_frame_num(mod_id); + uint16_t current_subframe = get_current_subframe(mod_id); + uint16_t current_sfn_sf = get_sfn_sf(mod_id); + + if (sfn_sf == current_sfn_sf) { + return 0; + } + + uint16_t frame_mask = !((1<<4) - 1); + uint16_t frame = (sfn_sf & frame_mask) >> 4; + + uint16_t sf_mask = !(((1<<12) - 1) << 4); + uint16_t subframe = (sfn_sf & sf_mask); + + if (frame == current_frame) { + return subframe - current_subframe; + } else if (frame > current_frame) { + diff_in_subframes = 9 - current_subframe; + diff_in_subframes += subframe; + diff_in_subframes += (frame-2) * 10; + if (diff_in_subframes > SCHED_AHEAD_SUBFRAMES) { + return -1; + } else { + return 1; + } + } else { //frame < current_frame + diff_in_subframes = 9 - current_subframe; + diff_in_subframes += subframe; + if (frame > 0) { + diff_in_subframes += (frame - 1) * 10; + } + diff_in_subframes += (1023 - current_frame) * 10; + if (diff_in_subframes > SCHED_AHEAD_SUBFRAMES) { + return -1; + } else { + return 1; + } + } +} diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h new file mode 100644 index 0000000000..2b8ec3ec19 --- /dev/null +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h @@ -0,0 +1,76 @@ +/******************************************************************************* + 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ + +/*! \file eNB_agent_scheduler_dlsch_ue_remote.h + * \brief Local stub for remote scheduler used by the controller + * \author Xenofon Foukas + * \date 2016 + * \email: x.foukas@sms.ed.ac.uk + * \version 0.1 + * @ingroup _mac + + */ + +#ifndef __LAYER2_MAC_ENB_AGENT_SCHEDULER_DLSCH_UE_REMOTE_H__ +#define __LAYER2_MAC_ENB_AGENT_SCHEDULER_DLSCH_UE_REMOTE_H___ + +#include "progran.pb-c.h" +#include "header.pb-c.h" + +#include "ENB_APP/enb_agent_defs.h" +#include "enb_agent_mac.h" + +#include + +// Maximum value of schedule ahead of time +// Required to identify if a dl_command is for the future or not +#define SCHED_AHEAD_SUBFRAMES 10 + +typedef struct dl_mac_config_element_s { + Protocol__ProgranMessage *dl_info; + TAILQ_ENTRY(dl_mac_config_element_s) configs; +} dl_mac_config_element_t; + +TAILQ_HEAD(DlMacConfigHead, dl_mac_config_element_s); + +/* + * Default scheduler used by the eNB agent + */ +void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, + int *mbsfn_flag, Protocol__ProgranMessage **dl_info); + + +// Find the difference in subframes from the given subframe +// negative for older value +// 0 for equal +// positive for future value +// Based on +int get_sf_difference(mid_t mod_id, uint16_t sfn_sf); + +#endif diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index e2423e2c10..9a172cb377 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -281,13 +281,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -330,13 +329,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -361,13 +359,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -398,13 +395,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -427,13 +423,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -471,13 +466,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -502,13 +496,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -539,13 +532,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -567,13 +559,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -620,13 +611,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -645,13 +635,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -673,13 +662,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -707,13 +695,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -731,13 +718,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -759,13 +745,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -798,13 +783,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -826,13 +810,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -859,13 +842,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -885,13 +867,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -911,13 +892,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -937,13 +917,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, frameP, @@ -965,19 +944,18 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - enb_agent_mac_create_empty_dl_config(module_idP, &msg); agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( module_idP, frameP, subframeP, mbsfn_status, - msg); + &msg); apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); + frameP, + subframeP, + mbsfn_status, + msg); enb_agent_mac_destroy_dl_config(msg); } #endif diff --git a/openair2/LAYER2/MAC/enb_agent_mac_proto.h b/openair2/LAYER2/MAC/enb_agent_mac_proto.h index 7fcdbc29c3..f453fa2fa3 100644 --- a/openair2/LAYER2/MAC/enb_agent_mac_proto.h +++ b/openair2/LAYER2/MAC/enb_agent_mac_proto.h @@ -48,14 +48,13 @@ * Default scheduler used by the eNB agent */ void schedule_ue_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__ProgranMessage *dl_info); - + int *mbsfn_flag, Protocol__ProgranMessage **dl_info); /* * Data plane function for applying the DL decisions of the scheduler */ void apply_dl_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, - Protocol__ProgranMessage *dl_scheduling_info); + const Protocol__ProgranMessage *dl_scheduling_info); /* * Data plane function for applying the UE specific DL decisions of the scheduler From c7c9da4296f2e2282cb3c9b214efa42d3ac9bfa0 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 29 Feb 2016 14:53:15 +0100 Subject: [PATCH 129/413] cosmetic changes to enable multiple antenna transmission --- cmake_targets/CMakeLists.txt | 2 +- openair2/ENB_APP/enb_config.c | 8 ++++---- targets/RT/USER/lte-softmodem.c | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index a94da4b2b8..5a679cdf4a 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -119,7 +119,7 @@ endmacro(add_list_string_option) #################################################### # compilation flags ############################################# -set(CMAKE_BUILD_TYPE "Debug") +#set(CMAKE_BUILD_TYPE "Debug") if (CMAKE_BUILD_TYPE STREQUAL "") set(CMAKE_BUILD_TYPE "RelWithDebInfo") endif() diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index b437c7e264..0aa980a8a3 100755 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -938,16 +938,16 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) enb_properties.properties[enb_properties_index]->nb_antennas_tx[j] = nb_antennas_tx; - if ((nb_antennas_tx <1) || (nb_antennas_tx > 4)) + if ((nb_antennas_tx <1) || (nb_antennas_tx > 64)) AssertError (0, parse_errors ++, - "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for nb_antennas_tx choice: 1..4 !\n", + "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for nb_antennas_tx choice: 1..64 !\n", lib_config_file_name_pP, i, nb_antennas_tx); enb_properties.properties[enb_properties_index]->nb_antennas_rx[j] = nb_antennas_rx; - if ((nb_antennas_rx <1) || (nb_antennas_rx > 4)) + if ((nb_antennas_rx <1) || (nb_antennas_rx > 64)) AssertError (0, parse_errors ++, - "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for nb_antennas_rx choice: 1..4 !\n", + "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for nb_antennas_rx choice: 1..64 !\n", lib_config_file_name_pP, i, nb_antennas_rx); enb_properties.properties[enb_properties_index]->tx_gain[j] = tx_gain; diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index cf1a374dae..72d32fbdef 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -2393,8 +2393,8 @@ static void get_options (int argc, char **argv) case 'x': transmission_mode = atoi(optarg); - if (transmission_mode > 2) { - printf("Transmission mode > 2 (%d) not supported for the moment\n",transmission_mode); + if (transmission_mode > 2 && transmission_mode != 7) { + printf("Transmission mode %d not supported for the moment\n",transmission_mode); exit(-1); } break; @@ -2476,7 +2476,7 @@ static void get_options (int argc, char **argv) frame_parms[CC_id]->N_RB_DL = enb_properties->properties[i]->N_RB_DL[CC_id]; frame_parms[CC_id]->N_RB_UL = enb_properties->properties[i]->N_RB_DL[CC_id]; frame_parms[CC_id]->nb_antennas_tx = enb_properties->properties[i]->nb_antennas_tx[CC_id]; - frame_parms[CC_id]->nb_antenna_ports_eNB = enb_properties->properties[i]->nb_antennas_tx[CC_id]; + frame_parms[CC_id]->nb_antenna_ports_eNB = 1;//enb_properties->properties[i]->nb_antenna_ports_eNB[CC_id]; frame_parms[CC_id]->nb_antennas_rx = enb_properties->properties[i]->nb_antennas_rx[CC_id]; //} // j } From f02e6ca52634768748762084ca35a4a41799e75a Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 29 Feb 2016 17:15:26 +0100 Subject: [PATCH 130/413] add beamforming function --- openair1/PHY/LTE_TRANSPORT/beamforming.c | 211 +++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 openair1/PHY/LTE_TRANSPORT/beamforming.c diff --git a/openair1/PHY/LTE_TRANSPORT/beamforming.c b/openair1/PHY/LTE_TRANSPORT/beamforming.c new file mode 100644 index 0000000000..7a2b75d74e --- /dev/null +++ b/openair1/PHY/LTE_TRANSPORT/beamforming.c @@ -0,0 +1,211 @@ +/******************************************************************************* + 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@eurecom.fr + +Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + + *******************************************************************************/ + +/*! \file PHY/LTE_TRANSPORT/beamforming.c + * \brief + * \author R. Knopp, F. Kaltenberger, X. JIANG + * \date 2015 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,xiwen.jiang@eurecom.fr + * \note + * \warning + */ +#include "PHY/defs.h" +#include "PHY/extern.h" +#include "PHY/CODING/defs.h" +#include "PHY/CODING/extern.h" +#include "PHY/CODING/lte_interleaver_inline.h" +#include "PHY/LTE_TRANSPORT/defs.h" +#include "defs.h" +#include "UTIL/LOG/vcd_signal_dumper.h" + + +// ue_spec_beamforming: perform beamforming for data in transmission_mode TM7-TM10 +int ue_spec_beamforming(int32_t **txdataF, + int32_t **txdataF_BF, + LTE_DL_FRAME_PARMS *frame_parms, + int32_t ***ue_spec_bf_weights, + int slot, + int symbol) +{ + uint8_t p,aa; + uint16_t re=0; + int slot_offset_F; + + slot_offset_F = slot*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); + + // clear txdata_BF[aa][re] for each call of spec_spec_beamforming + for(aa=0;aanb_antennas_tx;aa++) + memset(txdataF_BF[aa],0,4*(frame_parms->ofdm_symbol_size)); + + for (re=0;reofdm_symbol_size;re++) { + if (txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually using TM7 + for (aa=0;aanb_antennas_tx;aa++) { + ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0] + *((int16_t*)&ue_spec_bf_weights[0][aa][re])[0])>>15); + ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1] + *((int16_t*)&ue_spec_bf_weights[0][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0] + *((int16_t*)&ue_spec_bf_weights[0][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1] + *((int16_t*)&ue_spec_bf_weights[0][aa][re])[0])>>15); + +/* printf("beamforming.c:txdataF[5][%d]=%d+j%d, ue_bf_weights[0][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", + slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re, + ((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0], + ((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1], + aa,re, + ((int16_t*)&ue_spec_bf_weights[0][aa][re])[0],((int16_t*)&ue_spec_bf_weights[0][aa][re])[1], + aa,re, + ((int16_t*)&txdataF_BF[aa][re])[0], + ((int16_t*)&txdataF_BF[aa][re])[1]); */ + } + } + + if (txdataF[7][re+symbol*frame_parms->ofdm_symbol_size]!=0) { //that means this RE is actually using TM8-10 + for (p=0;p<8;p++) { + if (txdataF[p+7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually allocated + for (aa=0;aanb_antennas_tx;aa++) { + ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[p+7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0] + *((int16_t*)&ue_spec_bf_weights[p][aa][re])[0])>>15); + ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[p+7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1] + *((int16_t*)&ue_spec_bf_weights[p][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[p+7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0] + *((int16_t*)&ue_spec_bf_weights[p][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p+7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1] + *((int16_t*)&ue_spec_bf_weights[p][aa][re])[0])>>15); + } + } + } + } + } +} + +// cell_spec_beamforming: performed for all common data +int cell_spec_beamforming(int32_t **txdataF, + int32_t **txdataF_BF, + LTE_DL_FRAME_PARMS *frame_parms, + int32_t ***cell_spec_bf_weights, + int slot, + int symbol) +{ + uint8_t p,aa; + uint16_t re=0; + int slot_offset_F; + + slot_offset_F = slot*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); + + // clear txdata_BF[aa][re] for each call of cell_spec_beamforming + for(aa=0;aanb_antennas_tx;aa++) + memset(txdataF_BF[aa],0,4*(frame_parms->ofdm_symbol_size)); + + for (re=0;reofdm_symbol_size;re++) { + for (p=0;pnb_antenna_ports_eNB;p++) { + if (txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually allocated + for (aa=0;aanb_antennas_tx;aa++) { + //printf("cell_spec_beamforming():txdata_BF[%d][%d]=%d+j%d\n",aa,re,((int16_t*)&txdataF_BF[aa][re])[0],((int16_t*)&txdataF_BF[aa][re])[1]); + + ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0] + *((int16_t*)&cell_spec_bf_weights[p][aa][re])[0])>>15); + ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1] + *((int16_t*)&cell_spec_bf_weights[p][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0] + *((int16_t*)&cell_spec_bf_weights[p][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1] + *((int16_t*)&cell_spec_bf_weights[p][aa][re])[0])>>15); + // printf("beamforming.c:txdata[%d][%d]=%d+j%d, cell_bf_weights[%d][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", + // p,slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re, + // ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0], + // ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1], + // p,aa,re, + // ((int16_t*)&cell_spec_bf_weights[p][aa][re])[0],((int16_t*)&cell_spec_bf_weights[p][aa][re])[1], + // aa,re, + // ((int16_t*)&txdataF_BF[aa][re])[0], + // ((int16_t*)&txdataF_BF[aa][re])[1]); + } + } + } + } +} +/* +int ue_spec_beamforming(int32_t **txdataF, + int32_t **txdataF_BF, + LTE_DL_FRAME_PARMS *frame_parms, + LTE_eNB_DLSCH_t *dlsch0, + LTE_eNB_DLSCH_t *dlsch1, + int symbol) +{ + uint8_t p,aa; + uint16_t re=0; + + uint8_t harq_pid = dlsch0->current_harq_pid; + LTE_DL_eNB_HARQ_t *dlsch0_harq = dlsch0->harq_processes[harq_pid]; + LTE_DL_eNB_HARQ_t *dlsch1_harq; //= dlsch1->harq_processes[harq_pid]; + MIMO_mode_t mimo_mode = dlsch0_harq->mimo_mode; + int first_layer0 = dlsch0_harq->first_layer; + int Nlayers0 = dlsch0_harq->Nlayers; + + // Fill these in later for TM8-10 + int Nlayers1; + int first_layer1; + + if (dlsch1_harq) { + Nlayers1 = dlsch1_harq->Nlayers; + first_layer1 = dlsch1_harq->first_layer; + } + + //temp + if(mimo_mode==TM7){ + first_layer0 = 5; + Nlayers0=1; + } + + for (re=0;renb_antennas_tx;aa++) { + txdataF_BF[aa][re] += txdataF[p][re]*dlsch0->uespec_bf_weights[p][aa][re]; + } + } + } + + if(dlsch1_harq) { + for (p=first_layer1;pnb_antennas_tx;aa++) { + txdataF_BF[aa][re] += txdataF[p][re]*dlsch1->uespec_bf_weights[p][aa][re]; + } + } + } + } + + } +} */ From ea13be85b9ad0bccd55a0e8a4e6d9f7cfb885155 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 29 Feb 2016 17:49:33 +0100 Subject: [PATCH 131/413] enable n_tx=8 in dlsim.c --- openair1/SIMULATION/LTE_PHY/dlsim.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 7b38162784..6e2cafe8f9 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -601,10 +601,10 @@ int main(int argc, char **argv) } } - //if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=8 && n_tx_phy!=16 && n_tx_phy!=64 && n_tx_phy!=128)) { - if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=16 && n_tx_phy!=64)) { + if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=8 && n_tx_phy!=16 && n_tx_phy!=64 && n_tx_phy!=128)) { + // if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=16 && n_tx_phy!=64)) { msg("Physical number of antennas not supported for TM7.\n"); - exit(-1); + exit(-1); } break; @@ -715,7 +715,7 @@ int main(int argc, char **argv) for(re=0;reofdm_symbol_size;re++) { if (n_tx_phy==1 || n_tx_phy==2) cell_spec_bf_weights[aa][re] = 0x00007fff; - else if (n_tx_phy==4) + else if (n_tx_phy==4 || n_tx_phy==8) cell_spec_bf_weights[aa][re] = 0x00007fff>>1; else if (n_tx_phy==16) cell_spec_bf_weights[aa][re] = 0x00007fff>>2; From e3e30fbf07dd9747e29b66125bf70f6d8419736c Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 29 Feb 2016 18:16:12 +0100 Subject: [PATCH 132/413] add tm7 eNB config file --- .../CONF/enb.band38.tm7.exmimo2.conf | 169 ++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm7.exmimo2.conf diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm7.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm7.exmimo2.conf new file mode 100644 index 0000000000..deff3db9dd --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm7.exmimo2.conf @@ -0,0 +1,169 @@ +Active_eNBs = ( "eNB_Eurecom_LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB_Eurecom_LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = "1"; + + mobile_country_code = "208"; + + mobile_network_code = "93"; + + ////////// Physical parameters: + + component_carriers = ( + { + frame_type = "TDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 38; + downlink_frequency = 2580000000L; + uplink_frequency_offset = 0; //-120000000; + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antennas_tx = 4; + nb_antennas_rx = 4; + tx_gain = 10; //25; + rx_gain = 10; //20; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = -26; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 0; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -85; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -108; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 2; + rach_preambleInitialReceivedTargetPower = -100; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + } + ); + + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.12.70"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.212/24"; + + ENB_INTERFACE_NAME_FOR_S1U = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.212/24"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="debug"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="debug"; + rrc_log_verbosity ="medium"; + }; + } +); From 4a04aeb2aada32731ad5ee138efe2cbbe32e38ef Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 1 Mar 2016 13:08:29 +0000 Subject: [PATCH 133/413] Fixed bug in decoding frame and subframe number from sfn_sf field --- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c index 1818a64087..7f4ce23f9e 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c @@ -109,17 +109,17 @@ int get_sf_difference(mid_t mod_id, uint16_t sfn_sf) { return 0; } - uint16_t frame_mask = !((1<<4) - 1); - uint16_t frame = (sfn_sf & frame_mask) >> 4; + uint16_t frame_mask = ((1<<12) - 1); + uint16_t frame = (sfn_sf & (frame_mask << 4)) >> 4; - uint16_t sf_mask = !(((1<<12) - 1) << 4); + uint16_t sf_mask = ((1<<4) - 1); uint16_t subframe = (sfn_sf & sf_mask); if (frame == current_frame) { return subframe - current_subframe; } else if (frame > current_frame) { diff_in_subframes = 9 - current_subframe; - diff_in_subframes += subframe; + diff_in_subframes += (subframe + 1); diff_in_subframes += (frame-2) * 10; if (diff_in_subframes > SCHED_AHEAD_SUBFRAMES) { return -1; @@ -128,7 +128,7 @@ int get_sf_difference(mid_t mod_id, uint16_t sfn_sf) { } } else { //frame < current_frame diff_in_subframes = 9 - current_subframe; - diff_in_subframes += subframe; + diff_in_subframes += (subframe + 1); if (frame > 0) { diff_in_subframes += (frame - 1) * 10; } From bbd125a778e6cabc562779bb2c9d64d0e65941bc Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 1 Mar 2016 15:40:43 +0100 Subject: [PATCH 134/413] bug fixed for ULSIM --- openair1/SIMULATION/LTE_PHY/ulsim.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 8ba3434f48..47e41f3e85 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -28,7 +28,7 @@ *******************************************************************************/ /*! \file ulsim.c - \brief Top-level DL simulator + \brief Top-level UL simulator \author R. Knopp \date 2011 - 2014 \version 0.1 @@ -468,6 +468,7 @@ int main(int argc, char **argv) } lte_param_init(1, + 1, n_rx, 1, extended_prefix_flag, From 71b76934293a7f54a89b33dcc5266d44c2e9cde1 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 1 Mar 2016 15:41:07 +0100 Subject: [PATCH 135/413] change back 'p' and 'q' options for dlsim --- openair1/SIMULATION/LTE_PHY/dlsim.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 6e2cafe8f9..ba7d02b340 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -447,7 +447,7 @@ int main(int argc, char **argv) n_ch_rlz= atof(optarg); break; - case 'q': + case 'p': extended_prefix_flag=1; break; @@ -554,7 +554,7 @@ int main(int argc, char **argv) print_perf=1; break; - case 'p': + case 'q': n_tx_port=atoi(optarg); if ((n_tx_port==0) || ((n_tx_port>2))) { @@ -647,7 +647,7 @@ int main(int argc, char **argv) printf("-g [A:M] Use 3GPP 25.814 SCM-A/B/C/D('A','B','C','D') or 36-101 EPA('E'), EVA ('F'),ETU('G') models (ignores delay spread and Ricean factor), Rayghleigh8 ('H'), Rayleigh1('I'), Rayleigh1_corr('J'), Rayleigh1_anticorr ('K'), Rice8('L'), Rice1('M')\n"); printf("-F forgetting factor (0 new channel every trial, 1 channel constant\n"); printf("-x Transmission mode (1,2,6,7 for the moment)\n"); - printf("-p Number of TX antennas ports used in eNB\n"); + printf("-q Number of TX antennas ports used in eNB\n"); printf("-y Number of physical TX antennas used in eNB\n"); printf("-z Number of RX antennas used in UE\n"); printf("-t MCS of interfering UE\n"); From ad74bb0247033fd0293c2f7efe6937ab947c9b97 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 3 Mar 2016 15:05:54 +0000 Subject: [PATCH 136/413] Fixed enums issue and update time advance API function --- openair2/ENB_APP/enb_agent_common.c | 82 +++++++++++++++++++++++++---- openair2/ENB_APP/enb_agent_common.h | 2 +- openair2/ENB_APP/enb_agent_mac.c | 7 ++- 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 6122789d6e..f890ba829c 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -545,14 +545,43 @@ int get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) return rlc_status.bytes_in_buffer; } -int get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id) +int get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) { - if((((UE_list_t *)enb_ue[mod_id])->UE_sched_ctrl[ue_id].ta_update) > 0) + rnti_t rnti = 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); + + int32_t time_advance; + switch (PHY_vars_eNB_g[mod_id][CC_id]->lte_frame_parms.N_RB_DL) { + case 6: + time_advance = eNB_UE_stats->timing_advance_update; + break; + + case 15: + time_advance = eNB_UE_stats->timing_advance_update/2; + break; + + case 25: + time_advance = eNB_UE_stats->timing_advance_update/4; + break; + + case 50: + time_advance = eNB_UE_stats->timing_advance_update/8; + break; + + case 75: + time_advance = eNB_UE_stats->timing_advance_update/12; + break; + + case 100: + time_advance = eNB_UE_stats->timing_advance_update/16; + break; + } + + if(time_advance > 0) return 1; else return 0; } - int get_active_CC(mid_t mod_id, mid_t ue_id) { return ((UE_list_t *)enb_ue[mod_id])->numactiveCCs[ue_id]; @@ -1793,16 +1822,32 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Progr cell_conf[i]->pusch_hopping_offset = get_hopping_offset(enb_id,i); cell_conf[i]->has_pusch_hopping_offset = 1; //TODO: Fill in with actual value - cell_conf[i]->hopping_mode = get_hopping_mode(enb_id,i); + if(get_hopping_mode(enb_id,i) == 0){ + cell_conf[i]->hopping_mode = PROTOCOL__PRP_HOPPING_MODE__PRHM_INTER; + }else if(get_hopping_mode(enb_id,i) == 1){ + cell_conf[i]->hopping_mode = PROTOCOL__PRP_HOPPING_MODE__PRHM_INTERINTRA; + } cell_conf[i]->has_hopping_mode = 1; //TODO: Fill in with actual value, the number of subbands cell_conf[i]->n_sb = get_n_SB(enb_id,i); cell_conf[i]->has_n_sb = 1; //TODO: Fill in with actual value, The number of resource element groups used for PHICH. One of PRPR_ - cell_conf[i]->phich_resource = get_phich_resource(enb_id,i); + if(get_phich_resource(enb_id,i) == 0){ + cell_conf[i]->phich_resource = PROTOCOL__PRP_PHICH_RESOURCE__PRPR_ONE_SIXTH; //0 + }else if (get_phich_resource(enb_id,i) == 1){ + cell_conf[i]->phich_resource = PROTOCOL__PRP_PHICH_RESOURCE__PRPR_HALF; //1 + }else if (get_phich_resource(enb_id,i) == 2){ + cell_conf[i]->phich_resource = PROTOCOL__PRP_PHICH_RESOURCE__PRPR_ONE; // 2 + }else if (get_phich_resource(enb_id,i) == 3){ + cell_conf[i]->phich_resource = PROTOCOL__PRP_PHICH_RESOURCE__PRPR_TWO;//3 + } cell_conf[i]->has_phich_resource = 1; //TODO: Fill in with actual value, one of the PRPD_ values - cell_conf[i]->phich_duration = get_phich_duration(enb_id,i); + if(get_phich_duration(enb_id,i) == 0){ + cell_conf[i]->phich_duration = PROTOCOL__PRP_PHICH_DURATION__PRPD_NORMAL; + }else if(get_phich_duration(enb_id,i) == 1){ + cell_conf[i]->phich_duration = PROTOCOL__PRP_PHICH_DURATION__PRPD_EXTENDED; + } cell_conf[i]->has_phich_duration = 1; //TODO: Fill in with actual value, See TS 36.211, section 6.9 cell_conf[i]->init_nr_pdcch_ofdm_sym = get_num_pdcch_symb(enb_id,i); @@ -1852,16 +1897,29 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Progr cell_conf[i]->ul_bandwidth = get_N_RB_UL(enb_id,i); cell_conf[i]->has_ul_bandwidth = 1; //TODO: Fill in with actual value, one of PRUCPL values - cell_conf[i]->ul_cyclic_prefix_length = get_ul_cyclic_prefix_length(enb_id,i); + if(get_ul_cyclic_prefix_length(enb_id,i) == 0){ + cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__PRP_UL_CYCLIC_PREFIX_LENGTH__PRUCPL_NORMAL; + }else if(get_ul_cyclic_prefix_length(enb_id,i) == 1){ + cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__PRP_UL_CYCLIC_PREFIX_LENGTH__PRUCPL_EXTENDED; + } cell_conf[i]->has_ul_cyclic_prefix_length = 1; //TODO: Fill in with actual value, one of PRUCPL values - cell_conf[i]->dl_cyclic_prefix_length = get_dl_cyclic_prefix_length(enb_id,i); + if(get_ul_cyclic_prefix_length(enb_id,i) == 0){ + cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__PRP_DL_CYCLIC_PREFIX_LENGTH__PRDCPL_NORMAL; + }else if(get_ul_cyclic_prefix_length(enb_id,i) == 1){ + cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__PRP_DL_CYCLIC_PREFIX_LENGTH__PRDCPL_EXTENDED; + } + cell_conf[i]->has_dl_cyclic_prefix_length = 1; //TODO: Fill in with actual value, number of cell specific antenna ports cell_conf[i]->antenna_ports_count = 1; cell_conf[i]->has_antenna_ports_count = 1; //TODO: Fill in with actual value, one of PRDM values - cell_conf[i]->duplex_mode = get_duplex_mode(enb_id,i); + if(get_duplex_mode(enb_id,i) == 1){ + cell_conf[i]->duplex_mode = PROTOCOL__PRP_DUPLEX_MODE__PRDM_FDD; + }else if(get_duplex_mode(enb_id,i) == 0){ + cell_conf[i]->duplex_mode = PROTOCOL__PRP_DUPLEX_MODE__PRDM_TDD; + } cell_conf[i]->has_duplex_mode = 1; //TODO: Fill in with actual value, DL/UL subframe assignment. TDD only cell_conf[i]->subframe_assignment = get_subframe_assignment(enb_id,i); @@ -1936,7 +1994,11 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Progr cell_conf[i]->srs_mac_up_pts = get_srs_MaxUpPts(enb_id,i); cell_conf[i]->has_srs_mac_up_pts = 1; //TODO: Fill in with actual value, One of the PREQ_ values - cell_conf[i]->enable_64qam = get_enable64QAM(enb_id,i); + if(get_enable64QAM(enb_id,i) == 0){ + cell_conf[i]->enable_64qam = PROTOCOL__PRP_QAM__PREQ_MOD_16QAM; + }else if(get_enable64QAM(enb_id,i) == 1){ + cell_conf[i]->enable_64qam = PROTOCOL__PRP_QAM__PREQ_MOD_64QAM; + } cell_conf[i]->has_enable_64qam = 1; //TODO: Fill in with actual value, Carrier component index cell_conf[i]->carrier_index = i; diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 76c68437d0..e8fbf3afb8 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -157,7 +157,7 @@ int get_ue_wcqi (mid_t mod_id, mid_t ue_id); int get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); -int get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id); +int get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, int CC_id); int get_active_CC(mid_t mod_id, mid_t ue_id); diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index fa190bbf29..0957bd94f2 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -486,7 +486,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, /* Check flag for creation of MAC CE buffer status report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_MAC_CE_BS) { // TODO: Fill in the actual MAC CE buffer status report - ue_report[i]->pending_mac_ces = (get_MAC_CE_bitmap_TA(enb_id,i) | (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 + ue_report[i]->pending_mac_ces = (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__PRP_CE_TYPE__PRPCET_ values found in stats_common.pb-c.h. See prp_ce_type in progRAN specification */ @@ -957,7 +957,10 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran dl_info[i]->harq_status = malloc(sizeof(uint32_t) * dl_info[i]->n_harq_status); for (j = 0; j < dl_info[i]->n_harq_status; j++) { // TODO: This should be different per TB - dl_info[i]->harq_status[j] = harq_status; + if(harq_status == 0) + dl_info[i]->harq_status[j] = PROTOCOL__PRP_HARQ_STATUS__PRHS_ACK; + else if (harq_status == 1) + dl_info[i]->harq_status[j] = PROTOCOL__PRP_HARQ_STATUS__PRHS_NACK; } /*TODO: fill in the serving cell index for this UE */ dl_info[i]->serv_cell_index = UE_PCCID(mod_id,i); From a576127c49fe2711e5c20697aa66bbde5b268922 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 3 Mar 2016 15:17:19 +0000 Subject: [PATCH 137/413] Added temporary values in protocol for PUCCH power control --- openair2/ENB_APP/MESSAGES/V2/stats_common.proto | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto index 77df92a68b..3aaa018184 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto @@ -154,6 +154,7 @@ message prp_ul_cqi { optional prp_ul_cqi_type type = 1; repeated uint32 sinr = 2; optional uint32 serv_cell_index = 3; + optional int32 p0_pucch_dbm = 4; } // Full UL CQI report for a specific UE @@ -172,5 +173,6 @@ message prp_noise_interference_report { optional uint32 sfn_sf = 1; optional uint32 rip = 2; optional uint32 tnp = 3; + optional int32 p0_nominal_pucch = 4; } From d153208fc09116022c898abb998ebc4b7a070be2 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 3 Mar 2016 17:39:10 +0000 Subject: [PATCH 138/413] Added p0_PUCCH support in the agent --- .../ENB_APP/MESSAGES/V2/stats_common.proto | 6 ++++- openair2/ENB_APP/enb_agent_common.c | 20 ++++++++++++++ openair2/ENB_APP/enb_agent_common.h | 4 +++ openair2/ENB_APP/enb_agent_mac.c | 26 +++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto index 3aaa018184..50d66a620c 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto @@ -154,15 +154,19 @@ message prp_ul_cqi { optional prp_ul_cqi_type type = 1; repeated uint32 sinr = 2; optional uint32 serv_cell_index = 3; - optional int32 p0_pucch_dbm = 4; } // Full UL CQI report for a specific UE message prp_ul_cqi_report { optional uint32 sfn_sn = 1; repeated prp_ul_cqi cqi_meas = 2; + repeated prp_pucch_dbm pucch_dbm = 3; } +message prp_pucch_dbm { + optional int32 p0_pucch_dbm = 1; + optional uint32 serv_cell_index = 2; +} // // Cell related statistics diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index f890ba829c..64b51238f1 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -647,6 +647,26 @@ int get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, const i return 0; } +int 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 = 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->Po_PUCCH_update == 1) + { + return eNB_UE_stats->Po_PUCCH_dBm; + } + else + return -1; +} + +int 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; +} + /* * ************************************ diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index e8fbf3afb8..1c4d478aab 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -210,6 +210,10 @@ int get_tpc(mid_t mod_id, mid_t ue_id); int get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, const int frame, const uint8_t subframe, int *id, int *status); +int get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id); + +int get_p0_nominal_pucch(mid_t mod_id, int CC_id); + /* * ************************************ * Get Messages for UE Configuration Reply diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 0957bd94f2..29347b152b 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -657,8 +657,27 @@ int enb_agent_mac_stats_reply(mid_t mod_id, //TODO: Set the servCellIndex for this report ul_report[j]->serv_cell_index = 0; ul_report[j]->has_serv_cell_index = 1; + + /*if(get_p0_pucch_dbm(enb_id,i) != -1){ + ul_report[j]->p0_pucch_dbm = get_p0_pucch_dbm(enb_id,i); + ul_report[j]->has_p0_pucch_dbm = 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__PrpPucchDbm *) * full_ul_report->n_pucch_dbm); + + for (j = 0; j < MAX_NUM_CCs; j++) { + full_ul_report->pucch_dbm[j] = malloc(sizeof(Protocol__PrpPucchDbm)); + protocol__prp_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(get_p0_pucch_dbm(enb_id,i, j) != -1){ + full_ul_report->pucch_dbm[j]->p0_pucch_dbm = 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; } @@ -701,6 +720,9 @@ int enb_agent_mac_stats_reply(mid_t mod_id, // Thermal noise power in dbm ni_report->tnp = 0; ni_report->has_tnp = 1; + + ni_report->p0_nominal_pucch = get_p0_nominal_pucch(enb_id, 0); + ni_report->has_p0_nominal_pucch = 1; cell_report[i]->noise_inter_report = ni_report; } } @@ -822,6 +844,10 @@ int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg) { } free(ul_report->cqi_meas); } + for (j = 0; j < ul_report->n_pucch_dbm; j++) { + free(ul_report->pucch_dbm[j]); + } + free(ul_report->pucch_dbm); free(reply->ue_report[i]); } free(reply->ue_report); From d24f532396029e8bc690e42842f4b04082981f29 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 3 Mar 2016 19:49:51 +0000 Subject: [PATCH 139/413] Fixed bug in de-allocation of p0_pucch report --- openair2/ENB_APP/enb_agent_mac.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 29347b152b..197144d628 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -657,13 +657,10 @@ int enb_agent_mac_stats_reply(mid_t mod_id, //TODO: Set the servCellIndex for this report ul_report[j]->serv_cell_index = 0; ul_report[j]->has_serv_cell_index = 1; - - /*if(get_p0_pucch_dbm(enb_id,i) != -1){ - ul_report[j]->p0_pucch_dbm = get_p0_pucch_dbm(enb_id,i); - ul_report[j]->has_p0_pucch_dbm = 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__PrpPucchDbm *) * full_ul_report->n_pucch_dbm); @@ -843,11 +840,11 @@ int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg) { free(ul_report->cqi_meas[j]); } free(ul_report->cqi_meas); + for (j = 0; j < ul_report->n_pucch_dbm; j++) { + free(ul_report->pucch_dbm[j]); + } + free(ul_report->pucch_dbm); } - for (j = 0; j < ul_report->n_pucch_dbm; j++) { - free(ul_report->pucch_dbm[j]); - } - free(ul_report->pucch_dbm); free(reply->ue_report[i]); } free(reply->ue_report); From 47d3d7732225f8d14270d2e94d6681fdf2e25183 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 4 Mar 2016 10:04:29 +0000 Subject: [PATCH 140/413] Added updates in the dataplane based on dl_mac_config message --- .../LAYER2/MAC/eNB_agent_scheduler_dataplane.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c index a1bd039dff..6f84014070 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c @@ -163,6 +163,12 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, //Check if there is TA command and set the length appropriately ta_len = (dl_data->ce_bitmap[0] & PROTOCOL__PRP_CE_TYPE__PRPCET_TA) ? 2 : 0; } + + if (ta_len > 0) { + // Reset the measurement + ue_sched_ctl->ta_timer = 20; + eNB_UE_stats->timing_advance_update = 0; + } n_lc = dl_data->n_rlc_pdu; num_sdus = 0; @@ -333,6 +339,7 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, int size_bits, size_bytes; eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; UE_list_t *UE_list = &eNB->UE_list; + LTE_eNB_UE_stats *eNB_UE_stats = NULL; int UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]); @@ -346,6 +353,15 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, DCI_pdu = &eNB->common_channels[CC_id].DCI_pdu; frame_parms[CC_id] = mac_xface->get_lte_frame_parms(mod_id, CC_id); + + if (dl_dci->has_tpc == 1) { + // Check if tpc has been set and reset measurement */ + if ((dl_dci->tpc == 0) || (dl_dci->tpc == 2)) { + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + eNB_UE_stats->Po_PUCCH_update = 0; + } + } + switch (frame_parms[CC_id]->N_RB_DL) { case 6: From 06b55e3fba77b9c3bcccd2fff347c599bf04155d Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 4 Mar 2016 10:19:34 +0000 Subject: [PATCH 141/413] Fixed bug in creation of ul_cqi_report --- openair2/ENB_APP/enb_agent_mac.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 197144d628..630231560f 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -633,7 +633,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, if(ul_report == NULL) goto error; //Fill each UL report of the UE for each of the configured report types - for(j = 0; j++; j < full_ul_report->n_cqi_meas) { + for(j = 0; j < full_ul_report->n_cqi_meas; j++) { ul_report[j] = malloc(sizeof(Protocol__PrpUlCqi)); if(ul_report[j] == NULL) goto error; @@ -665,14 +665,14 @@ int enb_agent_mac_stats_reply(mid_t mod_id, full_ul_report->pucch_dbm = malloc(sizeof(Protocol__PrpPucchDbm *) * full_ul_report->n_pucch_dbm); for (j = 0; j < MAX_NUM_CCs; j++) { - full_ul_report->pucch_dbm[j] = malloc(sizeof(Protocol__PrpPucchDbm)); - protocol__prp_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(get_p0_pucch_dbm(enb_id,i, j) != -1){ - full_ul_report->pucch_dbm[j]->p0_pucch_dbm = 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] = malloc(sizeof(Protocol__PrpPucchDbm)); + protocol__prp_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(get_p0_pucch_dbm(enb_id,i, j) != -1){ + full_ul_report->pucch_dbm[j]->p0_pucch_dbm = 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 From 93b7cf05e868dac0135664ac03d62914babab5c6 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 4 Mar 2016 10:54:11 +0000 Subject: [PATCH 142/413] Fixed linking error with creation of empty dl_mac_config --- openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c | 6 +++--- openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c index 7f4ce23f9e..4fffeea132 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c @@ -70,7 +70,7 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, enb_agent_mac_destroy_dl_config(dl_config_elem->dl_info); free(dl_config_elem); } else { // next subframe, nothing to do now - enb_agent_create_empty_dl_config(mod_id, dl_info); + enb_agent_mac_create_empty_dl_config(mod_id, dl_info); return; } } @@ -87,7 +87,7 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, } else { // Intended for future subframe. Store it in local cache dl_mac_config_element_t *e = malloc(sizeof(dl_mac_config_element_t)); TAILQ_INSERT_TAIL(&queue_head, e, configs); - enb_agent_create_empty_dl_config(mod_id, dl_info); + enb_agent_mac_create_empty_dl_config(mod_id, dl_info); // No need to look for another. Messages arrive ordered return; } @@ -95,7 +95,7 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, } // We found no pending command, so we will simply pass an empty one - enb_agent_create_empty_dl_config(mod_id, dl_info); + enb_agent_mac_create_empty_dl_config(mod_id, dl_info); } int get_sf_difference(mid_t mod_id, uint16_t sfn_sf) { diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h index 2b8ec3ec19..e507f5d8a8 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h @@ -45,6 +45,7 @@ #include "ENB_APP/enb_agent_defs.h" #include "enb_agent_mac.h" +#include "LAYER2/MAC/enb_agent_mac_proto.h" #include From 26bdf501092cebe4cee227b4f51c49672c4a2f8f Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 4 Mar 2016 15:46:31 +0000 Subject: [PATCH 143/413] Added bugfixes for remote scheduling --- openair1/SCHED/phy_procedures_lte_eNb.c | 4 +- openair2/ENB_APP/enb_agent_common.c | 126 +++++++++--------- openair2/ENB_APP/enb_agent_mac.c | 2 + .../MAC/eNB_agent_scheduler_dlsch_ue_remote.c | 38 ++++-- 4 files changed, 94 insertions(+), 76 deletions(-) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 60cd0ec0f7..211c64e373 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -153,8 +153,8 @@ void remove_harq_pid_from_freelist(LTE_eNB_DLSCH_t *DLSCH_ptr, int harq_pid) * to be refined in case things don't work properly */ if (harq_pid != DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]) { - LOG_E(PHY, "%s:%d: critical error, get in touch with the authors\n", __FILE__, __LINE__); - abort(); + //LOG_E(PHY, "%s:%d: critical error, get in touch with the authors\n", __FILE__, __LINE__); + //abort(); } DLSCH_ptr->head_freelist = (DLSCH_ptr->head_freelist + 1) % 10; } diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 64b51238f1..646470d13f 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -272,31 +272,33 @@ int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg) { int enb_agent_destroy_enb_config_reply(Protocol__ProgranMessage *msg) { - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG) - goto error; - free(msg->enb_config_reply_msg->header); - int i, j; - Protocol__PrpEnbConfigReply *reply = msg->enb_config_reply_msg; - - for(i = 0; i < reply->n_cell_config;i++){ - free(reply->cell_config[i]->mbsfn_subframe_config_rfoffset); - free(reply->cell_config[i]->mbsfn_subframe_config_rfperiod); - free(reply->cell_config[i]->mbsfn_subframe_config_sfalloc); - for(j = 0; j < reply->cell_config[i]->si_config->n_si_message;j++){ - free(reply->cell_config[i]->si_config->si_message[j]); - } - free(reply->cell_config[i]->si_config->si_message); - free(reply->cell_config[i]->si_config); - free(reply->cell_config[i]); - } - free(reply->cell_config); - free(reply); - free(msg); - - return 0; - error: - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - return -1; + if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG) + goto error; + free(msg->enb_config_reply_msg->header); + int i, j; + Protocol__PrpEnbConfigReply *reply = msg->enb_config_reply_msg; + + for(i = 0; i < reply->n_cell_config;i++){ + free(reply->cell_config[i]->mbsfn_subframe_config_rfoffset); + free(reply->cell_config[i]->mbsfn_subframe_config_rfperiod); + free(reply->cell_config[i]->mbsfn_subframe_config_sfalloc); + if (reply->cell_config[i]->si_config != NULL) { + for(j = 0; j < reply->cell_config[i]->si_config->n_si_message;j++){ + free(reply->cell_config[i]->si_config->si_message[j]); + } + free(reply->cell_config[i]->si_config->si_message); + free(reply->cell_config[i]->si_config); + } + free(reply->cell_config[i]); + } + free(reply->cell_config); + free(reply); + free(msg); + + return 0; + error: + //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; } int enb_agent_destroy_ue_config_reply(Protocol__ProgranMessage *msg) { @@ -507,7 +509,7 @@ uint16_t get_sfn_sf (mid_t mod_id) { frame = (frame_t) get_current_system_frame_num(mod_id); subframe = (sub_frame_t) get_current_subframe(mod_id); frame_mask = ((1<<12) - 1); - sf_mask = ((1<<4) -1); + sf_mask = ((1<<4) - 1); sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4); return sfn_sf; @@ -1873,42 +1875,42 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Progr cell_conf[i]->init_nr_pdcch_ofdm_sym = get_num_pdcch_symb(enb_id,i); cell_conf[i]->has_init_nr_pdcch_ofdm_sym = 1; //TODO: Fill in with actual value - Protocol__PrpSiConfig *si_config; - si_config = malloc(sizeof(Protocol__PrpSiConfig)); - if(si_config == NULL) - goto error; - protocol__prp_si_config__init(si_config); - //TODO: Fill in with actual value, Frame number to apply the SI configuration - si_config->sfn = 1; - si_config->has_sfn = 1; - //TODO: Fill in with actual value, the length of SIB1 in bytes - si_config->sib1_length = get_sib1_length(enb_id,i); - si_config->has_sib1_length = 1; - //TODO: Fill in with actual value, Scheduling window for all SIs in SF - si_config->si_window_length = (uint32_t) get_si_window_length(enb_id,i); - si_config->has_si_window_length = 1; - //TODO: Fill in with actual value, the number of SI messages - si_config->n_si_message=1; - Protocol__PrpSiMessage **si_message; - si_message = malloc(sizeof(Protocol__PrpSiMessage *) * si_config->n_si_message); - if(si_message == NULL) - goto error; - for(j = 0; j < si_config->n_si_message; j++){ - si_message[j] = malloc(sizeof(Protocol__PrpSiMessage)); - if(si_message[j] == NULL) - goto error; - protocol__prp_si_message__init(si_message[j]); - //TODO: Fill in with actual value, Periodicity of SI msg in radio frames - si_message[j]->periodicity = 1; //SIPeriod - si_message[j]->has_periodicity = 1; - //TODO: Fill in with actual value, rhe length of the SI message in bytes - si_message[j]->length = 10; - si_message[j]->has_length = 1; - } - if(si_config->n_si_message > 0){ - si_config->si_message = si_message; - } - cell_conf[i]->si_config = si_config; + /* Protocol__PrpSiConfig *si_config; */ + /* si_config = malloc(sizeof(Protocol__PrpSiConfig)); */ + /* if(si_config == NULL) */ + /* goto error; */ + /* protocol__prp_si_config__init(si_config); */ + /* //TODO: Fill in with actual value, Frame number to apply the SI configuration */ + /* si_config->sfn = 1; */ + /* si_config->has_sfn = 1; */ + /* //TODO: Fill in with actual value, the length of SIB1 in bytes */ + /* si_config->sib1_length = get_sib1_length(enb_id,i); */ + /* si_config->has_sib1_length = 1; */ + /* //TODO: Fill in with actual value, Scheduling window for all SIs in SF */ + /* si_config->si_window_length = (uint32_t) get_si_window_length(enb_id,i); */ + /* si_config->has_si_window_length = 1; */ + /* //TODO: Fill in with actual value, the number of SI messages */ + /* si_config->n_si_message=1; */ + /* Protocol__PrpSiMessage **si_message; */ + /* si_message = malloc(sizeof(Protocol__PrpSiMessage *) * si_config->n_si_message); */ + /* if(si_message == NULL) */ + /* goto error; */ + /* for(j = 0; j < si_config->n_si_message; j++){ */ + /* si_message[j] = malloc(sizeof(Protocol__PrpSiMessage)); */ + /* if(si_message[j] == NULL) */ + /* goto error; */ + /* protocol__prp_si_message__init(si_message[j]); */ + /* //TODO: Fill in with actual value, Periodicity of SI msg in radio frames */ + /* si_message[j]->periodicity = 1; //SIPeriod */ + /* si_message[j]->has_periodicity = 1; */ + /* //TODO: Fill in with actual value, rhe length of the SI message in bytes */ + /* si_message[j]->length = 10; */ + /* si_message[j]->has_length = 1; */ + /* } */ + /* if(si_config->n_si_message > 0){ */ + /* si_config->si_message = si_message; */ + /* } */ + /* cell_conf[i]->si_config = si_config; */ //TODO: Fill in with actual value, the DL transmission bandwidth in RBs cell_conf[i]->dl_bandwidth = get_N_RB_DL(enb_id,i); diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 630231560f..f00012f158 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -41,6 +41,7 @@ #include "LAYER2/MAC/proto.h" #include "LAYER2/MAC/enb_agent_mac_proto.h" +#include "LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h" #include "liblfds700.h" @@ -1369,6 +1370,7 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_send_sf_trigger = enb_agent_send_sf_trigger; xface->enb_agent_send_update_mac_stats = enb_agent_send_update_mac_stats; xface->enb_agent_schedule_ue_spec = schedule_ue_spec_default; + //xface->enb_agent_schedule_ue_spec = schedule_ue_spec_remote; xface->enb_agent_get_pending_dl_mac_config = enb_agent_get_pending_dl_mac_config; xface->enb_agent_notify_ue_state_change = enb_agent_ue_state_change; diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c index 4fffeea132..c4f40faff7 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c @@ -46,7 +46,7 @@ int queue_initialized = 0; void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, Protocol__ProgranMessage **dl_info) { - if (queue_initialized) { + if (!queue_initialized) { TAILQ_INIT(&queue_head); queue_initialized = 1; } @@ -54,22 +54,26 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, dl_mac_config_element_t *dl_config_elem; int diff; - + LOG_D(MAC, "Current frame and subframe %d, %d\n", frame, subframe); // First we check to see if we have a scheduling decision for this sfn_sf already in our queue while(queue_head.tqh_first != NULL) { dl_config_elem = queue_head.tqh_first; + diff = get_sf_difference(mod_id, dl_config_elem->dl_info->dl_mac_config_msg->sfn_sf); // Check if this decision is for now, for a later or a previous subframe if ( diff == 0) { // Now + LOG_D(MAC, "Found a decision for this subframe in the queue. Let's use it!\n"); TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs); *dl_info = dl_config_elem->dl_info; free(dl_config_elem); return; } else if (diff < 0) { //previous subframe , delete message and free memory + LOG_D(MAC, "Found a decision for a previous subframe in the queue. Let's get rid of it\n"); TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs); enb_agent_mac_destroy_dl_config(dl_config_elem->dl_info); free(dl_config_elem); } else { // next subframe, nothing to do now + LOG_D(MAC, "Found a decision for a future subframe in the queue. Nothing to do now\n"); enb_agent_mac_create_empty_dl_config(mod_id, dl_info); return; } @@ -81,17 +85,22 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, diff = get_sf_difference(mod_id, (*dl_info)->dl_mac_config_msg->sfn_sf); if (diff == 0) { // Got a command for this sfn_sf + LOG_D(MAC, "Found a decision for this subframe pending. Let's use it\n"); return; } else if (diff < 0) { + LOG_D(MAC, "Found a decision for a previous subframe. Let's get rid of it\n"); enb_agent_mac_destroy_dl_config(*dl_info); + *dl_info = NULL; + enb_agent_get_pending_dl_mac_config(mod_id, dl_info); } else { // Intended for future subframe. Store it in local cache + LOG_D(MAC, "Found a decision for a future subframe in the queue. Let's store it in the cache\n"); dl_mac_config_element_t *e = malloc(sizeof(dl_mac_config_element_t)); + e->dl_info = *dl_info; TAILQ_INSERT_TAIL(&queue_head, e, configs); enb_agent_mac_create_empty_dl_config(mod_id, dl_info); // No need to look for another. Messages arrive ordered return; } - enb_agent_get_pending_dl_mac_config(mod_id, dl_info); } // We found no pending command, so we will simply pass an empty one @@ -114,25 +123,30 @@ int get_sf_difference(mid_t mod_id, uint16_t sfn_sf) { uint16_t sf_mask = ((1<<4) - 1); uint16_t subframe = (sfn_sf & sf_mask); + + LOG_D(MAC, "Target frame and subframe %d, %d\n", frame, subframe); if (frame == current_frame) { return subframe - current_subframe; } else if (frame > current_frame) { - diff_in_subframes = 9 - current_subframe; - diff_in_subframes += (subframe + 1); - diff_in_subframes += (frame-2) * 10; + diff_in_subframes = ((frame*10)+subframe) - ((current_frame*10)+current_subframe); + + // diff_in_subframes = 9 - current_subframe; + //diff_in_subframes += (subframe + 1); + //diff_in_subframes += (frame-2) * 10; if (diff_in_subframes > SCHED_AHEAD_SUBFRAMES) { return -1; } else { return 1; } } else { //frame < current_frame - diff_in_subframes = 9 - current_subframe; - diff_in_subframes += (subframe + 1); - if (frame > 0) { - diff_in_subframes += (frame - 1) * 10; - } - diff_in_subframes += (1023 - current_frame) * 10; + //diff_in_subframes = 9 - current_subframe; + //diff_in_subframes += (subframe + 1); + //if (frame > 0) { + // diff_in_subframes += (frame - 1) * 10; + //} + //diff_in_subframes += (1023 - current_frame) * 10; + diff_in_subframes = 10240 - ((current_frame*10)+current_subframe) + ((frame*10)+subframe); if (diff_in_subframes > SCHED_AHEAD_SUBFRAMES) { return -1; } else { From fc569650ce84d3aa0349ef1459d6f646125dbcb3 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 7 Mar 2016 10:02:40 +0000 Subject: [PATCH 144/413] Fixed problem with sfn_sf recoding in remote scheduler --- openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c | 8 ++++---- openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c index c4f40faff7..db90bb1754 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c @@ -54,7 +54,7 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, dl_mac_config_element_t *dl_config_elem; int diff; - LOG_D(MAC, "Current frame and subframe %d, %d\n", frame, subframe); + LOG_D(MAC, "[TEST] Current frame and subframe %d, %d\n", frame, subframe); // First we check to see if we have a scheduling decision for this sfn_sf already in our queue while(queue_head.tqh_first != NULL) { dl_config_elem = queue_head.tqh_first; @@ -107,12 +107,12 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, enb_agent_mac_create_empty_dl_config(mod_id, dl_info); } -int get_sf_difference(mid_t mod_id, uint16_t sfn_sf) { +int get_sf_difference(mid_t mod_id, uint32_t sfn_sf) { int diff_in_subframes; uint16_t current_frame = get_current_system_frame_num(mod_id); uint16_t current_subframe = get_current_subframe(mod_id); - uint16_t current_sfn_sf = get_sfn_sf(mod_id); + uint32_t current_sfn_sf = get_sfn_sf(mod_id); if (sfn_sf == current_sfn_sf) { return 0; @@ -124,7 +124,7 @@ int get_sf_difference(mid_t mod_id, uint16_t sfn_sf) { uint16_t sf_mask = ((1<<4) - 1); uint16_t subframe = (sfn_sf & sf_mask); - LOG_D(MAC, "Target frame and subframe %d, %d\n", frame, subframe); + LOG_D(MAC, "[TEST] Target frame and subframe %d, %d\n", frame, subframe); if (frame == current_frame) { return subframe - current_subframe; diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h index e507f5d8a8..c636ec0d95 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h @@ -72,6 +72,6 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, // 0 for equal // positive for future value // Based on -int get_sf_difference(mid_t mod_id, uint16_t sfn_sf); +int get_sf_difference(mid_t mod_id, uint32_t sfn_sf); #endif From 0dc76931c61b38bebf8cd60a022e6076ae1beb93 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 7 Mar 2016 12:37:46 +0000 Subject: [PATCH 145/413] Fixed bug in HARQ status reporting --- openair2/ENB_APP/enb_agent_mac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index f00012f158..5ba6c0b665 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -982,9 +982,9 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran for (j = 0; j < dl_info[i]->n_harq_status; j++) { // TODO: This should be different per TB if(harq_status == 0) - dl_info[i]->harq_status[j] = PROTOCOL__PRP_HARQ_STATUS__PRHS_ACK; - else if (harq_status == 1) dl_info[i]->harq_status[j] = PROTOCOL__PRP_HARQ_STATUS__PRHS_NACK; + else if (harq_status == 1) + dl_info[i]->harq_status[j] = PROTOCOL__PRP_HARQ_STATUS__PRHS_ACK; } /*TODO: fill in the serving cell index for this UE */ dl_info[i]->serv_cell_index = UE_PCCID(mod_id,i); @@ -1369,8 +1369,8 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_send_sr_info = enb_agent_send_sr_info; xface->enb_agent_send_sf_trigger = enb_agent_send_sf_trigger; xface->enb_agent_send_update_mac_stats = enb_agent_send_update_mac_stats; - xface->enb_agent_schedule_ue_spec = schedule_ue_spec_default; - //xface->enb_agent_schedule_ue_spec = schedule_ue_spec_remote; + //xface->enb_agent_schedule_ue_spec = schedule_ue_spec_default; + xface->enb_agent_schedule_ue_spec = schedule_ue_spec_remote; xface->enb_agent_get_pending_dl_mac_config = enb_agent_get_pending_dl_mac_config; xface->enb_agent_notify_ue_state_change = enb_agent_ue_state_change; From 2a5a389f7d80707d886c4783ff4e3c3a016047e8 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 7 Mar 2016 16:27:32 +0000 Subject: [PATCH 146/413] Improved stability and eNB goodput of remote scheduling --- openair1/SCHED/phy_procedures_lte_eNb.c | 4 ++-- openair2/ENB_APP/enb_agent_mac.c | 8 ++++---- openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 211c64e373..60cd0ec0f7 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -153,8 +153,8 @@ void remove_harq_pid_from_freelist(LTE_eNB_DLSCH_t *DLSCH_ptr, int harq_pid) * to be refined in case things don't work properly */ if (harq_pid != DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]) { - //LOG_E(PHY, "%s:%d: critical error, get in touch with the authors\n", __FILE__, __LINE__); - //abort(); + LOG_E(PHY, "%s:%d: critical error, get in touch with the authors\n", __FILE__, __LINE__); + abort(); } DLSCH_ptr->head_freelist = (DLSCH_ptr->head_freelist + 1) % 10; } diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 5ba6c0b665..ff8638ca4d 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -981,10 +981,10 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran dl_info[i]->harq_status = malloc(sizeof(uint32_t) * dl_info[i]->n_harq_status); for (j = 0; j < dl_info[i]->n_harq_status; j++) { // TODO: This should be different per TB - if(harq_status == 0) - dl_info[i]->harq_status[j] = PROTOCOL__PRP_HARQ_STATUS__PRHS_NACK; - else if (harq_status == 1) - dl_info[i]->harq_status[j] = PROTOCOL__PRP_HARQ_STATUS__PRHS_ACK; + if(harq_status == 0) + dl_info[i]->harq_status[j] = PROTOCOL__PRP_HARQ_STATUS__PRHS_ACK; + else if (harq_status == 1) + dl_info[i]->harq_status[j] = PROTOCOL__PRP_HARQ_STATUS__PRHS_NACK; } /*TODO: fill in the serving cell index for this UE */ dl_info[i]->serv_cell_index = UE_PCCID(mod_id,i); diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c index db90bb1754..90181f0e44 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c @@ -50,7 +50,7 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, TAILQ_INIT(&queue_head); queue_initialized = 1; } - + dl_mac_config_element_t *dl_config_elem; int diff; From ff5b5854468560c676174f5e265681fd42aee283 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 8 Mar 2016 12:58:44 +0000 Subject: [PATCH 147/413] Added check for ignoring empty mac dl config messages --- openair2/ENB_APP/enb_agent_mac.c | 4 ++-- openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index ff8638ca4d..296da7f1d2 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -1369,8 +1369,8 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_send_sr_info = enb_agent_send_sr_info; xface->enb_agent_send_sf_trigger = enb_agent_send_sf_trigger; xface->enb_agent_send_update_mac_stats = enb_agent_send_update_mac_stats; - //xface->enb_agent_schedule_ue_spec = schedule_ue_spec_default; - xface->enb_agent_schedule_ue_spec = schedule_ue_spec_remote; + xface->enb_agent_schedule_ue_spec = schedule_ue_spec_default; + //xface->enb_agent_schedule_ue_spec = schedule_ue_spec_remote; xface->enb_agent_get_pending_dl_mac_config = enb_agent_get_pending_dl_mac_config; xface->enb_agent_notify_ue_state_change = enb_agent_ue_state_change; diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c index 6f84014070..dc1ab3da0e 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c @@ -247,6 +247,11 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, } ta_update = (ta_len > 0) ? ue_sched_ctl->ta_update : 0; + + // If there is nothing to schedule, just leave + if ((sdu_length_total + ta_len) < 0) { + return; + } offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], num_sdus, //num_sdus From 8b283444487ec4aa000f8d9a7c3cf2e89fd74bc6 Mon Sep 17 00:00:00 2001 From: Mohamed Kassem Date: Tue, 8 Mar 2016 18:15:52 +0000 Subject: [PATCH 148/413] Temporary fix for bug in reporting number of initial pdcch symbols of cell and band5 configuration file for agent --- openair2/ENB_APP/enb_agent_common.c | 11 +- .../enb.band5.agent.usrpb210.epc.remote.conf | 175 ++++++++++++++++++ 2 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 646470d13f..18412bc502 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -873,11 +873,9 @@ int get_sib1_length(mid_t mod_id, int CC_id) } int get_num_pdcch_symb(mid_t mod_id, int CC_id) { - /*TODO: add these values to some struct in MAC - LTE_UE_PDCCH *lte_ue_pdcch; - lte_ue_pdcch = mac_xface->get_lte_ue_pdcch(mod_id, CC_id, mod_id); - */ - return (PHY_vars_UE_g[mod_id][CC_id]->lte_ue_pdcch_vars[mod_id]->num_pdcch_symbols); + /* 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); } /* @@ -1200,6 +1198,9 @@ int get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) int 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 { diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf new file mode 100644 index 0000000000..f8c5016de5 --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf @@ -0,0 +1,175 @@ +Active_eNBs = ( "eNB_Eurecom_LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB_Eurecom_LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = "1"; + + mobile_country_code = "208"; + mobile_network_code = "95"; + + ////////// Physical parameters: + + component_carriers = ( + { + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2660000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 125; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = -26; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -90; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -108; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + } + ); + + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + ////////// MME parameters: + mme_ip_address = ( {ipv4 = "192.168.100.103"; + ipv6="192:168:30::17"; + active="yes"; + preference="ipv4";}); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth0:1"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.102/24"; + + ENB_INTERFACE_NAME_FOR_S1U = "eth0:1"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.102/24"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + NETWORK_CONTROLLER : + { + ENB_AGENT_INTERFACE_NAME = "eth1"; + ENB_AGENT_IPV4_ADDRESS = "10.0.0.5/30"; + ENB_AGENT_PORT = 2210; + ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; + }; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="debug"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + + } +); From 34db5f2003120719f56c5f45626b64433fc9d184 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 9 Mar 2016 12:19:16 +0000 Subject: [PATCH 149/413] Moved agent async interface to lock-free implementation using lock-free ringbuffer --- cmake_targets/CMakeLists.txt | 1 + openair2/ENB_APP/enb_agent.c | 36 +++--- openair2/ENB_APP/enb_agent_async.c | 6 +- openair2/UTIL/ASYNC_IF/link_manager.c | 14 ++- openair2/UTIL/ASYNC_IF/link_manager.h | 3 +- openair2/UTIL/ASYNC_IF/ringbuffer_queue.c | 143 ++++++++++++++++++++++ openair2/UTIL/ASYNC_IF/ringbuffer_queue.h | 60 +++++++++ 7 files changed, 237 insertions(+), 26 deletions(-) create mode 100644 openair2/UTIL/ASYNC_IF/ringbuffer_queue.c create mode 100644 openair2/UTIL/ASYNC_IF/ringbuffer_queue.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 18eaf0f8b6..ea0cabe88f 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -832,6 +832,7 @@ if (ENB_AGENT_SB_IF) ${OPENAIR2_DIR}/UTIL/ASYNC_IF/socket_link.c ${OPENAIR2_DIR}/UTIL/ASYNC_IF/link_manager.c ${OPENAIR2_DIR}/UTIL/ASYNC_IF/message_queue.c + ${OPENAIR2_DIR}/UTIL/ASYNC_IF/ringbuffer_queue.c ) set(ASYNC_IF_LIB ASYNC_IF) include_directories(${OPENAIR2_DIR}/UTIL/ASYNC_IF) diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index a21e2f8e16..81d856fa97 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -135,32 +135,34 @@ void *receive_thread(void *args) { Protocol__ProgranMessage *msg; while (1) { - if (enb_agent_msg_recv(d->enb_id, ENB_AGENT_DEFAULT, &data, &size, &priority)) { - err_code = PROTOCOL__PROGRAN_ERR__MSG_DEQUEUING; - goto error; - } + //if (enb_agent_msg_recv(d->enb_id, ENB_AGENT_DEFAULT, &data, &size, &priority)) { + // err_code = PROTOCOL__PROGRAN_ERR__MSG_DEQUEUING; + // goto error; + //} - LOG_D(ENB_AGENT,"received message with size %d\n", size); + while (enb_agent_msg_recv(d->enb_id, ENB_AGENT_DEFAULT, &data, &size, &priority) == 0) { + + LOG_D(ENB_AGENT,"received message with size %d\n", size); - msg=enb_agent_handle_message(d->enb_id, data, size); + msg=enb_agent_handle_message(d->enb_id, data, size); - free(data); + free(data); - // check if there is something to send back to the controller - if (msg != NULL){ - data=enb_agent_pack_message(msg,&size); + // check if there is something to send back to the controller + if (msg != NULL){ + data=enb_agent_pack_message(msg,&size); - if (enb_agent_msg_send(d->enb_id, ENB_AGENT_DEFAULT, data, size, priority)) { - err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; - goto error; - } + if (enb_agent_msg_send(d->enb_id, ENB_AGENT_DEFAULT, data, size, priority)) { + err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + goto error; + } - LOG_D(ENB_AGENT,"sent message with size %d\n", size); + LOG_D(ENB_AGENT,"sent message with size %d\n", size); + } } - } - + return NULL; error: diff --git a/openair2/ENB_APP/enb_agent_async.c b/openair2/ENB_APP/enb_agent_async.c index d6389ea65f..a626566a8d 100644 --- a/openair2/ENB_APP/enb_agent_async.c +++ b/openair2/ENB_APP/enb_agent_async.c @@ -60,10 +60,10 @@ enb_agent_async_channel_t * enb_agent_async_channel_info(mid_t mod_id, char *dst /* * create a message queue */ - - channel->send_queue = new_message_queue(); + // Set size of queues statically for now + channel->send_queue = new_message_queue(500); if (channel->send_queue == NULL) goto error; - channel->receive_queue = new_message_queue(); + channel->receive_queue = new_message_queue(500); if (channel->receive_queue == NULL) goto error; /* diff --git a/openair2/UTIL/ASYNC_IF/link_manager.c b/openair2/UTIL/ASYNC_IF/link_manager.c index 9b31fc043b..a528577fd8 100644 --- a/openair2/UTIL/ASYNC_IF/link_manager.c +++ b/openair2/UTIL/ASYNC_IF/link_manager.c @@ -53,11 +53,15 @@ static void *link_manager_sender_thread(void *_manager) LOG_D(MAC, "starting link manager sender thread\n"); while (manager->run) { - if (message_get(manager->send_queue, &data, &size, &priority)) - goto error; - if (link_send_packet(manager->socket_link, data, size)) - goto error; - free(data); + while (message_get(manager->send_queue, &data, &size, &priority) == 0) { + link_send_packet(manager->socket_link, data, size); + free(data); + } + // if (message_get(manager->send_queue, &data, &size, &priority)) + // goto error; + //if (link_send_packet(manager->socket_link, data, size)) + // goto error; + //free(data); } LOG_D(MAC, "link manager sender thread quits\n"); diff --git a/openair2/UTIL/ASYNC_IF/link_manager.h b/openair2/UTIL/ASYNC_IF/link_manager.h index 3e24b8679a..4f0628c0ee 100644 --- a/openair2/UTIL/ASYNC_IF/link_manager.h +++ b/openair2/UTIL/ASYNC_IF/link_manager.h @@ -38,7 +38,8 @@ #ifndef LINK_MANAGER_H #define LINK_MANAGER_H -#include "message_queue.h" +//#include "message_queue.h" +#include "ringbuffer_queue.h" #include "socket_link.h" #include diff --git a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c new file mode 100644 index 0000000000..0d63e41431 --- /dev/null +++ b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c @@ -0,0 +1,143 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2015 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ +/*! \file ringbuffer_queue.c + * \brief Lock-free ringbuffer used for async message passing of agent + * \author Xenofon Foukas + * \date March 2016 + * \version 1.0 + * \email: x.foukas@sms.ed.ac.uk + * @ingroup _mac + */ + +#include "ringbuffer_queue.h" +#include "log.h" + +message_queue_t * new_message_queue(int size) { + + message_queue_t *ret = NULL; + + ret = calloc(1, sizeof(message_queue_t)); + if (ret == NULL) + goto error; + + lfds700_misc_library_init_valid_on_current_logical_core(); + lfds700_misc_prng_init(&(ret->ps)); + ret->ringbuffer_array = malloc(sizeof(struct lfds700_ringbuffer_element) * size); + lfds700_ringbuffer_init_valid_on_current_logical_core(&(ret->ringbuffer_state), + ret->ringbuffer_array, + size, + &(ret->ps), + NULL); + + return ret; + + error: + LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + if (ret != NULL) { + free(ret->ringbuffer_array); + memset(ret, 0, sizeof(message_queue_t)); + free(ret); + } + return NULL; +} + +int message_put(message_queue_t *queue, void *data, int size, int priority) { + + struct lfds700_misc_prng_state ls; + enum lfds700_misc_flag overwrite_occurred_flag; + message_t *overwritten_msg; + message_t *m = NULL; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + lfds700_misc_prng_init(&ls); + + m = calloc(1, sizeof(message_t)); + if (m == NULL) + goto error; + + m->data = data; + m->size = size; + m->priority = priority; + + lfds700_ringbuffer_write(&(queue->ringbuffer_state), + NULL, + (void *) m, + &overwrite_occurred_flag, + NULL, + (void **) &overwritten_msg, + &ls); + + if (overwrite_occurred_flag == LFDS700_MISC_FLAG_RAISED) { + free(overwritten_msg->data); + free(overwritten_msg); + } + + return 0; + + error: + free(m); + LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + return -1; +} + +int message_get(message_queue_t *queue, void **data, int *size, int *priority) { + message_t *m; + struct lfds700_misc_prng_state ls; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + lfds700_misc_prng_init(&ls); + + if (lfds700_ringbuffer_read(&(queue->ringbuffer_state), NULL, (void **) &m, &ls) == 0) { + return -1; + } + + *data = m->data; + *size = m->size; + *priority = m->priority; + free(m); + return 0; +} + +message_queue_t destroy_message_queue(message_queue_t *queue) { + struct lfds700_misc_prng_state ls; + + message_t *m; + + LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; + lfds700_misc_prng_init(&ls); + + while (lfds700_ringbuffer_read(&(queue->ringbuffer_state), NULL, (void **) &m, &ls) != 0) { + free(m->data); + memset(m, 0, sizeof(message_t)); + free(m); + } + free(queue->ringbuffer_array); + memset(queue, 0, sizeof(message_queue_t)); + free(queue); +} diff --git a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h new file mode 100644 index 0000000000..756a35ae4a --- /dev/null +++ b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h @@ -0,0 +1,60 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2015 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@eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ +/*! \file ringbuffer_queue.h + * \brief Lock-free ringbuffer used for async message passing of agent + * \author Xenofon Foukas + * \date March 2016 + * \version 1.0 + * \email: x.foukas@sms.ed.ac.uk + * @ingroup _mac + */ + +#ifndef RINGBUFFER_QUEUE_H +#define RINGBUFFER_QUEUE_H + +#include "liblfds700.h" + +typedef struct message_s { + void *data; + int size; + int priority; +} message_t; + +typedef struct { + struct lfds700_misc_prng_state ps; + struct lfds700_ringbuffer_element *ringbuffer_array; + struct lfds700_ringbuffer_state ringbuffer_state; +} message_queue_t; + +message_queue_t * new_message_queue(int size); +int message_put(message_queue_t *queue, void *data, int size, int priority); +int message_get(message_queue_t *queue, void **data, int *size, int *priority); +message_queue_t destroy_message_queue(message_queue_t *queue); + +#endif /* RINGBUFFER_QUEUE_H */ From 3a1f3df882b5769a2239935688377b5aea4e9d7b Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 9 Mar 2016 13:13:03 +0000 Subject: [PATCH 150/413] Added OAI priority to send and receive thread of agent --- openair2/UTIL/ASYNC_IF/link_manager.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openair2/UTIL/ASYNC_IF/link_manager.c b/openair2/UTIL/ASYNC_IF/link_manager.c index a528577fd8..0ab2ecc2b2 100644 --- a/openair2/UTIL/ASYNC_IF/link_manager.c +++ b/openair2/UTIL/ASYNC_IF/link_manager.c @@ -122,6 +122,16 @@ link_manager_t *create_link_manager( if (pthread_attr_init(&attr)) goto error; + // Make the async interface threads real-time + //#ifndef LOWLATENCY + struct sched_param sched_param_recv_thread; + struct sched_param sched_param_send_thread; + + sched_param_recv_thread.sched_priority = sched_get_priority_max(SCHED_RR) - 1; + pthread_attr_setschedparam(&attr, &sched_param_recv_thread); + pthread_attr_setschedpolicy(&attr, SCHED_RR); + //#endif + if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) goto error; From e88c4d97cf71f403536645f8ae961bcb8df563bf Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 10 Mar 2016 10:57:44 +0000 Subject: [PATCH 151/413] Code cleanups for control delegation and API --- openair2/ENB_APP/enb_agent_common.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 18412bc502..1b38ff9020 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -439,7 +439,6 @@ int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__Pro } } long time_elapsed_nanos = timer_end(vartime); - LOG_I(ENB_AGENT, "DID IT IN %lld\n", time_elapsed_nanos); *msg = NULL; return 0; @@ -890,7 +889,6 @@ int 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 = get_ue_crnti(mod_id,ue_id); - LOG_I(ENB_APP,"The value of rntiP is %d\n",rntiP); ue_context_p = rrc_eNB_get_ue_context(&eNB_rrc_inst[mod_id],rntiP); if(ue_context_p != NULL) { @@ -1254,8 +1252,6 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) int i =find_UE_id(mod_id,rnti); config->has_rnti = 1; config->rnti = rnti; - LOG_I(ENB_APP,"The value of i is %d\n",i); - LOG_I(ENB_APP,"The value of rnto is %d\n",rnti); //TODO: Set the time_alignment_timer if(get_time_alignment_timer(mod_id,i) != -1){ config->time_alignment_timer = get_time_alignment_timer(mod_id,i); From 3251cf792c99514c3747811e85dba3c0ac74793d Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 10 Mar 2016 14:12:47 +0000 Subject: [PATCH 152/413] Added shared libs for control delegation --- cmake_targets/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index ea0cabe88f..3ab5289365 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1115,7 +1115,8 @@ add_library(L2 ${OPENAIR2_DIR}/RRC/L2_INTERFACE/openair_rrc_L2_interface.c) #Test for adding a shared library -#add_library(alt_sched SHARED ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue_alt.c) +add_library(default_sched SHARED ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue.c) +add_library(remote_sched SHARED ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue_remote.c) # L3 Libs ########################## From 43b63be53ac578b34339d9d7d2f14e29dee72493 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 14 Mar 2016 11:42:04 +0000 Subject: [PATCH 153/413] Added nb_rb and oldNDI in template to be used for retransmissions --- .../MAC/eNB_agent_scheduler_dataplane.c | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c index dc1ab3da0e..e74d078fda 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c @@ -300,33 +300,46 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, 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; - nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + //nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + //Find the number of resource blocks and set them to the template for retransmissions + nb_rb = get_min_rb_unit(mod_id, CC_id); + uint16_t stats_tbs = mac_xface->get_TBS_DL(dl_dci->mcs[0], nb_rb); + + while (stats_tbs < TBS) { + nb_rb += get_min_rb_unit(mod_id, CC_id); + stats_tbs = mac_xface->get_TBS_DL(dl_dci->mcs[0], nb_rb); + } + + UE_list->UE_template[CC_id][UE_id].nb_rb[dl_dci->harq_process] = nb_rb; + UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=dl_dci->mcs[0]; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=dl_dci->mcs[0]; UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; - UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes= TBS- sdu_length_total; + UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes= TBS - sdu_length_total; UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes+= sdu_length_total; UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes+= TBS; UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus+=1; - eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; - eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); + //eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; + //eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); } } else { // No need to create anything apart of DCI in case of retransmission /*TODO: Must add these */ - //eNB_UE_stats->dlsch_trials[round]++; + // eNB_UE_stats->dlsch_trials[round]++; //UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; //UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; //UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; //UE_list->eNB_UE_stats[CC_id][UE_id].ncce_used_retx=nCCECC_id]; - //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1; - //UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=eNB_UE_stats->dlsch_mcs1; } + + UE_list->UE_template[CC_id][UE_id].oldNDI[dl_dci->harq_process] = dl_dci->ndi[0]; + eNB_UE_stats->dlsch_mcs1 = dl_dci->mcs[0]; + //Fill the proper DCI of OAI fill_oai_dci(mod_id, CC_id, rnti, dl_dci); } @@ -496,7 +509,7 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, /*TODO: Need to deal with unsupported DCI type*/ return; } - + add_ue_spec_dci(DCI_pdu, DLSCH_dci, rnti, From c2971d517672c635f9ca9f1c95ee59f9a55be753 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 15 Mar 2016 17:25:44 +0000 Subject: [PATCH 154/413] Added tcp_nodelay option in agent async interface --- openair2/UTIL/ASYNC_IF/socket_link.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/openair2/UTIL/ASYNC_IF/socket_link.c b/openair2/UTIL/ASYNC_IF/socket_link.c index 95a92ae3ee..f4bd248f78 100644 --- a/openair2/UTIL/ASYNC_IF/socket_link.c +++ b/openair2/UTIL/ASYNC_IF/socket_link.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -56,7 +57,8 @@ socket_link_t *new_link_server(int port) struct sockaddr_in addr; socklen_t addrlen; int socket_server = -1; - + int no_delay; + ret = calloc(1, sizeof(socket_link_t)); if (ret == NULL) { LOG_E(MAC, "%s:%d: out of memory\n", __FILE__, __LINE__); @@ -78,6 +80,12 @@ socket_link_t *new_link_server(int port) goto error; } + no_delay = 1; + if (setsockopt(socket_server, IPPROTO_TCP, TCP_NODELAY, &no_delay, sizeof(no_delay)) == -1) { + LOG_E(MAC, "%s:%d: setsockopt: %s\n", __FILE__, __LINE__, strerror(errno)); + goto error; + } + addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; @@ -115,6 +123,7 @@ socket_link_t *new_link_client(char *server, int port) { socket_link_t *ret = NULL; struct sockaddr_in addr; + int no_delay; ret = calloc(1, sizeof(socket_link_t)); if (ret == NULL) { @@ -131,6 +140,12 @@ socket_link_t *new_link_client(char *server, int port) goto error; } + no_delay = 1; + if (setsockopt(ret->socket_fd, SOL_TCP, TCP_NODELAY, &no_delay, sizeof(no_delay)) == -1) { + LOG_E(MAC, "%s:%d: setsockopt: %s\n", __FILE__, __LINE__, strerror(errno)); + goto error; + } + addr.sin_family = AF_INET; addr.sin_port = htons(port); if (inet_aton(server, &addr.sin_addr) == 0) { From ef22a539aa02f602bcd016e86cbe7cf5e6737fb4 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 16 Mar 2016 11:48:18 +0000 Subject: [PATCH 155/413] Added more checks when applying dci decisions in the dataplane, to reduce RLC request misses --- .../MAC/eNB_agent_scheduler_dataplane.c | 79 +++++++++++-------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c index e74d078fda..59dc70cda7 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c @@ -182,41 +182,56 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, if (rlc_size > 0) { rlc_status = mac_rlc_status_ind(mod_id, - rnti, - mod_id, - frame, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - rlc_size); // transport block set size + rnti, + mod_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + 0); + + if (rlc_status.bytes_in_buffer > 0) { + + rlc_status = mac_rlc_status_ind(mod_id, + rnti, + mod_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + rlc_size); // transport block set size - sdu_lengths[i] = 0; + sdu_lengths[i] = 0; - LOG_D(MAC, "[TEST] RLC can give %d bytes for LCID %d during second call\n", rlc_status.bytes_in_buffer, lcid); + LOG_D(MAC, "[TEST] RLC can give %d bytes for LCID %d during second call\n", rlc_status.bytes_in_buffer, lcid); - sdu_lengths[i] += mac_rlc_data_req(mod_id, - rnti, - mod_id, - frame, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - (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[i]); - sdu_length_total += sdu_lengths[i]; - sdu_lcids[i] = lcid; - - 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[i]; - - if (sdu_lengths[i] < 128) { - header_len += 2; - } else { - header_len += 3; + if (rlc_status.bytes_in_buffer > 0) { + + sdu_lengths[i] += mac_rlc_data_req(mod_id, + rnti, + mod_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + (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[i]); + sdu_length_total += sdu_lengths[i]; + sdu_lcids[i] = lcid; + + 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[i]; + + if (sdu_lengths[i] < 128) { + header_len += 2; + } else { + header_len += 3; + } + + num_sdus++; + } } - - num_sdus++; } } // SDU creation end @@ -249,7 +264,7 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, ta_update = (ta_len > 0) ? ue_sched_ctl->ta_update : 0; // If there is nothing to schedule, just leave - if ((sdu_length_total + ta_len) < 0) { + if ((sdu_length_total + ta_len) <= 0) { return; } From c77fb6479e537cd9f43c040fab039ed21ee9ebb4 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 16 Mar 2016 11:49:07 +0000 Subject: [PATCH 156/413] Changed timing of continuous MAC statistics to be reported at the end of the subframe --- openair2/LAYER2/MAC/eNB_scheduler.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 9a172cb377..06e115b392 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -72,6 +72,7 @@ #define DEBUG_eNB_SCHEDULER 1 #define ENABLE_ENB_AGENT_DL_SCHEDULER //#define DISABLE_SF_TRIGGER +//#define DISABLE_CONT_STATS //#define DEBUG_HEADER_PARSING 1 //#define DEBUG_PACKET_TRACE 1 @@ -219,7 +220,6 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, //Send subframe trigger to the controller if (mac_agent_registered[module_idP]) { agent_mac_xface[module_idP]->enb_agent_send_sf_trigger(module_idP); - agent_mac_xface[module_idP]->enb_agent_send_update_mac_stats(module_idP); } #endif @@ -971,6 +971,13 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, for (CC_id=0;CC_idenb_agent_send_update_mac_stats(module_idP); + } +#endif + LOG_D(MAC,"frameP %d, subframeP %d\n",frameP,subframeP); stop_meas(&eNB_mac_inst[module_idP].eNB_scheduler); From 7ab320d9239c28927b41bd985a366be8b568a05b Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 16 Mar 2016 13:40:46 +0000 Subject: [PATCH 157/413] Prevent timing advance update to be sent without payload --- openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c index 59dc70cda7..4642f9be00 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c @@ -264,7 +264,7 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, ta_update = (ta_len > 0) ? ue_sched_ctl->ta_update : 0; // If there is nothing to schedule, just leave - if ((sdu_length_total + ta_len) <= 0) { + if ((sdu_length_total) <= 0) { return; } From 06c4b91b61ead3637be02c38bccf7babe47af437 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 17 Mar 2016 10:28:06 +0100 Subject: [PATCH 158/413] move beamforming function to PHY/MODULATION folder --- cmake_targets/CMakeLists.txt | 2 +- openair1/PHY/LTE_TRANSPORT/proto.h | 35 ------------------- .../beamforming.c | 8 ++--- openair1/PHY/MODULATION/defs.h | 34 ++++++++++++++++++ openair1/SIMULATION/LTE_PHY/dlsim.c | 8 ++--- 5 files changed, 43 insertions(+), 44 deletions(-) rename openair1/PHY/{LTE_TRANSPORT => MODULATION}/beamforming.c (98%) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 5a679cdf4a..7981ea1023 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -868,12 +868,12 @@ set(PHY_SRC ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/rar_tools.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/print_stats.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/initial_sync.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/beamforming.c ${OPENAIR1_DIR}/PHY/MODULATION/ofdm_mod.c ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep.c ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_mbsfn.c ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_ul.c ${OPENAIR1_DIR}/PHY/MODULATION/ul_7_5_kHz.c + ${OPENAIR1_DIR}/PHY/MODULATION/beamforming.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/freq_equalization.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_time.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_timefreq.c diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 416bff82c4..35de21c7b8 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -336,41 +336,6 @@ int32_t generate_pbch(LTE_eNB_PBCH *eNB_pbch, int32_t generate_pbch_emul(PHY_VARS_eNB *phy_vars_eNB,uint8_t *pbch_pdu); - -/** \brief This function performs UE specific beamforming especially for - * transmission mode TM7-10 - @param txdataF Table of pointers for frequency-domain TX signals - @param txdataF_BF Table of pointers for frequency-domain TX signals -after beamforming - @param frame_parms Frame descriptor structure - @param ue_spec_bf_weights UE specific beamforming weights applied on -each antenna element and each carrier - @param slot Slot number - @param symbol Symbol index on which to act*/ -int ue_spec_beamforming(int32_t **txdataF, - int32_t **txdataF_BF, - LTE_DL_FRAME_PARMS *frame_parms, - int32_t ***ue_spec_bf_weights, - int slot, - int symbol); - -/** \brief This function performs cell specific beamforming for common - * data - @param txdataF Table of pointers for frequency-domain TX signals - @param txdataF_BF Table of pointers for frequency-domain TX signals - @param frame_parms Frame descriptor structure -after beamforming - @param cell_spec_bf_weights Common beamforming weights applied on each -antenna element and each carrier - @param slot Slot number - @param symbol Symbol index on which to act*/ -int cell_spec_beamforming(int32_t **txdataF, - int32_t **txdataF_BF, - LTE_DL_FRAME_PARMS *frame_parms, - int32_t ***cell_spec_bf_weights, - int slot, - int symbol); - /** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream QPSK/QPSK reception. @param stream0_in Input from channel compensated (MR combined) stream 0 @param stream1_in Input from channel compensated (MR combined) stream 1 diff --git a/openair1/PHY/LTE_TRANSPORT/beamforming.c b/openair1/PHY/MODULATION/beamforming.c similarity index 98% rename from openair1/PHY/LTE_TRANSPORT/beamforming.c rename to openair1/PHY/MODULATION/beamforming.c index 7a2b75d74e..867ba0d53d 100644 --- a/openair1/PHY/LTE_TRANSPORT/beamforming.c +++ b/openair1/PHY/MODULATION/beamforming.c @@ -27,13 +27,13 @@ Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 069 *******************************************************************************/ -/*! \file PHY/LTE_TRANSPORT/beamforming.c +/*! \file PHY/MODULATION/beamforming.c * \brief - * \author R. Knopp, F. Kaltenberger, X. JIANG - * \date 2015 + * \author X. JIANG, F. Kaltenberger, R. KNOPP + * \date 2016 * \version 0.1 * \company Eurecom - * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,xiwen.jiang@eurecom.fr + * \email: xiwen.jiang@eurecom.fr,florian.kaltenberger@eurecom.fr,raymond.knopp@eurecom.fr * \note * \warning */ diff --git a/openair1/PHY/MODULATION/defs.h b/openair1/PHY/MODULATION/defs.h index 6005d6d49a..fec65b8679 100644 --- a/openair1/PHY/MODULATION/defs.h +++ b/openair1/PHY/MODULATION/defs.h @@ -99,6 +99,40 @@ void remove_625_Hz(PHY_VARS_eNB *phy_vars_eNB,int16_t *prach); void apply_625_Hz(PHY_VARS_UE *phy_vars_ue,int16_t *prach); +/** \brief This function performs UE specific beamforming especially for + * transmission mode TM7-10 + @param txdataF Table of pointers for frequency-domain TX signals + @param txdataF_BF Table of pointers for frequency-domain TX signals +after beamforming + @param frame_parms Frame descriptor structure + @param ue_spec_bf_weights UE specific beamforming weights applied on +each antenna element and each carrier + @param slot Slot number + @param symbol Symbol index on which to act*/ +int ue_spec_beamforming(int32_t **txdataF, + int32_t **txdataF_BF, + LTE_DL_FRAME_PARMS *frame_parms, + int32_t ***ue_spec_bf_weights, + int slot, + int symbol); + +/** \brief This function performs cell specific beamforming for common + * data + @param txdataF Table of pointers for frequency-domain TX signals + @param txdataF_BF Table of pointers for frequency-domain TX signals + @param frame_parms Frame descriptor structure +after beamforming + @param cell_spec_bf_weights Common beamforming weights applied on each +antenna element and each carrier + @param slot Slot number + @param symbol Symbol index on which to act*/ +int cell_spec_beamforming(int32_t **txdataF, + int32_t **txdataF_BF, + LTE_DL_FRAME_PARMS *frame_parms, + int32_t ***cell_spec_bf_weights, + int slot, + int symbol); + #endif /** @}*/ #endif diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index ba7d02b340..beb90006ae 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -134,12 +134,12 @@ void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_sl //printf("do_OFDM_mod_l, slot=%d, l=%d, NUMBER_OF_OFDM_CARRIERS=%d,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES=%d\n",next_slot, l,NUMBER_OF_OFDM_CARRIERS,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES); if (lcell_spec_bf_weights,next_slot,l); + cell_spec_beamforming(txdataF,txdataF_BF,frame_parms,eNB_common_vars->cell_spec_bf_weights[eNB_id],next_slot,l); else if (transmission_mode<7) - cell_spec_beamforming(txdataF,txdataF_BF,frame_parms,eNB_common_vars->cell_spec_bf_weights,next_slot,l); + cell_spec_beamforming(txdataF,txdataF_BF,frame_parms,eNB_common_vars->cell_spec_bf_weights[eNB_id],next_slot,l); else - ue_spec_beamforming(txdataF,txdataF_BF,frame_parms,eNB_common_vars->ue_spec_bf_weights,next_slot,l); + ue_spec_beamforming(txdataF,txdataF_BF,frame_parms,eNB_common_vars->ue_spec_bf_weights[eNB_id],next_slot,l); for (aa=0; aanb_antennas_tx; aa++) { @@ -1026,7 +1026,7 @@ int main(int argc, char **argv) for (re=0;reofdm_symbol_size;re++) { if (n_tx_phy==1 || n_tx_phy==2) ue_spec_bf_weights[aa][re] = 0x00007fff; - else if (n_tx_phy==4) + else if (n_tx_phy==4 || n_tx_phy==8) ue_spec_bf_weights[aa][re] = 0x00007fff>>1; else if (n_tx_phy==16) ue_spec_bf_weights[aa][re] = 0x00007fff>>2; From 74819596477fbe5353463e05877e6ca31a61fe24 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 18 Mar 2016 19:38:55 +0000 Subject: [PATCH 159/413] Added agent config file for band7 usrbb210 --- .../enb.band5.agent.usrpb210.epc.remote.conf | 171 ++++++++--------- .../enb.band7.agent.usrpb210.epc.remote.conf | 174 ++++++++++++++++++ 2 files changed, 260 insertions(+), 85 deletions(-) create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.usrpb210.epc.remote.conf diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf index f8c5016de5..8936b2eb24 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf @@ -3,8 +3,8 @@ Active_eNBs = ( "eNB_Eurecom_LTEBox"); Asn1_verbosity = "none"; eNBs = -( - { +( + { ////////// Identification parameters: eNB_ID = 0xe00; @@ -13,110 +13,111 @@ eNBs = eNB_name = "eNB_Eurecom_LTEBox"; // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = "1"; + tracking_area_code = "10"; mobile_country_code = "208"; mobile_network_code = "95"; ////////// Physical parameters: + + component_carriers = ( + { + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 5; + downlink_frequency = 879000000L; + uplink_frequency_offset = -45000000; + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 115; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = -26; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ - component_carriers = ( - { - frame_type = "FDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 7; - downlink_frequency = 2660000000L; - uplink_frequency_offset = -120000000; - Nid_cell = 0; - N_RB_DL = 25; - Nid_cell_mbsfn = 0; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - tx_gain = 90; - rx_gain = 125; - prach_root = 0; - prach_config_index = 0; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 1; - prach_freq_offset = 2; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = -26; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 0; - pusch_groupHoppingEnabled = "ENABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 1; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =;*/ + pusch_p0_Nominal = -90; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -108; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; +/* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; +*/ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; - pusch_p0_Nominal = -90; - pusch_alpha = "AL1"; - pucch_p0_Nominal = -108; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; - rach_numberOfRA_Preambles = 64; - rach_preamblesGroupAConfig = "DISABLE"; - /* - rach_sizeOfRA_PreamblesGroupA = ; - rach_messageSizeGroupA = ; - rach_messagePowerOffsetGroupB = ; - */ - rach_powerRampingStep = 4; - rach_preambleInitialReceivedTargetPower = -108; - rach_preambleTransMax = 10; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - } - ); + } + ); srb1_parameters : { - # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] timer_poll_retransmit = 80; - + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] timer_reordering = 35; - + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] timer_status_prohibit = 0; - + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] poll_pdu = 4; - + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] poll_byte = 99999; - + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] max_retx_threshold = 4; } diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.usrpb210.epc.remote.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.usrpb210.epc.remote.conf new file mode 100644 index 0000000000..4f6a3ba101 --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.usrpb210.epc.remote.conf @@ -0,0 +1,174 @@ +Active_eNBs = ( "eNB_Eurecom_LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB_Eurecom_LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = "10"; + + mobile_country_code = "208"; + mobile_network_code = "95"; + + ////////// Physical parameters: + + component_carriers = ( + { + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2660000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 125; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = -26; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -90; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -108; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + } + ); + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + ////////// MME parameters: + mme_ip_address = ( {ipv4 = "192.168.100.103"; + ipv6="192:168:30::17"; + active="yes"; + preference="ipv4";}); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth0:1"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.102/24"; + + ENB_INTERFACE_NAME_FOR_S1U = "eth0:1"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.102/24"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + NETWORK_CONTROLLER : + { + ENB_AGENT_INTERFACE_NAME = "eth1"; + ENB_AGENT_IPV4_ADDRESS = "10.0.0.5/30"; + ENB_AGENT_PORT = 2210; + ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; + }; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="debug"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + + } +); From aa50fcf02a8125ad66b25645970fd4fdd3f67c17 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 18 Mar 2016 19:42:38 +0000 Subject: [PATCH 160/413] Fixed HARQ reporting to agent and changed sf trigger to report the upcoming subframe --- openair1/SCHED/phy_procedures_lte_eNb.c | 14 +++++++++++++ openair2/ENB_APP/enb_agent.c | 7 +++++++ openair2/ENB_APP/enb_agent_common.c | 26 +++++++++++++++++++++++++ openair2/ENB_APP/enb_agent_common.h | 2 ++ openair2/ENB_APP/enb_agent_mac.c | 26 +++++++++++++++++++++---- openair2/LAYER2/MAC/eNB_scheduler.c | 14 +++++++------ 6 files changed, 79 insertions(+), 10 deletions(-) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 375c0dcd1f..d843ebbaab 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -67,6 +67,12 @@ # endif #endif + +//Agent-related headers +#include "ENB_APP/enb_agent_extern.h" +#include "ENB_APP/enb_agent_mac.h" +#include "LAYER2/MAC/enb_agent_mac_proto.h" + //#define DIAG_PHY #define NS_PER_SLOT 500000 @@ -1411,6 +1417,7 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e #endif #endif + if (abstraction_flag == 0) { start_meas(&phy_vars_eNB->dlsch_encoding_stats); @@ -1603,6 +1610,13 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e phy_vars_eNB->dlsch_eNB_ra->active = 0; } +#ifndef DISABLE_SF_TRIGGER + //Send subframe trigger to the controller + if (mac_agent_registered[phy_vars_eNB->Mod_id]) { + agent_mac_xface[phy_vars_eNB->Mod_id]->enb_agent_send_sf_trigger(phy_vars_eNB->Mod_id); + } +#endif + // Now scan UE specific DLSCH for (UE_id=0; UE_idnum_UEs; diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 1c4d478aab..9b483ce4a0 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -145,6 +145,8 @@ unsigned int get_current_subframe(mid_t mod_id); Bits 0-3 subframe, rest for frame. Required by progRAN protocol*/ uint16_t get_sfn_sf (mid_t mod_id); +uint16_t get_future_sfn_sf(mid_t mod_id, int ahead_of_time); + int get_num_ues(mid_t mod_id); int get_ue_crnti (mid_t mod_id, mid_t ue_id); diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 296da7f1d2..fb9ae7322f 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -947,9 +947,27 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran } protocol__prp_sf_trigger__init(sf_trigger_msg); + frame_t frame; + sub_frame_t subframe; + + int ahead_of_time = 1; + + frame = (frame_t) get_current_system_frame_num(mod_id); + subframe = (sub_frame_t) get_current_subframe(mod_id); + + subframe = ((subframe + ahead_of_time) % 10); + + int full_frames_ahead = ((ahead_of_time / 10) % 10); + + frame = frame + full_frames_ahead; + + if (subframe < get_current_subframe(mod_id)) { + frame++; + } + sf_trigger_msg->header = header; sf_trigger_msg->has_sfn_sf = 1; - sf_trigger_msg->sfn_sf = get_sfn_sf(mod_id); + sf_trigger_msg->sfn_sf = get_future_sfn_sf(mod_id, 1); /*TODO: Fill in the number of dl HARQ related info, based on the number of currently *transmitting UEs @@ -973,7 +991,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran /*TODO: fill in the right id of this round's HARQ process for this UE*/ int harq_id; int harq_status; - get_harq(mod_id,UE_PCCID(mod_id,i),i,get_current_frame(mod_id),get_current_subframe(mod_id),&harq_id, &harq_status); + get_harq(mod_id, UE_PCCID(mod_id,i), i, frame, subframe, &harq_id, &harq_status); dl_info[i]->harq_process_id = harq_id; dl_info[i]->has_harq_process_id = 1; /*TODO: fill in the status of the HARQ process (2 TBs)*/ @@ -1369,8 +1387,8 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_send_sr_info = enb_agent_send_sr_info; xface->enb_agent_send_sf_trigger = enb_agent_send_sf_trigger; xface->enb_agent_send_update_mac_stats = enb_agent_send_update_mac_stats; - xface->enb_agent_schedule_ue_spec = schedule_ue_spec_default; - //xface->enb_agent_schedule_ue_spec = schedule_ue_spec_remote; + //xface->enb_agent_schedule_ue_spec = schedule_ue_spec_default; + xface->enb_agent_schedule_ue_spec = schedule_ue_spec_remote; xface->enb_agent_get_pending_dl_mac_config = enb_agent_get_pending_dl_mac_config; xface->enb_agent_notify_ue_state_change = enb_agent_ue_state_change; diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 06e115b392..3285b2b6dd 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -216,12 +216,12 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } -#ifndef DISABLE_SF_TRIGGER - //Send subframe trigger to the controller - if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_send_sf_trigger(module_idP); - } -#endif +/* #ifndef DISABLE_SF_TRIGGER */ +/* //Send subframe trigger to the controller */ +/* if (mac_agent_registered[module_idP]) { */ +/* agent_mac_xface[module_idP]->enb_agent_send_sf_trigger(module_idP); */ +/* } */ +/* #endif */ //if (subframeP%5 == 0) //#ifdef EXMIMO @@ -971,6 +971,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, for (CC_id=0;CC_id Date: Mon, 21 Mar 2016 16:52:03 +0100 Subject: [PATCH 161/413] bug fixed in beamforming.c --- openair1/PHY/MODULATION/beamforming.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openair1/PHY/MODULATION/beamforming.c b/openair1/PHY/MODULATION/beamforming.c index 867ba0d53d..157b8eb368 100644 --- a/openair1/PHY/MODULATION/beamforming.c +++ b/openair1/PHY/MODULATION/beamforming.c @@ -61,7 +61,7 @@ int ue_spec_beamforming(int32_t **txdataF, slot_offset_F = slot*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); - // clear txdata_BF[aa][re] for each call of spec_spec_beamforming + // clear txdata_BF[aa][re] for each call of ue_spec_beamforming for(aa=0;aanb_antennas_tx;aa++) memset(txdataF_BF[aa],0,4*(frame_parms->ofdm_symbol_size)); @@ -89,7 +89,7 @@ int ue_spec_beamforming(int32_t **txdataF, } } - if (txdataF[7][re+symbol*frame_parms->ofdm_symbol_size]!=0) { //that means this RE is actually using TM8-10 + if (txdataF[7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually using TM8-10 for (p=0;p<8;p++) { if (txdataF[p+7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually allocated for (aa=0;aanb_antennas_tx;aa++) { @@ -130,7 +130,6 @@ int cell_spec_beamforming(int32_t **txdataF, for (p=0;pnb_antenna_ports_eNB;p++) { if (txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually allocated for (aa=0;aanb_antennas_tx;aa++) { - //printf("cell_spec_beamforming():txdata_BF[%d][%d]=%d+j%d\n",aa,re,((int16_t*)&txdataF_BF[aa][re])[0],((int16_t*)&txdataF_BF[aa][re])[1]); ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0] *((int16_t*)&cell_spec_bf_weights[p][aa][re])[0])>>15); @@ -154,6 +153,10 @@ int cell_spec_beamforming(int32_t **txdataF, } } } + + + + /* int ue_spec_beamforming(int32_t **txdataF, int32_t **txdataF_BF, From 9fca33136d955aa74f2d4e7556fa7e3261ef18e9 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 21 Mar 2016 16:53:35 +0100 Subject: [PATCH 162/413] move symbol level ifft including beamforming into ofdm_mod.c --- openair1/PHY/MODULATION/ofdm_mod.c | 55 +++++++++++++++++++++++++++++ openair1/SIMULATION/LTE_PHY/dlsim.c | 54 ---------------------------- 2 files changed, 55 insertions(+), 54 deletions(-) diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 3dd76c0fbb..e8344a1972 100755 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -276,4 +276,59 @@ void do_OFDM_mod(mod_sym_t **txdataF, int32_t **txdata, uint32_t frame,uint16_t } +// OFDM modulation for each symbol +void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms, uint8_t num_pdcch_symbols, unsigned char transmission_mode) +{ + + int aa, l, slot_offset, slot_offset_F; + mod_sym_t **txdataF = eNB_common_vars->txdataF[eNB_id]; + mod_sym_t **txdataF_BF = eNB_common_vars->txdataF_BF[eNB_id]; + int32_t **txdata = eNB_common_vars->txdata[eNB_id]; + + //slot_offset_F = (next_slot)*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); + slot_offset = (next_slot)*(frame_parms->samples_per_tti>>1); + + // printf("Thread %d starting ... aa %d (%llu)\n",omp_get_thread_num(),aa,rdtsc()); + for (l=0; lsymbols_per_tti>>1; l++) { + + //printf("do_OFDM_mod_l, slot=%d, l=%d, NUMBER_OF_OFDM_CARRIERS=%d,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES=%d\n",next_slot, l,NUMBER_OF_OFDM_CARRIERS,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES); + if (lcell_spec_bf_weights[eNB_id],next_slot,l); + else + if (transmission_mode<7) + cell_spec_beamforming(txdataF,txdataF_BF,frame_parms,eNB_common_vars->cell_spec_bf_weights[eNB_id],next_slot,l); + else + ue_spec_beamforming(txdataF,txdataF_BF,frame_parms,eNB_common_vars->ue_spec_bf_weights[eNB_id],next_slot,l); + + for (aa=0; aanb_antennas_tx; aa++) { + + if (frame_parms->Ncp == 1) + PHY_ofdm_mod(txdataF_BF[aa], // input + &txdata[aa][slot_offset+l*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES], // output + frame_parms->ofdm_symbol_size, + 1, // number of symbols + frame_parms->nb_prefix_samples, // number of prefix samples + CYCLIC_PREFIX); + else { + if (l==0) { + PHY_ofdm_mod(txdataF_BF[aa], // input + &txdata[aa][slot_offset], // output + frame_parms->ofdm_symbol_size, + 1, // number of symbols + frame_parms->nb_prefix_samples0, // number of prefix samples + CYCLIC_PREFIX); + + } else { + PHY_ofdm_mod(txdataF_BF[aa], // input + &txdata[aa][slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES], // output + frame_parms->ofdm_symbol_size, + 1, // number of symbols + frame_parms->nb_prefix_samples, // number of prefix samples + CYCLIC_PREFIX); + } + } + } + } + +} /** @} */ diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index beb90006ae..81a27f4a53 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -118,60 +118,6 @@ uint64_t DLSCH_alloc_pdu_1[2]; #define CCCH_RB_ALLOC computeRIV(PHY_vars_eNB->lte_frame_parms.N_RB_UL,0,2) //#define DLSCH_RB_ALLOC 0x1fbf // igore DC component,RB13 //#define DLSCH_RB_ALLOC 0x0001 -void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms, uint8_t num_pdcch_symbols, unsigned char transmission_mode) -{ - - int aa, l, slot_offset, slot_offset_F; - mod_sym_t **txdataF = eNB_common_vars->txdataF[eNB_id]; - mod_sym_t **txdataF_BF = eNB_common_vars->txdataF_BF[eNB_id]; - int32_t **txdata = eNB_common_vars->txdata[eNB_id]; - - //slot_offset_F = (next_slot)*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); - slot_offset = (next_slot)*(frame_parms->samples_per_tti>>1); - - // printf("Thread %d starting ... aa %d (%llu)\n",omp_get_thread_num(),aa,rdtsc()); - for (l=0; lsymbols_per_tti>>1; l++) { - - //printf("do_OFDM_mod_l, slot=%d, l=%d, NUMBER_OF_OFDM_CARRIERS=%d,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES=%d\n",next_slot, l,NUMBER_OF_OFDM_CARRIERS,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES); - if (lcell_spec_bf_weights[eNB_id],next_slot,l); - else - if (transmission_mode<7) - cell_spec_beamforming(txdataF,txdataF_BF,frame_parms,eNB_common_vars->cell_spec_bf_weights[eNB_id],next_slot,l); - else - ue_spec_beamforming(txdataF,txdataF_BF,frame_parms,eNB_common_vars->ue_spec_bf_weights[eNB_id],next_slot,l); - - for (aa=0; aanb_antennas_tx; aa++) { - - if (frame_parms->Ncp == 1) - PHY_ofdm_mod(txdataF_BF[aa], // input - &txdata[aa][slot_offset+l*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES], // output - frame_parms->ofdm_symbol_size, - 1, // number of symbols - frame_parms->nb_prefix_samples, // number of prefix samples - CYCLIC_PREFIX); - else { - if (l==0) { - PHY_ofdm_mod(txdataF_BF[aa], // input - &txdata[aa][slot_offset], // output - frame_parms->ofdm_symbol_size, - 1, // number of symbols - frame_parms->nb_prefix_samples0, // number of prefix samples - CYCLIC_PREFIX); - - } else { - PHY_ofdm_mod(txdataF_BF[aa], // input - &txdata[aa][slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES], // output - frame_parms->ofdm_symbol_size, - 1, // number of symbols - frame_parms->nb_prefix_samples, // number of prefix samples - CYCLIC_PREFIX); - } - } - } - } - -} int main(int argc, char **argv) { From 9fcca73f538bf710d25f93ea9e03758d821a4b8e Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 21 Mar 2016 16:55:26 +0100 Subject: [PATCH 163/413] lte softmodem adaption for massive antennas (not complete) --- openair1/PHY/INIT/lte_init.c | 2 +- openair1/PHY/impl_defs_lte.h | 5 +++++ openair1/SCHED/phy_procedures_lte_eNb.c | 23 +++++++++++++++-------- targets/RT/USER/lte-softmodem.c | 4 ++-- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index e604d599a1..672a3a51ef 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1305,7 +1305,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, for (i=0; i<2; i++) { // 2 is the total number of cell specific antenna ports eNB_common_vars->cell_spec_bf_weights[eNB_id][i] = (int32_t **)malloc16_clear(frame_parms->nb_antennas_tx*sizeof(int32_t*)); for (j=0; jnb_antennas_tx; j++) { - eNB_common_vars->cell_spec_bf_weights[eNB_id][i][j] = (int32_t*)malloc16_clear(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); + eNB_common_vars->cell_spec_bf_weights[eNB_id][i][j] = (int32_t *)malloc16_clear(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); #ifdef DEBUG_PUY msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->cell_spec_bf_weights[%d][%d][%d] = %p (%d bytes)\n", eNB_id,i,j,eNB_common_vars->cell_spec_bf_weights[eNB_id][i][j], diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h index 134a92e15d..864d2d5d19 100644 --- a/openair1/PHY/impl_defs_lte.h +++ b/openair1/PHY/impl_defs_lte.h @@ -645,6 +645,11 @@ typedef struct { /// - third index: tx antenna [0..nb_antennas_tx[ /// - fourth index: sample [0..] int32_t **ue_spec_bf_weights[3][8]; + /// \brief Holds the tdd reciprocity calibration coefficients + /// - first index: eNB id [0..2] (hard coded) + /// - second index: tx antenna [0..nb_antennas_tx[ + /// - third index: frenquency [0..] + int32_t **tdd_calib_coeffs[3]; } LTE_eNB_COMMON; typedef struct { diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 082f0c0568..dece28f78e 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -2520,14 +2520,21 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e if (abstraction_flag==0) { start_meas(&phy_vars_eNB->ofdm_mod_stats); - do_OFDM_mod(phy_vars_eNB->lte_eNB_common_vars.txdataF[0], - phy_vars_eNB->lte_eNB_common_vars.txdata[0], - phy_vars_eNB->proc[sched_subframe].frame_tx,subframe<<1, - &phy_vars_eNB->lte_frame_parms); - do_OFDM_mod(phy_vars_eNB->lte_eNB_common_vars.txdataF[0], - phy_vars_eNB->lte_eNB_common_vars.txdata[0], - phy_vars_eNB->proc[sched_subframe].frame_tx,1+(subframe<<1), - &phy_vars_eNB->lte_frame_parms); + + do_OFDM_mod_l(phy_vars_eNB->lte_eNB_common_vars, + 0, + subframe<<1, + &phy_vars_eNB->lte_frame_parms, + num_pdcch_symbols, + eNB->transmission_mode[(uint8_t)UE_id]); + + do_OFDM_mod_l(phy_vars_eNB->lte_eNB_common_vars, + 0, + 1+(subframe<<1), + &phy_vars_eNB->lte_frame_parms, + num_pdcch_symbols, + eNB->transmission_mode[(uint8_t)UE_id]); + stop_meas(&phy_vars_eNB->ofdm_mod_stats); } diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 72d32fbdef..0fe4e2342c 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -2755,7 +2755,7 @@ int main( int argc, char **argv ) frame_parms[CC_id]->nb_antenna_ports_eNB = (transmission_mode == 1 || transmission_mode ==7) ? 1 : 2; //initial value overwritten by initial sync later } - frame_parms[CC_id]->mode1_flag = (transmission_mode == 1) ? 1 : 0; + frame_parms[CC_id]->mode1_flag = (transmission_mode == 1 || transmission_mode ==7) ? 1 : 0; frame_parms[CC_id]->phich_config_common.phich_resource = oneSixth; frame_parms[CC_id]->phich_config_common.phich_duration = normal; // UL RS Config @@ -3188,7 +3188,7 @@ int main( int argc, char **argv ) openair_daq_vars.timing_advance = 160; #endif if (setup_ue_buffers(UE,&openair0_cfg[0],rf_map)!=0) { - printf("Error setting up eNB buffer\n"); + printf("Error setting up UE buffer\n"); exit(-1); } From 3c7f2ff3cef9b9081fe90f079b99333c3d3fe2af Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 25 Mar 2016 09:19:34 +0100 Subject: [PATCH 164/413] fill dci for TM7 --- openair1/SCHED/phy_mac_stub.c | 2 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/openair1/SCHED/phy_mac_stub.c b/openair1/SCHED/phy_mac_stub.c index 9bcba1072c..62ca6ea8d0 100644 --- a/openair1/SCHED/phy_mac_stub.c +++ b/openair1/SCHED/phy_mac_stub.c @@ -226,7 +226,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e DCI_pdu->dci_alloc[0].format = format1; DCI_pdu->dci_alloc[0].ra_flag = 0; - if (transmission_mode<3) { + if (transmission_mode<3 || transmission_mode == 7) { //user 1 switch (phy_vars_eNB->lte_frame_parms.N_RB_DL) { case 25: diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index cd2c89f3c2..206ea63ae0 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -1151,7 +1151,7 @@ int main(int argc, char **argv) P_RNTI, PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single); - if(transmission_mode==7) + if (transmission_mode == 7) PHY_vars_eNB->dlsch_eNB[0][0]->harq_processes[0]->mimo_mode = TM7; //Xiwen: to check about harq_pid num_dci++; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 2a52d8779a..ca05786371 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -653,6 +653,7 @@ schedule_ue_spec( switch (mac_xface->get_transmission_mode(module_idP,CC_id,rnti)) { case 1: case 2: + case 7: default: switch (frame_parms[CC_id]->N_RB_DL) { case 6: @@ -1545,6 +1546,8 @@ fill_DLSCH_dci( case 1: case 2: + + case 7: LOG_D(MAC,"[eNB %d] CC_id %d Adding UE %d spec DCI for %d PRBS \n",module_idP, CC_id, UE_id, nb_rb); if (PHY_vars_eNB_g[module_idP][CC_id]->lte_frame_parms.frame_type == TDD) { From 7236e3ca177e11858df555a708e26f86efd90921 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 6 Apr 2016 13:34:37 +0100 Subject: [PATCH 165/413] Bugfixes to improve stability --- openair2/ENB_APP/enb_agent_common.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 2be189a2cd..f06599e258 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -561,7 +561,6 @@ int get_ue_phr (mid_t mod_id, mid_t ue_id) { } int get_ue_wcqi (mid_t mod_id, mid_t ue_id) { - return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].dl_cqi; } int get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) @@ -576,6 +575,10 @@ int get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) { rnti_t rnti = 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; + } int32_t time_advance; switch (PHY_vars_eNB_g[mod_id][CC_id]->lte_frame_parms.N_RB_DL) { @@ -622,6 +625,11 @@ int get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) rnti_t rnti = 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; } @@ -636,10 +644,16 @@ int get_tpc(mid_t mod_id, mid_t ue_id) eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, pCCid, rnti); - normalized_rx_power = eNB_UE_stats->UL_rssi[0]; - 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)) { @@ -680,6 +694,11 @@ int get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id) uint32_t rnti = 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; From 6b15195ac58e33fb4aab6d28bc4548e59944873a Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 7 Apr 2016 09:28:35 +0100 Subject: [PATCH 166/413] Added statistics for total and missed scheduling deadlines of remote scheduler --- openair2/LAYER2/MAC/defs.h | 7 +++++++ .../MAC/eNB_agent_scheduler_dlsch_ue_remote.c | 14 ++++++++++++++ openair2/LAYER2/openair2_proc.c | 6 ++++-- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index cd2d593726..7c0561121d 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -462,6 +462,13 @@ typedef struct { // uint32_t total_ulsch_pdus_rx; + + /// MAC agent-related stats + /// total number of scheduling decisions + int sched_decisions; + /// missed deadlines + int missed_deadlines; + } eNB_STATS; /*! \brief eNB statistics for the connected UEs*/ typedef struct { diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c index 90181f0e44..ad8b130584 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c @@ -39,6 +39,9 @@ #include "eNB_agent_scheduler_dlsch_ue_remote.h" +#include "LAYER2/MAC/defs.h" +#include "LAYER2/MAC/extern.h" + struct DlMacConfigHead queue_head; int queue_initialized = 0; @@ -46,10 +49,15 @@ int queue_initialized = 0; void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, Protocol__ProgranMessage **dl_info) { + + eNB_MAC_INST *eNB; + if (!queue_initialized) { TAILQ_INIT(&queue_head); queue_initialized = 1; } + + eNB = &eNB_mac_inst[mod_id]; dl_mac_config_element_t *dl_config_elem; @@ -66,12 +74,15 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs); *dl_info = dl_config_elem->dl_info; free(dl_config_elem); + eNB->eNB_stats[mod_id].sched_decisions++; return; } else if (diff < 0) { //previous subframe , delete message and free memory LOG_D(MAC, "Found a decision for a previous subframe in the queue. Let's get rid of it\n"); TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs); enb_agent_mac_destroy_dl_config(dl_config_elem->dl_info); free(dl_config_elem); + eNB->eNB_stats[mod_id].sched_decisions++; + eNB->eNB_stats[mod_id].missed_deadlines++; } else { // next subframe, nothing to do now LOG_D(MAC, "Found a decision for a future subframe in the queue. Nothing to do now\n"); enb_agent_mac_create_empty_dl_config(mod_id, dl_info); @@ -86,12 +97,15 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, diff = get_sf_difference(mod_id, (*dl_info)->dl_mac_config_msg->sfn_sf); if (diff == 0) { // Got a command for this sfn_sf LOG_D(MAC, "Found a decision for this subframe pending. Let's use it\n"); + eNB->eNB_stats[mod_id].sched_decisions++; return; } else if (diff < 0) { LOG_D(MAC, "Found a decision for a previous subframe. Let's get rid of it\n"); enb_agent_mac_destroy_dl_config(*dl_info); *dl_info = NULL; enb_agent_get_pending_dl_mac_config(mod_id, dl_info); + eNB->eNB_stats[mod_id].sched_decisions++; + eNB->eNB_stats[mod_id].missed_deadlines++; } else { // Intended for future subframe. Store it in local cache LOG_D(MAC, "Found a decision for a future subframe in the queue. Let's store it in the cache\n"); dl_mac_config_element_t *e = malloc(sizeof(dl_mac_config_element_t)); diff --git a/openair2/LAYER2/openair2_proc.c b/openair2/LAYER2/openair2_proc.c index e09adaea8c..4556bafeec 100644 --- a/openair2/LAYER2/openair2_proc.c +++ b/openair2/LAYER2/openair2_proc.c @@ -122,11 +122,13 @@ int dump_eNB_l2_stats(char *buffer, int length) for (CC_id=0 ; CC_id < MAX_NUM_CCs; CC_id++) { eNB->eNB_stats[CC_id].dlsch_bitrate= 0; - len += sprintf(&buffer[len],"eNB %d CC %d Frame %d: Active UEs %d, Available PRBs %d, nCCE %d \n", + len += sprintf(&buffer[len],"eNB %d CC %d Frame %d: Active UEs %d, Available PRBs %d, nCCE %d, Scheduling decisions %d, Missed Deadlines %d \n", eNB_id, CC_id, eNB->frame, eNB->eNB_stats[CC_id].num_dlactive_UEs, eNB->eNB_stats[CC_id].available_prbs, - eNB->eNB_stats[CC_id].available_ncces); + eNB->eNB_stats[CC_id].available_ncces, + eNB->eNB_stats[CC_id].sched_decisions, + eNB->eNB_stats[CC_id].missed_deadlines); len += sprintf(&buffer[len],"BCCH , NB_TX_MAC = %d, transmitted bytes (TTI %d, total %d) MCS (TTI %d)\n", eNB->eNB_stats[CC_id].total_num_bcch_pdu, From 9c9d3f45801e37bede099320330d2a619d363dff Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 12 Apr 2016 12:56:13 +0100 Subject: [PATCH 167/413] Added build support for packages required for the agent-enabled eNB --- cmake_targets/CMakeLists.txt | 14 ++++++++++--- cmake_targets/tools/build_helper | 36 +++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 1224768142..2db18176b4 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -911,6 +911,7 @@ if (ENB_AGENT_SB_IF) add_library(ENB_AGENT ${OPENAIR2_DIR}/ENB_APP/enb_agent_handler.c ${OPENAIR2_DIR}/ENB_APP/enb_agent_common.c + ${OPENAIR2_DIR}/ENB_APP/enb_agent_common_internal.c ${OPENAIR2_DIR}/ENB_APP/enb_agent_mac.c ${OPENAIR2_DIR}/ENB_APP/enb_agent.c ${OPENAIR2_DIR}/ENB_APP/enb_agent_task_manager.c @@ -923,6 +924,13 @@ if (ENB_AGENT_SB_IF) set(PROTOBUF_LIB "protobuf-c") + FIND_PATH(LIBYAML_INCLUDE_DIR NAMES yaml.h) + FIND_LIBRARY(LIBYAML_LIBRARIES NAMES yaml libyaml) + + INCLUDE(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(Yaml DEFAULT_MSG LIBYAML_LIBRARIES LIBYAML_INCLUDE_DIR) + MARK_AS_ADVANCED(LIBYAML_INCLUDE_DIR LIBYAML_LIBRARIES) + #set(PROTOBUF_LIB "protobuf") #for Cpp endif() @@ -1703,7 +1711,7 @@ target_link_libraries (lte-softmodem target_link_libraries (lte-softmodem ${LIBXML2_LIBRARIES}) -target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${option_HW_lib} ${option_TP_lib} ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS}) +target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${option_HW_lib} ${option_TP_lib} ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES}) target_link_libraries (lte-softmodem ${LIBBOOST_LIBRARIES}) target_link_libraries (lte-softmodem ${LIB_LMS_LIBRARIES}) @@ -1737,7 +1745,7 @@ target_link_libraries (lte-softmodem-nos1 -Wl,--end-group ) target_link_libraries (lte-softmodem-nos1 ${LIBXML2_LIBRARIES}) -target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib} ${option_TP_lib} ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS}) +target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib} ${option_TP_lib} ${XFORMS_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES}) target_link_libraries (lte-softmodem-nos1 ${LIBBOOST_LIBRARIES}) target_link_libraries (lte-softmodem-nos1 ${LIB_LMS_LIBRARIES}) @@ -1874,7 +1882,7 @@ target_link_libraries (oaisim_nos1 target_link_libraries (oaisim_nos1 ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) target_link_libraries (oaisim_nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib} ${option_TP_lib} - ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS}) + ${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES} ${PROTOBUF_LIB} ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES}) #Force link with forms, regardless XFORMS option target_link_libraries (oaisim_nos1 forms) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 294c5006a5..498dfbe7a9 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -146,6 +146,37 @@ install_nettle_from_source() { rm -rf /tmp/nettle-2.5.tar.gz /tmp/nettle-2.5 } + +install_protobuf_from_source(){ + cd /tmp + echo "Downloading protobuf" + rm -rf /tmp/protobuf-2.6.1.tar.gz* /tmp/protobuf-2.6.1 + wget https://github.com/google/protobuf/releases/download/v2.6.1/protobuf-2.6.1.tar.gz + tar -xzvf protobuf-2.6.1.tar.gz + cd protobuf-2.6.1/ + ./configure + echo "Compiling protobuf" + make -j`nproc` + $SUDO make install + rm -rf /tmp/protobuf-2.6.1.tar.gz /tmp/protobuf-2.6.1 + $SUDO ldconfig +} + +install_protobuf_c_from_source(){ + cd /tmp + echo "Downloading protobuf-c" + rm -rf /tmp/protobuf-c + git clone https://github.com/protobuf-c/protobuf-c.git + cd protobuf-c + ./autogen.sh + ./configure + echo "Compiling protobuf-c" + make -j`nproc` + $SUDO make install + rm -rf /tmp/protobuf-c + $SUDO ldconfig +} + install_gnutls_from_source(){ cd /tmp echo "Downloading gnutls archive" @@ -271,7 +302,8 @@ check_install_oai_software() { python-numpy \ sshpass \ libxslt1-dev \ - android-tools-adb + android-tools-adb \ + libyaml-dev $SUDO update-alternatives --set liblapack.so /usr/lib/atlas-base/atlas/liblapack.so if [ `lsb_release -rs` = '12.04' ] ; then @@ -285,6 +317,8 @@ check_install_oai_software() { install_asn1c_from_source $SUDO rm -fr /opt/ssh $SUDO git clone https://gist.github.com/2190472.git /opt/ssh + install_protobuf_from_source + install_protobuf_c_from_source } install_asn1c_from_source(){ From dd2e208361bd0d2a7280567ec0b1d7629d7da0d3 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 12 Apr 2016 12:56:55 +0100 Subject: [PATCH 168/413] Added protocol support for agent policy reconfiguration --- openair2/ENB_APP/MESSAGES/V2/header.proto | 1 + openair2/ENB_APP/MESSAGES/V2/progran.proto | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index 6ce9959104..44ad93e16b 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -38,5 +38,6 @@ enum prp_type { // Control delegation messages PRPT_DELEGATE_CONTROL = 15; + PRPT_RECONFIGURE_AGENT = 16; } diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto index 6b7b784629..235aba4363 100644 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ b/openair2/ENB_APP/MESSAGES/V2/progran.proto @@ -27,6 +27,7 @@ message progran_message { prp_dl_mac_config dl_mac_config_msg = 14; prp_ue_state_change ue_state_change_msg = 15; prp_control_delegation control_delegation_msg = 16; + prp_agent_reconfiguration agent_reconfiguration_msg = 17; } } @@ -180,7 +181,16 @@ message prp_control_delegation { optional prp_header header = 1; optional uint32 delegation_type = 2; // Bitmap of PRCDT_* flags optional bytes payload = 3; // Byte array of shared lib containing the delegated functions - repeated string name = 4; // The delegated functions names ordered based on bitmap flags + optional string name = 4; // The delegated functions names ordered based on bitmap flags +} + +// +// Agent reconfiguration message +// + +message prp_agent_reconfiguration { + optional prp_header header = 1; + optional string policy = 2; // The policy changes using YAML syntax in string format } // Extensions of the echo request and reply From a47f3654f8c347838b46de3e01d5a4dad9d46af5 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Tue, 12 Apr 2016 13:00:20 +0100 Subject: [PATCH 169/413] Added basic support for policy reconfiguration using yaml parser --- openair2/ENB_APP/enb_agent_common.c | 37 +- openair2/ENB_APP/enb_agent_common.h | 3 + openair2/ENB_APP/enb_agent_common_internal.c | 400 ++++++++++++++++++ openair2/ENB_APP/enb_agent_common_internal.h | 64 +++ openair2/ENB_APP/enb_agent_handler.c | 3 +- openair2/ENB_APP/enb_agent_mac.c | 4 + openair2/ENB_APP/enb_agent_mac_defs.h | 2 + openair2/ENB_APP/enb_agent_mac_internal.c | 235 ++++++++++ openair2/ENB_APP/enb_agent_mac_internal.h | 15 +- .../MAC/eNB_agent_scheduler_dlsch_ue_remote.c | 18 + 10 files changed, 758 insertions(+), 23 deletions(-) create mode 100644 openair2/ENB_APP/enb_agent_common_internal.c create mode 100644 openair2/ENB_APP/enb_agent_common_internal.h diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index f06599e258..e21c180cec 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -35,10 +35,10 @@ */ #include -#include #include #include "enb_agent_common.h" +#include "enb_agent_common_internal.h" #include "enb_agent_extern.h" #include "PHY/extern.h" #include "log.h" @@ -403,7 +403,6 @@ int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__Pro uint32_t delegation_type = control_delegation_msg->delegation_type; - void *lib; int i; struct timespec vartime = timer_start(); @@ -411,7 +410,7 @@ int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__Pro //Write the payload lib into a file in the cache and load the lib char lib_name[120]; char target[512]; - snprintf(lib_name, sizeof(lib_name), "/delegation_lib_%d.so", control_delegation_msg->header->xid); + snprintf(lib_name, sizeof(lib_name), "/%s.so", control_delegation_msg->name); strcpy(target, local_cache); strcat(target, lib_name); @@ -419,25 +418,7 @@ int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__Pro f = fopen(target, "wb"); fwrite(control_delegation_msg->payload.data, control_delegation_msg->payload.len, 1, f); fclose(f); - lib = dlopen(target, RTLD_NOW); - if (lib == NULL) { - goto error; - } - i = 0; - //Check functions that need to be delegated - - //DL UE scheduler delegation - if (delegation_type & PROTOCOL__PRP_CONTROL_DELEGATION_TYPE__PRCDT_MAC_DL_UE_SCHEDULER) { - void *loaded_scheduler = dlsym(lib, control_delegation_msg->name[i]); - i++; - if (loaded_scheduler) { - if (mac_agent_registered[mod_id]) { - agent_mac_xface[mod_id]->enb_agent_schedule_ue_spec = loaded_scheduler; - LOG_D(ENB_APP,"Delegated control for DL UE scheduler successfully\n"); - } - } - } long time_elapsed_nanos = timer_end(vartime); *msg = NULL; return 0; @@ -450,6 +431,20 @@ int enb_agent_destroy_control_delegation(Protocol__ProgranMessage *msg) { /*TODO: Dealocate memory for a dynamically allocated control delegation message*/ } +int enb_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { + Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; + Protocol__PrpAgentReconfiguration *agent_reconfiguration_msg = input->agent_reconfiguration_msg; + + apply_reconfiguration_policy(mod_id, agent_reconfiguration_msg->policy, strlen(agent_reconfiguration_msg->policy)); + + *msg = NULL; + return 0; +} + +int enb_agent_destroy_agent_reconfiguration(Protocol__ProgranMessage *msg) { + /*TODO: Dealocate memory for a dynamically allocated agent reconfiguration message*/ +} + /* * get generic info from RAN */ diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 9b483ce4a0..18c9129989 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -114,6 +114,9 @@ int enb_agent_destroy_ue_state_change(Protocol__ProgranMessage *msg); int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); int enb_agent_destroy_control_delegation(Protocol__ProgranMessage *msg); +int enb_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_destroy_agent_reconfiguration(Protocol__ProgranMessage *msg); + Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, uint8_t *data, uint32_t size); diff --git a/openair2/ENB_APP/enb_agent_common_internal.c b/openair2/ENB_APP/enb_agent_common_internal.c new file mode 100644 index 0000000000..ca61a96609 --- /dev/null +++ b/openair2/ENB_APP/enb_agent_common_internal.c @@ -0,0 +1,400 @@ +/******************************************************************************* + 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 enb_agent_common_internal.c + * \brief internal functions for common message primitves and utilities + * \author Xenofon Foukas + * \date 2016 + * \version 0.1 + */ + +#include +#include + +#include "enb_agent_common_internal.h" +#include "enb_agent_mac_internal.h" + +int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy_length) { + + yaml_parser_t parser; + yaml_event_t event; + + int done = 0; + int mapping_started = 0; + + LOG_I(ENB_APP, "Time to apply a new policy \n"); + + yaml_parser_initialize(&parser); + + yaml_parser_set_input_string(&parser, policy, strlen(policy)); + + while (!done) { + if (!yaml_parser_parse(&parser, &event)) + goto error; + + switch (event.type) { + case YAML_STREAM_START_EVENT: + case YAML_STREAM_END_EVENT: + case YAML_DOCUMENT_START_EVENT: + case YAML_DOCUMENT_END_EVENT: + break; + case YAML_MAPPING_START_EVENT: + mapping_started = 1; + break; + case YAML_MAPPING_END_EVENT: + mapping_started = 0; + break; + case YAML_SCALAR_EVENT: + // Check the system name and call the proper handler + if (strcmp(event.data.scalar.value, "mac") == 0) { + LOG_D(ENB_APP, "This is intended for the mac system\n"); + // Call the mac handler + if (parse_mac_config(mod_id, &parser) == -1) { + goto error; + } + } else if (strcmp(event.data.scalar.value, "rlc") == 0) { + // Call the RLC handler + LOG_D(ENB_APP, "This is intended for the rlc system\n"); + // TODO : Just skip it for now + if (skip_system_section(&parser) == -1) { + goto error; + } + } else if (strcmp(event.data.scalar.value, "pdcp") == 0) { + // Call the PDCP handler + LOG_D(ENB_APP, "This is intended for the pdcp system\n"); + // TODO : Just skip it for now + if (skip_system_section(&parser) == -1) { + goto error; + } + } else if (strcmp(event.data.scalar.value, "rrc") == 0) { + // Call the RRC handler + LOG_D(ENB_APP, "This is intended for the rrc system\n"); + // TODO : Just skip it for now + if (skip_system_section(&parser) == -1) { + goto error; + } + } else { + goto error; + } + break; + default: + // We are not expecting to find any other type of event at this level + // of the hierarchy + yaml_event_delete(&event); + goto error; + } + + done = (event.type == YAML_STREAM_END_EVENT); + + yaml_event_delete(&event); + } + + return 0; + + error: + yaml_parser_delete(&parser); + return -1; + +} + +int skip_system_section(yaml_parser_t *parser) { + yaml_event_t event; + + int done = 0; + + int sequence_started = 0; + int mapping_started = 0; + + while (!done) { + if (!yaml_parser_parse(parser, &event)) + goto error; + + switch (event.type) { + + case YAML_SEQUENCE_START_EVENT: + LOG_D(ENB_APP, "A sequence just started as expected\n"); + sequence_started = 1; + break; + case YAML_SEQUENCE_END_EVENT: + LOG_D(ENB_APP, "A sequence ended\n"); + sequence_started = 0; + break; + case YAML_MAPPING_START_EVENT: + if (!sequence_started) { + goto error; + } + LOG_D(ENB_APP, "A mapping started\n"); + mapping_started = 1; + break; + case YAML_MAPPING_END_EVENT: + if (!mapping_started) { + goto error; + } + LOG_D(ENB_APP, "A mapping ended\n"); + mapping_started = 0; + break; + case YAML_SCALAR_EVENT: + if (!mapping_started) { + goto error; + } + // Entered a subsystem section. Let's skip it + if (skip_subsystem_section(parser) == -1) { + goto error; + } + } + + done = (event.type == YAML_SEQUENCE_END_EVENT); + + yaml_event_delete(&event); + + } + + return 0; + + error: + yaml_event_delete(&event); + return -1; +} + +int skip_subsystem_section(yaml_parser_t *parser) { + + yaml_event_t event; + + int done = 0; + int mapping_started = 0; + + while (!done) { + if (!yaml_parser_parse(parser, &event)) + goto error; + + switch (event.type) { + case YAML_MAPPING_START_EVENT: + LOG_D(ENB_APP, "The mapping of the subsystem started\n"); + mapping_started = 1; + break; + case YAML_MAPPING_END_EVENT: + LOG_D(ENB_APP, "The mapping of the subsystem ended\n"); + mapping_started = 0; + break; + case YAML_SCALAR_EVENT: + if (!mapping_started) { + goto error; + } + // Check what key needs to be set + if (strcmp(event.data.scalar.value, "behavior") == 0) { + LOG_D(ENB_APP, "Skipping the behavior attribute\n"); + yaml_event_delete(&event); + if (!yaml_parser_parse(parser, &event)) { + goto error; + } + if (event.type == YAML_SCALAR_EVENT) { + break; + } else { + goto error; + } + } else if (strcmp(event.data.scalar.value, "parameters") == 0) { + LOG_D(ENB_APP, "Skipping the parameters for this subsystem\n"); + if (skip_subsystem_parameters_config(parser) == -1) { + goto error; + } + } + break; + default: + goto error; + } + + done = (event.type == YAML_MAPPING_END_EVENT); + yaml_event_delete(&event); + } + + return 0; + + error: + yaml_event_delete(&event); + return -1; +} + +int skip_subsystem_parameters_config(yaml_parser_t *parser) { + yaml_event_t event; + + void *param; + + int done = 0; + int mapping_started = 0; + + while (!done) { + + if (!yaml_parser_parse(parser, &event)) + goto error; + + switch (event.type) { + // We are expecting a mapping of parameters + case YAML_MAPPING_START_EVENT: + LOG_D(ENB_APP, "The mapping of the parameters started\n"); + mapping_started = 1; + break; + case YAML_MAPPING_END_EVENT: + LOG_D(ENB_APP, "The mapping of the parameters ended\n"); + mapping_started = 0; + break; + case YAML_SCALAR_EVENT: + if (!mapping_started) { + goto error; + } + // Check what key needs to be set + LOG_D(ENB_APP, "Skipping parameter %s\n", event.data.scalar.value); + if (skip_parameter_modification(parser) == -1 ) { + goto error; + } + break; + default: + goto error; + } + + done = (event.type == YAML_MAPPING_END_EVENT); + yaml_event_delete(&event); + } + + return 0; + + error: + yaml_event_delete(&event); + return -1; +} + + +int skip_parameter_modification(yaml_parser_t *parser) { + yaml_event_t event; + + int done = 0; + int is_array = 0; + int i = 0; + + while (!done) { + if (!yaml_parser_parse(parser, &event)) { + goto error; + } + + // Expecting either a scalar or a sequence + switch (event.type) { + case YAML_SEQUENCE_START_EVENT: + is_array = 1; + break; + case YAML_SCALAR_EVENT: + if ((strcmp(event.data.scalar.tag, YAML_INT_TAG) == 0) || + (strcmp(event.data.scalar.tag, YAML_FLOAT_TAG) == 0) || + (strcmp(event.data.scalar.tag, YAML_STR_TAG) == 0) || + (strcmp(event.data.scalar.tag, YAML_BOOL_TAG) == 0)) { + // Do nothing + } else { + // No other type is supported at the moment, so it should be considered an error + // if we reach here + goto error; + } + if (is_array) { + i++; + } else { + done = 1; + } + break; + case YAML_SEQUENCE_END_EVENT: + done = 1; + break; + default: + goto error; + } + yaml_event_delete(&event); + } + + return 0; + + error: + yaml_event_delete(&event); + return -1; +} + +int apply_parameter_modification(void *parameter, yaml_parser_t *parser) { + yaml_event_t event; + + int done = 0; + int is_array = 0; + int i = 0; + + char *endptr; + + while (!done) { + if (!yaml_parser_parse(parser, &event)) { + goto error; + } + + // Expecting either a scalar or a sequence + switch (event.type) { + case YAML_SEQUENCE_START_EVENT: + is_array = 1; + break; + case YAML_SCALAR_EVENT: + if (strcmp(event.data.scalar.tag, YAML_INT_TAG) == 0) { + ((int *) parameter)[i] = strtol(event.data.scalar.value, &endptr, 10); + } else if (strcmp(event.data.scalar.tag, YAML_FLOAT_TAG) == 0) { + ((float *) parameter)[i] = strtof(event.data.scalar.value, &endptr); + } else if (strcmp(event.data.scalar.tag, YAML_STR_TAG) == 0) { + strncpy(&((char *) parameter)[i], event.data.scalar.value, event.data.scalar.length); + } else if (strcmp(event.data.scalar.tag, YAML_BOOL_TAG) == 0) { + if (strcmp(event.data.scalar.value, "true") == 0) { + ((int *) parameter)[i] = 1; + } else { + ((int *) parameter)[i] = 0; + } + } else { + // No other type is supported at the moment, so it should be considered an error + // if we reach here + goto error; + } + if (is_array) { + i++; + } else { + done = 1; + } + break; + case YAML_SEQUENCE_END_EVENT: + done = 1; + break; + default: + goto error; + } + yaml_event_delete(&event); + } + + return 0; + + error: + yaml_event_delete(&event); + return -1; + +} diff --git a/openair2/ENB_APP/enb_agent_common_internal.h b/openair2/ENB_APP/enb_agent_common_internal.h new file mode 100644 index 0000000000..30fd51c5c8 --- /dev/null +++ b/openair2/ENB_APP/enb_agent_common_internal.h @@ -0,0 +1,64 @@ +/******************************************************************************* + 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 enb_agent_common_internal.h + * \brief internal agent functions for common message primitves and utilities + * \author Xenofon Foukas + * \date 2016 + * \version 0.1 + */ + +#ifndef ENB_AGENT_COMMON_INTERNAL_H_ +#define ENB_AGENT_COMMON_INTERNAL_H_ + +#include + +#include "enb_agent_defs.h" + +int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy_length); + +int apply_parameter_modification(void *parameter, yaml_parser_t *parser); + +// This can be used when parsing for a specific system that is not yet implmeneted +// in order to skip its configuration, without affecting the rest +int skip_system_section(yaml_parser_t *parser); + +// This can be used when parsing for a specific subsystem that is not yet implmeneted +// in order to skip its configuration, without affecting the rest +int skip_subsystem_section(yaml_parser_t *parser); + +// This can be used when parsing for the parameters of a specific subsystem +//that is not yet implmeneted in order to skip its configuration, without affecting the rest +int skip_subsystem_parameters_config(yaml_parser_t *parser); + +// This can be used when configuring the parameters of a specific subsystem +//that is not yet implmeneted in order to skip its configuration, without affecting the rest +int skip_parameter_modification(yaml_parser_t *parser); + +#endif diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index 721b3678f8..da53343818 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -58,7 +58,7 @@ enb_agent_message_decoded_callback agent_messages_callback[][3] = { {enb_agent_mac_handle_dl_mac_config, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG*/ {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG*/ {enb_agent_control_delegation, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_CONTROL_DELEGATION_MSG*/ - + {enb_agent_reconfiguration, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_AGENT_RECONFIGURATION_MSG*/ }; enb_agent_message_destruction_callback message_destruction_callback[] = { @@ -78,6 +78,7 @@ enb_agent_message_destruction_callback message_destruction_callback[] = { enb_agent_mac_destroy_dl_config, enb_agent_destroy_ue_state_change, enb_agent_destroy_control_delegation, + enb_agent_destroy_agent_reconfiguration, }; static const char *enb_agent_direction2String[] = { diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index fb9ae7322f..744768135e 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -1391,6 +1391,8 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_schedule_ue_spec = schedule_ue_spec_remote; xface->enb_agent_get_pending_dl_mac_config = enb_agent_get_pending_dl_mac_config; xface->enb_agent_notify_ue_state_change = enb_agent_ue_state_change; + + xface->dl_scheduler_loaded_lib = NULL; mac_agent_registered[mod_id] = 1; agent_mac_xface[mod_id] = xface; @@ -1408,6 +1410,8 @@ int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_get_pending_dl_mac_config = NULL; xface->enb_agent_notify_ue_state_change = NULL; + xface->dl_scheduler_loaded_lib = NULL; + mac_agent_registered[mod_id] = 0; agent_mac_xface[mod_id] = NULL; diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/enb_agent_mac_defs.h index c5a3204f0c..1511ee7262 100644 --- a/openair2/ENB_APP/enb_agent_mac_defs.h +++ b/openair2/ENB_APP/enb_agent_mac_defs.h @@ -74,6 +74,8 @@ typedef struct { void (*enb_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, uint32_t state_change); + + void *dl_scheduler_loaded_lib; /*TODO: Fill in with the rest of the MAC layer technology specific callbacks (UL/DL scheduling, RACH info etc)*/ } AGENT_MAC_xface; diff --git a/openair2/ENB_APP/enb_agent_mac_internal.c b/openair2/ENB_APP/enb_agent_mac_internal.c index c3cc584bcd..aa7482bd90 100644 --- a/openair2/ENB_APP/enb_agent_mac_internal.c +++ b/openair2/ENB_APP/enb_agent_mac_internal.c @@ -34,6 +34,9 @@ * \version 0.1 */ +#include +#include + #include "enb_agent_mac_internal.h" Protocol__ProgranMessage * enb_agent_generate_diff_mac_stats_report(Protocol__ProgranMessage *new_message, @@ -558,3 +561,235 @@ Protocol__PrpNoiseInterferenceReport * copy_noise_inter_report(Protocol__PrpNois error: return NULL; } + + +int parse_mac_config(mid_t mod_id, yaml_parser_t *parser) { + + yaml_event_t event; + + int done = 0; + + int sequence_started = 0; + int mapping_started = 0; + + while (!done) { + + if (!yaml_parser_parse(parser, &event)) + goto error; + + switch (event.type) { + case YAML_SEQUENCE_START_EVENT: + LOG_I(ENB_APP, "A sequence just started as expected\n"); + sequence_started = 1; + break; + case YAML_SEQUENCE_END_EVENT: + LOG_I(ENB_APP, "A sequence ended\n"); + sequence_started = 0; + break; + case YAML_MAPPING_START_EVENT: + if (!sequence_started) { + goto error; + } + LOG_I(ENB_APP, "A mapping started\n"); + mapping_started = 1; + break; + case YAML_MAPPING_END_EVENT: + if (!mapping_started) { + goto error; + } + LOG_I(ENB_APP, "A mapping ended\n"); + mapping_started = 0; + break; + case YAML_SCALAR_EVENT: + if (!mapping_started) { + goto error; + } + // Check the types of subsystems offered and handle their values accordingly + if (strcmp(event.data.scalar.value, "dl_scheduler") == 0) { + LOG_I(ENB_APP, "This is for the dl_scheduler subsystem\n"); + // Call the proper handler + if (parse_dl_scheduler_config(mod_id, parser) == -1) { + LOG_I(ENB_APP, "An error occured\n"); + goto error; + } + } else if (strcmp(event.data.scalar.value, "ul_scheduler") == 0) { + // Call the proper handler + LOG_I(ENB_APP, "This is for the ul_scheduler subsystem\n"); + goto error; + // TODO + } else if (strcmp(event.data.scalar.value, "ra_scheduler") == 0) { + // Call the proper handler + // TODO + } else if (strcmp(event.data.scalar.value, "page_scheduler") == 0) { + // Call the proper handler + // TODO + } else { + // Unknown subsystem + goto error; + } + break; + default: // We expect nothing else at this level of the hierarchy + goto error; + } + + done = (event.type == YAML_SEQUENCE_END_EVENT); + + yaml_event_delete(&event); + + } + + return 0; + + error: + yaml_event_delete(&event); + return -1; + +} + +int parse_dl_scheduler_config(mid_t mod_id, yaml_parser_t *parser) { + + yaml_event_t event; + + int done = 0; + int mapping_started = 0; + + while (!done) { + + if (!yaml_parser_parse(parser, &event)) + goto error; + + switch (event.type) { + // We are expecting a mapping (behavior and parameters) + case YAML_MAPPING_START_EVENT: + LOG_D(ENB_APP, "The mapping of the subsystem started\n"); + mapping_started = 1; + break; + case YAML_MAPPING_END_EVENT: + LOG_D(ENB_APP, "The mapping of the subsystem ended\n"); + mapping_started = 0; + break; + case YAML_SCALAR_EVENT: + if (!mapping_started) { + goto error; + } + // Check what key needs to be set + if (strcmp(event.data.scalar.value, "behavior") == 0) { + LOG_D(ENB_APP, "Time to set the behavior attribute\n"); + yaml_event_delete(&event); + if (!yaml_parser_parse(parser, &event)) { + goto error; + } + if (event.type == YAML_SCALAR_EVENT) { + if (load_dl_scheduler_function(mod_id, event.data.scalar.value) == -1) { + goto error; + } + } else { + goto error; + } + } else if (strcmp(event.data.scalar.value, "parameters") == 0) { + LOG_D(ENB_APP, "Now it is time to set the parameters for this subsystem\n"); + if (parse_dl_scheduler_parameters(mod_id, parser) == -1) { + goto error; + } + } + break; + default: + goto error; + } + + done = (event.type == YAML_MAPPING_END_EVENT); + yaml_event_delete(&event); + } + + return 0; + + error: + yaml_event_delete(&event); + return -1; +} + +int parse_dl_scheduler_parameters(mid_t mod_id, yaml_parser_t *parser) { + yaml_event_t event; + + void *param; + + int done = 0; + int mapping_started = 0; + + while (!done) { + + if (!yaml_parser_parse(parser, &event)) + goto error; + + switch (event.type) { + // We are expecting a mapping of parameters + case YAML_MAPPING_START_EVENT: + LOG_D(ENB_APP, "The mapping of the parameters started\n"); + mapping_started = 1; + break; + case YAML_MAPPING_END_EVENT: + LOG_D(ENB_APP, "The mapping of the parameters ended\n"); + mapping_started = 0; + break; + case YAML_SCALAR_EVENT: + if (!mapping_started) { + goto error; + } + // Check what key needs to be set + if (mac_agent_registered[mod_id]) { + LOG_D(ENB_APP, "Setting parameter %s\n", event.data.scalar.value); + param = dlsym(agent_mac_xface[mod_id]->dl_scheduler_loaded_lib, + event.data.scalar.value); + if (param == NULL) { + goto error; + } + apply_parameter_modification(param, parser); + } else { + goto error; + } + break; + default: + goto error; + } + + done = (event.type == YAML_MAPPING_END_EVENT); + yaml_event_delete(&event); + } + + return 0; + + error: + yaml_event_delete(&event); + return -1; +} + +int load_dl_scheduler_function(mid_t mod_id, const char *function_name) { + void *lib; + + char lib_name[120]; + char target[512]; + sprintf(lib_name, sizeof(lib_name), "/%s.so", function_name); + strcpy(target, local_cache); + strcat(target, lib_name); + + lib = dlopen(target, RTLD_NOW); + if (lib == NULL) { + goto error; + } + + void *loaded_scheduler = dlsym(lib, function_name); + if (loaded_scheduler) { + if (mac_agent_registered[mod_id]) { + agent_mac_xface[mod_id]->enb_agent_schedule_ue_spec = loaded_scheduler; + dlclose(agent_mac_xface[mod_id]->dl_scheduler_loaded_lib); + agent_mac_xface[mod_id]->dl_scheduler_loaded_lib = lib; + LOG_D(ENB_APP, "Delegated control for DL UE scheduler succesfully\n"); + } + } + + return 0; + + error: + return -1; + +} diff --git a/openair2/ENB_APP/enb_agent_mac_internal.h b/openair2/ENB_APP/enb_agent_mac_internal.h index 394d3e7730..4a76f0ed38 100644 --- a/openair2/ENB_APP/enb_agent_mac_internal.h +++ b/openair2/ENB_APP/enb_agent_mac_internal.h @@ -39,9 +39,11 @@ #include +#include + #include "enb_agent_mac.h" #include "enb_agent_common.h" - +#include "enb_agent_defs.h" /*This will be used for producing continuous status updates for the MAC *Needs to be thread-safe @@ -98,4 +100,15 @@ int compare_ue_stats_reports(Protocol__PrpUeStatsReport *rep1, int compare_cell_stats_reports(Protocol__PrpCellStatsReport *rep1, Protocol__PrpCellStatsReport *rep2); + +/* Functions for parsing the MAC agent policy reconfiguration command */ + +int parse_mac_config(mid_t mod_id, yaml_parser_t *parser); + +int parse_dl_scheduler_config(mid_t mod_id, yaml_parser_t *parser); + +int parse_dl_scheduler_parameters(mid_t mod_id, yaml_parser_t *parser); + +int load_dl_scheduler_function(mid_t mod_id, const char *function_name); + #endif /*ENB_AGENT_MAC_INTERNAL_H_*/ diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c index ad8b130584..d8d2373332 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c @@ -37,6 +37,8 @@ */ +#include "enb_agent_common_internal.h" + #include "eNB_agent_scheduler_dlsch_ue_remote.h" #include "LAYER2/MAC/defs.h" @@ -46,9 +48,25 @@ struct DlMacConfigHead queue_head; int queue_initialized = 0; +//uint32_t skip_subframe = 1; +//uint32_t period = 10; +//uint32_t sched [] = {1, 2, 3}; + void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, Protocol__ProgranMessage **dl_info) { + + //if ((subframe == skip_subframe) && (frame % period == 0)) { + // LOG_I(MAC, "Will skip subframe %d %d\n", subframe, frame); + // for (int i = 0; i < 3; i++) { + // LOG_I(MAC, "%d\n", sched[i]); + // } + //} + + /* if (frame == 500 && subframe == 1) { */ + /* char policy[] = "rrc: \n - ul_scheduler: \n behavior : tester_function\n parameters:\n period: !!int 3\nmac: \n - dl_scheduler: \n parameters: \n period : !!int 40\n skip_subframe : !!int 3\n sched : [!!int 4, !!int 5, !!int 6]"; */ + /* apply_reconfiguration_policy(mod_id, policy, strlen(policy)); */ + /* } */ eNB_MAC_INST *eNB; From 345a9382f282cda9dd68a4e2d2a865f4e60ad15f Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 14 Apr 2016 14:50:22 +0100 Subject: [PATCH 170/413] Fixed bug of local agent scheduler that did not allow the retransmission in HARQ processes --- openair2/LAYER2/MAC/defs.h | 6 ++++ .../MAC/eNB_agent_scheduler_dataplane.c | 2 -- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 33 ++++++++++--------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 7c0561121d..60c095fa14 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -609,6 +609,12 @@ typedef struct { /// Flag to indicate UE has been configured (ACK from RRCConnectionSetup received) boolean_t configured; + /// MCS from last scheduling + uint8_t mcs[8]; + + /// TPC from last scheduling + uint8_t oldTPC[8]; + // PHY interface info /// DCI format for DLSCH diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c index 4642f9be00..b2a66bfe2d 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c @@ -324,8 +324,6 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, nb_rb += get_min_rb_unit(mod_id, CC_id); stats_tbs = mac_xface->get_TBS_DL(dl_dci->mcs[0], nb_rb); } - - UE_list->UE_template[CC_id][UE_id].nb_rb[dl_dci->harq_process] = nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index 5031867394..79716af854 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -137,7 +137,7 @@ schedule_ue_spec_default( VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_IN); //weight = get_ue_weight(module_idP,UE_id); - aggregation = 1; // set to the maximum aggregation level + aggregation = 2; // set to the maximum aggregation level for (CC_id=0; CC_idN_RBG; j++) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0; + rballoc_sub[j] = 0; } 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", @@ -269,13 +270,6 @@ schedule_ue_spec_default( if (round > 0) { - mcs = UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1; - - // get freq_allocation - nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - - dci_tbs = mac_xface->get_TBS_DL(mcs, nb_rb); - if (frame_parms[CC_id]->frame_type == TDD) { UE_list->UE_template[CC_id][UE_id].DAI++; update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); @@ -283,6 +277,13 @@ schedule_ue_spec_default( CC_id, subframe,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); } + mcs = UE_list->UE_template[CC_id][UE_id].mcs[harq_pid]; + + // get freq_allocation + nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + + dci_tbs = mac_xface->get_TBS_DL(mcs, nb_rb); + if (nb_rb <= nb_available_rb) { if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { @@ -296,6 +297,7 @@ schedule_ue_spec_default( while((nb_rb_temp > 0) && (j < frame_parms[CC_id]->N_RBG)) { if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; + if((j == frame_parms[CC_id]->N_RBG-1) && ((frame_parms[CC_id]->N_RB_DL == 25)|| (frame_parms[CC_id]->N_RB_DL == 50))) { @@ -316,21 +318,20 @@ schedule_ue_spec_default( for(j=0; jN_RBG; j++) { PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; + rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; } - for(i=0; ilte_frame_parms.N_RBG; i++) { - rballoc_sub[i] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][i]; - } - // Keep the old NDI, do not toggle ndi = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; - tpc = 1; - + tpc = UE_list->UE_template[CC_id][UE_id].oldTPC[harq_pid]; + UE_list->UE_template[CC_id][UE_id].mcs[harq_pid] = mcs; + ue_has_transmission = 1; num_ues_added++; } else { LOG_D(MAC,"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", mod_id, frame, CC_id, UE_id); + ue_has_transmission = 0; } //End of retransmission } else { /* This is a potentially new SDU opportunity */ @@ -516,7 +517,6 @@ schedule_ue_spec_default( UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; - if (frame_parms[CC_id]->frame_type == TDD) { UE_list->UE_template[CC_id][UE_id].DAI++; // printf("DAI update: subframeP %d: UE %d, DAI %d\n",subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); @@ -572,6 +572,9 @@ schedule_ue_spec_default( UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]= 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; ndi = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + UE_list->UE_template[CC_id][UE_id].mcs[harq_pid] = mcs; + UE_list->UE_template[CC_id][UE_id].oldTPC[harq_pid] = tpc; + // Increase the pointer for the number of scheduled UEs num_ues_added++; ue_has_transmission = 1; From d4fd08785de065bada51f123b379bb2ccd7ba1a7 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 14 Apr 2016 14:51:00 +0100 Subject: [PATCH 171/413] Modified eNB conf file for USRP to use 50 rbs --- .../CONF/enb.band5.agent.usrpb210.epc.remote.conf | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf index 8936b2eb24..59aec03872 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf @@ -30,7 +30,7 @@ eNBs = downlink_frequency = 879000000L; uplink_frequency_offset = -45000000; Nid_cell = 0; - N_RB_DL = 25; + N_RB_DL = 50; Nid_cell_mbsfn = 0; nb_antennas_tx = 1; nb_antennas_rx = 1; @@ -131,24 +131,24 @@ eNBs = }; ////////// MME parameters: - mme_ip_address = ( {ipv4 = "192.168.100.103"; + mme_ip_address = ( {ipv4 = "192.168.100.102"; ipv6="192:168:30::17"; active="yes"; preference="ipv4";}); NETWORK_INTERFACES : { - ENB_INTERFACE_NAME_FOR_S1_MME = "eth0:1"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.102/24"; + ENB_INTERFACE_NAME_FOR_S1_MME = "eth2:1"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.103/24"; - ENB_INTERFACE_NAME_FOR_S1U = "eth0:1"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.102/24"; + ENB_INTERFACE_NAME_FOR_S1U = "eth2:1"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.103/24"; ENB_PORT_FOR_S1U = 2152; # Spec 2152 }; NETWORK_CONTROLLER : { - ENB_AGENT_INTERFACE_NAME = "eth1"; + ENB_AGENT_INTERFACE_NAME = "eth0"; ENB_AGENT_IPV4_ADDRESS = "10.0.0.5/30"; ENB_AGENT_PORT = 2210; ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; From 673ef5fa7a8748bc2553834f2b1ed3c1bc41c3b2 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Thu, 14 Apr 2016 15:13:15 +0100 Subject: [PATCH 172/413] Modified active harq reporting mechanism to support long schedule ahead of time values --- openair1/SCHED/defs.h | 5 + openair1/SCHED/phy_procedures_lte_eNb.c | 109 +++++++++++++++------- openair2/ENB_APP/enb_agent_common.c | 3 +- openair2/LAYER2/MAC/eNB_scheduler_RA.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 2 +- openair2/LAYER2/MAC/pre_processor.c | 4 +- 6 files changed, 84 insertions(+), 41 deletions(-) diff --git a/openair1/SCHED/defs.h b/openair1/SCHED/defs.h index 8692a31f12..72830f35cb 100644 --- a/openair1/SCHED/defs.h +++ b/openair1/SCHED/defs.h @@ -81,6 +81,11 @@ enum openair_SYNCH_STATUS { openair_SCHED_EXIT }; +enum openair_HARQ_TYPE { + openair_harq_DL = 0, + openair_harq_UL, + openair_harq_RA +}; #define DAQ_AGC_ON 1 #define DAQ_AGC_OFF 0 diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 15cd98881d..ba180e781f 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -29,11 +29,11 @@ /*! \file phy_procedures_lte_eNB.c * \brief Implementation of eNB procedures from 36.213 LTE specifications - * \author R. Knopp, F. Kaltenberger, N. Nikaein + * \author R. Knopp, F. Kaltenberger, N. Nikaein, X. Foukas * \date 2011 * \version 0.1 * \company Eurecom - * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,navid.nikaein@eurecom.fr + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,navid.nikaein@eurecom.fr, x.foukas@sms.ed.ac.uk * \note * \warning */ @@ -141,26 +141,23 @@ uint8_t is_SR_subframe(PHY_VARS_eNB *phy_vars_eNB,uint8_t UE_id,uint8_t sched_su void put_harq_pid_in_freelist(LTE_eNB_DLSCH_t *DLSCH_ptr, int harq_pid) { - DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->tail_freelist] = harq_pid; - DLSCH_ptr->tail_freelist = (DLSCH_ptr->tail_freelist + 1) % 10; + if (harq_pid >=0 && harq_pid < 8) { + DLSCH_ptr->harq_pid_freelist[harq_pid] = 1; + } else { + LOG_E(PHY, "%s:%d: critical error, get in touch with the authors\n", __FILE__, __LINE__); + abort(); + } } void remove_harq_pid_from_freelist(LTE_eNB_DLSCH_t *DLSCH_ptr, int harq_pid) { - if (DLSCH_ptr->head_freelist == DLSCH_ptr->tail_freelist) { - LOG_E(PHY, "%s:%d: you cannot read this!\n", __FILE__, __LINE__); - abort(); - } - /* basic check, in case several threads deal with the free list at the same time - * in normal situations it should not happen, that's also why we don't use any - * locking mechanism to protect the free list - * to be refined in case things don't work properly - */ - if (harq_pid != DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]) { + + if (harq_pid >=0 && harq_pid < 8) { + DLSCH_ptr->harq_pid_freelist[harq_pid] = 0; + } else { LOG_E(PHY, "%s:%d: critical error, get in touch with the authors\n", __FILE__, __LINE__); abort(); } - DLSCH_ptr->head_freelist = (DLSCH_ptr->head_freelist + 1) % 10; } int32_t add_ue(int16_t rnti, PHY_VARS_eNB *phy_vars_eNB) @@ -257,12 +254,17 @@ int8_t find_next_ue_index(PHY_VARS_eNB *phy_vars_eNB) return(-1); } -int get_ue_active_harq_pid(const uint8_t Mod_id,const uint8_t CC_id,const uint16_t rnti, const int frame, const uint8_t subframe,uint8_t *harq_pid,uint8_t *round,const uint8_t ul_flag) +int prev_frame = -1; +int prev_subframe = -1; +int prev_harq_pid = 0; +int prev_harq_round = 0; + +int get_ue_active_harq_pid(const uint8_t Mod_id,const uint8_t CC_id,const uint16_t rnti, const int frame, const uint8_t subframe,uint8_t *harq_pid,uint8_t *round,const uint8_t harq_flag) { LTE_eNB_DLSCH_t *DLSCH_ptr; LTE_eNB_ULSCH_t *ULSCH_ptr; uint8_t ulsch_subframe,ulsch_frame; - uint8_t i; + uint8_t i, j; int8_t UE_id = find_ue(rnti,PHY_vars_eNB_g[Mod_id][CC_id]); int sf1=(10*frame)+subframe,sf2,sfdiff,sfdiff_max=7; @@ -272,39 +274,74 @@ int get_ue_active_harq_pid(const uint8_t Mod_id,const uint8_t CC_id,const uint16 return(-1); } - if (ul_flag == 0) {// this is a DL request + if ((harq_flag == openair_harq_DL) || (harq_flag == openair_harq_RA)) {// this is a DL request + DLSCH_ptr = PHY_vars_eNB_g[Mod_id][CC_id]->dlsch_eNB[(uint32_t)UE_id][0]; + if (harq_flag == openair_harq_RA) { + if (DLSCH_ptr->harq_processes[0] != NULL) { + *harq_pid = 0; + *round = DLSCH_ptr->harq_processes[0]->round; + return 0; + } else { + return -1; + } + } + + if (prev_frame == frame && prev_subframe == subframe) { + *harq_pid = prev_harq_pid; + *round = prev_harq_round; + return (0); + } + // set to no available process first *harq_pid = -1; - for (i=0; iMdlharq; i++) { - if (DLSCH_ptr->harq_processes[i]!=NULL) { - if (DLSCH_ptr->harq_processes[i]->status == ACTIVE) { - sf2 = (DLSCH_ptr->harq_processes[i]->frame*10) + DLSCH_ptr->harq_processes[i]->subframe; - if (sf2<=sf1) - sfdiff = sf1-sf2; - else // this happens when wrapping around 1024 frame barrier - sfdiff = 10240 + sf1-sf2; - LOG_D(PHY,"process %d is active, round %d (waiting %d)\n",i,DLSCH_ptr->harq_processes[i]->round,sfdiff); + j = prev_harq_pid; - if (sfdiff>sfdiff_max) { // this is an active process that is waiting longer than the others (and longer than 7 ms) - sfdiff_max = sfdiff; - *harq_pid = i; - *round = DLSCH_ptr->harq_processes[i]->round; + for (i = 0; i < 8; i++) { + j = (j + 1) % 8; + if (DLSCH_ptr->harq_processes[j] != NULL) { + if (DLSCH_ptr->harq_processes[j]->status == ACTIVE) { + sf2 = (DLSCH_ptr->harq_processes[j]->frame*10) + DLSCH_ptr->harq_processes[j]->subframe; + if (sf2<=sf1) { + sfdiff = sf1-sf2; + } else { // this happens when wrapping around 1024 frame barrier + sfdiff = 10240 + sf1-sf2; + } + LOG_D(PHY,"process %d is active, round %d (waiting %d)\n",i,DLSCH_ptr->harq_processes[j]->round,sfdiff); + if (sfdiff > sfdiff_max) { + prev_harq_pid = j; + prev_harq_round = DLSCH_ptr->harq_processes[j]->round; + prev_frame = frame; + prev_subframe = subframe; + *harq_pid = j; + *round = DLSCH_ptr->harq_processes[j]->round; + LOG_D(PHY,"process %d, %d is the allocated process\n", *harq_pid, *round); + return 0; + } + } else { // Send from the freelist + if (DLSCH_ptr->harq_pid_freelist[j] == 1) { + *harq_pid = j; + *round = 0; + prev_harq_pid = *harq_pid; + prev_harq_round = *round; + prev_frame = frame; + prev_subframe = subframe; + LOG_D(PHY,"process %d is first free process\n", *harq_pid); + return 0; } } - } else { // a process is not defined + } else { LOG_E(PHY,"[eNB %d] DLSCH process %d for rnti %x (UE_id %d) not allocated\n",Mod_id,i,rnti,UE_id); return(-1); } } - /* if no active harq pid, get the oldest in the freelist, if any */ - if (*harq_pid == 255 && DLSCH_ptr->head_freelist != DLSCH_ptr->tail_freelist) { - *harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; + if (*harq_pid == 255) { *round = 0; - LOG_D(PHY,"process %d is first free process\n", *harq_pid); + LOG_I(PHY, "TEST, no process found\n"); + return -1; } LOG_D(PHY,"get_ue_active_harq_pid DL => Frame %d, Subframe %d : harq_pid %d\n", diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index e21c180cec..e3c2bcfcb5 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -43,6 +43,7 @@ #include "PHY/extern.h" #include "log.h" +#include "SCHED/defs.h" #include "RRC/LITE/extern.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" #include "rrc_eNB_UE_context.h" @@ -671,7 +672,7 @@ int get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, const i uint16_t rnti = get_ue_crnti(mod_id,ue_id); - mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&round,0); + mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&round,openair_harq_DL); *id = harq_pid; if (round > 0) { diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c index 8cb6b91301..a4b7339677 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c @@ -661,7 +661,7 @@ void schedule_RA(module_id_t module_idP,frame_t frameP, sub_frame_t subframeP,un LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Checking if Msg4 was acknowledged: \n", module_idP,CC_id,frameP,subframeP); // Get candidate harq_pid from PHY - mac_xface->get_ue_active_harq_pid(module_idP,CC_id,RA_template->rnti,frameP,subframeP,&harq_pid,&round,0); + mac_xface->get_ue_active_harq_pid(module_idP,CC_id,RA_template->rnti,frameP,subframeP,&harq_pid,&round,openair_harq_RA); if (round>0) { //RA_template->wait_ack_Msg4++; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index e6033d5057..17a8cec5db 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -753,7 +753,7 @@ void schedule_ulsch_rnti(module_id_t module_idP, DCI_pdu = &eNB->common_channels[CC_id].DCI_pdu; UE_template = &UE_list->UE_template[CC_id][UE_id]; - if (mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,1) == -1 ) { + if (mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL) == -1 ) { LOG_W(MAC,"[eNB %d] Scheduler Frame %d, subframeP %d: candidate harq_pid from PHY for UE %d CC %d RNTI %x\n", module_idP,frameP,subframeP, UE_id, CC_id, rnti); // NN --> RK: Don't schedule UE if we cannot get harq pid diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index c744d1d90a..64ae2d9453 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -760,7 +760,7 @@ void dlsch_scheduler_pre_processor_reset (int module_idP, frameP,subframeP, &ue_sched_ctl->harq_pid[CC_id], &ue_sched_ctl->round[CC_id], - 0); + openair_harq_DL); if (ue_sched_ctl->ta_timer == 0) { // WE SHOULD PROTECT the eNB_UE_stats with a mutex here ... @@ -1020,7 +1020,7 @@ void ulsch_scheduler_pre_processor(module_id_t module_idP, // This is the actual CC_id in the list CC_id = UE_list->ordered_ULCCids[n][UE_id]; - mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,1); + mac_xface->get_ue_active_harq_pid(module_idP,CC_id,rnti,frameP,subframeP,&harq_pid,&round,openair_harq_UL); if(round>0) { nb_allocated_rbs[CC_id][UE_id] = UE_list->UE_template[CC_id][UE_id].nb_rb_ul[harq_pid]; From bad4b7940a3ee92c281c9e87951ab17c3e4da1c1 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 15 Apr 2016 12:17:36 +0100 Subject: [PATCH 173/413] Fixed bug when delegating control when delegated lib was previously NULL --- openair2/ENB_APP/enb_agent_mac_internal.c | 24 ++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_mac_internal.c b/openair2/ENB_APP/enb_agent_mac_internal.c index aa7482bd90..4d5ba34610 100644 --- a/openair2/ENB_APP/enb_agent_mac_internal.c +++ b/openair2/ENB_APP/enb_agent_mac_internal.c @@ -579,25 +579,25 @@ int parse_mac_config(mid_t mod_id, yaml_parser_t *parser) { switch (event.type) { case YAML_SEQUENCE_START_EVENT: - LOG_I(ENB_APP, "A sequence just started as expected\n"); + LOG_D(ENB_APP, "A sequence just started as expected\n"); sequence_started = 1; break; case YAML_SEQUENCE_END_EVENT: - LOG_I(ENB_APP, "A sequence ended\n"); + LOG_D(ENB_APP, "A sequence ended\n"); sequence_started = 0; break; case YAML_MAPPING_START_EVENT: if (!sequence_started) { goto error; } - LOG_I(ENB_APP, "A mapping started\n"); + LOG_D(ENB_APP, "A mapping started\n"); mapping_started = 1; break; case YAML_MAPPING_END_EVENT: if (!mapping_started) { goto error; } - LOG_I(ENB_APP, "A mapping ended\n"); + LOG_D(ENB_APP, "A mapping ended\n"); mapping_started = 0; break; case YAML_SCALAR_EVENT: @@ -606,15 +606,15 @@ int parse_mac_config(mid_t mod_id, yaml_parser_t *parser) { } // Check the types of subsystems offered and handle their values accordingly if (strcmp(event.data.scalar.value, "dl_scheduler") == 0) { - LOG_I(ENB_APP, "This is for the dl_scheduler subsystem\n"); + LOG_D(ENB_APP, "This is for the dl_scheduler subsystem\n"); // Call the proper handler if (parse_dl_scheduler_config(mod_id, parser) == -1) { - LOG_I(ENB_APP, "An error occured\n"); + LOG_D(ENB_APP, "An error occured\n"); goto error; } } else if (strcmp(event.data.scalar.value, "ul_scheduler") == 0) { // Call the proper handler - LOG_I(ENB_APP, "This is for the ul_scheduler subsystem\n"); + LOG_D(ENB_APP, "This is for the ul_scheduler subsystem\n"); goto error; // TODO } else if (strcmp(event.data.scalar.value, "ra_scheduler") == 0) { @@ -674,7 +674,7 @@ int parse_dl_scheduler_config(mid_t mod_id, yaml_parser_t *parser) { } // Check what key needs to be set if (strcmp(event.data.scalar.value, "behavior") == 0) { - LOG_D(ENB_APP, "Time to set the behavior attribute\n"); + LOG_I(ENB_APP, "Time to set the behavior attribute\n"); yaml_event_delete(&event); if (!yaml_parser_parse(parser, &event)) { goto error; @@ -682,7 +682,7 @@ int parse_dl_scheduler_config(mid_t mod_id, yaml_parser_t *parser) { if (event.type == YAML_SCALAR_EVENT) { if (load_dl_scheduler_function(mod_id, event.data.scalar.value) == -1) { goto error; - } + } } else { goto error; } @@ -768,7 +768,7 @@ int load_dl_scheduler_function(mid_t mod_id, const char *function_name) { char lib_name[120]; char target[512]; - sprintf(lib_name, sizeof(lib_name), "/%s.so", function_name); + snprintf(lib_name, sizeof(lib_name), "/%s.so", function_name); strcpy(target, local_cache); strcat(target, lib_name); @@ -781,7 +781,9 @@ int load_dl_scheduler_function(mid_t mod_id, const char *function_name) { if (loaded_scheduler) { if (mac_agent_registered[mod_id]) { agent_mac_xface[mod_id]->enb_agent_schedule_ue_spec = loaded_scheduler; - dlclose(agent_mac_xface[mod_id]->dl_scheduler_loaded_lib); + if (agent_mac_xface[mod_id]->dl_scheduler_loaded_lib != NULL) { + dlclose(agent_mac_xface[mod_id]->dl_scheduler_loaded_lib); + } agent_mac_xface[mod_id]->dl_scheduler_loaded_lib = lib; LOG_D(ENB_APP, "Delegated control for DL UE scheduler succesfully\n"); } From bcea7d591761b476ec7ceff829486bf0cfbc2c00 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 18 Apr 2016 13:05:36 +0100 Subject: [PATCH 174/413] Fixed local scheduler bug when scheduling multiple UEs --- openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index 79716af854..655c60cc70 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -213,6 +213,8 @@ schedule_ue_spec_default( set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe,frame_parms); } + channels_added = 0; + // After this point all the UEs will be scheduled dl_data[num_ues_added] = (Protocol__PrpDlData *) malloc(sizeof(Protocol__PrpDlData)); protocol__prp_dl_data__init(dl_data[num_ues_added]); From 59ba6f9e7bc7725c502e6808a021d89742ec9704 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 20 Apr 2016 13:41:49 +0100 Subject: [PATCH 175/413] Made config changes for remote scheduler and eNB --- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h | 2 +- .../CONF/enb.band5.agent.usrpb210.epc.remote.conf | 2 +- .../CONF/enb.band7.agent.usrpb210.epc.remote.conf | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h index c636ec0d95..7d2c2cbc6f 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h @@ -51,7 +51,7 @@ // Maximum value of schedule ahead of time // Required to identify if a dl_command is for the future or not -#define SCHED_AHEAD_SUBFRAMES 10 +#define SCHED_AHEAD_SUBFRAMES 20 typedef struct dl_mac_config_element_s { Protocol__ProgranMessage *dl_info; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf index 59aec03872..e8bb16f2c8 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf @@ -30,7 +30,7 @@ eNBs = downlink_frequency = 879000000L; uplink_frequency_offset = -45000000; Nid_cell = 0; - N_RB_DL = 50; + N_RB_DL = 25; Nid_cell_mbsfn = 0; nb_antennas_tx = 1; nb_antennas_rx = 1; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.usrpb210.epc.remote.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.usrpb210.epc.remote.conf index 4f6a3ba101..6e4764be2d 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.usrpb210.epc.remote.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.usrpb210.epc.remote.conf @@ -129,24 +129,24 @@ eNBs = }; ////////// MME parameters: - mme_ip_address = ( {ipv4 = "192.168.100.103"; + mme_ip_address = ( {ipv4 = "192.168.100.102"; ipv6="192:168:30::17"; active="yes"; preference="ipv4";}); NETWORK_INTERFACES : { - ENB_INTERFACE_NAME_FOR_S1_MME = "eth0:1"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.102/24"; + ENB_INTERFACE_NAME_FOR_S1_MME = "eth2:1"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.103/24"; - ENB_INTERFACE_NAME_FOR_S1U = "eth0:1"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.102/24"; + ENB_INTERFACE_NAME_FOR_S1U = "eth2:1"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.103/24"; ENB_PORT_FOR_S1U = 2152; # Spec 2152 }; NETWORK_CONTROLLER : { - ENB_AGENT_INTERFACE_NAME = "eth1"; + ENB_AGENT_INTERFACE_NAME = "eth0"; ENB_AGENT_IPV4_ADDRESS = "10.0.0.5/30"; ENB_AGENT_PORT = 2210; ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; From 104ed9ade1634286bb981810dd38599b72b14d64 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 25 Apr 2016 17:09:53 +0100 Subject: [PATCH 176/413] Added fixes for multiple eNBs and simulation mode --- openair2/ENB_APP/enb_agent_common.c | 17 ++++----- openair2/RRC/LITE/rrc_eNB.c | 15 +++++--- openair2/UTIL/OTG/otg_tx.c | 5 ++- targets/SIMU/USER/oaisim.c | 5 +-- targets/SIMU/USER/oaisim_functions.c | 55 ++++++++++++++-------------- 5 files changed, 50 insertions(+), 47 deletions(-) diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index e3c2bcfcb5..1e477c6c3c 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -1418,6 +1418,9 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) config->has_extended_bsr_size = 1; config->extended_bsr_size = get_extended_bsr_size(mod_id,i); } + //TODO: Set index of primary cell + 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; @@ -1425,9 +1428,6 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) //TODO: Set cross carrier scheduling support (boolean) config->has_cross_carrier_sched_support = 1; config->cross_carrier_sched_support = 0; - //TODO: Set index of primary cell - config->has_pcell_carrier_index = 1; - config->pcell_carrier_index = 1; //TODO: Set secondary cells configuration // We do not set it for now. No carrier aggregation support @@ -1754,16 +1754,15 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra //TODO: Set carrier aggregation support (boolean) ue_config[i]->has_ca_support = 0; ue_config[i]->ca_support = 0; + //TODO: Set index of primary cell + ue_config[i]->has_pcell_carrier_index = 1; + ue_config[i]->pcell_carrier_index = UE_PCCID(mod_id, i); if(ue_config[i]->has_ca_support){ //TODO: Set cross carrier scheduling support (boolean) ue_config[i]->has_cross_carrier_sched_support = 1; ue_config[i]->cross_carrier_sched_support = 0; - //TODO: Set index of primary cell - ue_config[i]->has_pcell_carrier_index = 1; - ue_config[i]->pcell_carrier_index = 1; //TODO: Set secondary cells configuration // We do not set it for now. No carrier aggregation support - //TODO: Set deactivation timer for secondary cell ue_config[i]->has_scell_deactivation_timer = 1; ue_config[i]->scell_deactivation_timer = 1; @@ -1874,9 +1873,9 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Progr protocol__prp_cell_config__init(cell_conf[i]); //TODO: Fill in with actual value, the PCI of this cell cell_conf[i]->phy_cell_id = 1; - cell_conf[i]->has_phy_cell_id = 1; + cell_conf[i]->has_phy_cell_id = get_cell_id(enb_id,i); //TODO: Fill in with actual value, the PLMN cell id of this cell - cell_conf[i]->cell_id = get_cell_id(enb_id,i); + cell_conf[i]->cell_id = i; cell_conf[i]->has_cell_id = 1; //TODO: Fill in with actual value, PUSCH resources in RBs for hopping cell_conf[i]->pusch_hopping_offset = get_hopping_offset(enb_id,i); diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index ed8d4cd850..4c0bb3f5c8 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -644,6 +644,9 @@ void rrc_eNB_emulation_notify_ue_module_id( // find enb_module_id for (enb_module_id = 0; enb_module_id < NUMBER_OF_eNB_MAX; enb_module_id++) { + if(enb_module_id>1){ /*FIX LATER*/ + return; + } for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { if (eNB_rrc_inst[enb_module_id].carrier[CC_id].sib1 != NULL) { if ( @@ -652,7 +655,6 @@ void rrc_eNB_emulation_notify_ue_module_id( (eNB_rrc_inst[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[2] == cell_identity_byte2P) && (eNB_rrc_inst[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[3] == cell_identity_byte3P) ) { - oai_emulation.info.eNB_ue_module_id_to_rnti[enb_module_id][ue_module_idP] = rntiP; ue_context_p = rrc_eNB_get_ue_context( &eNB_rrc_inst[enb_module_id], rntiP @@ -662,10 +664,11 @@ void rrc_eNB_emulation_notify_ue_module_id( oai_emulation.info.eNB_ue_local_uid_to_ue_module_id[enb_module_id][ue_context_p->local_uid] = ue_module_idP; } - return; + //return; } } } + oai_emulation.info.eNB_ue_module_id_to_rnti[enb_module_id][ue_module_idP] = rntiP; } AssertFatal(enb_module_id == NUMBER_OF_eNB_MAX, @@ -4026,8 +4029,8 @@ rrc_eNB_decode_dcch( PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_RECONFIGURED \n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future - if (mac_agent_registered[ctxt_pP->eNB_index]) { - agent_mac_xface[ctxt_pP->eNB_index]->enb_agent_notify_ue_state_change(ctxt_pP->eNB_index, + if (mac_agent_registered[ctxt_pP->module_id]) { + agent_mac_xface[ctxt_pP->eNB_index]->enb_agent_notify_ue_state_change(ctxt_pP->module_id, ue_context_p->ue_id_rnti, PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_UPDATED); } @@ -4116,8 +4119,8 @@ rrc_eNB_decode_dcch( LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_CONNECTED \n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); //WARNING:Inform the controller about the UE activation. Should be moved to RRC agent in the future - if (mac_agent_registered[ctxt_pP->eNB_index]) { - agent_mac_xface[ctxt_pP->eNB_index]->enb_agent_notify_ue_state_change(ctxt_pP->eNB_index, + if (mac_agent_registered[ctxt_pP->module_id]) { + agent_mac_xface[ctxt_pP->eNB_index]->enb_agent_notify_ue_state_change(ctxt_pP->module_id, ue_context_p->ue_id_rnti, PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_ACTIVATED); } diff --git a/openair2/UTIL/OTG/otg_tx.c b/openair2/UTIL/OTG/otg_tx.c index e70bccbc73..ea5fad63dc 100644 --- a/openair2/UTIL/OTG/otg_tx.c +++ b/openair2/UTIL/OTG/otg_tx.c @@ -270,13 +270,14 @@ unsigned char *packet_gen( char *header=NULL; int header_size = 0; - + //LOG_I(OTG,"Src: %d - Dest: %d - before exit\n",src_instance,dst_instance); // check if the app is configured if (app >= g_otg->application_idx[src_instance][dst_instance]) { + //LOG_I(OTG,"Src: %d - Dest: %d - no packet to generate - no application\n",src_instance,dst_instance); return NULL; } - LOG_T(OTG,"[src %d] [dst %d ][APP %d] current time %d\n",src_instance, dst_instance, app, ctime); + //LOG_I(OTG,"[src %d] [dst %d ][APP %d] current time %d\n",src_instance, dst_instance, app, ctime); *pkt_size=0; init_packet_gen(src_instance, dst_instance,ctime); diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index 995516b6e8..c574527f62 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -498,7 +498,6 @@ l2l1_task (void *args_p) xargv[0] = xname; fl_initialize (&xargc, xargv, NULL, 0, 0); eNB_inst = 0; - for (UE_inst = 0; UE_inst < NB_UE_INST; UE_inst++) { for (CC_id=0;CC_id>1, 0); pdcp_run (&ctxt); #endif @@ -857,7 +856,7 @@ l2l1_task (void *args_p) CC_id++) { phy_procedures_UE_lte ( PHY_vars_UE_g[UE_inst][CC_id], - 0, abstraction_flag, + 0, abstraction_flag, normal_txrx, no_relay, NULL); } diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index 72153c3ee7..9a072ea2c4 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -1326,13 +1326,11 @@ void update_otg_eNB(module_id_t enb_module_idP, unsigned int ctime) // generate traffic if the ue is rrc reconfigured state //if ((rrc_state=mac_eNB_get_rrc_status(enb_module_idP, dst_id)) > 2 /*RRC_CONNECTED*/ ) { if (mac_eNB_get_rrc_status(enb_module_idP, oai_emulation.info.eNB_ue_module_id_to_rnti[enb_module_idP][dst_id]) > 2 ){ - if_times += 1; for (app_id=0; app_idotg_pkt).sdu_buffer = (uint8_t*) packet_gen(enb_module_idP, dst_id + NB_eNB_INST, app_id, ctime, &((otg_pkt->otg_pkt).sdu_buffer_size)); if ((otg_pkt->otg_pkt).sdu_buffer != NULL) { @@ -1459,6 +1457,7 @@ void update_otg_UE(module_id_t ue_mod_idP, unsigned int ctime) { #if defined(USER_MODE) && defined(OAI_EMU) + int app_id; if (oai_emulation.info.otg_enabled ==1 ) { module_id_t dst_id, src_id; //dst_id = eNB_index module_id_t module_id = ue_mod_idP+NB_eNB_INST; @@ -1468,31 +1467,33 @@ void update_otg_UE(module_id_t ue_mod_idP, unsigned int ctime) for (dst_id=0; dst_id 2 /*RRC_CONNECTED*/) { - Packet_otg_elt_t *otg_pkt = malloc (sizeof(Packet_otg_elt_t)); - - if (otg_pkt!=NULL) - memset(otg_pkt,0,sizeof(Packet_otg_elt_t)); - else { - LOG_E(OTG,"not enough memory\n"); - exit(-1); - }// Manage to add this packet to the tail of your list - - (otg_pkt->otg_pkt).sdu_buffer = (uint8_t*) packet_gen(src_id, dst_id, 0, ctime, &((otg_pkt->otg_pkt).sdu_buffer_size)); - - if ((otg_pkt->otg_pkt).sdu_buffer != NULL) { - (otg_pkt->otg_pkt).rb_id = DTCH-2; - (otg_pkt->otg_pkt).module_id = module_id; - (otg_pkt->otg_pkt).dst_id = dst_id; - (otg_pkt->otg_pkt).is_ue = 1; - //Adding the packet to the OTG-PDCP buffer - (otg_pkt->otg_pkt).mode = PDCP_TRANSMISSION_MODE_DATA; - pkt_list_add_tail_eurecom(otg_pkt, &(otg_pdcp_buffer[module_id])); - LOG_I(EMU, "[UE %d] ADD pkt to OTG buffer with size %d for dst %d on rb_id %d \n", - (otg_pkt->otg_pkt).module_id, otg_pkt->otg_pkt.sdu_buffer_size, (otg_pkt->otg_pkt).dst_id,(otg_pkt->otg_pkt).rb_id); - } else { - free(otg_pkt); - otg_pkt=NULL; - } + for (app_id=0; app_idotg_pkt).sdu_buffer = (uint8_t*) packet_gen(src_id, dst_id, app_id, ctime, &((otg_pkt->otg_pkt).sdu_buffer_size)); + + if ((otg_pkt->otg_pkt).sdu_buffer != NULL) { + (otg_pkt->otg_pkt).rb_id = DTCH-2; + (otg_pkt->otg_pkt).module_id = module_id; + (otg_pkt->otg_pkt).dst_id = dst_id; + (otg_pkt->otg_pkt).is_ue = 1; + //Adding the packet to the OTG-PDCP buffer + (otg_pkt->otg_pkt).mode = PDCP_TRANSMISSION_MODE_DATA; + pkt_list_add_tail_eurecom(otg_pkt, &(otg_pdcp_buffer[module_id])); + LOG_I(EMU, "[UE %d] ADD pkt to OTG buffer with size %d for dst %d on rb_id %d \n", + (otg_pkt->otg_pkt).module_id, otg_pkt->otg_pkt.sdu_buffer_size, (otg_pkt->otg_pkt).dst_id,(otg_pkt->otg_pkt).rb_id); + } else { + free(otg_pkt); + otg_pkt=NULL; + } + } } } } From 07d30b2288fdb6e296231e77c2acdf61135a81f5 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Sat, 23 Apr 2016 10:21:42 +0100 Subject: [PATCH 177/413] Fixed bug in the number of eNBs for the simulations --- openair2/ENB_APP/enb_app.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 63f071c743..dc21448aef 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -294,7 +294,7 @@ void *eNB_app_task(void *args_p) itti_mark_task_ready (TASK_ENB_APP); -# if defined(ENABLE_USE_MME) + # if defined(ENABLE_ITTI) # if defined(OAI_EMU) enb_nb = oai_emulation.info.nb_enb_local; enb_id_start = oai_emulation.info.first_enb_local; @@ -304,7 +304,7 @@ void *eNB_app_task(void *args_p) "Last eNB index is greater or equal to maximum eNB index (%d/%d)!", enb_id_end, NUMBER_OF_eNB_MAX); # endif -# endif + # endif enb_properties_p = enb_config_get(); From b9c92931440fd8c13c597c056b2eadbaefa92af6 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Sat, 23 Apr 2016 01:32:03 +0100 Subject: [PATCH 178/413] Added support for multiple eNBs --- openair2/ENB_APP/enb_agent.c | 28 +- openair2/ENB_APP/enb_agent_common.c | 7 +- .../CONF/enb.band7.agent.oaisim.2.enb.conf | 302 ++++++++++++++++++ 3 files changed, 325 insertions(+), 12 deletions(-) create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.2.enb.conf diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index 675272a2f4..6a9bcad878 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -59,13 +59,15 @@ void *receive_thread(void *args); pthread_t new_thread(void *(*f)(void *), void *b); Protocol__ProgranMessage *enb_agent_timeout(void* args); + +int agent_task_created = 0; /* * enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller * and can interact with other itti tasks */ void *enb_agent_task(void *args){ - enb_agent_instance_t *d = (enb_agent_instance_t *) args; + //enb_agent_instance_t *d = (enb_agent_instance_t *) args; Protocol__ProgranMessage *msg; void *data; int size; @@ -76,7 +78,7 @@ void *enb_agent_task(void *args){ const char *msg_name = NULL; instance_t instance; int result; - + struct enb_agent_timer_element_s * elem = NULL; itti_mark_task_ready(TASK_ENB_AGENT); @@ -100,7 +102,8 @@ void *enb_agent_task(void *args){ msg = enb_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, msg_p->ittiMsg.timer_has_expired.arg); if (msg != NULL){ data=enb_agent_pack_message(msg,&size); - if (enb_agent_msg_send(d->enb_id, ENB_AGENT_DEFAULT, data, size, priority)) { + elem = get_timer_entry(msg_p->ittiMsg.timer_has_expired.timer_id); + if (enb_agent_msg_send(elem->agent_id, ENB_AGENT_DEFAULT, data, size, priority)) { err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; goto error; } @@ -203,6 +206,7 @@ pthread_t new_thread(void *(*f)(void *), void *b) { return t; } +int channel_container_init = 0; int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ int channel_id; @@ -240,8 +244,10 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ /* * Initialize the channel container */ - enb_agent_init_channel_container(); - + if (!channel_container_init) { + enb_agent_init_channel_container(); + channel_container_init = 1; + } /*Create the async channel info*/ enb_agent_instance_t *channel_info = enb_agent_async_channel_info(mod_id, in_ip, in_port); @@ -294,12 +300,14 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ /* * start the enb agent task for tx and interaction with the underlying network function */ + if (!agent_task_created) { + if (itti_create_task (TASK_ENB_AGENT, enb_agent_task, (void *) &enb_agent[mod_id]) < 0) { + LOG_E(ENB_AGENT, "Create task for eNB Agent failed\n"); + return -1; + } + agent_task_created = 1; + } - if (itti_create_task (TASK_ENB_AGENT, enb_agent_task, (void *) &enb_agent[mod_id]) < 0) { - LOG_E(ENB_AGENT, "Create task for eNB Agent failed\n"); - return -1; - } - LOG_I(ENB_AGENT,"client ends\n"); return 0; diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 1e477c6c3c..1f4508f750 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -2090,11 +2090,14 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Progr //struct enb_agent_map agent_map; enb_agent_timer_instance_t timer_instance; +int agent_timer_init = 0; err_code_t enb_agent_init_timer(void){ LOG_I(ENB_AGENT, "init RB tree\n"); - - RB_INIT(&timer_instance.enb_agent_head); + if (!agent_timer_init) { + RB_INIT(&timer_instance.enb_agent_head); + agent_timer_init = 1; + } /* struct enb_agent_timer_element_s e; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.2.enb.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.2.enb.conf new file mode 100644 index 0000000000..c792961a18 --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.2.enb.conf @@ -0,0 +1,302 @@ +Active_eNBs = ( "eNB_Eurecom_LTEBox1", "eNB_Eurecom_LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0x00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB_Eurecom_LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = "1"; + + mobile_country_code = "208"; + + mobile_network_code = "10"; + + ////////// Physical parameters: + + component_carriers = ( + { + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2680000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 0; + N_RB_DL = 50; + Nid_cell_mbsfn = 0; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 25; + rx_gain = 20; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = 0; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 0; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -108; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -108; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 2; + rach_preambleInitialReceivedTargetPower = -100; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + } + ); + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.100.102"; + ipv6 = "0::0"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth2:1"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.103/24"; + + ENB_INTERFACE_NAME_FOR_S1U = "eth2:1"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.103/24"; + ENB_PORT_FOR_S1U = 2153; # Spec 2152 + }; + + NETWORK_CONTROLLER : + { + ENB_AGENT_INTERFACE_NAME = "eth0"; + ENB_AGENT_IPV4_ADDRESS = "10.0.0.5/30"; + ENB_AGENT_PORT = 2210; + ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; + }; + + log_config : + { + global_log_level ="trace"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="trace"; + phy_log_verbosity ="medium"; + mac_log_level ="trace"; + mac_log_verbosity ="medium"; + rlc_log_level ="trace"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="trace"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="trace"; + rrc_log_verbosity ="medium"; + gtpu_log_level ="debug"; + gtpu_log_verbosity ="medium"; + udp_log_level ="debug"; + udp_log_verbosity ="medium"; + osa_log_level ="debug"; + osa_log_verbosity ="low"; + }; + + }, + + { + ////////// Identification parameters: + eNB_ID = 0x01; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB_Eurecom_LTEBox1"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = "1"; + + mobile_country_code = "208"; + + mobile_network_code = "10"; + + ////////// Physical parameters: + + component_carriers = ( + { + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2680000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 10; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 25; + rx_gain = 20; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = 0; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 0; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -108; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -108; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 2; + rach_preambleInitialReceivedTargetPower = -100; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + } + ); + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.100.102"; + ipv6 = "0::0"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth2:2"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.104/24"; + + ENB_INTERFACE_NAME_FOR_S1U = "eth2:2"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.104/24"; + ENB_PORT_FOR_S1U = 2153; # Spec 2152 + }; + + NETWORK_CONTROLLER : + { + ENB_AGENT_INTERFACE_NAME = "eth0"; + ENB_AGENT_IPV4_ADDRESS = "10.0.0.5/30"; + ENB_AGENT_PORT = 2210; + ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; + }; + + log_config : + { + global_log_level ="trace"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="trace"; + phy_log_verbosity ="medium"; + mac_log_level ="trace"; + mac_log_verbosity ="medium"; + rlc_log_level ="trace"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="trace"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="trace"; + rrc_log_verbosity ="medium"; + gtpu_log_level ="debug"; + gtpu_log_verbosity ="medium"; + udp_log_level ="debug"; + udp_log_verbosity ="medium"; + osa_log_level ="debug"; + osa_log_verbosity ="low"; + }; + + } +); From 7e03fe232e00d5768704b3ecb6419fd0051f2dac Mon Sep 17 00:00:00 2001 From: Dominique Nussbaum Date: Thu, 26 May 2016 15:47:57 +0200 Subject: [PATCH 179/413] fixes for 20MHz --- openair1/SCHED/phy_mac_stub.c | 39 ++++++++++--------- openair1/SCHED/phy_procedures_lte_eNb.c | 3 +- targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m | 14 +++---- .../CONF/enb.band7.tm1.exmimo2.conf | 4 +- 4 files changed, 31 insertions(+), 29 deletions(-) diff --git a/openair1/SCHED/phy_mac_stub.c b/openair1/SCHED/phy_mac_stub.c index 3620b8bf27..56882bf404 100644 --- a/openair1/SCHED/phy_mac_stub.c +++ b/openair1/SCHED/phy_mac_stub.c @@ -57,6 +57,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e uint32_t rballoc = 0x7FFF; //uint32_t rballoc2 = 0x000F; + uint32_t rballoc_test = 0xFFFF; int subframe = phy_vars_eNB->proc[sched_subframe].subframe_tx; LTE_eNB_DLSCH_t *DLSCH_ptr = phy_vars_eNB->dlsch_eNB[0][0]; @@ -143,7 +144,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1A_10MHz_FDD_t; ((DCI1A_10MHz_FDD_t*)&bcch_pdu)->type = 1; ((DCI1A_10MHz_FDD_t*)&bcch_pdu)->vrb_type = 0; - ((DCI1A_10MHz_FDD_t*)&bcch_pdu)->rballoc = computeRIV(25,10,3); + ((DCI1A_10MHz_FDD_t*)&bcch_pdu)->rballoc = computeRIV(50,10,3); ((DCI1A_10MHz_FDD_t*)&bcch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; ((DCI1A_10MHz_FDD_t*)&bcch_pdu)->rv = 1; ((DCI1A_10MHz_FDD_t*)&bcch_pdu)->mcs = 1; @@ -154,7 +155,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1A_10MHz_TDD_1_6_t; ((DCI1A_10MHz_TDD_1_6_t*)&bcch_pdu)->type = 1; ((DCI1A_10MHz_TDD_1_6_t*)&bcch_pdu)->vrb_type = 0; - ((DCI1A_10MHz_TDD_1_6_t*)&bcch_pdu)->rballoc = computeRIV(25,10,3); + ((DCI1A_10MHz_TDD_1_6_t*)&bcch_pdu)->rballoc = computeRIV(50,10,3); ((DCI1A_10MHz_TDD_1_6_t*)&bcch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; ((DCI1A_10MHz_TDD_1_6_t*)&bcch_pdu)->rv = 1; ((DCI1A_10MHz_TDD_1_6_t*)&bcch_pdu)->mcs = 1; @@ -170,7 +171,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1A_20MHz_FDD_t; ((DCI1A_20MHz_FDD_t*)&bcch_pdu)->type = 1; ((DCI1A_20MHz_FDD_t*)&bcch_pdu)->vrb_type = 0; - ((DCI1A_20MHz_FDD_t*)&bcch_pdu)->rballoc = computeRIV(25,10,3); + ((DCI1A_20MHz_FDD_t*)&bcch_pdu)->rballoc = computeRIV(100,10,3); ((DCI1A_20MHz_FDD_t*)&bcch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; ((DCI1A_20MHz_FDD_t*)&bcch_pdu)->rv = 1; ((DCI1A_20MHz_FDD_t*)&bcch_pdu)->mcs = 1; @@ -181,7 +182,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1A_20MHz_TDD_1_6_t; ((DCI1A_20MHz_TDD_1_6_t*)&bcch_pdu)->type = 1; ((DCI1A_20MHz_TDD_1_6_t*)&bcch_pdu)->vrb_type = 0; - ((DCI1A_20MHz_TDD_1_6_t*)&bcch_pdu)->rballoc = computeRIV(25,10,3); + ((DCI1A_20MHz_TDD_1_6_t*)&bcch_pdu)->rballoc = computeRIV(100,10,3); ((DCI1A_20MHz_TDD_1_6_t*)&bcch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; ((DCI1A_20MHz_TDD_1_6_t*)&bcch_pdu)->rv = 1; ((DCI1A_20MHz_TDD_1_6_t*)&bcch_pdu)->mcs = 1; @@ -231,14 +232,14 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e if (phy_vars_eNB->lte_frame_parms.frame_type == FDD) { DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_5MHz_FDD_t; - ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc; + ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(25,10,3); ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->TPC = 0; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; //((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rv = 0; - memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_5MHz_TDD_t)); + memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_5MHz_FDD_t)); /* //user2 @@ -261,7 +262,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e } else { DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_5MHz_TDD_t; - ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->rballoc = rballoc; + ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(25,10,3); ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->TPC = 0; ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->dai = 0; ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; @@ -298,14 +299,14 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e if (phy_vars_eNB->lte_frame_parms.frame_type == FDD) { DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_10MHz_FDD_t; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc; + ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(50,10,3); ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->TPC = 0; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; //((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rv = 0; - memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_10MHz_TDD_t)); + memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_10MHz_FDD_t)); /* //user2 @@ -328,7 +329,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e } else { DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_10MHz_TDD_t; - ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->rballoc = rballoc; + ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(50,10,3); ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->TPC = 0; ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->dai = 0; ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; @@ -362,16 +363,16 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e case 100: if (phy_vars_eNB->lte_frame_parms.frame_type == FDD) { - DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_5MHz_FDD_t; + DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_20MHz_FDD_t; - ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc; - ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->TPC = 0; - ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; - ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; + ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(100,10,3); + ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->TPC = 0; + ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; + ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; //((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); - ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; - ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rv = 0; - memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_5MHz_TDD_t)); + ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; + ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->rv = 0; + memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_20MHz_FDD_t)); /* //user2 @@ -394,7 +395,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e } else { DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_20MHz_TDD_t; - ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->rballoc = rballoc; + ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(100,10,3); ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->TPC = 0; ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->dai = 0; ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 161e2e5c58..5b38d495ec 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -562,6 +562,7 @@ void phy_eNB_lte_check_measurement_thresholds(instance_t instanceP, ral_threshol unsigned int taus(void); +DCI_PDU DCI_pdu_tmp; void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_eNB,uint8_t abstraction_flag, relaying_type_t r_type,PHY_VARS_RN *phy_vars_rn) @@ -573,7 +574,7 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e uint8_t harq_pid; DCI_PDU *DCI_pdu; uint8_t *DLSCH_pdu=NULL; - DCI_PDU DCI_pdu_tmp; + //DCI_PDU DCI_pdu_tmp; uint8_t DLSCH_pdu_tmp[768*8]; int8_t UE_id; uint8_t num_pdcch_symbols=0; diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m index ad33d26123..455963b651 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m @@ -1,4 +1,4 @@ -fc = 1907600000; +fc = 2655000000; %fc = 1907600000; %fc = 859.5e6; @@ -8,9 +8,9 @@ eNB_flag = 0; card = 0; active_rf = [1 1 1 1]; autocal = [1 1 1 1]; -resampling_factor = [2 2 2 2]; +resampling_factor = [0 0 0 0]; limeparms; -rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM) * active_rf; +rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF10+RXLPFNORM+RXLPFEN+RXLPF10+LNA1ON+LNAMax+RFBBNORM) * active_rf; rf_mode = rf_mode + (DMAMODE_RX + DMAMODE_TX)*active_rf; %rf_mode = rf_mode + (DMAMODE_TX)*active_rf + DMAMODE_RX*active_rf; %rf_mode = RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAByp+RFBBLNA1; @@ -56,10 +56,10 @@ case 0 s(:,4) = amp * ones(1,length); case 1 - s(:,1) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/4))); - s(:,2) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/4))); - s(:,3) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/4))); - s(:,4) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/4))); + s(:,1) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/256))); + s(:,2) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/256))); + s(:,3) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/256))); + s(:,4) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/256))); case 2 s(38400+128,1)= 80-1j*40; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf index f1160e78ca..852d9603ce 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf @@ -31,11 +31,11 @@ eNBs = downlink_frequency = 2680000000L; uplink_frequency_offset = -120000000; Nid_cell = 0; - N_RB_DL = 25; + N_RB_DL = 50; Nid_cell_mbsfn = 0; nb_antennas_tx = 1; nb_antennas_rx = 1; - tx_gain = 25; + tx_gain = 0; rx_gain = 20; prach_root = 0; prach_config_index = 0; From b6e7f7ec513496d5448ecbd8011fe577f59cc032 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 30 May 2016 17:58:31 +0200 Subject: [PATCH 180/413] tx_eNB -> ant_ports in oaisim --- targets/SIMU/USER/oaisim_functions.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index 72153c3ee7..f7e6b97d37 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -934,12 +934,12 @@ void init_openair1(void) PHY_vars_eNB_g[eNB_id][CC_id]->pusch_config_dedicated[UE_id].betaOffset_ACK_Index = beta_ACK; PHY_vars_eNB_g[eNB_id][CC_id]->pusch_config_dedicated[UE_id].betaOffset_RI_Index = beta_RI; PHY_vars_eNB_g[eNB_id][CC_id]->pusch_config_dedicated[UE_id].betaOffset_CQI_Index = beta_CQI; - PHY_vars_eNB_g[eNB_id][CC_id]->lte_frame_parms.pdsch_config_common.p_b = (frame_parms[CC_id]->nb_antennas_tx_eNB>1) ? 1 : 0; // rho_A = rho_B + PHY_vars_eNB_g[eNB_id][CC_id]->lte_frame_parms.pdsch_config_common.p_b = (frame_parms[CC_id]->nb_antenna_ports_eNB>1) ? 1 : 0; // rho_A = rho_B PHY_vars_UE_g[UE_id][CC_id]->pusch_config_dedicated[eNB_id].betaOffset_ACK_Index = beta_ACK; PHY_vars_UE_g[UE_id][CC_id]->pusch_config_dedicated[eNB_id].betaOffset_RI_Index = beta_RI; PHY_vars_UE_g[UE_id][CC_id]->pusch_config_dedicated[eNB_id].betaOffset_CQI_Index = beta_CQI; - PHY_vars_UE_g[UE_id][CC_id]->lte_frame_parms.pdsch_config_common.p_b = (frame_parms[CC_id]->nb_antennas_tx_eNB>1) ? 1 : 0; // rho_A = rho_B + PHY_vars_UE_g[UE_id][CC_id]->lte_frame_parms.pdsch_config_common.p_b = (frame_parms[CC_id]->nb_antenna_ports_eNB>1) ? 1 : 0; // rho_A = rho_B } } } From d621de7fb3f41a3083fd435833fce1b702a4f68a Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 30 May 2016 18:38:52 +0200 Subject: [PATCH 181/413] enable TM7 in oaisim --- targets/SIMU/USER/oaisim_functions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index f7e6b97d37..1b29da3740 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -685,7 +685,7 @@ void get_simulation_options(int argc, char *argv[]) oai_emulation.info.transmission_mode[0] = atoi (optarg); if ((oai_emulation.info.transmission_mode[0] != 1) && (oai_emulation.info.transmission_mode[0] != 2) && (oai_emulation.info.transmission_mode[0] != 3) - && (oai_emulation.info.transmission_mode[0] != 5) && (oai_emulation.info.transmission_mode[0] != 6)) { + && (oai_emulation.info.transmission_mode[0] != 5) && (oai_emulation.info.transmission_mode[0] != 6) && (oai_emulation.info.transmission_mode[0] !=7)) { printf("Unsupported transmission mode %d\n",oai_emulation.info.transmission_mode[0]); exit(-1); } From 7ca6a84e200665d53e627ac600528e6b457c4be3 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 31 May 2016 17:37:19 +0200 Subject: [PATCH 182/413] bug fixed for oarf_get_frame --- targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc index 708910b4f7..e53dccd5db 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc @@ -192,14 +192,14 @@ DEFUN_DLD (oarf_get_frame, args, nargout,"Get frame") for (j=0; j Date: Tue, 31 May 2016 17:38:01 +0200 Subject: [PATCH 183/413] add exmimo octave api env to TDD rec proj --- targets/PROJECTS/TDDREC/s_init_params.m | 1 + 1 file changed, 1 insertion(+) diff --git a/targets/PROJECTS/TDDREC/s_init_params.m b/targets/PROJECTS/TDDREC/s_init_params.m index 9683ed2d17..be51524755 100644 --- a/targets/PROJECTS/TDDREC/s_init_params.m +++ b/targets/PROJECTS/TDDREC/s_init_params.m @@ -1,6 +1,7 @@ clear all close all addpath([getenv('OPENAIR_TARGETS') '/ARCH/EXMIMO/USERSPACE/OCTAVE']); +addpath([getenv('OPENAIR_DIR') '/cmake_targets/lte_build_oai/build']); %% -------- ExpressMIMO2 configuration -------- limeparms; From b1f64b22a6ea43368140076abd67664ef93e024e Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 31 May 2016 19:13:45 +0200 Subject: [PATCH 184/413] bug fixed for oarf_get_frame --- targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc index e53dccd5db..170f782a04 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/oarf_get_frame.cc @@ -178,7 +178,7 @@ DEFUN_DLD (oarf_get_frame, args, nargout,"Get frame") printf("Info : Only resampling_factor of channel 0 is taken into account for copying received frame for all the other chains\n"); - ComplexMatrix dx (FRAME_LENGTH_COMPLEX_SAMPLES*4, numant*openair0_num_detected_cards); + ComplexMatrix dx (FRAME_LENGTH_COMPLEX_SAMPLES*4, MAX_ANTENNAS*openair0_num_detected_cards); /* // set the tx buffer to 0x00010001 to put switch in rx mode for (aa=0; aa Date: Thu, 9 Jun 2016 12:16:57 +0200 Subject: [PATCH 185/413] fixed a bug in initialization of DCI --- openair1/SCHED/phy_mac_stub.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/openair1/SCHED/phy_mac_stub.c b/openair1/SCHED/phy_mac_stub.c index 56882bf404..e1a75a3a4e 100644 --- a/openair1/SCHED/phy_mac_stub.c +++ b/openair1/SCHED/phy_mac_stub.c @@ -239,6 +239,8 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e //((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rv = 0; + ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rah = 0; + memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_5MHz_FDD_t)); /* @@ -270,6 +272,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e //((DCI1_5MHz_TDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->rv = 0; + ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->rah = 0; memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_5MHz_TDD_t)); /* @@ -288,6 +291,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = 1; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rv = 0; + ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rah = 0; memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&((DCI1_5MHz_FDD_t *)&dlsch_pdu)->,sizeof(DCI1_5MHz_TDD_t)); */ } @@ -306,6 +310,8 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e //((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rv = 0; + ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rah = 0; + memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_10MHz_FDD_t)); /* @@ -324,6 +330,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = 1; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rv = 0; + ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rah = 0; memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&((DCI1_10MHz_FDD_t *)&dlsch_pdu)->,sizeof(DCI1_10MHz_TDD_t)); */ } else { @@ -337,6 +344,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e //((DCI1_10MHz_TDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->rv = 0; + ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->rah = 0; memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_10MHz_TDD_t)); /* @@ -355,6 +363,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = 1; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rv = 0; + ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rah = 0; memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&((DCI1_10MHz_FDD_t *)&dlsch_pdu)->,sizeof(DCI1_10MHz_TDD_t)); */ } @@ -372,6 +381,8 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e //((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->rv = 0; + ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->rah = 0; + memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_20MHz_FDD_t)); /* @@ -390,6 +401,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = 1; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rv = 0; + ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rah = 0; memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&((DCI1_5MHz_FDD_t *)&dlsch_pdu)->,sizeof(DCI1_5MHz_TDD_t)); */ } else { @@ -403,6 +415,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e //((DCI1_20MHz_TDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->rv = 0; + ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->rah = 0; memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_20MHz_TDD_t)); /* @@ -421,6 +434,7 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->ndi = 1; ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->rv = 0; + ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->rah = 0; memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&((DCI1_20MHz_FDD_t *)&dlsch_pdu)->,sizeof(DCI1_5MHz_TDD_t)); */ } From d7db5cdd57ebc92ddc57a9eaf5c923133091e8d3 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Wed, 15 Jun 2016 17:54:13 +0200 Subject: [PATCH 186/413] merge ue_spec beamforming and cell_spec beamforming to beam_precoding --- openair1/PHY/INIT/lte_init.c | 22 ++- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 2 +- openair1/PHY/MODULATION/beamforming.c | 185 +++++------------- openair1/PHY/MODULATION/defs.h | 35 +--- openair1/PHY/MODULATION/ofdm_mod.c | 13 +- openair1/PHY/impl_defs_lte.h | 15 +- openair1/SCHED/phy_procedures_lte_eNb.c | 19 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 10 +- .../CONF/enb.band7.tm1.exmimo2.conf | 8 +- 9 files changed, 109 insertions(+), 200 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index c13373647d..f5e9fdae10 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1235,7 +1235,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, LTE_eNB_PUSCH** const eNB_pusch_vars = phy_vars_eNB->lte_eNB_pusch_vars; LTE_eNB_SRS* const eNB_srs_vars = phy_vars_eNB->lte_eNB_srs_vars; LTE_eNB_PRACH* const eNB_prach_vars = &phy_vars_eNB->lte_eNB_prach_vars; - int i, j, eNB_id, UE_id; + int i, j, re, eNB_id, UE_id; phy_vars_eNB->total_dlsch_bitrate = 0; phy_vars_eNB->total_transmitted_bits = 0; @@ -1302,7 +1302,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, #endif } - for (i=0; i<2; i++) { // 2 is the total number of cell specific antenna ports + /*for (i=0; i<2; i++) { // 2 is the total number of cell specific antenna ports eNB_common_vars->cell_spec_bf_weights[eNB_id][i] = (int32_t **)malloc16_clear(frame_parms->nb_antennas_tx*sizeof(int32_t*)); for (j=0; jnb_antennas_tx; j++) { eNB_common_vars->cell_spec_bf_weights[eNB_id][i][j] = (int32_t *)malloc16_clear(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); @@ -1310,11 +1310,25 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->cell_spec_bf_weights[%d][%d][%d] = %p (%d bytes)\n", eNB_id,i,j,eNB_common_vars->cell_spec_bf_weights[eNB_id][i][j], OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); +#endif + } + } */ + + for (i=0; i<15; i++) { // 15 is the total number of antenna ports + eNB_common_vars->beam_weights[eNB_id][i] = (int32_t **)malloc16_clear(frame_parms->nb_antennas_tx*sizeof(int32_t*)); + for (j=0; jnb_antennas_tx; j++) { + eNB_common_vars->beam_weights[eNB_id][i][j] = (int32_t *)malloc16_clear(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); + for (re=0; rebeam_weights[eNB_id][i][j][re] = 0x00007fff; +#ifdef DEBUG_PUY + msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->beam_weights[%d][%d][%d] = %p (%d bytes)\n", + eNB_id,i,j,eNB_common_vars->beam_weights[eNB_id][i][j], + OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); #endif } } - for (i=0; i<8; i++) { //antenna port 5 for TM7, antenna port 7-15 for TM8-10 + /*for (i=0; i<8; i++) { //antenna port 5 for TM7, antenna port 7-15 for TM8-10 eNB_common_vars->ue_spec_bf_weights[eNB_id][i] = (int32_t **)malloc16_clear(frame_parms->nb_antennas_tx*sizeof(int32_t*)); for (j=0; jnb_antennas_tx; j++) { eNB_common_vars->ue_spec_bf_weights[eNB_id][i][j] = (int32_t*)malloc16_clear(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); @@ -1324,7 +1338,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); #endif } - } + } */ // RX vars eNB_common_vars->rxdata[eNB_id] = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*) ); diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index a59667c3f6..f50b0a7567 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -1446,7 +1446,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, // mapping ue specific beamforming weights from UE specified DLSCH structure to common space for (aa=0;aanb_antennas_tx;aa++){ - memcpy(phy_vars_eNB->lte_eNB_common_vars.ue_spec_bf_weights[0][0][aa],dlsch0->ue_spec_bf_weights[0][aa],frame_parms->ofdm_symbol_size*sizeof(int32_t)); + memcpy(phy_vars_eNB->lte_eNB_common_vars.beam_weights[0][5][aa],dlsch0->ue_spec_bf_weights[0][aa],frame_parms->ofdm_symbol_size*sizeof(int32_t)); } } diff --git a/openair1/PHY/MODULATION/beamforming.c b/openair1/PHY/MODULATION/beamforming.c index 157b8eb368..e37ab0e430 100644 --- a/openair1/PHY/MODULATION/beamforming.c +++ b/openair1/PHY/MODULATION/beamforming.c @@ -46,14 +46,12 @@ Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 069 #include "defs.h" #include "UTIL/LOG/vcd_signal_dumper.h" - -// ue_spec_beamforming: perform beamforming for data in transmission_mode TM7-TM10 -int ue_spec_beamforming(int32_t **txdataF, - int32_t **txdataF_BF, - LTE_DL_FRAME_PARMS *frame_parms, - int32_t ***ue_spec_bf_weights, - int slot, - int symbol) +int beam_precoding(int32_t **txdataF, + int32_t **txdataF_BF, + LTE_DL_FRAME_PARMS *frame_parms, + int32_t ***beam_weights, + int slot, + int symbol) { uint8_t p,aa; uint16_t re=0; @@ -66,41 +64,54 @@ int ue_spec_beamforming(int32_t **txdataF, memset(txdataF_BF[aa],0,4*(frame_parms->ofdm_symbol_size)); for (re=0;reofdm_symbol_size;re++) { + for (p=0; p<2; p++) { + if (txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { + for (aa=0;aanb_antennas_tx;aa++) { + ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); + ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[0][aa][re])[0])>>15); + + //printf("beamforming.c:txdata[%d][%d]=%d+j%d, beam_weights[%d][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", + // p,slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re, + // ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0], + // ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1], + // p,aa,re, + // ((int16_t*)&beam_weights[p][aa][re])[0],((int16_t*)&beam_weights[p][aa][re])[1], + // aa,re, + // ((int16_t*)&txdataF_BF[aa][re])[0], + // ((int16_t*)&txdataF_BF[aa][re])[1]); + } + + } + } if (txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually using TM7 for (aa=0;aanb_antennas_tx;aa++) { - ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0] - *((int16_t*)&ue_spec_bf_weights[0][aa][re])[0])>>15); - ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1] - *((int16_t*)&ue_spec_bf_weights[0][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0] - *((int16_t*)&ue_spec_bf_weights[0][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1] - *((int16_t*)&ue_spec_bf_weights[0][aa][re])[0])>>15); + ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[5][aa][re])[0])>>15); + ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[5][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[5][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[5][aa][re])[0])>>15); + // printf("beamforming.c:txdata[%d][%d]=%d+j%d, beam_weights[%d][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", + // p,slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re, + // ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0], + // ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1], + // p,aa,re, + // ((int16_t*)&beam_weights[p][aa][re])[0],((int16_t*)&beam_weights[p][aa][re])[1], + // aa,re, + // ((int16_t*)&txdataF_BF[aa][re])[0], + // ((int16_t*)&txdataF_BF[aa][re])[1]); -/* printf("beamforming.c:txdataF[5][%d]=%d+j%d, ue_bf_weights[0][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", - slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re, - ((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0], - ((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1], - aa,re, - ((int16_t*)&ue_spec_bf_weights[0][aa][re])[0],((int16_t*)&ue_spec_bf_weights[0][aa][re])[1], - aa,re, - ((int16_t*)&txdataF_BF[aa][re])[0], - ((int16_t*)&txdataF_BF[aa][re])[1]); */ } } if (txdataF[7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually using TM8-10 - for (p=0;p<8;p++) { - if (txdataF[p+7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually allocated + for (p=7;p<15;p++) { + if (txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually allocated for (aa=0;aanb_antennas_tx;aa++) { - ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[p+7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0] - *((int16_t*)&ue_spec_bf_weights[p][aa][re])[0])>>15); - ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[p+7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1] - *((int16_t*)&ue_spec_bf_weights[p][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[p+7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0] - *((int16_t*)&ue_spec_bf_weights[p][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p+7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1] - *((int16_t*)&ue_spec_bf_weights[p][aa][re])[0])>>15); + ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); + ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); } } } @@ -108,107 +119,3 @@ int ue_spec_beamforming(int32_t **txdataF, } } -// cell_spec_beamforming: performed for all common data -int cell_spec_beamforming(int32_t **txdataF, - int32_t **txdataF_BF, - LTE_DL_FRAME_PARMS *frame_parms, - int32_t ***cell_spec_bf_weights, - int slot, - int symbol) -{ - uint8_t p,aa; - uint16_t re=0; - int slot_offset_F; - - slot_offset_F = slot*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); - - // clear txdata_BF[aa][re] for each call of cell_spec_beamforming - for(aa=0;aanb_antennas_tx;aa++) - memset(txdataF_BF[aa],0,4*(frame_parms->ofdm_symbol_size)); - - for (re=0;reofdm_symbol_size;re++) { - for (p=0;pnb_antenna_ports_eNB;p++) { - if (txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually allocated - for (aa=0;aanb_antennas_tx;aa++) { - - ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0] - *((int16_t*)&cell_spec_bf_weights[p][aa][re])[0])>>15); - ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1] - *((int16_t*)&cell_spec_bf_weights[p][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0] - *((int16_t*)&cell_spec_bf_weights[p][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1] - *((int16_t*)&cell_spec_bf_weights[p][aa][re])[0])>>15); - // printf("beamforming.c:txdata[%d][%d]=%d+j%d, cell_bf_weights[%d][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", - // p,slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re, - // ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0], - // ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1], - // p,aa,re, - // ((int16_t*)&cell_spec_bf_weights[p][aa][re])[0],((int16_t*)&cell_spec_bf_weights[p][aa][re])[1], - // aa,re, - // ((int16_t*)&txdataF_BF[aa][re])[0], - // ((int16_t*)&txdataF_BF[aa][re])[1]); - } - } - } - } -} - - - - -/* -int ue_spec_beamforming(int32_t **txdataF, - int32_t **txdataF_BF, - LTE_DL_FRAME_PARMS *frame_parms, - LTE_eNB_DLSCH_t *dlsch0, - LTE_eNB_DLSCH_t *dlsch1, - int symbol) -{ - uint8_t p,aa; - uint16_t re=0; - - uint8_t harq_pid = dlsch0->current_harq_pid; - LTE_DL_eNB_HARQ_t *dlsch0_harq = dlsch0->harq_processes[harq_pid]; - LTE_DL_eNB_HARQ_t *dlsch1_harq; //= dlsch1->harq_processes[harq_pid]; - MIMO_mode_t mimo_mode = dlsch0_harq->mimo_mode; - int first_layer0 = dlsch0_harq->first_layer; - int Nlayers0 = dlsch0_harq->Nlayers; - - // Fill these in later for TM8-10 - int Nlayers1; - int first_layer1; - - if (dlsch1_harq) { - Nlayers1 = dlsch1_harq->Nlayers; - first_layer1 = dlsch1_harq->first_layer; - } - - //temp - if(mimo_mode==TM7){ - first_layer0 = 5; - Nlayers0=1; - } - - for (re=0;renb_antennas_tx;aa++) { - txdataF_BF[aa][re] += txdataF[p][re]*dlsch0->uespec_bf_weights[p][aa][re]; - } - } - } - - if(dlsch1_harq) { - for (p=first_layer1;pnb_antennas_tx;aa++) { - txdataF_BF[aa][re] += txdataF[p][re]*dlsch1->uespec_bf_weights[p][aa][re]; - } - } - } - } - - } -} */ diff --git a/openair1/PHY/MODULATION/defs.h b/openair1/PHY/MODULATION/defs.h index fec65b8679..88c4e2a2d8 100644 --- a/openair1/PHY/MODULATION/defs.h +++ b/openair1/PHY/MODULATION/defs.h @@ -89,6 +89,8 @@ void normal_prefix_mod(int32_t *txdataF,int32_t *txdata,uint8_t nsymb,LTE_DL_FRA void do_OFDM_mod(mod_sym_t **txdataF, int32_t **txdata, uint32_t frame,uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms); +void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms, uint8_t num_pdcch_symbols); + void remove_7_5_kHz(PHY_VARS_eNB *phy_vars_eNB,uint8_t subframe); void apply_7_5_kHz(PHY_VARS_UE *phy_vars_ue,int32_t*txdata,uint8_t subframe); @@ -99,39 +101,22 @@ void remove_625_Hz(PHY_VARS_eNB *phy_vars_eNB,int16_t *prach); void apply_625_Hz(PHY_VARS_UE *phy_vars_ue,int16_t *prach); -/** \brief This function performs UE specific beamforming especially for - * transmission mode TM7-10 - @param txdataF Table of pointers for frequency-domain TX signals - @param txdataF_BF Table of pointers for frequency-domain TX signals -after beamforming - @param frame_parms Frame descriptor structure - @param ue_spec_bf_weights UE specific beamforming weights applied on -each antenna element and each carrier - @param slot Slot number - @param symbol Symbol index on which to act*/ -int ue_spec_beamforming(int32_t **txdataF, - int32_t **txdataF_BF, - LTE_DL_FRAME_PARMS *frame_parms, - int32_t ***ue_spec_bf_weights, - int slot, - int symbol); - -/** \brief This function performs cell specific beamforming for common +/** \brief This function performs beamforming precoding for common * data @param txdataF Table of pointers for frequency-domain TX signals @param txdataF_BF Table of pointers for frequency-domain TX signals @param frame_parms Frame descriptor structure after beamforming - @param cell_spec_bf_weights Common beamforming weights applied on each + @param beam_weights Beamforming weights applied on each antenna element and each carrier @param slot Slot number @param symbol Symbol index on which to act*/ -int cell_spec_beamforming(int32_t **txdataF, - int32_t **txdataF_BF, - LTE_DL_FRAME_PARMS *frame_parms, - int32_t ***cell_spec_bf_weights, - int slot, - int symbol); +int beam_precoding(int32_t **txdataF, + int32_t **txdataF_BF, + LTE_DL_FRAME_PARMS *frame_parms, + int32_t ***beam_weights, + int slot, + int symbol); #endif /** @}*/ diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index e8344a1972..375c16c103 100755 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -277,10 +277,11 @@ void do_OFDM_mod(mod_sym_t **txdataF, int32_t **txdata, uint32_t frame,uint16_t } // OFDM modulation for each symbol -void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms, uint8_t num_pdcch_symbols, unsigned char transmission_mode) +void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms, uint8_t num_pdcch_symbols) { int aa, l, slot_offset, slot_offset_F; + int8_t UE_id=0; mod_sym_t **txdataF = eNB_common_vars->txdataF[eNB_id]; mod_sym_t **txdataF_BF = eNB_common_vars->txdataF_BF[eNB_id]; int32_t **txdata = eNB_common_vars->txdata[eNB_id]; @@ -292,13 +293,8 @@ void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_sl for (l=0; lsymbols_per_tti>>1; l++) { //printf("do_OFDM_mod_l, slot=%d, l=%d, NUMBER_OF_OFDM_CARRIERS=%d,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES=%d\n",next_slot, l,NUMBER_OF_OFDM_CARRIERS,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES); - if (lcell_spec_bf_weights[eNB_id],next_slot,l); - else - if (transmission_mode<7) - cell_spec_beamforming(txdataF,txdataF_BF,frame_parms,eNB_common_vars->cell_spec_bf_weights[eNB_id],next_slot,l); - else - ue_spec_beamforming(txdataF,txdataF_BF,frame_parms,eNB_common_vars->ue_spec_bf_weights[eNB_id],next_slot,l); + + beam_precoding(txdataF,txdataF_BF,frame_parms,eNB_common_vars->beam_weights[eNB_id],next_slot,l); for (aa=0; aanb_antennas_tx; aa++) { @@ -331,4 +327,3 @@ void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_sl } } -/** @} */ diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h index 864d2d5d19..7a6130cef8 100644 --- a/openair1/PHY/impl_defs_lte.h +++ b/openair1/PHY/impl_defs_lte.h @@ -638,17 +638,24 @@ typedef struct { /// - second index: cell specific eNB antenna port index, up to 2 logical antenna ports are supported /// - third index: tx antenna [0..nb_antennas_tx[ /// - fourth index: sample [0..] - int32_t **cell_spec_bf_weights[3][2]; + // int32_t **cell_spec_bf_weights[3][2]; /// \brief Holds the ue specific beamforming weights /// - first index: eNB id [0..2] (hard coded) /// - second index: ue specific eNB antenna port index, port5->index0, port7-15->index0-7 /// - third index: tx antenna [0..nb_antennas_tx[ /// - fourth index: sample [0..] - int32_t **ue_spec_bf_weights[3][8]; + // int32_t **ue_spec_bf_weights[3][8]; + /// \brief Holds the ue specific beamforming weights + /// - first index: eNB id [0..2] (hard coded) + /// - second index: eNB antenna port index + /// - third index: tx antenna [0..nb_antennas_tx[ + /// - fourth index: sample [0..] + int32_t **beam_weights[3][15]; /// \brief Holds the tdd reciprocity calibration coefficients /// - first index: eNB id [0..2] (hard coded) - /// - second index: tx antenna [0..nb_antennas_tx[ - /// - third index: frenquency [0..] + /// - second index: ue specific eNB antenna port index, port5->index0, port7-15->index0-7 + /// - third index: tx antenna [0..nb_antennas_tx[ + /// - forth index: frenquency [0..] int32_t **tdd_calib_coeffs[3]; } LTE_eNB_COMMON; diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index bb6eb704e0..d2a350a4b8 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -1610,7 +1610,7 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e phy_vars_eNB->dlsch_eNB_ra->active = 0; } - // Now scan UE specific DLSCH + // Now scan UE specific DLSCH for (UE_id=0; UE_iddlsch_eNB[(uint8_t)UE_id][0])&& @@ -1779,6 +1779,7 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->active = 0; //mac_xface->macphy_exit("first dlsch transmitted\n"); + } else if ((phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0])&& @@ -1791,6 +1792,7 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e //LOG_D(PHY,"[eNB %d] DCI: Clearing subframe_tx for subframe %d, UE %d\n",phy_vars_eNB->Mod_id,subframe,UE_id); #endif } + } @@ -1811,30 +1813,31 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e } - #ifdef EMOS phy_procedures_emos_eNB_TX(subframe, phy_vars_eNB); #endif + //cell-specific beamforming + #if !(defined(EXMIMO) || defined(OAI_USRP) || defined (CPRIGW)) if (abstraction_flag==0) { start_meas(&phy_vars_eNB->ofdm_mod_stats); - do_OFDM_mod_l(phy_vars_eNB->lte_eNB_common_vars, + //do_OFDM_mod (without l) ? + + do_OFDM_mod_l(&phy_vars_eNB->lte_eNB_common_vars, 0, subframe<<1, &phy_vars_eNB->lte_frame_parms, - num_pdcch_symbols, - phy_vars_eNB->transmission_mode[(uint8_t)UE_id]); + num_pdcch_symbols); - do_OFDM_mod_l(phy_vars_eNB->lte_eNB_common_vars, + do_OFDM_mod_l(&phy_vars_eNB->lte_eNB_common_vars, 0, 1+(subframe<<1), &phy_vars_eNB->lte_frame_parms, - num_pdcch_symbols, - phy_vars_eNB->transmission_mode[(uint8_t)UE_id]); + num_pdcch_symbols); stop_meas(&phy_vars_eNB->ofdm_mod_stats); } diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index f5c2446e86..19a0437bdf 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -643,7 +643,7 @@ int main(int argc, char **argv) frame_parms = &PHY_vars_eNB->lte_frame_parms; - cell_spec_bf_weights = PHY_vars_eNB->lte_eNB_common_vars.cell_spec_bf_weights[0][0]; + cell_spec_bf_weights = PHY_vars_eNB->lte_eNB_common_vars.beam_weights[0][0]; for(aa=0;aaofdm_symbol_size;re++) { if (n_tx_phy==1 || n_tx_phy==2) @@ -655,7 +655,7 @@ int main(int argc, char **argv) else if (n_tx_phy==64) cell_spec_bf_weights[aa][re] = 0x00007fff>>4; } - } + } if (transmission_mode==7){ lte_gold_ue_spec_port5(PHY_vars_eNB->lte_gold_uespec_port5_table[0],Nid_cell,n_rnti); @@ -2813,15 +2813,13 @@ PMI_FEEDBACK: eNB_id, (subframe*2), &PHY_vars_eNB->lte_frame_parms, - num_pdcch_symbols, - transmission_mode); + num_pdcch_symbols); do_OFDM_mod_l(&PHY_vars_eNB->lte_eNB_common_vars, eNB_id, (subframe*2)+1, &PHY_vars_eNB->lte_frame_parms, - num_pdcch_symbols, - transmission_mode); + num_pdcch_symbols); stop_meas(&PHY_vars_eNB->ofdm_mod_stats); stop_meas(&PHY_vars_eNB->phy_proc_tx); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf index 3ce32398f7..c0974d8703 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf @@ -154,13 +154,13 @@ eNBs = global_log_verbosity ="medium"; hw_log_level ="info"; hw_log_verbosity ="medium"; - phy_log_level ="warn"; + phy_log_level ="debug"; phy_log_verbosity ="medium"; - mac_log_level ="warn"; + mac_log_level ="debug"; mac_log_verbosity ="medium"; - rlc_log_level ="warn"; + rlc_log_level ="info"; rlc_log_verbosity ="medium"; - pdcp_log_level ="warn"; + pdcp_log_level ="info"; pdcp_log_verbosity ="medium"; rrc_log_level ="info"; rrc_log_verbosity ="medium"; From 81047e94af2092a83afcd9896c8ea9eb62b80ba2 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 17 Jun 2016 16:41:21 +0200 Subject: [PATCH 187/413] cosmetic changes --- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 1 - openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index eb13b52015..3f5fe2de84 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -204,7 +204,6 @@ LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_ for (i=0; i<4; i++) { dlsch->ue_spec_bf_weights[i] = (int32_t **)malloc16(nb_antennas_tx*sizeof(int32_t*)); - dlsch->ue_spec_bf_weights[i] = (int32_t **)malloc16(nb_antennas_tx*sizeof(int32_t*)); for (aa=0; aaue_spec_bf_weights[i][aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index f50b0a7567..1cba160c1f 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -46,7 +46,7 @@ Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 069 #include "defs.h" #include "UTIL/LOG/vcd_signal_dumper.h" -//#define DEBUG_DLSCH_MODULATION +#define DEBUG_DLSCH_MODULATION //#define is_not_pilot(pilots,re,nushift,use2ndpilots) ((pilots==0) || ((re!=nushift) && (re!=nushift+6)&&((re!=nushift+3)||(use2ndpilots==1))&&((re!=nushift+9)||(use2ndpilots==1)))?1:0) @@ -387,8 +387,8 @@ break; *jj=*jj+1; - ((int16_t *)&txdataF[aa][tti_offset])[0]=qam_table_s0[qam64_table_offset_re];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); - ((int16_t *)&txdataF[aa][tti_offset])[1]=qam_table_s0[qam64_table_offset_im];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); + ((int16_t *)&txdataF[0][tti_offset])[0]=qam_table_s0[qam64_table_offset_re];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); + ((int16_t *)&txdataF[0][tti_offset])[1]=qam_table_s0[qam64_table_offset_im];//(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); break; @@ -1457,7 +1457,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, symbol_offset = (uint32_t)frame_parms->ofdm_symbol_size*(l+(subframe_offset*nsymb)); //memset(&txdataF[aa][symbol_offset],0,frame_parms->ofdm_symbol_size<<2); - //printf("symbol_offset %d,subframe offset %d : pilots %d\n",symbol_offset,subframe_offset,pilots); + // printf("symbol_offset %d,subframe offset %d : pilots %d\n",symbol_offset,subframe_offset,pilots); for (rb=0; rbN_RB_DL; rb++) { if (rb < 32) @@ -1618,7 +1618,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, qam_table_s1 = NULL; if (rb_alloc_ind > 0) { - // printf("Allocated rb %d/symbol %d, skip_half %d, subframe_offset %d, symbol_offset %d, re_offset %d, jj %d\n",rb,l,skip_half,subframe_offset,symbol_offset,re_offset,jj); + //printf("Allocated rb %d/symbol %d, skip_half %d, subframe_offset %d, symbol_offset %d, re_offset %d, jj %d\n",rb,l,skip_half,subframe_offset,symbol_offset,re_offset,jj); allocate_REs_in_RB(phy_vars_eNB, txdataF, &jj, @@ -1660,7 +1660,7 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, #ifdef DEBUG_DLSCH_MODULATION - msg("generate_dlsch : jj = %d,re_allocated = %d (G %d)\n",jj,re_allocated,get_G(frame_parms,dlsch0_harq->nb_rb,dlsch0_harq->rb_alloc,mod_order0,Nl0,2,0,subframe_offset)); + msg("generate_dlsch : jj = %d,re_allocated = %d (G %d)\n",jj,re_allocated,get_G(frame_parms,dlsch0_harq->nb_rb,dlsch0_harq->rb_alloc,mod_order0,Nl0,2,0,subframe_offset,1/*transmission mode*/)); #endif VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_MODULATION, VCD_FUNCTION_OUT); @@ -1759,7 +1759,7 @@ int mch_modulation(mod_sym_t **txdataF, #ifdef DEBUG_DLSCH_MODULATION - msg("generate_dlsch(MCH) : jj = %d,re_allocated = %d (G %d)\n",jj,re_allocated,get_G(frame_parms,dlsch->harq_processes[0]->nb_rb,dlsch->harq_processes[0]->rb_alloc,mod_order,1,2,0,subframe_offset)); + msg("generate_dlsch(MCH) : jj = %d,re_allocated = %d (G %d)\n",jj,re_allocated,get_G(frame_parms,dlsch->harq_processes[0]->nb_rb,dlsch->harq_processes[0]->rb_alloc,mod_order,1,2,0,subframe_offset,1/*transmission mode*/)); #endif return (re_allocated); From 5a40c9a8c74cf0530a508278ff9e5eb0676c5264 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 17 Jun 2016 16:42:40 +0200 Subject: [PATCH 188/413] bug fixed for dlsch_modulation input --- openair1/SCHED/phy_procedures_lte_eNb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index d2a350a4b8..e03ffa2120 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -1436,7 +1436,7 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e 1, num_pdcch_symbols,phy_vars_eNB->proc[sched_subframe].frame_tx, subframe, - (phy_vars_eNB->transmission_mode[(uint8_t)UE_id]<7?0:phy_vars_eNB->transmission_mode[(uint8_t)UE_id])), + 0), 0, subframe<<1); @@ -1444,7 +1444,7 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e start_meas(&phy_vars_eNB->dlsch_modulation_stats); // for (sect_id=0;sect_idlte_eNB_common_vars.txdataF[0], AMP, subframe, From a04682d47a54d0f0d5890f29599306d1ed341bf4 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 17 Jun 2016 16:44:30 +0200 Subject: [PATCH 189/413] oaisim takes tx and rx antenna number from config file and transmission mode from the command line --- targets/SIMU/USER/init_lte.c | 8 ++++---- targets/SIMU/USER/init_lte.h | 1 + targets/SIMU/USER/oaisim_functions.c | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/targets/SIMU/USER/init_lte.c b/targets/SIMU/USER/init_lte.c index 3b2bc34391..3463da77d8 100644 --- a/targets/SIMU/USER/init_lte.c +++ b/targets/SIMU/USER/init_lte.c @@ -229,7 +229,7 @@ void init_lte_vars(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs], uint8_t N_RB_DL, uint16_t Nid_cell, uint8_t cooperation_flag,uint8_t transmission_mode,uint8_t abstraction_flag, - int nb_antennas_rx, uint8_t eMBMS_active_state) + int nb_antennas_rx, int nb_antennas_tx, uint8_t eMBMS_active_state) { uint8_t eNB_id,UE_id,RN_id,CC_id; @@ -252,10 +252,10 @@ void init_lte_vars(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs], (frame_parms[CC_id])->Ncp = extended_prefix_flag; (frame_parms[CC_id])->Nid_cell = Nid_cell; (frame_parms[CC_id])->nushift = (Nid_cell%6); - (frame_parms[CC_id])->nb_antennas_tx = (transmission_mode == 1) ? 1 : 2; + (frame_parms[CC_id])->nb_antennas_tx = nb_antennas_tx; + (frame_parms[CC_id])->nb_antennas_rx = nb_antennas_rx; (frame_parms[CC_id])->nb_antenna_ports_eNB = (transmission_mode == 1 || transmission_mode == 7) ? 1 : 2; - (frame_parms[CC_id])->nb_antennas_rx = (transmission_mode == 1) ? 1 : 2; - (frame_parms[CC_id])->mode1_flag = (transmission_mode == 1) ? 1 : 0; + (frame_parms[CC_id])->mode1_flag = (frame_parms[CC_id])->nb_antenna_ports_eNB==1 ? 1 : 0; init_frame_parms(frame_parms[CC_id],1); diff --git a/targets/SIMU/USER/init_lte.h b/targets/SIMU/USER/init_lte.h index b00f1f8a3c..269863085d 100644 --- a/targets/SIMU/USER/init_lte.h +++ b/targets/SIMU/USER/init_lte.h @@ -57,4 +57,5 @@ void init_lte_vars(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs], uint8_t transmission_mode, uint8_t abstraction_flag, int nb_antennas_rx, + int nb_antennas_tx, uint8_t eMBMS_active_state); diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index 1b29da3740..326813181a 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -174,10 +174,11 @@ extern time_stats_t ul_chan_stats; extern int xforms; +const Enb_properties_array_t *enb_properties; + void get_simulation_options(int argc, char *argv[]) { int option; - const Enb_properties_array_t *enb_properties; char *conf_config_file_name = NULL; enum long_option_e { @@ -925,7 +926,7 @@ void init_openair1(void) // change the nb_connected_eNB for (CC_id=0; CC_idproperties[0]->nb_antennas_tx[CC_id],enb_properties->properties[0]->nb_antennas_tx[CC_id], oai_emulation.info.eMBMS_active_state); } for (eNB_id=0; eNB_id Date: Thu, 31 Mar 2016 11:34:32 +0200 Subject: [PATCH 190/413] transmission mode is now taken into account in RRC signalling small bugfix in dlsch_demodulation shunted out TM3-7 specific DCI generation in scheduler to enable basic operation. more work needed. --- .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 1 - openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 31 +++++-------------- openair2/RRC/LITE/MESSAGES/asn1_msg.c | 2 +- openair2/RRC/LITE/rrc_eNB.c | 2 +- .../CONF/enb.band7.exmimo2.conf | 2 +- 5 files changed, 11 insertions(+), 27 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index f578c6f3e4..aeca578ef5 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -829,7 +829,6 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, return(-1); break; } - return(0); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 58078082c0..2708f3bbb3 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -738,7 +738,8 @@ schedule_ue_spec( } break; - + /* + // 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; @@ -776,6 +777,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, @@ -1403,8 +1405,9 @@ schedule_ue_spec( break; + /* + // disabled for now as this needs to be done properly case 4: - // if (nb_rb>10) { ((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; @@ -1412,15 +1415,6 @@ schedule_ue_spec( ((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; - //} - /* else { - ((DCI2_5MHz_2A_L10PRB_TDD_t*)DLSCH_dci)->mcs1 = eNB_UE_stats->DL_cqi[0]; - ((DCI2_5MHz_2A_L10PRB_TDD_t*)DLSCH_dci)->harq_pid = harq_pid; - ((DCI2_5MHz_2A_L10PRB_TDD_t*)DLSCH_dci)->ndi1 = 1; - ((DCI2_5MHz_2A_L10PRB_TDD_t*)DLSCH_dci)->rv1 = round&3; - ((DCI2_5MHz_2A_L10PRB_TDD_t*)DLSCH_dci)->tpmi = 5; - ((DCI2_5MHz_2A_L10PRB_TDD_t*)DLSCH_dci)->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; - }*/ break; case 5: @@ -1451,6 +1445,7 @@ schedule_ue_spec( ((DCI1E_5MHz_2A_M10PRB_TDD_t*)DLSCH_dci)->TPC = tpc; break; + */ } // Toggle NDI for next time @@ -1732,9 +1727,9 @@ fill_DLSCH_dci( break; + /* case 4: - //if (nb_rb>10) { // DCI format 2_2A ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->rballoc = allocate_prbs_sub(nb_rb,rballoc_sub); ((DCI2_5MHz_2A_TDD_t*)DLSCH_dci)->rah = 0; @@ -1746,17 +1741,6 @@ fill_DLSCH_dci( sizeof_DCI2_5MHz_2A_TDD_t, format2, 0); - /*} - else { - ((DCI2_5MHz_2A_L10PRB_TDD_t*)DLSCH_dci)->rballoc = allocate_prbs_sub(nb_rb,rballoc_sub); - add_ue_spec_dci(DCI_pdu, - DLSCH_dci, - rnti, - sizeof(DCI2_5MHz_2A_L10PRB_TDD_t), - 2,//aggregation, - sizeof_DCI2_5MHz_2A_L10PRB_TDD_t, - format2_2A_L10PRB); - }*/ break; case 5: @@ -1786,6 +1770,7 @@ fill_DLSCH_dci( format1E_2A_M10PRB, 0); break; + */ } } diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index ff0adf713b..83fd5d357d 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -107,7 +107,7 @@ int errno; # endif #endif -//#define XER_PRINT +#define XER_PRINT extern Enb_properties_array_t enb_properties; typedef struct xer_sprint_string_s { diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 42e28f752f..c53df65046 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -3289,7 +3289,7 @@ rrc_eNB_generate_RRCConnectionSetup( do_RRCConnectionSetup(ctxt_pP, ue_context_pP, (uint8_t*) eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.Payload, - (mac_xface->lte_frame_parms->nb_antennas_tx==2)?2:1, + mac_xface->get_transmission_mode(ctxt_pP->module_id,CC_id,ue_context_pP->ue_id_rnti), rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id), mac_xface->lte_frame_parms, SRB_configList, diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.exmimo2.conf index bc9d15195c..6493c01167 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.exmimo2.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.exmimo2.conf @@ -47,7 +47,7 @@ eNBs = pucch_nCS_AN = 0; pucch_n1_AN = 32; pdsch_referenceSignalPower = -24; - pdsch_p_b = 0; + pdsch_p_b = 1; pusch_n_SB = 1; pusch_enable64QAM = "DISABLE"; pusch_hoppingMode = "interSubFrame"; From 61a6b0612960c135c9988b1a81f2a5be8b0795ca Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Wed, 22 Jun 2016 11:09:24 +0200 Subject: [PATCH 191/413] distinguish beamforming mode in rx_pdsch for SI, RA and data --- openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index aeca578ef5..831744bc09 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -100,7 +100,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, int avgs, rb; LTE_DL_UE_HARQ_t *dlsch0_harq,*dlsch1_harq = 0; - uint8_t beamforming_mode = phy_vars_ue->transmission_mode[eNB_id]<7?0:phy_vars_ue->transmission_mode[eNB_id]; + uint8_t beamforming_mode; uint32_t *rballoc; switch (type) { @@ -108,12 +108,14 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, lte_ue_pdsch_vars = &phy_vars_ue->lte_ue_pdsch_vars_SI[eNB_id]; dlsch_ue = &phy_vars_ue->dlsch_ue_SI[eNB_id]; dlsch0_harq = dlsch_ue[0]->harq_processes[harq_pid]; + beamforming_mode = 0; break; case RA_PDSCH: lte_ue_pdsch_vars = &phy_vars_ue->lte_ue_pdsch_vars_ra[eNB_id]; dlsch_ue = &phy_vars_ue->dlsch_ue_ra[eNB_id]; dlsch0_harq = dlsch_ue[0]->harq_processes[harq_pid]; + beamforming_mode = 0; break; case PDSCH: @@ -121,6 +123,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, dlsch_ue = phy_vars_ue->dlsch_ue[eNB_id]; dlsch0_harq = dlsch_ue[0]->harq_processes[harq_pid]; dlsch1_harq = dlsch_ue[1]->harq_processes[harq_pid]; + beamforming_mode = phy_vars_ue->transmission_mode[eNB_id]<7?0:phy_vars_ue->transmission_mode[eNB_id]; break; default: @@ -204,7 +207,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, phy_vars_ue->high_speed_flag, frame_parms); } - } else if (beamforming_mode==0) {// if n_tx>1 + } else if (beamforming_mode==0) { //else if nb_antennas_ports_eNB==1 && beamforming_mode == 0 nb_rb = dlsch_extract_rbs_single(lte_ue_common_vars->rxdataF, lte_ue_common_vars->dl_ch_estimates[eNB_id], lte_ue_pdsch_vars[eNB_id]->rxdataF_ext, @@ -243,7 +246,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, phy_vars_ue->high_speed_flag, frame_parms); } - } else if (beamforming_mode==7) { //else n_tx>1 + } else if (beamforming_mode==7) { //else if beamforming_mode == 7 nb_rb = dlsch_extract_rbs_TM7(lte_ue_common_vars->rxdataF, lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates, lte_ue_pdsch_vars[eNB_id]->rxdataF_ext, From b3fc3850d8764c529af57d3b95854bd2b976f588 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Thu, 23 Jun 2016 15:14:01 +0200 Subject: [PATCH 192/413] changing the way data is generated at eNB in --phy-test option --- openair1/SCHED/phy_mac_stub.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/openair1/SCHED/phy_mac_stub.c b/openair1/SCHED/phy_mac_stub.c index 5ed1b6837d..011d2cd954 100644 --- a/openair1/SCHED/phy_mac_stub.c +++ b/openair1/SCHED/phy_mac_stub.c @@ -233,10 +233,10 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(25,10,3); ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->TPC = 0; - ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; + ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->harq_pid = subframe%5; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; //((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); - ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; + ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = subframe/5; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rv = 0; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rah = 0; @@ -266,10 +266,10 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(25,10,3); ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->TPC = 0; ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->dai = 0; - ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; + ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->harq_pid = subframe%5; ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; //((DCI1_5MHz_TDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); - ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; + ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->ndi = subframe/5; ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->rv = 0; ((DCI1_5MHz_TDD_t *)&dlsch_pdu)->rah = 0; memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_5MHz_TDD_t)); @@ -304,10 +304,10 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(50,10,3); ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->TPC = 0; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; + ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->harq_pid = subframe%5; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; //((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; + ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = subframe/5; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rv = 0; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rah = 0; @@ -338,10 +338,10 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(50,10,3); ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->TPC = 0; ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->dai = 0; - ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; + ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->harq_pid = subframe%5; ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; //((DCI1_10MHz_TDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); - ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; + ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->ndi = subframe/5; ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->rv = 0; ((DCI1_10MHz_TDD_t *)&dlsch_pdu)->rah = 0; memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_10MHz_TDD_t)); @@ -375,10 +375,10 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(100,10,3); ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->TPC = 0; - ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; + ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->harq_pid = subframe%5; ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; //((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); - ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; + ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->ndi = subframe/5; ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->rv = 0; ((DCI1_20MHz_FDD_t *)&dlsch_pdu)->rah = 0; @@ -409,10 +409,10 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(100,10,3); ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->TPC = 0; ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->dai = 0; - ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; + ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->harq_pid = subframe%5; ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->mcs = openair_daq_vars.target_ue_dl_mcs; //((DCI1_20MHz_TDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((phy_vars_eNB->frame%1024)%28); - ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; + ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->ndi = subframe/5; ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->rv = 0; ((DCI1_20MHz_TDD_t *)&dlsch_pdu)->rah = 0; memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_20MHz_TDD_t)); @@ -451,13 +451,13 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->tpmi = 0; ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->rv1 = 0; - ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->ndi1 = phy_vars_eNB->proc[sched_subframe].frame_tx&1; + ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->ndi1 = subframe/5; ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->mcs1 = openair_daq_vars.target_ue_dl_mcs; ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->rv2 = 0; - ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->ndi2 = phy_vars_eNB->proc[sched_subframe].frame_tx&1; + ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->ndi2 = subframe/5; ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->mcs2 = openair_daq_vars.target_ue_dl_mcs; ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->tb_swap = 0; - ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; + ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->harq_pid = subframe%5; ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->TPC = 0; ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->rballoc = openair_daq_vars.ue_dl_rb_alloc; ((DCI2_5MHz_2A_FDD_t*) (&DCI_pdu->dci_alloc[0].dci_pdu))->rah = 0; @@ -473,13 +473,13 @@ void fill_dci(DCI_PDU *DCI_pdu, uint8_t sched_subframe, PHY_VARS_eNB *phy_vars_e DLSCH_alloc_pdu1E.tpmi = 5; //5=use feedback DLSCH_alloc_pdu1E.rv = 0; - DLSCH_alloc_pdu1E.ndi = phy_vars_eNB->proc[sched_subframe].frame_tx&1; + DLSCH_alloc_pdu1E.ndi = subframe/5; //DLSCH_alloc_pdu1E.mcs = cqi_to_mcs[phy_vars_eNB->eNB_UE_stats->DL_cqi[0]]; //DLSCH_alloc_pdu1E.mcs = (unsigned char) (taus()%28); DLSCH_alloc_pdu1E.mcs = openair_daq_vars.target_ue_dl_mcs; //DLSCH_alloc_pdu1E.mcs = (unsigned char) ((phy_vars_eNB->proc[subframe].frame%1024)%28); phy_vars_eNB->eNB_UE_stats[0].dlsch_mcs1 = DLSCH_alloc_pdu1E.mcs; - DLSCH_alloc_pdu1E.harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; + DLSCH_alloc_pdu1E.harq_pid = subframe%5; DLSCH_alloc_pdu1E.dai = 0; DLSCH_alloc_pdu1E.TPC = 0; DLSCH_alloc_pdu1E.rballoc = openair_daq_vars.ue_dl_rb_alloc; From 4fa0810cdd9c8ddddd1585021279d140459f0e9a Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 24 Jun 2016 12:20:38 +0200 Subject: [PATCH 193/413] add tm7 case into asn1 message --- openair2/RRC/LITE/MESSAGES/asn1_msg.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index 83fd5d357d..aa7dcba62f 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -1602,6 +1602,7 @@ do_RRCConnectionSetup( // AntennaInfoDedicated__transmissionMode_tm2); switch (transmission_mode) { + default: case 1: physicalConfigDedicated2->antennaInfo->choice.explicitValue.transmissionMode= AntennaInfoDedicated__transmissionMode_tm1; break; @@ -1634,6 +1635,10 @@ do_RRCConnectionSetup( case 6: physicalConfigDedicated2->antennaInfo->choice.explicitValue.transmissionMode= AntennaInfoDedicated__transmissionMode_tm6; break; + + case 7: + physicalConfigDedicated2->antennaInfo->choice.explicitValue.transmissionMode= AntennaInfoDedicated__transmissionMode_tm7; + break; } From 6a8a551ef33f8def8c37ab9f955e1e290cea0dd0 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 24 Jun 2016 12:32:57 +0200 Subject: [PATCH 194/413] add beamforming_mode into generate eNB and UE dlsch parameters from DCI --- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 23 +++++++++--- openair1/PHY/LTE_TRANSPORT/proto.h | 6 ++-- openair1/SCHED/phy_procedures_lte_eNb.c | 9 +++-- openair1/SCHED/phy_procedures_lte_ue.c | 16 +++++---- openair1/SIMULATION/LTE_PHY/dlsim.c | 48 +++++++++++++++---------- 5 files changed, 68 insertions(+), 34 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index f1bf0da14f..a01b31ee90 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -872,7 +872,8 @@ int generate_eNB_dlsch_params_from_dci(int frame, uint16_t si_rnti, uint16_t ra_rnti, uint16_t p_rnti, - uint16_t DL_pmi_single) + uint16_t DL_pmi_single, + uint8_t beamforming_mode) { uint8_t harq_pid = UINT8_MAX; @@ -1244,7 +1245,13 @@ int generate_eNB_dlsch_params_from_dci(int frame, dlsch0_harq->Nl = 1; // dlsch[0]->layer_index = 0; - dlsch0_harq->mimo_mode = (frame_parms->mode1_flag == 1) ? SISO : ALAMOUTI; + if (beamforming_mode == 0) + dlsch0_harq->mimo_mode = (frame_parms->mode1_flag == 1) ? SISO : ALAMOUTI; + else if (beamforming_mode == 7) + dlsch0_harq->mimo_mode = TM7; + else + LOG_E(PHY,"Invalid beamforming mode %dL\n", beamforming_mode); + dlsch0_harq->dl_power_off = 1; /* if (dlsch[0]->harq_processes[harq_pid]->first_tx == 1) { @@ -3854,7 +3861,8 @@ int generate_ue_dlsch_params_from_dci(int frame, PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated, uint16_t si_rnti, uint16_t ra_rnti, - uint16_t p_rnti) + uint16_t p_rnti, + uint8_t beamforming_mode) { uint8_t harq_pid=0; @@ -4171,6 +4179,7 @@ int generate_ue_dlsch_params_from_dci(int frame, dlsch0_harq->rvidx = rv; dlsch0_harq->Nl = 1; // dlsch[0]->layer_index = 0; + dlsch0_harq->mimo_mode = frame_parms->mode1_flag == 1 ?SISO : ALAMOUTI; dlsch0_harq->dl_power_off = 1; //no power offset @@ -4521,7 +4530,13 @@ int generate_ue_dlsch_params_from_dci(int frame, dlsch[0]->rnti = rnti; - dlsch0_harq->mimo_mode = (frame_parms->mode1_flag == 1) ? SISO : ALAMOUTI; + if (beamforming_mode == 0) + dlsch0_harq->mimo_mode = (frame_parms->mode1_flag == 1) ? SISO : ALAMOUTI; + else if (beamforming_mode == 7) + dlsch0_harq->mimo_mode = TM7; + else + LOG_E(PHY,"Not supported beamforming mode %d\n",beamforming_mode); + dlsch0 = dlsch[0]; diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 35de21c7b8..7535a26470 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -1424,7 +1424,8 @@ int generate_ue_dlsch_params_from_dci(int frame, PDSCH_CONFIG_DEDICATED *pdsch_config_dedicated, uint16_t si_rnti, uint16_t ra_rnti, - uint16_t p_rnti); + uint16_t p_rnti, + uint8_t beamforming_mode); int32_t generate_eNB_dlsch_params_from_dci(int frame, uint8_t subframe, @@ -1437,7 +1438,8 @@ int32_t generate_eNB_dlsch_params_from_dci(int frame, uint16_t si_rnti, uint16_t ra_rnti, uint16_t p_rnti, - uint16_t DL_pmi_single); + uint16_t DL_pmi_single, + uint8_t beamforming_mode); int32_t generate_eNB_ulsch_params_from_rar(uint8_t *rar_pdu, frame_t frame, diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index e03ffa2120..e9ee770545 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -1094,7 +1094,8 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e SI_RNTI, 0, P_RNTI, - phy_vars_eNB->eNB_UE_stats[0].DL_pmi_single); + phy_vars_eNB->eNB_UE_stats[0].DL_pmi_single, + 0); phy_vars_eNB->dlsch_eNB_SI->nCCE[subframe] = DCI_pdu->dci_alloc[i].firstCCE; @@ -1129,7 +1130,8 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e SI_RNTI, DCI_pdu->dci_alloc[i].rnti, P_RNTI, - phy_vars_eNB->eNB_UE_stats[0].DL_pmi_single); + phy_vars_eNB->eNB_UE_stats[0].DL_pmi_single, + 0); // mac_xface->macphy_exit("Transmitted RAR, exiting\n"); @@ -1187,7 +1189,8 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e SI_RNTI, 0, P_RNTI, - phy_vars_eNB->eNB_UE_stats[(uint8_t)UE_id].DL_pmi_single); + phy_vars_eNB->eNB_UE_stats[(uint8_t)UE_id].DL_pmi_single, + phy_vars_eNB->transmission_mode[(uint8_t)UE_id]>7?0:phy_vars_eNB->transmission_mode[(uint8_t)UE_id]); LOG_D(PHY,"[eNB %"PRIu8"][PDSCH %"PRIx16"/%"PRIu8"] Frame %d subframe %d: Generated dlsch params\n", phy_vars_eNB->Mod_id,DCI_pdu->dci_alloc[i].rnti,phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->current_harq_pid,phy_vars_eNB->proc[sched_subframe].frame_tx,subframe); diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 0ad6505149..d87a8479f5 100755 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -132,7 +132,7 @@ void dump_dlsch(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t subframe,uint8_t phy_vars_ue->lte_ue_pdcch_vars[eNB_id]->num_pdcch_symbols, phy_vars_ue->frame_rx, subframe, - phy_vars_ue->transmission_mode[eNB_id]); + phy_vars_ue->transmission_mode[eNB_id]); write_output("rxsigF0.m","rxsF0", phy_vars_ue->lte_ue_common_vars.rxdataF[0],2*nsymb*phy_vars_ue->lte_frame_parms.ofdm_symbol_size,2,1); write_output("rxsigF0_ext.m","rxsF0_ext", phy_vars_ue->lte_ue_pdsch_vars[0]->rxdataF_ext[0],2*nsymb*phy_vars_ue->lte_frame_parms.ofdm_symbol_size,1,1); @@ -2143,7 +2143,8 @@ int lte_ue_pdcch_procedures(uint8_t eNB_id,PHY_VARS_UE *phy_vars_ue,uint8_t abst phy_vars_ue->pdsch_config_dedicated, SI_RNTI, 0, - P_RNTI)==0)) { + P_RNTI, + phy_vars_ue->transmission_mode[eNB_id]>7?0:phy_vars_ue->transmission_mode[eNB_id])==0)) { #ifdef DIAG_PHY @@ -2211,7 +2212,8 @@ int lte_ue_pdcch_procedures(uint8_t eNB_id,PHY_VARS_UE *phy_vars_ue,uint8_t abst phy_vars_ue->pdsch_config_dedicated, SI_RNTI, 0, - P_RNTI)==0) { + P_RNTI, + 0)==0) { phy_vars_ue->dlsch_SI_received[eNB_id]++; @@ -2255,7 +2257,8 @@ int lte_ue_pdcch_procedures(uint8_t eNB_id,PHY_VARS_UE *phy_vars_ue,uint8_t abst phy_vars_ue->pdsch_config_dedicated, SI_RNTI, phy_vars_ue->prach_resources[eNB_id]->ra_RNTI, - P_RNTI)==0) { + P_RNTI, + 0)==0) { phy_vars_ue->dlsch_ra_received[eNB_id]++; @@ -2790,7 +2793,7 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac phy_vars_ue->lte_ue_pdcch_vars[eNB_id]->num_pdcch_symbols, frame_rx, subframe_prev, - phy_vars_ue->transmission_mode[eNB_id]); + 0); #ifdef DEBUG_PHY_PROC LOG_D(PHY,"Decoding DLSCH_SI : rb_alloc %x : nb_rb %d G %d TBS %d, num_pdcch_sym %d\n",phy_vars_ue->dlsch_ue_SI[eNB_id]->harq_processes[0]->rb_alloc_even[0], @@ -2853,8 +2856,7 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac phy_vars_ue->dlsch_ue_SI[eNB_id]->harq_processes[0]->rb_alloc_even[2], phy_vars_ue->dlsch_ue_SI[eNB_id]->harq_processes[0]->rb_alloc_even[3]); #endif - - // dump_dlsch_SI(phy_vars_ue,eNB_id,subframe_prev); + // dump_dlsch_SI(phy_vars_ue,eNB_id,subframe_prev); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_OUT); stop_meas(&phy_vars_ue->phy_proc_rx); return(-1); diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 19a0437bdf..6e78ad1a56 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -1149,10 +1149,11 @@ int main(int argc, char **argv) SI_RNTI, 0, P_RNTI, - PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single); + PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single, + transmission_mode<7?0:transmission_mode); - if (transmission_mode == 7) - PHY_vars_eNB->dlsch_eNB[0][0]->harq_processes[0]->mimo_mode = TM7; //Xiwen: to check about harq_pid + /*if (transmission_mode == 7) + PHY_vars_eNB->dlsch_eNB[0][0]->harq_processes[0]->mimo_mode = TM7; //Xiwen: to check about harq_pid*/ num_dci++; num_ue_spec_dci++; @@ -1292,7 +1293,8 @@ int main(int argc, char **argv) SI_RNTI, 0, P_RNTI, - PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single); + PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single, + 0); num_common_dci++; num_dci++; @@ -1459,7 +1461,8 @@ int main(int argc, char **argv) SI_RNTI, 0, P_RNTI, - PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single); + PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single, + 0); num_dci++; num_ue_spec_dci++; @@ -1599,7 +1602,8 @@ int main(int argc, char **argv) SI_RNTI, 0, P_RNTI, - PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single); + PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single, + 0); num_common_dci++; num_dci++; @@ -1767,7 +1771,8 @@ int main(int argc, char **argv) SI_RNTI, 0, P_RNTI, - PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single); + PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single, + 0); num_dci++; num_ue_spec_dci++; @@ -1907,7 +1912,8 @@ int main(int argc, char **argv) SI_RNTI, 0, P_RNTI, - PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single); + PHY_vars_eNB->eNB_UE_stats[0].DL_pmi_single, + 0); num_common_dci++; num_dci++; @@ -1936,7 +1942,8 @@ int main(int argc, char **argv) SI_RNTI, 0, P_RNTI, - PHY_vars_eNB->eNB_UE_stats[k].DL_pmi_single); + PHY_vars_eNB->eNB_UE_stats[k].DL_pmi_single, + 0); dump_dci(&PHY_vars_eNB->lte_frame_parms,&dci_alloc[num_dci]); num_ue_spec_dci++; @@ -3226,7 +3233,8 @@ PMI_FEEDBACK: PHY_vars_UE->pdsch_config_dedicated, SI_RNTI, 0, - P_RNTI)==0)) { + P_RNTI==0, + transmission_mode<7?0:transmission_mode))) { //dump_dci(&PHY_vars_UE->lte_frame_parms,&dci_alloc_rx[i]); coded_bits_per_codeword = get_G(&PHY_vars_eNB->lte_frame_parms, PHY_vars_UE->dlsch_ue[0][0]->harq_processes[PHY_vars_UE->dlsch_ue[0][0]->current_harq_pid]->nb_rb, @@ -3237,8 +3245,8 @@ PMI_FEEDBACK: 0, subframe, (transmission_mode<7?0:transmission_mode)); - if (transmission_mode==7 && common_flag==0) - PHY_vars_UE->dlsch_ue[0][0]->harq_processes[0]->mimo_mode = TM7; + /*if (transmission_mode==7 && common_flag==0) + PHY_vars_UE->dlsch_ue[0][0]->harq_processes[0]->mimo_mode = TM7; */ /* rate = (double)dlsch_tbs25[get_I_TBS(PHY_vars_UE->dlsch_ue[0][0]->harq_processes[PHY_vars_UE->dlsch_ue[0][0]->current_harq_pid]->mcs)][PHY_vars_UE->dlsch_ue[0][0]->nb_rb-1]/(coded_bits_per_codeword); @@ -3289,9 +3297,10 @@ PMI_FEEDBACK: PHY_vars_UE->pdsch_config_dedicated, SI_RNTI, 0, - P_RNTI); - if(transmission_mode==7 && common_flag==0) - PHY_vars_UE->dlsch_ue[0][0]->harq_processes[0]->mimo_mode = TM7; + P_RNTI, + transmission_mode<7?0:transmission_mode); + /*if(transmission_mode==7 && common_flag==0) + PHY_vars_UE->dlsch_ue[0][0]->harq_processes[0]->mimo_mode = TM7;*/ break; case 3: @@ -3306,7 +3315,8 @@ PMI_FEEDBACK: PHY_vars_UE->pdsch_config_dedicated, SI_RNTI, 0, - P_RNTI); + P_RNTI, + 0); // printf("Rate: TM3 (after) round %d (%d) first_tx %d\n",round,PHY_vars_UE->dlsch_ue[0][0]->harq_processes[0]->round,PHY_vars_UE->dlsch_ue[0][0]->harq_processes[0]->first_tx); break; @@ -3321,7 +3331,8 @@ PMI_FEEDBACK: PHY_vars_UE->pdsch_config_dedicated, SI_RNTI, 0, - P_RNTI); + P_RNTI, + 0); break; case 5: @@ -3336,7 +3347,8 @@ PMI_FEEDBACK: PHY_vars_UE->pdsch_config_dedicated, SI_RNTI, 0, - P_RNTI); + P_RNTI, + 0); break; } From 7d7cbc57f84fd19dd0e35f90880648a52c9ccd8f Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 24 Jun 2016 18:09:06 +0200 Subject: [PATCH 195/413] set transmission mode in phy_config_dedicated_[UE|eNB] after RRCConnectionReconfiguration(eNB) and RRCConnectionReconfigurationComplete(UE) --- openair1/PHY/INIT/lte_init.c | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index f5e9fdae10..c1f8c89b55 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -663,6 +663,39 @@ void phy_config_dedicated_eNB(uint8_t Mod_id, if (physicalConfigDedicated) { phy_vars_eNB->physicalConfigDedicated[UE_id] = physicalConfigDedicated; LOG_I(PHY,"phy_config_dedicated_eNB: physicalConfigDedicated=%p\n",physicalConfigDedicated); + + if (physicalConfigDedicated->antennaInfo) { + switch(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode) { + case AntennaInfoDedicated__transmissionMode_tm1: + phy_vars_eNB->transmission_mode[UE_id] = 1; + break; + case AntennaInfoDedicated__transmissionMode_tm2: + phy_vars_eNB->transmission_mode[UE_id] = 2; + break; + case AntennaInfoDedicated__transmissionMode_tm3: + phy_vars_eNB->transmission_mode[UE_id] = 3; + break; + case AntennaInfoDedicated__transmissionMode_tm4: + phy_vars_eNB->transmission_mode[UE_id] = 4; + break; + case AntennaInfoDedicated__transmissionMode_tm5: + phy_vars_eNB->transmission_mode[UE_id] = 5; + break; + case AntennaInfoDedicated__transmissionMode_tm6: + phy_vars_eNB->transmission_mode[UE_id] = 6; + break; + case AntennaInfoDedicated__transmissionMode_tm7: + phy_vars_eNB->transmission_mode[UE_id] = 7; + lte_gold_ue_spec_port5(phy_vars_eNB->lte_gold_uespec_port5_table[0],phy_vars_eNB->lte_frame_parms.Nid_cell,rnti); + break; + default: + LOG_E(PHY,"Unknown transmission mode!\n"); + break; + } + } else { + LOG_D(PHY,"[eNB %d] Frame %d: Received NULL radioResourceConfigDedicated->antennaInfo from eNB %d\n",Mod_id, phy_vars_eNB->proc[8].frame_tx,UE_id); + } + } else { LOG_E(PHY,"[eNB %d] Frame %d: Received NULL radioResourceConfigDedicated from eNB %d\n",Mod_id, phy_vars_eNB->proc[8].frame_tx,UE_id); return; @@ -825,6 +858,35 @@ void phy_config_dedicated_ue(uint8_t Mod_id,int CC_id,uint8_t CH_index, phy_vars_ue->transmission_mode[CH_index] = 1+(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode); LOG_D(PHY,"Transmission Mode %d\n",phy_vars_ue->transmission_mode[CH_index]); LOG_D(PHY,"\n"); + switch(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode) { + case AntennaInfoDedicated__transmissionMode_tm1: + phy_vars_ue->transmission_mode[CH_index] = 1; + break; + case AntennaInfoDedicated__transmissionMode_tm2: + phy_vars_ue->transmission_mode[CH_index] = 2; + break; + case AntennaInfoDedicated__transmissionMode_tm3: + phy_vars_ue->transmission_mode[CH_index] = 3; + break; + case AntennaInfoDedicated__transmissionMode_tm4: + phy_vars_ue->transmission_mode[CH_index] = 4; + break; + case AntennaInfoDedicated__transmissionMode_tm5: + phy_vars_ue->transmission_mode[CH_index] = 5; + break; + case AntennaInfoDedicated__transmissionMode_tm6: + phy_vars_ue->transmission_mode[CH_index] = 6; + break; + case AntennaInfoDedicated__transmissionMode_tm7: + phy_vars_ue->transmission_mode[CH_index] = 7; + lte_gold_ue_spec_port5(phy_vars_ue->lte_gold_uespec_port5_table, phy_vars_ue->lte_frame_parms.Nid_cell, phy_vars_ue->lte_ue_pdcch_vars[CH_index]->crnti); + break; + default: + LOG_E(PHY,"Unknown transmission mode!\n"); + break; + } + } else { + LOG_D(PHY,"[UE %d] Frame %d: Received NULL physicalConfigDedicated->antennaInfo from eNB %d\n",Mod_id, phy_vars_ue->frame_rx,CH_index); } if (physicalConfigDedicated->schedulingRequestConfig) { From 95808aec1062d66d124955407d36f79e6579f8ba Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 24 Jun 2016 18:11:21 +0200 Subject: [PATCH 196/413] add ue_TransmissionMode in RrcConfigurationReq --- openair2/RRC/LITE/rrc_eNB.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index c53df65046..6b591e0c35 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -99,7 +99,7 @@ #include "SIMULATION/TOOLS/defs.h" // for taus -//#define XER_PRINT +#define XER_PRINT #ifdef PHY_EMUL extern EMULATION_VARS *Emul_vars; @@ -3289,7 +3289,8 @@ rrc_eNB_generate_RRCConnectionSetup( do_RRCConnectionSetup(ctxt_pP, ue_context_pP, (uint8_t*) eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.Payload, - mac_xface->get_transmission_mode(ctxt_pP->module_id,CC_id,ue_context_pP->ue_id_rnti), + //mac_xface->get_transmission_mode(ctxt_pP->module_id,CC_id,ue_context_pP->ue_id_rnti), + (mac_xface->lte_frame_parms->nb_antenna_ports_eNB==2)?2:1, //at this point we do not have the UE capability information, so it can only be TM1 or TM2 rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id), mac_xface->lte_frame_parms, SRB_configList, From 224498cf3bfd631bd16bb7fd6217a7516a6ec888 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 24 Jun 2016 18:13:02 +0200 Subject: [PATCH 197/413] add ue_TransmissionMode in RrcConfigurationReq --- openair2/COMMON/rrc_messages_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 816b936895..ffe194265f 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -179,7 +179,7 @@ typedef struct RrcConfigurationReq_s { long ue_TimersAndConstants_t311[MAX_NUM_CCs]; long ue_TimersAndConstants_n310[MAX_NUM_CCs]; long ue_TimersAndConstants_n311[MAX_NUM_CCs]; - + long ue_TransmissionMode[MAX_NUM_CCs]; } RrcConfigurationReq; // UE: NAS -> RRC messages From 71c047d1aefbcea25f6a33b749da7573bc8db239 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 29 Jun 2016 12:32:19 +0300 Subject: [PATCH 198/413] Revert to single eNodeB for simulation --- openair2/RRC/LITE/rrc_eNB.c | 4619 +++++++++++++++++++++++++++++++++++ 1 file changed, 4619 insertions(+) create mode 100644 openair2/RRC/LITE/rrc_eNB.c diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c new file mode 100644 index 0000000000..804bc8aa21 --- /dev/null +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -0,0 +1,4619 @@ +/******************************************************************************* + 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ + +/*! \file rrc_eNB.c + * \brief rrc procedures for eNB + * \author Navid Nikaein and Raymond Knopp + * \date 2011 - 2014 + * \version 1.0 + * \company Eurecom + * \email: navid.nikaein@eurecom.fr and raymond.knopp@eurecom.fr + */ +#define RRC_ENB +#define RRC_ENB_C + +#include "defs.h" +#include "extern.h" +#include "assertions.h" +#include "asn1_conversions.h" +#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" +#include "LAYER2/RLC/rlc.h" +#include "LAYER2/MAC/proto.h" +#include "UTIL/LOG/log.h" +#include "COMMON/mac_rrc_primitives.h" +#include "RRC/LITE/MESSAGES/asn1_msg.h" +#include "RRCConnectionRequest.h" +#include "RRCConnectionReestablishmentRequest.h" +//#include "ReestablishmentCause.h" +#include "UL-CCCH-Message.h" +#include "DL-CCCH-Message.h" +#include "UL-DCCH-Message.h" +#include "DL-DCCH-Message.h" +#include "TDD-Config.h" +#include "HandoverCommand.h" +#include "rlc.h" +#include "SIMULATION/ETH_TRANSPORT/extern.h" +#include "rrc_eNB_UE_context.h" +#include "platform_types.h" +#include "msc.h" + +#include "T.h" + +//#ifdef Rel10 +#include "MeasResults.h" +//#endif + +#ifdef USER_MODE +# include "RRC/NAS/nas_config.h" +# include "RRC/NAS/rb_config.h" +# include "OCG.h" +# include "OCG_extern.h" +#endif + +#if defined(ENABLE_SECURITY) +# include "UTIL/OSA/osa_defs.h" +#endif + +#if defined(ENABLE_USE_MME) +# include "rrc_eNB_S1AP.h" +# include "rrc_eNB_GTPV1U.h" +# if defined(ENABLE_ITTI) +# else +# include "../../S1AP/s1ap_eNB.h" +# endif +#endif + +#include "pdcp.h" + +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +#endif + +#if ENABLE_RAL +# include "rrc_eNB_ral.h" +#endif + +#include "SIMULATION/TOOLS/defs.h" // for taus + +#include "enb_agent_extern.h" + +//#define XER_PRINT + +#ifdef PHY_EMUL +extern EMULATION_VARS *Emul_vars; +#endif +extern eNB_MAC_INST *eNB_mac_inst; +extern UE_MAC_INST *UE_mac_inst; +#ifdef BIGPHYSAREA +extern void* bigphys_malloc(int); +#endif + +extern uint16_t two_tier_hexagonal_cellIds[7]; + +/* TS 36.331: RRC-TransactionIdentifier ::= INTEGER (0..3) */ +static const uint8_t RRC_TRANSACTION_IDENTIFIER_NUMBER = 4; + +mui_t rrc_eNB_mui = 0; + +//----------------------------------------------------------------------------- +static void +init_SI( + const protocol_ctxt_t* const ctxt_pP, + const int CC_id +#if defined(ENABLE_ITTI) + , + RrcConfigurationReq * configuration +#endif +) +//----------------------------------------------------------------------------- +{ + uint8_t SIwindowsize = 1; + uint16_t SIperiod = 8; +#ifdef Rel10 + int i; +#endif + /* + uint32_t mib=0; + int i; + int N_RB_DL,phich_resource; + + do_MIB(enb_mod_idP, mac_xface->lte_frame_parms,0x321,&mib); + + for (i=0;i<1024;i+=4) + do_MIB(enb_mod_idP, mac_xface->lte_frame_parms,i,&mib); + + N_RB_DL=6; + while (N_RB_DL != 0) { + phich_resource = 1; + while (phich_resource != 0) { + for (i=0;i<2;i++) { + mac_xface->lte_frame_parms->N_RB_DL = N_RB_DL; + mac_xface->lte_frame_parms->phich_config_common.phich_duration=i; + mac_xface->lte_frame_parms->phich_config_common.phich_resource = phich_resource; + do_MIB(enb_mod_idP, mac_xface->lte_frame_parms,0,&mib); + } + if (phich_resource == 1) + phich_resource = 3; + else if (phich_resource == 3) + phich_resource = 6; + else if (phich_resource == 6) + phich_resource = 12; + else if (phich_resource == 12) + phich_resource = 0; + } + if (N_RB_DL == 6) + N_RB_DL = 15; + else if (N_RB_DL == 15) + N_RB_DL = 25; + else if (N_RB_DL == 25) + N_RB_DL = 50; + else if (N_RB_DL == 50) + N_RB_DL = 75; + else if (N_RB_DL == 75) + N_RB_DL = 100; + else if (N_RB_DL == 100) + N_RB_DL = 0; + } + exit(-1); + */ + + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sizeof_SIB1 = 0; + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sizeof_SIB23 = 0; + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].SIB1 = (uint8_t*) malloc16(32); + + /* + printf ("before SIB1 init : Nid_cell %d\n", mac_xface->lte_frame_parms->Nid_cell); + printf ("before SIB1 init : frame_type %d,tdd_config %d\n", + mac_xface->lte_frame_parms->frame_type, + mac_xface->lte_frame_parms->tdd_config); + */ + + if (eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].SIB1) + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sizeof_SIB1 = do_SIB1( + ctxt_pP->module_id, + CC_id, + mac_xface->lte_frame_parms, + (uint8_t*)eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].SIB1, + &eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].siblock1, + &eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib1 +#if defined(ENABLE_ITTI) + , configuration +#endif + ); + else { + LOG_E(RRC, PROTOCOL_RRC_CTXT_FMT" init_SI: FATAL, no memory for SIB1 allocated\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); + mac_xface->macphy_exit("[RRC][init_SI] FATAL, no memory for SIB1 allocated"); + } + + /* + printf ("after SIB1 init : Nid_cell %d\n", mac_xface->lte_frame_parms->Nid_cell); + printf ("after SIB1 init : frame_type %d,tdd_config %d\n", + mac_xface->lte_frame_parms->frame_type, + mac_xface->lte_frame_parms->tdd_config); + */ + if (eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sizeof_SIB1 == 255) { + mac_xface->macphy_exit("[RRC][init_SI] FATAL, eNB_rrc_inst[enb_mod_idP].carrier[CC_id].sizeof_SIB1 == 255"); + } + + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].SIB23 = (uint8_t*) malloc16(64); + + if (eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].SIB23) { + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sizeof_SIB23 = do_SIB23( + ctxt_pP->module_id, + CC_id, + mac_xface->lte_frame_parms, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].SIB23, + &eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].systemInformation, + &eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2, + &eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib3 +#ifdef Rel10 + , &eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib13, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].MBMS_flag +#endif +#if defined(ENABLE_ITTI) + , configuration +#endif + ); + + /* + eNB_rrc_inst[ctxt_pP->module_id].sizeof_SIB23 = do_SIB2_AT4(ctxt_pP->module_id, + eNB_rrc_inst[ctxt_pP->module_id].SIB23, + &eNB_rrc_inst[ctxt_pP->module_id].systemInformation, + &eNB_rrc_inst[ctxt_pP->module_id].sib2, + #if defined(ENABLE_ITTI) + , configuration + #endif + ); + */ + if (eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sizeof_SIB23 == 255) { + mac_xface->macphy_exit("[RRC][init_SI] FATAL, eNB_rrc_inst[mod].carrier[CC_id].sizeof_SIB23 == 255"); + } + + LOG_T(RRC, PROTOCOL_RRC_CTXT_FMT" SIB2/3 Contents (partial)\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); + LOG_T(RRC, PROTOCOL_RRC_CTXT_FMT" pusch_config_common.n_SB = %ld\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->radioResourceConfigCommon.pusch_ConfigCommon. + pusch_ConfigBasic.n_SB); + LOG_T(RRC, PROTOCOL_RRC_CTXT_FMT" pusch_config_common.hoppingMode = %ld\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->radioResourceConfigCommon.pusch_ConfigCommon. + pusch_ConfigBasic.hoppingMode); + LOG_T(RRC, PROTOCOL_RRC_CTXT_FMT" pusch_config_common.pusch_HoppingOffset = %ld\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->radioResourceConfigCommon.pusch_ConfigCommon. + pusch_ConfigBasic.pusch_HoppingOffset); + LOG_T(RRC, PROTOCOL_RRC_CTXT_FMT" pusch_config_common.enable64QAM = %d\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + (int)eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->radioResourceConfigCommon.pusch_ConfigCommon. + pusch_ConfigBasic.enable64QAM); + LOG_T(RRC, PROTOCOL_RRC_CTXT_FMT" pusch_config_common.groupHoppingEnabled = %d\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + (int)eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->radioResourceConfigCommon.pusch_ConfigCommon. + ul_ReferenceSignalsPUSCH.groupHoppingEnabled); + LOG_T(RRC, PROTOCOL_RRC_CTXT_FMT" pusch_config_common.groupAssignmentPUSCH = %ld\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->radioResourceConfigCommon.pusch_ConfigCommon. + ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH); + LOG_T(RRC, PROTOCOL_RRC_CTXT_FMT" pusch_config_common.sequenceHoppingEnabled = %d\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + (int)eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->radioResourceConfigCommon.pusch_ConfigCommon. + ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled); + LOG_T(RRC, PROTOCOL_RRC_CTXT_FMT" pusch_config_common.cyclicShift = %ld\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->radioResourceConfigCommon.pusch_ConfigCommon. + ul_ReferenceSignalsPUSCH.cyclicShift); + +#ifdef Rel10 + + if (eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].MBMS_flag > 0) { + for (i = 0; i < eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->mbsfn_SubframeConfigList->list.count; i++) { + // SIB 2 + // LOG_D(RRC, "[eNB %d] mbsfn_SubframeConfigList.list.count = %ld\n", enb_mod_idP, eNB_rrc_inst[enb_mod_idP].sib2->mbsfn_SubframeConfigList->list.count); + LOG_D(RRC, PROTOCOL_RRC_CTXT_FMT" SIB13 contents for MBSFN subframe allocation %d/%d(partial)\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + i, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->mbsfn_SubframeConfigList->list.count); + LOG_D(RRC, PROTOCOL_RRC_CTXT_FMT" mbsfn_Subframe_pattern is = %x\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->mbsfn_SubframeConfigList->list.array[i]->subframeAllocation.choice.oneFrame.buf[0] >> 0); + LOG_D(RRC, PROTOCOL_RRC_CTXT_FMT" radioframe_allocation_period = %ld (just index number, not the real value)\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->mbsfn_SubframeConfigList->list.array[i]->radioframeAllocationPeriod); // need to display the real value, using array of char (like in dumping SIB2) + LOG_D(RRC, PROTOCOL_RRC_CTXT_FMT" radioframe_allocation_offset = %ld\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->mbsfn_SubframeConfigList->list.array[i]->radioframeAllocationOffset); + } + + // SIB13 + for (i = 0; i < eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib13->mbsfn_AreaInfoList_r9.list.count; i++) { + LOG_D(RRC, PROTOCOL_RRC_CTXT_FMT" SIB13 contents for MBSFN sync area %d/2 (partial)\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + i, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib13->mbsfn_AreaInfoList_r9.list.count); + LOG_D(RRC, PROTOCOL_RRC_CTXT_FMT" MCCH Repetition Period: %d (just index number, not real value)\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib13->mbsfn_AreaInfoList_r9.list.array[i]->mcch_Config_r9.mcch_RepetitionPeriod_r9); + LOG_D(RRC, PROTOCOL_RRC_CTXT_FMT" MCCH Offset: %d\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib13->mbsfn_AreaInfoList_r9.list.array[i]->mcch_Config_r9.mcch_Offset_r9); + } + } + +#endif + + LOG_D(RRC, + PROTOCOL_RRC_CTXT_FMT" RRC_UE --- MAC_CONFIG_REQ (SIB1.tdd & SIB2 params) ---> MAC_UE\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); + rrc_mac_config_req(ctxt_pP->module_id, CC_id, ENB_FLAG_YES, 0, 0, + (RadioResourceConfigCommonSIB_t *) & + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->radioResourceConfigCommon, + (struct PhysicalConfigDedicated *)NULL, +#ifdef Rel10 + (SCellToAddMod_r10_t *)NULL, + //(struct PhysicalConfigDedicatedSCell_r10 *)NULL, +#endif + (MeasObjectToAddMod_t **) NULL, + (MAC_MainConfig_t *) NULL, 0, + (struct LogicalChannelConfig *)NULL, + (MeasGapConfig_t *) NULL, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib1->tdd_Config, + NULL, + &SIwindowsize, &SIperiod, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->freqInfo.ul_CarrierFreq, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->freqInfo.ul_Bandwidth, + &eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->freqInfo.additionalSpectrumEmission, + (MBSFN_SubframeConfigList_t*) eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib2->mbsfn_SubframeConfigList +#ifdef Rel10 + , + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].MBMS_flag, + (MBSFN_AreaInfoList_r9_t*) & eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].sib13->mbsfn_AreaInfoList_r9, + (PMCH_InfoList_r9_t *) NULL +#endif +#ifdef CBA + , 0, //eNB_rrc_inst[ctxt_pP->module_id].num_active_cba_groups, + 0 //eNB_rrc_inst[ctxt_pP->module_id].cba_rnti[0] +#endif + ); + } else { + LOG_E(RRC, PROTOCOL_RRC_CTXT_FMT" init_SI: FATAL, no memory for SIB2/3 allocated\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); + mac_xface->macphy_exit("[RRC][init_SI] FATAL, no memory for SIB2/3 allocated"); + } +} + +#ifdef Rel10 +/*------------------------------------------------------------------------------*/ +static void +init_MCCH( + module_id_t enb_mod_idP, + int CC_id +) +//----------------------------------------------------------------------------- +{ + + int sync_area = 0; + // initialize RRC_eNB_INST MCCH entry + eNB_rrc_inst[enb_mod_idP].carrier[CC_id].MCCH_MESSAGE = + malloc(eNB_rrc_inst[enb_mod_idP].carrier[CC_id].num_mbsfn_sync_area * sizeof(uint8_t*)); + + for (sync_area = 0; sync_area < eNB_rrc_inst[enb_mod_idP].carrier[CC_id].num_mbsfn_sync_area; sync_area++) { + + eNB_rrc_inst[enb_mod_idP].carrier[CC_id].sizeof_MCCH_MESSAGE[sync_area] = 0; + eNB_rrc_inst[enb_mod_idP].carrier[CC_id].MCCH_MESSAGE[sync_area] = (uint8_t *) malloc16(32); + + if (eNB_rrc_inst[enb_mod_idP].carrier[CC_id].MCCH_MESSAGE[sync_area] == NULL) { + LOG_E(RRC, "[eNB %d][MAIN] init_MCCH: FATAL, no memory for MCCH MESSAGE allocated \n", enb_mod_idP); + mac_xface->macphy_exit("[RRC][init_MCCH] not enough memory\n"); + } else { + eNB_rrc_inst[enb_mod_idP].carrier[CC_id].sizeof_MCCH_MESSAGE[sync_area] = do_MBSFNAreaConfig(enb_mod_idP, + mac_xface->lte_frame_parms, + sync_area, + (uint8_t *)eNB_rrc_inst[enb_mod_idP].carrier[CC_id].MCCH_MESSAGE[sync_area], + &eNB_rrc_inst[enb_mod_idP].carrier[CC_id].mcch, + &eNB_rrc_inst[enb_mod_idP].carrier[CC_id].mcch_message); + + LOG_I(RRC, "mcch message pointer %p for sync area %d \n", + eNB_rrc_inst[enb_mod_idP].carrier[CC_id].MCCH_MESSAGE[sync_area], + sync_area); + LOG_D(RRC, "[eNB %d] MCCH_MESSAGE contents for Sync Area %d (partial)\n", enb_mod_idP, sync_area); + LOG_D(RRC, "[eNB %d] CommonSF_AllocPeriod_r9 %d\n", enb_mod_idP, + eNB_rrc_inst[enb_mod_idP].carrier[CC_id].mcch_message->commonSF_AllocPeriod_r9); + LOG_D(RRC, + "[eNB %d] CommonSF_Alloc_r9.list.count (number of MBSFN Subframe Pattern) %d\n", + enb_mod_idP, eNB_rrc_inst[enb_mod_idP].carrier[CC_id].mcch_message->commonSF_Alloc_r9.list.count); + LOG_D(RRC, "[eNB %d] MBSFN Subframe Pattern: %02x (in hex)\n", + enb_mod_idP, + eNB_rrc_inst[enb_mod_idP].carrier[CC_id].mcch_message->commonSF_Alloc_r9.list.array[0]->subframeAllocation. + choice.oneFrame.buf[0]); + + if (eNB_rrc_inst[enb_mod_idP].carrier[CC_id].sizeof_MCCH_MESSAGE[sync_area] == 255) { + mac_xface->macphy_exit("[RRC][init_MCCH] eNB_rrc_inst[enb_mod_idP].carrier[CC_id].sizeof_MCCH_MESSAGE[sync_area] == 255"); + } else { + eNB_rrc_inst[enb_mod_idP].carrier[CC_id].MCCH_MESS[sync_area].Active = 1; + } + } + } + + //Set the eNB_rrc_inst[enb_mod_idP].MCCH_MESS.Active to 1 (allow to transfer MCCH message RRC->MAC in function mac_rrc_data_req) + + // ??Configure MCCH logical channel + // call mac_config_req with appropriate structure from ASN.1 description + + // LOG_I(RRC, "DUY: serviceID is %d\n",eNB_rrc_inst[enb_mod_idP].mcch_message->pmch_InfoList_r9.list.array[0]->mbms_SessionInfoList_r9.list.array[0]->tmgi_r9.serviceId_r9.buf[2]); + // LOG_I(RRC, "DUY: session ID is %d\n",eNB_rrc_inst[enb_mod_idP].mcch_message->pmch_InfoList_r9.list.array[0]->mbms_SessionInfoList_r9.list.array[0]->sessionId_r9->buf[0]); + rrc_mac_config_req(enb_mod_idP, CC_id, ENB_FLAG_YES, 0, 0, + (RadioResourceConfigCommonSIB_t *) NULL, + (struct PhysicalConfigDedicated *)NULL, +#ifdef Rel10 + (SCellToAddMod_r10_t *)NULL, + //(struct PhysicalConfigDedicatedSCell_r10 *)NULL, +#endif + (MeasObjectToAddMod_t **) NULL, + (MAC_MainConfig_t *) NULL, + 0, + (struct LogicalChannelConfig *)NULL, + (MeasGapConfig_t *) NULL, + (TDD_Config_t *) NULL, + NULL, (uint8_t *) NULL, (uint16_t *) NULL, NULL, NULL, NULL, (MBSFN_SubframeConfigList_t *) NULL +# ifdef Rel10 + , + 0, + (MBSFN_AreaInfoList_r9_t *) NULL, + (PMCH_InfoList_r9_t *) & (eNB_rrc_inst[enb_mod_idP].carrier[CC_id].mcch_message->pmch_InfoList_r9) +# endif +# ifdef CBA + , 0, 0 +# endif + ); + + //LOG_I(RRC,"DUY: lcid after rrc_mac_config_req is %02d\n",eNB_rrc_inst[enb_mod_idP].mcch_message->pmch_InfoList_r9.list.array[0]->mbms_SessionInfoList_r9.list.array[0]->logicalChannelIdentity_r9); + +} + +//----------------------------------------------------------------------------- +static void init_MBMS( + module_id_t enb_mod_idP, + int CC_id, + frame_t frameP +) +//----------------------------------------------------------------------------- +{ + // init the configuration for MTCH + protocol_ctxt_t ctxt; + + if (eNB_rrc_inst[enb_mod_idP].carrier[CC_id].MBMS_flag > 0) { + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, enb_mod_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, 0,enb_mod_idP); + + LOG_D(RRC, "[eNB %d] Frame %d : Radio Bearer config request for MBMS\n", enb_mod_idP, frameP); //check the lcid + // Configuring PDCP and RLC for MBMS Radio Bearer + + rrc_pdcp_config_asn1_req(&ctxt, + (SRB_ToAddModList_t *)NULL, // SRB_ToAddModList + (DRB_ToAddModList_t *)NULL, // DRB_ToAddModList + (DRB_ToReleaseList_t *)NULL, + 0, // security mode + NULL, // key rrc encryption + NULL, // key rrc integrity + NULL // key encryption +# ifdef Rel10 + , &(eNB_rrc_inst[enb_mod_idP].carrier[CC_id].mcch_message->pmch_InfoList_r9) +# endif + ); + + rrc_rlc_config_asn1_req(&ctxt, + NULL, // SRB_ToAddModList + NULL, // DRB_ToAddModList + NULL, // DRB_ToReleaseList + &(eNB_rrc_inst[enb_mod_idP].carrier[CC_id].mcch_message->pmch_InfoList_r9)); + + //rrc_mac_config_req(); + } +} +#endif + +//----------------------------------------------------------------------------- +uint8_t +rrc_eNB_get_next_transaction_identifier( + module_id_t enb_mod_idP +) +//----------------------------------------------------------------------------- +{ + static uint8_t rrc_transaction_identifier[NUMBER_OF_eNB_MAX]; + rrc_transaction_identifier[enb_mod_idP] = (rrc_transaction_identifier[enb_mod_idP] + 1) % RRC_TRANSACTION_IDENTIFIER_NUMBER; + return rrc_transaction_identifier[enb_mod_idP]; +} +/*------------------------------------------------------------------------------*/ +/* Functions to handle UE index in eNB UE list */ + + +////----------------------------------------------------------------------------- +//static module_id_t +//rrc_eNB_get_UE_index( +// module_id_t enb_mod_idP, +// uint64_t UE_identity +//) +////----------------------------------------------------------------------------- +//{ +// +// boolean_t reg = FALSE; +// module_id_t i; +// +// AssertFatal(enb_mod_idP < NB_eNB_INST, "eNB index invalid (%d/%d)!", enb_mod_idP, NB_eNB_INST); +// +// for (i = 0; i < NUMBER_OF_UE_MAX; i++) { +// if (eNB_rrc_inst[enb_mod_idP].Info.UE_list[i] == UE_identity) { +// // UE_identity already registered +// reg = TRUE; +// break; +// } +// } +// +// if (reg == FALSE) { +// return (UE_MODULE_INVALID); +// } else +// return (i); +//} + + +//----------------------------------------------------------------------------- +// return the ue context if there is already an UE with ue_identityP, NULL otherwise +static struct rrc_eNB_ue_context_s* +rrc_eNB_ue_context_random_exist( + const protocol_ctxt_t* const ctxt_pP, + const uint64_t ue_identityP +) +//----------------------------------------------------------------------------- +{ + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(eNB_rrc_inst[ctxt_pP->module_id].rrc_ue_head)) { + if (ue_context_p->ue_context.random_ue_identity == ue_identityP) + return ue_context_p; + } + return NULL; +} +//----------------------------------------------------------------------------- +// return the ue context if there is already an UE with the same S-TMSI(MMEC+M-TMSI), NULL otherwise +static struct rrc_eNB_ue_context_s* +rrc_eNB_ue_context_stmsi_exist( + const protocol_ctxt_t* const ctxt_pP, + const mme_code_t mme_codeP, + const m_tmsi_t m_tmsiP +) +//----------------------------------------------------------------------------- +{ + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(eNB_rrc_inst[ctxt_pP->module_id].rrc_ue_head)) { + LOG_I(RRC,"checking for UE S-TMSI %x, mme %x (%p): rnti %x", + m_tmsiP, mme_codeP, ue_context_p, + ue_context_p->ue_context.rnti); + if (ue_context_p->ue_context.Initialue_identity_s_TMSI.presence == TRUE) { + printf("S-TMSI %x, MME %x\n", + ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, + ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code); + if (ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi == m_tmsiP) + if (ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code == mme_codeP) + return ue_context_p; + } + else + printf("\n"); + + } + return NULL; +} + +//----------------------------------------------------------------------------- +// return a new ue context structure if ue_identityP, ctxt_pP->rnti not found in collection +static struct rrc_eNB_ue_context_s* +rrc_eNB_get_next_free_ue_context( + const protocol_ctxt_t* const ctxt_pP, + const uint64_t ue_identityP +) +//----------------------------------------------------------------------------- +{ + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + ue_context_p = rrc_eNB_get_ue_context( + &eNB_rrc_inst[ctxt_pP->module_id], + ctxt_pP->rnti); + + if (ue_context_p == NULL) { + RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(eNB_rrc_inst[ctxt_pP->module_id].rrc_ue_head)) { + if (ue_context_p->ue_context.random_ue_identity == ue_identityP) { + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" Cannot create new UE context, already exist rand UE id 0x%x, uid %u\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + ue_identityP, + ue_context_p->local_uid); + return NULL; + } + } + ue_context_p = rrc_eNB_allocate_new_UE_context(&eNB_rrc_inst[ctxt_pP->module_id]); + + if (ue_context_p == NULL) { + LOG_E(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" Cannot create new UE context, no memory\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + return NULL; + } + + ue_context_p->ue_id_rnti = ctxt_pP->rnti; // here ue_id_rnti is just a key, may be something else + ue_context_p->ue_context.rnti = ctxt_pP->rnti; // yes duplicate, 1 may be removed + ue_context_p->ue_context.random_ue_identity = ue_identityP; + RB_INSERT(rrc_ue_tree_s, &eNB_rrc_inst[ctxt_pP->module_id].rrc_ue_head, ue_context_p); + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" Created new UE context uid %u\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + ue_context_p->local_uid); + return ue_context_p; + + } else { + LOG_E(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" Cannot create new UE context, already exist\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + return NULL; + } +} + +#if !defined(ENABLE_USE_MME) +void rrc_eNB_emulation_notify_ue_module_id( + const module_id_t ue_module_idP, + const rnti_t rntiP, + const uint8_t cell_identity_byte0P, + const uint8_t cell_identity_byte1P, + const uint8_t cell_identity_byte2P, + const uint8_t cell_identity_byte3P) +{ + module_id_t enb_module_id; + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + int CC_id; + + // find enb_module_id + for (enb_module_id = 0; enb_module_id < NUMBER_OF_eNB_MAX; enb_module_id++) { + if(enb_module_id>0){ /*FIX LATER*/ + return; + } + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + if (eNB_rrc_inst[enb_module_id].carrier[CC_id].sib1 != NULL) { + if ( + (eNB_rrc_inst[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[0] == cell_identity_byte0P) && + (eNB_rrc_inst[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[1] == cell_identity_byte1P) && + (eNB_rrc_inst[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[2] == cell_identity_byte2P) && + (eNB_rrc_inst[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[3] == cell_identity_byte3P) + ) { + ue_context_p = rrc_eNB_get_ue_context( + &eNB_rrc_inst[enb_module_id], + rntiP + ); + + if (NULL != ue_context_p) { + oai_emulation.info.eNB_ue_local_uid_to_ue_module_id[enb_module_id][ue_context_p->local_uid] = ue_module_idP; + } + + //return; + } + } + } + oai_emulation.info.eNB_ue_module_id_to_rnti[enb_module_id][ue_module_idP] = rntiP; + } + + AssertFatal(enb_module_id == NUMBER_OF_eNB_MAX, + "Cell identity not found for ue module id %u rnti %x", + ue_module_idP, rntiP); +} +#endif + +//----------------------------------------------------------------------------- +void +rrc_eNB_free_mem_UE_context( + const protocol_ctxt_t* const ctxt_pP, + struct rrc_eNB_ue_context_s* const ue_context_pP +) +//----------------------------------------------------------------------------- +{ + int i; + LOG_T(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" Clearing UE context 0x%x (free internal structs)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + ue_context_pP); +#ifdef Rel10 + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SCellToAddMod_r10, &ue_context_pP->ue_context.sCell_config[0]); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SCellToAddMod_r10, &ue_context_pP->ue_context.sCell_config[1]); +#endif + + if (ue_context_pP->ue_context.SRB_configList) { + ASN_STRUCT_FREE(asn_DEF_SRB_ToAddModList, ue_context_pP->ue_context.SRB_configList); + ue_context_pP->ue_context.SRB_configList = NULL; + } + + if (ue_context_pP->ue_context.DRB_configList) { + ASN_STRUCT_FREE(asn_DEF_DRB_ToAddModList, ue_context_pP->ue_context.DRB_configList); + ue_context_pP->ue_context.DRB_configList = NULL; + } + + memset(ue_context_pP->ue_context.DRB_active, 0, sizeof(ue_context_pP->ue_context.DRB_active)); + + if (ue_context_pP->ue_context.physicalConfigDedicated) { + ASN_STRUCT_FREE(asn_DEF_PhysicalConfigDedicated, ue_context_pP->ue_context.physicalConfigDedicated); + ue_context_pP->ue_context.physicalConfigDedicated = NULL; + } + + if (ue_context_pP->ue_context.sps_Config) { + ASN_STRUCT_FREE(asn_DEF_SPS_Config, ue_context_pP->ue_context.sps_Config); + ue_context_pP->ue_context.sps_Config = NULL; + } + + for (i=0; i < MAX_MEAS_OBJ; i++) { + if (ue_context_pP->ue_context.MeasObj[i] != NULL) { + ASN_STRUCT_FREE(asn_DEF_MeasObjectToAddMod, ue_context_pP->ue_context.MeasObj[i]); + ue_context_pP->ue_context.MeasObj[i] = NULL; + } + } + + for (i=0; i < MAX_MEAS_CONFIG; i++) { + if (ue_context_pP->ue_context.ReportConfig[i] != NULL) { + ASN_STRUCT_FREE(asn_DEF_ReportConfigToAddMod, ue_context_pP->ue_context.ReportConfig[i]); + ue_context_pP->ue_context.ReportConfig[i] = NULL; + } + } + + if (ue_context_pP->ue_context.QuantityConfig) { + ASN_STRUCT_FREE(asn_DEF_QuantityConfig, ue_context_pP->ue_context.QuantityConfig); + ue_context_pP->ue_context.QuantityConfig = NULL; + } + + if (ue_context_pP->ue_context.mac_MainConfig) { + ASN_STRUCT_FREE(asn_DEF_MAC_MainConfig, ue_context_pP->ue_context.mac_MainConfig); + ue_context_pP->ue_context.mac_MainConfig = NULL; + } + + if (ue_context_pP->ue_context.measGapConfig) { + ASN_STRUCT_FREE(asn_DEF_MeasGapConfig, ue_context_pP->ue_context.measGapConfig); + ue_context_pP->ue_context.measGapConfig = NULL; + } + + //SRB_INFO SI; + //SRB_INFO Srb0; + //SRB_INFO_TABLE_ENTRY Srb1; + //SRB_INFO_TABLE_ENTRY Srb2; + if (ue_context_pP->ue_context.measConfig) { + ASN_STRUCT_FREE(asn_DEF_MeasConfig, ue_context_pP->ue_context.measConfig); + ue_context_pP->ue_context.measConfig = NULL; + } + + if (ue_context_pP->ue_context.measConfig) { + ASN_STRUCT_FREE(asn_DEF_MeasConfig, ue_context_pP->ue_context.measConfig); + ue_context_pP->ue_context.measConfig = NULL; + } + + //HANDOVER_INFO *handover_info; +#if defined(ENABLE_SECURITY) + //uint8_t kenb[32]; +#endif + //e_SecurityAlgorithmConfig__cipheringAlgorithm ciphering_algorithm; + //e_SecurityAlgorithmConfig__integrityProtAlgorithm integrity_algorithm; + //uint8_t Status; + //rnti_t rnti; + //uint64_t random_ue_identity; +#if defined(ENABLE_ITTI) + //UE_S_TMSI Initialue_identity_s_TMSI; + //EstablishmentCause_t establishment_cause; + //ReestablishmentCause_t reestablishment_cause; + //uint16_t ue_initial_id; + //uint32_t eNB_ue_s1ap_id :24; + //security_capabilities_t security_capabilities; + //uint8_t nb_of_e_rabs; + //e_rab_param_t e_rab[S1AP_MAX_E_RAB]; + //uint32_t enb_gtp_teid[S1AP_MAX_E_RAB]; + //transport_layer_addr_t enb_gtp_addrs[S1AP_MAX_E_RAB]; + //rb_id_t enb_gtp_ebi[S1AP_MAX_E_RAB]; +#endif +} + +//----------------------------------------------------------------------------- +// should be called when UE is lost by eNB +void +rrc_eNB_free_UE(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_s* const ue_context_pP) +//----------------------------------------------------------------------------- +{ + + + protocol_ctxt_t ctxt; +#if !defined(ENABLE_USE_MME) + module_id_t ue_module_id; + /* avoid gcc warnings */ + (void)ue_module_id; +#endif + rnti_t rnti = ue_context_pP->ue_context.rnti; + + + AssertFatal(enb_mod_idP < NB_eNB_INST, "eNB inst invalid (%d/%d) for UE %x!", enb_mod_idP, NB_eNB_INST, rnti); + /* ue_context_p = rrc_eNB_get_ue_context( + &eNB_rrc_inst[enb_mod_idP], + rntiP + ); + */ + if (NULL != ue_context_pP) { + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, enb_mod_idP, ENB_FLAG_YES, rnti, 0, 0,enb_mod_idP); + LOG_W(RRC, "[eNB %d] Removing UE RNTI %x\n", enb_mod_idP, rnti); + +#if defined(ENABLE_USE_MME) + rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ(enb_mod_idP, ue_context_pP, S1AP_CAUSE_RADIO_NETWORK, 21); // send cause 21: connection with ue lost + /* From 3GPP 36300v10 p129 : 19.2.2.2.2 S1 UE Context Release Request (eNB triggered) + * If the E-UTRAN internal reason is a radio link failure detected in the eNB, the eNB shall wait a sufficient time before + * triggering the S1 UE Context Release Request procedure + * in order to allow the UE to perform the NAS recovery + * procedure, see TS 23.401 [17]. + */ +#else +#if defined(OAI_EMU) + AssertFatal(ue_context_pP->local_uid < NUMBER_OF_UE_MAX, "local_uid invalid (%d<%d) for UE %x!", ue_context_pP->local_uid, NUMBER_OF_UE_MAX, rnti); + ue_module_id = oai_emulation.info.eNB_ue_local_uid_to_ue_module_id[enb_mod_idP][ue_context_pP->local_uid]; + AssertFatal(ue_module_id < NUMBER_OF_UE_MAX, "ue_module_id invalid (%d<%d) for UE %x!", ue_module_id, NUMBER_OF_UE_MAX, rnti); + oai_emulation.info.eNB_ue_local_uid_to_ue_module_id[enb_mod_idP][ue_context_pP->local_uid] = -1; + oai_emulation.info.eNB_ue_module_id_to_rnti[enb_mod_idP][ue_module_id] = NOT_A_RNTI; +#endif +#endif + + rrc_mac_remove_ue(enb_mod_idP,rnti); + rrc_rlc_remove_ue(&ctxt); + pdcp_remove_UE(&ctxt); + + rrc_eNB_remove_ue_context( + &ctxt, + &eNB_rrc_inst[enb_mod_idP], + (struct rrc_eNB_ue_context_s*) ue_context_pP); + } +} + +//----------------------------------------------------------------------------- +void +rrc_eNB_process_RRCConnectionSetupComplete( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + RRCConnectionSetupComplete_r8_IEs_t * rrcConnectionSetupComplete +) +//----------------------------------------------------------------------------- +{ + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel UL-DCCH, " "processing RRCConnectionSetupComplete from UE\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + + T(T_ENB_RRC_CONNECTION_SETUP_COMPLETE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + +#if defined(ENABLE_USE_MME) + + if (EPC_MODE_ENABLED == 1) { + // Forward message to S1AP layer + rrc_eNB_send_S1AP_NAS_FIRST_REQ( + ctxt_pP, + ue_context_pP, + rrcConnectionSetupComplete); + } else +#endif + { + // RRC loop back (no S1AP), send SecurityModeCommand to UE + rrc_eNB_generate_SecurityModeCommand( + ctxt_pP, + ue_context_pP); + // rrc_eNB_generate_UECapabilityEnquiry(enb_mod_idP,frameP,ue_mod_idP); + } +} + +//----------------------------------------------------------------------------- +void +rrc_eNB_generate_SecurityModeCommand( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP +) +//----------------------------------------------------------------------------- +{ + uint8_t buffer[100]; + uint8_t size; + + T(T_ENB_RRC_SECURITY_MODE_COMMAND, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + size = do_SecurityModeCommand( + ctxt_pP, + buffer, + rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id), + ue_context_pP->ue_context.ciphering_algorithm, + ue_context_pP->ue_context.integrity_algorithm); + +#ifdef RRC_MSG_PRINT + uint16_t i=0; + LOG_F(RRC,"[MSG] RRC Security Mode Command\n"); + + for (i = 0; i < size; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)buffer)[i]); + } + + LOG_F(RRC,"\n"); +#endif + + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" Logical Channel DL-DCCH, Generate SecurityModeCommand (bytes %d)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + size); + + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" --- PDCP_DATA_REQ/%d Bytes (securityModeCommand to UE MUI %d) --->[PDCP][RB %02d]\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + size, + rrc_eNB_mui, + DCCH); + + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + buffer, + size, + MSC_AS_TIME_FMT" securityModeCommand 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); + +} + +//----------------------------------------------------------------------------- +void +rrc_eNB_generate_UECapabilityEnquiry( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP +) +//----------------------------------------------------------------------------- +{ + + uint8_t buffer[100]; + uint8_t size; + + T(T_ENB_RRC_UE_CAPABILITY_ENQUIRY, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + size = do_UECapabilityEnquiry( + ctxt_pP, + buffer, + rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id)); + + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" Logical Channel DL-DCCH, Generate UECapabilityEnquiry (bytes %d)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + size); + + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" --- PDCP_DATA_REQ/%d Bytes (UECapabilityEnquiry MUI %d) --->[PDCP][RB %02d]\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + size, + rrc_eNB_mui, + DCCH); + + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + buffer, + size, + MSC_AS_TIME_FMT" rrcUECapabilityEnquiry 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); + +} + +//----------------------------------------------------------------------------- +void +rrc_eNB_generate_RRCConnectionReject( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + const int CC_id +) +//----------------------------------------------------------------------------- +{ +#ifdef RRC_MSG_PRINT + int cnt; +#endif + + T(T_ENB_RRC_CONNECTION_REJECT, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size = + do_RRCConnectionReject(ctxt_pP->module_id, + (uint8_t*) eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.Payload); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRCConnectionReject\n"); + + for (cnt = 0; cnt < eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size; cnt++) { + LOG_F(RRC,"%02x ", ((uint8_t*)eNB_rrc_inst[ctxt_pP->module_id].Srb0.Tx_buffer.Payload)[cnt]); + } + + LOG_F(RRC,"\n"); +#endif + + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.Header, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size, + MSC_AS_TIME_FMT" RRCConnectionReject UE %x size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_pP == NULL ? -1 : ue_context_pP->ue_context.rnti, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size); + + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel DL-CCCH, Generating RRCConnectionReject (bytes %d)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size); +} + +//----------------------------------------------------------------------------- +void +rrc_eNB_generate_RRCConnectionReestablishmentReject( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + const int CC_id +) +//----------------------------------------------------------------------------- +{ +#ifdef RRC_MSG_PRINT + int cnt; +#endif + + T(T_ENB_RRC_CONNECTION_REESTABLISHMENT_REJECT, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size = + do_RRCConnectionReestablishmentReject(ctxt_pP->module_id, + (uint8_t*) eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.Payload); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRCConnectionReestablishmentReject\n"); + + for (cnt = 0; cnt < eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size; cnt++) { + LOG_F(RRC,"%02x ", ((uint8_t*)eNB_rrc_inst[ctxt_pP->module_id].Srb0.Tx_buffer.Payload)[cnt]); + } + + LOG_F(RRC,"\n"); +#endif + + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.Header, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size, + MSC_AS_TIME_FMT" RRCConnectionReestablishmentReject UE %x size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_pP == NULL ? -1 : ue_context_pP->ue_context.rnti, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size); + + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel DL-CCCH, Generating RRCConnectionReestablishmentReject (bytes %d)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size); +} + +//----------------------------------------------------------------------------- +void +rrc_eNB_generate_RRCConnectionRelease( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP +) +//----------------------------------------------------------------------------- +{ + + uint8_t buffer[RRC_BUF_SIZE]; + uint16_t size; + + T(T_ENB_RRC_CONNECTION_RELEASE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + memset(buffer, 0, RRC_BUF_SIZE); + + size = do_RRCConnectionRelease(ctxt_pP->module_id, buffer,rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id)); + // set release timer + ue_context_pP->ue_context.ue_release_timer=1; + + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" Logical Channel DL-DCCH, Generate RRCConnectionRelease (bytes %d)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + size); + + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" --- PDCP_DATA_REQ/%d Bytes (rrcConnectionRelease MUI %d) --->[PDCP][RB %u]\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + size, + rrc_eNB_mui, + DCCH); + + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + buffer, + size, + MSC_AS_TIME_FMT" rrcConnectionRelease 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); +} + +//----------------------------------------------------------------------------- +void +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 +) +//----------------------------------------------------------------------------- +{ + 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; + + 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; +#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 + SRB2_config = CALLOC(1, sizeof(*SRB2_config)); + SRB_configList2 = CALLOC(1, sizeof(*SRB_configList2)); + memset(SRB_configList2, 0, sizeof(*SRB_configList2)); + + 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 = 1; + 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; + ASN_SEQUENCE_ADD(&SRB_configList->list, SRB2_config); + ASN_SEQUENCE_ADD(&SRB_configList2->list, SRB2_config); + + // Configure DRB + //*DRB_configList = CALLOC(1, sizeof(*DRB_configList)); + *DRB_configList = CALLOC(1, sizeof(**DRB_configList)); + /// 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 + // 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 = 2; // lower priority than srb1, srb2 + DRB_ul_SpecificParameters->prioritisedBitRate = + 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); + + 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 = MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf64; + mac_MainConfig->ul_SCH_Config->periodicBSR_Timer = periodicBSR_Timer; + mac_MainConfig->ul_SCH_Config->retxBSR_Timer = MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_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 + + // 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); + + MeasId1 = CALLOC(1, sizeof(*MeasId1)); + MeasId1->measId = 2; + MeasId1->measObjectId = 1; + MeasId1->reportConfigId = 2; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId1); + + MeasId2 = CALLOC(1, sizeof(*MeasId2)); + MeasId2->measId = 3; + MeasId2->measObjectId = 1; + MeasId2->reportConfigId = 3; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId2); + + MeasId3 = CALLOC(1, sizeof(*MeasId3)); + MeasId3->measId = 4; + MeasId3->measObjectId = 1; + MeasId3->reportConfigId = 4; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId3); + + MeasId4 = CALLOC(1, sizeof(*MeasId4)); + MeasId4->measId = 5; + MeasId4->measObjectId = 1; + MeasId4->reportConfigId = 5; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId4); + + MeasId5 = CALLOC(1, sizeof(*MeasId5)); + MeasId5->measId = 6; + MeasId5->measObjectId = 1; + MeasId5->reportConfigId = 6; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId5); + + // rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measIdToAddModList = MeasId_list; + + // 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 + ReportConfig_list = CALLOC(1, sizeof(*ReportConfig_list)); + + ReportConfig_per = CALLOC(1, sizeof(*ReportConfig_per)); + + ReportConfig_A1 = CALLOC(1, sizeof(*ReportConfig_A1)); + + ReportConfig_A2 = CALLOC(1, sizeof(*ReportConfig_A2)); + + ReportConfig_A3 = CALLOC(1, sizeof(*ReportConfig_A3)); + + ReportConfig_A4 = CALLOC(1, sizeof(*ReportConfig_A4)); + + ReportConfig_A5 = CALLOC(1, sizeof(*ReportConfig_A5)); + + 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.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 = ReportInterval_ms120; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_per); + + ReportConfig_A1->reportConfigId = 2; + ReportConfig_A1->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA1; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA1. + a1_Threshold.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA1. + a1_Threshold.choice.threshold_RSRP = 10; + + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerQuantity = ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + 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); + ReportConfig_A2->reportConfigId = 3; + ReportConfig_A2->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA2; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA2.a2_Threshold.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA2.a2_Threshold.choice.threshold_RSRP = 10; + + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerQuantity = + ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A2); + + ReportConfig_A3->reportConfigId = 4; + ReportConfig_A3->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA3; + + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA3.a3_Offset = 1; //10; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA3.reportOnLeave = 1; + + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerQuantity = + ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.hysteresis = 0.5; // FIXME ...hysteresis is of type long! + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.timeToTrigger = + TimeToTrigger_ms40; + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A3); + + ReportConfig_A4->reportConfigId = 5; + ReportConfig_A4->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA4; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA4.a4_Threshold.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA4.a4_Threshold.choice.threshold_RSRP = 10; + + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerQuantity = + ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A4); + + ReportConfig_A5->reportConfigId = 6; + ReportConfig_A5->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA5; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA5.a5_Threshold1.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA5.a5_Threshold2.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA5.a5_Threshold1.choice.threshold_RSRP = 10; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA5.a5_Threshold2.choice.threshold_RSRP = 10; + + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerQuantity = + ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A5); + // rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->reportConfigToAddModList = ReportConfig_list; + + rsrp = CALLOC(1, sizeof(RSRP_Range_t)); + *rsrp = 20; + + Sparams = CALLOC(1, sizeof(*Sparams)); + Sparams->present = MeasConfig__speedStatePars_PR_setup; + Sparams->choice.setup.timeToTrigger_SF.sf_High = SpeedStateScaleFactors__sf_Medium_oDot75; + Sparams->choice.setup.timeToTrigger_SF.sf_Medium = SpeedStateScaleFactors__sf_High_oDot5; + Sparams->choice.setup.mobilityStateParameters.n_CellChangeHigh = 10; + Sparams->choice.setup.mobilityStateParameters.n_CellChangeMedium = 5; + Sparams->choice.setup.mobilityStateParameters.t_Evaluation = MobilityStateParameters__t_Evaluation_s60; + Sparams->choice.setup.mobilityStateParameters.t_HystNormal = MobilityStateParameters__t_HystNormal_s120; + + 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; + + LOG_I(RRC, + "[eNB %d] Frame %d: potential handover preparation: store the information in an intermediate structure in case of failure\n", + ctxt_pP->module_id, ctxt_pP->frame); + // store the information in an intermediate structure for Hanodver management + //rrc_inst->handover_info.as_config.sourceRadioResourceConfig.srb_ToAddModList = CALLOC(1,sizeof()); + ue_context_pP->ue_context.handover_info = CALLOC(1, sizeof(*(ue_context_pP->ue_context.handover_info))); + //memcpy((void *)rrc_inst->handover_info[ue_mod_idP]->as_config.sourceRadioResourceConfig.srb_ToAddModList,(void *)SRB_list,sizeof(SRB_ToAddModList_t)); + ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.srb_ToAddModList = SRB_configList2; + //memcpy((void *)rrc_inst->handover_info[ue_mod_idP]->as_config.sourceRadioResourceConfig.drb_ToAddModList,(void *)DRB_list,sizeof(DRB_ToAddModList_t)); + ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.drb_ToAddModList = *DRB_configList; + ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.drb_ToReleaseList = NULL; + ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.mac_MainConfig = + CALLOC(1, sizeof(*ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.mac_MainConfig)); + memcpy((void*)ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.mac_MainConfig, + (void *)mac_MainConfig, sizeof(MAC_MainConfig_t)); + ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.physicalConfigDedicated = + CALLOC(1, sizeof(PhysicalConfigDedicated_t)); + memcpy((void*)ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.physicalConfigDedicated, + (void*)ue_context_pP->ue_context.physicalConfigDedicated, sizeof(PhysicalConfigDedicated_t)); + ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.sps_Config = NULL; + //memcpy((void *)rrc_inst->handover_info[ue_mod_idP]->as_config.sourceRadioResourceConfig.sps_Config,(void *)rrc_inst->sps_Config[ue_mod_idP],sizeof(SPS_Config_t)); + + } + +#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; + } + + /* 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, + rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id), //Transaction_id, + (SRB_ToAddModList_t*)NULL, /// NN: do not reconfig srb1: SRB_configList2, + (DRB_ToAddModList_t*)*DRB_configList, + (DRB_ToReleaseList_t*)NULL, // DRB2_list, + (struct SPS_Config*)NULL, // *sps_Config, +#ifdef EXMIMO_IOT + NULL, NULL, NULL, NULL,NULL, +#else + (struct PhysicalConfigDedicated*)*physicalConfigDedicated, + (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 +#ifdef Rel10 + , (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); +} + + + +//----------------------------------------------------------------------------- +int +rrc_eNB_generate_RRCConnectionReconfiguration_SCell( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + uint32_t dl_CarrierFreq_r10 +) +//----------------------------------------------------------------------------- +{ + + uint8_t size; + uint8_t buffer[100]; + +#ifdef Rel10 + uint8_t sCellIndexToAdd = 0; //one SCell so far + + // uint8_t sCellIndexToAdd; + // sCellIndexToAdd = rrc_find_free_SCell_index(enb_mod_idP, ue_mod_idP, 1); + // if (eNB_rrc_inst[enb_mod_idP].sCell_config[ue_mod_idP][sCellIndexToAdd] ) { + if (ue_context_pP->ue_context.sCell_config != NULL) { + ue_context_pP->ue_context.sCell_config[sCellIndexToAdd].cellIdentification_r10->dl_CarrierFreq_r10 = dl_CarrierFreq_r10; + } else { + LOG_E(RRC,"Scell not configured!\n"); + return(-1); + } + +#endif + size = do_RRCConnectionReconfiguration(ctxt_pP, + buffer, + rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id),//Transaction_id, + (SRB_ToAddModList_t*)NULL, + (DRB_ToAddModList_t*)NULL, + (DRB_ToReleaseList_t*)NULL, + (struct SPS_Config*)NULL, + (struct PhysicalConfigDedicated*)NULL, + (MeasObjectToAddModList_t*)NULL, + (ReportConfigToAddModList_t*)NULL, + (QuantityConfig_t*)NULL, + (MeasIdToAddModList_t*)NULL, + (MAC_MainConfig_t*)NULL, + (MeasGapConfig_t*)NULL, + (MobilityControlInfo_t*)NULL, + (struct MeasConfig__speedStatePars*)NULL, + (RSRP_Range_t*)NULL, + (C_RNTI_t*)NULL, + (struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList*)NULL + +#ifdef Rel10 + , ue_context_pP->ue_context.sCell_config +#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); + + 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); + return(0); +} + + +//----------------------------------------------------------------------------- +void +rrc_eNB_process_MeasurementReport( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + const MeasResults_t* const measResults2 +) +//----------------------------------------------------------------------------- +{ + 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); + + 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)); + } + +#ifdef Rel10 + LOG_I(RRC, "RSRP of Source %d\n", measResults2->measResultPCell.rsrpResult); + LOG_I(RRC, "RSRQ of Source %d\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 + + 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 + //Wait for Handover Acknowledgement <- target eNB + //Send Handover Command + + //x2delay(); + // handover_request_x2(ue_mod_idP,enb_mod_idP,measResults2->measResultNeighCells->choice.measResultListEUTRA.list.array[0]->physCellId); + + // uint8_t buffer[100]; + // int size=rrc_eNB_generate_Handover_Command_TeNB(0,0,buffer); + // + // send_check_message((char*)buffer,size); + //send_handover_command(); + +} + +//----------------------------------------------------------------------------- +void +rrc_eNB_generate_HandoverPreparationInformation( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + PhysCellId_t targetPhyId +) +//----------------------------------------------------------------------------- +{ + struct rrc_eNB_ue_context_s* ue_context_target_p = NULL; + //uint8_t UE_id_target = -1; + uint8_t mod_id_target = get_adjacent_cell_mod_id(targetPhyId); + HANDOVER_INFO *handoverInfo = CALLOC(1, sizeof(*handoverInfo)); + /* + uint8_t buffer[100]; + uint8_t size; + struct PhysicalConfigDedicated **physicalConfigDedicated = &eNB_rrc_inst[enb_mod_idP].physicalConfigDedicated[ue_mod_idP]; + RadioResourceConfigDedicated_t *radioResourceConfigDedicated = CALLOC(1,sizeof(RadioResourceConfigDedicated_t)); + */ + + T(T_ENB_RRC_HANDOVER_PREPARATION_INFORMATION, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + handoverInfo->as_config.antennaInfoCommon.antennaPortsCount = 0; //Not used 0- but check value + handoverInfo->as_config.sourceDl_CarrierFreq = 36090; //Verify! + + memcpy((void *)&handoverInfo->as_config.sourceMasterInformationBlock, + (void*)&eNB_rrc_inst[ctxt_pP->module_id].carrier[0] /* CROUX TBC */.mib, sizeof(MasterInformationBlock_t)); + memcpy((void *)&handoverInfo->as_config.sourceMeasConfig, + (void*)ue_context_pP->ue_context.measConfig, sizeof(MeasConfig_t)); + + // FIXME handoverInfo not used... + free( handoverInfo ); + handoverInfo = 0; + + //to be configured + memset((void*)&ue_context_pP->ue_context.handover_info->as_config.sourceSecurityAlgorithmConfig, + 0, sizeof(SecurityAlgorithmConfig_t)); + + memcpy((void*)&ue_context_pP->ue_context.handover_info->as_config.sourceSystemInformationBlockType1, + (void*)&eNB_rrc_inst[ctxt_pP->module_id].carrier[0] /* CROUX TBC */.SIB1, sizeof(SystemInformationBlockType1_t)); + memcpy((void*)&ue_context_pP->ue_context.handover_info->as_config.sourceSystemInformationBlockType2, + (void*)&eNB_rrc_inst[ctxt_pP->module_id].carrier[0] /* CROUX TBC */.SIB23, sizeof(SystemInformationBlockType2_t)); + ue_context_pP->ue_context.handover_info->as_context.reestablishmentInfo = + CALLOC(1, sizeof(ReestablishmentInfo_t)); + ue_context_pP->ue_context.handover_info->as_context.reestablishmentInfo->sourcePhysCellId = + eNB_rrc_inst[ctxt_pP->module_id].carrier[0] /* CROUX TBC */.physCellId; + ue_context_pP->ue_context.handover_info->as_context.reestablishmentInfo->targetCellShortMAC_I.buf = NULL; // Check values later + ue_context_pP->ue_context.handover_info->as_context.reestablishmentInfo->targetCellShortMAC_I.size = 0; + ue_context_pP->ue_context.handover_info->as_context.reestablishmentInfo->targetCellShortMAC_I.bits_unused = 0; + ue_context_pP->ue_context.handover_info->as_context.reestablishmentInfo->additionalReestabInfoList = NULL; + ue_context_pP->ue_context.handover_info->ho_prepare = 0xFF; //0xF0; + ue_context_pP->ue_context.handover_info->ho_complete = 0; + + if (mod_id_target != 0xFF) { + //UE_id_target = rrc_find_free_ue_index(modid_target); + ue_context_target_p = + rrc_eNB_get_ue_context( + &eNB_rrc_inst[mod_id_target], + ue_context_pP->ue_context.rnti); + + /*UE_id_target = rrc_eNB_get_next_free_UE_index( + mod_id_target, + eNB_rrc_inst[ctxt_pP->module_id].Info.UE_list[ue_mod_idP]); //this should return a new index*/ + + if (ue_context_target_p == NULL) { // if not already in target cell + ue_context_target_p = rrc_eNB_allocate_new_UE_context(&eNB_rrc_inst[ctxt_pP->module_id]); + ue_context_target_p->ue_id_rnti = ue_context_pP->ue_context.rnti; // LG: should not be the same + ue_context_target_p->ue_context.rnti = ue_context_target_p->ue_id_rnti; // idem + LOG_N(RRC, + "[eNB %d] Frame %d : Emulate sending HandoverPreparationInformation msg from eNB source %d to eNB target %d: source UE_id %x target UE_id %x source_modId: %d target_modId: %d\n", + ctxt_pP->module_id, + ctxt_pP->frame, + eNB_rrc_inst[ctxt_pP->module_id].carrier[0] /* CROUX TBC */.physCellId, + targetPhyId, + ue_context_pP->ue_context.rnti, + ue_context_target_p->ue_id_rnti, + ctxt_pP->module_id, + mod_id_target); + ue_context_target_p->ue_context.handover_info = + CALLOC(1, sizeof(*(ue_context_target_p->ue_context.handover_info))); + memcpy((void*)&ue_context_target_p->ue_context.handover_info->as_context, + (void*)&ue_context_pP->ue_context.handover_info->as_context, + sizeof(AS_Context_t)); + memcpy((void*)&ue_context_target_p->ue_context.handover_info->as_config, + (void*)&ue_context_pP->ue_context.handover_info->as_config, + sizeof(AS_Config_t)); + ue_context_target_p->ue_context.handover_info->ho_prepare = 0x00;// 0xFF; + ue_context_target_p->ue_context.handover_info->ho_complete = 0; + ue_context_pP->ue_context.handover_info->modid_t = mod_id_target; + ue_context_pP->ue_context.handover_info->ueid_s = ue_context_pP->ue_context.rnti; + ue_context_pP->ue_context.handover_info->modid_s = ctxt_pP->module_id; + ue_context_target_p->ue_context.handover_info->modid_t = mod_id_target; + ue_context_target_p->ue_context.handover_info->modid_s = ctxt_pP->module_id; + ue_context_target_p->ue_context.handover_info->ueid_t = ue_context_target_p->ue_context.rnti; + + } else { + LOG_E(RRC, "\nError in obtaining free UE id in target eNB %l for handover \n", targetPhyId); + } + + } else { + LOG_E(RRC, "\nError in obtaining Module ID of target eNB for handover \n"); + } +} + +//----------------------------------------------------------------------------- +void +rrc_eNB_process_handoverPreparationInformation( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP +) +//----------------------------------------------------------------------------- +{ + T(T_ENB_RRC_HANDOVER_PREPARATION_INFORMATION, 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 : Logical Channel UL-DCCH, processing RRCHandoverPreparationInformation, sending RRCConnectionReconfiguration to UE %d \n", + ctxt_pP->module_id, ctxt_pP->frame, ue_context_pP->ue_context.rnti); + rrc_eNB_generate_RRCConnectionReconfiguration_handover( + ctxt_pP, + ue_context_pP, + NULL, + 0); +} + + +//----------------------------------------------------------------------------- +void +check_handovers( + protocol_ctxt_t* const ctxt_pP +) +//----------------------------------------------------------------------------- +{ + int result; + struct rrc_eNB_ue_context_s* ue_context_p; + RB_FOREACH(ue_context_p, rrc_ue_tree_s, &eNB_rrc_inst[ctxt_pP->module_id].rrc_ue_head) { + ctxt_pP->rnti = ue_context_p->ue_id_rnti; + + if (ue_context_p->ue_context.handover_info != NULL) { + if (ue_context_p->ue_context.handover_info->ho_prepare == 0xFF) { + LOG_D(RRC, + "[eNB %d] Frame %d: Incoming handover detected for new UE_idx %d (source eNB %d->target eNB %d) \n", + ctxt_pP->module_id, + ctxt_pP->frame, + ctxt_pP->rnti, + ctxt_pP->module_id, + ue_context_p->ue_context.handover_info->modid_t); + // source eNB generates rrcconnectionreconfiguration to prepare the HO + rrc_eNB_process_handoverPreparationInformation( + ctxt_pP, + ue_context_p); + ue_context_p->ue_context.handover_info->ho_prepare = 0xF1; + } + + if (ue_context_p->ue_context.handover_info->ho_complete == 0xF1) { + LOG_D(RRC, + "[eNB %d] Frame %d: handover Command received for new UE_id %x current eNB %d target eNB: %d \n", + ctxt_pP->module_id, + ctxt_pP->frame, + ctxt_pP->rnti, + ctxt_pP->module_id, + ue_context_p->ue_context.handover_info->modid_t); + //rrc_eNB_process_handoverPreparationInformation(enb_mod_idP,frameP,i); + result = pdcp_data_req(ctxt_pP, + SRB_FLAG_YES, + DCCH, + rrc_eNB_mui++, + SDU_CONFIRM_NO, + ue_context_p->ue_context.handover_info->size, + ue_context_p->ue_context.handover_info->buf, + PDCP_TRANSMISSION_MODE_CONTROL); + AssertFatal(result == TRUE, "PDCP data request failed!\n"); + ue_context_p->ue_context.handover_info->ho_complete = 0xF2; + } + } + } +} + +// 5.3.5.4 RRCConnectionReconfiguration including the mobilityControlInfo to prepare the UE handover +//----------------------------------------------------------------------------- +void +rrc_eNB_generate_RRCConnectionReconfiguration_handover( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + uint8_t* const nas_pdu, + const uint32_t nas_length +) +//----------------------------------------------------------------------------- +{ + 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)); + + + uint8_t buffer[RRC_BUF_SIZE]; + uint16_t size; + int i; + uint8_t rv[2]; + uint16_t Idx; + // 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; + struct SRB_ToAddMod__rlc_Config *SRB2_rlc_config; + struct SRB_ToAddMod__logicalChannelConfig *SRB2_lchan_config; + struct LogicalChannelConfig__ul_SpecificParameters *SRB2_ul_SpecificParameters; + LogicalChannelConfig_t *SRB1_logicalChannelConfig = NULL; + SRB_ToAddModList_t* SRB_configList = ue_context_pP->ue_context.SRB_configList; // not used in this context: may be removed + SRB_ToAddModList_t *SRB_configList2; + + struct DRB_ToAddMod *DRB_config; + struct RLC_Config *DRB_rlc_config; + struct PDCP_Config *DRB_pdcp_config; + struct PDCP_Config__rlc_UM *PDCP_rlc_UM; + struct LogicalChannelConfig *DRB_lchan_config; + struct LogicalChannelConfig__ul_SpecificParameters *DRB_ul_SpecificParameters; + DRB_ToAddModList_t *DRB_configList2; + + MAC_MainConfig_t *mac_MainConfig; + MeasObjectToAddModList_t *MeasObj_list; + MeasObjectToAddMod_t *MeasObj; + ReportConfigToAddModList_t *ReportConfig_list; + ReportConfigToAddMod_t *ReportConfig_per, *ReportConfig_A1, + *ReportConfig_A2, *ReportConfig_A3, *ReportConfig_A4, *ReportConfig_A5; + MeasIdToAddModList_t *MeasId_list; + MeasIdToAddMod_t *MeasId0, *MeasId1, *MeasId2, *MeasId3, *MeasId4, *MeasId5; + QuantityConfig_t *quantityConfig; + MobilityControlInfo_t *mobilityInfo; + // HandoverCommand_t handoverCommand; + //uint8_t sourceModId = + // get_adjacent_cell_mod_id(ue_context_pP->ue_context.handover_info->as_context.reestablishmentInfo->sourcePhysCellId); +#if Rel10 + long *sr_ProhibitTimer_r9; +#endif + + long *logicalchannelgroup, *logicalchannelgroup_drb; + long *maxHARQ_Tx, *periodicBSR_Timer; + + // RSRP_Range_t *rsrp; + struct MeasConfig__speedStatePars *Sparams; + CellsToAddMod_t *CellToAdd; + CellsToAddModList_t *CellsToAddModList; + // srb 1: for HO + struct SRB_ToAddMod *SRB1_config; + struct SRB_ToAddMod__rlc_Config *SRB1_rlc_config; + struct SRB_ToAddMod__logicalChannelConfig *SRB1_lchan_config; + struct LogicalChannelConfig__ul_SpecificParameters *SRB1_ul_SpecificParameters; + // phy config dedicated + PhysicalConfigDedicated_t *physicalConfigDedicated2; + struct RRCConnectionReconfiguration_r8_IEs__dedicatedInfoNASList *dedicatedInfoNASList; + protocol_ctxt_t ctxt; + + LOG_D(RRC, "[eNB %d] Frame %d: handover preparation: get the newSourceUEIdentity (C-RNTI): ", + ctxt_pP->module_id, ctxt_pP->frame); + + for (i = 0; i < 2; i++) { + rv[i] = taus() & 0xff; + LOG_D(RRC, " %x.", rv[i]); + } + + LOG_D(RRC, "[eNB %d] Frame %d : handover reparation: add target eNB SRB1 and PHYConfigDedicated reconfiguration\n", + ctxt_pP->module_id, ctxt_pP->frame); + // 1st: reconfigure SRB + SRB_configList2 = CALLOC(1, sizeof(*SRB_configList)); + SRB1_config = CALLOC(1, sizeof(*SRB1_config)); + SRB1_config->srb_Identity = 1; + SRB1_rlc_config = CALLOC(1, sizeof(*SRB1_rlc_config)); + SRB1_config->rlc_Config = SRB1_rlc_config; + + SRB1_rlc_config->present = SRB_ToAddMod__rlc_Config_PR_explicitValue; + SRB1_rlc_config->choice.explicitValue.present = RLC_Config_PR_am; + SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.t_PollRetransmit = T_PollRetransmit_ms15; + SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollPDU = PollPDU_p8; + SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.pollByte = PollByte_kB1000; + SRB1_rlc_config->choice.explicitValue.choice.am.ul_AM_RLC.maxRetxThreshold = UL_AM_RLC__maxRetxThreshold_t16; + SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_Reordering = T_Reordering_ms35; + SRB1_rlc_config->choice.explicitValue.choice.am.dl_AM_RLC.t_StatusProhibit = T_StatusProhibit_ms10; + + SRB1_lchan_config = CALLOC(1, sizeof(*SRB1_lchan_config)); + SRB1_config->logicalChannelConfig = SRB1_lchan_config; + + SRB1_lchan_config->present = SRB_ToAddMod__logicalChannelConfig_PR_explicitValue; + SRB1_ul_SpecificParameters = CALLOC(1, sizeof(*SRB1_ul_SpecificParameters)); + + SRB1_lchan_config->choice.explicitValue.ul_SpecificParameters = SRB1_ul_SpecificParameters; + + SRB1_ul_SpecificParameters->priority = 1; + + //assign_enum(&SRB1_ul_SpecificParameters->prioritisedBitRate,LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity); + SRB1_ul_SpecificParameters->prioritisedBitRate = + LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity; + + //assign_enum(&SRB1_ul_SpecificParameters->bucketSizeDuration,LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50); + SRB1_ul_SpecificParameters->bucketSizeDuration = + LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50; + + logicalchannelgroup = CALLOC(1, sizeof(long)); + *logicalchannelgroup = 0; + SRB1_ul_SpecificParameters->logicalChannelGroup = logicalchannelgroup; + + ASN_SEQUENCE_ADD(&SRB_configList2->list, SRB1_config); + + //2nd: now reconfigure phy config dedicated + physicalConfigDedicated2 = CALLOC(1, sizeof(*physicalConfigDedicated2)); + *physicalConfigDedicated = physicalConfigDedicated2; + + physicalConfigDedicated2->pdsch_ConfigDedicated = + CALLOC(1, sizeof(*physicalConfigDedicated2->pdsch_ConfigDedicated)); + physicalConfigDedicated2->pucch_ConfigDedicated = + CALLOC(1, sizeof(*physicalConfigDedicated2->pucch_ConfigDedicated)); + physicalConfigDedicated2->pusch_ConfigDedicated = + CALLOC(1, sizeof(*physicalConfigDedicated2->pusch_ConfigDedicated)); + physicalConfigDedicated2->uplinkPowerControlDedicated = + CALLOC(1, sizeof(*physicalConfigDedicated2->uplinkPowerControlDedicated)); + physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH = + CALLOC(1, sizeof(*physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH)); + physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH = + CALLOC(1, sizeof(*physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH)); + physicalConfigDedicated2->cqi_ReportConfig = NULL; //CALLOC(1,sizeof(*physicalConfigDedicated2->cqi_ReportConfig)); + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated = NULL; //CALLOC(1,sizeof(*physicalConfigDedicated2->soundingRS_UL_ConfigDedicated)); + physicalConfigDedicated2->antennaInfo = CALLOC(1, sizeof(*physicalConfigDedicated2->antennaInfo)); + physicalConfigDedicated2->schedulingRequestConfig = + CALLOC(1, sizeof(*physicalConfigDedicated2->schedulingRequestConfig)); + // PDSCH + //assign_enum(&physicalConfigDedicated2->pdsch_ConfigDedicated->p_a, + // PDSCH_ConfigDedicated__p_a_dB0); + physicalConfigDedicated2->pdsch_ConfigDedicated->p_a = PDSCH_ConfigDedicated__p_a_dB0; + + // PUCCH + physicalConfigDedicated2->pucch_ConfigDedicated->ackNackRepetition.present = + PUCCH_ConfigDedicated__ackNackRepetition_PR_release; + physicalConfigDedicated2->pucch_ConfigDedicated->ackNackRepetition.choice.release = 0; + physicalConfigDedicated2->pucch_ConfigDedicated->tdd_AckNackFeedbackMode = NULL; //PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing; + + // Pusch_config_dedicated + physicalConfigDedicated2->pusch_ConfigDedicated->betaOffset_ACK_Index = 0; // 2.00 + physicalConfigDedicated2->pusch_ConfigDedicated->betaOffset_RI_Index = 0; // 1.25 + physicalConfigDedicated2->pusch_ConfigDedicated->betaOffset_CQI_Index = 8; // 2.25 + + // UplinkPowerControlDedicated + physicalConfigDedicated2->uplinkPowerControlDedicated->p0_UE_PUSCH = 0; // 0 dB + //assign_enum(&physicalConfigDedicated2->uplinkPowerControlDedicated->deltaMCS_Enabled, + // UplinkPowerControlDedicated__deltaMCS_Enabled_en1); + physicalConfigDedicated2->uplinkPowerControlDedicated->deltaMCS_Enabled = + UplinkPowerControlDedicated__deltaMCS_Enabled_en1; + physicalConfigDedicated2->uplinkPowerControlDedicated->accumulationEnabled = 1; // should be TRUE in order to have 0dB power offset + physicalConfigDedicated2->uplinkPowerControlDedicated->p0_UE_PUCCH = 0; // 0 dB + physicalConfigDedicated2->uplinkPowerControlDedicated->pSRS_Offset = 0; // 0 dB + physicalConfigDedicated2->uplinkPowerControlDedicated->filterCoefficient = + CALLOC(1, sizeof(*physicalConfigDedicated2->uplinkPowerControlDedicated->filterCoefficient)); + // assign_enum(physicalConfigDedicated2->uplinkPowerControlDedicated->filterCoefficient,FilterCoefficient_fc4); // fc4 dB + *physicalConfigDedicated2->uplinkPowerControlDedicated->filterCoefficient = FilterCoefficient_fc4; // fc4 dB + + // TPC-PDCCH-Config + physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH->present = TPC_PDCCH_Config_PR_setup; + physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH->choice.setup.tpc_Index.present = TPC_Index_PR_indexOfFormat3; + physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH->choice.setup.tpc_Index.choice.indexOfFormat3 = 1; + physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH->choice.setup.tpc_RNTI.buf = CALLOC(1, 2); + physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH->choice.setup.tpc_RNTI.size = 2; + physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH->choice.setup.tpc_RNTI.buf[0] = 0x12; + physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH->choice.setup.tpc_RNTI.buf[1] = 0x34 + ue_context_pP->local_uid; + physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH->choice.setup.tpc_RNTI.bits_unused = 0; + + physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH->present = TPC_PDCCH_Config_PR_setup; + physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH->choice.setup.tpc_Index.present = TPC_Index_PR_indexOfFormat3; + physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH->choice.setup.tpc_Index.choice.indexOfFormat3 = 1; + physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH->choice.setup.tpc_RNTI.buf = CALLOC(1, 2); + physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH->choice.setup.tpc_RNTI.size = 2; + physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH->choice.setup.tpc_RNTI.buf[0] = 0x22; + physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH->choice.setup.tpc_RNTI.buf[1] = 0x34 + ue_context_pP->local_uid; + physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH->choice.setup.tpc_RNTI.bits_unused = 0; + + // CQI ReportConfig + /* + physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportModeAperiodic=CALLOC(1,sizeof(*physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportModeAperiodic)); + assign_enum(physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportModeAperiodic, + CQI_ReportConfig__cqi_ReportModeAperiodic_rm30); // HLC CQI, no PMI + physicalConfigDedicated2->cqi_ReportConfig->nomPDSCH_RS_EPRE_Offset = 0; // 0 dB + physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic=CALLOC(1,sizeof(*physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic)); + physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic->present = CQI_ReportPeriodic_PR_setup; + physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex = 0; // n2_pucch + physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.cqi_pmi_ConfigIndex = 0; // Icqi/pmi + physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present = CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI; // subband CQI + physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.choice.subbandCQI.k=4; + + physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.ri_ConfigIndex=NULL; + physicalConfigDedicated2->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.simultaneousAckNackAndCQI=0; + */ + + //soundingRS-UL-ConfigDedicated + /* + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->present = SoundingRS_UL_ConfigDedicated_PR_setup; + assign_enum(&physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth, + SoundingRS_UL_ConfigDedicated__setup__srs_Bandwidth_bw0); + assign_enum(&physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth, + SoundingRS_UL_ConfigDedicated__setup__srs_HoppingBandwidth_hbw0); + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition=0; + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.duration=1; + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex=1; + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb=0; + assign_enum(&physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift, + SoundingRS_UL_ConfigDedicated__setup__cyclicShift_cs0); + */ + + //AntennaInfoDedicated + physicalConfigDedicated2->antennaInfo = CALLOC(1, sizeof(*physicalConfigDedicated2->antennaInfo)); + physicalConfigDedicated2->antennaInfo->present = PhysicalConfigDedicated__antennaInfo_PR_explicitValue; + //assign_enum(&physicalConfigDedicated2->antennaInfo->choice.explicitValue.transmissionMode, + // AntennaInfoDedicated__transmissionMode_tm2); + /* + switch (transmission_mode){ + case 1: + physicalConfigDedicated2->antennaInfo->choice.explicitValue.transmissionMode= AntennaInfoDedicated__transmissionMode_tm1; + break; + case 2: + physicalConfigDedicated2->antennaInfo->choice.explicitValue.transmissionMode= AntennaInfoDedicated__transmissionMode_tm2; + break; + case 4: + physicalConfigDedicated2->antennaInfo->choice.explicitValue.transmissionMode= AntennaInfoDedicated__transmissionMode_tm4; + break; + case 5: + physicalConfigDedicated2->antennaInfo->choice.explicitValue.transmissionMode= AntennaInfoDedicated__transmissionMode_tm5; + break; + case 6: + physicalConfigDedicated2->antennaInfo->choice.explicitValue.transmissionMode= AntennaInfoDedicated__transmissionMode_tm6; + break; + } + */ + physicalConfigDedicated2->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.present = + AntennaInfoDedicated__ue_TransmitAntennaSelection_PR_release; + physicalConfigDedicated2->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.release = 0; + + // SchedulingRequestConfig + physicalConfigDedicated2->schedulingRequestConfig->present = SchedulingRequestConfig_PR_setup; + physicalConfigDedicated2->schedulingRequestConfig->choice.setup.sr_PUCCH_ResourceIndex = ue_context_pP->local_uid; + + if (mac_xface->lte_frame_parms->frame_type == 0) { // FDD + physicalConfigDedicated2->schedulingRequestConfig->choice.setup.sr_ConfigIndex = 5 + (ue_context_pP->local_uid % + 10); // Isr = 5 (every 10 subframes, offset=2+UE_id mod3) + } else { + switch (mac_xface->lte_frame_parms->tdd_config) { + case 1: + physicalConfigDedicated2->schedulingRequestConfig->choice.setup.sr_ConfigIndex = 7 + (ue_context_pP->local_uid & 1) + (( + ue_context_pP->local_uid & 3) >> 1) * 5; // Isr = 5 (every 10 subframes, offset=2 for UE0, 3 for UE1, 7 for UE2, 8 for UE3 , 2 for UE4 etc..) + break; + + case 3: + physicalConfigDedicated2->schedulingRequestConfig->choice.setup.sr_ConfigIndex = 7 + (ue_context_pP->local_uid % + 3); // Isr = 5 (every 10 subframes, offset=2 for UE0, 3 for UE1, 3 for UE2, 2 for UE3 , etc..) + break; + + case 4: + physicalConfigDedicated2->schedulingRequestConfig->choice.setup.sr_ConfigIndex = 7 + (ue_context_pP->local_uid & + 1); // Isr = 5 (every 10 subframes, offset=2 for UE0, 3 for UE1, 3 for UE2, 2 for UE3 , etc..) + break; + + default: + physicalConfigDedicated2->schedulingRequestConfig->choice.setup.sr_ConfigIndex = 7; // Isr = 5 (every 10 subframes, offset=2 for all UE0 etc..) + break; + } + } + + // assign_enum(&physicalConfigDedicated2->schedulingRequestConfig->choice.setup.dsr_TransMax, + //SchedulingRequestConfig__setup__dsr_TransMax_n4); + // assign_enum(&physicalConfigDedicated2->schedulingRequestConfig->choice.setup.dsr_TransMax = SchedulingRequestConfig__setup__dsr_TransMax_n4; + physicalConfigDedicated2->schedulingRequestConfig->choice.setup.dsr_TransMax = + SchedulingRequestConfig__setup__dsr_TransMax_n4; + + LOG_D(RRC, + "handover_config [FRAME %05d][RRC_eNB][MOD %02d][][--- MAC_CONFIG_REQ (SRB1 UE %x) --->][MAC_eNB][MOD %02d][]\n", + ctxt_pP->frame, ctxt_pP->module_id, ue_context_pP->ue_context.rnti, ctxt_pP->module_id); + rrc_mac_config_req( + ctxt_pP->module_id, + ue_context_pP->ue_context.primaryCC_id, + ENB_FLAG_YES, + ue_context_pP->ue_context.rnti, + 0, + (RadioResourceConfigCommonSIB_t*) NULL, + ue_context_pP->ue_context.physicalConfigDedicated, +#ifdef Rel10 + (SCellToAddMod_r10_t *)NULL, + //(struct PhysicalConfigDedicatedSCell_r10 *)NULL, +#endif + (MeasObjectToAddMod_t **) NULL, + ue_context_pP->ue_context.mac_MainConfig, + 1, + SRB1_logicalChannelConfig, + ue_context_pP->ue_context.measGapConfig, + (TDD_Config_t*) NULL, + (MobilityControlInfo_t*) NULL, + (uint8_t*) NULL, + (uint16_t*) NULL, + NULL, + NULL, + NULL, + (MBSFN_SubframeConfigList_t *) NULL +#ifdef Rel10 + , 0, (MBSFN_AreaInfoList_r9_t *) NULL, (PMCH_InfoList_r9_t *) NULL +#endif +#ifdef CBA + , eNB_rrc_inst[ctxt_pP->module_id].num_active_cba_groups, eNB_rrc_inst[ctxt_pP->module_id].cba_rnti[0] +#endif + ); + + // Configure target eNB SRB2 + /// SRB2 + SRB2_config = CALLOC(1, sizeof(*SRB2_config)); + SRB_configList2 = CALLOC(1, sizeof(*SRB_configList2)); + memset(SRB_configList2, 0, sizeof(*SRB_configList2)); + + 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 = 1; + 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; + ASN_SEQUENCE_ADD(&SRB_configList->list, SRB2_config); + ASN_SEQUENCE_ADD(&SRB_configList2->list, SRB2_config); + + // Configure target eNB DRB + DRB_configList2 = CALLOC(1, sizeof(*DRB_configList2)); + /// DRB + DRB_config = CALLOC(1, sizeof(*DRB_config)); + + //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 + DRB_config->logicalChannelIdentity = CALLOC(1, sizeof(long)); + *(DRB_config->logicalChannelIdentity) = (long)3; + DRB_rlc_config = CALLOC(1, sizeof(*DRB_rlc_config)); + DRB_config->rlc_Config = DRB_rlc_config; + 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; + DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.t_Reordering = T_Reordering_ms35; + + DRB_pdcp_config = CALLOC(1, sizeof(*DRB_pdcp_config)); + DRB_config->pdcp_Config = DRB_pdcp_config; + DRB_pdcp_config->discardTimer = NULL; + DRB_pdcp_config->rlc_AM = NULL; + 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; + 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 = 2; // lower priority than srb1, srb2 + DRB_ul_SpecificParameters->prioritisedBitRate = + 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_configList2->list, DRB_config); + + 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 = MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_sf64; + mac_MainConfig->ul_SCH_Config->periodicBSR_Timer = periodicBSR_Timer; + + mac_MainConfig->ul_SCH_Config->retxBSR_Timer = MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf320; + + mac_MainConfig->ul_SCH_Config->ttiBundling = 0; // FALSE + + 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 + // 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); + + MeasId1 = CALLOC(1, sizeof(*MeasId1)); + MeasId1->measId = 2; + MeasId1->measObjectId = 1; + MeasId1->reportConfigId = 2; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId1); + + MeasId2 = CALLOC(1, sizeof(*MeasId2)); + MeasId2->measId = 3; + MeasId2->measObjectId = 1; + MeasId2->reportConfigId = 3; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId2); + + MeasId3 = CALLOC(1, sizeof(*MeasId3)); + MeasId3->measId = 4; + MeasId3->measObjectId = 1; + MeasId3->reportConfigId = 4; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId3); + + MeasId4 = CALLOC(1, sizeof(*MeasId4)); + MeasId4->measId = 5; + MeasId4->measObjectId = 1; + MeasId4->reportConfigId = 5; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId4); + + MeasId5 = CALLOC(1, sizeof(*MeasId5)); + MeasId5->measId = 6; + MeasId5->measObjectId = 1; + MeasId5->reportConfigId = 6; + ASN_SEQUENCE_ADD(&MeasId_list->list, MeasId5); + + // rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->measIdToAddModList = MeasId_list; + + // 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 = 36090; + 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 + ReportConfig_list = CALLOC(1, sizeof(*ReportConfig_list)); + + ReportConfig_per = CALLOC(1, sizeof(*ReportConfig_per)); + + ReportConfig_A1 = CALLOC(1, sizeof(*ReportConfig_A1)); + + ReportConfig_A2 = CALLOC(1, sizeof(*ReportConfig_A2)); + + ReportConfig_A3 = CALLOC(1, sizeof(*ReportConfig_A3)); + + ReportConfig_A4 = CALLOC(1, sizeof(*ReportConfig_A4)); + + ReportConfig_A5 = CALLOC(1, sizeof(*ReportConfig_A5)); + + 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.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 = ReportInterval_ms120; + ReportConfig_per->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_per); + + ReportConfig_A1->reportConfigId = 2; + ReportConfig_A1->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA1; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA1. + a1_Threshold.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA1. + a1_Threshold.choice.threshold_RSRP = 10; + + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.triggerQuantity = ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A1->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A1); + + ReportConfig_A2->reportConfigId = 3; + ReportConfig_A2->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA2; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA2. + a2_Threshold.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA2. + a2_Threshold.choice.threshold_RSRP = 10; + + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.triggerQuantity = ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A2->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A2); + + ReportConfig_A3->reportConfigId = 4; + ReportConfig_A3->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA3; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA3.a3_Offset = + 10; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA3.reportOnLeave = 1; + + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.triggerQuantity = ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A3->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A3); + + ReportConfig_A4->reportConfigId = 5; + ReportConfig_A4->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA4; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA4. + a4_Threshold.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice.eventA4. + a4_Threshold.choice.threshold_RSRP = 10; + + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.triggerQuantity = ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A4->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A4); + + ReportConfig_A5->reportConfigId = 6; + ReportConfig_A5->reportConfig.present = ReportConfigToAddMod__reportConfig_PR_reportConfigEUTRA; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.present = + ReportConfigEUTRA__triggerType_PR_event; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.present = + ReportConfigEUTRA__triggerType__event__eventId_PR_eventA5; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA5.a5_Threshold1.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA5.a5_Threshold2.present = ThresholdEUTRA_PR_threshold_RSRP; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA5.a5_Threshold1.choice.threshold_RSRP = 10; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerType.choice.event.eventId.choice. + eventA5.a5_Threshold2.choice.threshold_RSRP = 10; + + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.triggerQuantity = ReportConfigEUTRA__triggerQuantity_rsrp; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportQuantity = ReportConfigEUTRA__reportQuantity_both; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.maxReportCells = 2; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportInterval = ReportInterval_ms120; + ReportConfig_A5->reportConfig.choice.reportConfigEUTRA.reportAmount = ReportConfigEUTRA__reportAmount_infinity; + + ASN_SEQUENCE_ADD(&ReportConfig_list->list, ReportConfig_A5); + + Sparams = CALLOC(1, sizeof(*Sparams)); + Sparams->present = MeasConfig__speedStatePars_PR_setup; + Sparams->choice.setup.timeToTrigger_SF.sf_High = SpeedStateScaleFactors__sf_Medium_oDot75; + Sparams->choice.setup.timeToTrigger_SF.sf_Medium = SpeedStateScaleFactors__sf_High_oDot5; + Sparams->choice.setup.mobilityStateParameters.n_CellChangeHigh = 10; + Sparams->choice.setup.mobilityStateParameters.n_CellChangeMedium = 5; + Sparams->choice.setup.mobilityStateParameters.t_Evaluation = MobilityStateParameters__t_Evaluation_s60; + Sparams->choice.setup.mobilityStateParameters.t_HystNormal = MobilityStateParameters__t_HystNormal_s120; + + quantityConfig = CALLOC(1, sizeof(*quantityConfig)); + memset((void *)quantityConfig, 0, sizeof(*quantityConfig)); + quantityConfig->quantityConfigEUTRA = CALLOC(1, sizeof(*quantityConfig->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; + + /* mobilityinfo */ + + mobilityInfo = CALLOC(1, sizeof(*mobilityInfo)); + memset((void *)mobilityInfo, 0, sizeof(*mobilityInfo)); + mobilityInfo->targetPhysCellId = + (PhysCellId_t) two_tier_hexagonal_cellIds[ue_context_pP->ue_context.handover_info->modid_t]; + LOG_D(RRC, "[eNB %d] Frame %d: handover preparation: targetPhysCellId: %d mod_id: %d ue: %x \n", + ctxt_pP->module_id, + ctxt_pP->frame, + mobilityInfo->targetPhysCellId, + ctxt_pP->module_id, + ue_context_pP->ue_context.rnti); + + mobilityInfo->additionalSpectrumEmission = CALLOC(1, sizeof(*mobilityInfo->additionalSpectrumEmission)); + *mobilityInfo->additionalSpectrumEmission = 1; //Check this value! + + mobilityInfo->t304 = MobilityControlInfo__t304_ms50; // need to configure an appropriate value here + + // New UE Identity (C-RNTI) to identify an UE uniquely in a cell + mobilityInfo->newUE_Identity.size = 2; + mobilityInfo->newUE_Identity.bits_unused = 0; + mobilityInfo->newUE_Identity.buf = rv; + mobilityInfo->newUE_Identity.buf[0] = rv[0]; + mobilityInfo->newUE_Identity.buf[1] = rv[1]; + + //memset((void *)&mobilityInfo->radioResourceConfigCommon,(void *)&rrc_inst->sib2->radioResourceConfigCommon,sizeof(RadioResourceConfigCommon_t)); + //memset((void *)&mobilityInfo->radioResourceConfigCommon,0,sizeof(RadioResourceConfigCommon_t)); + + // Configuring radioResourceConfigCommon + mobilityInfo->radioResourceConfigCommon.rach_ConfigCommon = + CALLOC(1, sizeof(*mobilityInfo->radioResourceConfigCommon.rach_ConfigCommon)); + memcpy((void *)mobilityInfo->radioResourceConfigCommon.rach_ConfigCommon, + (void *)&rrc_inst->carrier[0] /* CROUX TBC */.sib2->radioResourceConfigCommon.rach_ConfigCommon, sizeof(RACH_ConfigCommon_t)); + mobilityInfo->radioResourceConfigCommon.prach_Config.prach_ConfigInfo = + CALLOC(1, sizeof(*mobilityInfo->radioResourceConfigCommon.prach_Config.prach_ConfigInfo)); + memcpy((void *)mobilityInfo->radioResourceConfigCommon.prach_Config.prach_ConfigInfo, + (void *)&rrc_inst->carrier[0] /* CROUX TBC */.sib2->radioResourceConfigCommon.prach_Config.prach_ConfigInfo, + sizeof(PRACH_ConfigInfo_t)); + + mobilityInfo->radioResourceConfigCommon.prach_Config.rootSequenceIndex = + rrc_inst->carrier[0] /* CROUX TBC */.sib2->radioResourceConfigCommon.prach_Config.rootSequenceIndex; + mobilityInfo->radioResourceConfigCommon.pdsch_ConfigCommon = + CALLOC(1, sizeof(*mobilityInfo->radioResourceConfigCommon.pdsch_ConfigCommon)); + memcpy((void *)mobilityInfo->radioResourceConfigCommon.pdsch_ConfigCommon, + (void *)&rrc_inst->carrier[0] /* CROUX TBC */.sib2->radioResourceConfigCommon.pdsch_ConfigCommon, sizeof(PDSCH_ConfigCommon_t)); + memcpy((void *)&mobilityInfo->radioResourceConfigCommon.pusch_ConfigCommon, + (void *)&rrc_inst->carrier[0] /* CROUX TBC */.sib2->radioResourceConfigCommon.pusch_ConfigCommon, sizeof(PUSCH_ConfigCommon_t)); + mobilityInfo->radioResourceConfigCommon.phich_Config = NULL; + mobilityInfo->radioResourceConfigCommon.pucch_ConfigCommon = + CALLOC(1, sizeof(*mobilityInfo->radioResourceConfigCommon.pucch_ConfigCommon)); + memcpy((void *)mobilityInfo->radioResourceConfigCommon.pucch_ConfigCommon, + (void *)&rrc_inst->carrier[0] /* CROUX TBC */.sib2->radioResourceConfigCommon.pucch_ConfigCommon, sizeof(PUCCH_ConfigCommon_t)); + mobilityInfo->radioResourceConfigCommon.soundingRS_UL_ConfigCommon = + CALLOC(1, sizeof(*mobilityInfo->radioResourceConfigCommon.soundingRS_UL_ConfigCommon)); + memcpy((void *)mobilityInfo->radioResourceConfigCommon.soundingRS_UL_ConfigCommon, + (void *)&rrc_inst->carrier[0] /* CROUX TBC */.sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon, + sizeof(SoundingRS_UL_ConfigCommon_t)); + mobilityInfo->radioResourceConfigCommon.uplinkPowerControlCommon = + CALLOC(1, sizeof(*mobilityInfo->radioResourceConfigCommon.uplinkPowerControlCommon)); + memcpy((void *)mobilityInfo->radioResourceConfigCommon.uplinkPowerControlCommon, + (void *)&rrc_inst->carrier[0] /* CROUX TBC */.sib2->radioResourceConfigCommon.uplinkPowerControlCommon, + sizeof(UplinkPowerControlCommon_t)); + mobilityInfo->radioResourceConfigCommon.antennaInfoCommon = NULL; + mobilityInfo->radioResourceConfigCommon.p_Max = NULL; // CALLOC(1,sizeof(*mobilityInfo->radioResourceConfigCommon.p_Max)); + //memcpy((void *)mobilityInfo->radioResourceConfigCommon.p_Max,(void *)rrc_inst->sib1->p_Max,sizeof(P_Max_t)); + mobilityInfo->radioResourceConfigCommon.tdd_Config = NULL; //CALLOC(1,sizeof(TDD_Config_t)); + //memcpy((void *)mobilityInfo->radioResourceConfigCommon.tdd_Config,(void *)rrc_inst->sib1->tdd_Config,sizeof(TDD_Config_t)); + mobilityInfo->radioResourceConfigCommon.ul_CyclicPrefixLength = + rrc_inst->carrier[0] /* CROUX TBC */.sib2->radioResourceConfigCommon.ul_CyclicPrefixLength; + //End of configuration of radioResourceConfigCommon + + mobilityInfo->carrierFreq = CALLOC(1, sizeof(*mobilityInfo->carrierFreq)); //CALLOC(1,sizeof(CarrierFreqEUTRA_t)); 36090 + mobilityInfo->carrierFreq->dl_CarrierFreq = 36090; + mobilityInfo->carrierFreq->ul_CarrierFreq = NULL; + + mobilityInfo->carrierBandwidth = CALLOC(1, sizeof( + *mobilityInfo->carrierBandwidth)); //CALLOC(1,sizeof(struct CarrierBandwidthEUTRA)); AllowedMeasBandwidth_mbw25 + mobilityInfo->carrierBandwidth->dl_Bandwidth = CarrierBandwidthEUTRA__dl_Bandwidth_n25; + mobilityInfo->carrierBandwidth->ul_Bandwidth = NULL; + mobilityInfo->rach_ConfigDedicated = NULL; + + // store the srb and drb list for ho management, mainly in case of failure + + memcpy(ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.srb_ToAddModList, + (void*)SRB_configList2, + sizeof(SRB_ToAddModList_t)); + memcpy((void*)ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.drb_ToAddModList, + (void*)DRB_configList2, + sizeof(DRB_ToAddModList_t)); + ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.drb_ToReleaseList = NULL; + memcpy((void*)ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.mac_MainConfig, + (void*)mac_MainConfig, + sizeof(MAC_MainConfig_t)); + memcpy((void*)ue_context_pP->ue_context.handover_info->as_config.sourceRadioResourceConfig.physicalConfigDedicated, + (void*)ue_context_pP->ue_context.physicalConfigDedicated, + sizeof(PhysicalConfigDedicated_t)); + /* memcpy((void *)rrc_inst->handover_info[ue_mod_idP]->as_config.sourceRadioResourceConfig.sps_Config, + (void *)rrc_inst->sps_Config[ue_mod_idP], + sizeof(SPS_Config_t)); + */ + LOG_I(RRC, "[eNB %d] Frame %d: adding new UE\n"); + //Idx = (ue_mod_idP * NB_RB_MAX) + DCCH; + Idx = DCCH; + // SRB1 + ue_context_pP->ue_context.Srb1.Active = 1; + ue_context_pP->ue_context.Srb1.Srb_info.Srb_id = Idx; + memcpy(&ue_context_pP->ue_context.Srb1.Srb_info.Lchan_desc[0], &DCCH_LCHAN_DESC, LCHAN_DESC_SIZE); + memcpy(&ue_context_pP->ue_context.Srb1.Srb_info.Lchan_desc[1], &DCCH_LCHAN_DESC, LCHAN_DESC_SIZE); + + // SRB2 + ue_context_pP->ue_context.Srb2.Active = 1; + ue_context_pP->ue_context.Srb2.Srb_info.Srb_id = Idx; + memcpy(&ue_context_pP->ue_context.Srb2.Srb_info.Lchan_desc[0], &DCCH_LCHAN_DESC, LCHAN_DESC_SIZE); + memcpy(&ue_context_pP->ue_context.Srb2.Srb_info.Lchan_desc[1], &DCCH_LCHAN_DESC, LCHAN_DESC_SIZE); + LOG_I(RRC, "[eNB %d] CALLING RLC CONFIG SRB1 (rbid %d) for UE %x\n", + ctxt_pP->module_id, Idx, ue_context_pP->ue_context.rnti); + + // rrc_pdcp_config_req (enb_mod_idP, frameP, 1, CONFIG_ACTION_ADD, idx, UNDEF_SECURITY_MODE); + // rrc_rlc_config_req(enb_mod_idP,frameP,1,CONFIG_ACTION_ADD,Idx,SIGNALLING_RADIO_BEARER,Rlc_info_am_config); + + rrc_pdcp_config_asn1_req(&ctxt, + ue_context_pP->ue_context.SRB_configList, + (DRB_ToAddModList_t *) NULL, (DRB_ToReleaseList_t *) NULL, 0xff, NULL, NULL, NULL +#ifdef Rel10 + , (PMCH_InfoList_r9_t *) NULL +#endif + ); + + rrc_rlc_config_asn1_req(&ctxt, + ue_context_pP->ue_context.SRB_configList, + (DRB_ToAddModList_t *) NULL, (DRB_ToReleaseList_t *) NULL +#ifdef Rel10 + , (PMCH_InfoList_r9_t *) NULL +#endif + ); + + /* Initialize NAS list */ + dedicatedInfoNASList = NULL; + + // rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.measConfig->reportConfigToAddModList = ReportConfig_list; + memset(buffer, 0, RRC_BUF_SIZE); + + size = do_RRCConnectionReconfiguration( + ctxt_pP, + buffer, + rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id), //Transaction_id, + SRB_configList2, + DRB_configList2, + NULL, // DRB2_list, + NULL, //*sps_Config, + ue_context_pP->ue_context.physicalConfigDedicated, + MeasObj_list, + ReportConfig_list, + NULL, //quantityConfig, + MeasId_list, + mac_MainConfig, + NULL, + mobilityInfo, + Sparams, + NULL, + NULL, + dedicatedInfoNASList +#ifdef Rel10 + , NULL // SCellToAddMod_r10_t +#endif + ); + + LOG_I(RRC, + "[eNB %d] Frame %d, Logical Channel DL-DCCH, Generate RRCConnectionReconfiguration for handover (bytes %d, UE rnti %x)\n", + ctxt_pP->module_id, ctxt_pP->frame, size, ue_context_pP->ue_context.rnti); + // to be updated if needed + /*if (eNB_rrc_inst[ctxt_pP->module_id].SRB1_config[ue_mod_idP]->logicalChannelConfig) { + if (eNB_rrc_inst[ctxt_pP->module_id].SRB1_config[ue_mod_idP]->logicalChannelConfig->present == SRB_ToAddMod__logicalChannelConfig_PR_explicitValue) { + SRB1_logicalChannelConfig = &eNB_rrc_inst[ctxt_pP->module_id].SRB1_config[ue_mod_idP]->logicalChannelConfig->choice.explicitValue; + } + else { + SRB1_logicalChannelConfig = &SRB1_logicalChannelConfig_defaultValue; + } + } + else { + SRB1_logicalChannelConfig = &SRB1_logicalChannelConfig_defaultValue; + } + */ + + LOG_D(RRC, + "[FRAME %05d][RRC_eNB][MOD %02d][][--- PDCP_DATA_REQ/%d Bytes (rrcConnectionReconfiguration_handover to UE %x MUI %d) --->][PDCP][MOD %02d][RB %02d]\n", + ctxt_pP->frame, ctxt_pP->module_id, size, ue_context_pP->ue_context.rnti, rrc_eNB_mui, ctxt_pP->module_id, DCCH); + //rrc_rlc_data_req(ctxt_pP->module_id,frameP, 1,(ue_mod_idP*NB_RB_MAX)+DCCH,rrc_eNB_mui++,0,size,(char*)buffer); + //pdcp_data_req (ctxt_pP->module_id, frameP, 1, (ue_mod_idP * NB_RB_MAX) + DCCH,rrc_eNB_mui++, 0, size, (char *) buffer, 1); + rrc_mac_config_req( + ctxt_pP->module_id, + ue_context_pP->ue_context.primaryCC_id, + ENB_FLAG_YES, + ue_context_pP->ue_context.rnti, + 0, + (RadioResourceConfigCommonSIB_t *) NULL, + ue_context_pP->ue_context.physicalConfigDedicated, +#ifdef Rel10 + (SCellToAddMod_r10_t *)NULL, + //(struct PhysicalConfigDedicatedSCell_r10 *)NULL, +#endif + (MeasObjectToAddMod_t **) NULL, + ue_context_pP->ue_context.mac_MainConfig, + 1, + SRB1_logicalChannelConfig, + ue_context_pP->ue_context.measGapConfig, + (TDD_Config_t *) NULL, + (MobilityControlInfo_t *) mobilityInfo, + (uint8_t *) NULL, (uint16_t *) NULL, NULL, NULL, NULL, (MBSFN_SubframeConfigList_t *) NULL +#ifdef Rel10 + , 0, (MBSFN_AreaInfoList_r9_t *) NULL, (PMCH_InfoList_r9_t *) NULL +#endif +#ifdef CBA + , 0, 0 +#endif + ); + + /* + handoverCommand.criticalExtensions.present = HandoverCommand__criticalExtensions_PR_c1; + handoverCommand.criticalExtensions.choice.c1.present = HandoverCommand__criticalExtensions__c1_PR_handoverCommand_r8; + handoverCommand.criticalExtensions.choice.c1.choice.handoverCommand_r8.handoverCommandMessage.buf = buffer; + handoverCommand.criticalExtensions.choice.c1.choice.handoverCommand_r8.handoverCommandMessage.size = size; + */ +//#warning "COMPILATION PROBLEM" +#ifdef PROBLEM_COMPILATION_RESOLVED + + if (sourceModId != 0xFF) { + memcpy(eNB_rrc_inst[sourceModId].handover_info[eNB_rrc_inst[ctxt_pP->module_id].handover_info[ue_mod_idP]->ueid_s]->buf, + (void *)buffer, size); + eNB_rrc_inst[sourceModId].handover_info[eNB_rrc_inst[ctxt_pP->module_id].handover_info[ue_mod_idP]->ueid_s]->size = size; + eNB_rrc_inst[sourceModId].handover_info[eNB_rrc_inst[ctxt_pP->module_id].handover_info[ue_mod_idP]->ueid_s]->ho_complete = + 0xF1; + //eNB_rrc_inst[ctxt_pP->module_id].handover_info[ue_mod_idP]->ho_complete = 0xFF; + LOG_D(RRC, "[eNB %d] Frame %d: setting handover complete to 0xF1 for (%d,%d) and to 0xFF for (%d,%d)\n", + ctxt_pP->module_id, + ctxt_pP->frame, + sourceModId, + eNB_rrc_inst[ctxt_pP->module_id].handover_info[ue_mod_idP]->ueid_s, + ctxt_pP->module_id, + ue_mod_idP); + } else + LOG_W(RRC, + "[eNB %d] Frame %d: rrc_eNB_generate_RRCConnectionReconfiguration_handover: Could not find source eNB mod_id.\n", + ctxt_pP->module_id, ctxt_pP->frame); + +#endif +} + +/* + void ue_rrc_process_rrcConnectionReconfiguration(uint8_t enb_mod_idP,frame_t frameP, + RRCConnectionReconfiguration_t *rrcConnectionReconfiguration, + uint8_t CH_index) { + + if (rrcConnectionReconfiguration->criticalExtensions.present == RRCConnectionReconfiguration__criticalExtensions_PR_c1) + if (rrcConnectionReconfiguration->criticalExtensions.choice.c1.present == RRCConnectionReconfiguration__criticalExtensions__c1_PR_rrcConnectionReconfiguration_r8) { + + if (rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated) { + rrc_ue_process_radioResourceConfigDedicated(enb_mod_idP,frameP,CH_index, + rrcConnectionReconfiguration->criticalExtensions.choice.c1.choice.rrcConnectionReconfiguration_r8.radioResourceConfigDedicated); + + } + + // check other fields for + } + } +*/ + +//----------------------------------------------------------------------------- +void +rrc_eNB_process_RRCConnectionReconfigurationComplete( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + RRCConnectionReconfigurationComplete_r8_IEs_t* rrcConnectionReconfigurationComplete +) +//----------------------------------------------------------------------------- +{ + int i; +#ifdef PDCP_USE_NETLINK + int oip_ifup = 0; + int dest_ip_offset = 0; + module_id_t ue_module_id = -1; + /* avoid gcc warnings */ + (void)oip_ifup; + (void)dest_ip_offset; + (void)ue_module_id; +#endif + + uint8_t *kRRCenc = NULL; + uint8_t *kRRCint = NULL; + uint8_t *kUPenc = NULL; + + DRB_ToAddModList_t* DRB_configList = ue_context_pP->ue_context.DRB_configList; + //SRB_ToAddModList_t* SRB_configList = ue_context_pP->ue_context.SRB_configList; + + T(T_ENB_RRC_CONNECTION_RECONFIGURATION_COMPLETE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + +#if defined(ENABLE_SECURITY) + + /* Derive the keys from kenb */ + if (DRB_configList != NULL) { + derive_key_up_enc(ue_context_pP->ue_context.ciphering_algorithm, + ue_context_pP->ue_context.kenb, &kUPenc); + } + + derive_key_rrc_enc(ue_context_pP->ue_context.ciphering_algorithm, + ue_context_pP->ue_context.kenb, &kRRCenc); + derive_key_rrc_int(ue_context_pP->ue_context.integrity_algorithm, + ue_context_pP->ue_context.kenb, &kRRCint); + +#endif +#if ENABLE_RAL + { + MessageDef *message_ral_p = NULL; + rrc_ral_connection_reconfiguration_ind_t connection_reconfiguration_ind; + int i; + + message_ral_p = itti_alloc_new_message(TASK_RRC_ENB, RRC_RAL_CONNECTION_RECONFIGURATION_IND); + memset(&connection_reconfiguration_ind, 0, sizeof(rrc_ral_connection_reconfiguration_ind_t)); + connection_reconfiguration_ind.ue_id = ctxt_pP->rnti; + + if (DRB_configList != NULL) { + connection_reconfiguration_ind.num_drb = DRB_configList->list.count; + + for (i = 0; (i < DRB_configList->list.count) && (i < maxDRB); i++) { + connection_reconfiguration_ind.drb_id[i] = DRB_configList->list.array[i]->drb_Identity; + } + } else { + connection_reconfiguration_ind.num_drb = 0; + } + + if (SRB_configList != NULL) { + connection_reconfiguration_ind.num_srb = SRB_configList->list.count; + } else { + connection_reconfiguration_ind.num_srb = 0; + } + + memcpy(&message_ral_p->ittiMsg, (void *)&connection_reconfiguration_ind, + sizeof(rrc_ral_connection_reconfiguration_ind_t)); + LOG_I(RRC, "Sending RRC_RAL_CONNECTION_RECONFIGURATION_IND to RAL\n"); + itti_send_msg_to_task(TASK_RAL_ENB, ctxt_pP->instance, message_ral_p); + } +#endif + // Refresh SRBs/DRBs + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_PDCP_ENB, + NULL, + 0, + MSC_AS_TIME_FMT" CONFIG_REQ UE %x DRB (security unchanged)", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_pP->ue_context.rnti); + + rrc_pdcp_config_asn1_req( + ctxt_pP, + NULL, //LG-RK 14/05/2014 SRB_configList, + DRB_configList, (DRB_ToReleaseList_t *) NULL, + /*eNB_rrc_inst[ctxt_pP->module_id].ciphering_algorithm[ue_mod_idP] | + (eNB_rrc_inst[ctxt_pP->module_id].integrity_algorithm[ue_mod_idP] << 4), + */ + 0xff, // already configured during the securitymodecommand + kRRCenc, + kRRCint, + kUPenc +#ifdef Rel10 + , (PMCH_InfoList_r9_t *) NULL +#endif + ); + // Refresh SRBs/DRBs + rrc_rlc_config_asn1_req( + ctxt_pP, + NULL, //LG-RK 14/05/2014 SRB_configList, + DRB_configList, + (DRB_ToReleaseList_t *) NULL +#ifdef Rel10 + , (PMCH_InfoList_r9_t *) NULL +#endif + ); + + // Loop through DRBs and establish if necessary + + if (DRB_configList != NULL) { + for (i = 0; i < DRB_configList->list.count; i++) { // num max DRB (11-3-8) + if (DRB_configList->list.array[i]) { + LOG_I(RRC, + "[eNB %d] Frame %d : Logical Channel UL-DCCH, Received RRCConnectionReconfigurationComplete from UE rnti %x, reconfiguring DRB %d/LCID %d\n", + ctxt_pP->module_id, + ctxt_pP->frame, + ctxt_pP->rnti, + (int)DRB_configList->list.array[i]->drb_Identity, + (int)*DRB_configList->list.array[i]->logicalChannelIdentity); + // for pre-ci tests + LOG_I(RRC, + "[eNB %d] Frame %d : Logical Channel UL-DCCH, Received RRCConnectionReconfigurationComplete from UE %u, reconfiguring DRB %d/LCID %d\n", + ctxt_pP->module_id, + ctxt_pP->frame, + oai_emulation.info.eNB_ue_local_uid_to_ue_module_id[ctxt_pP->module_id][ue_context_pP->local_uid], + (int)DRB_configList->list.array[i]->drb_Identity, + (int)*DRB_configList->list.array[i]->logicalChannelIdentity); + + if (ue_context_pP->ue_context.DRB_active[i] == 0) { + /* + rrc_pdcp_config_req (ctxt_pP->module_id, frameP, 1, CONFIG_ACTION_ADD, + (ue_mod_idP * NB_RB_MAX) + *DRB_configList->list.array[i]->logicalChannelIdentity,UNDEF_SECURITY_MODE); + rrc_rlc_config_req(ctxt_pP->module_id,frameP,1,CONFIG_ACTION_ADD, + (ue_mod_idP * NB_RB_MAX) + (int)*eNB_rrc_inst[ctxt_pP->module_id].DRB_config[ue_mod_idP][i]->logicalChannelIdentity, + RADIO_ACCESS_BEARER,Rlc_info_um); + */ + ue_context_pP->ue_context.DRB_active[i] = 1; + + LOG_D(RRC, + "[eNB %d] Frame %d: Establish RLC UM Bidirectional, DRB %d Active\n", + ctxt_pP->module_id, ctxt_pP->frame, (int)DRB_configList->list.array[i]->drb_Identity); +#if defined(PDCP_USE_NETLINK) && !defined(LINK_ENB_PDCP_TO_GTPV1U) + // can mean also IPV6 since ether -> ipv6 autoconf +# if !defined(OAI_NW_DRIVER_TYPE_ETHERNET) && !defined(EXMIMO) && !defined(OAI_USRP) && !defined(OAI_BLADERF) && !defined(ETHERNET) + LOG_I(OIP, "[eNB %d] trying to bring up the OAI interface oai%d\n", + ctxt_pP->module_id, + ctxt_pP->module_id); + oip_ifup = nas_config( + ctxt_pP->module_id, // interface index + ctxt_pP->module_id + 1, // thrid octet + ctxt_pP->module_id + 1); // fourth octet + + if (oip_ifup == 0) { // interface is up --> send a config the DRB +# ifdef OAI_EMU + oai_emulation.info.oai_ifup[ctxt_pP->module_id] = 1; + dest_ip_offset = NB_eNB_INST; +# else + dest_ip_offset = 8; +# endif + LOG_I(OIP, + "[eNB %d] Config the oai%d to send/receive pkt on DRB %d to/from the protocol stack\n", + ctxt_pP->module_id, ctxt_pP->module_id, + (ue_context_pP->local_uid * maxDRB) + DRB_configList->list.array[i]->drb_Identity); + ue_module_id = oai_emulation.info.eNB_ue_local_uid_to_ue_module_id[ctxt_pP->module_id][ue_context_pP->local_uid]; + rb_conf_ipv4(0, //add + ue_module_id, //cx + ctxt_pP->module_id, //inst + (ue_module_id * maxDRB) + DRB_configList->list.array[i]->drb_Identity, // RB + 0, //dscp + ipv4_address(ctxt_pP->module_id + 1, ctxt_pP->module_id + 1), //saddr + ipv4_address(ctxt_pP->module_id + 1, dest_ip_offset + ue_module_id + 1)); //daddr + LOG_D(RRC, "[eNB %d] State = Attached (UE rnti %x module id %u)\n", + ctxt_pP->module_id, ue_context_pP->ue_context.rnti, ue_module_id); + } + +# else +# ifdef OAI_EMU + oai_emulation.info.oai_ifup[ctxt_pP->module_id] = 1; +# endif +# endif +#endif + + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RRC_eNB --- MAC_CONFIG_REQ (DRB) ---> MAC_eNB\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + + if (DRB_configList->list.array[i]->logicalChannelIdentity) { + DRB2LCHAN[i] = (uint8_t) * DRB_configList->list.array[i]->logicalChannelIdentity; + } + + rrc_mac_config_req( + ctxt_pP->module_id, + ue_context_pP->ue_context.primaryCC_id, + ENB_FLAG_YES, + ue_context_pP->ue_context.rnti, + 0, + (RadioResourceConfigCommonSIB_t *) NULL, + ue_context_pP->ue_context.physicalConfigDedicated, +#ifdef Rel10 + (SCellToAddMod_r10_t *)NULL, + //(struct PhysicalConfigDedicatedSCell_r10 *)NULL, +#endif + (MeasObjectToAddMod_t **) NULL, + ue_context_pP->ue_context.mac_MainConfig, + DRB2LCHAN[i], + DRB_configList->list.array[i]->logicalChannelConfig, + ue_context_pP->ue_context.measGapConfig, + (TDD_Config_t *) NULL, + NULL, + (uint8_t *) NULL, + (uint16_t *) NULL, NULL, NULL, NULL, (MBSFN_SubframeConfigList_t *) NULL +#ifdef Rel10 + , 0, (MBSFN_AreaInfoList_r9_t *) NULL, (PMCH_InfoList_r9_t *) NULL +#endif +#ifdef CBA + , eNB_rrc_inst[ctxt_pP->module_id].num_active_cba_groups, eNB_rrc_inst[ctxt_pP->module_id].cba_rnti[0] +#endif + ); + + } else { // remove LCHAN from MAC/PHY + + if (ue_context_pP->ue_context.DRB_active[i] == 1) { + // DRB has just been removed so remove RLC + PDCP for DRB + /* rrc_pdcp_config_req (ctxt_pP->module_id, frameP, 1, CONFIG_ACTION_REMOVE, + (ue_mod_idP * NB_RB_MAX) + DRB2LCHAN[i],UNDEF_SECURITY_MODE); + */ + rrc_rlc_config_req( + ctxt_pP, + SRB_FLAG_NO, + MBMS_FLAG_NO, + CONFIG_ACTION_REMOVE, + DRB2LCHAN[i], + Rlc_info_um); + } + + ue_context_pP->ue_context.DRB_active[i] = 0; + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RRC_eNB --- MAC_CONFIG_REQ (DRB) ---> MAC_eNB\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + rrc_mac_config_req(ctxt_pP->module_id, + ue_context_pP->ue_context.primaryCC_id, + ENB_FLAG_YES, + ue_context_pP->ue_context.rnti, + 0, + (RadioResourceConfigCommonSIB_t *) NULL, + ue_context_pP->ue_context.physicalConfigDedicated, +#ifdef Rel10 + (SCellToAddMod_r10_t *)NULL, + //(struct PhysicalConfigDedicatedSCell_r10 *)NULL, +#endif + (MeasObjectToAddMod_t **) NULL, + ue_context_pP->ue_context.mac_MainConfig, + DRB2LCHAN[i], + (LogicalChannelConfig_t *) NULL, + (MeasGapConfig_t *) NULL, + (TDD_Config_t *) NULL, + NULL, (uint8_t *) NULL, (uint16_t *) NULL, NULL, NULL, NULL, NULL +#ifdef Rel10 + , 0, (MBSFN_AreaInfoList_r9_t *) NULL, (PMCH_InfoList_r9_t *) NULL +#endif +#ifdef CBA + , 0, 0 +#endif + ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +void +rrc_eNB_generate_RRCConnectionSetup( + const protocol_ctxt_t* const ctxt_pP, + rrc_eNB_ue_context_t* const ue_context_pP, + const int CC_id +) +//----------------------------------------------------------------------------- +{ + + LogicalChannelConfig_t *SRB1_logicalChannelConfig; //,*SRB2_logicalChannelConfig; + SRB_ToAddModList_t **SRB_configList; + SRB_ToAddMod_t *SRB1_config; + int cnt; + + T(T_ENB_RRC_CONNECTION_SETUP, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + SRB_configList = &ue_context_pP->ue_context.SRB_configList; + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size = + do_RRCConnectionSetup(ctxt_pP, + ue_context_pP, + (uint8_t*) eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.Payload, + (mac_xface->lte_frame_parms->nb_antennas_tx==2)?2:1, + rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id), + mac_xface->lte_frame_parms, + SRB_configList, + &ue_context_pP->ue_context.physicalConfigDedicated); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC Connection Setup\n"); + + for (cnt = 0; cnt < eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size; cnt++) { + LOG_F(RRC,"%02x ", ((uint8_t*)eNB_rrc_inst[ctxt_pP->module_id].Srb0.Tx_buffer.Payload)[cnt]); + } + + LOG_F(RRC,"\n"); + ////////////////////////////////// +#endif + + // configure SRB1/SRB2, PhysicalConfigDedicated, MAC_MainConfig for UE + + if (*SRB_configList != NULL) { + for (cnt = 0; cnt < (*SRB_configList)->list.count; cnt++) { + if ((*SRB_configList)->list.array[cnt]->srb_Identity == 1) { + SRB1_config = (*SRB_configList)->list.array[cnt]; + + if (SRB1_config->logicalChannelConfig) { + if (SRB1_config->logicalChannelConfig->present == + SRB_ToAddMod__logicalChannelConfig_PR_explicitValue) { + SRB1_logicalChannelConfig = &SRB1_config->logicalChannelConfig->choice.explicitValue; + } else { + SRB1_logicalChannelConfig = &SRB1_logicalChannelConfig_defaultValue; + } + } else { + SRB1_logicalChannelConfig = &SRB1_logicalChannelConfig_defaultValue; + } + + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RRC_eNB --- MAC_CONFIG_REQ (SRB1) ---> MAC_eNB\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + rrc_mac_config_req( + ctxt_pP->module_id, + ue_context_pP->ue_context.primaryCC_id, + ENB_FLAG_YES, + ue_context_pP->ue_context.rnti, + 0, + (RadioResourceConfigCommonSIB_t *) NULL, + ue_context_pP->ue_context.physicalConfigDedicated, +#ifdef Rel10 + (SCellToAddMod_r10_t *)NULL, + //(struct PhysicalConfigDedicatedSCell_r10 *)NULL, +#endif + (MeasObjectToAddMod_t **) NULL, + ue_context_pP->ue_context.mac_MainConfig, + 1, + SRB1_logicalChannelConfig, + ue_context_pP->ue_context.measGapConfig, + (TDD_Config_t *) NULL, + NULL, + (uint8_t *) NULL, + (uint16_t *) NULL, NULL, NULL, NULL, (MBSFN_SubframeConfigList_t *) NULL +#ifdef Rel10 + , 0, (MBSFN_AreaInfoList_r9_t *) NULL, (PMCH_InfoList_r9_t *) NULL +#endif +#ifdef CBA + , 0, 0 +#endif + ); + break; + } + } + } + + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.Header, // LG WARNING + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size, + MSC_AS_TIME_FMT" RRCConnectionSetup UE %x size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_pP->ue_context.rnti, + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size); + + + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" [RAPROC] Logical Channel DL-CCCH, Generating RRCConnectionSetup (bytes %d)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size); + +} + +#if defined(ENABLE_ITTI) +char +//----------------------------------------------------------------------------- +openair_rrc_eNB_init( + const module_id_t enb_mod_idP +) +//----------------------------------------------------------------------------- +{ + /* Dummy function, initialization will be done through ITTI messaging */ + return 0; +} +#endif + +#if defined(ENABLE_ITTI) +//----------------------------------------------------------------------------- +char +openair_rrc_eNB_configuration( + const module_id_t enb_mod_idP, + RrcConfigurationReq* configuration +) +#else +char +openair_rrc_eNB_init( + const module_id_t enb_mod_idP +) +#endif +//----------------------------------------------------------------------------- +{ + protocol_ctxt_t ctxt; + int CC_id; + + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, enb_mod_idP, ENB_FLAG_YES, NOT_A_RNTI, 0, 0,enb_mod_idP); + LOG_I(RRC, + PROTOCOL_RRC_CTXT_FMT" Init...\n", + PROTOCOL_RRC_CTXT_ARGS(&ctxt)); + + AssertFatal(eNB_rrc_inst != NULL, "eNB_rrc_inst not initialized!"); + AssertFatal(NUMBER_OF_UE_MAX < (module_id_t)0xFFFFFFFFFFFFFFFF, " variable overflow"); + + // for (j = 0; j < NUMBER_OF_UE_MAX; j++) + // eNB_rrc_inst[ctxt.module_id].Info.UE[j].Status = RRC_IDLE; //CH_READY; + // + //#if defined(ENABLE_USE_MME) + // // Connect eNB to MME + // if (EPC_MODE_ENABLED <= 0) + //#endif + // { + // /* Init security parameters */ + // for (j = 0; j < NUMBER_OF_UE_MAX; j++) { + // eNB_rrc_inst[ctxt.module_id].ciphering_algorithm[j] = SecurityAlgorithmConfig__cipheringAlgorithm_eea0; + // eNB_rrc_inst[ctxt.module_id].integrity_algorithm[j] = SecurityAlgorithmConfig__integrityProtAlgorithm_eia2; + // rrc_eNB_init_security(enb_mod_idP, j); + // } + // } + eNB_rrc_inst[ctxt.module_id].Nb_ue = 0; + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + eNB_rrc_inst[ctxt.module_id].carrier[CC_id].Srb0.Active = 0; + } + + uid_linear_allocator_init(&eNB_rrc_inst[ctxt.module_id].uid_allocator); + RB_INIT(&eNB_rrc_inst[ctxt.module_id].rrc_ue_head); + // for (j = 0; j < (NUMBER_OF_UE_MAX + 1); j++) { + // eNB_rrc_inst[enb_mod_idP].Srb2[j].Active = 0; + // } + + + eNB_rrc_inst[ctxt.module_id].initial_id2_s1ap_ids = hashtable_create (NUMBER_OF_UE_MAX * 2, NULL, NULL); + eNB_rrc_inst[ctxt.module_id].s1ap_id2_s1ap_ids = hashtable_create (NUMBER_OF_UE_MAX * 2, NULL, NULL); + + + /// System Information INIT + + LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" Checking release \n", + PROTOCOL_RRC_CTXT_ARGS(&ctxt)); +#ifdef Rel10 + + // This has to come from some top-level configuration + // only CC_id 0 is logged + LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" Rel10 RRC detected, MBMS flag %d\n", + PROTOCOL_RRC_CTXT_ARGS(&ctxt), + eNB_rrc_inst[ctxt.module_id].carrier[0].MBMS_flag); + +#else + LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" Rel8 RRC\n", PROTOCOL_RRC_CTXT_ARGS(&ctxt)); +#endif +#ifdef CBA + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + for (j = 0; j < NUM_MAX_CBA_GROUP; j++) { + eNB_rrc_inst[ctxt.module_id].carrier[CC_id].cba_rnti[j] = CBA_OFFSET + j; + } + + if (eNB_rrc_inst[ctxt.module_id].carrier[CC_id].num_active_cba_groups > NUM_MAX_CBA_GROUP) { + eNB_rrc_inst[ctxt.module_id].carrier[CC_id].num_active_cba_groups = NUM_MAX_CBA_GROUP; + } + + LOG_D(RRC, + PROTOCOL_RRC_CTXT_FMT" Initialization of 4 cba_RNTI values (%x %x %x %x) num active groups %d\n", + PROTOCOL_RRC_CTXT_ARGS(&ctxt), + enb_mod_idP, eNB_rrc_inst[ctxt.module_id].carrier[CC_id].cba_rnti[0], + eNB_rrc_inst[ctxt.module_id].carrier[CC_id].cba_rnti[1], + eNB_rrc_inst[ctxt.module_id].carrier[CC_id].cba_rnti[2], + eNB_rrc_inst[ctxt.module_id].carrier[CC_id].cba_rnti[3], + eNB_rrc_inst[ctxt.module_id].carrier[CC_id].num_active_cba_groups); + } + +#endif + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + init_SI(&ctxt, + CC_id +#if defined(ENABLE_ITTI) + , configuration +#endif + ); + } + +#ifdef Rel10 + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + switch (eNB_rrc_inst[ctxt.module_id].carrier[CC_id].MBMS_flag) { + case 1: + case 2: + case 3: + LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" Configuring 1 MBSFN sync area\n", PROTOCOL_RRC_CTXT_ARGS(&ctxt)); + eNB_rrc_inst[ctxt.module_id].carrier[CC_id].num_mbsfn_sync_area = 1; + break; + + case 4: + LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" Configuring 2 MBSFN sync area\n", PROTOCOL_RRC_CTXT_ARGS(&ctxt)); + eNB_rrc_inst[ctxt.module_id].carrier[CC_id].num_mbsfn_sync_area = 2; + break; + + default: + eNB_rrc_inst[ctxt.module_id].carrier[CC_id].num_mbsfn_sync_area = 0; + break; + } + + // if we are here the eNB_rrc_inst[enb_mod_idP].MBMS_flag > 0, + /// MCCH INIT + if (eNB_rrc_inst[ctxt.module_id].carrier[CC_id].MBMS_flag > 0) { + init_MCCH(ctxt.module_id, CC_id); + /// MTCH data bearer init + init_MBMS(ctxt.module_id, CC_id, 0); + } + } + +#endif + +#ifdef NO_RRM //init ch SRB0, SRB1 & BDTCH + openair_rrc_on(&ctxt); +#else + eNB_rrc_inst[ctxt.module_id].Last_scan_req = 0; + send_msg(&S_rrc, msg_rrc_phy_synch_to_MR_ind(ctxt.module_id, eNB_rrc_inst[ctxt.module_id].Mac_id)); +#endif + + return 0; + +} + +/*------------------------------------------------------------------------------*/ +int +rrc_eNB_decode_ccch( + protocol_ctxt_t* const ctxt_pP, + const SRB_INFO* const Srb_info, + const int CC_id +) +//----------------------------------------------------------------------------- +{ + module_id_t Idx; + asn_dec_rval_t dec_rval; + UL_CCCH_Message_t *ul_ccch_msg = NULL; + RRCConnectionRequest_r8_IEs_t* rrcConnectionRequest = NULL; + RRCConnectionReestablishmentRequest_r8_IEs_t* rrcConnectionReestablishmentRequest = NULL; + int i, rval; + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint64_t random_value = 0; + int stmsi_received = 0; + + T(T_ENB_RRC_UL_CCCH_DATA_IN, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + //memset(ul_ccch_msg,0,sizeof(UL_CCCH_Message_t)); + + LOG_D(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Decoding UL CCCH %x.%x.%x.%x.%x.%x (%p)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + ((uint8_t*) Srb_info->Rx_buffer.Payload)[0], + ((uint8_t *) Srb_info->Rx_buffer.Payload)[1], + ((uint8_t *) Srb_info->Rx_buffer.Payload)[2], + ((uint8_t *) Srb_info->Rx_buffer.Payload)[3], + ((uint8_t *) Srb_info->Rx_buffer.Payload)[4], + ((uint8_t *) Srb_info->Rx_buffer.Payload)[5], (uint8_t *) Srb_info->Rx_buffer.Payload); + dec_rval = uper_decode( + NULL, + &asn_DEF_UL_CCCH_Message, + (void**)&ul_ccch_msg, + (uint8_t*) Srb_info->Rx_buffer.Payload, + 100, + 0, + 0); + +#if defined(ENABLE_ITTI) +# if defined(DISABLE_ITTI_XER_PRINT) + { + MessageDef *message_p; + + message_p = itti_alloc_new_message(TASK_RRC_ENB, RRC_UL_CCCH_MESSAGE); + memcpy(&message_p->ittiMsg, (void *)ul_ccch_msg, sizeof(RrcUlCcchMessage)); + + itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, message_p); + } +# else + { + char message_string[10000]; + size_t message_string_size; + + if ((message_string_size = + xer_sprint(message_string, sizeof(message_string), &asn_DEF_UL_CCCH_Message, (void *)ul_ccch_msg)) > 0) { + MessageDef *msg_p; + + msg_p = itti_alloc_new_message_sized(TASK_RRC_ENB, RRC_UL_CCCH, message_string_size + sizeof(IttiMsgText)); + msg_p->ittiMsg.rrc_ul_ccch.size = message_string_size; + memcpy(&msg_p->ittiMsg.rrc_ul_ccch.text, message_string, message_string_size); + + itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, msg_p); + } + } +# endif +#endif + + for (i = 0; i < 8; i++) { + LOG_T(RRC, "%x.", ((uint8_t *) & ul_ccch_msg)[i]); + } + + if (dec_rval.consumed == 0) { + LOG_E(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" FATAL Error in receiving CCCH\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + return -1; + } + + if (ul_ccch_msg->message.present == UL_CCCH_MessageType_PR_c1) { + + switch (ul_ccch_msg->message.choice.c1.present) { + + case UL_CCCH_MessageType__c1_PR_NOTHING: + LOG_I(RRC, + PROTOCOL_RRC_CTXT_FMT" Received PR_NOTHING on UL-CCCH-Message\n", + PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); + break; + + case UL_CCCH_MessageType__c1_PR_rrcConnectionReestablishmentRequest: + T(T_ENB_RRC_CONNECTION_REESTABLISHMENT_REQUEST, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC Connection Reestablishement Request\n"); + + for (i = 0; i < Srb_info->Rx_buffer.payload_size; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)Srb_info->Rx_buffer.Payload)[i]); + } + + LOG_F(RRC,"\n"); +#endif + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT"MAC_eNB--- MAC_DATA_IND (rrcConnectionReestablishmentRequest on SRB0) --> RRC_eNB\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + rrcConnectionReestablishmentRequest = + &ul_ccch_msg->message.choice.c1.choice.rrcConnectionReestablishmentRequest.criticalExtensions.choice.rrcConnectionReestablishmentRequest_r8; + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RRCConnectionReestablishmentRequest cause %s\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + ((rrcConnectionReestablishmentRequest->reestablishmentCause == ReestablishmentCause_otherFailure) ? "Other Failure" : + (rrcConnectionReestablishmentRequest->reestablishmentCause == ReestablishmentCause_handoverFailure) ? "Handover Failure" : + "reconfigurationFailure")); + /*{ + uint64_t c_rnti = 0; + + memcpy(((uint8_t *) & c_rnti) + 3, rrcConnectionReestablishmentRequest.UE_identity.c_RNTI.buf, + rrcConnectionReestablishmentRequest.UE_identity.c_RNTI.size); + ue_mod_id = rrc_eNB_get_UE_index(enb_mod_idP, c_rnti); + } + + if ((eNB_rrc_inst[enb_mod_idP].phyCellId == rrcConnectionReestablishmentRequest.UE_identity.physCellId) && + (ue_mod_id != UE_INDEX_INVALID)){ + rrc_eNB_generate_RRCConnectionReestablishment(enb_mod_idP, frameP, ue_mod_id); + }else { + rrc_eNB_generate_RRCConnectionReestablishmentReject(enb_mod_idP, frameP, ue_mod_id); + } + */ + /* reject all reestablishment attempts for the moment */ + rrc_eNB_generate_RRCConnectionReestablishmentReject(ctxt_pP, + rrc_eNB_get_ue_context(&eNB_rrc_inst[ctxt_pP->module_id], ctxt_pP->rnti), + CC_id); + break; + + case UL_CCCH_MessageType__c1_PR_rrcConnectionRequest: + T(T_ENB_RRC_CONNECTION_REQUEST, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC Connection Request\n"); + + for (i = 0; i < Srb_info->Rx_buffer.payload_size; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)Srb_info->Rx_buffer.Payload)[i]); + } + + LOG_F(RRC,"\n"); +#endif + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT"MAC_eNB --- MAC_DATA_IND (rrcConnectionRequest on SRB0) --> RRC_eNB\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + ue_context_p = rrc_eNB_get_ue_context( + &eNB_rrc_inst[ctxt_pP->module_id], + ctxt_pP->rnti); + + if (ue_context_p != NULL) { + // erase content + rrc_eNB_free_mem_UE_context(ctxt_pP, ue_context_p); + + MSC_LOG_RX_DISCARDED_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + Srb_info->Rx_buffer.Payload, + dec_rval.consumed, + MSC_AS_TIME_FMT" RRCConnectionRequest UE %x size %u (UE already in context)", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_p->ue_context.rnti, + dec_rval.consumed); + } else { + rrcConnectionRequest = &ul_ccch_msg->message.choice.c1.choice.rrcConnectionRequest.criticalExtensions.choice.rrcConnectionRequest_r8; + { + if (InitialUE_Identity_PR_randomValue == rrcConnectionRequest->ue_Identity.present) { + AssertFatal(rrcConnectionRequest->ue_Identity.choice.randomValue.size == 5, + "wrong InitialUE-Identity randomValue size, expected 5, provided %d", + rrcConnectionRequest->ue_Identity.choice.randomValue.size); + memcpy(((uint8_t*) & random_value) + 3, + rrcConnectionRequest->ue_Identity.choice.randomValue.buf, + rrcConnectionRequest->ue_Identity.choice.randomValue.size); + /* if there is already a registered UE (with another RNTI) with this random_value, + * the current one must be removed from MAC/PHY (zombie UE) + */ + if ((ue_context_p = rrc_eNB_ue_context_random_exist(ctxt_pP, random_value))) { +//#warning "TODO: random_exist: remove UE from MAC/PHY (how?)" + // AssertFatal(0 == 1, "TODO: remove UE from MAC/PHY (how?)"); + ue_context_p = NULL; + } else { + ue_context_p = rrc_eNB_get_next_free_ue_context(ctxt_pP, random_value); + } + } else if (InitialUE_Identity_PR_s_TMSI == rrcConnectionRequest->ue_Identity.present) { + /* Save s-TMSI */ + S_TMSI_t s_TMSI = rrcConnectionRequest->ue_Identity.choice.s_TMSI; + mme_code_t mme_code = BIT_STRING_to_uint8(&s_TMSI.mmec); + m_tmsi_t m_tmsi = BIT_STRING_to_uint32(&s_TMSI.m_TMSI); + random_value = (((uint64_t)mme_code) << 32) | m_tmsi; + if ((ue_context_p = rrc_eNB_ue_context_stmsi_exist(ctxt_pP, mme_code, m_tmsi))) { + + //#warning "TODO: stmsi_exist: remove UE from MAC/PHY (how?)" + LOG_I(RRC," S-TMSI exists, ue_context_p %p\n",ue_context_p); + stmsi_received=1; + ue_context_p->ue_context.rnti = ctxt_pP->rnti; + // AssertFatal(0 == 1, "TODO: remove UE from MAC/PHY (how?)"); + // ue_context_p = NULL; + } else { + ue_context_p = rrc_eNB_get_next_free_ue_context(ctxt_pP, NOT_A_RANDOM_UE_IDENTITY); + ue_context_p->ue_context.Initialue_identity_s_TMSI.presence = TRUE; + ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code = mme_code; + ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi = m_tmsi; + } + + MSC_LOG_RX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + Srb_info->Rx_buffer.Payload, + dec_rval.consumed, + MSC_AS_TIME_FMT" RRCConnectionRequest UE %x size %u (s-TMSI mmec %u m_TMSI %u random UE id (0x%" PRIx64 ")", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_p->ue_context.rnti, + dec_rval.consumed, + ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code, + ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, + ue_context_p->ue_context.random_ue_identity); + } else { + LOG_E(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RRCConnectionRequest without random UE identity or S-TMSI not supported, let's reject the UE\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + rrc_eNB_generate_RRCConnectionReject(ctxt_pP, + rrc_eNB_get_ue_context(&eNB_rrc_inst[ctxt_pP->module_id], ctxt_pP->rnti), + CC_id); + break; + } + + } + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" UE context: %X\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + ue_context_p); + + if (ue_context_p != NULL) { + + +#if defined(ENABLE_ITTI) + ue_context_p->ue_context.establishment_cause = rrcConnectionRequest->establishmentCause; + if (stmsi_received==0) + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Accept new connection from UE random UE identity (0x%" PRIx64 ") MME code %u TMSI %u cause %u\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + ue_context_p->ue_context.random_ue_identity, + ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code, + ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, + ue_context_p->ue_context.establishment_cause); + else + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Accept new connection from UE MME code %u TMSI %u cause %u\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code, + ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, + ue_context_p->ue_context.establishment_cause); +#else + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Accept new connection for UE random UE identity (0x%" PRIx64 ")\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + ue_context_p->ue_context.random_ue_identity); +#endif + if (stmsi_received == 0) + eNB_rrc_inst[ctxt_pP->module_id].Nb_ue++; + + } else { + // no context available + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Can't create new context for UE random UE identity (0x%" PRIx64 ")\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + random_value); + return -1; + } + } + +#ifndef NO_RRM + send_msg(&S_rrc, msg_rrc_MR_attach_ind(ctxt_pP->module_id, Mac_id)); +#else + + ue_context_p->ue_context.primaryCC_id = CC_id; + + //LG COMMENT Idx = (ue_mod_idP * NB_RB_MAX) + DCCH; + Idx = DCCH; + // SRB1 + ue_context_p->ue_context.Srb1.Active = 1; + ue_context_p->ue_context.Srb1.Srb_info.Srb_id = Idx; + memcpy(&ue_context_p->ue_context.Srb1.Srb_info.Lchan_desc[0], + &DCCH_LCHAN_DESC, + LCHAN_DESC_SIZE); + memcpy(&ue_context_p->ue_context.Srb1.Srb_info.Lchan_desc[1], + &DCCH_LCHAN_DESC, + LCHAN_DESC_SIZE); + + // SRB2 + ue_context_p->ue_context.Srb2.Active = 1; + ue_context_p->ue_context.Srb2.Srb_info.Srb_id = Idx; + memcpy(&ue_context_p->ue_context.Srb2.Srb_info.Lchan_desc[0], + &DCCH_LCHAN_DESC, + LCHAN_DESC_SIZE); + memcpy(&ue_context_p->ue_context.Srb2.Srb_info.Lchan_desc[1], + &DCCH_LCHAN_DESC, + LCHAN_DESC_SIZE); + + rrc_eNB_generate_RRCConnectionSetup(ctxt_pP, ue_context_p, CC_id); + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT"CALLING RLC CONFIG SRB1 (rbid %d)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + Idx); + + MSC_LOG_TX_MESSAGE( + MSC_RRC_ENB, + MSC_PDCP_ENB, + NULL, + 0, + MSC_AS_TIME_FMT" CONFIG_REQ UE %x SRB", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_p->ue_context.rnti); + + rrc_pdcp_config_asn1_req(ctxt_pP, + ue_context_p->ue_context.SRB_configList, + (DRB_ToAddModList_t *) NULL, + (DRB_ToReleaseList_t*) NULL, + 0xff, + NULL, + NULL, + NULL +# ifdef Rel10 + , (PMCH_InfoList_r9_t *) NULL +# endif + ); + + rrc_rlc_config_asn1_req(ctxt_pP, + ue_context_p->ue_context.SRB_configList, + (DRB_ToAddModList_t*) NULL, + (DRB_ToReleaseList_t*) NULL +# ifdef Rel10 + , (PMCH_InfoList_r9_t *) NULL +# endif + ); +#endif //NO_RRM + + break; + + default: + LOG_E(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Unknown message\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + rval = -1; + break; + } + + rval = 0; + } else { + LOG_E(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Unknown error \n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + rval = -1; + } + + return rval; +} + +//----------------------------------------------------------------------------- +int +rrc_eNB_decode_dcch( + const protocol_ctxt_t* const ctxt_pP, + const rb_id_t Srb_id, + const uint8_t* const Rx_sdu, + const sdu_size_t sdu_sizeP +) +//----------------------------------------------------------------------------- +{ + + asn_dec_rval_t dec_rval; + //UL_DCCH_Message_t uldcchmsg; + UL_DCCH_Message_t *ul_dcch_msg = NULL; //&uldcchmsg; + UE_EUTRA_Capability_t *UE_EUTRA_Capability = NULL; + int i; + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + + T(T_ENB_RRC_UL_DCCH_DATA_IN, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + if ((Srb_id != 1) && (Srb_id != 2)) { + LOG_E(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Received message on SRB%d, should not have ...\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + Srb_id); + } + + //memset(ul_dcch_msg,0,sizeof(UL_DCCH_Message_t)); + + LOG_D(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Decoding UL-DCCH Message\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + dec_rval = uper_decode( + NULL, + &asn_DEF_UL_DCCH_Message, + (void**)&ul_dcch_msg, + Rx_sdu, + sdu_sizeP, + 0, + 0); + +#if defined(ENABLE_ITTI) +# if defined(DISABLE_ITTI_XER_PRINT) + { + MessageDef *message_p; + + message_p = itti_alloc_new_message(TASK_RRC_ENB, RRC_UL_DCCH_MESSAGE); + memcpy(&message_p->ittiMsg, (void *)ul_dcch_msg, sizeof(RrcUlDcchMessage)); + + itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, message_p); + } +# else + { + char message_string[10000]; + size_t message_string_size; + + if ((message_string_size = + xer_sprint(message_string, sizeof(message_string), &asn_DEF_UL_DCCH_Message, (void *)ul_dcch_msg)) >= 0) { + MessageDef *msg_p; + + msg_p = itti_alloc_new_message_sized(TASK_RRC_ENB, RRC_UL_DCCH, message_string_size + sizeof(IttiMsgText)); + msg_p->ittiMsg.rrc_ul_dcch.size = message_string_size; + memcpy(&msg_p->ittiMsg.rrc_ul_dcch.text, message_string, message_string_size); + + itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, msg_p); + } + } +# endif +#endif + + { + for (i = 0; i < sdu_sizeP; i++) { + LOG_T(RRC, "%x.", Rx_sdu[i]); + } + + LOG_T(RRC, "\n"); + } + + if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { + LOG_E(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Failed to decode UL-DCCH (%d bytes)\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + dec_rval.consumed); + return -1; + } + + ue_context_p = rrc_eNB_get_ue_context( + &eNB_rrc_inst[ctxt_pP->module_id], + ctxt_pP->rnti); + + if (ul_dcch_msg->message.present == UL_DCCH_MessageType_PR_c1) { + + switch (ul_dcch_msg->message.choice.c1.present) { + case UL_DCCH_MessageType__c1_PR_NOTHING: /* No components present */ + break; + + case UL_DCCH_MessageType__c1_PR_csfbParametersRequestCDMA2000: + break; + + case UL_DCCH_MessageType__c1_PR_measurementReport: + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RLC RB %02d --- RLC_DATA_IND " + "%d bytes (measurementReport) ---> RRC_eNB\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + DCCH, + sdu_sizeP); + rrc_eNB_process_MeasurementReport( + ctxt_pP, + ue_context_p, + &ul_dcch_msg->message.choice.c1.choice.measurementReport. + criticalExtensions.choice.c1.choice.measurementReport_r8.measResults); + break; + + case UL_DCCH_MessageType__c1_PR_rrcConnectionReconfigurationComplete: +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC Connection Reconfiguration Complete\n"); + + for (i = 0; i < sdu_sizeP; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); + } + + LOG_F(RRC,"\n"); +#endif + MSC_LOG_RX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + Rx_sdu, + sdu_sizeP, + MSC_AS_TIME_FMT" RRCConnectionReconfigurationComplete UE %x size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_p->ue_context.rnti, + sdu_sizeP); + + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RLC RB %02d --- RLC_DATA_IND %d bytes " + "(RRCConnectionReconfigurationComplete) ---> RRC_eNB]\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + DCCH, + sdu_sizeP); + + if (ul_dcch_msg->message.choice.c1.choice.rrcConnectionReconfigurationComplete.criticalExtensions. + present == + RRCConnectionReconfigurationComplete__criticalExtensions_PR_rrcConnectionReconfigurationComplete_r8) { + rrc_eNB_process_RRCConnectionReconfigurationComplete( + ctxt_pP, + ue_context_p, + &ul_dcch_msg->message.choice.c1.choice. + rrcConnectionReconfigurationComplete. + criticalExtensions.choice. + rrcConnectionReconfigurationComplete_r8); + ue_context_p->ue_context.Status = RRC_RECONFIGURED; + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_RECONFIGURED \n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + //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]->enb_agent_notify_ue_state_change(ctxt_pP->module_id, + ue_context_p->ue_id_rnti, + PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_UPDATED); + } + } + +#if defined(ENABLE_USE_MME) +# if defined(ENABLE_ITTI) + + if (EPC_MODE_ENABLED == 1) { + rrc_eNB_send_S1AP_INITIAL_CONTEXT_SETUP_RESP( + ctxt_pP, + ue_context_p); + } + +# endif +#endif + break; + + case UL_DCCH_MessageType__c1_PR_rrcConnectionReestablishmentComplete: + T(T_ENB_RRC_CONNECTION_REESTABLISHMENT_COMPLETE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC Connection Reestablishment Complete\n"); + + for (i = 0; i < sdu_sizeP; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); + } + + LOG_F(RRC,"\n"); +#endif + + MSC_LOG_RX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + Rx_sdu, + sdu_sizeP, + MSC_AS_TIME_FMT" rrcConnectionReestablishmentComplete UE %x size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_p->ue_context.rnti, + sdu_sizeP); + + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RLC RB %02d --- RLC_DATA_IND %d bytes " + "(rrcConnectionReestablishmentComplete) ---> RRC_eNB\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + DCCH, + sdu_sizeP); + break; + + case UL_DCCH_MessageType__c1_PR_rrcConnectionSetupComplete: +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC Connection SetupComplete\n"); + + for (i = 0; i < sdu_sizeP; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); + } + + LOG_F(RRC,"\n"); +#endif + + MSC_LOG_RX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + Rx_sdu, + sdu_sizeP, + MSC_AS_TIME_FMT" RRCConnectionSetupComplete UE %x size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_p->ue_context.rnti, + sdu_sizeP); + + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RLC RB %02d --- RLC_DATA_IND %d bytes " + "(RRCConnectionSetupComplete) ---> RRC_eNB\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + DCCH, + sdu_sizeP); + + if (ul_dcch_msg->message.choice.c1.choice.rrcConnectionSetupComplete.criticalExtensions.present == + RRCConnectionSetupComplete__criticalExtensions_PR_c1) { + if (ul_dcch_msg->message.choice.c1.choice.rrcConnectionSetupComplete.criticalExtensions.choice.c1. + present == + RRCConnectionSetupComplete__criticalExtensions__c1_PR_rrcConnectionSetupComplete_r8) { + rrc_eNB_process_RRCConnectionSetupComplete( + ctxt_pP, + ue_context_p, + &ul_dcch_msg->message.choice.c1.choice.rrcConnectionSetupComplete.criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8); + ue_context_p->ue_context.Status = RRC_CONNECTED; + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_CONNECTED \n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + //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]->enb_agent_notify_ue_state_change(ctxt_pP->module_id, + ue_context_p->ue_id_rnti, + PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_ACTIVATED); + } + } + } + + break; + + case UL_DCCH_MessageType__c1_PR_securityModeComplete: + T(T_ENB_RRC_SECURITY_MODE_COMPLETE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC Security Mode Complete\n"); + + for (i = 0; i < sdu_sizeP; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); + } + + LOG_F(RRC,"\n"); +#endif + + MSC_LOG_RX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + Rx_sdu, + sdu_sizeP, + MSC_AS_TIME_FMT" securityModeComplete UE %x size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_p->ue_context.rnti, + sdu_sizeP); + + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" received securityModeComplete on UL-DCCH %d from UE\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + DCCH); + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RLC RB %02d --- RLC_DATA_IND %d bytes " + "(securityModeComplete) ---> RRC_eNB\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + DCCH, + sdu_sizeP); +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_UL_DCCH_Message, (void *)ul_dcch_msg); +#endif + // confirm with PDCP about the security mode for DCCH + //rrc_pdcp_config_req (enb_mod_idP, frameP, 1,CONFIG_ACTION_SET_SECURITY_MODE, (ue_mod_idP * NB_RB_MAX) + DCCH, 0x77); + // continue the procedure + rrc_eNB_generate_UECapabilityEnquiry( + ctxt_pP, + ue_context_p); + break; + + case UL_DCCH_MessageType__c1_PR_securityModeFailure: + T(T_ENB_RRC_SECURITY_MODE_FAILURE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC Security Mode Failure\n"); + + for (i = 0; i < sdu_sizeP; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); + } + + LOG_F(RRC,"\n"); +#endif + + MSC_LOG_RX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + Rx_sdu, + sdu_sizeP, + MSC_AS_TIME_FMT" securityModeFailure UE %x size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_p->ue_context.rnti, + sdu_sizeP); + + LOG_W(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RLC RB %02d --- RLC_DATA_IND %d bytes " + "(securityModeFailure) ---> RRC_eNB\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + DCCH, + sdu_sizeP); +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_UL_DCCH_Message, (void *)ul_dcch_msg); +#endif + // cancel the security mode in PDCP + + // followup with the remaining procedure +//#warning "LG Removed rrc_eNB_generate_UECapabilityEnquiry after receiving securityModeFailure" + rrc_eNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p); + break; + + case UL_DCCH_MessageType__c1_PR_ueCapabilityInformation: + T(T_ENB_RRC_UE_CAPABILITY_INFORMATION, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC UECapablility Information \n"); + + for (i = 0; i < sdu_sizeP; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); + } + + LOG_F(RRC,"\n"); +#endif + + MSC_LOG_RX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + Rx_sdu, + sdu_sizeP, + MSC_AS_TIME_FMT" ueCapabilityInformation UE %x size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_p->ue_context.rnti, + sdu_sizeP); + + LOG_I(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" received ueCapabilityInformation on UL-DCCH %d from UE\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + DCCH); + LOG_D(RRC, + PROTOCOL_RRC_CTXT_UE_FMT" RLC RB %02d --- RLC_DATA_IND %d bytes " + "(UECapabilityInformation) ---> RRC_eNB\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + DCCH, + sdu_sizeP); +#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_UL_DCCH_Message, (void *)ul_dcch_msg); +#endif + dec_rval = uper_decode(NULL, + &asn_DEF_UE_EUTRA_Capability, + (void **)&UE_EUTRA_Capability, + ul_dcch_msg->message.choice.c1.choice.ueCapabilityInformation.criticalExtensions. + choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list. + array[0]->ueCapabilityRAT_Container.buf, + ul_dcch_msg->message.choice.c1.choice.ueCapabilityInformation.criticalExtensions. + choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list. + array[0]->ueCapabilityRAT_Container.size, 0, 0); + //#ifdef XER_PRINT + xer_fprint(stdout, &asn_DEF_UE_EUTRA_Capability, (void *)UE_EUTRA_Capability); + //#endif + +#if defined(ENABLE_USE_MME) + + if (EPC_MODE_ENABLED == 1) { + rrc_eNB_send_S1AP_UE_CAPABILITIES_IND(ctxt_pP, + ue_context_p, + ul_dcch_msg); + } + +#endif + + rrc_eNB_generate_defaultRRCConnectionReconfiguration(ctxt_pP, + ue_context_p, + eNB_rrc_inst[ctxt_pP->module_id].HO_flag); + break; + + case UL_DCCH_MessageType__c1_PR_ulHandoverPreparationTransfer: + T(T_ENB_RRC_UL_HANDOVER_PREPARATION_TRANSFER, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + break; + + case UL_DCCH_MessageType__c1_PR_ulInformationTransfer: + T(T_ENB_RRC_UL_INFORMATION_TRANSFER, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + +#ifdef RRC_MSG_PRINT + LOG_F(RRC,"[MSG] RRC UL Information Transfer \n"); + + for (i = 0; i < sdu_sizeP; i++) { + LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); + } + + LOG_F(RRC,"\n"); +#endif + + + MSC_LOG_RX_MESSAGE( + MSC_RRC_ENB, + MSC_RRC_UE, + Rx_sdu, + sdu_sizeP, + MSC_AS_TIME_FMT" ulInformationTransfer UE %x size %u", + MSC_AS_TIME_ARGS(ctxt_pP), + ue_context_p->ue_context.rnti, + sdu_sizeP); + +#if defined(ENABLE_USE_MME) + + if (EPC_MODE_ENABLED == 1) { + rrc_eNB_send_S1AP_UPLINK_NAS(ctxt_pP, + ue_context_p, + ul_dcch_msg); + } + +#endif + break; + + case UL_DCCH_MessageType__c1_PR_counterCheckResponse: + T(T_ENB_RRC_COUNTER_CHECK_RESPONSE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + break; + +#ifdef Rel10 + + case UL_DCCH_MessageType__c1_PR_ueInformationResponse_r9: + T(T_ENB_RRC_UE_INFORMATION_RESPONSE_R9, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + break; + + case UL_DCCH_MessageType__c1_PR_proximityIndication_r9: + T(T_ENB_RRC_PROXIMITY_INDICATION_R9, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + break; + + case UL_DCCH_MessageType__c1_PR_rnReconfigurationComplete_r10: + T(T_ENB_RRC_RECONFIGURATION_COMPLETE_R10, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + break; + + case UL_DCCH_MessageType__c1_PR_mbmsCountingResponse_r10: + T(T_ENB_RRC_MBMS_COUNTING_RESPONSE_R10, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + break; + + case UL_DCCH_MessageType__c1_PR_interFreqRSTDMeasurementIndication_r10: + T(T_ENB_RRC_INTER_FREQ_RSTD_MEASUREMENT_INDICATION, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + break; +#endif + + default: + T(T_ENB_RRC_UNKNOW_MESSAGE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); + + LOG_E(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Unknown message %s:%u\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + __FILE__, __LINE__); + return -1; + } + + return 0; + } else { + LOG_E(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Unknown error %s:%u\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + __FILE__, __LINE__); + return -1; + } + +} + +#if defined(ENABLE_ITTI) +//----------------------------------------------------------------------------- +void* +rrc_enb_task( + void* args_p +) +//----------------------------------------------------------------------------- +{ + MessageDef *msg_p; + const char *msg_name_p; + instance_t instance; + int result; + SRB_INFO *srb_info_p; + int CC_id; + + protocol_ctxt_t ctxt; + itti_mark_task_ready(TASK_RRC_ENB); + + while (1) { + // Wait for a message + itti_receive_msg(TASK_RRC_ENB, &msg_p); + + msg_name_p = ITTI_MSG_NAME(msg_p); + instance = ITTI_MSG_INSTANCE(msg_p); + + switch (ITTI_MSG_ID(msg_p)) { + case TERMINATE_MESSAGE: + itti_exit_task(); + break; + + case MESSAGE_TEST: + LOG_I(RRC, "[eNB %d] Received %s\n", instance, msg_name_p); + break; + + /* Messages from MAC */ + case RRC_MAC_CCCH_DATA_IND: + PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, + instance, + ENB_FLAG_YES, + RRC_MAC_CCCH_DATA_IND(msg_p).rnti, + msg_p->ittiMsgHeader.lte_time.frame, + msg_p->ittiMsgHeader.lte_time.slot); + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Received %s\n", + PROTOCOL_RRC_CTXT_UE_ARGS(&ctxt), + msg_name_p); + + CC_id = RRC_MAC_CCCH_DATA_IND(msg_p).CC_id; + srb_info_p = &eNB_rrc_inst[instance].carrier[CC_id].Srb0; + + memcpy(srb_info_p->Rx_buffer.Payload, + RRC_MAC_CCCH_DATA_IND(msg_p).sdu, + RRC_MAC_CCCH_DATA_IND(msg_p).sdu_size); + srb_info_p->Rx_buffer.payload_size = RRC_MAC_CCCH_DATA_IND(msg_p).sdu_size; + rrc_eNB_decode_ccch(&ctxt, srb_info_p, CC_id); + break; + + /* Messages from PDCP */ + case RRC_DCCH_DATA_IND: + PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, + instance, + ENB_FLAG_YES, + RRC_DCCH_DATA_IND(msg_p).rnti, + msg_p->ittiMsgHeader.lte_time.frame, + msg_p->ittiMsgHeader.lte_time.slot); + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Received on DCCH %d %s\n", + PROTOCOL_RRC_CTXT_UE_ARGS(&ctxt), + RRC_DCCH_DATA_IND(msg_p).dcch_index, + msg_name_p); + rrc_eNB_decode_dcch(&ctxt, + RRC_DCCH_DATA_IND(msg_p).dcch_index, + RRC_DCCH_DATA_IND(msg_p).sdu_p, + RRC_DCCH_DATA_IND(msg_p).sdu_size); + + // Message buffer has been processed, free it now. + result = itti_free(ITTI_MSG_ORIGIN_ID(msg_p), RRC_DCCH_DATA_IND(msg_p).sdu_p); + AssertFatal(result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + break; + +# if defined(ENABLE_USE_MME) + + /* Messages from S1AP */ + case S1AP_DOWNLINK_NAS: + rrc_eNB_process_S1AP_DOWNLINK_NAS(msg_p, msg_name_p, instance, &rrc_eNB_mui); + break; + + case S1AP_INITIAL_CONTEXT_SETUP_REQ: + rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ(msg_p, msg_name_p, instance); + break; + + case S1AP_UE_CTXT_MODIFICATION_REQ: + rrc_eNB_process_S1AP_UE_CTXT_MODIFICATION_REQ(msg_p, msg_name_p, instance); + break; + + case S1AP_PAGING_IND: + LOG_E(RRC, "[eNB %d] Received not yet implemented message %s\n", instance, msg_name_p); + break; + + case S1AP_UE_CONTEXT_RELEASE_REQ: + rrc_eNB_process_S1AP_UE_CONTEXT_RELEASE_REQ(msg_p, msg_name_p, instance); + break; + + case S1AP_UE_CONTEXT_RELEASE_COMMAND: + rrc_eNB_process_S1AP_UE_CONTEXT_RELEASE_COMMAND(msg_p, msg_name_p, instance); + break; + + case GTPV1U_ENB_DELETE_TUNNEL_RESP: + /* Nothing to do. Apparently everything is done in S1AP processing */ + //LOG_I(RRC, "[eNB %d] Received message %s, not processed because procedure not synched\n", + //instance, msg_name_p); + break; + +# endif + + /* Messages from eNB app */ + case RRC_CONFIGURATION_REQ: + LOG_I(RRC, "[eNB %d] Received %s\n", instance, msg_name_p); + openair_rrc_eNB_configuration(ENB_INSTANCE_TO_MODULE_ID(instance), &RRC_CONFIGURATION_REQ(msg_p)); + break; + +# if ENABLE_RAL + + case RRC_RAL_CONFIGURE_THRESHOLD_REQ: + rrc_enb_ral_handle_configure_threshold_request(instance, msg_p); + break; + + //SPECTRA: Add the RRC connection reconfiguration with Second cell configuration + case RRC_RAL_CONNECTION_RECONFIGURATION_REQ: + // ue_mod_id = 0; /* TODO force ue_mod_id to first UE, NAS UE not virtualized yet */ +//#warning "TODO GET RIGHT RNTI" + PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, + instance, + ENB_FLAG_YES, + NOT_A_RNTI, // TO DO GET RIGHT RNTI + msg_p->ittiMsgHeader.lte_time.frame, + msg_p->ittiMsgHeader.lte_time.slot); + LOG_I(RRC, "[eNB %d] Send RRC_RAL_CONNECTION_RECONFIGURATION_REQ to UE %s\n", instance, msg_name_p); + //Method RRC connection reconfiguration command with Second cell configuration + //rrc_eNB_generate_RRCConnectionReconfiguration_SCell(instance, 0/* TODO put frameP number ! */, /*ue_mod_id force ue_mod_id to first UE*/0, 36126); + //rrc_eNB_generate_defaultRRCConnectionReconfiguration(instance, 0/* TODO put frameP number ! */, /*ue_mod_id force ue_mod_id to first UE*/0, + // eNB_rrc_inst[instance].HO_flag); + break; +# endif + + default: + LOG_E(RRC, "[eNB %d] Received unexpected message %s\n", instance, msg_name_p); + break; + } + + result = itti_free(ITTI_MSG_ORIGIN_ID(msg_p), msg_p); + AssertFatal(result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + msg_p = NULL; + } +} +#endif + +#ifndef USER_MODE +EXPORT_SYMBOL(Rlc_info_am_config); +#endif From cd8cc1a35c8d07b2782ef79865b12200e75dde0b Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Fri, 1 Jul 2016 13:19:18 +0200 Subject: [PATCH 199/413] added ue_transmission_mode and nb_antenna_ports to eNB config file transmisison mode gets set with RRCReconfiguration --- openair2/ENB_APP/enb_app.c | 3 ++ openair2/ENB_APP/enb_config.c | 46 ++++++++++++++++++- openair2/ENB_APP/enb_config.h | 7 +-- openair2/RRC/LITE/defs.h | 3 ++ openair2/RRC/LITE/rrc_eNB.c | 19 ++++++-- .../CONF/enb.band7.exmimo2.conf | 9 ++-- .../CONF/enb.band7.tm1.exmimo2.conf | 3 ++ targets/SIMU/USER/init_lte.c | 24 +++++----- targets/SIMU/USER/init_lte.h | 4 +- targets/SIMU/USER/oaisim_functions.c | 19 +++++++- 10 files changed, 109 insertions(+), 28 deletions(-) diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 6d95c215db..7ce2a0fa6d 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -187,6 +187,9 @@ static void configure_rrc(uint32_t enb_id, const Enb_properties_array_t *enb_pro RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n310[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_n310[CC_id]; RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t311[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_t311[CC_id]; RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n311[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_n311[CC_id]; + + RRC_CONFIGURATION_REQ (msg_p).ue_TransmissionMode[CC_id] = enb_properties->properties[enb_id]->ue_TransmissionMode[CC_id]; + } itti_send_msg_to_task (TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index d2f5c0dda5..0dad2a10ee 100755 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -84,6 +84,7 @@ #define ENB_CONFIG_STRING_NID_CELL "Nid_cell" #define ENB_CONFIG_STRING_N_RB_DL "N_RB_DL" #define ENB_CONFIG_STRING_CELL_MBSFN "Nid_cell_mbsfn" +#define ENB_CONFIG_STRING_NB_ANT_PORTS "nb_antenna_ports" #define ENB_CONFIG_STRING_NB_ANT_TX "nb_antennas_tx" #define ENB_CONFIG_STRING_NB_ANT_RX "nb_antennas_rx" #define ENB_CONFIG_STRING_TX_GAIN "tx_gain" @@ -145,6 +146,7 @@ #define ENB_CONFIG_STRING_UETIMERS_T311 "ue_TimersAndConstants_t311" #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_SRB1 "srb1_parameters" #define ENB_CONFIG_STRING_SRB1_TIMER_POLL_RETRANSMIT "timer_poll_retransmit" @@ -322,6 +324,7 @@ void enb_config_display(void) printf( "\n\tCell ID for CC %d:\t%"PRId16":\n",j,enb_properties.properties[i]->Nid_cell[j]); printf( "\tN_RB_DL for CC %d:\t%"PRId16":\n",j,enb_properties.properties[i]->N_RB_DL[j]); + printf( "\tnb_antenna_ports for CC %d:\t%d:\n",j,enb_properties.properties[i]->nb_antenna_ports[j]); printf( "\tnb_antennas_tx for CC %d:\t%d:\n",j,enb_properties.properties[i]->nb_antennas_tx[j]); printf( "\tnb_antennas_rx for CC %d:\t%d:\n",j,enb_properties.properties[i]->nb_antennas_rx[j]); @@ -411,6 +414,8 @@ void enb_config_display(void) printf( "\tue_TimersAndConstants_t311 for CC %d:\t%ld:\n",j,enb_properties.properties[i]->ue_TimersAndConstants_t311[j]); printf( "\tue_TimersAndConstants_n311 for CC %d:\t%ld:\n",j,enb_properties.properties[i]->ue_TimersAndConstants_n311[j]); + printf( "\tue_TransmissionMode for CC %d:\t%ld:\n",j,enb_properties.properties[i]->ue_TransmissionMode[j]); + } for (j=0; j < enb_properties.properties[i]->num_otg_elements; j++) { @@ -526,6 +531,7 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) libconfig_int Nid_cell = 0; libconfig_int Nid_cell_mbsfn = 0; libconfig_int N_RB_DL = 0; + libconfig_int nb_antenna_ports = 0; libconfig_int nb_antennas_tx = 0; libconfig_int nb_antennas_rx = 0; libconfig_int tx_gain = 0; @@ -589,7 +595,7 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) libconfig_int ue_TimersAndConstants_t311 = 0; libconfig_int ue_TimersAndConstants_n310 = 0; libconfig_int ue_TimersAndConstants_n311 = 0; - + libconfig_int ue_TransmissionMode = 0; libconfig_int srb1_timer_poll_retransmit = 0; @@ -797,6 +803,7 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) && config_setting_lookup_int(component_carrier, ENB_CONFIG_STRING_NID_CELL, &Nid_cell) && config_setting_lookup_int(component_carrier, ENB_CONFIG_STRING_N_RB_DL, &N_RB_DL) && config_setting_lookup_int(component_carrier, ENB_CONFIG_STRING_CELL_MBSFN, &Nid_cell_mbsfn) + && config_setting_lookup_int(component_carrier, ENB_CONFIG_STRING_NB_ANT_PORTS, &nb_antenna_ports) && config_setting_lookup_int(component_carrier, ENB_CONFIG_STRING_NB_ANT_TX, &nb_antennas_tx) && config_setting_lookup_int(component_carrier, ENB_CONFIG_STRING_NB_ANT_RX, &nb_antennas_rx) && config_setting_lookup_int(component_carrier, ENB_CONFIG_STRING_TX_GAIN, &tx_gain) @@ -852,6 +859,7 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) && config_setting_lookup_int(component_carrier, ENB_CONFIG_STRING_UETIMERS_T311, &ue_TimersAndConstants_t311) && config_setting_lookup_int(component_carrier, ENB_CONFIG_STRING_UETIMERS_N310, &ue_TimersAndConstants_n310) && config_setting_lookup_int(component_carrier, ENB_CONFIG_STRING_UETIMERS_N311, &ue_TimersAndConstants_n311) + && config_setting_lookup_int(component_carrier, ENB_CONFIG_STRING_UE_TRANSMISSION_MODE, &ue_TransmissionMode) #ifdef Rel10 @@ -968,6 +976,13 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) enb_properties.properties[enb_properties_index]->nb_antennas_tx[j] = nb_antennas_tx; + if ((nb_antenna_ports <1) || (nb_antenna_ports > 2)) + AssertError (0, parse_errors ++, + "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for nb_antenna_ports choice: 1..2 !\n", + lib_config_file_name_pP, i, nb_antenna_ports); + + enb_properties.properties[enb_properties_index]->nb_antenna_ports[j] = nb_antenna_ports; + if ((nb_antennas_tx <1) || (nb_antennas_tx > 64)) AssertError (0, parse_errors ++, "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for nb_antennas_tx choice: 1..64 !\n", @@ -1832,6 +1847,35 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) break; } + + switch (ue_TransmissionMode) { + case 1: + enb_properties.properties[enb_properties_index]->ue_TransmissionMode[j] = AntennaInfoDedicated__transmissionMode_tm1; + break; + case 2: + enb_properties.properties[enb_properties_index]->ue_TransmissionMode[j] = AntennaInfoDedicated__transmissionMode_tm2; + break; + case 3: + enb_properties.properties[enb_properties_index]->ue_TransmissionMode[j] = AntennaInfoDedicated__transmissionMode_tm3; + break; + case 4: + enb_properties.properties[enb_properties_index]->ue_TransmissionMode[j] = AntennaInfoDedicated__transmissionMode_tm4; + break; + case 5: + enb_properties.properties[enb_properties_index]->ue_TransmissionMode[j] = AntennaInfoDedicated__transmissionMode_tm5; + break; + case 6: + enb_properties.properties[enb_properties_index]->ue_TransmissionMode[j] = AntennaInfoDedicated__transmissionMode_tm6; + break; + case 7: + enb_properties.properties[enb_properties_index]->ue_TransmissionMode[j] = AntennaInfoDedicated__transmissionMode_tm7; + break; + default: + AssertError (0, parse_errors ++, + "Failed to parse eNB configuration file %s, enb %d unknown value \"%d\" for ue_TransmissionMode choice: 1,2,3,4,5,6,7", + lib_config_file_name_pP, i, ue_TransmissionMode); + break; + } } } diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h index 5f7f2636a3..4bdaf67514 100755 --- a/openair2/ENB_APP/enb_config.h +++ b/openair2/ENB_APP/enb_config.h @@ -136,9 +136,10 @@ typedef struct Enb_properties_s { int16_t Nid_cell[1+MAX_NUM_CCs];// for testing, change later int16_t N_RB_DL[1+MAX_NUM_CCs];// for testing, change later - int nb_antennas_tx[1+MAX_NUM_CCs]; + int nb_antenna_ports[1+MAX_NUM_CCs]; + int nb_antennas_tx[1+MAX_NUM_CCs]; int nb_antennas_rx[1+MAX_NUM_CCs]; - int tx_gain[1+MAX_NUM_CCs]; + int tx_gain[1+MAX_NUM_CCs]; int rx_gain[1+MAX_NUM_CCs]; long prach_root[1+MAX_NUM_CCs]; long prach_config_index[1+MAX_NUM_CCs]; @@ -198,7 +199,7 @@ typedef struct Enb_properties_s { long ue_TimersAndConstants_t311[1+MAX_NUM_CCs]; long ue_TimersAndConstants_n310[1+MAX_NUM_CCs]; long ue_TimersAndConstants_n311[1+MAX_NUM_CCs]; - + long ue_TransmissionMode[1+MAX_NUM_CCs]; long srb1_timer_poll_retransmit; long srb1_timer_reordering; diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index 78240de082..2603cbbb01 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -430,6 +430,9 @@ typedef struct eNB_RRC_INST_s { /// localization list for aggregated measurements from PHY struct list loc_list; #endif + + //pointer to configuration + RrcConfigurationReq *configuration; } eNB_RRC_INST; #define MAX_UE_CAPABILITY_SIZE 255 diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 6b591e0c35..90cf172f37 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -1133,8 +1133,8 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration( 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; + 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; @@ -1360,6 +1360,14 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration( //sps_RA_ConfigList_rlola = NULL; #endif + //change the transmission mode for the primary component carrier + //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 %d+1\n",rrc_inst->configuration->ue_TransmissionMode[0]); + } + // Measurement ID list MeasId_list = CALLOC(1, sizeof(*MeasId_list)); memset((void *)MeasId_list, 0, sizeof(*MeasId_list)); @@ -1672,10 +1680,10 @@ rrc_eNB_generate_defaultRRCConnectionReconfiguration( (DRB_ToAddModList_t*)*DRB_configList, (DRB_ToReleaseList_t*)NULL, // DRB2_list, (struct SPS_Config*)NULL, // *sps_Config, -#ifdef EXMIMO_IOT - NULL, NULL, NULL, NULL,NULL, -#else (struct PhysicalConfigDedicated*)*physicalConfigDedicated, +#ifdef EXMIMO_IOT + NULL, NULL, NULL,NULL, +#else (MeasObjectToAddModList_t*)MeasObj_list, (ReportConfigToAddModList_t*)ReportConfig_list, (QuantityConfig_t*)quantityConfig, @@ -3449,6 +3457,7 @@ openair_rrc_lite_eNB_init( eNB_rrc_inst[ctxt.module_id].initial_id2_s1ap_ids = hashtable_create (NUMBER_OF_UE_MAX * 2, NULL, NULL); eNB_rrc_inst[ctxt.module_id].s1ap_id2_s1ap_ids = hashtable_create (NUMBER_OF_UE_MAX * 2, NULL, NULL); + eNB_rrc_inst[ctxt.module_id].configuration = configuration; /// System Information INIT diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.exmimo2.conf index 6493c01167..68e5f8b056 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.exmimo2.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.exmimo2.conf @@ -33,6 +33,7 @@ eNBs = Nid_cell = 0; N_RB_DL = 25; Nid_cell_mbsfn = 0; + nb_antenna_ports = 2; nb_antennas_tx = 2; nb_antennas_rx = 2; tx_gain = 25; @@ -97,6 +98,8 @@ eNBs = ue_TimersAndConstants_t311 = 10000; ue_TimersAndConstants_n310 = 20; ue_TimersAndConstants_n311 = 1; + + ue_TransmissionMode = 2; } ); @@ -165,13 +168,13 @@ eNBs = */ log_config : { - global_log_level ="info"; + global_log_level ="debug"; global_log_verbosity ="medium"; hw_log_level ="debug"; hw_log_verbosity ="medium"; - phy_log_level ="info"; + phy_log_level ="debug"; phy_log_verbosity ="medium"; - mac_log_level ="info"; + mac_log_level ="debug"; mac_log_verbosity ="high"; rlc_log_level ="info"; rlc_log_verbosity ="medium"; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf index c0974d8703..15cb63a5b7 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf @@ -33,6 +33,7 @@ eNBs = Nid_cell = 0; N_RB_DL = 25; Nid_cell_mbsfn = 0; + nb_antenna_ports = 1; nb_antennas_tx = 1; nb_antennas_rx = 1; tx_gain = 25; @@ -97,6 +98,8 @@ eNBs = ue_TimersAndConstants_t311 = 10000; ue_TimersAndConstants_n310 = 20; ue_TimersAndConstants_n311 = 1; + + ue_TransmissionMode = 1; } ); diff --git a/targets/SIMU/USER/init_lte.c b/targets/SIMU/USER/init_lte.c index 3463da77d8..5514984a7d 100644 --- a/targets/SIMU/USER/init_lte.c +++ b/targets/SIMU/USER/init_lte.c @@ -53,7 +53,6 @@ PHY_VARS_eNB* init_lte_eNB(LTE_DL_FRAME_PARMS *frame_parms, uint8_t eNB_id, uint8_t Nid_cell, uint8_t cooperation_flag, - uint8_t transmission_mode, uint8_t abstraction_flag) { @@ -72,7 +71,6 @@ PHY_VARS_eNB* init_lte_eNB(LTE_DL_FRAME_PARMS *frame_parms, LOG_I(PHY,"init eNB: number of ue max %d number of enb max %d number of harq pid max %d\n", NUMBER_OF_UE_MAX, NUMBER_OF_eNB_MAX, NUMBER_OF_HARQ_PID_MAX); LOG_I(PHY,"init eNB: N_RB_DL %d\n", frame_parms->N_RB_DL); - LOG_I(PHY,"init eNB: Transmission mode %d\n", transmission_mode); for (i=0; itransmission_mode[i] = transmission_mode; + PHY_vars_eNB->transmission_mode[i] = frame_parms->nb_antenna_ports_eNB==1 ? 1 : 2; #ifdef LOCALIZATION PHY_vars_eNB->ulsch_eNB[1+i]->aggregation_period_ms = 5000; // 5000 milliseconds // could be given as an argument (TBD)) struct timeval ts; @@ -156,8 +154,8 @@ PHY_VARS_eNB* init_lte_eNB(LTE_DL_FRAME_PARMS *frame_parms, PHY_VARS_UE* init_lte_UE(LTE_DL_FRAME_PARMS *frame_parms, uint8_t UE_id, - uint8_t abstraction_flag, - uint8_t transmission_mode) + uint8_t abstraction_flag) + { int i,j; @@ -190,7 +188,7 @@ PHY_VARS_UE* init_lte_UE(LTE_DL_FRAME_PARMS *frame_parms, PHY_vars_UE->dlsch_ue_SI[i] = new_ue_dlsch(1,1,NSOFT,MAX_TURBO_ITERATIONS,frame_parms->N_RB_DL, abstraction_flag); PHY_vars_UE->dlsch_ue_ra[i] = new_ue_dlsch(1,1,NSOFT,MAX_TURBO_ITERATIONS,frame_parms->N_RB_DL, abstraction_flag); - PHY_vars_UE->transmission_mode[i] = transmission_mode; + PHY_vars_UE->transmission_mode[i] = frame_parms->nb_antenna_ports_eNB==1 ? 1 : 2; } PHY_vars_UE->lte_frame_parms.pucch_config_common.deltaPUCCH_Shift = 1; @@ -228,8 +226,12 @@ void init_lte_vars(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs], uint8_t extended_prefix_flag, uint8_t N_RB_DL, uint16_t Nid_cell, - uint8_t cooperation_flag,uint8_t transmission_mode,uint8_t abstraction_flag, - int nb_antennas_rx, int nb_antennas_tx, uint8_t eMBMS_active_state) + uint8_t cooperation_flag, + uint8_t nb_antenna_ports, + uint8_t abstraction_flag, + int nb_antennas_rx, + int nb_antennas_tx, + uint8_t eMBMS_active_state) { uint8_t eNB_id,UE_id,RN_id,CC_id; @@ -254,7 +256,7 @@ void init_lte_vars(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs], (frame_parms[CC_id])->nushift = (Nid_cell%6); (frame_parms[CC_id])->nb_antennas_tx = nb_antennas_tx; (frame_parms[CC_id])->nb_antennas_rx = nb_antennas_rx; - (frame_parms[CC_id])->nb_antenna_ports_eNB = (transmission_mode == 1 || transmission_mode == 7) ? 1 : 2; + (frame_parms[CC_id])->nb_antenna_ports_eNB = nb_antenna_ports; (frame_parms[CC_id])->mode1_flag = (frame_parms[CC_id])->nb_antenna_ports_eNB==1 ? 1 : 0; init_frame_parms(frame_parms[CC_id],1); @@ -277,7 +279,7 @@ void init_lte_vars(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs], PHY_vars_eNB_g[eNB_id] = (PHY_VARS_eNB**) malloc(MAX_NUM_CCs*sizeof(PHY_VARS_eNB*)); for (CC_id=0; CC_idMod_id=eNB_id; PHY_vars_eNB_g[eNB_id][CC_id]->CC_id=CC_id; } @@ -294,7 +296,7 @@ void init_lte_vars(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs], (frame_parms[CC_id])->nb_antennas_rx = nb_antennas_rx; - PHY_vars_UE_g[UE_id][CC_id] = init_lte_UE(frame_parms[CC_id], UE_id,abstraction_flag,transmission_mode); + PHY_vars_UE_g[UE_id][CC_id] = init_lte_UE(frame_parms[CC_id], UE_id,abstraction_flag); PHY_vars_UE_g[UE_id][CC_id]->Mod_id=UE_id; PHY_vars_UE_g[UE_id][CC_id]->CC_id=CC_id; } diff --git a/targets/SIMU/USER/init_lte.h b/targets/SIMU/USER/init_lte.h index 269863085d..e033b27e47 100644 --- a/targets/SIMU/USER/init_lte.h +++ b/targets/SIMU/USER/init_lte.h @@ -34,13 +34,11 @@ PHY_VARS_eNB* init_lte_eNB(LTE_DL_FRAME_PARMS *frame_parms, uint8_t eNB_id, uint8_t Nid_cell, uint8_t cooperation_flag, - uint8_t transmission_mode, uint8_t abstraction_flag); PHY_VARS_UE* init_lte_UE(LTE_DL_FRAME_PARMS *frame_parms, uint8_t UE_id, - uint8_t abstraction_flag, - uint8_t transmission_mode); + uint8_t abstraction_flag); PHY_VARS_RN* init_lte_RN(LTE_DL_FRAME_PARMS *frame_parms, uint8_t RN_id, diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index 326813181a..4ce98cd701 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -683,6 +683,7 @@ void get_simulation_options(int argc, char *argv[]) break; case 'x': + /* oai_emulation.info.transmission_mode[0] = atoi (optarg); if ((oai_emulation.info.transmission_mode[0] != 1) && (oai_emulation.info.transmission_mode[0] != 2) && (oai_emulation.info.transmission_mode[0] != 3) @@ -690,6 +691,9 @@ void get_simulation_options(int argc, char *argv[]) printf("Unsupported transmission mode %d\n",oai_emulation.info.transmission_mode[0]); exit(-1); } + */ + printf("Option -x deprecated. Please set transmission mode in eNB config file\n"); + exit(-1); break; @@ -925,8 +929,19 @@ void init_openair1(void) // change the nb_connected_eNB for (CC_id=0; CC_idproperties[0]->nb_antennas_tx[CC_id],enb_properties->properties[0]->nb_antennas_tx[CC_id], oai_emulation.info.eMBMS_active_state); + init_lte_vars (&frame_parms[CC_id], + oai_emulation.info.frame_type[CC_id], + oai_emulation.info.tdd_config[CC_id], + oai_emulation.info.tdd_config_S[CC_id], + oai_emulation.info.extended_prefix_flag[CC_id], + oai_emulation.info.N_RB_DL[CC_id], + Nid_cell, + cooperation_flag, + enb_properties->properties[0]->nb_antenna_ports[CC_id], + abstraction_flag, + enb_properties->properties[0]->nb_antennas_tx[CC_id], + enb_properties->properties[0]->nb_antennas_tx[CC_id], + oai_emulation.info.eMBMS_active_state); } for (eNB_id=0; eNB_id Date: Fri, 1 Jul 2016 13:20:15 +0200 Subject: [PATCH 200/413] mostly bugfixes --- openair1/PHY/INIT/defs.h | 12 ++ openair1/PHY/INIT/lte_init.c | 4 +- openair1/PHY/LTE_TRANSPORT/defs.h | 4 +- .../PHY/LTE_TRANSPORT/dlsch_demodulation.c | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 2 +- openair1/SCHED/phy_procedures_lte_ue.c | 2 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 22 +-- openair2/RRC/LITE/rrc_UE.c | 2 +- .../CONF/enb.band7.tm7.exmimo2.conf | 179 ++++++++++++++++++ 9 files changed, 210 insertions(+), 19 deletions(-) create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm7.exmimo2.conf diff --git a/openair1/PHY/INIT/defs.h b/openair1/PHY/INIT/defs.h index f08ca678db..58b04e7e01 100644 --- a/openair1/PHY/INIT/defs.h +++ b/openair1/PHY/INIT/defs.h @@ -337,6 +337,18 @@ int init_frame_parms(LTE_DL_FRAME_PARMS *frame_parms,uint8_t osf); void dump_frame_parms(LTE_DL_FRAME_PARMS *frame_parms); #endif +void lte_param_init(unsigned char N_tx_port_eNB, + unsigned char N_tx_phy, + unsigned char N_rx, + unsigned char transmission_mode, + uint8_t extended_prefix_flag, + frame_t frame_type, + uint16_t Nid_cell, + uint8_t tdd_config, + uint8_t N_RB_DL, + uint8_t threequarter_fs, + uint8_t osf, + uint32_t perfect_ce); /** @} */ #endif diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index c1f8c89b55..25a77aa024 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1338,7 +1338,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, // TX vars eNB_common_vars->txdata[eNB_id] = (int32_t**)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*)); eNB_common_vars->txdataF[eNB_id] = (mod_sym_t **)malloc16(NB_ANTENNA_PORTS_ENB*sizeof(mod_sym_t*)); - eNB_common_vars->txdataF_BF[eNB_id] = (mod_sym_t ***)malloc16(frame_parms->nb_antennas_tx*sizeof(mod_sym_t**)); + eNB_common_vars->txdataF_BF[eNB_id] = (mod_sym_t **)malloc16(frame_parms->nb_antennas_tx*sizeof(mod_sym_t*)); for (i=0; i<14; i++) { eNB_common_vars->txdataF[eNB_id][i] = (mod_sym_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t) ); @@ -1350,7 +1350,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, } for (i=0; inb_antennas_tx; i++) { - eNB_common_vars->txdataF_BF[eNB_id][i] = (mod_sym_t*)malloc16_clear( OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(mod_sym_t*) ); + eNB_common_vars->txdataF_BF[eNB_id][i] = (mod_sym_t*)malloc16_clear( OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(mod_sym_t) ); #ifdef USER_MODE eNB_common_vars->txdata[eNB_id][i] = (int32_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(int32_t) ); #else // USER_MODE diff --git a/openair1/PHY/LTE_TRANSPORT/defs.h b/openair1/PHY/LTE_TRANSPORT/defs.h index ae1d339770..22b70672e8 100644 --- a/openair1/PHY/LTE_TRANSPORT/defs.h +++ b/openair1/PHY/LTE_TRANSPORT/defs.h @@ -239,9 +239,9 @@ typedef struct { typedef struct { /// TX buffers for UE-spec transmission (antenna ports 5 or 7..14, prior to precoding) - uint32_t *txdataF[8]; + int32_t *txdataF[8]; /// beamforming weights for UE-spec transmission (antenna ports 5 or 7..14), for each codeword, maximum 4 layers? - uint32_t **ue_spec_bf_weights[4]; + int32_t **ue_spec_bf_weights[4]; /// Allocated RNTI (0 means DLSCH_t is not currently used) uint16_t rnti; /// Active flag for baseband transmitter processing diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c index 831744bc09..916883cc23 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_demodulation.c @@ -96,7 +96,7 @@ int rx_pdsch(PHY_VARS_UE *phy_vars_ue, LTE_UE_DLSCH_t **dlsch_ue; unsigned char aatx,aarx; - unsigned short nb_rb; + unsigned short nb_rb=0; int avgs, rb; LTE_DL_UE_HARQ_t *dlsch0_harq,*dlsch1_harq = 0; diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index e9ee770545..f7a978545f 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -1190,7 +1190,7 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e 0, P_RNTI, phy_vars_eNB->eNB_UE_stats[(uint8_t)UE_id].DL_pmi_single, - phy_vars_eNB->transmission_mode[(uint8_t)UE_id]>7?0:phy_vars_eNB->transmission_mode[(uint8_t)UE_id]); + phy_vars_eNB->transmission_mode[(uint8_t)UE_id]<7?0:phy_vars_eNB->transmission_mode[(uint8_t)UE_id]); LOG_D(PHY,"[eNB %"PRIu8"][PDSCH %"PRIx16"/%"PRIu8"] Frame %d subframe %d: Generated dlsch params\n", phy_vars_eNB->Mod_id,DCI_pdu->dci_alloc[i].rnti,phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->current_harq_pid,phy_vars_eNB->proc[sched_subframe].frame_tx,subframe); diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index d87a8479f5..cfaca44a43 100755 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -2144,7 +2144,7 @@ int lte_ue_pdcch_procedures(uint8_t eNB_id,PHY_VARS_UE *phy_vars_ue,uint8_t abst SI_RNTI, 0, P_RNTI, - phy_vars_ue->transmission_mode[eNB_id]>7?0:phy_vars_ue->transmission_mode[eNB_id])==0)) { + (phy_vars_ue->transmission_mode[eNB_id]<7)?0:phy_vars_ue->transmission_mode[eNB_id])==0)) { #ifdef DIAG_PHY diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 6e78ad1a56..7c58488e2d 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -3359,17 +3359,17 @@ PMI_FEEDBACK: if (dlsch_active == 1) { - if (transmission_mode==7) { - if (PHY_vars_UE->lte_frame_parms.Ncp==0) { - if ((Ns==(2*subframe) && ((l==3) || (l==6))) || - Ns==(1+(2*subframe)) && ((l==2) || (l==5))) { - if (perfect_ce==0) - lte_dl_bf_channel_estimation(PHY_vars_UE,eNB_id,0,Ns,5,l+7*(Ns%2==1)); - } - } else { - msg("Beamforming channel estimation not supported yet for TM7 extented CP.\n"); - } - } + if (transmission_mode==7) { + if (PHY_vars_UE->lte_frame_parms.Ncp==0) { + if ((Ns==(2*subframe) && ((l==3) || (l==6))) || + (Ns==(1+2*subframe) && ((l==2) || (l==5)))) { + if (perfect_ce==0) + lte_dl_bf_channel_estimation(PHY_vars_UE,eNB_id,0,Ns,5,l+7*(Ns%2==1)); + } + } else { + msg("Beamforming channel estimation not supported yet for TM7 extented CP.\n"); + } + } if ((Ns==(1+(2*subframe))) && (l==0)) {// process PDSCH symbols 1,2,3,4,5,(6 Normal Prefix) diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index 7da26897e8..19d7b9a36e 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -103,7 +103,7 @@ extern UE_MAC_INST *UE_mac_inst; extern void *bigphys_malloc(int); #endif -//#define XER_PRINT +#define XER_PRINT extern int8_t dB_fixed2(uint32_t x,uint32_t y); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm7.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm7.exmimo2.conf new file mode 100644 index 0000000000..dedf4797bc --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm7.exmimo2.conf @@ -0,0 +1,179 @@ +Active_eNBs = ( "eNB_Eurecom_LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB_Eurecom_LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = "1"; + + mobile_country_code = "208"; + + mobile_network_code = "93"; + + ////////// Physical parameters: + + component_carriers = ( + { + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2680000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 1; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 25; + rx_gain = 20; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = -26; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 0; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -80; /*-85;*/ + pusch_alpha = "AL1"; + pucch_p0_Nominal = -108; /* -108 */ + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 2; + rach_preambleInitialReceivedTargetPower = -100; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + + ue_TransmissionMode = 7; + } + ); + + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.12.171"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth2"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.80/24"; + + ENB_INTERFACE_NAME_FOR_S1U = "eth2"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.80/24"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + log_config : + { + global_log_level ="debug"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="debug"; + phy_log_verbosity ="medium"; + mac_log_level ="debug"; + mac_log_verbosity ="medium"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + gtpu_log_level ="error"; + gtpu_log_verbosity ="medium"; + udp_log_level ="error"; + udp_log_verbosity ="medium"; + osa_log_level ="warn"; + osa_log_verbosity ="low"; + }; + + } +); From 08f73c72d829bb1dad6acbc35447be6b168dedf3 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 5 Jul 2016 15:11:12 +0200 Subject: [PATCH 201/413] resolve conflict when merge develop --- openair1/PHY/INIT/lte_init.c | 6 ++--- openair1/PHY/LTE_REFSIG/defs.h | 2 +- openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c | 8 +++---- openair1/PHY/LTE_REFSIG/lte_dl_uespec.c | 4 ++-- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 2 +- openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c | 4 ++-- openair1/PHY/LTE_TRANSPORT/proto.h | 3 +-- openair1/PHY/MODULATION/ofdm_mod.c | 4 ++-- openair1/SIMULATION/LTE_PHY/dlsim.c | 22 ++----------------- 9 files changed, 18 insertions(+), 37 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 218a6b166c..17622db1ae 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1334,7 +1334,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, eNB_common_vars->txdataF_BF[eNB_id] = (int32_t **)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*)); for (i=0; i<14; i++) { - eNB_common_vars->txdataF[eNB_id][i] = (mod_sym_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t) ); + eNB_common_vars->txdataF[eNB_id][i] = (int32_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(int32_t) ); #ifdef DEBUG_PHY msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->txdataF[%d][%d] = %p (%d bytes)\n", eNB_id,i,eNB_common_vars->txdataF[eNB_id][i], @@ -1343,7 +1343,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, } for (i=0; inb_antennas_tx; i++) { - eNB_common_vars->txdataF_BF[eNB_id][i] = (mod_sym_t*)malloc16_clear( OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(mod_sym_t) ); + eNB_common_vars->txdataF_BF[eNB_id][i] = (int32_t*)malloc16_clear( OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t) ); #ifdef USER_MODE eNB_common_vars->txdata[eNB_id][i] = (int32_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(int32_t) ); #else // USER_MODE @@ -1352,7 +1352,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, #ifdef DEBUG_PHY msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->txdataF_BF[%d][%d][%d] = %p (%d bytes)\n", eNB_id,i,j,eNB_common_vars->txdataF_BF[eNB_id][i][j], - OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(mod_sym_t)); + OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->txdata[%d][%d] = %p\n",eNB_id,i,eNB_common_vars->txdata[eNB_id][i]); #endif } diff --git a/openair1/PHY/LTE_REFSIG/defs.h b/openair1/PHY/LTE_REFSIG/defs.h index 9377368d7d..e8c3f7c807 100644 --- a/openair1/PHY/LTE_REFSIG/defs.h +++ b/openair1/PHY/LTE_REFSIG/defs.h @@ -139,7 +139,7 @@ int lte_dl_cell_spec_rx(PHY_VARS_UE *phy_vars_ue, @param nRB_PDSCH number of allocated PDSCH RBs */ int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, - mod_sym_t *output, + int32_t *output, unsigned char Ns, unsigned char p, int lprime, diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c b/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c index d029f959ed..a1926ba6b4 100644 --- a/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c +++ b/openair1/PHY/LTE_REFSIG/lte_dl_ue_spec.c @@ -55,7 +55,7 @@ int Wbar_NCP[8][4] = {{1,1,1,1},{1,-1,1,-1},{1,1,1,1},{1,-1,1,-1},{1,1,-1,-1},{- /* int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, uint8_t UE_id, - mod_sym_t *output, + int32_t *output, short amp, uint8_t Ns, uint8_t lprime, @@ -63,7 +63,7 @@ int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, int SS_flag) { - mod_sym_t qpsk[4],nqpsk[4]; + int32_t qpsk[4],nqpsk[4]; int16_t k=0,a; int mprime,ind,ind_dword,ind_qpsk_symb; unsigned nushift,kprime; @@ -133,14 +133,14 @@ int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, - mod_sym_t *output, + int32_t *output, unsigned char Ns, unsigned char p, int lprime, int SS_flag, uint16_t nRB_PDSCH) { - mod_sym_t qpsk[4],nqpsk[4],*qpsk_p,*output_p; + int32_t qpsk[4],nqpsk[4],*qpsk_p,*output_p; int w,mprime,ind,l,ind_dword,ind_qpsk_symb,nPRB; short pamp; diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c b/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c index 7b788514f5..5f30180883 100644 --- a/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c +++ b/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c @@ -133,14 +133,14 @@ int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, - mod_sym_t *output, + int32_t *output, unsigned char Ns, unsigned char p, int lprime, int SS_flag, uint16_t nRB_PDSCH) { - mod_sym_t qpsk[4],nqpsk[4],*qpsk_p,*output_p; + int32_t qpsk[4],nqpsk[4],*qpsk_p,*output_p; int w,mprime,ind,l,ind_dword,ind_qpsk_symb,nPRB; short pamp; diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 723e3eee90..b96d60a8f6 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -232,7 +232,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB *phy_vars_eNB, int s=1; int mprime2 = mprime,ind,ind_dword,ind_qpsk_symb; - mod_sym_t qpsk[4]; + int32_t qpsk[4]; gain_lin_QPSK = (int16_t)((amp*ONE_OVER_SQRT2_Q15)>>15); // if (mimo_mode == LARGE_CDD) gain_lin_QPSK>>=1; diff --git a/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c b/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c index 4651308dfd..4a9010fca0 100644 --- a/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c +++ b/openair1/PHY/LTE_TRANSPORT/pilots_ue_spec.c @@ -42,7 +42,7 @@ void generate_ue_spec_pilots(PHY_VARS_eNB *phy_vars_eNB, uint8_t UE_id, - mod_sym_t **txdataF, + int32_t **txdataF, int16_t amp, uint16_t Ntti, uint8_t beamforming_mode) @@ -127,7 +127,7 @@ void generate_ue_spec_pilots(PHY_VARS_eNB *phy_vars_eNB, } /*int generate_ue_spec_pilots_slot(PHY_VARS_eNB *phy_vars_eNB, - mod_sym_t **txdataF, + int32_t **txdataF, int16_t amp, uint16_t slot, int first_pilot_only) diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 17338ebb78..d775aea822 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -306,10 +306,9 @@ int32_t generate_mbsfn_pilot(PHY_VARS_eNB *phy_vars_eNB, int16_t amp, uint16_t subframe); -<<<<<<< HEAD void generate_ue_spec_pilots(PHY_VARS_eNB *phy_vars_eNB, uint8_t UE_id, - mod_sym_t **txdataF, + int32_t **txdataF, int16_t amp, uint16_t Ntti, uint8_t beamforming_mode); diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 23d5ed1269..1f7aeb533a 100755 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -296,8 +296,8 @@ void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_sl int aa, l, slot_offset, slot_offset_F; int8_t UE_id=0; - mod_sym_t **txdataF = eNB_common_vars->txdataF[eNB_id]; - mod_sym_t **txdataF_BF = eNB_common_vars->txdataF_BF[eNB_id]; + int32_t **txdataF = eNB_common_vars->txdataF[eNB_id]; + int32_t **txdataF_BF = eNB_common_vars->txdataF_BF[eNB_id]; int32_t **txdata = eNB_common_vars->txdata[eNB_id]; //slot_offset_F = (next_slot)*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 886d02c954..378c79803b 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -505,11 +505,8 @@ int main(int argc, char **argv) exit(-1); } - if (transmission_mode>1 && transmission_mode<7){ + if (transmission_mode>1 && transmission_mode<7) { n_tx_port = 2; - n_tx_phy = n_tx_port; - } else if (transmission_mode==7){ - n_tx_port = 1; } break; @@ -521,14 +518,10 @@ int main(int argc, char **argv) if(n_tx_phy==1) { msg("n_tx_phy must be >1 for transmission_mode %d\n",transmission_mode); exit(-1); - } else if (n_tx_phy!=n_tx_port) { // to be changed - msg("For transmission mode TM2-TM6, physical antenna number should be the same as antenna port number.\n"); - exit(-1); - } + } } if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=8 && n_tx_phy!=16 && n_tx_phy!=64 && n_tx_phy!=128)) { - // if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=16 && n_tx_phy!=64)) { msg("Physical number of antennas not supported for TM7.\n"); exit(-1); } @@ -616,8 +609,6 @@ int main(int argc, char **argv) } else NB_RB = 4; - /*if ((transmission_mode > 1) && (n_tx != 2)) - printf("n_tx must be >1 for transmission_mode %d\n",transmission_mode);*/ if (xforms==1) { fl_initialize (&argc, argv, NULL, 0, 0); @@ -673,15 +664,6 @@ int main(int argc, char **argv) snr1 = snr0+snr_int; printf("SNR0 %f, SNR1 %f\n",snr0,snr1); - /* - txdataF = (int **)malloc16(2*sizeof(int*)); - txdataF[0] = (int *)malloc16(FRAME_LENGTH_BYTES); - txdataF[1] = (int *)malloc16(FRAME_LENGTH_BYTES); - - txdata = (int **)malloc16(2*sizeof(int*)); - txdata[0] = (int *)malloc16(FRAME_LENGTH_BYTES); - txdata[1] = (int *)malloc16(FRAME_LENGTH_BYTES); - */ s_re = malloc(n_tx_phy*sizeof(double*)); s_im = malloc(n_tx_phy*sizeof(double*)); From 35bdc94092db108dec4ec5a07ec76e3d4ce75051 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Wed, 6 Jul 2016 10:28:27 +0200 Subject: [PATCH 202/413] fixing a few bugs after merge --- openair1/PHY/INIT/lte_init.c | 6 +++--- openair1/PHY/LTE_REFSIG/defs.h | 2 +- openair1/PHY/LTE_REFSIG/lte_dl_uespec.c | 4 ++-- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 2 +- openair1/PHY/LTE_TRANSPORT/proto.h | 3 +-- openair1/PHY/MODULATION/ofdm_mod.c | 4 ++-- targets/RT/USER/lte-softmodem.c | 4 ++-- 7 files changed, 12 insertions(+), 13 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 218a6b166c..17622db1ae 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1334,7 +1334,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, eNB_common_vars->txdataF_BF[eNB_id] = (int32_t **)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*)); for (i=0; i<14; i++) { - eNB_common_vars->txdataF[eNB_id][i] = (mod_sym_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(mod_sym_t) ); + eNB_common_vars->txdataF[eNB_id][i] = (int32_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(int32_t) ); #ifdef DEBUG_PHY msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->txdataF[%d][%d] = %p (%d bytes)\n", eNB_id,i,eNB_common_vars->txdataF[eNB_id][i], @@ -1343,7 +1343,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, } for (i=0; inb_antennas_tx; i++) { - eNB_common_vars->txdataF_BF[eNB_id][i] = (mod_sym_t*)malloc16_clear( OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(mod_sym_t) ); + eNB_common_vars->txdataF_BF[eNB_id][i] = (int32_t*)malloc16_clear( OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t) ); #ifdef USER_MODE eNB_common_vars->txdata[eNB_id][i] = (int32_t*)malloc16_clear( FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(int32_t) ); #else // USER_MODE @@ -1352,7 +1352,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, #ifdef DEBUG_PHY msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->txdataF_BF[%d][%d][%d] = %p (%d bytes)\n", eNB_id,i,j,eNB_common_vars->txdataF_BF[eNB_id][i][j], - OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(mod_sym_t)); + OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->txdata[%d][%d] = %p\n",eNB_id,i,eNB_common_vars->txdata[eNB_id][i]); #endif } diff --git a/openair1/PHY/LTE_REFSIG/defs.h b/openair1/PHY/LTE_REFSIG/defs.h index 9377368d7d..e8c3f7c807 100644 --- a/openair1/PHY/LTE_REFSIG/defs.h +++ b/openair1/PHY/LTE_REFSIG/defs.h @@ -139,7 +139,7 @@ int lte_dl_cell_spec_rx(PHY_VARS_UE *phy_vars_ue, @param nRB_PDSCH number of allocated PDSCH RBs */ int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, - mod_sym_t *output, + int32_t *output, unsigned char Ns, unsigned char p, int lprime, diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c b/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c index 7b788514f5..5f30180883 100644 --- a/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c +++ b/openair1/PHY/LTE_REFSIG/lte_dl_uespec.c @@ -133,14 +133,14 @@ int lte_dl_ue_spec(PHY_VARS_eNB *phy_vars_eNB, int lte_dl_ue_spec_rx(PHY_VARS_UE *phy_vars_ue, - mod_sym_t *output, + int32_t *output, unsigned char Ns, unsigned char p, int lprime, int SS_flag, uint16_t nRB_PDSCH) { - mod_sym_t qpsk[4],nqpsk[4],*qpsk_p,*output_p; + int32_t qpsk[4],nqpsk[4],*qpsk_p,*output_p; int w,mprime,ind,l,ind_dword,ind_qpsk_symb,nPRB; short pamp; diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 723e3eee90..b96d60a8f6 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -232,7 +232,7 @@ int allocate_REs_in_RB(PHY_VARS_eNB *phy_vars_eNB, int s=1; int mprime2 = mprime,ind,ind_dword,ind_qpsk_symb; - mod_sym_t qpsk[4]; + int32_t qpsk[4]; gain_lin_QPSK = (int16_t)((amp*ONE_OVER_SQRT2_Q15)>>15); // if (mimo_mode == LARGE_CDD) gain_lin_QPSK>>=1; diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 17338ebb78..d775aea822 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -306,10 +306,9 @@ int32_t generate_mbsfn_pilot(PHY_VARS_eNB *phy_vars_eNB, int16_t amp, uint16_t subframe); -<<<<<<< HEAD void generate_ue_spec_pilots(PHY_VARS_eNB *phy_vars_eNB, uint8_t UE_id, - mod_sym_t **txdataF, + int32_t **txdataF, int16_t amp, uint16_t Ntti, uint8_t beamforming_mode); diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 23d5ed1269..1f7aeb533a 100755 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -296,8 +296,8 @@ void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_sl int aa, l, slot_offset, slot_offset_F; int8_t UE_id=0; - mod_sym_t **txdataF = eNB_common_vars->txdataF[eNB_id]; - mod_sym_t **txdataF_BF = eNB_common_vars->txdataF_BF[eNB_id]; + int32_t **txdataF = eNB_common_vars->txdataF[eNB_id]; + int32_t **txdataF_BF = eNB_common_vars->txdataF_BF[eNB_id]; int32_t **txdata = eNB_common_vars->txdata[eNB_id]; //slot_offset_F = (next_slot)*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 38723e6152..8b48148955 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -3069,7 +3069,7 @@ int main( int argc, char **argv ) for (CC_id=0; CC_idNid_cell,cooperation_flag,transmission_mode,abstraction_flag); + PHY_vars_eNB_g[0][CC_id] = init_lte_eNB(frame_parms[CC_id],0,frame_parms[CC_id]->Nid_cell,cooperation_flag,abstraction_flag); PHY_vars_eNB_g[0][CC_id]->CC_id = CC_id; if (phy_test==1) From a5b57ddce4b5a8f3538c72a39235e09ca263158f Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Wed, 6 Jul 2016 15:01:58 +0200 Subject: [PATCH 203/413] dci decoding procedure --- openair1/PHY/INIT/lte_init.c | 4 ++-- openair1/PHY/LTE_TRANSPORT/dci.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 17622db1ae..f667379331 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -473,7 +473,7 @@ void phy_config_dedicated_eNB_step2(PHY_VARS_eNB *phy_vars_eNB) if (physicalConfigDedicated->antennaInfo) { phy_vars_eNB->transmission_mode[UE_id] = 1+(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode); - LOG_D(PHY,"Transmission Mode %d\n",phy_vars_eNB->transmission_mode[UE_id]); + LOG_D(PHY,"eNB:Transmission Mode %d\n",phy_vars_eNB->transmission_mode[UE_id]); LOG_D(PHY,"\n"); } @@ -845,7 +845,7 @@ void phy_config_dedicated_ue(uint8_t Mod_id,int CC_id,uint8_t CH_index, if (physicalConfigDedicated->antennaInfo) { phy_vars_ue->transmission_mode[CH_index] = 1+(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode); - LOG_D(PHY,"Transmission Mode %d\n",phy_vars_ue->transmission_mode[CH_index]); + LOG_D(PHY,"UE:Transmission Mode %d\n",phy_vars_ue->transmission_mode[CH_index]); LOG_D(PHY,"\n"); switch(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode) { case AntennaInfoDedicated__transmissionMode_tm1: diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index d7fc7042a5..da2fe77141 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -3339,7 +3339,7 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *phy_vars_ue, // These are for CRNTI based on transmission mode - if (tmode < 3) { + if ((tmode < 3) || (tmode == 7)) { // Now check UE_SPEC format 1 search spaces at aggregation 1 old_dci_cnt=dci_cnt; dci_decoding_procedure0(lte_ue_pdcch_vars,0,subframe, @@ -3684,7 +3684,7 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *phy_vars_ue, &CCEmap1, &CCEmap2); //#endif - } else if (tmode >=5) { // This is MU-MIMO + } else if ((tmode==5) || (tmode==6)) { // This is MU-MIMO // Now check UE_SPEC format 1E_2A_M10PRB search spaces aggregation 1 #ifdef DEBUG_DCI_DECODING From 142c02a5b83caa5cf9f2f3772d8d33bbb40d8d4a Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Tue, 12 Jul 2016 11:18:05 +0200 Subject: [PATCH 204/413] small fix in CMakeLists.txt to avoid inclusion of unwanted files --- cmake_targets/CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 67cc6cfc3a..09d5322a69 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -929,7 +929,14 @@ add_library(SECU_CN ${SECU_CN_SRC}) # Scheduler ################################" -file(GLOB SCHED_SRC ${OPENAIR1_DIR}/SCHED/*.c) +set(SCHED_SRC + ${OPENAIR1_DIR}/SCHED/phy_procedures_lte_eNb.c + ${OPENAIR1_DIR}/SCHED/phy_procedures_lte_ue.c + ${OPENAIR1_DIR}/SCHED/phy_procedures_lte_common.c + ${OPENAIR1_DIR}/SCHED/phy_mac_stub.c + ${OPENAIR1_DIR}/SCHED/pucch_pc.c + ${OPENAIR1_DIR}/SCHED/pusch_pc.c +) add_library(SCHED_LIB ${SCHED_SRC}) # Layer 1 From 4763438131a7ab3ca3ae31bb0147dbf39f0cdcbb Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 15 Jul 2016 16:48:41 +0200 Subject: [PATCH 205/413] bug fixed for ue_spec_bf_weights initialisation --- .../oaisim_noS1_build_oai/CMakeLists.template | 1 - openair1/PHY/INIT/lte_init.c | 24 ------------- .../lte_dl_bf_channel_estimation.c | 2 +- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 8 ----- openair1/PHY/MODULATION/beamforming.c | 22 ++++++------ openair1/SCHED/phy_procedures_lte_ue.c | 11 ++++++ openair1/SIMULATION/LTE_PHY/dlsim.c | 35 ++++++++++++------- targets/SIMU/USER/init_lte.c | 14 +++++++- 8 files changed, 59 insertions(+), 58 deletions(-) diff --git a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template index 6d8fc6d26a..20015eb42a 100644 --- a/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template +++ b/cmake_targets/oaisim_noS1_build_oai/CMakeLists.template @@ -1,6 +1,5 @@ cmake_minimum_required(VERSION 2.8) -set ( CMAKE_BUILD_TYPE "RelWithDebInfo" ) set ( ADDR_CONF False ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index f667379331..9780f226bd 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1357,18 +1357,6 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, #endif } - /*for (i=0; i<2; i++) { // 2 is the total number of cell specific antenna ports - eNB_common_vars->cell_spec_bf_weights[eNB_id][i] = (int32_t **)malloc16_clear(frame_parms->nb_antennas_tx*sizeof(int32_t*)); - for (j=0; jnb_antennas_tx; j++) { - eNB_common_vars->cell_spec_bf_weights[eNB_id][i][j] = (int32_t *)malloc16_clear(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); -#ifdef DEBUG_PUY - msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->cell_spec_bf_weights[%d][%d][%d] = %p (%d bytes)\n", - eNB_id,i,j,eNB_common_vars->cell_spec_bf_weights[eNB_id][i][j], - OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); -#endif - } - } */ - for (i=0; i<15; i++) { // 15 is the total number of antenna ports eNB_common_vars->beam_weights[eNB_id][i] = (int32_t **)malloc16_clear(frame_parms->nb_antennas_tx*sizeof(int32_t*)); for (j=0; jnb_antennas_tx; j++) { @@ -1383,18 +1371,6 @@ int phy_init_lte_eNB(PHY_VARS_eNB *phy_vars_eNB, } } - /*for (i=0; i<8; i++) { //antenna port 5 for TM7, antenna port 7-15 for TM8-10 - eNB_common_vars->ue_spec_bf_weights[eNB_id][i] = (int32_t **)malloc16_clear(frame_parms->nb_antennas_tx*sizeof(int32_t*)); - for (j=0; jnb_antennas_tx; j++) { - eNB_common_vars->ue_spec_bf_weights[eNB_id][i][j] = (int32_t*)malloc16_clear(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); -#ifdef DEBUG_PUY - msg("[openair][LTE_PHY][INIT] lte_eNB_common_vars->ue_spec_bf_weights[%d][%d][%d] = %p (%d bytes)\n", - eNB_id,i,j,eNB_common_vars->ue_spec_bf_weights[eNB_id][i][j], - OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); -#endif - } - } */ - // RX vars eNB_common_vars->rxdata[eNB_id] = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*) ); eNB_common_vars->rxdata_7_5kHz[eNB_id] = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*) ); diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c index 5fecc9c34f..80df031c41 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c @@ -708,7 +708,7 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, } } //aarx - //printf("[dlsch bf ch est]: dl_bf_estimates[0][600] %d, %d \n",*(short *)&dl_bf_ch_estimates[0][600],*(short*)&phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates[0][600]); + // printf("[dlsch bf ch est]: dl_bf_estimates[0][600] %d, %d \n",*(short *)&dl_bf_ch_estimates[0][600],*(short*)&phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates[0][600]); return(0); diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index e79aa11feb..48498a4873 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -204,14 +204,6 @@ LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_ put_harq_pid_in_freelist(dlsch, i); } - for (i=0; i<4; i++) { - dlsch->ue_spec_bf_weights[i] = (int32_t **)malloc16(nb_antennas_tx*sizeof(int32_t*)); - - for (aa=0; aaue_spec_bf_weights[i][aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); - } - } - if (exit_flag==0) { for (i=0; iharq_processes[i]->round=0; diff --git a/openair1/PHY/MODULATION/beamforming.c b/openair1/PHY/MODULATION/beamforming.c index e37ab0e430..2e38b7cb93 100644 --- a/openair1/PHY/MODULATION/beamforming.c +++ b/openair1/PHY/MODULATION/beamforming.c @@ -91,16 +91,18 @@ int beam_precoding(int32_t **txdataF, ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[5][aa][re])[1])>>15); ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[5][aa][re])[1])>>15); ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[5][aa][re])[0])>>15); - // printf("beamforming.c:txdata[%d][%d]=%d+j%d, beam_weights[%d][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", - // p,slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re, - // ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0], - // ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1], - // p,aa,re, - // ((int16_t*)&beam_weights[p][aa][re])[0],((int16_t*)&beam_weights[p][aa][re])[1], - // aa,re, - // ((int16_t*)&txdataF_BF[aa][re])[0], - // ((int16_t*)&txdataF_BF[aa][re])[1]); - +/* + printf("beamforming.c:txdata[5][%d]=%d+j%d, beam_weights[5][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", + slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re, + ((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0], + ((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1], + aa,re, + ((int16_t*)&beam_weights[5][aa][re])[0], + ((int16_t*)&beam_weights[5][aa][re])[1], + aa,re, + ((int16_t*)&txdataF_BF[aa][re])[0], + ((int16_t*)&txdataF_BF[aa][re])[1]); +*/ } } diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 9241c59508..36a7f525e3 100755 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -2557,10 +2557,21 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac if ((slot_rx%2)==1) // odd slots phy_vars_ue->dlsch_ue[eNB_id][0]->active = 0; } + } #endif + if (phy_vars_ue->dlsch_ue[eNB_id][0]->active == 1) { + if (phy_vars_ue->transmission_mode[eNB_id]==7) { + if (phy_vars_ue->lte_frame_parms.Ncp==0) { + if (((slot_rx%2)==0 && ((l==3) || (l==6))) || ((slot_rx%2)==1 && ((l==2) || (l==5)))) + lte_dl_bf_channel_estimation(phy_vars_ue,eNB_id,0,slot_rx,5,l+7*(slot_rx%2==1)); + } else { + LOG_E(PHY,"[UE %d]Beamforming channel estimation not supported yet for TM7 extented CP.\n",phy_vars_ue->Mod_id); + } + } + } // process last DLSCH symbols + invoke decoding if (((slot_rx%2)==0) && (l==0)) { // Regular PDSCH diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 378c79803b..dd535064d1 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -119,7 +119,8 @@ int main(int argc, char **argv) uint8_t extended_prefix_flag=0,transmission_mode=1,n_tx_port=1,n_tx_phy=1,n_rx=1; uint16_t Nid_cell=0; - int32_t **ue_spec_bf_weights, **cell_spec_bf_weights; + int32_t **cell_spec_bf_weights; + int32_t *ue_spec_bf_weights; int eNB_id = 0, eNB_id_i = 1; unsigned char mcs1=0,mcs2=0,mcs_i=0,dual_stream_UE = 0,awgn_flag=0,round,dci_flag=0; @@ -932,23 +933,31 @@ int main(int argc, char **argv) exit(-1); } else { // this initilisation may should be moved to another place - for (j=0; j<4; j++) { // antenna port 5,7-14 + for (j=0; j<4; j++) { + PHY_vars_eNB->dlsch_eNB[k][i]->ue_spec_bf_weights[j] = (int32_t **)malloc16(n_tx_phy*sizeof(int32_t*)); + + for (aa=0; aadlsch_eNB[k][i]->ue_spec_bf_weights[j][aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); + ue_spec_bf_weights = PHY_vars_eNB->dlsch_eNB[k][i]->ue_spec_bf_weights[j][aa]; + + for (re=0;reofdm_symbol_size;re++) { + if (n_tx_phy==1 || n_tx_phy==2) + ue_spec_bf_weights[re] = 0x00007fff; + else if (n_tx_phy==4 || n_tx_phy==8) + ue_spec_bf_weights[re] = 0x00007fff>>1; + else if (n_tx_phy==16) + ue_spec_bf_weights[re] = 0x00007fff>>2; + else if (n_tx_phy==64) + ue_spec_bf_weights[re] = 0x00007fff>>4; + } + + } + } ue_spec_bf_weights = PHY_vars_eNB->dlsch_eNB[k][i]->ue_spec_bf_weights[j]; for (aa=0; aanb_antennas_tx; aa++) { - for (re=0;reofdm_symbol_size;re++) { - if (n_tx_phy==1 || n_tx_phy==2) - ue_spec_bf_weights[aa][re] = 0x00007fff; - else if (n_tx_phy==4 || n_tx_phy==8) - ue_spec_bf_weights[aa][re] = 0x00007fff>>1; - else if (n_tx_phy==16) - ue_spec_bf_weights[aa][re] = 0x00007fff>>2; - else if (n_tx_phy==64) - ue_spec_bf_weights[aa][re] = 0x00007fff>>4; - } } - } } PHY_vars_eNB->dlsch_eNB[k][i]->rnti = n_rnti+k; diff --git a/targets/SIMU/USER/init_lte.c b/targets/SIMU/USER/init_lte.c index 985cb6036c..512187a52b 100644 --- a/targets/SIMU/USER/init_lte.c +++ b/targets/SIMU/USER/init_lte.c @@ -53,7 +53,7 @@ PHY_VARS_eNB* init_lte_eNB(LTE_DL_FRAME_PARMS *frame_parms, uint8_t abstraction_flag) { - int i,j; + int i,j,layer,aa,re; PHY_VARS_eNB* PHY_vars_eNB = malloc(sizeof(PHY_VARS_eNB)); memset(PHY_vars_eNB,0,sizeof(PHY_VARS_eNB)); PHY_vars_eNB->Mod_id=eNB_id; @@ -79,6 +79,18 @@ PHY_VARS_eNB* init_lte_eNB(LTE_DL_FRAME_PARMS *frame_parms, } else { LOG_D(PHY,"dlsch_eNB[%d][%d] => %p\n",i,j,PHY_vars_eNB->dlsch_eNB[i][j]); PHY_vars_eNB->dlsch_eNB[i][j]->rnti=0; + + for (layer=0; layer<4; layer++) { + PHY_vars_eNB->dlsch_eNB[i][j]->ue_spec_bf_weights[layer] = (int32_t **)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*)); + + for (aa=0; aanb_antennas_tx; aa++) { + PHY_vars_eNB->dlsch_eNB[i][j]->ue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); + for (re=0;redlsch_eNB[i][j]->ue_spec_bf_weights[layer][aa][re] = 0x00007fff; + } + } + } + } } From 79e8653f03c1dfadec022922d7a441e2a0d42edd Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Fri, 15 Jul 2016 16:52:08 +0200 Subject: [PATCH 206/413] add read_F.c to openairinterface1/PHY/TOOLS --- openair1/PHY/TOOLS/read_F.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 openair1/PHY/TOOLS/read_F.c diff --git a/openair1/PHY/TOOLS/read_F.c b/openair1/PHY/TOOLS/read_F.c new file mode 100644 index 0000000000..32ade0dfdb --- /dev/null +++ b/openair1/PHY/TOOLS/read_F.c @@ -0,0 +1,24 @@ +#include +#include + +int f_read(char *calibF_fname, int nb_antM, int nb_freq, int16_t (*calibF_mtx)[nb_freq*2]){ + + FILE *calibF_fd; + int i,j,l,calibF_e; + + calibF_fd = fopen(calibF_fname,"r"); + + if (calibF_fd) { + printf("Loading Calibration matrix from %s\n", calibF_fname); + + for(i=0;i Date: Fri, 22 Jul 2016 19:51:24 +0200 Subject: [PATCH 207/413] change the MAX_CARDS to 16 --- targets/ARCH/EXMIMO/DEFS/openair_device.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/ARCH/EXMIMO/DEFS/openair_device.h b/targets/ARCH/EXMIMO/DEFS/openair_device.h index 2be7b7f088..519693461e 100755 --- a/targets/ARCH/EXMIMO/DEFS/openair_device.h +++ b/targets/ARCH/EXMIMO/DEFS/openair_device.h @@ -33,8 +33,8 @@ // Maximum number of concurrently supported cards // -#define MAX_CARDS 8 -#define INIT_ZEROS {0, 0, 0, 0, 0, 0, 0, 0}; +#define MAX_CARDS 16 +#define INIT_ZEROS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /** PCIe subsystem configuration Space From 987ffdd8a0b6122efca57a652ee8204e738f786a Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 25 Jul 2016 14:25:22 +0200 Subject: [PATCH 208/413] add ue spec channel estimation in UE RX procedure (TM7 works for DLSCH) --- .../lte_dl_bf_channel_estimation.c | 70 ++++++++++++++----- openair1/SCHED/phy_procedures_lte_ue.c | 29 +++++--- 2 files changed, 71 insertions(+), 28 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c index 80df031c41..4d20cfe522 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c @@ -32,7 +32,7 @@ #include "defs.h" #include "PHY/defs.h" #include "filt16_32.h" -//#define DEBUG_CH +//#define DEBUG_BF_CH int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, uint8_t eNB_id, @@ -373,19 +373,25 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); multadd_real_vector_complex_scalar(fl,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); +#ifdef DEBUG_BF_CH + printf("symbol=%d,rxF[0]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); +#endif pil+=2; ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); multadd_real_vector_complex_scalar(fm,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[8],rxF[9],pil[0],pil[1],ch[0],ch[1]); +#ifdef DEBUG_BF_CH + printf("symbol=%d,rxF[4]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,rxF[8],rxF[9],pil[0],pil[1],ch[0],ch[1]); +#endif pil+=2; ch[0] = (short)(((int)pil[0]*rxF[16] - (int)pil[1]*rxF[17])>>15); ch[1] = (short)(((int)pil[0]*rxF[17] + (int)pil[1]*rxF[16])>>15); multadd_real_vector_complex_scalar(fr,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[16],rxF[17],pil[0],pil[1],ch[0],ch[1]); +#ifdef DEBUG_BF_CH + printf("symbol=%d,rxF[8]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,rxF[16],rxF[17],pil[0],pil[1],ch[0],ch[1]); +#endif pil+=2; } @@ -447,13 +453,17 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); multadd_real_vector_complex_scalar(fl_dc,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); +#ifdef DEBUG_BF_CH + //printf("symbol=%d,rxF[0]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); +#endif pil+=2;; ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); multadd_real_vector_complex_scalar(fm_dc,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[8],rxF[9],pil[0],pil[1],ch[0],ch[1]); +#ifdef DEBUG_BF_CH + //printf("symbol=%d,rxF[4]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,rxF[8],rxF[9],pil[0],pil[1],ch[0],ch[1]); +#endif pil+=2;; rxF = (short *)&rxdataF[aarx][symbol*(frame_parms->ofdm_symbol_size)]; @@ -461,13 +471,17 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, ch[0] = (short)(((int)pil[0]*rxF[6] - (int)pil[1]*rxF[7])>>15); ch[1] = (short)(((int)pil[0]*rxF[7] + (int)pil[1]*rxF[6])>>15); multadd_real_vector_complex_scalar(fr_dc,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[6],rxF[7],pil[0],pil[1],ch[0],ch[1]); +#ifdef DEBUG_BF_CH + //printf("symbol=%d,rxF[3]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,rxF[6],rxF[7],pil[0],pil[1],ch[0],ch[1]); +#endif pil+=2;; } else { ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); multadd_real_vector_complex_scalar(fl_dc,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); +#ifdef DEBUG_BF_CH + //printf("symbol=%d,rxF[0]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); +#endif pil+=2;; rxF = (short *)&rxdataF[aarx][symbol*(frame_parms->ofdm_symbol_size)]; @@ -475,13 +489,17 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, ch[0] = (short)(((int)pil[0]*rxF[2] - (int)pil[1]*rxF[3])>>15); ch[1] = (short)(((int)pil[0]*rxF[3] + (int)pil[1]*rxF[2])>>15); multadd_real_vector_complex_scalar(fm_dc,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[2],rxF[3],pil[0],pil[1],ch[0],ch[1]); +#ifdef DEBUG_BF_CH + //printf("symbol=%d,rxF[1]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,rxF[2],rxF[3],pil[0],pil[1],ch[0],ch[1]); +#endif pil+=2;; ch[0] = (short)(((int)pil[0]*rxF[10] - (int)pil[1]*rxF[11])>>15); ch[1] = (short)(((int)pil[0]*rxF[11] + (int)pil[1]*rxF[10])>>15); multadd_real_vector_complex_scalar(fr_dc,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[10],rxF[11],pil[0],pil[1],ch[0],ch[1]); +#ifdef DEBUG_BF_CH + //printf("symbol=%d,rxF[5]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,rxF[10],rxF[11],pil[0],pil[1],ch[0],ch[1]); +#endif pil+=2;; } } // rballoc==1 @@ -604,19 +622,25 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, ch[0] = (short)(((int)pil[0]*rxF[0] - (int)pil[1]*rxF[1])>>15); ch[1] = (short)(((int)pil[0]*rxF[1] + (int)pil[1]*rxF[0])>>15); multadd_real_vector_complex_scalar(fl,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); +#ifdef DEBUG_BF_CH + printf("symbol=%d,rxF[0]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,rxF[0],rxF[1],pil[0],pil[1],ch[0],ch[1]); +#endif pil+=2; ch[0] = (short)(((int)pil[0]*rxF[8] - (int)pil[1]*rxF[9])>>15); ch[1] = (short)(((int)pil[0]*rxF[9] + (int)pil[1]*rxF[8])>>15); multadd_real_vector_complex_scalar(fm,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[8],rxF[9],pil[0],pil[1],ch[0],ch[1]); +#ifdef DEBUG_BF_CH + printf("symbol=%d,rxF[4]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,rxF[8],rxF[9],pil[0],pil[1],ch[0],ch[1]); +#endif pil+=2; ch[0] = (short)(((int)pil[0]*rxF[16] - (int)pil[1]*rxF[17])>>15); ch[1] = (short)(((int)pil[0]*rxF[17] + (int)pil[1]*rxF[16])>>15); multadd_real_vector_complex_scalar(fr,ch,dl_bf_ch,16); - //printf("symbol=%d,rxF[%d]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,pil_offset,rxF[16],rxF[17],pil[0],pil[1],ch[0],ch[1]); +#ifdef DEBUG_BF_CH + printf("symbol=%d,rxF[8]=(%d,%d),pil=(%d,%d),ch=(%d,%d)\n",symbol,rxF[16],rxF[17],pil[0],pil[1],ch[0],ch[1]); +#endif pil+=2; } @@ -641,7 +665,9 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, if (phy_vars_ue->perfect_ce == 0) { dl_bf_ch = (short *)&dl_bf_ch_estimates[aarx][ch_offset]; - //printf("dlsch_bf_ch_est.c:symbol %d, dl_bf_ch (%d,%d)\n",symbol,dl_bf_ch[0],dl_bf_ch[1]); +#ifdef DEBUG_BF_CH + printf("[dlsch_bf_ch_est.c]:symbol %d, dl_bf_ch (%d,%d)\n",symbol,dl_bf_ch[0],dl_bf_ch[1]); +#endif if (phy_vars_ue->high_speed_flag == 0) { multadd_complex_vector_real_scalar(dl_bf_ch, @@ -655,7 +681,9 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, // printf("Interpolating %d->0\n",4-phy_vars_ue->lte_frame_parms.Ncp); // dl_bf_ch_prev = (short *)&dl_bf_ch_estimates[aarx][(4-phy_vars_ue->lte_frame_parms.Ncp)*(frame_parms->ofdm_symbol_size)]; dl_bf_ch_prev = (short *)&dl_bf_ch_estimates[aarx][pilot3*(frame_parms->ofdm_symbol_size)]; - +#ifdef DEBUG_BF_CH + printf("[dlsch_bf_ch_est.c] symbol=%d, dl_bf_ch_prev=(%d,%d), dl_bf_ch=(%d,%d)\n", symbol, dl_bf_ch_prev[0], dl_bf_ch_prev[1], dl_bf_ch[0], dl_bf_ch[1]); +#endif // pilot spacing 5 symbols (1/5,2/5,3/5,4/5 combination) multadd_complex_vector_real_scalar(dl_bf_ch_prev,26214,dl_bf_ch_prev+(2*(frame_parms->ofdm_symbol_size)),1,frame_parms->ofdm_symbol_size); multadd_complex_vector_real_scalar(dl_bf_ch,6554,dl_bf_ch_prev+(2*(frame_parms->ofdm_symbol_size)),0,frame_parms->ofdm_symbol_size); @@ -670,6 +698,9 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, multadd_complex_vector_real_scalar(dl_bf_ch,26214,dl_bf_ch-(2*(frame_parms->ofdm_symbol_size)),0,frame_parms->ofdm_symbol_size); } else if (symbol == pilot1) { dl_bf_ch_prev = (short *)&dl_bf_ch_estimates[aarx][pilot0*(frame_parms->ofdm_symbol_size)]; +#ifdef DEBUG_BF_CH + printf("[dlsch_bf_ch_est.c] symbol=%d, dl_bf_ch_prev=(%d,%d), dl_bf_ch=(%d,%d)\n", symbol, dl_bf_ch_prev[0], dl_bf_ch_prev[1], dl_bf_ch[0], dl_bf_ch[1]); +#endif // pilot spacing 3 symbols (1/3,2/3 combination) multadd_complex_vector_real_scalar(dl_bf_ch_prev,21845,dl_bf_ch_prev+(2*(frame_parms->ofdm_symbol_size)),1,frame_parms->ofdm_symbol_size); @@ -680,6 +711,9 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, } else if (symbol == pilot2) { dl_bf_ch_prev = (short *)&dl_bf_ch_estimates[aarx][pilot1*(frame_parms->ofdm_symbol_size)]; +#ifdef DEBUG_BF_CH + printf("[dlsch_bf_ch_est.c] symbol=%d, dl_bf_ch_prev=(%d,%d), dl_bf_ch=(%d,%d)\n", symbol, dl_bf_ch_prev[0], dl_bf_ch_prev[1], dl_bf_ch[0], dl_bf_ch[1]); +#endif multadd_complex_vector_real_scalar(dl_bf_ch_prev,21845,dl_bf_ch_prev+(2*(frame_parms->ofdm_symbol_size)),1,frame_parms->ofdm_symbol_size); multadd_complex_vector_real_scalar(dl_bf_ch,10923,dl_bf_ch_prev+(2*(frame_parms->ofdm_symbol_size)),0,frame_parms->ofdm_symbol_size); @@ -707,8 +741,10 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, } } } //aarx - - // printf("[dlsch bf ch est]: dl_bf_estimates[0][600] %d, %d \n",*(short *)&dl_bf_ch_estimates[0][600],*(short*)&phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates[0][600]); + +#ifdef DEBUG_BF_CH + printf("[dlsch_bf_ch_est.c]: dl_bf_estimates[0][600] %d, %d \n",*(short *)&dl_bf_ch_estimates[0][600],*(short*)&phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates[0][600]); +#endif return(0); diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 36a7f525e3..a4c40036aa 100755 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -2562,16 +2562,6 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac #endif - if (phy_vars_ue->dlsch_ue[eNB_id][0]->active == 1) { - if (phy_vars_ue->transmission_mode[eNB_id]==7) { - if (phy_vars_ue->lte_frame_parms.Ncp==0) { - if (((slot_rx%2)==0 && ((l==3) || (l==6))) || ((slot_rx%2)==1 && ((l==2) || (l==5)))) - lte_dl_bf_channel_estimation(phy_vars_ue,eNB_id,0,slot_rx,5,l+7*(slot_rx%2==1)); - } else { - LOG_E(PHY,"[UE %d]Beamforming channel estimation not supported yet for TM7 extented CP.\n",phy_vars_ue->Mod_id); - } - } - } // process last DLSCH symbols + invoke decoding if (((slot_rx%2)==0) && (l==0)) { // Regular PDSCH @@ -3092,7 +3082,8 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac } - if ((((slot_rx%2)==0) && ((l==pilot1))) || + if ((((slot_rx%2)==0) && (l==pilot1) && (phy_vars_ue->transmission_mode[eNB_id]<7)) || + (((slot_rx%2)==0) && (l==3) && (phy_vars_ue->transmission_mode[eNB_id]==7)) || ((pmch_flag==1)&&(l==1))) { #ifdef DEBUG_PHY_PROC @@ -3114,6 +3105,22 @@ int phy_procedures_UE_RX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstrac #endif } + // TM7 UE specific channel estimation +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[UE %d] BF: dlsch->active in subframe %d => %d, l=%d\n",phy_vars_ue->Mod_id,subframe_rx,phy_vars_ue->dlsch_ue[eNB_id][0]->active, l); +#endif + if (phy_vars_ue->dlsch_ue[eNB_id][0]->active == 1) { + if (phy_vars_ue->transmission_mode[eNB_id]==7) { + if (phy_vars_ue->lte_frame_parms.Ncp==0) { + if (((slot_rx%2)==0 && ((l==3) || (l==6))) || ((slot_rx%2)==1 && ((l==2) || (l==5)))) + //LOG_D(PHY,"[UE %d] dlsch->active in subframe %d => %d, l=%d\n",phy_vars_ue->Mod_id,subframe_rx,phy_vars_ue->dlsch_ue[eNB_id][0]->active, l); + lte_dl_bf_channel_estimation(phy_vars_ue,eNB_id,0,slot_rx,5,l+7*(slot_rx%2==1)); + } else { + LOG_E(PHY,"[UE %d]Beamforming channel estimation not supported yet for TM7 extented CP.\n",phy_vars_ue->Mod_id); + } + } + } + if (abstraction_flag==0) { if (((slot_rx%2)==1) && (l==0)) { From e3dbfa3dde100d5c7d3a05b866168101e4231743 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 26 Jul 2016 11:43:10 +0200 Subject: [PATCH 209/413] some cleanup --- openair1/PHY/impl_defs_lte.h | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h index 73974623f7..f61aa2dcc9 100644 --- a/openair1/PHY/impl_defs_lte.h +++ b/openair1/PHY/impl_defs_lte.h @@ -632,19 +632,8 @@ typedef struct { /// - first index: eNB id [0..2] (hard coded) /// - second index: sample [0..samples_per_tti*10[ uint32_t *sync_corr[3]; - /// \brief Holds the cell specific beamforming weights - /// - first index: eNB id [0..2] (hard coded) - /// - second index: cell specific eNB antenna port index, up to 2 logical antenna ports are supported - /// - third index: tx antenna [0..nb_antennas_tx[ - /// - fourth index: sample [0..] - // int32_t **cell_spec_bf_weights[3][2]; - /// \brief Holds the ue specific beamforming weights - /// - first index: eNB id [0..2] (hard coded) - /// - second index: ue specific eNB antenna port index, port5->index0, port7-15->index0-7 - /// - third index: tx antenna [0..nb_antennas_tx[ - /// - fourth index: sample [0..] - // int32_t **ue_spec_bf_weights[3][8]; - /// \brief Holds the ue specific beamforming weights + // int32_t **beam_weights[3][15]; + /// \brief Holds the beamforming weights /// - first index: eNB id [0..2] (hard coded) /// - second index: eNB antenna port index /// - third index: tx antenna [0..nb_antennas_tx[ From fdde582e9208e9c3ab47cfd728f46655cded432c Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 11 Aug 2016 16:29:43 +0200 Subject: [PATCH 210/413] bug fixed in pbch for nb_antennas_tx>1 --- openair1/PHY/LTE_TRANSPORT/pbch.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/pbch.c b/openair1/PHY/LTE_TRANSPORT/pbch.c index cba6a16fa4..3ad974dab6 100755 --- a/openair1/PHY/LTE_TRANSPORT/pbch.c +++ b/openair1/PHY/LTE_TRANSPORT/pbch.c @@ -74,7 +74,7 @@ int allocate_pbch_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, MIMO_mode_t mimo_mode = (frame_parms->mode1_flag==1)?SISO:ALAMOUTI; - uint32_t tti_offset,aa; + uint32_t tti_offset; uint8_t re; int16_t gain_lin_QPSK; int16_t re_off=re_offset; @@ -99,15 +99,11 @@ int allocate_pbch_REs_in_RB(LTE_DL_FRAME_PARMS *frame_parms, *re_allocated = *re_allocated + 1; // printf("%d(%d) : %d,%d => ",tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t*)&txdataF[aa][tti_offset])[0] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i - } + ((int16_t*)&txdataF[0][tti_offset])[0] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i *jj = *jj + 1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t*)&txdataF[aa][tti_offset])[1] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} - } + ((int16_t*)&txdataF[0][tti_offset])[1] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} *jj = *jj + 1; } else if (mimo_mode == ALAMOUTI) { From 9f4a849115c6fa90f96ef4243b8a7deeff843520 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Thu, 18 Aug 2016 12:46:02 +0200 Subject: [PATCH 211/413] added prototypes to compute beamforming weights --- cmake_targets/CMakeLists.txt | 1 + openair1/PHY/MODULATION/beamforming.c | 1 - openair1/PHY/MODULATION/compute_bf_weights.c | 54 ++++++++++++++++++++ openair1/PHY/MODULATION/defs.h | 7 +++ openair1/PHY/impl_defs_lte.h | 9 ++++ 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 openair1/PHY/MODULATION/compute_bf_weights.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 02a6ac5151..1027718d48 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -976,6 +976,7 @@ set(PHY_SRC ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_ul.c ${OPENAIR1_DIR}/PHY/MODULATION/ul_7_5_kHz.c ${OPENAIR1_DIR}/PHY/MODULATION/beamforming.c + ${OPENAIR1_DIR}/PHY/MODULATION/compute_bf_weights.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/freq_equalization.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_time.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_timefreq.c diff --git a/openair1/PHY/MODULATION/beamforming.c b/openair1/PHY/MODULATION/beamforming.c index 2e38b7cb93..00bb9e5dca 100644 --- a/openair1/PHY/MODULATION/beamforming.c +++ b/openair1/PHY/MODULATION/beamforming.c @@ -120,4 +120,3 @@ int beam_precoding(int32_t **txdataF, } } } - diff --git a/openair1/PHY/MODULATION/compute_bf_weights.c b/openair1/PHY/MODULATION/compute_bf_weights.c new file mode 100644 index 0000000000..620380737c --- /dev/null +++ b/openair1/PHY/MODULATION/compute_bf_weights.c @@ -0,0 +1,54 @@ +#include +#include +#include "PHY/impl_defs_lte.h" + +int f_read(char *calibF_fname, int nb_ant, int nb_freq, int32_t **tdd_calib_coeffs){ + + FILE *calibF_fd; + int i,j,l,calibF_e; + + calibF_fd = fopen(calibF_fname,"r"); + + if (calibF_fd) { + printf("Loading Calibration matrix from %s\n", calibF_fname); + + for(i=0;irx_vars[a].RX_DMA_BUFFER. From 7b114b08dbdf961a195232033de3db511ee3c032 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Thu, 18 Aug 2016 12:48:54 +0200 Subject: [PATCH 212/413] adding functions to compute bf weights to dlsim --- openair1/PHY/LTE_TRANSPORT/defs.h | 2 ++ openair1/PHY/MODULATION/compute_bf_weights.c | 4 ++- openair1/PHY/impl_defs_lte.h | 8 ++---- openair1/SIMULATION/LTE_PHY/dlsim.c | 30 ++++++++++++++++++++ 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/defs.h b/openair1/PHY/LTE_TRANSPORT/defs.h index 8bcf312c3e..e0029be318 100644 --- a/openair1/PHY/LTE_TRANSPORT/defs.h +++ b/openair1/PHY/LTE_TRANSPORT/defs.h @@ -242,6 +242,8 @@ typedef struct { int32_t *txdataF[8]; /// beamforming weights for UE-spec transmission (antenna ports 5 or 7..14), for each codeword, maximum 4 layers? int32_t **ue_spec_bf_weights[4]; + /// dl channel estimates (estimated from ul channel estimates) + int32_t **calib_dl_ch_estimates; /// Allocated RNTI (0 means DLSCH_t is not currently used) uint16_t rnti; /// Active flag for baseband transmitter processing diff --git a/openair1/PHY/MODULATION/compute_bf_weights.c b/openair1/PHY/MODULATION/compute_bf_weights.c index 620380737c..32a91c11f5 100644 --- a/openair1/PHY/MODULATION/compute_bf_weights.c +++ b/openair1/PHY/MODULATION/compute_bf_weights.c @@ -47,8 +47,10 @@ int compute_BF_weights(int32_t **beam_weights, int32_t **calib_dl_ch_estimates, } // temporal test function +/* void main(){ // initialization // compare printf("Hello world!\n"); -} \ No newline at end of file +} +*/ diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h index 9cbff7fdb6..9d075dd9bb 100644 --- a/openair1/PHY/impl_defs_lte.h +++ b/openair1/PHY/impl_defs_lte.h @@ -641,18 +641,16 @@ typedef struct { /// - first index: eNB id [0..2] (hard coded) /// - second index: sample [0..samples_per_tti*10[ uint32_t *sync_corr[3]; - // int32_t **beam_weights[3][15]; /// \brief Holds the beamforming weights /// - first index: eNB id [0..2] (hard coded) - /// - second index: eNB antenna port index + /// - second index: eNB antenna port index (hard coded) /// - third index: tx antenna [0..nb_antennas_tx[ /// - fourth index: sample [0..] int32_t **beam_weights[3][15]; /// \brief Holds the tdd reciprocity calibration coefficients /// - first index: eNB id [0..2] (hard coded) - /// - second index: ue specific eNB antenna port index, port5->index0, port7-15->index0-7 - /// - third index: tx antenna [0..nb_antennas_tx[ - /// - forth index: frenquency [0..] + /// - second index: tx antenna [0..nb_antennas_tx[ + /// - third index: frequency [0..] int32_t **tdd_calib_coeffs[3]; } LTE_eNB_COMMON; diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index dd535064d1..1a34e59f5a 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -991,6 +991,9 @@ int main(int argc, char **argv) PHY_vars_eNB->eNB_UE_stats[1].DL_pmi_single = 0; } + //TODO: allocate memory for calibration matrix and calib_dl_ch_estimates in init_lte.c + //for first tests initialze calibration matrix with idendity + //read_calibration_matrix(calib_fname, nb_ant, nb_freq, PHY_vars_eNB->lte_eNB_common_vars.tdd_calib_coeffs[0]); if (input_fd==NULL) { @@ -2142,6 +2145,32 @@ int main(int argc, char **argv) PMI_FEEDBACK: + //make sure dlsim is called with perfect channel estimation option (for freq_channel) + //fill drs_ch_estimates with data from eNB2UE->chF + for(aa=0; aanb_antenna_ports_eNB; aa++) { + for (aarx=0; aarxnb_antennas_rx; aarx++) { + for (i=0; iN_RB_DL*12; i++) { + for (l=0; lsymbols_per_tti; l++) { + ((int16_t *) PHY_vars_eNB->lte_eNB_pusch_vars[0]->drs_ch_estimates[0][(aa<<1)+aarx])[2*i+(l*frame_parms->ofdm_symbol_size)*2]=(int16_t)(eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x*AMP); + //printf("x=%d,AMP=%d\n",eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x,AMP); + ((int16_t *) PHY_vars_eNB->lte_eNB_pusch_vars[0]->drs_ch_estimates[0][(aa<<1)+aarx])[2*i+1+(l*frame_parms->ofdm_symbol_size)*2]=(int16_t)(eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].y*AMP); + } + } + } + } + + estimate_DLCSI_from_ULCSI(PHY_vars_eNB->dlsch_eNB[0][0]->calib_dl_ch_estimates, + &PHY_vars_eNB->lte_eNB_pusch_vars[0]->drs_ch_estimates[0][0/*position of second DMRS*/], + PHY_vars_eNB->lte_eNB_common_vars.tdd_calib_coeffs[0], + frame_parms->nb_antennas_tx, + frame_parms->N_RB_DL*12); + + compute_BF_weights(PHY_vars_eNB->dlsch_eNB[0][0]->ue_spec_bf_weights[0], + PHY_vars_eNB->dlsch_eNB[0][0]->calib_dl_ch_estimates, + MRT, + frame_parms->nb_antennas_tx, + frame_parms->N_RB_DL*12); + //printf("Trial %d : Round %d, pmi_feedback %d \n",trials,round,pmi_feedback); for (aa=0; aalte_eNB_common_vars.txdataF[eNB_id][aa][0],0,FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(int32_t)); @@ -3088,6 +3117,7 @@ PMI_FEEDBACK: eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].y*AMP); if (transmission_mode == 7){ + //this should include the BF weights! Will not work for a random channel if (PHY_vars_UE->high_speed_flag==0) { ((int16_t *)PHY_vars_UE->lte_ue_pdsch_vars[0]->dl_bf_ch_estimates[(aa<<1)+aarx])[2*i]=(int16_t)( eNB2UE[round]->chF[aarx+(aa*frame_parms->nb_antennas_rx)][i].x*AMP); From cc6ca6fc122113ef19e89febcfda89a861220c17 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 18 Aug 2016 17:29:03 +0200 Subject: [PATCH 213/413] bug fixed for PSS and SSS generation --- openair1/PHY/LTE_TRANSPORT/pss.c | 4 ++-- openair1/PHY/LTE_TRANSPORT/sss.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/pss.c b/openair1/PHY/LTE_TRANSPORT/pss.c index e2a4c549da..f14f7cf326 100644 --- a/openair1/PHY/LTE_TRANSPORT/pss.c +++ b/openair1/PHY/LTE_TRANSPORT/pss.c @@ -80,12 +80,12 @@ int generate_pss(int32_t **txdataF, return(-1); } - a = (frame_parms->nb_antennas_tx == 1) ? amp: (amp*ONE_OVER_SQRT2_Q15)>>15; + a = (frame_parms->nb_antenna_ports_eNB == 1) ? amp: (amp*ONE_OVER_SQRT2_Q15)>>15; //printf("[PSS] amp=%d, a=%d\n",amp,a); Nsymb = (frame_parms->Ncp==NORMAL)?14:12; - for (aa=0; aanb_antennas_tx; aa++) { + for (aa=0; aanb_antenna_ports_eNB; aa++) { // aa = 0; // The PSS occupies the inner 6 RBs, which start at diff --git a/openair1/PHY/LTE_TRANSPORT/sss.c b/openair1/PHY/LTE_TRANSPORT/sss.c index 34d55daaea..bd38db80d5 100644 --- a/openair1/PHY/LTE_TRANSPORT/sss.c +++ b/openair1/PHY/LTE_TRANSPORT/sss.c @@ -67,10 +67,10 @@ int generate_sss(int32_t **txdataF, Nsymb = (frame_parms->Ncp==NORMAL)?14:12; k = frame_parms->ofdm_symbol_size-3*12+5; - a = (frame_parms->nb_antennas_tx == 1) ? amp : (amp*ONE_OVER_SQRT2_Q15)>>15; + a = (frame_parms->nb_antenna_ports_eNB == 1) ? amp : (amp*ONE_OVER_SQRT2_Q15)>>15; for (i=0; i<62; i++) { - for (aa=0; aanb_antennas_tx; aa++) { + for (aa=0; aanb_antenna_ports_eNB; aa++) { ((int16_t*)txdataF[aa])[2*(slot_offset*Nsymb/2*frame_parms->ofdm_symbol_size + symbol*frame_parms->ofdm_symbol_size + k)] = From e10ed0bec865aeb80ca7e8c3a995a9a73941434f Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 18 Aug 2016 17:30:12 +0200 Subject: [PATCH 214/413] EXMIMO duplex mode always set to FDD --- targets/RT/USER/lte-softmodem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 8b48148955..5511b4a15f 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -3278,9 +3278,11 @@ int main( int argc, char **argv ) openair0_cfg[card].rx_bw = 1.5e6; } + /* if (frame_parms[0]->frame_type==TDD) openair0_cfg[card].duplex_mode = duplex_mode_TDD; else //FDD + */ openair0_cfg[card].duplex_mode = duplex_mode_FDD; From 0985080287eb84ae08827c3409f2ff22041c99dd Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 18 Aug 2016 17:34:25 +0200 Subject: [PATCH 215/413] add tm7 tdd config file --- openair1/PHY/INIT/lte_parms.c | 1 + .../GENERIC-LTE-EPC/CONF/enb.band38.tm7.exmimo2.conf | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/openair1/PHY/INIT/lte_parms.c b/openair1/PHY/INIT/lte_parms.c index fa0e731af9..7930549f67 100644 --- a/openair1/PHY/INIT/lte_parms.c +++ b/openair1/PHY/INIT/lte_parms.c @@ -191,6 +191,7 @@ void dump_frame_parms(LTE_DL_FRAME_PARMS *frame_parms) printf("frame_parms->tdd_config=%d\n",frame_parms->tdd_config); printf("frame_parms->tdd_config_S=%d\n",frame_parms->tdd_config_S); printf("frame_parms->mode1_flag=%d\n",frame_parms->mode1_flag); + printf("frame_parms->nb_antenna_ports_eNB=%d\n",frame_parms->nb_antenna_ports_eNB); printf("frame_parms->nb_antennas_tx=%d\n",frame_parms->nb_antennas_tx); printf("frame_parms->nb_antennas_rx=%d\n",frame_parms->nb_antennas_rx); printf("frame_parms->ofdm_symbol_size=%d\n",frame_parms->ofdm_symbol_size); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm7.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm7.exmimo2.conf index deff3db9dd..f9b765d1e0 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm7.exmimo2.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm7.exmimo2.conf @@ -33,8 +33,9 @@ eNBs = Nid_cell = 0; N_RB_DL = 25; Nid_cell_mbsfn = 0; - nb_antennas_tx = 4; - nb_antennas_rx = 4; + nb_antenna_ports = 1; + nb_antennas_tx = 1; + nb_antennas_rx = 1; tx_gain = 10; //25; rx_gain = 10; //20; prach_root = 0; @@ -97,6 +98,8 @@ eNBs = ue_TimersAndConstants_t311 = 10000; ue_TimersAndConstants_n310 = 20; ue_TimersAndConstants_n311 = 1; + + ue_TransmissionMode = 7; } ); @@ -152,7 +155,7 @@ eNBs = { global_log_level ="info"; global_log_verbosity ="medium"; - hw_log_level ="debug"; + hw_log_level ="info"; hw_log_verbosity ="medium"; phy_log_level ="info"; phy_log_verbosity ="medium"; From 1cbb2c5caa169c26e8d99942be60f1ea5841ac68 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 18 Aug 2016 19:08:51 +0200 Subject: [PATCH 216/413] memory allocation for calibration coefficients and dlsch ue spec bf weight --- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 20 +++++++++++++++++++- openair1/SIMULATION/LTE_PHY/dlsim.c | 5 +---- targets/SIMU/USER/init_lte.c | 12 ------------ 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index 48498a4873..9d7f5597cf 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -123,7 +123,8 @@ LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_ { LTE_eNB_DLSCH_t *dlsch; - unsigned char exit_flag = 0,i,j,r,aa; + unsigned char exit_flag = 0,i,j,r,aa,layer; + int re; unsigned char bw_scaling =1; uint8_t nb_antennas_tx = frame_parms->nb_antennas_tx; @@ -154,6 +155,23 @@ LTE_eNB_DLSCH_t *new_eNB_dlsch(unsigned char Kmimo,unsigned char Mdlharq,uint32_ dlsch->Mlimit = 4; dlsch->Nsoft = Nsoft; + for (layer=0; layer<4; layer++) { + dlsch->ue_spec_bf_weights[layer] = (int32_t**)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*)); + + for (aa=0; aanb_antennas_tx; aa++) { + dlsch->ue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); + for (re=0;reue_spec_bf_weights[layer][aa][re] = 0x00007fff; + } + } + } + + dlsch->calib_dl_ch_estimates = (int32_t**)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*)); + for (aa=0; aanb_antennas_tx; aa++) { + dlsch->calib_dl_ch_estimates[aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); + + } + for (i=0; i<10; i++) dlsch->harq_ids[i] = Mdlharq; diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 1a34e59f5a..294dbf3b44 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -934,13 +934,10 @@ int main(int argc, char **argv) } else { // this initilisation may should be moved to another place for (j=0; j<4; j++) { - PHY_vars_eNB->dlsch_eNB[k][i]->ue_spec_bf_weights[j] = (int32_t **)malloc16(n_tx_phy*sizeof(int32_t*)); - for (aa=0; aadlsch_eNB[k][i]->ue_spec_bf_weights[j][aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); ue_spec_bf_weights = PHY_vars_eNB->dlsch_eNB[k][i]->ue_spec_bf_weights[j][aa]; - for (re=0;reofdm_symbol_size;re++) { + for (re=0;re %p\n",i,j,PHY_vars_eNB->dlsch_eNB[i][j]); PHY_vars_eNB->dlsch_eNB[i][j]->rnti=0; - - for (layer=0; layer<4; layer++) { - PHY_vars_eNB->dlsch_eNB[i][j]->ue_spec_bf_weights[layer] = (int32_t **)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*)); - - for (aa=0; aanb_antennas_tx; aa++) { - PHY_vars_eNB->dlsch_eNB[i][j]->ue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); - for (re=0;redlsch_eNB[i][j]->ue_spec_bf_weights[layer][aa][re] = 0x00007fff; - } - } - } - } } From bc9c4cfebc0c904a925b02984f0cc8c0c4e3aeaa Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 22 Aug 2016 10:33:43 +0200 Subject: [PATCH 217/413] do_OFDM_mod_rt to perform on each symbol --- targets/RT/USER/lte-softmodem.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 5511b4a15f..cab7e15b27 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -962,7 +962,21 @@ void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB) ((subframe_select(&phy_vars_eNB->lte_frame_parms,subframe)==SF_S))) { // LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot); + do_OFDM_mod_l(&phy_vars_eNB->lte_eNB_common_vars, + 0, + subframe<<1, + &phy_vars_eNB->lte_frame_parms); + + // if S-subframe generate first slot only + if (subframe_select(&phy_vars_eNB->lte_frame_parms,subframe) == SF_DL) { + do_OFDM_mod_l(&phy_vars_eNB->lte_eNB_common_vars, + 0, + 1+(subframe<<1), + &phy_vars_eNB->lte_frame_parms); + } + +/* for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { if (phy_vars_eNB->lte_frame_parms.Ncp == EXTENDED) { PHY_ofdm_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F], @@ -989,7 +1003,9 @@ void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB) 7, &(phy_vars_eNB->lte_frame_parms)); } + } */ + for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { // if S-subframe generate first slot only if (subframe_select(&phy_vars_eNB->lte_frame_parms,subframe) == SF_S) len = phy_vars_eNB->lte_frame_parms.samples_per_tti>>1; @@ -1012,9 +1028,13 @@ void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB) if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti)) tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti; - ((short*)&phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset])[0] = ((short*)dummy_tx_b)[2*i]<lte_eNB_common_vars.txdata[0][aa][tx_offset])[0] = ((short*)dummy_tx_b)[2*i]<lte_eNB_common_vars.txdata[0][aa][tx_offset])[1] = ((short*)dummy_tx_b)[2*i+1]<lte_eNB_common_vars.txdata[0][aa][tx_offset])[1] = ((short*)dummy_tx_b)[2*i+1]<lte_eNB_common_vars.txdata[0][aa][tx_offset])[0] = ((short*)&phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset])[0]<lte_eNB_common_vars.txdata[0][aa][tx_offset])[1] = ((short*)&phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset])[1]<lte_frame_parms,subframe) == SF_S) { From f277acfef5f8ab68765c0fbe81c24e14073ac090 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 22 Aug 2016 10:35:11 +0200 Subject: [PATCH 218/413] remove num_pdcch_symb from paramters of dp_OFDM_mod_l --- openair1/PHY/MODULATION/defs.h | 2 +- openair1/PHY/MODULATION/ofdm_mod.c | 14 +++++++++----- openair1/SCHED/phy_procedures_lte_eNb.c | 10 ++-------- openair1/SIMULATION/LTE_PHY/dlsim.c | 6 ++---- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/openair1/PHY/MODULATION/defs.h b/openair1/PHY/MODULATION/defs.h index 597d433df8..92d4988f77 100644 --- a/openair1/PHY/MODULATION/defs.h +++ b/openair1/PHY/MODULATION/defs.h @@ -89,7 +89,7 @@ void normal_prefix_mod(int32_t *txdataF,int32_t *txdata,uint8_t nsymb,LTE_DL_FRA void do_OFDM_mod(int32_t **txdataF, int32_t **txdata, uint32_t frame,uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms); -void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms, uint8_t num_pdcch_symbols); +void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms); void remove_7_5_kHz(PHY_VARS_eNB *phy_vars_eNB,uint8_t subframe); diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 1f7aeb533a..3139a7bc08 100755 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -291,19 +291,17 @@ void do_OFDM_mod(int32_t **txdataF, int32_t **txdata, uint32_t frame,uint16_t ne } // OFDM modulation for each symbol -void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms, uint8_t num_pdcch_symbols) +void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms) { - int aa, l, slot_offset, slot_offset_F; - int8_t UE_id=0; + int aa, l, slot_offset; int32_t **txdataF = eNB_common_vars->txdataF[eNB_id]; int32_t **txdataF_BF = eNB_common_vars->txdataF_BF[eNB_id]; int32_t **txdata = eNB_common_vars->txdata[eNB_id]; - //slot_offset_F = (next_slot)*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); slot_offset = (next_slot)*(frame_parms->samples_per_tti>>1); - // printf("Thread %d starting ... aa %d (%llu)\n",omp_get_thread_num(),aa,rdtsc()); + //printf("Thread %d starting ... aa %d (%llu)\n",omp_get_thread_num(),aa,rdtsc()); for (l=0; lsymbols_per_tti>>1; l++) { //printf("do_OFDM_mod_l, slot=%d, l=%d, NUMBER_OF_OFDM_CARRIERS=%d,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES=%d\n",next_slot, l,NUMBER_OF_OFDM_CARRIERS,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES); @@ -312,6 +310,8 @@ void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_sl for (aa=0; aanb_antennas_tx; aa++) { + //PMCH case not implemented... + if (frame_parms->Ncp == 1) PHY_ofdm_mod(txdataF_BF[aa], // input &txdata[aa][slot_offset+l*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES], // output @@ -335,6 +335,10 @@ void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_sl 1, // number of symbols frame_parms->nb_prefix_samples, // number of prefix samples CYCLIC_PREFIX); + + /* printf("txdata[%d][%d]=%d\n",aa, + slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES, + &txdata[aa][slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES]);*/ } } } diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 3c2b1bdf17..523e54c448 100755 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -1649,27 +1649,21 @@ void phy_procedures_eNB_TX(unsigned char sched_subframe,PHY_VARS_eNB *phy_vars_e phy_procedures_emos_eNB_TX(subframe, phy_vars_eNB); #endif - //cell-specific beamforming - #if !(defined(EXMIMO) || defined(OAI_USRP) || defined (CPRIGW)) if (abstraction_flag==0) { start_meas(&phy_vars_eNB->ofdm_mod_stats); - //do_OFDM_mod (without l) ? - do_OFDM_mod_l(&phy_vars_eNB->lte_eNB_common_vars, 0, subframe<<1, - &phy_vars_eNB->lte_frame_parms, - num_pdcch_symbols); + &phy_vars_eNB->lte_frame_parms); do_OFDM_mod_l(&phy_vars_eNB->lte_eNB_common_vars, 0, 1+(subframe<<1), - &phy_vars_eNB->lte_frame_parms, - num_pdcch_symbols); + &phy_vars_eNB->lte_frame_parms); stop_meas(&phy_vars_eNB->ofdm_mod_stats); } diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 294dbf3b44..0ea247f440 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -2835,14 +2835,12 @@ PMI_FEEDBACK: do_OFDM_mod_l(&PHY_vars_eNB->lte_eNB_common_vars, eNB_id, (subframe*2), - &PHY_vars_eNB->lte_frame_parms, - num_pdcch_symbols); + &PHY_vars_eNB->lte_frame_parms); do_OFDM_mod_l(&PHY_vars_eNB->lte_eNB_common_vars, eNB_id, (subframe*2)+1, - &PHY_vars_eNB->lte_frame_parms, - num_pdcch_symbols); + &PHY_vars_eNB->lte_frame_parms); stop_meas(&PHY_vars_eNB->ofdm_mod_stats); stop_meas(&PHY_vars_eNB->phy_proc_tx); From fd068005dfec6e15524ca4fd37d2440cb2523159 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 22 Aug 2016 10:36:16 +0200 Subject: [PATCH 219/413] cosmetic changes --- openair1/PHY/MODULATION/beamforming.c | 31 ++++++++++--------- .../CONF/enb.band38.tm7.exmimo2.conf | 4 +-- .../CONF/enb.band7.tm7.exmimo2.conf | 6 ++-- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/openair1/PHY/MODULATION/beamforming.c b/openair1/PHY/MODULATION/beamforming.c index 00bb9e5dca..3aa7810aec 100644 --- a/openair1/PHY/MODULATION/beamforming.c +++ b/openair1/PHY/MODULATION/beamforming.c @@ -72,15 +72,15 @@ int beam_precoding(int32_t **txdataF, ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[0][aa][re])[0])>>15); - //printf("beamforming.c:txdata[%d][%d]=%d+j%d, beam_weights[%d][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", - // p,slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re, - // ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0], - // ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1], - // p,aa,re, - // ((int16_t*)&beam_weights[p][aa][re])[0],((int16_t*)&beam_weights[p][aa][re])[1], - // aa,re, - // ((int16_t*)&txdataF_BF[aa][re])[0], - // ((int16_t*)&txdataF_BF[aa][re])[1]); + /*printf("beamforming.c:txdata[%d][%d]=%d+j%d, beam_weights[%d][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", + p,slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re, + ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0], + ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1], + p,aa,re, + ((int16_t*)&beam_weights[p][aa][re])[0],((int16_t*)&beam_weights[p][aa][re])[1], + aa,re, + ((int16_t*)&txdataF_BF[aa][re])[0], + ((int16_t*)&txdataF_BF[aa][re])[1]); */ } } @@ -90,9 +90,9 @@ int beam_precoding(int32_t **txdataF, ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[5][aa][re])[0])>>15); ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[5][aa][re])[1])>>15); ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[5][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[5][aa][re])[0])>>15); -/* - printf("beamforming.c:txdata[5][%d]=%d+j%d, beam_weights[5][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", + ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[5][aa][re])[0])>>15); + + /* printf("beamforming.c:txdata[5][%d]=%d+j%d, beam_weights[5][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re, ((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0], ((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1], @@ -101,8 +101,8 @@ int beam_precoding(int32_t **txdataF, ((int16_t*)&beam_weights[5][aa][re])[1], aa,re, ((int16_t*)&txdataF_BF[aa][re])[0], - ((int16_t*)&txdataF_BF[aa][re])[1]); -*/ + ((int16_t*)&txdataF_BF[aa][re])[1]); */ + } } @@ -119,4 +119,7 @@ int beam_precoding(int32_t **txdataF, } } } + +return 0; + } diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm7.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm7.exmimo2.conf index f9b765d1e0..6209fbe150 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm7.exmimo2.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm7.exmimo2.conf @@ -34,8 +34,8 @@ eNBs = N_RB_DL = 25; Nid_cell_mbsfn = 0; nb_antenna_ports = 1; - nb_antennas_tx = 1; - nb_antennas_rx = 1; + nb_antennas_tx = 3; + nb_antennas_rx = 3; tx_gain = 10; //25; rx_gain = 10; //20; prach_root = 0; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm7.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm7.exmimo2.conf index dedf4797bc..d26ebbe735 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm7.exmimo2.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm7.exmimo2.conf @@ -34,8 +34,8 @@ eNBs = N_RB_DL = 25; Nid_cell_mbsfn = 0; nb_antenna_ports = 1; - nb_antennas_tx = 1; - nb_antennas_rx = 1; + nb_antennas_tx = 2; + nb_antennas_rx = 2; tx_gain = 25; rx_gain = 20; prach_root = 0; @@ -153,7 +153,7 @@ eNBs = log_config : { - global_log_level ="debug"; + global_log_level ="info"; global_log_verbosity ="medium"; hw_log_level ="info"; hw_log_verbosity ="medium"; From 394c4cab6ad9c9944aae2b8ca9785b7b971cfd71 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 22 Aug 2016 20:06:13 +0200 Subject: [PATCH 220/413] antenna number bug fixed --- targets/SIMU/USER/init_lte.c | 3 +-- targets/SIMU/USER/oaisim_functions.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/targets/SIMU/USER/init_lte.c b/targets/SIMU/USER/init_lte.c index 4a71b0aad9..e90605dcc8 100644 --- a/targets/SIMU/USER/init_lte.c +++ b/targets/SIMU/USER/init_lte.c @@ -291,8 +291,7 @@ void init_lte_vars(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs], for (CC_id=0; CC_idnb_antennas_tx = 1; - (frame_parms[CC_id])->nb_antennas_rx = nb_antennas_rx; - + (frame_parms[CC_id])->nb_antennas_rx = 1; // UE rx number hard coded PHY_vars_UE_g[UE_id][CC_id] = init_lte_UE(frame_parms[CC_id], UE_id,abstraction_flag); PHY_vars_UE_g[UE_id][CC_id]->Mod_id=UE_id; diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index e96881d2d3..89921d1151 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -971,7 +971,7 @@ void init_openair1(void) cooperation_flag, enb_properties->properties[0]->nb_antenna_ports[CC_id], abstraction_flag, - enb_properties->properties[0]->nb_antennas_tx[CC_id], + enb_properties->properties[0]->nb_antennas_rx[CC_id], enb_properties->properties[0]->nb_antennas_tx[CC_id], oai_emulation.info.eMBMS_active_state); } From fc1e26d07409162521a2d1e4e92317123032d830 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 23 Aug 2016 18:21:45 +0200 Subject: [PATCH 221/413] add VCD by function name for beam precoding and do_ofdm_l --- openair1/PHY/MODULATION/ofdm_mod.c | 8 +++++--- openair1/SIMULATION/LTE_PHY/dlsim.c | 4 ---- openair2/UTIL/LOG/vcd_signal_dumper.c | 2 ++ openair2/UTIL/LOG/vcd_signal_dumper.h | 2 ++ targets/RT/USER/lte-softmodem.c | 7 ++++++- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 3139a7bc08..44ca2dff9f 100755 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -38,6 +38,7 @@ This section deals with basic functions for OFDM Modulation. #include "PHY/defs.h" #include "UTIL/LOG/log.h" +#include "UTIL/LOG/vcd_signal_dumper.h" //static short temp2[2048*4] __attribute__((aligned(16))); @@ -306,7 +307,9 @@ void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_sl //printf("do_OFDM_mod_l, slot=%d, l=%d, NUMBER_OF_OFDM_CARRIERS=%d,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES=%d\n",next_slot, l,NUMBER_OF_OFDM_CARRIERS,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_BEAM_PRECODING,1); beam_precoding(txdataF,txdataF_BF,frame_parms,eNB_common_vars->beam_weights[eNB_id],next_slot,l); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_BEAM_PRECODING,0); for (aa=0; aanb_antennas_tx; aa++) { @@ -336,9 +339,8 @@ void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_sl frame_parms->nb_prefix_samples, // number of prefix samples CYCLIC_PREFIX); - /* printf("txdata[%d][%d]=%d\n",aa, - slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES, - &txdata[aa][slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES]);*/ + /* printf("txdata[%d][%d]=%d\n",aa,slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES,txdata[aa][slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES]); + * */ } } } diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 0ea247f440..78308ade0d 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -951,10 +951,6 @@ int main(int argc, char **argv) } } - ue_spec_bf_weights = PHY_vars_eNB->dlsch_eNB[k][i]->ue_spec_bf_weights[j]; - - for (aa=0; aanb_antennas_tx; aa++) { - } } PHY_vars_eNB->dlsch_eNB[k][i]->rnti = n_rnti+k; diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.c b/openair2/UTIL/LOG/vcd_signal_dumper.c index 78e481f3d6..4e38aac6eb 100644 --- a/openair2/UTIL/LOG/vcd_signal_dumper.c +++ b/openair2/UTIL/LOG/vcd_signal_dumper.c @@ -275,6 +275,8 @@ const char* eurecomFunctionsNames[] = { "phy_eNB_dlsch_modulation", "phy_eNB_dlsch_encoding", "phy_eNB_dlsch_scrambling", + "phy_eNB_beam_precoding", + "phy_eNB_ofdm_mod_l", /* MAC signals */ "macxface_macphy_init", diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.h b/openair2/UTIL/LOG/vcd_signal_dumper.h index 0592e78b50..4bc11a281c 100644 --- a/openair2/UTIL/LOG/vcd_signal_dumper.h +++ b/openair2/UTIL/LOG/vcd_signal_dumper.h @@ -249,6 +249,8 @@ typedef enum { VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_MODULATION, VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ENCODING, VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_SCRAMBLING, + VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_BEAM_PRECODING, + VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_OFDM_MODULATION, /* MAC signals */ VCD_SIGNAL_DUMPER_FUNCTIONS_MACPHY_INIT, diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index cab7e15b27..bd7d41610e 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -958,10 +958,13 @@ void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB) slot_offset = subframe*phy_vars_eNB->lte_frame_parms.samples_per_tti; + if ((subframe_select(&phy_vars_eNB->lte_frame_parms,subframe)==SF_DL)|| ((subframe_select(&phy_vars_eNB->lte_frame_parms,subframe)==SF_S))) { // LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_OFDM_MODULATION,1); + do_OFDM_mod_l(&phy_vars_eNB->lte_eNB_common_vars, 0, subframe<<1, @@ -974,6 +977,8 @@ void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB) 1+(subframe<<1), &phy_vars_eNB->lte_frame_parms); } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_OFDM_MODULATION,0); /* @@ -1289,7 +1294,7 @@ static void* eNB_thread_tx( void* param ) break; } } - + do_OFDM_mod_rt( proc->subframe_tx, PHY_vars_eNB_g[0][proc->CC_id] ); /* short *txdata = (short*)&PHY_vars_eNB_g[0][proc->CC_id]->lte_eNB_common_vars.txdata[0][0][proc->subframe_tx*PHY_vars_eNB_g[0][proc->CC_id]->lte_frame_parms.samples_per_tti]; From 1f8c702fbb1ec9bf782ad9ed07aa6ec7c66217b6 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 25 Aug 2016 17:44:16 +0200 Subject: [PATCH 222/413] support more >1 EXMIMO2 cards --- openair1/PHY/impl_defs_lte.h | 8 ++--- targets/ARCH/EXMIMO/DRIVER/eurecom/fileops.c | 10 ++++-- .../ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c | 31 +++++++++-------- targets/RT/USER/lte-softmodem.c | 33 +++++++++++-------- 4 files changed, 48 insertions(+), 34 deletions(-) diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h index 9d075dd9bb..ab8abd15de 100644 --- a/openair1/PHY/impl_defs_lte.h +++ b/openair1/PHY/impl_defs_lte.h @@ -1040,13 +1040,13 @@ typedef struct { /// first index: ? [0..1023] (hard coded) int16_t *prachF; /// \brief ?. - /// first index: rx antenna [0..3] (hard coded) \note Hard coded array size indexed by \c nb_antennas_rx. + /// first index: rx antenna [0..63] (hard coded) \note Hard coded array size indexed by \c nb_antennas_rx. /// second index: ? [0..ofdm_symbol_size*12[ - int16_t *rxsigF[4]; + int16_t *rxsigF[64]; /// \brief local buffer to compute prach_ifft (necessary in case of multiple CCs) - /// first index: rx antenna [0..3] (hard coded) \note Hard coded array size indexed by \c nb_antennas_rx. + /// first index: rx antenna [0..63] (hard coded) \note Hard coded array size indexed by \c nb_antennas_rx. /// second index: ? [0..2047] (hard coded) - int16_t *prach_ifft[4]; + int16_t *prach_ifft[64]; } LTE_eNB_PRACH; typedef struct { diff --git a/targets/ARCH/EXMIMO/DRIVER/eurecom/fileops.c b/targets/ARCH/EXMIMO/DRIVER/eurecom/fileops.c index 4427f4c8af..8153a44164 100755 --- a/targets/ARCH/EXMIMO/DRIVER/eurecom/fileops.c +++ b/targets/ARCH/EXMIMO/DRIVER/eurecom/fileops.c @@ -277,14 +277,18 @@ int openair_device_ioctl(struct inode *inode,struct file *filp, unsigned int cmd printk("[openair][IOCTL] : openair_DUMP_CONFIG(%d): exmimo_pci_kvirt[%d].exmimo_config_ptr = %p (phys %08x)\n", (int)arg, (int)arg, exmimo_pci_kvirt[(int)arg].exmimo_config_ptr, p_exmimo_pci_phys[(int)arg]->exmimo_config_ptr); - /*printk("EXMIMO_CONFIG: freq0 %d Hz, freq1 %d Hz, freqtx0 %d Hz, freqtx1 %d Hz, \nRX gain0 %d dB, RX Gain1 %d dB\n", + printk("[openair][IOCTL]: EXMIMO_CONFIG: freq0 %u Hz, freq1 %u Hz, freqtx0 %u Hz, freqtx1 %u Hz, \nRX gain0 %d dB, RX Gain1 %d dB, autocal (%d,%d,%d,%d)\n", exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_rx[0], exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_rx[1], exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_tx[0], exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rf_freq_tx[1], exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rx_gain[0][0], - exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rx_gain[1][0]); - */ + exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.rx_gain[1][0], + exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.do_autocal[0], + exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.do_autocal[1], + exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.do_autocal[2], + exmimo_pci_kvirt[(int)arg].exmimo_config_ptr->rf.do_autocal[3]); + exmimo_send_pccmd((int)arg, EXMIMO_CONFIG); diff --git a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c index 427cd47be8..c4d85d3d1a 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c +++ b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c @@ -252,7 +252,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { // Initialize card // exmimo_config_t *p_exmimo_config; exmimo_id_t *p_exmimo_id; - int ret; + int ret, card; ret = openair0_open(); @@ -276,15 +276,17 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { printf ("Detected %d number of cards, %d number of antennas.\n", openair0_num_detected_cards, openair0_num_antennas[0]); } - // p_exmimo_config = openair0_exmimo_pci[0].exmimo_config_ptr; - p_exmimo_id = openair0_exmimo_pci[0].exmimo_id_ptr; + for (card=0; cardboard_exmimoversion, p_exmimo_id->board_hwrev, p_exmimo_id->board_swrev); + printf("Card %d: ExpressMIMO %d, HW Rev %d, SW Rev 0x%d\n", card, p_exmimo_id->board_exmimoversion, p_exmimo_id->board_hwrev, p_exmimo_id->board_swrev); - // check if the software matches firmware - if (p_exmimo_id->board_swrev!=BOARD_SWREV_CNTL2) { - printf("Software revision %d and firmware revision %d do not match. Please update either the firmware or the software!\n",BOARD_SWREV_CNTL2,p_exmimo_id->board_swrev); - return(-1); + // check if the software matches firmware + if (p_exmimo_id->board_swrev!=BOARD_SWREV_CNTL2) { + printf("Software revision %d and firmware revision %d do not match. Please update either the firmware or the software!\n",BOARD_SWREV_CNTL2,p_exmimo_id->board_swrev); + return(-1); + } } device->type = EXMIMO_DEV; @@ -361,11 +363,17 @@ int openair0_config(openair0_config_t *openair0_cfg, int UE_flag) #endif for (ant=0; ant<4; ant++) { + p_exmimo_config->rf.rf_freq_rx[ant] = 0; + p_exmimo_config->rf.rf_freq_tx[ant] = 0; + p_exmimo_config->rf.rf_mode[ant] = 0; + p_exmimo_config->rf.rx_gain[ant][0] = 0; + p_exmimo_config->rf.tx_gain[ant][0] = 0; + if (openair0_cfg[card].rx_freq[ant] || openair0_cfg[card].tx_freq[ant]) { ACTIVE_RF += (1<rf.rf_mode[ant] = RF_MODE_BASE; p_exmimo_config->rf.do_autocal[ant] = 1;//openair0_cfg[card].autocal[ant]; - printf("card %d, antenna %d, autocal %d\n",card,ant,openair0_cfg[card].autocal[ant]); + printf("card %d, antenna %d, autocal %d\n",card,ant,p_exmimo_config->rf.do_autocal[ant]); } if (openair0_cfg[card].tx_freq[ant]) { @@ -396,10 +404,7 @@ int openair0_config(openair0_config_t *openair0_cfg, int UE_flag) p_exmimo_config->rf.rf_mode[ant] += LNAByp; break; } - } else { - p_exmimo_config->rf.rf_mode[ant] = 0; - p_exmimo_config->rf.do_autocal[ant] = 0; - } + } p_exmimo_config->rf.rf_local[ant] = rf_local[ant]; p_exmimo_config->rf.rf_rxdc[ant] = rf_rxdc[ant]; diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index bd7d41610e..a5dd06e221 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -2926,7 +2926,8 @@ int main( int argc, char **argv ) if (rf_config_file[0] == '\0') openair0_cfg[0].configFilename = NULL; else - openair0_cfg[0].configFilename = rf_config_file; + for (card=0; cardnb_antennas_rx; i++) { - printf("Mapping eNB CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n",CC_id,i,downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i],rf_map[CC_id].card,rf_map[CC_id].chain+i); + card = i/4; + ant = i%4; + printf("Mapping eNB CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n",CC_id,i,downlink_frequency[CC_id][ant]+uplink_frequency_offset[CC_id][ant],rf_map[CC_id].card+card, rf_map[CC_id].chain+ant); free(phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i]); - phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i] = (int32_t*) openair0_exmimo_pci[rf_map[CC_id].card].adc_head[rf_map[CC_id].chain+i]; + phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i] = (int32_t*) openair0_exmimo_pci[rf_map[CC_id].card+card].adc_head[rf_map[CC_id].chain+ant]; - if (openair0_cfg[rf_map[CC_id].card].rx_freq[rf_map[CC_id].chain+i]) { + if (openair0_cfg[rf_map[CC_id].card+card].rx_freq[rf_map[CC_id].chain+ant]) { printf("Error with rf_map! A channel has already been allocated!\n"); return(-1); } else { - openair0_cfg[rf_map[CC_id].card].rx_freq[rf_map[CC_id].chain+i] = downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i]; - openair0_cfg[rf_map[CC_id].card].rx_gain[rf_map[CC_id].chain+i] = rx_gain[CC_id][i]; - openair0_cfg[rf_map[CC_id].card].rx_num_channels++; + openair0_cfg[rf_map[CC_id].card+card].rx_freq[rf_map[CC_id].chain+ant] = downlink_frequency[CC_id][ant]+uplink_frequency_offset[CC_id][ant]; + openair0_cfg[rf_map[CC_id].card+card].rx_gain[rf_map[CC_id].chain+ant] = rx_gain[CC_id][ant]; + openair0_cfg[rf_map[CC_id].card+card].rx_num_channels++; } printf("rxdata[%d] @ %p\n",i,phy_vars_eNB[CC_id]->lte_eNB_common_vars.rxdata[0][i]); @@ -3982,17 +3985,19 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c } for (i=0; inb_antennas_tx; i++) { - printf("Mapping eNB CC_id %d, tx_ant %d, freq %u on card %d, chain %d\n",CC_id,i,downlink_frequency[CC_id][i],rf_map[CC_id].card,rf_map[CC_id].chain+i); + card = i/4; + ant = i%4; + printf("Mapping eNB CC_id %d, tx_ant %d, freq %u on card %d chain %d\n",CC_id,i,downlink_frequency[CC_id][ant],rf_map[CC_id].card+card,rf_map[CC_id].chain+ant); free(phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i]); - phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i] = (int32_t*) openair0_exmimo_pci[rf_map[CC_id].card].dac_head[rf_map[CC_id].chain+i]; + phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i] = (int32_t*) openair0_exmimo_pci[rf_map[CC_id].card+card].dac_head[rf_map[CC_id].chain+ant]; - if (openair0_cfg[rf_map[CC_id].card].tx_freq[rf_map[CC_id].chain+i]) { + if (openair0_cfg[rf_map[CC_id].card+card].tx_freq[rf_map[CC_id].chain+ant]) { printf("Error with rf_map! A channel has already been allocated!\n"); return(-1); } else { - openair0_cfg[rf_map[CC_id].card].tx_freq[rf_map[CC_id].chain+i] = downlink_frequency[CC_id][i]; - openair0_cfg[rf_map[CC_id].card].tx_gain[rf_map[CC_id].chain+i] = tx_gain[CC_id][i]; - openair0_cfg[rf_map[CC_id].card].tx_num_channels++; + openair0_cfg[rf_map[CC_id].card+card].tx_freq[rf_map[CC_id].chain+ant] = downlink_frequency[CC_id][ant]; + openair0_cfg[rf_map[CC_id].card+card].tx_gain[rf_map[CC_id].chain+ant] = tx_gain[CC_id][ant]; + openair0_cfg[rf_map[CC_id].card+card].tx_num_channels++; } printf("txdata[%d] @ %p\n",i,phy_vars_eNB[CC_id]->lte_eNB_common_vars.txdata[0][i]); From eac26b014fcc81c2676c3a754412e6f8e8f503cf Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Tue, 30 Aug 2016 15:59:24 +0200 Subject: [PATCH 223/413] enabling deadline scheduler by default for EXMIMO2 --- cmake_targets/build_oai | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 935c57f0f1..625e2fcf5e 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -333,7 +333,7 @@ function main() { #By default: EXMIMO: enable if [ "$FORCE_DEADLINE_SCHEDULER_FLAG_USER" = "" ]; then if [ "$HW" = "EXMIMO" ] ; then - DEADLINE_SCHEDULER_FLAG_USER="False" + DEADLINE_SCHEDULER_FLAG_USER="True" elif [ "$HW" = "ETHERNET" ] ; then DEADLINE_SCHEDULER_FLAG_USER="True" elif [ "$HW" = "OAI_USRP" ] ; then From cf672ca01684cece6c557a5d48803c2e82654f29 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 30 Aug 2016 17:11:39 +0200 Subject: [PATCH 224/413] temporary fix for exmimo2 build (no longer requires libboost) to be tested with USRP --- cmake_targets/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index a537f17e31..bfd2db6199 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -556,7 +556,7 @@ elseif (${RF_BOARD} STREQUAL "OAI_USRP") set(HW_SOURCE ${HW_SOURCE} ${OPENAIR_TARGETS}/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp) LINK_DIRECTORIES("/opt/lib") - set(option_HW_lib "-luhd -rdynamic -ldl") + set(option_HW_lib "-luhd -rdynamic -ldl -lboost_system") elseif (${RF_BOARD} STREQUAL "OAI_BLADERF") include_directories("${OPENAIR_TARGETS}/ARCH/BLADERF/USERSPACE/LIB/") @@ -1644,7 +1644,7 @@ target_link_libraries (lte-softmodem -ldl target_link_libraries (lte-softmodem ${LIBXML2_LIBRARIES}) target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${option_HW_lib} ${option_TP_lib} ${XFORMS_LIBRARIES} ) -target_link_libraries (lte-softmodem ${LIBBOOST_LIBRARIES} -lboost_system) #Added manually as it is not found for some reason for USRP +#target_link_libraries (lte-softmodem ${LIBBOOST_LIBRARIES} -lboost_system) #Added manually as it is not found for some reason for USRP target_link_libraries (lte-softmodem ${LIB_LMS_LIBRARIES}) target_link_libraries (lte-softmodem ${T_LIB}) @@ -1680,7 +1680,7 @@ target_link_libraries (lte-softmodem-nos1 target_link_libraries (lte-softmodem-nos1 ${LIBXML2_LIBRARIES}) target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib} ${option_TP_lib} ${XFORMS_LIBRARIES} ) -target_link_libraries (lte-softmodem-nos1 ${LIBBOOST_LIBRARIES} -lboost_system) #Added manually as it is not found for some reason for USRP +#target_link_libraries (lte-softmodem-nos1 ${LIBBOOST_LIBRARIES} -lboost_system) #Added manually as it is not found for some reason for USRP target_link_libraries (lte-softmodem-nos1 ${LIB_LMS_LIBRARIES}) target_link_libraries (lte-softmodem-nos1 ${T_LIB}) @@ -1703,7 +1703,7 @@ target_link_libraries(rrh_gw UTIL LFDS -Wl,--end-group ) target_link_libraries (rrh_gw rt pthread m ) -target_link_libraries (rrh_gw ${option_HW_lib} ${option_TP_lib} ${LIBBOOST_LIBRARIES} -lboost_system ) #Added manually as it is not found for some reason for USRP +target_link_libraries (rrh_gw ${option_HW_lib} ${option_TP_lib} ${LIBBOOST_LIBRARIES}) #Added manually as it is not found for some reason for USRP target_link_libraries (rrh_gw ${LIB_LMS_LIBRARIES}) target_link_libraries (rrh_gw ${T_LIB}) From e29524a5fe5a50f78a3153965c5da894a953b153 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 5 Sep 2016 11:15:26 +0300 Subject: [PATCH 225/413] Fixed bug when using DCCH2 --- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 7 +- .../CONF/enb.band5.agent.usrpb210.conf | 180 ++++++++++++++++++ 2 files changed, 184 insertions(+), 3 deletions(-) create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.conf diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index 655c60cc70..5f1e0dbbf2 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -364,8 +364,9 @@ schedule_ue_spec_default( header_len_dcch = 2; // 2 bytes DCCH SDU subheader + // TODO : Need to prioritize DRBs // Loop through the UE logical channels (DCCH, DCCH1, DTCH for now) - for (j = 1; j < 4; j++) { + for (j = 1; j < NB_RB_MAX; j++) { header_len+=3; // Need to see if we have space for data from this channel @@ -389,8 +390,8 @@ schedule_ue_spec_default( if (data_to_request < 128) { //The header will be one byte less header_len--; } - if (j == 1) { - data_to_request++; //It is not correct but fixes some RLC bug for DCCH + if (j == 1 || j == 2) { + data_to_request++; //It is not correct but fixes some RLC bug for DCCH } LOG_D(MAC, "[TEST]Will request %d from DCCH\n", data_to_request); rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.conf new file mode 100644 index 0000000000..caf54b5541 --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.conf @@ -0,0 +1,180 @@ +Active_eNBs = ( "eNB_Eurecom_LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB_Eurecom_LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = "1"; + + mobile_country_code = "208"; + + mobile_network_code = "95"; + + ////////// Physical parameters: + + component_carriers = ( + { + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 5; + downlink_frequency = 879000000L; + uplink_frequency_offset = -45000000; + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 1; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 125; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = -29; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -90; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -96; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + + ue_TransmissionMode = 1; + } + ); + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.100.101"; + ipv6 = "192:168:100::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.106/24"; + + ENB_INTERFACE_NAME_FOR_S1U = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.106/24"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + NETWORK_CONTROLLER : + { + ENB_AGENT_INTERFACE_NAME = "eth1"; + ENB_AGENT_IPV4_ADDRESS = "10.0.2.5/30"; + ENB_AGENT_PORT = 2210; + ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; + }; + + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + } +); From 6b48fd6380424a00fe1bec170ee7639512bdda55 Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Mon, 2 May 2016 22:58:45 +0800 Subject: [PATCH 226/413] ** new procedure - refresh kENB from NAS -> AS ** added flow to refresh KeNB key in RRC on receiving S1AP-InitialContextSetup added flow to configure PDCP security mode enabled filling in the PDCP MAC code during and after RRC-SMC procedure (cherry picked from commit 898cd5c45aedb27625d73352568211b4467c8dd9) --- openair2/COMMON/as_message.h | 10 +++ openair2/COMMON/rrc_messages_def.h | 3 + openair2/COMMON/rrc_messages_types.h | 6 ++ openair2/RRC/LITE/defs.h | 4 + openair2/RRC/LITE/rrc_UE.c | 94 ++++++++++++++++++++ openair3/NAS/COMMON/API/NETWORK/l2_message.h | 10 +++ openair3/NAS/UE/EMM/SecurityModeControl.c | 6 +- openair3/NAS/UE/nas_itti_messaging.c | 35 ++++++++ openair3/NAS/UE/nas_itti_messaging.h | 5 ++ 9 files changed, 172 insertions(+), 1 deletion(-) diff --git a/openair2/COMMON/as_message.h b/openair2/COMMON/as_message.h index 30810a325e..5f7f6f3fa9 100644 --- a/openair2/COMMON/as_message.h +++ b/openair2/COMMON/as_message.h @@ -220,6 +220,16 @@ typedef struct broadcast_info_ind_s { #define AS_HSDUPA (1 << NET_ACCESS_HSDUPA) #define AS_EUTRAN (1 << NET_ACCESS_EUTRAN) +#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete +/* + * NAS->AS -K_eNB refresh request + * NAS request AS to refresh its KeNB key + */ +typedef struct kenb_refresh_req_s { + Byte_t kenb[32]; +} kenb_refresh_req_t; +#endif + /* * NAS->AS - Cell Information request * NAS request AS to search for a suitable cell belonging to the selected diff --git a/openair2/COMMON/rrc_messages_def.h b/openair2/COMMON/rrc_messages_def.h index 27d3a6bdd4..d521eab0ff 100644 --- a/openair2/COMMON/rrc_messages_def.h +++ b/openair2/COMMON/rrc_messages_def.h @@ -64,6 +64,9 @@ MESSAGE_DEF(RRC_STATE_IND, MESSAGE_PRIORITY_MED, RrcStateInd, MESSAGE_DEF(RRC_CONFIGURATION_REQ, MESSAGE_PRIORITY_MED, RrcConfigurationReq, rrc_configuration_req) // UE: NAS -> RRC messages +#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete +MESSAGE_DEF(NAS_KENB_REFRESH_REQ, MESSAGE_PRIORITY_MED, NasKenbRefreshReq, nas_kenb_refresh_req) +#endif MESSAGE_DEF(NAS_CELL_SELECTION_REQ, MESSAGE_PRIORITY_MED, NasCellSelectionReq, nas_cell_selection_req) MESSAGE_DEF(NAS_CONN_ESTABLI_REQ, MESSAGE_PRIORITY_MED, NasConnEstabliReq, nas_conn_establi_req) MESSAGE_DEF(NAS_UPLINK_DATA_REQ, MESSAGE_PRIORITY_MED, NasUlDataReq, nas_ul_data_req) diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index ffe194265f..908510d94b 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -70,6 +70,9 @@ typedef UL_DCCH_Message_t RrcUlDcchMessage; #define RRC_CONFIGURATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_configuration_req +#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete +#define NAS_KENB_REFRESH_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_kenb_refresh_req +#endif #define NAS_CELL_SELECTION_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_cell_selection_req #define NAS_CONN_ESTABLI_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_conn_establi_req #define NAS_UPLINK_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_ul_data_req @@ -183,6 +186,9 @@ typedef struct RrcConfigurationReq_s { } RrcConfigurationReq; // UE: NAS -> RRC messages +#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete +typedef kenb_refresh_req_t NasKenbRefreshReq; +#endif typedef cell_info_req_t NasCellSelectionReq; typedef nas_establish_req_t NasConnEstabliReq; typedef ul_info_transfer_req_t NasUlDataReq; diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index e546b52f8e..e34c532990 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -182,7 +182,11 @@ typedef enum HO_STATE_e { #define PAYLOAD_SIZE_MAX 1024 #define RRC_BUF_SIZE 255 #define UNDEF_SECURITY_MODE 0xff +#if 1 // wilson 2016-05-01 let RRC security mode command to return OK instead of failed +#define NO_SECURITY_MODE 0x20 +#else #define NO_SECURITY_MODE 0x33 +#endif #define CBA_OFFSET 0xfff4 // #define NUM_MAX_CBA_GROUP 4 // in the platform_constants diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index 01c1ee6ca9..51c7aa076d 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -39,6 +39,7 @@ #define RRC_UE_C #include "assertions.h" +#include "hashtable.h" #include "asn1_conversions.h" #include "defs.h" #include "PHY/TOOLS/dB_routines.h" @@ -107,6 +108,15 @@ extern void *bigphys_malloc(int); extern int8_t dB_fixed2(uint32_t x,uint32_t y); +extern void pdcp_config_set_security( + const protocol_ctxt_t* const ctxt_pP, + pdcp_t * const pdcp_pP, + const rb_id_t rb_idP, + const uint16_t lc_idP, + const uint8_t security_modeP, + uint8_t * const kRRCenc, + uint8_t * const kRRCint, + uint8_t * const kUPenc); // internal prototypes @@ -1392,6 +1402,64 @@ rrc_ue_process_securityModeCommand( ul_dcch_msg.message.choice.c1.present = UL_DCCH_MessageType__c1_PR_securityModeFailure; } + +#if 1 // wilson 2016-01-05 config PDCP security mode +#if defined(ENABLE_SECURITY) + uint8_t *kRRCenc = NULL; + uint8_t *kUPenc = NULL; + uint8_t *kRRCint = NULL; + pdcp_t *pdcp_p = NULL; + hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; + hashtable_rc_t h_rc; + + key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, + ctxt_pP->enb_flag, DCCH, SRB_FLAG_YES); + h_rc = hashtable_get(pdcp_coll_p, key, (void**) &pdcp_p); + + if (h_rc == HASH_TABLE_OK) { + LOG_D(RRC, "PDCP_COLL_KEY_VALUE() returns valid key = %d\n", key); + + LOG_D(RRC, "driving kRRCenc, kRRCint and kUPenc from KeNB=" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x\n", + UE_rrc_inst[ctxt_pP->module_id].kenb[0], UE_rrc_inst[ctxt_pP->module_id].kenb[1], UE_rrc_inst[ctxt_pP->module_id].kenb[2], UE_rrc_inst[ctxt_pP->module_id].kenb[3], + UE_rrc_inst[ctxt_pP->module_id].kenb[4], UE_rrc_inst[ctxt_pP->module_id].kenb[5], UE_rrc_inst[ctxt_pP->module_id].kenb[6], UE_rrc_inst[ctxt_pP->module_id].kenb[7], + UE_rrc_inst[ctxt_pP->module_id].kenb[8], UE_rrc_inst[ctxt_pP->module_id].kenb[9], UE_rrc_inst[ctxt_pP->module_id].kenb[10], UE_rrc_inst[ctxt_pP->module_id].kenb[11], + UE_rrc_inst[ctxt_pP->module_id].kenb[12], UE_rrc_inst[ctxt_pP->module_id].kenb[13], UE_rrc_inst[ctxt_pP->module_id].kenb[14], UE_rrc_inst[ctxt_pP->module_id].kenb[15], + UE_rrc_inst[ctxt_pP->module_id].kenb[16], UE_rrc_inst[ctxt_pP->module_id].kenb[17], UE_rrc_inst[ctxt_pP->module_id].kenb[18], UE_rrc_inst[ctxt_pP->module_id].kenb[19], + UE_rrc_inst[ctxt_pP->module_id].kenb[20], UE_rrc_inst[ctxt_pP->module_id].kenb[21], UE_rrc_inst[ctxt_pP->module_id].kenb[22], UE_rrc_inst[ctxt_pP->module_id].kenb[23], + UE_rrc_inst[ctxt_pP->module_id].kenb[24], UE_rrc_inst[ctxt_pP->module_id].kenb[25], UE_rrc_inst[ctxt_pP->module_id].kenb[26], UE_rrc_inst[ctxt_pP->module_id].kenb[27], + UE_rrc_inst[ctxt_pP->module_id].kenb[28], UE_rrc_inst[ctxt_pP->module_id].kenb[29], UE_rrc_inst[ctxt_pP->module_id].kenb[30], UE_rrc_inst[ctxt_pP->module_id].kenb[31]); + + derive_key_rrc_enc(UE_rrc_inst[ctxt_pP->module_id].ciphering_algorithm, + UE_rrc_inst[ctxt_pP->module_id].kenb, &kRRCenc); + derive_key_rrc_int(UE_rrc_inst[ctxt_pP->module_id].integrity_algorithm, + UE_rrc_inst[ctxt_pP->module_id].kenb, &kRRCint); + derive_key_up_enc(UE_rrc_inst[ctxt_pP->module_id].ciphering_algorithm, + UE_rrc_inst[ctxt_pP->module_id].kenb, &kUPenc); + + if (securityMode != 0xff) { + pdcp_config_set_security(ctxt_pP, pdcp_p, 0, 0, + UE_rrc_inst[ctxt_pP->module_id].ciphering_algorithm + | (UE_rrc_inst[ctxt_pP->module_id].integrity_algorithm << 4), + kRRCenc, kRRCint, kUPenc); + } else { + LOG_W(RRC, "skipped pdcp_config_set_security() as securityMode == 0x%02x", + securityMode); + } + } else { + LOG_W(RRC, "Could not get PDCP instance where key=0x%\n", key); + } + +#endif //#if defined(ENABLE_SECURITY) +#endif //#if 1 //wilson + if (securityModeCommand->criticalExtensions.present == SecurityModeCommand__criticalExtensions_PR_c1) { if (securityModeCommand->criticalExtensions.choice.c1.present == SecurityModeCommand__criticalExtensions__c1_PR_securityModeCommand_r8) { @@ -4063,6 +4131,32 @@ void *rrc_ue_task( void *args_p ) # if defined(ENABLE_USE_MME) +#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete + case NAS_KENB_REFRESH_REQ: + memcpy((void*)UE_rrc_inst[ue_mod_id].kenb, (void*)NAS_KENB_REFRESH_REQ(msg_p).kenb, sizeof(UE_rrc_inst[ue_mod_id].kenb)); + + LOG_D(RRC, "[UE %d] Received %s: refreshed RRC::KeNB = " + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x\n", + ue_mod_id, msg_name, + UE_rrc_inst[ue_mod_id].kenb[0], UE_rrc_inst[ue_mod_id].kenb[1], UE_rrc_inst[ue_mod_id].kenb[2], UE_rrc_inst[ue_mod_id].kenb[3], + UE_rrc_inst[ue_mod_id].kenb[4], UE_rrc_inst[ue_mod_id].kenb[5], UE_rrc_inst[ue_mod_id].kenb[6], UE_rrc_inst[ue_mod_id].kenb[7], + UE_rrc_inst[ue_mod_id].kenb[8], UE_rrc_inst[ue_mod_id].kenb[9], UE_rrc_inst[ue_mod_id].kenb[10], UE_rrc_inst[ue_mod_id].kenb[11], + UE_rrc_inst[ue_mod_id].kenb[12], UE_rrc_inst[ue_mod_id].kenb[13], UE_rrc_inst[ue_mod_id].kenb[14], UE_rrc_inst[ue_mod_id].kenb[15], + UE_rrc_inst[ue_mod_id].kenb[16], UE_rrc_inst[ue_mod_id].kenb[17], UE_rrc_inst[ue_mod_id].kenb[18], UE_rrc_inst[ue_mod_id].kenb[19], + UE_rrc_inst[ue_mod_id].kenb[20], UE_rrc_inst[ue_mod_id].kenb[21], UE_rrc_inst[ue_mod_id].kenb[22], UE_rrc_inst[ue_mod_id].kenb[23], + UE_rrc_inst[ue_mod_id].kenb[24], UE_rrc_inst[ue_mod_id].kenb[25], UE_rrc_inst[ue_mod_id].kenb[26], UE_rrc_inst[ue_mod_id].kenb[27], + UE_rrc_inst[ue_mod_id].kenb[28], UE_rrc_inst[ue_mod_id].kenb[29], UE_rrc_inst[ue_mod_id].kenb[30], UE_rrc_inst[ue_mod_id].kenb[31]); + + break; +#endif + /* NAS messages */ case NAS_CELL_SELECTION_REQ: ue_mod_id = 0; /* TODO force ue_mod_id to first UE, NAS UE not virtualized yet */ diff --git a/openair3/NAS/COMMON/API/NETWORK/l2_message.h b/openair3/NAS/COMMON/API/NETWORK/l2_message.h index 02e5d87354..603f7c0d7d 100644 --- a/openair3/NAS/COMMON/API/NETWORK/l2_message.h +++ b/openair3/NAS/COMMON/API/NETWORK/l2_message.h @@ -116,6 +116,15 @@ Description Defines the messages supported by the Access Stratum sublayer #define AS_HSDUPA (1 << NET_ACCESS_HSDUPA) #define AS_EUTRAN (1 << NET_ACCESS_EUTRAN) +/* + * NAS->AS -K_eNB refresh request + * NAS request AS to refresh its KeNB key + */ +typedef struct kenb_refresh_req_s { + Byte_t kenb[32]; +} kenb_refresh_req_t; + +#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete /* * NAS->AS - Cell Information request * NAS request AS to search for a suitable cell belonging to the selected @@ -125,6 +134,7 @@ typedef struct { plmn_t plmnID; /* PLMN identifier */ Byte_t rat; /* Bitmap - set of radio access technologies */ } cell_info_req_t; +#endif /* * AS->NAS - Cell Information response diff --git a/openair3/NAS/UE/EMM/SecurityModeControl.c b/openair3/NAS/UE/EMM/SecurityModeControl.c index fd7e4c3991..fa500ad316 100755 --- a/openair3/NAS/UE/EMM/SecurityModeControl.c +++ b/openair3/NAS/UE/EMM/SecurityModeControl.c @@ -72,6 +72,8 @@ Description Defines the security mode control EMM procedure executed by the #include "secu_defs.h" #include "msc.h" +#include "nas_itti_messaging.h" + /****************************************************************************/ /**************** E X T E R N A L D E F I N I T I O N S ****************/ /****************************************************************************/ @@ -293,7 +295,9 @@ int emm_proc_security_mode_command(int native_ksi, int ksi, _emm_data.security->selected_algorithms.encryption = seea; _emm_data.security->selected_algorithms.integrity = seia; - +#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete + nas_itti_kenb_refresh_req(_security_data.kenb.value); +#endif } /* * NAS security mode command not accepted by the UE diff --git a/openair3/NAS/UE/nas_itti_messaging.c b/openair3/NAS/UE/nas_itti_messaging.c index 7b8f630b89..ff16c83ebf 100755 --- a/openair3/NAS/UE/nas_itti_messaging.c +++ b/openair3/NAS/UE/nas_itti_messaging.c @@ -187,6 +187,41 @@ int nas_itti_protected_msg(const char *buffer, const nas_message_t *msg, const i extern unsigned char NB_eNB_INST; +#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete +int nas_itti_kenb_refresh_req(const Byte_t kenb[32]) +{ + MessageDef *message_p; + + message_p = itti_alloc_new_message(TASK_NAS_UE, NAS_KENB_REFRESH_REQ); + + memcpy(NAS_KENB_REFRESH_REQ(message_p).kenb, kenb, sizeof(NAS_KENB_REFRESH_REQ(message_p).kenb)); + + MSC_LOG_TX_MESSAGE( + MSC_NAS_UE, + MSC_RRC_UE, + NULL,0, + "0 NAS_KENB_REFRESH_REQ KeNB " + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x", + kenb[0], kenb[1], kenb[2], kenb[3], + kenb[4], kenb[5], kenb[6], kenb[7], + kenb[8], kenb[9], kenb[10], kenb[11], + kenb[12], kenb[13], kenb[14], kenb[15], + kenb[16], kenb[17], kenb[18], kenb[19], + kenb[20], kenb[21], kenb[22], kenb[23], + kenb[24], kenb[25], kenb[26], kenb[27], + kenb[28], kenb[29], kenb[30], kenb[31]); + + return itti_send_msg_to_task(TASK_RRC_UE, NB_eNB_INST + 0 /* TODO to be virtualized */, message_p); +} +#endif + int nas_itti_cell_info_req(const plmn_t plmnID, const Byte_t rat) { MessageDef *message_p; diff --git a/openair3/NAS/UE/nas_itti_messaging.h b/openair3/NAS/UE/nas_itti_messaging.h index 9ea80f63c0..dc8d41a239 100755 --- a/openair3/NAS/UE/nas_itti_messaging.h +++ b/openair3/NAS/UE/nas_itti_messaging.h @@ -54,6 +54,11 @@ int nas_itti_protected_msg( # if defined(NAS_BUILT_IN_UE) + +#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete +int nas_itti_kenb_refresh_req(const Byte_t kenb[32]); +#endif + int nas_itti_cell_info_req(const plmn_t plmnID, const Byte_t rat); int nas_itti_nas_establish_req(as_cause_t cause, as_call_type_t type, as_stmsi_t s_tmsi, plmn_t plmnID, Byte_t *data_pP, uint32_t lengthP); From fe2b7d80d3f43845e3e1a0404f92a9d1a4a77c7e Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Mon, 2 May 2016 23:13:30 +0800 Subject: [PATCH 227/413] removed 'wilson' from the codes --- openair2/COMMON/as_message.h | 2 -- openair2/COMMON/rrc_messages_def.h | 2 -- openair2/COMMON/rrc_messages_types.h | 4 ---- openair2/RRC/LITE/defs.h | 4 ---- openair2/RRC/LITE/rrc_UE.c | 4 ---- openair3/NAS/COMMON/API/NETWORK/l2_message.h | 2 -- openair3/NAS/UE/EMM/SecurityModeControl.c | 2 -- openair3/NAS/UE/nas_itti_messaging.c | 2 -- openair3/NAS/UE/nas_itti_messaging.h | 2 -- 9 files changed, 24 deletions(-) diff --git a/openair2/COMMON/as_message.h b/openair2/COMMON/as_message.h index 5f7f6f3fa9..976a398061 100644 --- a/openair2/COMMON/as_message.h +++ b/openair2/COMMON/as_message.h @@ -220,7 +220,6 @@ typedef struct broadcast_info_ind_s { #define AS_HSDUPA (1 << NET_ACCESS_HSDUPA) #define AS_EUTRAN (1 << NET_ACCESS_EUTRAN) -#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete /* * NAS->AS -K_eNB refresh request * NAS request AS to refresh its KeNB key @@ -228,7 +227,6 @@ typedef struct broadcast_info_ind_s { typedef struct kenb_refresh_req_s { Byte_t kenb[32]; } kenb_refresh_req_t; -#endif /* * NAS->AS - Cell Information request diff --git a/openair2/COMMON/rrc_messages_def.h b/openair2/COMMON/rrc_messages_def.h index d521eab0ff..83cd8558d4 100644 --- a/openair2/COMMON/rrc_messages_def.h +++ b/openair2/COMMON/rrc_messages_def.h @@ -64,9 +64,7 @@ MESSAGE_DEF(RRC_STATE_IND, MESSAGE_PRIORITY_MED, RrcStateInd, MESSAGE_DEF(RRC_CONFIGURATION_REQ, MESSAGE_PRIORITY_MED, RrcConfigurationReq, rrc_configuration_req) // UE: NAS -> RRC messages -#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete MESSAGE_DEF(NAS_KENB_REFRESH_REQ, MESSAGE_PRIORITY_MED, NasKenbRefreshReq, nas_kenb_refresh_req) -#endif MESSAGE_DEF(NAS_CELL_SELECTION_REQ, MESSAGE_PRIORITY_MED, NasCellSelectionReq, nas_cell_selection_req) MESSAGE_DEF(NAS_CONN_ESTABLI_REQ, MESSAGE_PRIORITY_MED, NasConnEstabliReq, nas_conn_establi_req) MESSAGE_DEF(NAS_UPLINK_DATA_REQ, MESSAGE_PRIORITY_MED, NasUlDataReq, nas_ul_data_req) diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 908510d94b..1befc4a676 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -70,9 +70,7 @@ typedef UL_DCCH_Message_t RrcUlDcchMessage; #define RRC_CONFIGURATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_configuration_req -#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete #define NAS_KENB_REFRESH_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_kenb_refresh_req -#endif #define NAS_CELL_SELECTION_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_cell_selection_req #define NAS_CONN_ESTABLI_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_conn_establi_req #define NAS_UPLINK_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_ul_data_req @@ -186,9 +184,7 @@ typedef struct RrcConfigurationReq_s { } RrcConfigurationReq; // UE: NAS -> RRC messages -#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete typedef kenb_refresh_req_t NasKenbRefreshReq; -#endif typedef cell_info_req_t NasCellSelectionReq; typedef nas_establish_req_t NasConnEstabliReq; typedef ul_info_transfer_req_t NasUlDataReq; diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index e34c532990..b15b70b815 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -182,11 +182,7 @@ typedef enum HO_STATE_e { #define PAYLOAD_SIZE_MAX 1024 #define RRC_BUF_SIZE 255 #define UNDEF_SECURITY_MODE 0xff -#if 1 // wilson 2016-05-01 let RRC security mode command to return OK instead of failed #define NO_SECURITY_MODE 0x20 -#else -#define NO_SECURITY_MODE 0x33 -#endif #define CBA_OFFSET 0xfff4 // #define NUM_MAX_CBA_GROUP 4 // in the platform_constants diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index 51c7aa076d..d666e54684 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -1403,7 +1403,6 @@ rrc_ue_process_securityModeCommand( } -#if 1 // wilson 2016-01-05 config PDCP security mode #if defined(ENABLE_SECURITY) uint8_t *kRRCenc = NULL; uint8_t *kUPenc = NULL; @@ -1458,7 +1457,6 @@ rrc_ue_process_securityModeCommand( } #endif //#if defined(ENABLE_SECURITY) -#endif //#if 1 //wilson if (securityModeCommand->criticalExtensions.present == SecurityModeCommand__criticalExtensions_PR_c1) { if (securityModeCommand->criticalExtensions.choice.c1.present == SecurityModeCommand__criticalExtensions__c1_PR_securityModeCommand_r8) { @@ -4131,7 +4129,6 @@ void *rrc_ue_task( void *args_p ) # if defined(ENABLE_USE_MME) -#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete case NAS_KENB_REFRESH_REQ: memcpy((void*)UE_rrc_inst[ue_mod_id].kenb, (void*)NAS_KENB_REFRESH_REQ(msg_p).kenb, sizeof(UE_rrc_inst[ue_mod_id].kenb)); @@ -4155,7 +4152,6 @@ void *rrc_ue_task( void *args_p ) UE_rrc_inst[ue_mod_id].kenb[28], UE_rrc_inst[ue_mod_id].kenb[29], UE_rrc_inst[ue_mod_id].kenb[30], UE_rrc_inst[ue_mod_id].kenb[31]); break; -#endif /* NAS messages */ case NAS_CELL_SELECTION_REQ: diff --git a/openair3/NAS/COMMON/API/NETWORK/l2_message.h b/openair3/NAS/COMMON/API/NETWORK/l2_message.h index 603f7c0d7d..9c349b8d06 100644 --- a/openair3/NAS/COMMON/API/NETWORK/l2_message.h +++ b/openair3/NAS/COMMON/API/NETWORK/l2_message.h @@ -124,7 +124,6 @@ typedef struct kenb_refresh_req_s { Byte_t kenb[32]; } kenb_refresh_req_t; -#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete /* * NAS->AS - Cell Information request * NAS request AS to search for a suitable cell belonging to the selected @@ -134,7 +133,6 @@ typedef struct { plmn_t plmnID; /* PLMN identifier */ Byte_t rat; /* Bitmap - set of radio access technologies */ } cell_info_req_t; -#endif /* * AS->NAS - Cell Information response diff --git a/openair3/NAS/UE/EMM/SecurityModeControl.c b/openair3/NAS/UE/EMM/SecurityModeControl.c index fa500ad316..b3f2b6f8a8 100755 --- a/openair3/NAS/UE/EMM/SecurityModeControl.c +++ b/openair3/NAS/UE/EMM/SecurityModeControl.c @@ -295,9 +295,7 @@ int emm_proc_security_mode_command(int native_ksi, int ksi, _emm_data.security->selected_algorithms.encryption = seea; _emm_data.security->selected_algorithms.integrity = seia; -#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete nas_itti_kenb_refresh_req(_security_data.kenb.value); -#endif } /* * NAS security mode command not accepted by the UE diff --git a/openair3/NAS/UE/nas_itti_messaging.c b/openair3/NAS/UE/nas_itti_messaging.c index ff16c83ebf..a28c7394b2 100755 --- a/openair3/NAS/UE/nas_itti_messaging.c +++ b/openair3/NAS/UE/nas_itti_messaging.c @@ -187,7 +187,6 @@ int nas_itti_protected_msg(const char *buffer, const nas_message_t *msg, const i extern unsigned char NB_eNB_INST; -#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete int nas_itti_kenb_refresh_req(const Byte_t kenb[32]) { MessageDef *message_p; @@ -220,7 +219,6 @@ int nas_itti_kenb_refresh_req(const Byte_t kenb[32]) return itti_send_msg_to_task(TASK_RRC_UE, NB_eNB_INST + 0 /* TODO to be virtualized */, message_p); } -#endif int nas_itti_cell_info_req(const plmn_t plmnID, const Byte_t rat) { diff --git a/openair3/NAS/UE/nas_itti_messaging.h b/openair3/NAS/UE/nas_itti_messaging.h index dc8d41a239..a9db232d70 100755 --- a/openair3/NAS/UE/nas_itti_messaging.h +++ b/openair3/NAS/UE/nas_itti_messaging.h @@ -55,9 +55,7 @@ int nas_itti_protected_msg( # if defined(NAS_BUILT_IN_UE) -#if 1 // wilson 2016-05-02 add new message to update kenb in RRC after NAS SMC complete int nas_itti_kenb_refresh_req(const Byte_t kenb[32]); -#endif int nas_itti_cell_info_req(const plmn_t plmnID, const Byte_t rat); From 7e2c8e39f820a0dc76d340ec290ab8a26f9ea747 Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Tue, 3 May 2016 01:32:48 +0800 Subject: [PATCH 228/413] fixed oaisim build failed with the new KeNB refresh request message from NAS -> AS --- openair3/NAS/UE/EMM/SecurityModeControl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair3/NAS/UE/EMM/SecurityModeControl.c b/openair3/NAS/UE/EMM/SecurityModeControl.c index b3f2b6f8a8..9f4186412e 100755 --- a/openair3/NAS/UE/EMM/SecurityModeControl.c +++ b/openair3/NAS/UE/EMM/SecurityModeControl.c @@ -72,7 +72,9 @@ Description Defines the security mode control EMM procedure executed by the #include "secu_defs.h" #include "msc.h" +#if defined(NAS_BUILT_IN_UE) #include "nas_itti_messaging.h" +#endif /****************************************************************************/ /**************** E X T E R N A L D E F I N I T I O N S ****************/ @@ -295,7 +297,9 @@ int emm_proc_security_mode_command(int native_ksi, int ksi, _emm_data.security->selected_algorithms.encryption = seea; _emm_data.security->selected_algorithms.integrity = seia; +#if defined(NAS_BUILT_IN_UE) nas_itti_kenb_refresh_req(_security_data.kenb.value); +#endif } /* * NAS security mode command not accepted by the UE From 19c81e741e61956cb0c49ddc2c7d65872efb1101 Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Sun, 18 Sep 2016 15:34:47 +0800 Subject: [PATCH 229/413] fixed hard-code DRB-ID<->LC-ID mapping (DRB-ID = LC-ID - 2) so they are not fully configurable fixed hard-code default DRB-ID (1) so it is now fully configurable (cherry picked from commit 4499124853b8985c3f157721997125370f1ca475) Conflicts: openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c Conflicts: openair2/LAYER2/PDCP_v10.1.0/pdcp.c --- openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 64 ++++++++- openair2/LAYER2/PDCP_v10.1.0/pdcp.h | 20 ++- openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 28 +++- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 10 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h | 12 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c | 7 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h | 4 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c | 4 +- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c | 15 ++- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h | 10 +- .../RLC/UM_v9.3.0/rlc_um_control_primitives.c | 18 ++- .../RLC/UM_v9.3.0/rlc_um_control_primitives.h | 14 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c | 20 +-- openair2/LAYER2/RLC/rlc.h | 13 +- openair2/LAYER2/RLC/rlc_mac.c | 20 ++- openair2/LAYER2/RLC/rlc_rrc.c | 122 +++++++++++++----- openair2/RRC/LITE/defs.h | 3 + openair2/RRC/LITE/rrc_UE.c | 22 +++- openair2/RRC/LITE/rrc_eNB.c | 8 +- 19 files changed, 323 insertions(+), 91 deletions(-) diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 3779adbbc9..7f9017201a 100755 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -1065,6 +1065,7 @@ rrc_pdcp_config_asn1_req ( #ifdef Rel10 ,PMCH_InfoList_r9_t* const pmch_InfoList_r9_pP #endif + ,rb_id_t *const defaultDRB // 2016-05-28 wilson : remember the default DRB ) //----------------------------------------------------------------------------- { @@ -1086,6 +1087,10 @@ rrc_pdcp_config_asn1_req ( hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; +#ifndef ASTRI_FIX // 2016-05-28 wilson : remember the default DRB + hash_key_t key_defaultDRB = HASHTABLE_NOT_A_KEY_VALUE; + hashtable_rc_t h_defaultDRB_rc; +#endif #ifdef Rel10 int i,j; MBMS_SessionInfoList_r9_t *mbms_SessionInfoList_r9_p = NULL; @@ -1106,7 +1111,11 @@ rrc_pdcp_config_asn1_req ( srb_id = srb2add_list_pP->list.array[cnt]->srb_Identity; srb_toaddmod_p = srb2add_list_pP->list.array[cnt]; rlc_type = RLC_MODE_AM; +#if 0 lc_id = srb_id;// + 2; +#else // 2016-05-27 wilson : fixing the LC-id <-> SRB-id mapping + lc_id = srb_id; +#endif key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_YES); h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p); @@ -1186,8 +1195,23 @@ rrc_pdcp_config_asn1_req ( drb_toaddmod_p = drb2add_list_pP->list.array[cnt]; drb_id = drb_toaddmod_p->drb_Identity;// + drb_id_offset; - +#ifdef ASTRI_FIX lc_id = drb_id + 2; +#else // 2016-05-27 wilson : fixing the mapping between LC-id and DRB-id + if (drb_toaddmod_p->logicalChannelIdentity) { + lc_id = *(drb_toaddmod_p->logicalChannelIdentity); + } else { + LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" logicalChannelIdentity is missing in DRB-ToAddMod information element!\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); + continue; + } + + if (lc_id == 1 || lc_id == 2) { + LOG_E(RLC, PROTOCOL_CTXT_FMT" logicalChannelIdentity = %d is invalid in RRC message when adding DRB!\n", PROTOCOL_CTXT_ARGS(ctxt_pP), lc_id); + continue; + } +#endif + DevCheck4(drb_id < maxDRB, drb_id, maxDRB, ctxt_pP->module_id, ctxt_pP->rnti); key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, drb_id, SRB_FLAG_NO); h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p); @@ -1203,6 +1227,22 @@ rrc_pdcp_config_asn1_req ( pdcp_p = calloc(1, sizeof(pdcp_t)); h_rc = hashtable_insert(pdcp_coll_p, key, pdcp_p); +#ifndef ASTRI_FIX + if ((defaultDRB != NULL) && (*defaultDRB == drb_id)) { + key_defaultDRB = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag); + h_defaultDRB_rc = hashtable_insert(pdcp_coll_p, key_defaultDRB, pdcp_p); + } else { + h_defaultDRB_rc = HASH_TABLE_OK; // do not trigger any error handling if this is not a default DRB + } + + if (h_defaultDRB_rc != HASH_TABLE_OK) { + LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD default DRB key 0x%"PRIx64" FAILED\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), + key_defaultDRB); + free(pdcp_p); + return TRUE; + } else +#endif if (h_rc != HASH_TABLE_OK) { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD key 0x%"PRIx64" FAILED\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), @@ -1297,7 +1337,9 @@ rrc_pdcp_config_asn1_req ( for (cnt=0; cntlist.count; cnt++) { pdrb_id_p = drb2release_list_pP->list.array[cnt]; drb_id = *pdrb_id_p; +#if 0 // 2016-05-27 wilson : fixing the hard-coded mapping between DRB-id <-> LC-id lc_id = drb_id + 2; +#endif key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_NO); h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p); @@ -1308,6 +1350,10 @@ rrc_pdcp_config_asn1_req ( continue; } +#ifndef ASTRI_FIX // 2016-05-27 wilson : fixing the hard-coded mapping between DRB-id <-> LC-id + lc_id = pdcp_p->lcid; +#endif + action = CONFIG_ACTION_REMOVE; pdcp_config_req_asn1 ( ctxt_pP, @@ -1326,6 +1372,22 @@ rrc_pdcp_config_asn1_req ( kRRCint_pP, kUPenc_pP); h_rc = hashtable_remove(pdcp_coll_p, key); + +#ifndef ASTRI_FIX // 2016-05-28 wilson : remember the default DRB + if ((defaultDRB != NULL) && (*defaultDRB == drb_id)) { + // this is the default DRB being removed, although this is not allowed in standard + key_defaultDRB = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag); + h_defaultDRB_rc = hashtable_get(pdcp_coll_p, key_defaultDRB, (void**)&pdcp_p); + + if (h_defaultDRB_rc == HASH_TABLE_OK) { + h_defaultDRB_rc = hashtable_remove(pdcp_coll_p, key_defaultDRB); + } else { + LOG_E(PDCP, PROTOCOL_CTXT_FMT" PDCP REMOVE FAILED default DRB\n", PROTOCOL_CTXT_ARGS(ctxt_pP)); + } + } else { + key_defaultDRB = HASH_TABLE_OK; // do not trigger any error handling if this is not a default DRB + } +#endif } } diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index 52322b1348..5f9e3f397a 100755 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -279,6 +279,7 @@ public_pdcp(void rrc_pdcp_config_req ( * \param[in] kRRCenc RRC encryption key * \param[in] kRRCint RRC integrity key * \param[in] kUPenc User-Plane encryption key +* \param[in] defaultDRB Default DRB ID * \return A status about the processing, OK or error code. */ public_pdcp( @@ -294,6 +295,7 @@ public_pdcp( #ifdef Rel10 ,PMCH_InfoList_r9_t *pmch_InfoList_r9 #endif + ,rb_id_t *const defaultDRB // 2016-05-28 wilson : remember the default DRB )); /*! \fn boolean_t pdcp_config_req_asn1 (const protocol_ctxt_t* const ctxt_pP, srb_flag_t srb_flagP, uint32_t action, rb_id_t rb_id, uint8_t rb_sn, uint8_t rb_report, uint16_t header_compression_profile, uint8_t security_mode) @@ -467,12 +469,28 @@ protected_pdcp(unsigned char pdcp_input_sdu_buffer[MAX_IP_PACKET_SIZE]; protected_pdcp(sdu_size_t pdcp_input_index_header;) protected_pdcp(sdu_size_t pdcp_input_sdu_size_read;) protected_pdcp(sdu_size_t pdcp_input_sdu_remaining_size_to_read;) + #define PDCP_COLL_KEY_VALUE(mODULE_iD, rNTI, iS_eNB, rB_iD, iS_sRB) \ ((hash_key_t)mODULE_iD | \ (((hash_key_t)(rNTI)) << 8) | \ (((hash_key_t)(iS_eNB)) << 24) | \ (((hash_key_t)(rB_iD)) << 25) | \ - (((hash_key_t)(iS_sRB)) << 33)) + (((hash_key_t)(iS_sRB)) << 33) | \ + (((hash_key_t)(0x55)) << 34)) + +#ifndef ASTRI_FIX // 2016-05-28 wilson : for remeber the default DRB + +// hash key to the same PDCP as indexed by PDCP_COLL_KEY_VALUE(... rB_iD, iS_sRB=0) where rB_iD +// is the default DRB ID. The hidden code 0x55 indicates the key is indexed by (rB_iD,is_sRB) +// whereas the hidden code 0xaa indicates the key is for default DRB only +#define PDCP_COLL_KEY_DEFAULT_DRB_VALUE(mODULE_iD, rNTI, iS_eNB) \ + ((hash_key_t)mODULE_iD | \ + (((hash_key_t)(rNTI)) << 8) | \ + (((hash_key_t)(iS_eNB)) << 24) | \ + (((hash_key_t)(0xff)) << 25) | \ + (((hash_key_t)(0x00)) << 33) | \ + (((hash_key_t)(0xaa)) << 34)) +#endif // service id max val is maxServiceCount = 16 (asn1_constants.h) diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index 390ad5a48d..8dea985345 100755 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -75,6 +75,7 @@ extern int otg_enabled; #ifdef PDCP_USE_NETLINK #include #include +#include "NETWORK_DRIVER/UE_IP/constant.h" extern char nl_rx_buf[NL_MAX_PAYLOAD]; extern struct sockaddr_nl nas_src_addr, nas_dest_addr; @@ -194,7 +195,7 @@ int pdcp_fifo_flush_sdus(const protocol_ctxt_t* const ctxt_pP) ret = sendmsg(nas_sock_fd,&nas_msg_tx,0); if (ret<0) { - LOG_D(PDCP, "[PDCP_FIFOS] sendmsg returns %d (errno: %d)\n", ret, errno); + LOG_E(PDCP, "[PDCP_FIFOS] sendmsg returns %d (errno: %d)\n", ret, errno); MSC_LOG_TX_MESSAGE_FAILED( (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_IP_ENB:MSC_IP_UE, @@ -499,6 +500,10 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const ctxt_pP) ctxt.frame = ctxt_cpy.frame; ctxt.enb_flag = ctxt_cpy.enb_flag; +#ifdef PDCP_DEBUG + LOG_I(PDCP, "[PDCP][NETLINK] pdcp_read_header_g.rb_id = %d\n", pdcp_read_header_g.rb_id); +#endif + if (ctxt_cpy.enb_flag) { ctxt.module_id = 0; rab_id = pdcp_read_header_g.rb_id % maxDRB; @@ -594,11 +599,26 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const ctxt_pP) } } else { // enb_flag if (rab_id != 0) { - rab_id = rab_id % maxDRB; - key = PDCP_COLL_KEY_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id, SRB_FLAG_NO); - h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p); +#ifndef ASTRI_FIX // 2016-05-30 wilson : fix hard-code default DRB ID + if (rab_id == UE_IP_DEFAULT_RAB_ID) { + LOG_D(PDCP, "PDCP_COLL_KEY_DEFAULT_DRB_VALUE(module_id=%d, rnti=%x, enb_flag=%d)\n", + ctxt.module_id, ctxt.rnti, ctxt.enb_flag); + key = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag); + h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p); + } else +#endif + { + rab_id = rab_id % maxDRB; + LOG_D(PDCP, "PDCP_COLL_KEY_VALUE(module_id=%d, rnti=%x, enb_flag=%d, rab_id=%d, SRB_FLAG=%d)\n", + ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id, SRB_FLAG_NO); + key = PDCP_COLL_KEY_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id, SRB_FLAG_NO); + h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p); + } if (h_rc == HASH_TABLE_OK) { +#ifndef ASTRI_FIX // 2016-05-30 wilson : fix default DRB-ID to be configurable + rab_id = pdcp_p->rb_id; +#endif #ifdef PDCP_DEBUG LOG_D(PDCP, "[FRAME %5u][UE][NETLINK][IP->PDCP] INST %d: Received socket with length %d (nlmsg_len = %d) on Rab %d \n", ctxt.frame, 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 fd8279579d..8d45ac9582 100755 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -120,7 +120,8 @@ config_req_rlc_am ( const protocol_ctxt_t* const ctxt_pP, const srb_flag_t srb_flagP, rlc_am_info_t * const config_am_pP, - const rb_id_t rb_idP + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP // 2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC ) { rlc_union_t *rlc_union_p = NULL; @@ -142,7 +143,7 @@ config_req_rlc_am ( config_am_pP->t_reordering, config_am_pP->t_status_prohibit); rlc_am_init(ctxt_pP, l_rlc_p); - rlc_am_set_debug_infos(ctxt_pP, l_rlc_p, srb_flagP, rb_idP); + rlc_am_set_debug_infos(ctxt_pP, l_rlc_p, srb_flagP, rb_idP, chan_idP); rlc_am_configure(ctxt_pP, l_rlc_p, config_am_pP->max_retx_threshold, config_am_pP->poll_pdu, @@ -167,7 +168,8 @@ void config_req_rlc_am_asn1 ( const protocol_ctxt_t* const ctxt_pP, const srb_flag_t srb_flagP, const struct RLC_Config__am * const config_am_pP, - const rb_id_t rb_idP) + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP) // 2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC { rlc_union_t *rlc_union_p = NULL; rlc_am_entity_t *l_rlc_p = NULL; @@ -208,7 +210,7 @@ void config_req_rlc_am_asn1 ( t_StatusProhibit_tab[config_am_pP->dl_AM_RLC.t_StatusProhibit]); rlc_am_init(ctxt_pP, l_rlc_p); - rlc_am_set_debug_infos(ctxt_pP, l_rlc_p, srb_flagP, rb_idP); + rlc_am_set_debug_infos(ctxt_pP, l_rlc_p, srb_flagP, rb_idP, chan_idP); rlc_am_configure(ctxt_pP, l_rlc_p, maxRetxThreshold_tab[config_am_pP->ul_AM_RLC.maxRetxThreshold], pollPDU_tab[config_am_pP->ul_AM_RLC.pollPDU], 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 70cbb3b12e..df9f8d6c88 100755 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h @@ -135,31 +135,35 @@ public_rlc_am(void rlc_am_release ( * @{ */ -/*! \fn void config_req_rlc_am (const protocol_ctxt_t* const ctxtP, const srb_flag_t srb_flagP, rlc_am_info_t * config_amP, rb_id_t rb_idP) +/*! \fn void config_req_rlc_am (const protocol_ctxt_t* const ctxtP, const srb_flag_t srb_flagP, rlc_am_info_t * config_amP, rb_id_t rb_idP, logical_chan_id_t chan_idP) * \brief Configure the UL and DL parameters of the RLC AM * \param[in] ctxt_pP Running context. * \param[in] srb_flagP Flag to indicate signalling radio bearer (1) or data radio bearer (0). * \param[in] config_amP Configuration parameters for RLC AM instance. * \param[in] rb_idP Radio bearer identifier. +* \param[in] chan_idP Transport channel identifier. */ public_rlc_am(void config_req_rlc_am ( const protocol_ctxt_t* const ctxtP, const srb_flag_t srb_flagP, const rlc_am_info_t * const config_amP, - const rb_id_t rb_idP);) + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP);) // 2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC -/*! \fn void config_req_rlc_am_asn1 (const protocol_ctxt_t* const ctxtP, const srb_flag_t srb_flagP, struct RLC_Config__am * config_amP, rb_id_t rb_idP) +/*! \fn void config_req_rlc_am_asn1 (const protocol_ctxt_t* const ctxtP, const srb_flag_t srb_flagP, struct RLC_Config__am * config_amP, rb_id_t rb_idP, logical_chan_id_t chan_idP) * \brief Configure the UL and DL parameters of the RLC AM with the asn1c autogenerated pameters structs * \param[in] ctxt_pP Running context. * \param[in] srb_flagP Flag to indicate signalling radio bearer (1) or data radio bearer (0). * \param[in] config_amP Configuration parameters for RLC AM instance. * \param[in] rb_idP Radio bearer identifier. +* \param[in] chan_idP Transport channel identifier. */ public_rlc_am(void config_req_rlc_am_asn1 ( const protocol_ctxt_t* const ctxtP, const srb_flag_t srb_flagP, const struct RLC_Config__am * const config_amP, - const rb_id_t rb_idP);) + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP);) // 2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC /** @} */ 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 81645f06fe..5dcdbc68d1 100755 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c @@ -253,10 +253,13 @@ rlc_am_set_debug_infos( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlc_pP, const srb_flag_t srb_flagP, - const rb_id_t rb_idP) + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP) // 2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC) { - rlc_pP->rb_id = rb_idP; +#ifndef ASTRI_FIX // 2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC) + rlc_pP->channel_id = chan_idP; +#endif if (srb_flagP) { rlc_pP->is_data_plane = 0; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h index ed2f7f2936..f3e38b6bd2 100755 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h @@ -112,13 +112,15 @@ public_rlc_am_init( void rlc_am_configure(const protocol_ctxt_t* const ctxtP, const uint32_t t_reorderingP, const uint32_t t_status_prohibitP);) + /*! \fn void rlc_am_set_debug_infos(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, const srb_flag_t srb_flagP, const rb_id_t rb_idP) * \brief Set informations that will be displayed in traces, helping the debug process. * \param[in] ctxtP Running context. * \param[in] rlc_pP RLC AM protocol instance pointer. * \param[in] srb_flagP Flag to indicate signalling radio bearer (1) or data radio bearer (0). * \param[in] rb_idP Radio bearer identifier. +* \param[in] chan_idP Transport channel identifier. */ -public_rlc_am_init( void rlc_am_set_debug_infos(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, const srb_flag_t srb_flagP, const rb_id_t rb_idP);) +public_rlc_am_init( void rlc_am_set_debug_infos(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, const srb_flag_t srb_flagP, const rb_id_t rb_idP, const logical_chan_id_t chan_idP /*2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC)*/);) /** @} */ #endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c index 13f96e1f3f..719ba2c241 100755 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_test.c @@ -705,8 +705,8 @@ void rlc_am_v9_3_0_test_tx_rx() rlc_am_init(&g_am_tx, g_frame); rlc_am_init(&g_am_rx, g_frame); - rlc_am_set_debug_infos(&g_am_tx, g_frame, 0, 0, 0, 1); - rlc_am_set_debug_infos(&g_am_rx, g_frame, 1, 1, 1, 1); + rlc_am_set_debug_infos(&g_am_tx, g_frame, 0, 0, 0, 1, 1 /* LC-id = DRB-id */); + rlc_am_set_debug_infos(&g_am_rx, g_frame, 1, 1, 1, 1, 1 /* LC-id = DRB-id */); rlc_am_configure(&g_am_tx, g_frame, max_retx_threshold, poll_pdu, poll_byte, t_poll_retransmit, t_reordering, t_status_prohibit); rlc_am_configure(&g_am_rx, g_frame, max_retx_threshold, poll_pdu, poll_byte, t_poll_retransmit, t_reordering, t_status_prohibit); diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c index 6b1b487286..533730ce68 100755 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c @@ -36,7 +36,8 @@ void config_req_rlc_tm ( const protocol_ctxt_t* const ctxt_pP, const srb_flag_t srb_flagP, const rlc_tm_info_t * const config_tmP, - const rb_id_t rb_idP + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP ) { rlc_union_t *rlc_union_p = NULL; @@ -55,7 +56,11 @@ void config_req_rlc_tm ( rlc_tm_init(ctxt_pP, rlc_p); rlc_p->protocol_state = RLC_DATA_TRANSFER_READY_STATE; - rlc_tm_set_debug_infos(ctxt_pP, rlc_p, rb_idP, srb_flagP); +#ifdef ASTRI_FIX + rlc_tm_set_debug_infos(ctxt_pP, rlc_p, srb_flagP, rb_idP); // 2016-05-27 wilson : fix incorrect argument ordering! +#else + rlc_tm_set_debug_infos(ctxt_pP, rlc_p, srb_flagP, rb_idP, chan_idP); // 2016-05-27 wilson : fix DRB-id <-> LC-id mapping +#endif rlc_tm_configure(ctxt_pP, rlc_p, config_tmP->is_uplink_downlink); } else { LOG_E(RLC, PROTOCOL_RLC_TM_CTXT_FMT" CONFIG_REQ RB %u RLC NOT FOUND\n", @@ -151,9 +156,11 @@ void rlc_tm_set_debug_infos( const protocol_ctxt_t* const ctxt_pP, rlc_tm_entity_t * const rlcP, const srb_flag_t srb_flagP, - const rb_id_t rb_idP) + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP) // 2016-05-27 wilson : fixing the DRB-id <-> LC-id mapping { - rlcP->rb_id = rb_idP; + rlcP->rb_id = rb_idP; + rlcP->channel_id = chan_idP; if (srb_flagP) { rlcP->is_data_plane = 0; diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h index 48322c98b8..ecd23a2c2f 100755 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h @@ -80,13 +80,14 @@ typedef volatile struct rlc_tm_info_s { * \param[in] srb_flagP Flag to indicate SRB (1) or DRB (0) * \param[in] config_tmP Configuration parameters for RLC TM instance. * \param[in] rb_idP Radio bearer identifier. -* \param[in] srb_flagP Flag to indicate signalling radio bearer (1) or data radio bearer (0). +* \param[in] chan_idP Transport channel identifier. */ public_rlc_tm_init( void config_req_rlc_tm ( const protocol_ctxt_t* const ctxt_pP, const srb_flag_t srb_flagP, const rlc_tm_info_t * const config_tmP, - const rb_id_t rb_idP);) + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP);) // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping /*! \fn void rlc_tm_init (const protocol_ctxt_t* const ctxt_pP, rlc_tm_entity_t * const rlcP) * \brief Initialize a RLC TM protocol instance, initialize all variables, lists, allocate buffers for making this instance ready to be configured with protocol configuration parameters. After this initialization the RLC TM protocol instance will be in RLC_NULL_STATE state. @@ -127,11 +128,14 @@ protected_rlc_tm_init(void rlc_tm_configure( * \param[in] rlcP RLC TM protocol instance pointer. * \param[in] srb_flagP Flag to indicate signalling radio bearer (1) or data radio bearer (0). * \param[in] rb_idP Radio bearer identifier. +* \param[in] chan_idP Transport channel identifier */ protected_rlc_tm_init(void rlc_tm_set_debug_infos( const protocol_ctxt_t* const ctxt_pP, rlc_tm_entity_t * const rlcP, const srb_flag_t srb_flagP, - const rb_id_t rb_idP);) + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP);) /*2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC)*/ + /** @} */ # endif diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c index a91e384a55..990399c940 100755 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c @@ -47,7 +47,8 @@ void config_req_rlc_um ( const protocol_ctxt_t* const ctxt_pP, const srb_flag_t srb_flagP, const rlc_um_info_t * const config_um_pP, - const rb_id_t rb_idP) + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP) { rlc_union_t *rlc_union_p = NULL; rlc_um_entity_t *rlc_p = NULL; @@ -68,7 +69,7 @@ void config_req_rlc_um ( rlc_um_init(ctxt_pP, rlc_p); if (rlc_um_fsm_notify_event (ctxt_pP, rlc_p, RLC_UM_RECEIVE_CRLC_CONFIG_REQ_ENTER_DATA_TRANSFER_READY_STATE_EVENT)) { - rlc_um_set_debug_infos(ctxt_pP, rlc_p, srb_flagP, rb_idP); + rlc_um_set_debug_infos(ctxt_pP, rlc_p, srb_flagP, rb_idP, chan_idP); rlc_um_configure( ctxt_pP, rlc_p, @@ -94,7 +95,8 @@ void config_req_rlc_um_asn1 ( const mbms_service_id_t mbms_service_idP, const UL_UM_RLC_t * const ul_rlc_pP, const DL_UM_RLC_t * const dl_rlc_pP, - const rb_id_t rb_idP) + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP) { uint32_t ul_sn_FieldLength = 0; uint32_t dl_sn_FieldLength = 0; @@ -142,7 +144,7 @@ void config_req_rlc_um_asn1 ( if (rlc_um_fsm_notify_event (ctxt_pP, rlc_p, RLC_UM_RECEIVE_CRLC_CONFIG_REQ_ENTER_DATA_TRANSFER_READY_STATE_EVENT)) { - rlc_um_set_debug_infos(ctxt_pP,rlc_p, srb_flagP, rb_idP); + rlc_um_set_debug_infos(ctxt_pP,rlc_p, srb_flagP, rb_idP, chan_idP); if (ul_rlc_pP != NULL) { switch (ul_rlc_pP->sn_FieldLength) { @@ -423,14 +425,16 @@ void rlc_um_configure( void rlc_um_set_debug_infos( const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_idP) + const srb_flag_t srb_flagP, + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP) // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping { LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" [SET DEBUG INFOS] rb_id %d srb_flag %d\n", PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP), rb_idP, srb_flagP); - rlc_pP->rb_id = rb_idP; + rlc_pP->rb_id = rb_idP; + rlc_pP->channel_id = chan_idP; // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping if (srb_flagP) { rlc_pP->is_data_plane = 0; diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.h index b9a5166ed2..18dd656024 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.h @@ -84,12 +84,14 @@ typedef volatile struct { * \param[in] srb_flagP Flag to indicate signalling radio bearer (1) or data radio bearer (0). * \param[in] config_umP Configuration parameters for RLC UM instance. * \param[in] rb_idP Radio bearer identifier. +* \param[in] chan_idP Transport channel identifier. */ public_rlc_um_control_primitives( void config_req_rlc_um ( const protocol_ctxt_t* const ctxt_pP, const srb_flag_t srb_flagP, const rlc_um_info_t * const config_umP, - const rb_id_t rb_idP);) + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP);) // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping /*! \fn void config_req_rlc_um_asn1 ( * const protocol_ctxt_t* const ctxt_pP, @@ -109,6 +111,7 @@ public_rlc_um_control_primitives( void config_req_rlc_um ( * \param[in] ul_rlc_pP Configuration parameters for RLC UM UL instance. * \param[in] dl_rlc_pP Configuration parameters for RLC UM DL instance. * \param[in] rb_idP Radio bearer identifier. +* \param[in] chan_idP Transport channel identifier. */ public_rlc_um_control_primitives( void config_req_rlc_um_asn1 ( const protocol_ctxt_t* const ctxt_pP, @@ -118,7 +121,8 @@ public_rlc_um_control_primitives( void config_req_rlc_um_asn1 ( const mbms_service_id_t mbms_service_idP, const UL_UM_RLC_t * const ul_rlc_pP, const DL_UM_RLC_t * const dl_rlc_pP, - const rb_id_t rb_idP);) + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP);) // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping /*! \fn void rlc_um_init (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP) * \brief Initialize a RLC UM protocol instance, initialize all variables, lists, allocate buffers for making this instance ready to be configured with protocol configuration parameters. After this initialization the RLC UM protocol instance will be in RLC_NULL_STATE state. @@ -176,13 +180,15 @@ protected_rlc_um_control_primitives(void rlc_um_configure( * \brief Set debug informations for a RLC UM protocol instance, these informations are only for trace purpose. * \param[in] ctxtP Running context. * \param[in] rlc_pP RLC UM protocol instance pointer. -* \param[in] rb_idP Radio bearer identifier. * \param[in] srb_flagP Flag to indicate signalling radio bearer (1) or data radio bearer (0). +* \param[in] rb_idP Radio bearer identifier. +* \param[in] chan_idP Transport channel identifier. */ protected_rlc_um_control_primitives(void rlc_um_set_debug_infos( const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP, const srb_flag_t srb_flagP, - const rb_id_t rb_idP);) + const rb_id_t rb_idP, + const logical_chan_id_t chan_idP);) // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping /** @} */ # endif diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c index 04afcff0ff..ce613be23e 100755 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c @@ -195,8 +195,8 @@ void rlc_um_v9_3_0_test_windows_10() rlc_um_init(&um1); rlc_um_init(&um2); - rlc_um_set_debug_infos(&um1, g_frame, 0, 0, 0, 1); - rlc_um_set_debug_infos(&um2, g_frame, 1, 1, 1, 1); + rlc_um_set_debug_infos(&um1, g_frame, 0, 0, 0, 1, 1 /*LC-id = RAB-id*/); + rlc_um_set_debug_infos(&um2, g_frame, 1, 1, 1, 1, 1 /*LC-id = RAB-id*/); rlc_um_configure(&um1, g_frame, timer_reordering, sn_field_length, sn_field_length, is_mXch); rlc_um_configure(&um2, g_frame, timer_reordering, sn_field_length, sn_field_length, is_mXch); @@ -249,8 +249,8 @@ void rlc_um_v9_3_0_test_windows_5() rlc_um_init(&um1); rlc_um_init(&um2); - rlc_um_set_debug_infos(&um1, g_frame, 0, 0, 0, 1); - rlc_um_set_debug_infos(&um2, g_frame, 1, 1, 1, 1); + rlc_um_set_debug_infos(&um1, g_frame, 0, 0, 0, 1, 1 /* LC-id = DRB-id */); + rlc_um_set_debug_infos(&um2, g_frame, 1, 1, 1, 1, 1 /* LC-id = DRB-id */); rlc_um_configure(&um1, g_frame, timer_reordering, sn_field_length, sn_field_length, is_mXch); rlc_um_configure(&um2, g_frame, timer_reordering, sn_field_length, sn_field_length, is_mXch); @@ -621,8 +621,8 @@ void rlc_um_v9_3_0_test_reordering(uint32_t sn_field_lengthP) um_info.is_mXch = 0; srand (0); - config_req_rlc_um (&um_tx, 0,0,0, &um_info, 0, SIGNALLING_RADIO_BEARER); - config_req_rlc_um (&um_rx, 0,1,1, &um_info, 1, SIGNALLING_RADIO_BEARER); + config_req_rlc_um (&um_tx, 0,0,0, &um_info, 0, SIGNALLING_RADIO_BEARER, SIGNALLING_RADIO_BEARER /*LC-id = DRB-id*/); + config_req_rlc_um (&um_rx, 0,1,1, &um_info, 1, SIGNALLING_RADIO_BEARER, SIGNALLING_RADIO_BEARER /*LC-id = DRB-id*/); rlc_um_display_rx_window(&um_tx); @@ -743,8 +743,8 @@ void rlc_um_v9_3_0_test_tx_rx_10(void) um_info.is_mXch = 0; srand (0); - config_req_rlc_um (&um_tx, 0,0,0, &um_info, 0, SIGNALLING_RADIO_BEARER); - config_req_rlc_um (&um_rx, 0,1,1, &um_info, 1, SIGNALLING_RADIO_BEARER); + config_req_rlc_um (&um_tx, 0,0,0, &um_info, 0, SIGNALLING_RADIO_BEARER, SIGNALLING_RADIO_BEARER /*LC-id = DRB-id*/); + config_req_rlc_um (&um_rx, 0,1,1, &um_info, 1, SIGNALLING_RADIO_BEARER, SIGNALLING_RADIO_BEARER /*LC-id = DRB-id*/); rlc_um_display_rx_window(&um_tx); @@ -1072,8 +1072,8 @@ void rlc_um_v9_3_0_test_tx_rx_5(void) um_info.is_mXch = 0; srand (0); - config_req_rlc_um (&um_tx, 0,0,0, &um_info, 0, SIGNALLING_RADIO_BEARER); - config_req_rlc_um (&um_rx, 0,1,1, &um_info, 1, SIGNALLING_RADIO_BEARER); + config_req_rlc_um (&um_tx, 0,0,0, &um_info, 0, SIGNALLING_RADIO_BEARER, SIGNALLING_RADIO_BEARER /*LC-id = DRB-id*/); + config_req_rlc_um (&um_rx, 0,1,1, &um_info, 1, SIGNALLING_RADIO_BEARER, SIGNALLING_RADIO_BEARER /*LC-id = DRB-id*/); rlc_um_display_rx_window(&um_tx); diff --git a/openair2/LAYER2/RLC/rlc.h b/openair2/LAYER2/RLC/rlc.h index 72fde0b746..525e75a4d9 100755 --- a/openair2/LAYER2/RLC/rlc.h +++ b/openair2/LAYER2/RLC/rlc.h @@ -269,7 +269,18 @@ public_rlc(logical_chan_id_t rlc_mbms_rbid2lcid_eNB[NUMBER_OF_eNB_MAX][NB_RB_ (((hash_key_t)(rNTI)) << 8) | \ (((hash_key_t)(iS_eNB)) << 24) | \ (((hash_key_t)(rB_iD)) << 25) | \ - (((hash_key_t)(iS_sRB)) << 33)) + (((hash_key_t)(iS_sRB)) << 33) | \ + (((hash_key_t)(0x05)) << 34)) + +// index to the same RLC entity as RLC_COLL_KEY_VALUE(), but using LC_id instead +// the hidden last key indicates if this is a hash-key with RB_id (0x05) or LC_id (0x0a) +#define RLC_COLL_KEY_LCID_VALUE(eNB_iD, rNTI, iS_eNB, lC_iD, iS_sRB) \ + ((hash_key_t)eNB_iD | \ + (((hash_key_t)(rNTI)) << 8) | \ + (((hash_key_t)(iS_eNB)) << 24) | \ + (((hash_key_t)(lC_iD)) << 25) | \ + (((hash_key_t)(iS_sRB)) << 33) | \ + (((hash_key_t)(0x0a)) << 34)) // service id max val is maxServiceCount = 16 (asn1_constants.h) diff --git a/openair2/LAYER2/RLC/rlc_mac.c b/openair2/LAYER2/RLC/rlc_mac.c index 3bde40888f..2f347cd227 100644 --- a/openair2/LAYER2/RLC/rlc_mac.c +++ b/openair2/LAYER2/RLC/rlc_mac.c @@ -136,7 +136,7 @@ tbs_size_t mac_rlc_data_req( { //----------------------------------------------------------------------------- struct mac_data_req data_request; - rb_id_t rb_id = 0; + // rb_id_t rb_id = 0; // 2016-05-27 wilson : not needed after DRB-id <-> LC-id mapping fix rlc_mode_t rlc_mode = RLC_MODE_NONE; rlc_mbms_id_t *mbms_id_p = NULL; rlc_union_t *rlc_union_p = NULL; @@ -179,6 +179,7 @@ tbs_size_t mac_rlc_data_req( return (tbs_size_t)0; } } else { +#ifdef ASTRI_FIX // 2016-05-27 wilson : fixing the DRB-id <-> LC-id mapping if (channel_idP > 2) { rb_id = channel_idP - 2; } else { @@ -186,6 +187,9 @@ tbs_size_t mac_rlc_data_req( } key = RLC_COLL_KEY_VALUE(module_idP, rntiP, enb_flagP, rb_id, srb_flag); +#else + key = RLC_COLL_KEY_LCID_VALUE(module_idP, rntiP, enb_flagP, channel_idP, srb_flag); +#endif } h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); @@ -194,7 +198,7 @@ tbs_size_t mac_rlc_data_req( rlc_mode = rlc_union_p->mode; } else { rlc_mode = RLC_MODE_NONE; - AssertFatal (0 , "RLC not configured rb id %u lcid %u RNTI %x!\n", rb_id, channel_idP, rntiP); + AssertFatal (0 , "RLC not configured lcid %u RNTI %x!\n", channel_idP, rntiP); } switch (rlc_mode) { @@ -244,7 +248,7 @@ void mac_rlc_data_ind ( crc_t *crcs_pP) { //----------------------------------------------------------------------------- - rb_id_t rb_id = 0; + // rb_id_t rb_id = 0; // 2016-05-27 wilson : not needed after DRB-id <-> LC-id mapping fix rlc_mode_t rlc_mode = RLC_MODE_NONE; rlc_mbms_id_t *mbms_id_p = NULL; rlc_union_t *rlc_union_p = NULL; @@ -294,6 +298,7 @@ void mac_rlc_data_ind ( return; } } else { +#ifdef ASTRI_FIX // 2016-05-27 wilson : fixing the DRB-id <-> LC-id mapping if (channel_idP > 2) { rb_id = channel_idP - 2; } else { @@ -301,6 +306,9 @@ void mac_rlc_data_ind ( } key = RLC_COLL_KEY_VALUE(module_idP, rntiP, enb_flagP, rb_id, srb_flag); +#else + key = RLC_COLL_KEY_LCID_VALUE(module_idP, rntiP, enb_flagP, channel_idP, srb_flag); +#endif } h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); @@ -350,7 +358,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind( mac_rlc_status_resp_t mac_rlc_status_resp; struct mac_status_ind tx_status; struct mac_status_resp status_resp; - rb_id_t rb_id = 0; + // rb_id_t rb_id = 0; // 2016-05-27 wilson : not needed after DRB-id <-> LC-id mapping fix rlc_mode_t rlc_mode = RLC_MODE_NONE; rlc_mbms_id_t *mbms_id_p = NULL; rlc_union_t *rlc_union_p = NULL; @@ -399,6 +407,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind( key = RLC_COLL_KEY_MBMS_VALUE(module_idP, rntiP, enb_flagP, mbms_id_p->service_id, mbms_id_p->session_id); } else { +#ifdef ASTRI_FIX // 2016-05-27 wilson : fixing the DRB-id <-> LC-id mapping if (channel_idP > 2) { rb_id = channel_idP - 2; } else { @@ -406,6 +415,9 @@ mac_rlc_status_resp_t mac_rlc_status_ind( } key = RLC_COLL_KEY_VALUE(module_idP, rntiP, enb_flagP, rb_id, srb_flag); +#else + key = RLC_COLL_KEY_LCID_VALUE(module_idP, rntiP, enb_flagP, channel_idP, srb_flag); +#endif } h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); diff --git a/openair2/LAYER2/RLC/rlc_rrc.c b/openair2/LAYER2/RLC/rlc_rrc.c index 9919cc0f70..aba2ab411f 100644 --- a/openair2/LAYER2/RLC/rlc_rrc.c +++ b/openair2/LAYER2/RLC/rlc_rrc.c @@ -104,7 +104,11 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP if (srb2add_listP != NULL) { for (cnt=0; cntlist.count; cnt++) { rb_id = srb2add_listP->list.array[cnt]->srb_Identity; +#if 0 lc_id = rb_id + 2; +#else // 2016-05-26 wilson : fixing the LC-id<->SRB-id mapping for SRB + lc_id = rb_id; +#endif LOG_D(RLC, "Adding SRB %d, rb_id %d\n",srb2add_listP->list.array[cnt]->srb_Identity,rb_id); srb_toaddmod_p = srb2add_listP->list.array[cnt]; @@ -125,7 +129,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP ctxt_pP, SRB_FLAG_YES, &srb_toaddmod_p->rlc_Config->choice.explicitValue.choice.am, - rb_id); + rb_id, lc_id); } else { LOG_E(RLC, PROTOCOL_CTXT_FMT" ERROR IN ALLOCATING SRB %d \n", PROTOCOL_CTXT_ARGS(ctxt_pP), @@ -144,7 +148,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP UNUSED_PARAM_MBMS_SERVICE_ID, &srb_toaddmod_p->rlc_Config->choice.explicitValue.choice.um_Bi_Directional.ul_UM_RLC, &srb_toaddmod_p->rlc_Config->choice.explicitValue.choice.um_Bi_Directional.dl_UM_RLC, - rb_id); + rb_id, lc_id); } else { LOG_E(RLC, PROTOCOL_CTXT_FMT" ERROR IN ALLOCATING SRB %d \n", PROTOCOL_CTXT_ARGS(ctxt_pP), @@ -163,7 +167,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP UNUSED_PARAM_MBMS_SERVICE_ID, &srb_toaddmod_p->rlc_Config->choice.explicitValue.choice.um_Uni_Directional_UL.ul_UM_RLC, NULL, - rb_id); + rb_id, lc_id); } else { LOG_E(RLC, PROTOCOL_CTXT_FMT" ERROR IN ALLOCATING SRB %d \n", PROTOCOL_CTXT_ARGS(ctxt_pP), @@ -182,7 +186,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP UNUSED_PARAM_MBMS_SERVICE_ID, NULL, &srb_toaddmod_p->rlc_Config->choice.explicitValue.choice.um_Uni_Directional_DL.dl_UM_RLC, - rb_id); + rb_id, lc_id); } else { LOG_E(RLC, PROTOCOL_CTXT_FMT" ERROR IN ALLOCATING SRB %d \n", PROTOCOL_CTXT_ARGS(ctxt_pP), @@ -211,7 +215,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP UNUSED_PARAM_MBMS_SERVICE_ID, NULL, // TO DO DEFAULT CONFIG NULL, // TO DO DEFAULT CONFIG - rb_id); + rb_id, lc_id); } else { LOG_D(RLC, PROTOCOL_CTXT_FMT" ERROR IN ALLOCATING SRB %d \n", PROTOCOL_CTXT_ARGS(ctxt_pP), @@ -232,7 +236,22 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP drb_toaddmod_p = drb2add_listP->list.array[cnt]; drb_id = drb_toaddmod_p->drb_Identity; +#if 0 lc_id = drb_id + 2; +#else // 2016-05-26 wilson : fixing the LC-id <-> DRB-id mapping + if (drb_toaddmod_p->logicalChannelIdentity) { + lc_id = *drb_toaddmod_p->logicalChannelIdentity; + } else { + LOG_E(RLC, PROTOCOL_CTXT_FMT" logicalChannelIdentity is missing from drb-ToAddMod information element!\n", PROTOCOL_CTXT_ARGS(ctxt_pP)); + continue; + } + + if (lc_id == 1 || lc_id == 2) { + LOG_E(RLC, PROTOCOL_CTXT_FMT" logicalChannelIdentity = %d is invalid in RRC message when adding DRB!\n", PROTOCOL_CTXT_ARGS(ctxt_pP), lc_id); + continue; + } + +#endif LOG_I(RLC, "Adding DRB %d, lc_id %d\n",drb_id,lc_id); @@ -249,7 +268,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP ctxt_pP, SRB_FLAG_NO, &drb_toaddmod_p->rlc_Config->choice.am, - drb_id); + drb_id, lc_id); } break; @@ -264,7 +283,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP UNUSED_PARAM_MBMS_SERVICE_ID, &drb_toaddmod_p->rlc_Config->choice.um_Bi_Directional.ul_UM_RLC, &drb_toaddmod_p->rlc_Config->choice.um_Bi_Directional.dl_UM_RLC, - drb_id); + drb_id, lc_id); } break; @@ -279,7 +298,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP UNUSED_PARAM_MBMS_SERVICE_ID, &drb_toaddmod_p->rlc_Config->choice.um_Uni_Directional_UL.ul_UM_RLC, NULL, - drb_id); + drb_id, lc_id); } break; @@ -294,7 +313,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP UNUSED_PARAM_MBMS_SERVICE_ID, NULL, &drb_toaddmod_p->rlc_Config->choice.um_Uni_Directional_DL.dl_UM_RLC, - drb_id); + drb_id, lc_id); } break; @@ -378,7 +397,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP mbms_service_id, NULL, &dl_um_rlc, - rb_id); + rb_id, lc_id); } } } @@ -459,6 +478,10 @@ rlc_op_status_t rrc_rlc_remove_rlc ( logical_chan_id_t lcid = 0; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; +#ifndef ASTRI_FIX // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping + hash_key_t key_lcid = HASHTABLE_NOT_A_KEY_VALUE; + hashtable_rc_t h_lcid_rc; +#endif rlc_union_t *rlc_union_p = NULL; #ifdef Rel10 rlc_mbms_id_t *mbms_id_p = NULL; @@ -502,23 +525,51 @@ rlc_op_status_t rrc_rlc_remove_rlc ( h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); if (h_rc == HASH_TABLE_OK) { - h_rc = hashtable_remove(rlc_coll_p, key); - LOG_D(RLC, PROTOCOL_CTXT_FMT"[%s %u] RELEASED %s\n", - PROTOCOL_CTXT_ARGS(ctxt_pP), - (srb_flagP) ? "SRB" : "DRB", - rb_idP, - (srb_flagP) ? "SRB" : "DRB"); - } else if (h_rc == HASH_TABLE_KEY_NOT_EXISTS) { - LOG_D(RLC, PROTOCOL_CTXT_FMT"[%s %u] RELEASE : RLC NOT FOUND %s\n", - PROTOCOL_CTXT_ARGS(ctxt_pP), - (srb_flagP) ? "SRB" : "DRB", - rb_idP, - (srb_flagP) ? "SRB" : "DRB"); +#ifndef ASTRI_FIX // 2016-05-27 wilson : fixing the DRB-id <-> LC-id mapping + // also remove the hash-key created by LC-id + switch (rlc_union_p->mode) { + case RLC_MODE_AM: + lcid = rlc_union_p->rlc.am.channel_id; + break; + case RLC_MODE_UM: + lcid = rlc_union_p->rlc.um.channel_id; + break; + case RLC_MODE_TM: + lcid = rlc_union_p->rlc.tm.channel_id; + break; + default: + LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u] RLC mode is unknown!\n", + PROTOCOL_CTXT_ARGS(ctxt_pP), + (srb_flagP) ? "SRB" : "DRB", + rb_idP); + } + key_lcid = RLC_COLL_KEY_LCID_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, lcid, srb_flagP); + h_lcid_rc = hashtable_get(rlc_coll_p, key_lcid, (void**)&rlc_union_p); } else { - LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u] RELEASE : INTERNAL ERROR %s\n", + h_lcid_rc = HASH_TABLE_KEY_NOT_EXISTS; + } + + if ((h_rc == HASH_TABLE_OK) && (h_lcid_rc == HASH_TABLE_OK)) { + h_lcid_rc = hashtable_remove(rlc_coll_p, key_lcid); +#endif + h_rc = hashtable_remove(rlc_coll_p, key); + LOG_D(RLC, PROTOCOL_CTXT_FMT"[%s %u LCID %d] RELEASED %s\n", PROTOCOL_CTXT_ARGS(ctxt_pP), (srb_flagP) ? "SRB" : "DRB", - rb_idP, + rb_idP, lcid, + (srb_flagP) ? "SRB" : "DRB"); + } else if ((h_rc == HASH_TABLE_KEY_NOT_EXISTS) || (h_lcid_rc == HASH_TABLE_KEY_NOT_EXISTS)) { + LOG_D(RLC, PROTOCOL_CTXT_FMT"[%s %u LCID %d] RELEASE : RLC NOT FOUND %s, by RB-ID=%d, by LC-ID=%d\n", + PROTOCOL_CTXT_ARGS(ctxt_pP), + (srb_flagP) ? "SRB" : "DRB", + rb_idP, lcid, + (srb_flagP) ? "SRB" : "DRB", + h_rc, h_lcid_rc); + } else { + LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u LCID %d] RELEASE : INTERNAL ERROR %s\n", + PROTOCOL_CTXT_ARGS(ctxt_pP), + (srb_flagP) ? "SRB" : "DRB", + rb_idP, lcid, (srb_flagP) ? "SRB" : "DRB"); } @@ -536,6 +587,10 @@ rlc_union_t* rrc_rlc_add_rlc ( //----------------------------------------------------------------------------- hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; +#if 1 // 2016-05-26 wilson hash_key to the same RLC entity but indexed by LC_id instead of RB_id + hash_key_t key_lcid = HASHTABLE_NOT_A_KEY_VALUE; + hashtable_rc_t h_lcid_rc; +#endif rlc_union_t *rlc_union_p = NULL; #ifdef Rel10 rlc_mbms_id_t *mbms_id_p = NULL; @@ -576,6 +631,9 @@ rlc_union_t* rrc_rlc_add_rlc ( #endif { key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); +#ifndef ASTRI_FIX // 2016-05-26 wilson : fix DRB-id <-> LC-id mapping + key_lcid = RLC_COLL_KEY_LCID_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, chan_idP, srb_flagP); +#endif } h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); @@ -591,8 +649,11 @@ rlc_union_t* rrc_rlc_add_rlc ( } else if (h_rc == HASH_TABLE_KEY_NOT_EXISTS) { rlc_union_p = calloc(1, sizeof(rlc_union_t)); h_rc = hashtable_insert(rlc_coll_p, key, rlc_union_p); +#ifndef ASTRI_FIX // 2016-05-26 wilson + h_lcid_rc = hashtable_insert(rlc_coll_p, key_lcid, rlc_union_p); +#endif - if (h_rc == HASH_TABLE_OK) { + if ((h_rc == HASH_TABLE_OK) && (h_lcid_rc == HASH_TABLE_OK)) { #ifdef Rel10 if (MBMS_flagP == TRUE) { @@ -613,11 +674,12 @@ rlc_union_t* rrc_rlc_add_rlc ( rlc_union_p->mode = rlc_modeP; return rlc_union_p; } else { - LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u] rrc_rlc_add_rlc FAILED %s\n", + LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u] rrc_rlc_add_rlc FAILED %s (add by RB_id=%d; add by LC_id=%d)\n", PROTOCOL_CTXT_ARGS(ctxt_pP), (srb_flagP) ? "SRB" : "DRB", rb_idP, - (srb_flagP) ? "SRB" : "DRB"); + (srb_flagP) ? "SRB" : "DRB", + h_rc, h_lcid_rc); free(rlc_union_p); rlc_union_p = NULL; return NULL; @@ -674,7 +736,7 @@ rlc_op_status_t rrc_rlc_config_req ( ctxt_pP, srb_flagP, &rlc_infoP.rlc.rlc_am_info, - rb_idP); + rb_idP, rb_idP); break; case RLC_MODE_UM: @@ -685,7 +747,7 @@ rlc_op_status_t rrc_rlc_config_req ( ctxt_pP, srb_flagP, &rlc_infoP.rlc.rlc_um_info, - rb_idP); + rb_idP, rb_idP); break; case RLC_MODE_TM: @@ -696,7 +758,7 @@ rlc_op_status_t rrc_rlc_config_req ( ctxt_pP, srb_flagP, &rlc_infoP.rlc.rlc_tm_info, - rb_idP); + rb_idP, rb_idP); break; default: diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index e546b52f8e..1a39020a84 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -506,6 +506,9 @@ typedef struct UE_RRC_INST_s { struct SRB_ToAddMod *SRB1_config[NB_CNX_UE]; struct SRB_ToAddMod *SRB2_config[NB_CNX_UE]; struct DRB_ToAddMod *DRB_config[NB_CNX_UE][8]; +#ifndef ASTRI_FIX + rb_id_t *defaultDRB; // 2015-05-27 wilson : remember the default DRB ID +#endif MeasObjectToAddMod_t *MeasObj[NB_CNX_UE][MAX_MEAS_OBJ]; struct ReportConfigToAddMod *ReportConfig[NB_CNX_UE][MAX_MEAS_CONFIG]; struct QuantityConfig *QuantityConfig[NB_CNX_UE]; diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index 01c1ee6ca9..cd1389fbc0 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -1060,7 +1060,7 @@ rrc_ue_process_radioResourceConfigDedicated( #ifdef Rel10 ,(PMCH_InfoList_r9_t *)NULL #endif - ); + ,NULL); // Refresh SRBs rrc_rlc_config_asn1_req(ctxt_pP, @@ -1200,6 +1200,18 @@ rrc_ue_process_radioResourceConfigDedicated( // Establish DRBs if present if (radioResourceConfigDedicated->drb_ToAddModList) { + +#ifndef ASTRI_FIX // 2016-05-28 wilson : remember the default DRB ID + if ( (UE_rrc_inst[ctxt_pP->module_id].defaultDRB == NULL) && + (radioResourceConfigDedicated->drb_ToAddModList->list.count >= 1) ) { + // configure the first DRB ID as the default DRB ID + UE_rrc_inst[ctxt_pP->module_id].defaultDRB = malloc(sizeof(rb_id_t)); + *UE_rrc_inst[ctxt_pP->module_id].defaultDRB = radioResourceConfigDedicated->drb_ToAddModList->list.array[0]->drb_Identity; + LOG_I(RRC,"[UE %d] default DRB = %d\n",ctxt_pP->module_id, *UE_rrc_inst[ctxt_pP->module_id].defaultDRB); + } + +#endif + uint8_t *kUPenc = NULL; #if defined(ENABLE_SECURITY) @@ -1231,7 +1243,7 @@ rrc_ue_process_radioResourceConfigDedicated( #ifdef Rel10 ,(PMCH_InfoList_r9_t *)NULL #endif - ); + , UE_rrc_inst[ctxt_pP->module_id].defaultDRB); // Refresh DRBs rrc_rlc_config_asn1_req(ctxt_pP, @@ -1725,7 +1737,7 @@ rrc_ue_process_mobilityControlInfo( #ifdef Rel10 ,NULL #endif - ); + ,NULL); rrc_rlc_config_asn1_req(NB_eNB_INST+ue_mod_idP, frameP,0,eNB_index, NULL,// SRB_ToAddModList @@ -1734,7 +1746,7 @@ rrc_ue_process_mobilityControlInfo( #ifdef Rel10 ,NULL #endif - ); + ,NULL); */ @@ -3906,7 +3918,7 @@ static void decode_MBSFNAreaConfiguration( module_id_t ue_mod_idP, uint8_t eNB_i #ifdef Rel10 ,&(UE_rrc_inst[ue_mod_idP].mcch_message[eNB_index]->pmch_InfoList_r9) #endif - ); + ,NULL); rrc_rlc_config_asn1_req(&ctxt, NULL,// SRB_ToAddModList diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 7f36a9b36c..428f5196f6 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -481,7 +481,7 @@ static void init_MBMS( # ifdef Rel10 , &(eNB_rrc_inst[enb_mod_idP].carrier[CC_id].mcch_message->pmch_InfoList_r9) # endif - ); + ,NULL); rrc_rlc_config_asn1_req(&ctxt, NULL, // SRB_ToAddModList @@ -3282,7 +3282,7 @@ rrc_eNB_generate_RRCConnectionReconfiguration_handover( #ifdef Rel10 , (PMCH_InfoList_r9_t *) NULL #endif - ); + ,NULL); rrc_rlc_config_asn1_req(&ctxt, ue_context_pP->ue_context.SRB_configList, @@ -3524,7 +3524,7 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( #ifdef Rel10 , (PMCH_InfoList_r9_t *) NULL #endif - ); + ,NULL); // Refresh SRBs/DRBs rrc_rlc_config_asn1_req( ctxt_pP, @@ -4336,7 +4336,7 @@ rrc_eNB_decode_ccch( # ifdef Rel10 , (PMCH_InfoList_r9_t *) NULL # endif - ); + ,NULL); rrc_rlc_config_asn1_req(ctxt_pP, ue_context_p->ue_context.SRB_configList, From 6feb848ebe204653ed565d73881ecb7ef3c0d892 Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Sun, 18 Sep 2016 15:35:48 +0800 Subject: [PATCH 230/413] removed all 'wilson' and 'ASTRI' words from comments Conflicts: openair2/LAYER2/PDCP_v10.1.0/pdcp.c openair2/LAYER2/RLC/rlc_rrc.c --- openair2/LAYER2/PDCP_v10.1.0/pdcp.c | 28 +++------------- openair2/LAYER2/PDCP_v10.1.0/pdcp.h | 5 +-- openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 7 +--- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 4 +-- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h | 4 +-- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c | 4 +-- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h | 2 +- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c | 8 ++--- openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h | 4 +-- .../RLC/UM_v9.3.0/rlc_um_control_primitives.c | 4 +-- .../RLC/UM_v9.3.0/rlc_um_control_primitives.h | 6 ++-- openair2/LAYER2/RLC/rlc_mac.c | 33 ------------------- openair2/LAYER2/RLC/rlc_rrc.c | 21 +----------- openair2/RRC/LITE/defs.h | 4 +-- openair2/RRC/LITE/rrc_UE.c | 3 -- 15 files changed, 23 insertions(+), 114 deletions(-) diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 7f9017201a..8c7abe963c 100755 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -1065,7 +1065,7 @@ rrc_pdcp_config_asn1_req ( #ifdef Rel10 ,PMCH_InfoList_r9_t* const pmch_InfoList_r9_pP #endif - ,rb_id_t *const defaultDRB // 2016-05-28 wilson : remember the default DRB + ,rb_id_t *const defaultDRB ) //----------------------------------------------------------------------------- { @@ -1087,10 +1087,8 @@ rrc_pdcp_config_asn1_req ( hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; -#ifndef ASTRI_FIX // 2016-05-28 wilson : remember the default DRB hash_key_t key_defaultDRB = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_defaultDRB_rc; -#endif #ifdef Rel10 int i,j; MBMS_SessionInfoList_r9_t *mbms_SessionInfoList_r9_p = NULL; @@ -1111,11 +1109,7 @@ rrc_pdcp_config_asn1_req ( srb_id = srb2add_list_pP->list.array[cnt]->srb_Identity; srb_toaddmod_p = srb2add_list_pP->list.array[cnt]; rlc_type = RLC_MODE_AM; -#if 0 - lc_id = srb_id;// + 2; -#else // 2016-05-27 wilson : fixing the LC-id <-> SRB-id mapping lc_id = srb_id; -#endif key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_YES); h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p); @@ -1195,9 +1189,6 @@ rrc_pdcp_config_asn1_req ( drb_toaddmod_p = drb2add_list_pP->list.array[cnt]; drb_id = drb_toaddmod_p->drb_Identity;// + drb_id_offset; -#ifdef ASTRI_FIX - lc_id = drb_id + 2; -#else // 2016-05-27 wilson : fixing the mapping between LC-id and DRB-id if (drb_toaddmod_p->logicalChannelIdentity) { lc_id = *(drb_toaddmod_p->logicalChannelIdentity); } else { @@ -1210,7 +1201,6 @@ rrc_pdcp_config_asn1_req ( LOG_E(RLC, PROTOCOL_CTXT_FMT" logicalChannelIdentity = %d is invalid in RRC message when adding DRB!\n", PROTOCOL_CTXT_ARGS(ctxt_pP), lc_id); continue; } -#endif DevCheck4(drb_id < maxDRB, drb_id, maxDRB, ctxt_pP->module_id, ctxt_pP->rnti); key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, drb_id, SRB_FLAG_NO); @@ -1227,7 +1217,7 @@ rrc_pdcp_config_asn1_req ( pdcp_p = calloc(1, sizeof(pdcp_t)); h_rc = hashtable_insert(pdcp_coll_p, key, pdcp_p); -#ifndef ASTRI_FIX + // save the first configured DRB-ID as the default DRB-ID if ((defaultDRB != NULL) && (*defaultDRB == drb_id)) { key_defaultDRB = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag); h_defaultDRB_rc = hashtable_insert(pdcp_coll_p, key_defaultDRB, pdcp_p); @@ -1241,9 +1231,7 @@ rrc_pdcp_config_asn1_req ( key_defaultDRB); free(pdcp_p); return TRUE; - } else -#endif - if (h_rc != HASH_TABLE_OK) { + } else if (h_rc != HASH_TABLE_OK) { LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD key 0x%"PRIx64" FAILED\n", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), key); @@ -1337,9 +1325,6 @@ rrc_pdcp_config_asn1_req ( for (cnt=0; cntlist.count; cnt++) { pdrb_id_p = drb2release_list_pP->list.array[cnt]; drb_id = *pdrb_id_p; -#if 0 // 2016-05-27 wilson : fixing the hard-coded mapping between DRB-id <-> LC-id - lc_id = drb_id + 2; -#endif key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_NO); h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p); @@ -1349,10 +1334,7 @@ rrc_pdcp_config_asn1_req ( drb_id); continue; } - -#ifndef ASTRI_FIX // 2016-05-27 wilson : fixing the hard-coded mapping between DRB-id <-> LC-id lc_id = pdcp_p->lcid; -#endif action = CONFIG_ACTION_REMOVE; pdcp_config_req_asn1 ( @@ -1373,9 +1355,8 @@ rrc_pdcp_config_asn1_req ( kUPenc_pP); h_rc = hashtable_remove(pdcp_coll_p, key); -#ifndef ASTRI_FIX // 2016-05-28 wilson : remember the default DRB if ((defaultDRB != NULL) && (*defaultDRB == drb_id)) { - // this is the default DRB being removed, although this is not allowed in standard + // default DRB being removed. nevertheless this shouldn't happen as removing default DRB is not allowed in standard key_defaultDRB = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag); h_defaultDRB_rc = hashtable_get(pdcp_coll_p, key_defaultDRB, (void**)&pdcp_p); @@ -1387,7 +1368,6 @@ rrc_pdcp_config_asn1_req ( } else { key_defaultDRB = HASH_TABLE_OK; // do not trigger any error handling if this is not a default DRB } -#endif } } diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index 5f9e3f397a..7d162d1609 100755 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -295,7 +295,7 @@ public_pdcp( #ifdef Rel10 ,PMCH_InfoList_r9_t *pmch_InfoList_r9 #endif - ,rb_id_t *const defaultDRB // 2016-05-28 wilson : remember the default DRB + ,rb_id_t *const defaultDRB )); /*! \fn boolean_t pdcp_config_req_asn1 (const protocol_ctxt_t* const ctxt_pP, srb_flag_t srb_flagP, uint32_t action, rb_id_t rb_id, uint8_t rb_sn, uint8_t rb_report, uint16_t header_compression_profile, uint8_t security_mode) @@ -478,8 +478,6 @@ protected_pdcp(sdu_size_t pdcp_input_sdu_remaining_size_to_read;) (((hash_key_t)(iS_sRB)) << 33) | \ (((hash_key_t)(0x55)) << 34)) -#ifndef ASTRI_FIX // 2016-05-28 wilson : for remeber the default DRB - // hash key to the same PDCP as indexed by PDCP_COLL_KEY_VALUE(... rB_iD, iS_sRB=0) where rB_iD // is the default DRB ID. The hidden code 0x55 indicates the key is indexed by (rB_iD,is_sRB) // whereas the hidden code 0xaa indicates the key is for default DRB only @@ -490,7 +488,6 @@ protected_pdcp(sdu_size_t pdcp_input_sdu_remaining_size_to_read;) (((hash_key_t)(0xff)) << 25) | \ (((hash_key_t)(0x00)) << 33) | \ (((hash_key_t)(0xaa)) << 34)) -#endif // service id max val is maxServiceCount = 16 (asn1_constants.h) diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index 8dea985345..1cde2010f4 100755 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -599,15 +599,12 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const ctxt_pP) } } else { // enb_flag if (rab_id != 0) { -#ifndef ASTRI_FIX // 2016-05-30 wilson : fix hard-code default DRB ID if (rab_id == UE_IP_DEFAULT_RAB_ID) { LOG_D(PDCP, "PDCP_COLL_KEY_DEFAULT_DRB_VALUE(module_id=%d, rnti=%x, enb_flag=%d)\n", ctxt.module_id, ctxt.rnti, ctxt.enb_flag); key = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt.module_id, ctxt.rnti, ctxt.enb_flag); h_rc = hashtable_get(pdcp_coll_p, key, (void**)&pdcp_p); - } else -#endif - { + } else { rab_id = rab_id % maxDRB; LOG_D(PDCP, "PDCP_COLL_KEY_VALUE(module_id=%d, rnti=%x, enb_flag=%d, rab_id=%d, SRB_FLAG=%d)\n", ctxt.module_id, ctxt.rnti, ctxt.enb_flag, rab_id, SRB_FLAG_NO); @@ -616,9 +613,7 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const ctxt_pP) } if (h_rc == HASH_TABLE_OK) { -#ifndef ASTRI_FIX // 2016-05-30 wilson : fix default DRB-ID to be configurable rab_id = pdcp_p->rb_id; -#endif #ifdef PDCP_DEBUG LOG_D(PDCP, "[FRAME %5u][UE][NETLINK][IP->PDCP] INST %d: Received socket with length %d (nlmsg_len = %d) on Rab %d \n", ctxt.frame, 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 8d45ac9582..ff807f711e 100755 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -121,7 +121,7 @@ config_req_rlc_am ( const srb_flag_t srb_flagP, rlc_am_info_t * const config_am_pP, const rb_id_t rb_idP, - const logical_chan_id_t chan_idP // 2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC + const logical_chan_id_t chan_idP ) { rlc_union_t *rlc_union_p = NULL; @@ -169,7 +169,7 @@ void config_req_rlc_am_asn1 ( const srb_flag_t srb_flagP, const struct RLC_Config__am * const config_am_pP, const rb_id_t rb_idP, - const logical_chan_id_t chan_idP) // 2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC + const logical_chan_id_t chan_idP) { rlc_union_t *rlc_union_p = NULL; rlc_am_entity_t *l_rlc_p = NULL; 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 df9f8d6c88..305326113e 100755 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h @@ -148,7 +148,7 @@ public_rlc_am(void config_req_rlc_am ( const srb_flag_t srb_flagP, const rlc_am_info_t * const config_amP, const rb_id_t rb_idP, - const logical_chan_id_t chan_idP);) // 2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC + const logical_chan_id_t chan_idP);) /*! \fn void config_req_rlc_am_asn1 (const protocol_ctxt_t* const ctxtP, const srb_flag_t srb_flagP, struct RLC_Config__am * config_amP, rb_id_t rb_idP, logical_chan_id_t chan_idP) * \brief Configure the UL and DL parameters of the RLC AM with the asn1c autogenerated pameters structs @@ -163,7 +163,7 @@ public_rlc_am(void config_req_rlc_am_asn1 ( const srb_flag_t srb_flagP, const struct RLC_Config__am * const config_amP, const rb_id_t rb_idP, - const logical_chan_id_t chan_idP);) // 2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC + const logical_chan_id_t chan_idP);) /** @} */ 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 5dcdbc68d1..1c82c1ff4b 100755 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c @@ -254,12 +254,10 @@ rlc_am_set_debug_infos( rlc_am_entity_t *const rlc_pP, const srb_flag_t srb_flagP, const rb_id_t rb_idP, - const logical_chan_id_t chan_idP) // 2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC) + const logical_chan_id_t chan_idP) { rlc_pP->rb_id = rb_idP; -#ifndef ASTRI_FIX // 2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC) rlc_pP->channel_id = chan_idP; -#endif if (srb_flagP) { rlc_pP->is_data_plane = 0; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h index f3e38b6bd2..342921bcc9 100755 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.h @@ -121,6 +121,6 @@ public_rlc_am_init( void rlc_am_configure(const protocol_ctxt_t* const ctxtP, * \param[in] rb_idP Radio bearer identifier. * \param[in] chan_idP Transport channel identifier. */ -public_rlc_am_init( void rlc_am_set_debug_infos(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, const srb_flag_t srb_flagP, const rb_id_t rb_idP, const logical_chan_id_t chan_idP /*2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC)*/);) +public_rlc_am_init( void rlc_am_set_debug_infos(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, const srb_flag_t srb_flagP, const rb_id_t rb_idP, const logical_chan_id_t chan_idP);) /** @} */ #endif diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c index 533730ce68..f89aa3b454 100755 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.c @@ -56,11 +56,7 @@ void config_req_rlc_tm ( rlc_tm_init(ctxt_pP, rlc_p); rlc_p->protocol_state = RLC_DATA_TRANSFER_READY_STATE; -#ifdef ASTRI_FIX - rlc_tm_set_debug_infos(ctxt_pP, rlc_p, srb_flagP, rb_idP); // 2016-05-27 wilson : fix incorrect argument ordering! -#else - rlc_tm_set_debug_infos(ctxt_pP, rlc_p, srb_flagP, rb_idP, chan_idP); // 2016-05-27 wilson : fix DRB-id <-> LC-id mapping -#endif + rlc_tm_set_debug_infos(ctxt_pP, rlc_p, srb_flagP, rb_idP, chan_idP); rlc_tm_configure(ctxt_pP, rlc_p, config_tmP->is_uplink_downlink); } else { LOG_E(RLC, PROTOCOL_RLC_TM_CTXT_FMT" CONFIG_REQ RB %u RLC NOT FOUND\n", @@ -157,7 +153,7 @@ void rlc_tm_set_debug_infos( rlc_tm_entity_t * const rlcP, const srb_flag_t srb_flagP, const rb_id_t rb_idP, - const logical_chan_id_t chan_idP) // 2016-05-27 wilson : fixing the DRB-id <-> LC-id mapping + const logical_chan_id_t chan_idP) { rlcP->rb_id = rb_idP; rlcP->channel_id = chan_idP; diff --git a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h index ecd23a2c2f..daf9b5a643 100755 --- a/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h +++ b/openair2/LAYER2/RLC/TM_v9.3.0/rlc_tm_init.h @@ -87,7 +87,7 @@ public_rlc_tm_init( void config_req_rlc_tm ( const srb_flag_t srb_flagP, const rlc_tm_info_t * const config_tmP, const rb_id_t rb_idP, - const logical_chan_id_t chan_idP);) // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping + const logical_chan_id_t chan_idP);) /*! \fn void rlc_tm_init (const protocol_ctxt_t* const ctxt_pP, rlc_tm_entity_t * const rlcP) * \brief Initialize a RLC TM protocol instance, initialize all variables, lists, allocate buffers for making this instance ready to be configured with protocol configuration parameters. After this initialization the RLC TM protocol instance will be in RLC_NULL_STATE state. @@ -135,7 +135,7 @@ protected_rlc_tm_init(void rlc_tm_set_debug_infos( rlc_tm_entity_t * const rlcP, const srb_flag_t srb_flagP, const rb_id_t rb_idP, - const logical_chan_id_t chan_idP);) /*2016-05-27 wilson : added this argument for storing the DRB-id <-> LC-id mapping in RLC)*/ + const logical_chan_id_t chan_idP);) /** @} */ # endif diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c index 990399c940..1ecf5f882a 100755 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.c @@ -427,14 +427,14 @@ void rlc_um_set_debug_infos( rlc_um_entity_t * const rlc_pP, const srb_flag_t srb_flagP, const rb_id_t rb_idP, - const logical_chan_id_t chan_idP) // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping + const logical_chan_id_t chan_idP) { LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" [SET DEBUG INFOS] rb_id %d srb_flag %d\n", PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP), rb_idP, srb_flagP); rlc_pP->rb_id = rb_idP; - rlc_pP->channel_id = chan_idP; // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping + rlc_pP->channel_id = chan_idP; if (srb_flagP) { rlc_pP->is_data_plane = 0; diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.h index 18dd656024..af3934f662 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_control_primitives.h @@ -91,7 +91,7 @@ public_rlc_um_control_primitives( void config_req_rlc_um ( const srb_flag_t srb_flagP, const rlc_um_info_t * const config_umP, const rb_id_t rb_idP, - const logical_chan_id_t chan_idP);) // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping + const logical_chan_id_t chan_idP);) /*! \fn void config_req_rlc_um_asn1 ( * const protocol_ctxt_t* const ctxt_pP, @@ -122,7 +122,7 @@ public_rlc_um_control_primitives( void config_req_rlc_um_asn1 ( const UL_UM_RLC_t * const ul_rlc_pP, const DL_UM_RLC_t * const dl_rlc_pP, const rb_id_t rb_idP, - const logical_chan_id_t chan_idP);) // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping + const logical_chan_id_t chan_idP);) /*! \fn void rlc_um_init (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP) * \brief Initialize a RLC UM protocol instance, initialize all variables, lists, allocate buffers for making this instance ready to be configured with protocol configuration parameters. After this initialization the RLC UM protocol instance will be in RLC_NULL_STATE state. @@ -189,6 +189,6 @@ protected_rlc_um_control_primitives(void rlc_um_set_debug_infos( rlc_um_entity_t * const rlc_pP, const srb_flag_t srb_flagP, const rb_id_t rb_idP, - const logical_chan_id_t chan_idP);) // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping + const logical_chan_id_t chan_idP);) /** @} */ # endif diff --git a/openair2/LAYER2/RLC/rlc_mac.c b/openair2/LAYER2/RLC/rlc_mac.c index 2f347cd227..76dab9a6d3 100644 --- a/openair2/LAYER2/RLC/rlc_mac.c +++ b/openair2/LAYER2/RLC/rlc_mac.c @@ -136,7 +136,6 @@ tbs_size_t mac_rlc_data_req( { //----------------------------------------------------------------------------- struct mac_data_req data_request; - // rb_id_t rb_id = 0; // 2016-05-27 wilson : not needed after DRB-id <-> LC-id mapping fix rlc_mode_t rlc_mode = RLC_MODE_NONE; rlc_mbms_id_t *mbms_id_p = NULL; rlc_union_t *rlc_union_p = NULL; @@ -179,17 +178,7 @@ tbs_size_t mac_rlc_data_req( return (tbs_size_t)0; } } else { -#ifdef ASTRI_FIX // 2016-05-27 wilson : fixing the DRB-id <-> LC-id mapping - if (channel_idP > 2) { - rb_id = channel_idP - 2; - } else { - rb_id = channel_idP; - } - - key = RLC_COLL_KEY_VALUE(module_idP, rntiP, enb_flagP, rb_id, srb_flag); -#else key = RLC_COLL_KEY_LCID_VALUE(module_idP, rntiP, enb_flagP, channel_idP, srb_flag); -#endif } h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); @@ -248,7 +237,6 @@ void mac_rlc_data_ind ( crc_t *crcs_pP) { //----------------------------------------------------------------------------- - // rb_id_t rb_id = 0; // 2016-05-27 wilson : not needed after DRB-id <-> LC-id mapping fix rlc_mode_t rlc_mode = RLC_MODE_NONE; rlc_mbms_id_t *mbms_id_p = NULL; rlc_union_t *rlc_union_p = NULL; @@ -298,17 +286,7 @@ void mac_rlc_data_ind ( return; } } else { -#ifdef ASTRI_FIX // 2016-05-27 wilson : fixing the DRB-id <-> LC-id mapping - if (channel_idP > 2) { - rb_id = channel_idP - 2; - } else { - rb_id = channel_idP; - } - - key = RLC_COLL_KEY_VALUE(module_idP, rntiP, enb_flagP, rb_id, srb_flag); -#else key = RLC_COLL_KEY_LCID_VALUE(module_idP, rntiP, enb_flagP, channel_idP, srb_flag); -#endif } h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); @@ -358,7 +336,6 @@ mac_rlc_status_resp_t mac_rlc_status_ind( mac_rlc_status_resp_t mac_rlc_status_resp; struct mac_status_ind tx_status; struct mac_status_resp status_resp; - // rb_id_t rb_id = 0; // 2016-05-27 wilson : not needed after DRB-id <-> LC-id mapping fix rlc_mode_t rlc_mode = RLC_MODE_NONE; rlc_mbms_id_t *mbms_id_p = NULL; rlc_union_t *rlc_union_p = NULL; @@ -407,17 +384,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind( key = RLC_COLL_KEY_MBMS_VALUE(module_idP, rntiP, enb_flagP, mbms_id_p->service_id, mbms_id_p->session_id); } else { -#ifdef ASTRI_FIX // 2016-05-27 wilson : fixing the DRB-id <-> LC-id mapping - if (channel_idP > 2) { - rb_id = channel_idP - 2; - } else { - rb_id = channel_idP; - } - - key = RLC_COLL_KEY_VALUE(module_idP, rntiP, enb_flagP, rb_id, srb_flag); -#else key = RLC_COLL_KEY_LCID_VALUE(module_idP, rntiP, enb_flagP, channel_idP, srb_flag); -#endif } h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); diff --git a/openair2/LAYER2/RLC/rlc_rrc.c b/openair2/LAYER2/RLC/rlc_rrc.c index aba2ab411f..c6ef4a1c5d 100644 --- a/openair2/LAYER2/RLC/rlc_rrc.c +++ b/openair2/LAYER2/RLC/rlc_rrc.c @@ -104,11 +104,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP if (srb2add_listP != NULL) { for (cnt=0; cntlist.count; cnt++) { rb_id = srb2add_listP->list.array[cnt]->srb_Identity; -#if 0 - lc_id = rb_id + 2; -#else // 2016-05-26 wilson : fixing the LC-id<->SRB-id mapping for SRB lc_id = rb_id; -#endif LOG_D(RLC, "Adding SRB %d, rb_id %d\n",srb2add_listP->list.array[cnt]->srb_Identity,rb_id); srb_toaddmod_p = srb2add_listP->list.array[cnt]; @@ -236,9 +232,6 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP drb_toaddmod_p = drb2add_listP->list.array[cnt]; drb_id = drb_toaddmod_p->drb_Identity; -#if 0 - lc_id = drb_id + 2; -#else // 2016-05-26 wilson : fixing the LC-id <-> DRB-id mapping if (drb_toaddmod_p->logicalChannelIdentity) { lc_id = *drb_toaddmod_p->logicalChannelIdentity; } else { @@ -251,9 +244,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP continue; } -#endif - - LOG_I(RLC, "Adding DRB %d, lc_id %d\n",drb_id,lc_id); + LOG_D(RLC, "Adding DRB %d, lc_id %d\n",drb_id,lc_id); if (drb_toaddmod_p->rlc_Config) { @@ -478,10 +469,8 @@ rlc_op_status_t rrc_rlc_remove_rlc ( logical_chan_id_t lcid = 0; hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; -#ifndef ASTRI_FIX // 2016-05-27 wilson : fixing DRB-id <-> LC-id mapping hash_key_t key_lcid = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_lcid_rc; -#endif rlc_union_t *rlc_union_p = NULL; #ifdef Rel10 rlc_mbms_id_t *mbms_id_p = NULL; @@ -525,7 +514,6 @@ rlc_op_status_t rrc_rlc_remove_rlc ( h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); if (h_rc == HASH_TABLE_OK) { -#ifndef ASTRI_FIX // 2016-05-27 wilson : fixing the DRB-id <-> LC-id mapping // also remove the hash-key created by LC-id switch (rlc_union_p->mode) { case RLC_MODE_AM: @@ -551,7 +539,6 @@ rlc_op_status_t rrc_rlc_remove_rlc ( if ((h_rc == HASH_TABLE_OK) && (h_lcid_rc == HASH_TABLE_OK)) { h_lcid_rc = hashtable_remove(rlc_coll_p, key_lcid); -#endif h_rc = hashtable_remove(rlc_coll_p, key); LOG_D(RLC, PROTOCOL_CTXT_FMT"[%s %u LCID %d] RELEASED %s\n", PROTOCOL_CTXT_ARGS(ctxt_pP), @@ -587,10 +574,8 @@ rlc_union_t* rrc_rlc_add_rlc ( //----------------------------------------------------------------------------- hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_rc; -#if 1 // 2016-05-26 wilson hash_key to the same RLC entity but indexed by LC_id instead of RB_id hash_key_t key_lcid = HASHTABLE_NOT_A_KEY_VALUE; hashtable_rc_t h_lcid_rc; -#endif rlc_union_t *rlc_union_p = NULL; #ifdef Rel10 rlc_mbms_id_t *mbms_id_p = NULL; @@ -631,9 +616,7 @@ rlc_union_t* rrc_rlc_add_rlc ( #endif { key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); -#ifndef ASTRI_FIX // 2016-05-26 wilson : fix DRB-id <-> LC-id mapping key_lcid = RLC_COLL_KEY_LCID_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, chan_idP, srb_flagP); -#endif } h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); @@ -649,9 +632,7 @@ rlc_union_t* rrc_rlc_add_rlc ( } else if (h_rc == HASH_TABLE_KEY_NOT_EXISTS) { rlc_union_p = calloc(1, sizeof(rlc_union_t)); h_rc = hashtable_insert(rlc_coll_p, key, rlc_union_p); -#ifndef ASTRI_FIX // 2016-05-26 wilson h_lcid_rc = hashtable_insert(rlc_coll_p, key_lcid, rlc_union_p); -#endif if ((h_rc == HASH_TABLE_OK) && (h_lcid_rc == HASH_TABLE_OK)) { #ifdef Rel10 diff --git a/openair2/RRC/LITE/defs.h b/openair2/RRC/LITE/defs.h index 1a39020a84..04d1fcc9f5 100644 --- a/openair2/RRC/LITE/defs.h +++ b/openair2/RRC/LITE/defs.h @@ -506,9 +506,7 @@ typedef struct UE_RRC_INST_s { struct SRB_ToAddMod *SRB1_config[NB_CNX_UE]; struct SRB_ToAddMod *SRB2_config[NB_CNX_UE]; struct DRB_ToAddMod *DRB_config[NB_CNX_UE][8]; -#ifndef ASTRI_FIX - rb_id_t *defaultDRB; // 2015-05-27 wilson : remember the default DRB ID -#endif + rb_id_t *defaultDRB; // remember the ID of the default DRB MeasObjectToAddMod_t *MeasObj[NB_CNX_UE][MAX_MEAS_OBJ]; struct ReportConfigToAddMod *ReportConfig[NB_CNX_UE][MAX_MEAS_CONFIG]; struct QuantityConfig *QuantityConfig[NB_CNX_UE]; diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index cd1389fbc0..b51b00241f 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -1201,7 +1201,6 @@ rrc_ue_process_radioResourceConfigDedicated( // Establish DRBs if present if (radioResourceConfigDedicated->drb_ToAddModList) { -#ifndef ASTRI_FIX // 2016-05-28 wilson : remember the default DRB ID if ( (UE_rrc_inst[ctxt_pP->module_id].defaultDRB == NULL) && (radioResourceConfigDedicated->drb_ToAddModList->list.count >= 1) ) { // configure the first DRB ID as the default DRB ID @@ -1210,8 +1209,6 @@ rrc_ue_process_radioResourceConfigDedicated( LOG_I(RRC,"[UE %d] default DRB = %d\n",ctxt_pP->module_id, *UE_rrc_inst[ctxt_pP->module_id].defaultDRB); } -#endif - uint8_t *kUPenc = NULL; #if defined(ENABLE_SECURITY) From 1de77c7a4e4c792b51c86954a77be03366b361bf Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Fri, 29 Jul 2016 17:01:00 +0800 Subject: [PATCH 231/413] changed so USRP also uses the piece of codes EXMIMO is uing in setting TA=624 when it is TDD (cherry picked from commit a75dbc4156ed4e216145f1deb81c6e04c1cddf02) --- targets/RT/USER/lte-softmodem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index ee4344cd2d..59b2604ec5 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -3163,7 +3163,7 @@ int main( int argc, char **argv ) UE[CC_id]->tx_power_max_dBm = tx_max_power[CC_id]; -#ifdef EXMIMO +#if defined(EXMIMO) || defined(OAI_USRP) // 2016-04-27 wilson also set TDD N_TA_offset with USRP //N_TA_offset if (UE[CC_id]->lte_frame_parms.frame_type == TDD) { if (UE[CC_id]->lte_frame_parms.N_RB_DL == 100) From 95077bae4f88c83bd828c8c5be71f75cf67fdbd3 Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Mon, 19 Sep 2016 12:01:16 +0800 Subject: [PATCH 232/413] removed words 'wilson' from src --- targets/RT/USER/lte-softmodem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 59b2604ec5..28d7620810 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -3163,7 +3163,7 @@ int main( int argc, char **argv ) UE[CC_id]->tx_power_max_dBm = tx_max_power[CC_id]; -#if defined(EXMIMO) || defined(OAI_USRP) // 2016-04-27 wilson also set TDD N_TA_offset with USRP +#if defined(EXMIMO) || defined(OAI_USRP) //N_TA_offset if (UE[CC_id]->lte_frame_parms.frame_type == TDD) { if (UE[CC_id]->lte_frame_parms.N_RB_DL == 100) From 754cab7ec44631db4bc194829e0880e1954c2b1b Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Mon, 19 Sep 2016 15:08:50 +0800 Subject: [PATCH 233/413] added SFN to wireshark logging output Conflicts: openair2/LAYER2/MAC/eNB_scheduler_ulsch.c openair2/LAYER2/MAC/ue_procedures.c --- openair2/LAYER2/MAC/eNB_scheduler_RA.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_bch.c | 1 + openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_mch.c | 2 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 2 +- openair2/LAYER2/MAC/ra_procedures.c | 4 ++-- openair2/LAYER2/MAC/rar_tools.c | 2 +- openair2/LAYER2/MAC/ue_procedures.c | 7 ++++--- openair2/UTIL/OPT/opt.h | 2 +- openair2/UTIL/OPT/probe.c | 14 +++++++------- 10 files changed, 20 insertions(+), 18 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c index c3a2aea0a5..7022333439 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c @@ -651,7 +651,7 @@ void schedule_RA(module_id_t module_idP,frame_t frameP, sub_frame_t subframeP,un if (opt_enabled==1) { trace_pdu(1, (uint8_t *)eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0], rrc_sdu_length, UE_id, 3, UE_RNTI(module_idP, UE_id), - eNB->subframe,0,0); + eNB->frame, eNB->subframe,0,0); LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d trace pdu for rnti %x with size %d\n", module_idP, CC_id, frameP, UE_RNTI(module_idP,UE_id), rrc_sdu_length); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_bch.c b/openair2/LAYER2/MAC/eNB_scheduler_bch.c index f3774777a1..f4586ff9e8 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_bch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_bch.c @@ -319,6 +319,7 @@ schedule_SI( 0xffff, 4, 0xffff, + eNB->frame, eNB->subframe, 0, 0); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 61a0357691..fb8d4f3354 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -1122,7 +1122,7 @@ schedule_ue_spec( if (opt_enabled == 1) { trace_pdu(1, (uint8_t *)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS, module_idP, 3, UE_RNTI(module_idP,UE_id), - eNB->subframe,0,0); + eNB->frame, eNB->subframe,0,0); LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", module_idP, CC_id, frameP, UE_RNTI(module_idP,UE_id), TBS); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_mch.c b/openair2/LAYER2/MAC/eNB_scheduler_mch.c index a6926e15ad..42189d0df2 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_mch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_mch.c @@ -629,7 +629,7 @@ int schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_fra if (opt_enabled ==1 ) { trace_pdu(1, (uint8_t *)eNB_mac_inst[module_idP].common_channels[CC_id].MCH_pdu.payload, TBS, module_idP, 6, 0xffff, // M_RNTI = 6 in wirehsark - eNB_mac_inst[module_idP].subframe,0,0); + eNB_mac_inst[module_idP].frame, eNB_mac_inst[module_idP].subframe,0,0); LOG_D(OPT,"[eNB %d][MCH] CC_id %d Frame %d : MAC PDU with size %d\n", module_idP, CC_id, frameP, TBS); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index f0ad4ee3ee..a5395c2f7c 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -101,7 +101,7 @@ void rx_sdu(const module_id_t enb_mod_idP, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_SDU,1); if (opt_enabled == 1) { - trace_pdu(0, sduP,sdu_lenP, 0, 3, rntiP,subframeP, 0,0); + trace_pdu(0, sduP,sdu_lenP, 0, 3, rntiP, frameP, subframeP, 0,0); LOG_D(OPT,"[eNB %d][ULSCH] Frame %d rnti %x with size %d\n", enb_mod_idP, frameP, rntiP, sdu_lenP); } diff --git a/openair2/LAYER2/MAC/ra_procedures.c b/openair2/LAYER2/MAC/ra_procedures.c index 669077bf4f..61289e0d36 100644 --- a/openair2/LAYER2/MAC/ra_procedures.c +++ b/openair2/LAYER2/MAC/ra_procedures.c @@ -280,7 +280,7 @@ void Msg1_tx(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id if (opt_enabled) { trace_pdu(0, NULL, 0, module_idP, 2, UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex, - UE_mac_inst[module_idP].subframe, 0, UE_mac_inst[module_idP].RA_attempt_number); + UE_mac_inst[module_idP].frame, UE_mac_inst[module_idP].subframe, 0, UE_mac_inst[module_idP].RA_attempt_number); LOG_D(OPT,"[UE %d][RAPROC] TX MSG1 Frame %d trace pdu for rnti %x with size %d\n", module_idP, frameP, 1, UE_mac_inst[module_idP].RA_Msg3_size); } @@ -304,7 +304,7 @@ void Msg3_tx(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id if (opt_enabled) { // msg3 trace_pdu(0, &UE_mac_inst[module_idP].CCCH_pdu.payload[0], UE_mac_inst[module_idP].RA_Msg3_size, - module_idP, 3, UE_mac_inst[module_idP].crnti, UE_mac_inst[module_idP].subframe, 0, 0); + module_idP, 3, UE_mac_inst[module_idP].crnti, UE_mac_inst[module_idP].frame, UE_mac_inst[module_idP].subframe, 0, 0); LOG_D(OPT,"[UE %d][RAPROC] MSG3 Frame %d trace pdu Preamble %d with size %d\n", module_idP, frameP, UE_mac_inst[module_idP].crnti /*UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex*/, UE_mac_inst[module_idP].RA_Msg3_size); } diff --git a/openair2/LAYER2/MAC/rar_tools.c b/openair2/LAYER2/MAC/rar_tools.c index be8dc43c97..c31b50eab6 100644 --- a/openair2/LAYER2/MAC/rar_tools.c +++ b/openair2/LAYER2/MAC/rar_tools.c @@ -126,7 +126,7 @@ unsigned short fill_rar( if (opt_enabled) { trace_pdu(1, dlsch_buffer, input_buffer_length, module_idP, 2, 1, - eNB_mac_inst[module_idP].subframe, 0, 0); + eNB_mac_inst[module_idP].frame, eNB_mac_inst[module_idP].subframe, 0, 0); LOG_D(OPT,"[eNB %d][RAPROC] CC_id %d RAR Frame %d trace pdu for rnti %x and rapid %d size %d\n", module_idP, CC_id, frameP, eNB_mac_inst[module_idP].common_channels[CC_id].RA_template[ra_idx].rnti, rarh->RAPID, input_buffer_length); diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 90d227eb35..41415f2e1a 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -321,7 +321,7 @@ ue_send_sdu(module_id_t module_idP, if (opt_enabled) { trace_pdu(1, sdu, sdu_len, module_idP, 3, UE_mac_inst[module_idP].crnti, - UE_mac_inst[module_idP].subframe, 0, 0); + UE_mac_inst[module_idP].frame, UE_mac_inst[module_idP].subframe, 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); } @@ -499,6 +499,7 @@ void ue_decode_si(module_id_t module_idP,int CC_id,frame_t frameP, uint8_t eNB_i module_idP, 4, 0xffff, + UE_mac_inst[module_idP].frame, UE_mac_inst[module_idP].subframe, 0, 0); @@ -1498,9 +1499,9 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf stop_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu); if (opt_enabled) { - trace_pdu(0, ulsch_buffer, buflen, module_idP, 3, UE_mac_inst[module_idP].crnti, UE_mac_inst[module_idP].subframe, 0, 0); + trace_pdu(0, ulsch_buffer, buflen, module_idP, 3, UE_mac_inst[module_idP].crnti, UE_mac_inst[module_idP].frame, UE_mac_inst[module_idP].subframe, 0, 0); LOG_D(OPT,"[UE %d][ULSCH] Frame %d trace pdu for rnti %x with size %d\n", - module_idP, UE_mac_inst[module_idP].subframe, UE_mac_inst[module_idP].crnti, buflen); + module_idP, UE_mac_inst[module_idP].frame, UE_mac_inst[module_idP].subframe, UE_mac_inst[module_idP].crnti, buflen); } } diff --git a/openair2/UTIL/OPT/opt.h b/openair2/UTIL/OPT/opt.h index bb3a099e12..8d2464641c 100644 --- a/openair2/UTIL/OPT/opt.h +++ b/openair2/UTIL/OPT/opt.h @@ -85,7 +85,7 @@ extern char in_path[100]; */ void trace_pdu(int direction, uint8_t *pdu_buffer, unsigned int pdu_buffer_size, - int ueid, int rntiType, int rnti, uint8_t subframe, + int ueid, int rntiType, int rnti, uint16_t sysFrame, uint8_t subframe, int oob_event, int oob_event_value); int init_opt(char *path, char *ip, char *port, radio_type_t radio_type_p); diff --git a/openair2/UTIL/OPT/probe.c b/openair2/UTIL/OPT/probe.c index eef98ae729..059a55a319 100644 --- a/openair2/UTIL/OPT/probe.c +++ b/openair2/UTIL/OPT/probe.c @@ -260,7 +260,7 @@ int opt_create_listener_socket(char *ip_address, uint16_t port) */ /* Add framing header to MAC PDU and send. */ static void SendFrame(guint8 radioType, guint8 direction, guint8 rntiType, - guint16 rnti, guint16 ueid, guint16 subframeNumber, + guint16 rnti, guint16 ueid, guint16 sfnSf, guint8 isPredefinedData, guint8 retx, guint8 crcStatus, guint8 oob_event, guint8 oob_event_value, uint8_t *pdu_buffer, unsigned int pdu_buffer_size) @@ -308,7 +308,7 @@ static void SendFrame(guint8 radioType, guint8 direction, guint8 rntiType, /* Subframe number */ frameBuffer[frameOffset++] = MAC_LTE_SUBFRAME_TAG; - tmp16 = htons(subframeNumber); // frame counter : this will give an expert info as wireshark expects SF and not F + tmp16 = htons(sfnSf); // frame counter : this will give an expert info as wireshark expects SF and not F memcpy(frameBuffer+frameOffset, &tmp16, 2); frameOffset += 2; @@ -317,7 +317,7 @@ static void SendFrame(guint8 radioType, guint8 direction, guint8 rntiType, #ifdef WIRESHARK_DEV frameOffset += 2; - tmp16 = htons(subframeNumber); // subframe + tmp16 = htons(sfnSf); // subframe memcpy(frameBuffer+frameOffset, &tmp16, 2); frameOffset += 2; #endif @@ -458,7 +458,7 @@ static int MAC_LTE_PCAP_WritePDU(MAC_Context_Info_t *context, /* Remote serveraddress (where Wireshark is running) */ void trace_pdu(int direction, uint8_t *pdu_buffer, unsigned int pdu_buffer_size, - int ueid, int rntiType, int rnti, uint8_t subframe, int oob_event, + int ueid, int rntiType, int rnti, uint16_t sysFrameNumber, uint8_t subFrameNumber, int oob_event, int oob_event_value) { MAC_Context_Info_t pdu_context; @@ -471,7 +471,7 @@ void trace_pdu(int direction, uint8_t *pdu_buffer, unsigned int pdu_buffer_size, SendFrame(radio_type, (direction == DIRECTION_DOWNLINK) ? DIRECTION_DOWNLINK : DIRECTION_UPLINK, - rntiType, rnti, ueid, subframe, + rntiType, rnti, ueid, (sysFrameNumber<<4) + subFrameNumber, 1, 0, 1, //guint8 isPredefinedData, guint8 retx, guint8 crcStatus oob_event,oob_event_value, pdu_buffer, pdu_buffer_size); @@ -490,8 +490,8 @@ void trace_pdu(int direction, uint8_t *pdu_buffer, unsigned int pdu_buffer_size, pdu_context.ueid = ueid; pdu_context.isRetx = 0; pdu_context.crcStatusOK =1; - pdu_context.sysFrameNumber = subframe; - pdu_context.subFrameNumber = 0; + pdu_context.sysFrameNumber = sysFrameNumber; + pdu_context.subFrameNumber = subFrameNumber; pdu_context.subframesSinceCaptureStart = subframesSinceCaptureStart++; MAC_LTE_PCAP_WritePDU( &pdu_context, pdu_buffer, pdu_buffer_size); break; From 8ce73e5a7e16de89bfe78976434cbc7b3012edfa Mon Sep 17 00:00:00 2001 From: calvin wang Date: Tue, 27 Sep 2016 17:08:17 +0800 Subject: [PATCH 234/413] L2 stabilization BSR fertilization --- openair2/LAYER2/MAC/config.c | 23 +++ openair2/LAYER2/MAC/defs.h | 8 + openair2/LAYER2/MAC/extern.h | 2 + openair2/LAYER2/MAC/proto.h | 6 +- openair2/LAYER2/MAC/ue_procedures.c | 219 +++++++++++++++++++--------- openair2/LAYER2/MAC/vars.h | 9 ++ 6 files changed, 198 insertions(+), 69 deletions(-) diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 2c5a0799d2..030ac7a9f3 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -76,6 +76,7 @@ void ue_mac_reset(module_id_t module_idP,uint8_t eNB_index) // cancel all pending SRs UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; + UE_mac_inst[module_idP].BSR_reporting_active=0; // stop ongoing RACH procedure @@ -235,10 +236,31 @@ rrc_mac_config_req( UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = (uint16_t) 0; } + if (mac_MainConfig->ext2 && mac_MainConfig->ext2->mac_MainConfig_v1020) { + if (mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10) { + UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t) *mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10; + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t)0; + } + if (mac_MainConfig->ext2->mac_MainConfig_v1020->extendedPHR_r10) { + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t) *mac_MainConfig->ext2->mac_MainConfig_v1020->extendedPHR_r10; + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t)0; + } + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t)0; + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t)0; + } #endif UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer); UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer); + UE_mac_inst[Mod_idP].BSR_reporting_active = 0; + LOG_D(MAC,"[UE %d]: periodic BSR %d (SF), retx BSR %d (SF)\n", + Mod_idP, + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF, + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF); + UE_mac_inst[Mod_idP].scheduling_info.drx_config = mac_MainConfig->drx_Config; UE_mac_inst[Mod_idP].scheduling_info.phr_config = mac_MainConfig->phr_Config; @@ -259,6 +281,7 @@ rrc_mac_config_req( UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer); UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer); UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[Mod_idP].scheduling_info.PathlossChange); + UE_mac_inst[Mod_idP].PHR_reporting_active = 0; LOG_D(MAC,"[UE %d] config PHR (%d): periodic %d (SF) prohibit %d (SF) pathlosschange %d (db) \n", Mod_idP, (mac_MainConfig->phr_Config)?mac_MainConfig->phr_Config->present:-1, diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 713c9d967c..4edfef1677 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -983,6 +983,12 @@ typedef struct { int16_t prohibitPHR_SF; ///DL Pathloss Change in db uint16_t PathlossChange_db; + + /// default value is false + uint16_t extendedBSR_Sizes_r10; + /// default value is false + uint16_t extendedPHR_r10; + //Bj bucket usage per lcid int16_t Bj[MAX_NUM_LCID]; // Bucket size per lcid @@ -1070,6 +1076,8 @@ typedef struct { uint8_t PHR_reporting_active; /// power backoff due to power management (as allowed by P-MPRc) for this cell uint8_t power_backoff_db[NUMBER_OF_eNB_MAX]; + /// BSR report falg management + uint8_t BSR_reporting_active; /// MBSFN_Subframe Configuration struct MBSFN_SubframeConfig *mbsfn_SubframeConfig[8]; // FIXME replace 8 by MAX_MBSFN_AREA? /// number of subframe allocation pattern available for MBSFN sync area diff --git a/openair2/LAYER2/MAC/extern.h b/openair2/LAYER2/MAC/extern.h index ca847acf4c..bb37a3766f 100644 --- a/openair2/LAYER2/MAC/extern.h +++ b/openair2/LAYER2/MAC/extern.h @@ -53,6 +53,8 @@ extern const uint32_t BSR_TABLE[BSR_TABLE_SIZE]; //extern uint32_t EBSR_Level[63]; +extern const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE]; +//extern uint32_t Extended_BSR_TABLE[63]; ----currently not used extern UE_MAC_INST *UE_mac_inst; extern eNB_MAC_INST *eNB_mac_inst; diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 9a0f60167d..4133d6a2eb 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -548,7 +548,7 @@ int cba_access(module_id_t module_idP,frame_t frameP,sub_frame_t subframe, uint8 \param[in] Mod_id instance of the UE \param[out] lcgid */ -int get_bsr_lcgid (module_id_t module_idP); +int get_bsr_lcgid (module_id_t module_idP, int *num_lcgid); /*! \fn uint8_t get_bsr_len (module_id_t module_idP,uint16_t bufflen); \brief determine whether the bsr is short or long assuming that the MAC pdu is built @@ -582,14 +582,14 @@ BSR_LONG * get_bsr_long(module_id_t module_idP, uint8_t bsr_len); */ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_index, uint8_t lcid, uint8_t lcgid); -/*! \fn locate (int *table, int size, int value) +/*! \fn locate_BsrIndexByBufferSize (int *table, int size, int value) \brief locate the BSR level in the table as defined in 36.321. This function requires that he values in table to be monotonic, either increasing or decreasing. The returned value is not less than 0, nor greater than n-1, where n is the size of table. \param[in] *table Pointer to BSR table \param[in] size Size of the table \param[in] value Value of the buffer \return the index in the BSR_LEVEL table */ -uint8_t locate (const uint32_t *table, int size, int value); +uint8_t locate_BsrIndexByBufferSize (const uint32_t *table, int size, int value); /*! \fn int get_sf_periodicBSRTimer(uint8_t periodicBSR_Timer) diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 90d227eb35..6fc95f55d5 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -110,13 +110,17 @@ void ue_init_mac(module_id_t module_idP) UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer_Running=0; UE_mac_inst[module_idP].scheduling_info.maxHARQ_Tx=MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; UE_mac_inst[module_idP].scheduling_info.ttiBundling=0; + UE_mac_inst[module_idP].scheduling_info.extendedBSR_Sizes_r10=0; + UE_mac_inst[module_idP].scheduling_info.extendedPHR_r10=0; UE_mac_inst[module_idP].scheduling_info.drx_config=NULL; UE_mac_inst[module_idP].scheduling_info.phr_config=NULL; UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); + UE_mac_inst[module_idP].BSR_reporting_active = 0; UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer); UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer); UE_mac_inst[module_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[module_idP].scheduling_info.PathlossChange); + UE_mac_inst[module_idP].PHR_reporting_active = 0; for (i=0; i < MAX_NUM_LCID; i++) { LOG_D(MAC,"[UE%d] Applying default logical channel config for LCGID %d\n",module_idP,i); @@ -296,18 +300,28 @@ uint32_t ue_get_SR(module_id_t module_idP,int CC_id,frame_t frameP,uint8_t eNB_i // initiate RA UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; + // release all pucch resource + UE_mac_inst[module_idP].physicalConfigDedicated = NULL; + UE_mac_inst[module_idP].ul_active=0; + UE_mac_inst[module_idP].BSR_reporting_active=0; + + LOG_T(MAC,"[UE %d] Release all SRs \n", module_idP); return(0); } } //------------------------------------------------------------------------------ void -ue_send_sdu(module_id_t module_idP, - uint8_t CC_id, - frame_t frameP, - uint8_t* sdu, - uint16_t sdu_len, - uint8_t eNB_index) { +ue_send_sdu( + module_id_t module_idP, + uint8_t CC_id, + frame_t frameP, + uint8_t* sdu, + uint16_t sdu_len, + uint8_t eNB_index +) +//------------------------------------------------------------------------------ +{ unsigned char rx_ces[MAX_NUM_CE],num_ce,num_sdu,i,*payload_ptr; unsigned char rx_lcids[NB_RB_MAX]; @@ -1188,17 +1202,20 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf uint8_t payload_offset=0,num_sdus=0; uint8_t ulsch_buff[MAX_ULSCH_PAYLOAD_BYTES]; uint16_t sdu_length_total=0; - BSR_SHORT bsr_short; + BSR_SHORT bsr_short,bsr_truncated; BSR_LONG bsr_long; BSR_SHORT *bsr_s=&bsr_short; + BSR_SHORT *bsr_t=&bsr_truncated; BSR_LONG *bsr_l=&bsr_long; POWER_HEADROOM_CMD phr; POWER_HEADROOM_CMD *phr_p=&phr; - unsigned short short_padding=0, post_padding=0; + unsigned short short_padding=0, post_padding=0, padding_len=0; int lcgid; int j; // used for padding // Compute header length - + int all_pdu_len; + int num_lcgid=0; + if (CC_id>0) { LOG_E(MAC,"Transmission on secondary CCs is not supported yet\n"); mac_xface->macphy_exit("MAC FATAL CC_id>0"); @@ -1243,8 +1260,8 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf } bsr_ce_len = get_bsr_len (module_idP, buflen-phr_len); - - if (bsr_ce_len > 0 ) { + // retxBSR-Timer expires or periodicBSR-Timer expires and UE has data available for transmission + if ((bsr_ce_len > 0 ) && (UE_mac_inst[module_idP].BSR_reporting_active > 0)) { bsr_len = bsr_ce_len + bsr_header_len; LOG_D(MAC,"[UE %d] header size info: dcch %d, dcch1 %d, dtch %d, bsr (ce%d,hdr%d) buff_len %d\n", module_idP, dcch_header_len,dcch1_header_len,dtch_header_len, bsr_ce_len, bsr_header_len, buflen); @@ -1338,8 +1355,9 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len+=3; dtch_header_len_last=3; + all_pdu_len = bsr_len+phr_len+dcch_header_len+dcch1_header_len+dtch_header_len+sdu_length_total; if ((UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) && - ((bsr_len+phr_len+dcch_header_len+dcch1_header_len+dtch_header_len+sdu_length_total) <= buflen)) { + (all_pdu_len <= buflen)) { // optimize the dtch header lenght //if ((UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DTCH] > 128) && @@ -1357,7 +1375,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf ENB_FLAG_NO, MBMS_FLAG_NO, // eNB_index lcid, - buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total); + buflen-all_pdu_len); LOG_D(MAC,"[UE %d] Frame %d : UL-DTCH -> ULSCH%d, %d bytes to send (Transport Block size %d, mac header len %d, BSR byte[%d] %d)\n", module_idP,frameP, lcid, rlc_status.bytes_in_buffer,buflen,dtch_header_len, @@ -1390,31 +1408,54 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len -= 3; } } - - lcgid= get_bsr_lcgid(module_idP); - if (lcgid < 0 ) { + lcgid= get_bsr_lcgid(module_idP, &num_lcgid); + + if (num_lcgid == 0 ) { bsr_s = NULL; - bsr_l = NULL ; - } else if ((lcgid ==MAX_NUM_LCGID) && (bsr_ce_len == sizeof(BSR_LONG))) { - bsr_s = NULL; - bsr_l->Buffer_size0 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]; - bsr_l->Buffer_size1 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]; - bsr_l->Buffer_size2 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]; - bsr_l->Buffer_size3 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]; - LOG_D(MAC, "[UE %d] Frame %d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP, - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2], - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]); - } else if (bsr_ce_len == sizeof(BSR_SHORT)) { + bsr_t = NULL; bsr_l = NULL; - bsr_s->LCGID = lcgid; - bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]; - LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n", + } else if (num_lcgid == 1){ + if (bsr_ce_len == sizeof(BSR_SHORT)){ + bsr_l = NULL; + bsr_t = NULL; + bsr_s->LCGID = lcgid; + bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]; + LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n", + module_idP, frameP, UE_mac_inst[module_idP].scheduling_info.BSR[lcgid],lcgid); + } else { + bsr_s = NULL; + bsr_t = NULL; + bsr_l = NULL; + } + } else if (num_lcgid > 1) { + if (bsr_ce_len == sizeof(BSR_LONG)){ + bsr_t = NULL; + bsr_s = NULL; + bsr_l->Buffer_size0 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]; + bsr_l->Buffer_size1 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]; + bsr_l->Buffer_size2 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]; + bsr_l->Buffer_size3 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]; + LOG_D(MAC, "[UE %d] Frame %d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP, + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2], + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]); + } else if (bsr_ce_len == sizeof(BSR_SHORT)){ + bsr_l = NULL; + bsr_s = NULL; + bsr_t->LCGID = lcgid; + bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]; + LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n", module_idP, frameP, UE_mac_inst[module_idP].scheduling_info.BSR[lcgid],lcgid); + } else { + bsr_s = NULL; + bsr_t = NULL; + bsr_l = NULL; + } } else { bsr_s = NULL; + bsr_t = NULL; bsr_l = NULL; } @@ -1444,12 +1485,14 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len_last-=1; dtch_header_len= (dtch_header_len >0)? dtch_header_len - dtch_header_len_last : dtch_header_len; } - - if ((buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total) <= 2) { - short_padding = buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total; + // 1-bit padding or 2-bit padding special padding subheader + padding_len = buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total; + if (padding_len <= 2) { + short_padding = padding_len; + // only add padding header post_padding = 0; } else { - if ((buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total) == buflen) { + if (padding_len == buflen) {// nona mac pdu *access_mode=CANCELED_ACCESS; } @@ -1474,7 +1517,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf sdu_lcids, // sdu lcid phr_p, // power headroom NULL, // crnti - NULL, // truncated bsr + bsr_t, // truncated bsr bsr_s, // short bsr bsr_l, post_padding); // long_bsr @@ -1494,6 +1537,9 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf module_idP,payload_offset, sdu_length_total); UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; + UE_mac_inst[module_idP].BSR_reporting_active=0; + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_OUT); stop_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu); @@ -1655,7 +1701,22 @@ ue_scheduler( // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures // outlined in Sections 5.4.4 an 5.4.5 of 36.321 - // Put this in another function + // Call BSR procedure as described in Section 5.4.5 in 36.321 + if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF == get_sf_periodicBSRTimer(MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity)) { + UE_mac_inst[module_idP].BSR_reporting_active = 1; + } else if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF <= 0 ){ + // trigger BSR and reset the timer later when the BSR report is sent + UE_mac_inst[module_idP].BSR_reporting_active = 1; + } else if (UE_mac_inst[module_idP].BSR_reporting_active == 0 ) { + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF--; + } + + if (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF <= 0){ + // trigger BSR and reset the timer later when the BSR report is sent + UE_mac_inst[module_idP].BSR_reporting_active = 1; + } else if (UE_mac_inst[module_idP].BSR_reporting_active == 0 ) { + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF--; + } // Get RLC status info and update Bj for all lcids that are active for (lcid=DCCH; lcid <= DTCH; lcid++ ) { @@ -1899,54 +1960,75 @@ int cba_access(module_id_t module_idP,frame_t frameP,sub_frame_t subframe, uint8 } #endif -int get_bsr_lcgid (module_id_t module_idP) +int get_bsr_lcgid (module_id_t module_idP, int *num_lcgid) { int lcgid, lcgid_tmp=-1; int num_active_lcgid = 0; for (lcgid = 0 ; lcgid < MAX_NUM_LCGID; lcgid++) { if (UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] > 0 ) { - lcgid_tmp = lcgid; + if (lcgid_tmp == -1){ + // first priority lcgid + lcgid_tmp = lcgid; + } num_active_lcgid+=1; } } - + *num_lcgid = num_active_lcgid; + if (num_active_lcgid == 0) { - return -1; - } else if (num_active_lcgid == 1) { - return lcgid_tmp; + return -1; // no data } else { - return MAX_NUM_LCGID; + return lcgid_tmp;//only one lcgid, report short bsr } } uint8_t get_bsr_len (module_id_t module_idP, uint16_t buflen) { - int lcgid=0; uint8_t bsr_len=0, num_lcgid=0; int pdu = 0; + int long_bsr_plus_subheader_length = sizeof(BSR_LONG)+sizeof(SCH_SUBHEADER_FIXED); + int short_bsr_plus_subheader_length = sizeof(BSR_SHORT)+sizeof(SCH_SUBHEADER_FIXED); - + // check how many lcg have data to report for (lcgid=0; lcgid < MAX_NUM_LCGID; lcgid++ ) { if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 0 ) { - pdu += (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] + bsr_len + 2); //2 = sizeof(SCH_SUBHEADER_SHORT) + num_lcgid ++; + pdu += (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] + sizeof(SCH_SUBHEADER_SHORT)); } - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 128 ) { // long header size: adjust the header size pdu += 1; } - - // current phy buff can not transport all sdu for this lcgid -> transmit a bsr for this lcgid - - if ( (pdu > buflen) && (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 0 ) ) { - num_lcgid +=1; - bsr_len = (num_lcgid >= 2 ) ? sizeof(BSR_LONG) : sizeof(BSR_SHORT) ; + LOG_D(MAC,"BSR Bytes %d for lcgid %d num lcgid %d\n", UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid], lcgid, num_lcgid); + } + // current phy buff can not transport all sdu for this lcgid -> transmit a bsr for this lcgid + if (buflen < pdu) { + if (num_lcgid > 0) { + bsr_len = sizeof(BSR_SHORT); + } else { + bsr_len = 0; } - - LOG_D(MAC,"BSR Bytes %d for lcgid %d bsr len %d num lcgid %d\n", UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid], lcgid, bsr_len, num_lcgid); + } + // padding larger then long bsr + if (buflen > (pdu + long_bsr_plus_subheader_length)) { + if (num_lcgid > 1) { + bsr_len = sizeof(BSR_LONG); + } else if (num_lcgid > 0) { + bsr_len = sizeof(BSR_SHORT); + } else { + bsr_len = 0; + } + } + // padding larger then short bsr and shorter then long bsr + if ((buflen < (pdu + long_bsr_plus_subheader_length)) && + (buflen > (pdu + short_bsr_plus_subheader_length))) { + if (num_lcgid > 0) { + bsr_len = sizeof(BSR_SHORT); + } else { + bsr_len = 0; + } } - if ( bsr_len > 0 ) LOG_D(MAC,"[UE %d] Prepare a %s (Transport Block Size %d, MAC pdu Size %d) \n", module_idP, map_int_to_str(BSR_names, bsr_len), buflen, pdu); @@ -1959,11 +2041,11 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in { mac_rlc_status_resp_t rlc_status; - boolean_t sr_pending = FALSE; + boolean_t Bsr_pending = FALSE; if ((lcg_id < 0) || (lcg_id >= MAX_NUM_LCGID) ) { - return sr_pending; + return Bsr_pending; } // fixme: need a better way to reset @@ -1979,10 +2061,15 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in 0); if (rlc_status.bytes_in_buffer > 0 ) { - sr_pending = TRUE; + //BSR trigger SR + Bsr_pending = TRUE; UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_NOT_EMPTY; - UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] += locate (BSR_TABLE,BSR_TABLE_SIZE, rlc_status.bytes_in_buffer); - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id] += rlc_status.bytes_in_buffer; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id] = rlc_status.bytes_in_buffer; + if (UE_mac_inst[module_idP].scheduling_info.extendedBSR_Sizes_r10 == TRUE){ + UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = locate_BsrIndexByBufferSize(Extended_BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); + } else { + UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); + } // UE_mac_inst[module_idP].scheduling_info.BSR_short_lcid = lcid; // only applicable to short bsr LOG_D(MAC,"[UE %d] BSR level %d (LCGID %d, rlc buffer %d byte)\n", module_idP, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id],lcg_id, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); @@ -1992,10 +2079,10 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in } //} - return sr_pending; + return Bsr_pending; } -uint8_t locate (const uint32_t *table, int size, int value) +uint8_t locate_BsrIndexByBufferSize (const uint32_t *table, int size, int value) { uint8_t ju, jm, jl; @@ -2026,7 +2113,7 @@ uint8_t locate (const uint32_t *table, int size, int value) if (value == table[jl]) { return jl; - } else { + } else { return jl+1; //equally ju } diff --git a/openair2/LAYER2/MAC/vars.h b/openair2/LAYER2/MAC/vars.h index 508c7f8c21..3020706815 100644 --- a/openair2/LAYER2/MAC/vars.h +++ b/openair2/LAYER2/MAC/vars.h @@ -52,6 +52,15 @@ const uint32_t BSR_TABLE[BSR_TABLE_SIZE]= {0,10,12,14,17,19,22,26,31,36,42,49,57 1326,1552,1817,2127,2490,2915,3413,3995,4677,5467,6411,7505,8787,10287,12043,14099, 16507,19325,22624,26487,31009,36304,42502,49759,58255,68201,79846,93479,109439, 128125,150000, 300000 }; +// extended bsr table--currently not used +const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE] = {0,10,13,16,19,23,29,35,43,53,65,80,98,120,147, + 181,223,274,337,414,509,625,769,945,1162,1429, + 1757,2161,2657,3267,4017,4940,6074,7469,9185, + 11294,13888,17077,20999,25822,31752,39045,48012, + 59039,72598,89272,109774,134986,165989,204111, + 250990,308634,379519,466683,573866,705666,867737, + 1067031,1312097,1613447,1984009,2439678,3000000, + 6000000}; //uint32_t EBSR_Level[63]={0,10,13,16,19,23,29,35,43,53,65,80,98,120,147,181}; From a5210e4f4f9160730edc2b84c40a5f502de4db74 Mon Sep 17 00:00:00 2001 From: fnabet Date: Wed, 28 Sep 2016 17:36:07 +0200 Subject: [PATCH 235/413] UE L2 changes for 3GPP alignement --- openair2/LAYER2/MAC/ue_procedures.c | 31 ++++++++++++++++++- .../LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c | 3 +- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 90d227eb35..4547adabac 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -151,7 +151,7 @@ unsigned char *parse_header(unsigned char *mac_header, unsigned short tb_length) { - unsigned char not_done=1,num_ces=0,num_sdus=0,lcid, num_sdu_cnt; + unsigned char not_done=1,num_ces=0,num_cont_res = 0,num_padding = 0,num_sdus=0,lcid, num_sdu_cnt; unsigned char *mac_header_ptr = mac_header; unsigned short length,ce_len=0; @@ -165,6 +165,14 @@ unsigned char *parse_header(unsigned char *mac_header, lcid = ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID; if (lcid < UE_CONT_RES) { + //FNA: Contention Resolution check according to Annex B of 36.321 + // if this is for CCCH then a Contention Resolution must have been parsed before + if ((lcid == 0) && (num_cont_res == 0)) { + LOG_W(MAC,"[UE] Msg4 Wrong received format: CCCH received without Contention Resolution before\n"); + // exit parsing + return NULL; + } + //printf("[MAC][UE] header %x.%x.%x\n",mac_header_ptr[0],mac_header_ptr[1],mac_header_ptr[2]); if (not_done==0) {// last MAC SDU, length is implicit mac_header_ptr++; @@ -196,6 +204,7 @@ unsigned char *parse_header(unsigned char *mac_header, num_sdus++; } else { // This is a control element subheader if (lcid == SHORT_PADDING) { + num_padding ++; mac_header_ptr++; } else { rx_ces[num_ces] = lcid; @@ -205,6 +214,23 @@ unsigned char *parse_header(unsigned char *mac_header, if (lcid==TIMING_ADV_CMD) { ce_len++; } else if (lcid==UE_CONT_RES) { + + // FNA: check MAC Header is one of thoses defined in Annex B of 36.321 + // Check there is only 1 Contention Resolution + if (num_cont_res) { + LOG_W(MAC,"[UE] Msg4 Wrong received format: More than 1 Contention Resolution\n"); + // exit parsing + return NULL; + + } + + // UE_CONT_RES shall never be the last subheader unless this is the only MAC subheader + if ((not_done == 0) && ((num_sdus) || (num_ces > 1) || (num_padding))) { + LOG_W(MAC,"[UE] Msg4 Wrong received format: Contention Resolution after num_ces=%d num_sdus=%d num_padding=%d\n",num_ces,num_sdus,num_padding); + // exit parsing + return NULL; + } + num_cont_res ++; ce_len+=6; } } @@ -343,6 +369,8 @@ ue_send_sdu(module_id_t module_idP, LOG_T(MAC,"\n"); #endif + if (payload_ptr != NULL) { + for (i=0; it_reordering.running) { - if ((rlc_pP->vr_x == rlc_pP->vr_r) || ((rlc_am_in_rx_window(ctxt_pP, rlc_pP, pdu_info_p->sn) == 0) && (rlc_pP->vr_x != rlc_pP->vr_mr))) { + 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))) { rlc_am_stop_and_reset_timer_reordering(ctxt_pP, rlc_pP); } } From 82e54108e9845cb1eb38d9a959e9a04237c104d6 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Mon, 3 Oct 2016 02:44:47 +0200 Subject: [PATCH 236/413] add hotfix to add usrp ud-host package --- cmake_targets/tools/build_helper | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 0f87ce1ad3..7e0ea5ce35 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -233,7 +233,7 @@ check_install_usrp_uhd_driver(){ $SUDO add-apt-repository ppa:ettusresearch/uhd -y $SUDO apt-get update $SUDO apt-get -y install python python-tk libboost-all-dev libusb-1.0-0-dev - $SUDO apt-get -y install libuhd-dev libuhd003 + $SUDO apt-get -y install libuhd-dev libuhd003 uhd-host } install_usrp_uhd_driver() { From b11ed995d258dd65877849947c0b08390019649e Mon Sep 17 00:00:00 2001 From: fnabet Date: Mon, 10 Oct 2016 16:22:01 +0200 Subject: [PATCH 237/413] fix build issue after merge from develop --- openair2/LAYER2/MAC/ue_procedures.c | 1 + openair2/LAYER2/RLC/rlc_rrc.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index f06582c857..4bc613ffbe 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -564,6 +564,7 @@ void ue_decode_p(module_id_t module_idP,int CC_id,frame_t frameP, uint8_t eNB_in module_idP, 4, P_RNTI, + UE_mac_inst[module_idP].frame, UE_mac_inst[module_idP].subframe, 0, 0); diff --git a/openair2/LAYER2/RLC/rlc_rrc.c b/openair2/LAYER2/RLC/rlc_rrc.c index ae091651a8..9ed5c4672e 100644 --- a/openair2/LAYER2/RLC/rlc_rrc.c +++ b/openair2/LAYER2/RLC/rlc_rrc.c @@ -216,7 +216,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP ctxt_pP, SRB_FLAG_YES, &srb_toaddmod_p->rlc_Config->choice.explicitValue.choice.am, - rb_id); + rb_id,lc_id); } else { LOG_E(RLC, PROTOCOL_CTXT_FMT" ERROR IN ALLOCATING SRB %d \n", PROTOCOL_CTXT_ARGS(ctxt_pP), From b0887a1b85ed4c23c5ff5809abde80446dd0b7bb Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 10 Oct 2016 16:33:12 +0200 Subject: [PATCH 238/413] issue 137 - correct computation of G G was wrongly computed in some places, not taking into account CQI and RI bits. This commit saves the correct value computed in ulsch_decoding so we can reuse it in ulsch_decoding_data (and the like). Only the file openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c has been checked. If the computation is done somewhere else the problem might still exist. --- openair1/PHY/LTE_TRANSPORT/defs.h | 2 ++ openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/defs.h b/openair1/PHY/LTE_TRANSPORT/defs.h index 26e2d40460..0cd98f98a9 100644 --- a/openair1/PHY/LTE_TRANSPORT/defs.h +++ b/openair1/PHY/LTE_TRANSPORT/defs.h @@ -374,6 +374,8 @@ typedef struct { uint32_t TBS; /// The payload + CRC size in bits uint32_t B; + /// Number of soft channel bits + uint32_t G; /// CQI CRC status uint8_t cqi_crc_status; /// Pointer to CQI data diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index afcce70b7f..45117a64c2 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -236,7 +236,7 @@ int ulsch_decoding_data_2thread0(td_params* tdp) { LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; int Q_m = get_Qm_ul(ulsch_harq->mcs); - int G = ulsch_harq->nb_rb * (12 * Q_m) * ulsch_harq->Nsymb_pusch; + int G = ulsch_harq->G; uint32_t E; uint32_t Gp,GpmodC,Nl=1; uint32_t C = ulsch_harq->C; @@ -458,7 +458,7 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; int Q_m = get_Qm_ul(ulsch_harq->mcs); - int G = ulsch_harq->nb_rb * (12 * Q_m) * ulsch_harq->Nsymb_pusch; + int G = ulsch_harq->G; unsigned int E; int Cby2; @@ -666,7 +666,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; int Q_m = get_Qm_ul(ulsch_harq->mcs); - int G = ulsch_harq->nb_rb * (12 * Q_m) * ulsch_harq->Nsymb_pusch; + int G = ulsch_harq->G; unsigned int E; uint8_t (*tc)(int16_t *y, @@ -1044,6 +1044,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, #endif G = G - Q_RI - Q_CQI; + ulsch_harq->G = G; if ((int)G < 0) { LOG_E(PHY,"FATAL: ulsch_decoding.c G < 0 (%d) : Q_RI %d, Q_CQI %d\n",G,Q_RI,Q_CQI); From 190fc96af4fb5663134e7318a47e1893d4f1184c Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 10 Oct 2016 16:36:52 +0200 Subject: [PATCH 239/413] issue 137 - fix RI bits decoding RI bits are present only in some transmission modes. For aperiodic reporting (the mode we do as of today), 36.213 7.2.1 (release 10) says: "RI is only reported for transmission modes 3 and 4, as well as transmission modes 8 and 9 with PMI/RI reporting" This commit activates decoding of RI bits only for transmission modes 3 and 4. 8 and 9 are not done today (as far as I know). --- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 2f578d9cc1..8f4bc4d45f 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -7213,7 +7213,17 @@ int generate_eNB_ulsch_params_from_dci(PHY_VARS_eNB *eNB, if (cqi_req == 1) { - ulsch->harq_processes[harq_pid]->O_RI = 1; //we only support 2 antenna ports, so this is always 1 according to 3GPP 36.213 Table + /* 36.213 7.2.1 (release 10) says: + * "RI is only reported for transmission modes 3 and 4, + * as well as transmission modes 8 and 9 with PMI/RI reporting" + * This is for aperiodic reporting. + * TODO: deal with TM 8&9 correctly when they are implemented. + * TODO: deal with periodic reporting if we implement it. + */ + if (transmission_mode == 3 || transmission_mode == 4) + ulsch->harq_processes[harq_pid]->O_RI = 1; //we only support 2 antenna ports, so this is always 1 according to 3GPP 36.213 Table + else + ulsch->harq_processes[harq_pid]->O_RI = 0; switch(transmission_mode) { // The aperiodic CQI reporting mode is fixed for every transmission mode instead of being configured by higher layer signaling From 5894f3e6c213cf71b90bb18f9964f8dccf67ecb4 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 10 Oct 2016 16:40:42 +0200 Subject: [PATCH 240/413] issue 137 - remove hack: MCS reduction in case of CQI reporting This hack was probably put in place in an attempt to circumvent problems solved by previous commits. As far as I checked (with my knowledge of the day) we can't exhaust uplink physical bits with ULSCH data bits when there is CQI reporting at the same time. To be refined if this idea is proved wrong. --- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index aa3b5554e2..b6395fe191 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -838,9 +838,6 @@ void schedule_ulsch_rnti(module_id_t module_idP, UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power=target_rx_power; UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=UE_template->pre_assigned_mcs_ul; mcs = UE_template->pre_assigned_mcs_ul;//cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS - if ((cqi_req==1) && (mcs>19)) { - mcs=19; - } if (UE_template->pre_allocated_rb_table_index_ul >=0) { rb_table_index=UE_template->pre_allocated_rb_table_index_ul; } else { From 138ed2fbb429efc465ed9136a80cf3a79780ce5c Mon Sep 17 00:00:00 2001 From: fnabet Date: Mon, 10 Oct 2016 17:16:01 +0200 Subject: [PATCH 241/413] [OAI-UE] fixes: 1- frame/subframe update 2- ccch discard regression --- openair2/LAYER2/MAC/ue_procedures.c | 8 -------- targets/RT/USER/lte-ue.c | 9 +++++++-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 4bc613ffbe..448d2ed541 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -165,14 +165,6 @@ unsigned char *parse_header(unsigned char *mac_header, lcid = ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID; if (lcid < UE_CONT_RES) { - //FNA: Contention Resolution check according to Annex B of 36.321 - // if this is for CCCH then a Contention Resolution must have been parsed before - if ((lcid == 0) && (num_cont_res == 0)) { - LOG_W(MAC,"[UE] Msg4 Wrong received format: CCCH received without Contention Resolution before\n"); - // exit parsing - return NULL; - } - //printf("[MAC][UE] header %x.%x.%x\n",mac_header_ptr[0],mac_header_ptr[1],mac_header_ptr[2]); if (not_done==0) {// last MAC SDU, length is implicit mac_header_ptr++; diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 1c338c3df0..81d60a3d08 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -1035,8 +1035,8 @@ void *UE_thread(void *arg) { }// start_rx_stream==0 else { - UE->proc.proc_rxtx[0].frame_rx++; - UE->proc.proc_rxtx[1].frame_rx++; + //UE->proc.proc_rxtx[0].frame_rx++; + //UE->proc.proc_rxtx[1].frame_rx++; for (int sf=0;sf<10;sf++) { for (i=0; iframe_parms.nb_antennas_rx; i++) @@ -1122,6 +1122,11 @@ void *UE_thread(void *arg) { } // increment instance count and change proc subframe/frame variables int instance_cnt_rxtx = ++proc->instance_cnt_rxtx; + if(sf == 0) + { + UE->proc.proc_rxtx[0].frame_rx++; + UE->proc.proc_rxtx[1].frame_rx++; + } proc->subframe_rx=sf; proc->subframe_tx=(sf+4)%10; proc->frame_tx = proc->frame_rx + ((proc->subframe_rx>5)?1:0); From 8dcf0f0cfd183849b8828bebd70b31bbae6c35ba Mon Sep 17 00:00:00 2001 From: Dominique Nussbaum Date: Wed, 12 Oct 2016 10:17:07 +0200 Subject: [PATCH 242/413] option -a is now handled correctly at UE --- targets/RT/USER/lte-ue.c | 201 ++++++++++++--------------------------- 1 file changed, 63 insertions(+), 138 deletions(-) diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 0e834a53ab..4089796d61 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -203,7 +203,7 @@ static void *UE_thread_synch(void *arg) int current_band = 0; int current_offset = 0; sync_mode_t sync_mode = pbch; - int card; + int CC_id; int ind; int found; int freq_offset=0; @@ -302,9 +302,9 @@ static void *UE_thread_synch(void *arg) printf( "Scanning band %d, dl_min %"PRIu32", ul_min %"PRIu32"\n", current_band, eutra_bands[ind].dl_min,eutra_bands[ind].ul_min); if ((eutra_bands[ind].dl_min <= downlink_frequency[0][0]) && (eutra_bands[ind].dl_max >= downlink_frequency[0][0])) { - for (card=0; cardUE_scan == 1) { current_band=0; - for (card=0; cardrx_total_gain_dB;//-USRP_GAIN_OFFSET; + openair0_cfg[rf_map[CC_id].card].rx_gain[i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET; -#if 0 // UHD 3.8 - switch(UE->lte_frame_parms.N_RB_DL) { - case 6: - openair0_cfg[card].rx_gain[i] -= 12; - break; - - case 25: - openair0_cfg[card].rx_gain[i] -= 6; - break; - - case 50: - openair0_cfg[card].rx_gain[i] -= 3; - break; - - case 100: - openair0_cfg[card].rx_gain[i] -= 0; - break; - - default: - printf( "Unknown number of RBs %d\n", UE->lte_frame_parms.N_RB_DL ); - break; - } -#endif printf( "UE synch: setting RX gain (%d,%d) to %f\n", card, i, openair0_cfg[card].rx_gain[i] ); #endif } @@ -414,52 +392,24 @@ static void *UE_thread_synch(void *arg) oai_exit=1; } - for (card=0; cardrx_total_gain_dB;//-USRP_GAIN_OFFSET; // 65 calibrated for USRP B210 @ 2.6 GHz - -#if 0 // UHD 3.8 - switch(UE->lte_frame_parms.N_RB_DL) { - case 6: - openair0_cfg[card].rx_gain[i] -= 12; - break; - - case 25: - openair0_cfg[card].rx_gain[i] -= 6; - break; - - case 50: - openair0_cfg[card].rx_gain[i] -= 3; - break; - - case 100: - openair0_cfg[card].rx_gain[i] -= 0; - break; - - default: - printf("Unknown number of RBs %d\n",UE->lte_frame_parms.N_RB_DL); - break; - } -#endif - + openair0_cfg[rf_map[CC_id].card].rx_gain[rf_map[CC_id].chain+i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET; // 65 calibrated for USRP B210 @ 2.6 GHz printf("UE synch: setting RX gain (%d,%d) to %f\n",card,i,openair0_cfg[card].rx_gain[i]); #endif - } + if (UE->UE_scan_carrier) { + openair0_cfg[rf_map[CC_id].card].autocal[rf_map[CC_id].chain+i] = 1; + } - } - - if (UE->UE_scan_carrier) { - - for (i=0;iUE_scan_carrier = 0; // rerun with new cell parameters and frequency-offset - for (i=0;irx_total_gain_dB;//-USRP_GAIN_OFFSET; - openair0_cfg[0].rx_freq[i] -= UE->lte_ue_common_vars.freq_offset; - openair0_cfg[0].tx_freq[i] = openair0_cfg[0].rx_freq[i]+uplink_frequency_offset[0][i]; - downlink_frequency[0][i] = openair0_cfg[0].rx_freq[i]; - freq_offset=0; - } + for (CC_id=0; CC_idrx_total_gain_dB;//-USRP_GAIN_OFFSET; + openair0_cfg[rf_map[CC_id].card].rx_freq[rf_map[CC_id].chain+i] -= UE->lte_ue_common_vars.freq_offset; + openair0_cfg[rf_map[CC_id].card].tx_freq[rf_map[CC_id].chain+i] = openair0_cfg[rf_map[CC_id].card].rx_freq[rf_map[CC_id].chain+i]+uplink_frequency_offset[CC_id][i]; + downlink_frequency[CC_id][i] = openair0_cfg[CC_id].rx_freq[i]; + freq_offset=0; + } // reconfigure for potentially different bandwidth switch(UE->lte_frame_parms.N_RB_DL) { case 6: - openair0_cfg[0].sample_rate =1.92e6; - openair0_cfg[0].rx_bw =.96e6; - openair0_cfg[0].tx_bw =.96e6; + openair0_cfg[rf_map[CC_id].card].sample_rate =1.92e6; + openair0_cfg[rf_map[CC_id].card].rx_bw =.96e6; + openair0_cfg[rf_map[CC_id].card].tx_bw =.96e6; // openair0_cfg[0].rx_gain[0] -= 12; break; case 25: - openair0_cfg[0].sample_rate =7.68e6; - openair0_cfg[0].rx_bw =2.5e6; - openair0_cfg[0].tx_bw =2.5e6; + openair0_cfg[rf_map[CC_id].card].sample_rate =7.68e6; + openair0_cfg[rf_map[CC_id].card].rx_bw =2.5e6; + openair0_cfg[rf_map[CC_id].card].tx_bw =2.5e6; // openair0_cfg[0].rx_gain[0] -= 6; break; case 50: - openair0_cfg[0].sample_rate =15.36e6; - openair0_cfg[0].rx_bw =5.0e6; - openair0_cfg[0].tx_bw =5.0e6; + openair0_cfg[rf_map[CC_id].card].sample_rate =15.36e6; + openair0_cfg[rf_map[CC_id].card].rx_bw =5.0e6; + openair0_cfg[rf_map[CC_id].card].tx_bw =5.0e6; // openair0_cfg[0].rx_gain[0] -= 3; break; case 100: - openair0_cfg[0].sample_rate=30.72e6; - openair0_cfg[0].rx_bw=10.0e6; - openair0_cfg[0].tx_bw=10.0e6; + openair0_cfg[rf_map[CC_id].card].sample_rate=30.72e6; + openair0_cfg[rf_map[CC_id].card].rx_bw=10.0e6; + openair0_cfg[rf_map[CC_id].card].tx_bw=10.0e6; // openair0_cfg[0].rx_gain[0] -= 0; break; } + } #ifndef EXMIMO openair0.trx_set_freq_func(&openair0,&openair0_cfg[0],0); //openair0.trx_set_gains_func(&openair0,&openair0_cfg[0]); @@ -594,53 +546,26 @@ static void *UE_thread_synch(void *arg) downlink_frequency[0][0]+freq_offset, downlink_frequency[0][0]+uplink_frequency_offset[0][0]+freq_offset ); - for (card=0; cardrx_total_gain_dB;//-USRP_GAIN_OFFSET; - - -#if 0 - switch(UE->lte_frame_parms.N_RB_DL) { - case 6: - openair0_cfg[card].rx_gain[i] -= 12; - break; - - case 25: - openair0_cfg[card].rx_gain[i] -= 6; - break; - - case 50: - openair0_cfg[card].rx_gain[i] -= 0;//3; - break; - - case 100: - openair0_cfg[card].rx_gain[i] -= 0; - break; - - default: - printf("Unknown number of RBs %d\n",UE->lte_frame_parms.N_RB_DL); - break; - } -#endif + openair0_cfg[rf_map[CC_id].card].rx_gain[rf_map[CC_id].chain+i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET; #endif + if (UE->UE_scan_carrier==1) { + openair0_cfg[rf_map[CC_id].card].autocal[rf_map[CC_id].chain+i] = 1; + } } } - if (UE->UE_scan_carrier==1) { - for (i=0;i Date: Wed, 12 Oct 2016 14:29:48 +0200 Subject: [PATCH 243/413] [OAI-UE] SRS feature 1- Implement SRS procedures --- cmake_targets/CMakeLists.txt | 1 + openair1/PHY/INIT/lte_init.c | 41 +++ openair1/PHY/LTE_TRANSPORT/defs.h | 2 + openair1/PHY/extern.h | 12 + openair1/PHY/impl_defs_lte.h | 4 + openair1/SCHED/Makefile.inc | 1 + openair1/SCHED/defs.h | 9 + openair1/SCHED/phy_procedures_lte_ue.c | 243 +++++++++++++++++- openair1/SCHED/srs_pc.c | 99 +++++++ openair2/RRC/LITE/MESSAGES/asn1_msg.c | 18 +- openair2/RRC/LITE/rrc_eNB.c | 2 +- ...band7.tm1.generic.oaisim.local_no_mme.conf | 10 +- targets/SIMU/USER/oaisim_functions.c | 4 +- 13 files changed, 421 insertions(+), 25 deletions(-) create mode 100644 openair1/SCHED/srs_pc.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 5e86d59378..d47389e7b4 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -931,6 +931,7 @@ set(SCHED_SRC ${OPENAIR1_DIR}/SCHED/phy_mac_stub.c ${OPENAIR1_DIR}/SCHED/pucch_pc.c ${OPENAIR1_DIR}/SCHED/pusch_pc.c + ${OPENAIR1_DIR}/SCHED/srs_pc.c ) add_library(SCHED_LIB ${SCHED_SRC}) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index a2e4fa8747..d358329b63 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -489,6 +489,26 @@ void phy_config_dedicated_eNB_step2(PHY_VARS_eNB *eNB) } + if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated) { + if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated->present == SchedulingRequestConfig_PR_setup) { + + eNB->soundingrs_ul_config_dedicated[UE_id].duration = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.duration; + eNB->soundingrs_ul_config_dedicated[UE_id].cyclicShift = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift; + eNB->soundingrs_ul_config_dedicated[UE_id].freqDomainPosition = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition; + eNB->soundingrs_ul_config_dedicated[UE_id].srs_Bandwidth = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth; + eNB->soundingrs_ul_config_dedicated[UE_id].srs_ConfigIndex = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex; + eNB->soundingrs_ul_config_dedicated[UE_id].srs_HoppingBandwidth = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth; + eNB->soundingrs_ul_config_dedicated[UE_id].transmissionComb = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb; + + + LOG_D(PHY,"soundingrs_ul_config_dedicated.srs_ConfigIndex %d\n",eNB->soundingrs_ul_config_dedicated[UE_id].srs_ConfigIndex); + + } + + LOG_D(PHY,"------------------------------------------------------------\n"); + + } + eNB->physicalConfigDedicated[UE_id] = NULL; } } @@ -859,6 +879,27 @@ void phy_config_dedicated_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, } + if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated) { + + if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated->present == SchedulingRequestConfig_PR_setup) { + + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].duration = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.duration; + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].cyclicShift = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift; + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].freqDomainPosition = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition; + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srs_Bandwidth = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth; + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srs_ConfigIndex = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex; + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srs_HoppingBandwidth = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth; + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].transmissionComb = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb; + + + LOG_D(PHY,"soundingrs_ul_config_dedicated.srs_ConfigIndex %d\n",phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srs_ConfigIndex); + } + + LOG_D(PHY,"------------------------------------------------------------\n"); + + } + + #ifdef CBA if (physicalConfigDedicated->pusch_CBAConfigDedicated_vlola) { diff --git a/openair1/PHY/LTE_TRANSPORT/defs.h b/openair1/PHY/LTE_TRANSPORT/defs.h index 26e2d40460..be6cd4f5a0 100644 --- a/openair1/PHY/LTE_TRANSPORT/defs.h +++ b/openair1/PHY/LTE_TRANSPORT/defs.h @@ -341,6 +341,8 @@ typedef struct { int16_t Po_PUSCH; /// PHR - current power headroom (based on last PUSCH transmission) int16_t PHR; + /// Po_SRS - target output power for SRS + int16_t Po_SRS; /// num active cba group uint8_t num_active_cba_groups; /// num dci found for cba diff --git a/openair1/PHY/extern.h b/openair1/PHY/extern.h index 867f980e5f..2ce2d03ff5 100755 --- a/openair1/PHY/extern.h +++ b/openair1/PHY/extern.h @@ -118,5 +118,17 @@ extern char eNB_timing[2][20]; extern int16_t unscrambling_lut[65536*16]; extern uint8_t scrambling_lut[65536*16]; +extern unsigned short msrsb_6_40[8][4]; +extern unsigned short msrsb_41_60[8][4]; +extern unsigned short msrsb_61_80[8][4]; +extern unsigned short msrsb_81_110[8][4]; +extern unsigned short Nb_6_40[8][4]; +extern unsigned short Nb_41_60[8][4]; +extern unsigned short Nb_61_80[8][4]; +extern unsigned short Nb_81_110[8][4]; + +extern uint16_t hundred_times_log10_NPRB[100]; +extern uint8_t alpha_lut[8]; + #endif /*__PHY_EXTERN_H__ */ diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h index bed2057800..6813fe058f 100644 --- a/openair1/PHY/impl_defs_lte.h +++ b/openair1/PHY/impl_defs_lte.h @@ -319,6 +319,10 @@ typedef struct { uint16_t srs_ConfigIndex; /// Parameter: \f$n^\text{CS}_\text{SRS}\f$. See TS 36.211 (5.5.3.1). \vr{[0..7]} \note the specification sais it is an enumerated value. uint8_t cyclicShift; + // Parameter: cell srs subframe for internal implementation + uint8_t srsCellSubframe; + // Parameter: ue srs subframe for internal implementation + uint8_t srsUeSubframe; } SOUNDINGRS_UL_CONFIG_DEDICATED; /// UplinkPowerControlDedicated Information Element from 36.331 RRC spec diff --git a/openair1/SCHED/Makefile.inc b/openair1/SCHED/Makefile.inc index e3fd877e5d..559d3dca32 100644 --- a/openair1/SCHED/Makefile.inc +++ b/openair1/SCHED/Makefile.inc @@ -3,3 +3,4 @@ SCHED_OBJS += $(TOP_DIR)/SCHED/phy_procedures_lte_ue.o SCHED_OBJS += $(TOP_DIR)/SCHED/phy_procedures_lte_eNb.o SCHED_OBJS += $(TOP_DIR)/SCHED/pusch_pc.o SCHED_OBJS += $(TOP_DIR)/SCHED/pucch_pc.o +SCHED_OBJS += $(TOP_DIR)/SCHED/srs_pc.o diff --git a/openair1/SCHED/defs.h b/openair1/SCHED/defs.h index f9ebd3b3b0..10a0cf6e4b 100644 --- a/openair1/SCHED/defs.h +++ b/openair1/SCHED/defs.h @@ -444,6 +444,15 @@ int8_t pucch_power_cntl(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t subframe,ui */ void pusch_power_cntl(PHY_VARS_UE *phy_vars_ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t j, uint8_t abstraction_flag); +/*! \brief This function implements the power control mechanism for SRS from 36.213. + @param phy_vars_ue PHY variables + @param proc Pointer to proc descriptor + @param eNB_id Index of eNB + @param j index of type of PUSCH (SPS, Normal, Msg3) + @returns Transmit power + */ +void srs_power_cntl(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t *pnb_rb_srs, uint8_t abstraction_flag); + int8_t get_PHR(uint8_t Mod_id, uint8_t CC_id, uint8_t eNB_index); #ifdef LOCALIZATION diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 5fa9f9f2f5..f15e4768c0 100755 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -205,6 +205,7 @@ unsigned int get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb_rb int gain_dB = power_dBm - power_max_dBm; double gain_lin; + LOG_I(PHY,"Get Tx Amp; Gain[dB]: %d, AMP: %d\n",gain_dB,AMP); if (gain_dB < -20) return(AMP/10); @@ -385,6 +386,180 @@ uint8_t is_SR_TXOp(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id) return(0); } +void compute_srs_pos(lte_frame_type_t frameType,uint16_t isrs,uint16_t *psrsPeriodicity,uint16_t *psrsOffset) +{ + if(TDD == frameType) + { + if(isrs<10) + { + mac_xface->macphy_exit("2 ms SRS periodicity not supported"); + } + + if((isrs>9)&&(isrs<15)) + { + *psrsPeriodicity=5; + *psrsOffset=isrs-10; + } + if((isrs>14)&&(isrs<25)) + { + *psrsPeriodicity=10; + *psrsOffset=isrs-15; + } + if((isrs>24)&&(isrs<45)) + { + *psrsPeriodicity=20; + *psrsOffset=isrs-25; + } + if((isrs>44)&&(isrs<85)) + { + *psrsPeriodicity=40; + *psrsOffset=isrs-45; + } + if((isrs>84)&&(isrs<165)) + { + *psrsPeriodicity=80; + *psrsOffset=isrs-85; + } + if((isrs>164)&&(isrs<325)) + { + *psrsPeriodicity=160; + *psrsOffset=isrs-165; + } + if((isrs>324)&&(isrs<645)) + { + *psrsPeriodicity=320; + *psrsOffset=isrs-325; + } + + if(isrs>644) + { + mac_xface->macphy_exit("Isrs out of range"); + } + + } + else + { + if(isrs<2) + { + *psrsPeriodicity=2; + *psrsOffset=isrs; + } + if((isrs>1)&&(isrs<7)) + { + *psrsPeriodicity=5; + *psrsOffset=isrs-2; + } + if((isrs>6)&&(isrs<17)) + { + *psrsPeriodicity=10; + *psrsOffset=isrs-7; + } + if((isrs>16)&&(isrs<37)) + { + *psrsPeriodicity=20; + *psrsOffset=isrs-17; + } + if((isrs>36)&&(isrs<77)) + { + *psrsPeriodicity=40; + *psrsOffset=isrs-37; + } + if((isrs>76)&&(isrs<157)) + { + *psrsPeriodicity=80; + *psrsOffset=isrs-77; + } + if((isrs>156)&&(isrs<317)) + { + *psrsPeriodicity=160; + *psrsOffset=isrs-157; + } + if((isrs>316)&&(isrs<637)) + { + *psrsPeriodicity=320; + *psrsOffset=isrs-317; + } + if(isrs>636) + { + mac_xface->macphy_exit("Isrs out of range"); + } + } +} + +void ue_compute_srs_occasion(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id) +{ + LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + int frame_tx = proc->frame_tx; + int subframe_tx = proc->subframe_tx; + uint8_t isSubframeSRS = 0; // SRS Cell Occasion + uint8_t isSubframeSRSTx = 0; // SRS UE Occasion + + SOUNDINGRS_UL_CONFIG_DEDICATED *pSoundingrs_ul_config_dedicated=&ue->soundingrs_ul_config_dedicated[eNB_id]; + + // check for SRS opportunity + pSoundingrs_ul_config_dedicated->srsUeSubframe = 0; + pSoundingrs_ul_config_dedicated->srsCellSubframe = 0; + if(frame_parms->soundingrs_ul_config_common.enabled_flag) + { + + LOG_D(PHY," SRS SUBFRAMECONFIG: %d, Isrs: %d \n", frame_parms->soundingrs_ul_config_common.srs_SubframeConfig, pSoundingrs_ul_config_dedicated->srs_ConfigIndex); + + uint8_t TSFC; + uint16_t deltaTSFC; // bitmap + uint8_t srs_SubframeConfig; + uint16_t srsPeriodicity; + uint16_t srsOffset; + + // table resuming TSFC (Period) and deltaSFC (offset) + const uint16_t deltaTSFCTabType1[15][2] = { {1,1},{1,2},{2,2},{1,5},{2,5},{4,5},{8,5},{3,5},{12,5},{1,10},{2,10},{4,10},{8,10},{351,10},{383,10} }; // Table 5.5.3.3-2 3GPP 36.211 FDD + const uint16_t deltaTSFCTabType2[14][2] = { {2,5},{6,5},{10,5},{18,5},{14,5},{22,5},{26,5},{30,5},{70,10},{74,10},{194,10},{326,10},{586,10},{210,10} }; // Table 5.5.3.3-2 3GPP 36.211 TDD + + srs_SubframeConfig = frame_parms->soundingrs_ul_config_common.srs_SubframeConfig; + if (FDD == frame_parms->frame_type) + { + // srs_SubframeConfig =< 14 + deltaTSFC = deltaTSFCTabType1[srs_SubframeConfig][0]; + TSFC = deltaTSFCTabType1[srs_SubframeConfig][1]; + } + else + { + // srs_SubframeConfig =< 13 + deltaTSFC = deltaTSFCTabType2[srs_SubframeConfig][0]; + TSFC = deltaTSFCTabType2[srs_SubframeConfig][1]; + } + + LOG_D(PHY," ISTDD: %d, TSFC: %d, deltaTSFC: %d, AbsSubframeTX: %d\n", frame_parms->frame_type, TSFC, deltaTSFC, (((int)frame_tx*10)+(int)subframe_tx)); + + // Sounding reference signal subframes are the subframes satisfying ns/2 mod TSFC (- deltaTSFC + uint16_t tmp = (subframe_tx % TSFC); + if((1<srsCellSubframe = 1; + } + + + compute_srs_pos(frame_parms->frame_type, pSoundingrs_ul_config_dedicated->srs_ConfigIndex, &srsPeriodicity, &srsOffset); + + // transmit SRS if the four following constraints are respected: + // - UE is configured to transmit SRS + // - SRS are configured in current subframe + // - UE is configured to send SRS in this subframe + // - CQI is not scheduled in PUCCH transmission - TO BE ADDED + // - simultaneous transmission of SRS and ACKNACK is authorised - TO BE CHECKED + if( isSubframeSRS && + (((10*frame_tx+subframe_tx) % srsPeriodicity) == srsOffset) + //(! is_pucch_per_cqi_report)) + ) + { + isSubframeSRSTx = 1; + pSoundingrs_ul_config_dedicated->srsUeSubframe = 1; + } + LOG_D(PHY," isSubframeSRS: %d, isSubframeSRSTx: %d \n", isSubframeSRS, isSubframeSRSTx); + } +} + uint16_t get_n1_pucch(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t eNB_id, @@ -1086,6 +1261,49 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB } // subframe_scheduling_flag==1 } +void ue_srs_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t abstraction_flag) +{ + + //LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + //int8_t frame_tx = proc->frame_tx; + int8_t subframe_tx = proc->subframe_tx; + int16_t tx_amp; + int16_t Po_SRS; + uint8_t nb_rb_srs; + + SOUNDINGRS_UL_CONFIG_DEDICATED *pSoundingrs_ul_config_dedicated=&ue->soundingrs_ul_config_dedicated[eNB_id]; + uint8_t isSrsTxOccasion = pSoundingrs_ul_config_dedicated->srsUeSubframe; + + if(isSrsTxOccasion) + { + ue->generate_ul_signal[eNB_id] = 1; + if (ue->mac_enabled==1) + { + srs_power_cntl(ue,proc,eNB_id, (uint8_t*)(&nb_rb_srs), abstraction_flag); + Po_SRS = ue->ulsch[eNB_id]->Po_SRS; + } + else + { + Po_SRS = ue->tx_power_max_dBm; + } + +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) + tx_amp = get_tx_amp(Po_SRS, + ue->tx_power_max_dBm, + ue->frame_parms.N_RB_UL, + nb_rb_srs); +#else + tx_amp = AMP; +#endif + LOG_I(PHY,"SRS PROC; TX_MAX_POWER %d, Po_SRS %d, NB_RB_UL %d, NB_RB_SRS %d TX_AMPL %d\n",ue->tx_power_max_dBm, + Po_SRS, + ue->frame_parms.N_RB_UL, + nb_rb_srs, + tx_amp); + + generate_srs_tx(ue, eNB_id, tx_amp, subframe_tx); + } +} void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t abstraction_flag) { @@ -1103,6 +1321,9 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin int tx_amp; int8_t Po_PUCCH; + SOUNDINGRS_UL_CONFIG_DEDICATED *pSoundingrs_ul_config_dedicated=&ue->soundingrs_ul_config_dedicated[eNB_id]; + uint8_t isShortenPucch = pSoundingrs_ul_config_dedicated->srsCellSubframe; + bundling_flag = ue->pucch_config_dedicated[eNB_id].tdd_AckNackFeedbackMode; if ((frame_parms->frame_type==FDD) || @@ -1175,19 +1396,21 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin #endif if (SR_payload>0) { - LOG_D(PHY,"[UE %d][SR %x] Frame %d subframe %d Generating PUCCH 1a/1b payload %d,%d (with SR for PUSCH), n1_pucch %d, Po_PUCCH, amp %d\n", + LOG_I(PHY,"[UE %d][SR %x] Frame %d subframe %d Generating PUCCH 1a/1b payload %d,%d (with SR for PUSCH), shorten_pucch %d, n1_pucch %d, Po_PUCCH, amp %d\n", Mod_id, ue->dlsch[eNB_id][0]->rnti, + isShortenPucch, frame_tx, subframe_tx, pucch_ack_payload[0],pucch_ack_payload[1], ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex, Po_PUCCH, tx_amp); } else { - LOG_D(PHY,"[UE %d][PDSCH %x] Frame %d subframe %d Generating PUCCH 1a/1b, n1_pucch %d, b[0]=%d,b[1]=%d (SR_Payload %d), Po_PUCCH %d, amp %d\n", + LOG_I(PHY,"[UE %d][PDSCH %x] Frame %d subframe %d Generating PUCCH 1a/1b, shorten_pucch %d, n1_pucch %d, b[0]=%d,b[1]=%d (SR_Payload %d), Po_PUCCH %d, amp %d\n", Mod_id, ue->dlsch[eNB_id][0]->rnti, frame_tx, subframe_tx, + isShortenPucch, n1_pucch,pucch_ack_payload[0],pucch_ack_payload[1],SR_payload, Po_PUCCH, tx_amp); @@ -1201,7 +1424,7 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin format, &ue->pucch_config_dedicated[eNB_id], n1_pucch, - 1, // shortened format + isShortenPucch, // shortened format pucch_ack_payload, tx_amp, subframe_tx); @@ -1236,10 +1459,11 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin #else tx_amp = AMP; #endif - LOG_D(PHY,"[UE %d][SR %x] Frame %d subframe %d Generating PUCCH 1 (SR for PUSCH), n1_pucch %d, Po_PUCCH %d\n", + LOG_I(PHY,"[UE %d][SR %x] Frame %d subframe %d Generating PUCCH 1 (SR for PUSCH), shorten_pucch %d, n1_pucch %d, Po_PUCCH %d\n", Mod_id, ue->dlsch[eNB_id][0]->rnti, frame_tx, subframe_tx, + isShortenPucch, ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex, Po_PUCCH); @@ -1251,7 +1475,7 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin pucch_format1, &ue->pucch_config_dedicated[eNB_id], ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex, - 1, // shortened format + isShortenPucch, // shortened format pucch_ack_payload, // this is ignored anyway, we just need a pointer tx_amp, subframe_tx); @@ -1306,8 +1530,13 @@ void phy_procedures_UE_TX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,ui } - if (ue->UE_mode[eNB_id] == PUSCH) { // check if we need to use PUCCH 1a/1b - ue_pucch_procedures(ue,proc,eNB_id,abstraction_flag); + if (ue->UE_mode[eNB_id] == PUSCH) { + // check cell srs subframe and ue srs subframe + ue_compute_srs_occasion(ue,proc,eNB_id); + // check if we need to use PUCCH 1a/1b + ue_pucch_procedures(ue,proc,eNB_id,abstraction_flag); + // check if we need to use SRS + ue_srs_procedures(ue,proc,eNB_id,abstraction_flag); } // UE_mode==PUSCH diff --git a/openair1/SCHED/srs_pc.c b/openair1/SCHED/srs_pc.c new file mode 100644 index 0000000000..dc9b8fef46 --- /dev/null +++ b/openair1/SCHED/srs_pc.c @@ -0,0 +1,99 @@ +/******************************************************************************* + 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + + *******************************************************************************/ + +/*! \file srs_pc.c + * \brief Implementation of UE SRS Power Control procedures from 36.213 LTE specifications (Section + * \author H. Bilel + * \date 2016 + * \version 0.1 + * \company TCL + * \email: haithem.bilel@alcatelOneTouch.com + * \note + * \warning + */ + +#include "PHY/defs.h" +#include "PHY/LTE_TRANSPORT/proto.h" +#include "PHY/extern.h" + +void srs_power_cntl(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t *pnb_rb_srs, uint8_t abstraction_flag) +{ + + int16_t PL; + int8_t P_opusch; + int8_t Psrs_offset; + int16_t P_srs; + int16_t f_pusch; + uint8_t alpha; + uint8_t Msrs = 0; + + + SOUNDINGRS_UL_CONFIG_DEDICATED *psoundingrs_ul_config_dedicated = &ue->soundingrs_ul_config_dedicated[eNB_id]; + LTE_DL_FRAME_PARMS *pframe_parms = &ue->frame_parms; + + uint8_t Bsrs = psoundingrs_ul_config_dedicated->srs_Bandwidth; + uint8_t Csrs = pframe_parms->soundingrs_ul_config_common.srs_BandwidthConfig; + LOG_I(PHY," SRS Power Control; AbsSubframe %d.%d, eNB_id %d, srs_Bandwidth %d, srs_BandwidthConfig %d \n",proc->frame_tx,proc->subframe_tx,eNB_id,Bsrs,Csrs); + + if (pframe_parms->N_RB_UL < 41) + { + Msrs = Nb_6_40[Csrs][Bsrs]; + } + else if (pframe_parms->N_RB_UL < 61) + { + Msrs = Nb_41_60[Csrs][Bsrs]; + } + else if (pframe_parms->N_RB_UL < 81) + { + Msrs = Nb_61_80[Csrs][Bsrs]; + } + else if (pframe_parms->N_RB_UL <111) + { + Msrs = Nb_81_110[Csrs][Bsrs]; + } + + // SRS Power control 36.213 5.1.3.1 + // P_srs = P_srs_offset+ 10log10(Msrs) + P_opusch(j) + alpha*PL + f(i)) + + Psrs_offset = (ue->ul_power_control_dedicated[eNB_id].pSRS_Offset - 3); + P_opusch = ue->frame_parms.ul_power_control_config_common.p0_NominalPUSCH; + f_pusch = ue->ulsch[eNB_id]->f_pusch; + alpha = alpha_lut[ue->frame_parms.ul_power_control_config_common.alpha]; + PL = get_PL(ue->Mod_id,ue->CC_id,eNB_id); + + LOG_I(PHY," SRS Power Control; eNB_id %d, p0_NominalPUSCH %d, alpha %d \n",eNB_id,P_opusch,alpha); + LOG_I(PHY," SRS Power Control; eNB_id %d, pSRS_Offset %d, Msrs %d, PL %d, f_pusch %d \n",eNB_id,Psrs_offset,Msrs,PL,f_pusch); + + P_srs = P_opusch + Psrs_offset + f_pusch; + P_srs += (((int32_t)alpha * (int32_t)PL) + hundred_times_log10_NPRB[Msrs-1])/100 ; + + ue->ulsch[eNB_id]->Po_SRS = P_srs; + pnb_rb_srs[0] = Msrs; + LOG_I(PHY," SRS Power Control; eNB_id %d, P_srs[dBm] %d\n",eNB_id,P_srs); +} diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index 13cfae80da..e0556b92bf 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -1496,7 +1496,7 @@ do_RRCConnectionSetup( physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH = CALLOC(1,sizeof(*physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH)); physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH = CALLOC(1,sizeof(*physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH)); physicalConfigDedicated2->cqi_ReportConfig = CALLOC(1,sizeof(*physicalConfigDedicated2->cqi_ReportConfig)); - physicalConfigDedicated2->soundingRS_UL_ConfigDedicated = NULL;//CALLOC(1,sizeof(*physicalConfigDedicated2->soundingRS_UL_ConfigDedicated)); + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated = CALLOC(1,sizeof(*physicalConfigDedicated2->soundingRS_UL_ConfigDedicated)); physicalConfigDedicated2->antennaInfo = CALLOC(1,sizeof(*physicalConfigDedicated2->antennaInfo)); physicalConfigDedicated2->schedulingRequestConfig = CALLOC(1,sizeof(*physicalConfigDedicated2->schedulingRequestConfig)); #ifdef CBA @@ -1582,19 +1582,17 @@ do_RRCConnectionSetup( */ //soundingRS-UL-ConfigDedicated - /* physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->present = SoundingRS_UL_ConfigDedicated_PR_setup; - assign_enum(&physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth, - SoundingRS_UL_ConfigDedicated__setup__srs_Bandwidth_bw0); - assign_enum(&physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth, - SoundingRS_UL_ConfigDedicated__setup__srs_HoppingBandwidth_hbw0); + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth = + SoundingRS_UL_ConfigDedicated__setup__srs_Bandwidth_bw0; + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth = + SoundingRS_UL_ConfigDedicated__setup__srs_HoppingBandwidth_hbw0; physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition=0; physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.duration=1; - physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex=1; + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex=45; physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb=0; - assign_enum(&physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift, - SoundingRS_UL_ConfigDedicated__setup__cyclicShift_cs0); - */ + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift= + SoundingRS_UL_ConfigDedicated__setup__cyclicShift_cs0; //AntennaInfoDedicated diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 5807ababf2..517e354164 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -2621,7 +2621,7 @@ rrc_eNB_generate_RRCConnectionReconfiguration_handover( physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH = CALLOC(1, sizeof(*physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH)); physicalConfigDedicated2->cqi_ReportConfig = NULL; //CALLOC(1,sizeof(*physicalConfigDedicated2->cqi_ReportConfig)); - physicalConfigDedicated2->soundingRS_UL_ConfigDedicated = NULL; //CALLOC(1,sizeof(*physicalConfigDedicated2->soundingRS_UL_ConfigDedicated)); + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated = CALLOC(1,sizeof(*physicalConfigDedicated2->soundingRS_UL_ConfigDedicated)); physicalConfigDedicated2->antennaInfo = CALLOC(1, sizeof(*physicalConfigDedicated2->antennaInfo)); physicalConfigDedicated2->schedulingRequestConfig = CALLOC(1, sizeof(*physicalConfigDedicated2->schedulingRequestConfig)); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.generic.oaisim.local_no_mme.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.generic.oaisim.local_no_mme.conf index ef7c1cc19c..a79cb2cae6 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.generic.oaisim.local_no_mme.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.generic.oaisim.local_no_mme.conf @@ -62,11 +62,11 @@ eNBs = pusch_nDMRS1 = 0; phich_duration = "NORMAL"; phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =;*/ + srs_enable = "ENABLE"; + srs_BandwidthConfig =2; + srs_SubframeConfig =13; + srs_ackNackST ="DISABLE"; + srs_MaxUpPts ="DISABLE"; pusch_p0_Nominal = -108; pusch_alpha = "AL1"; diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index 2b19e30a9b..c493086963 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -1283,7 +1283,7 @@ void init_openair1(void) for (UE_id=0; UE_idtx_power_max_dBm=23; + PHY_vars_UE_g[UE_id][CC_id]->tx_power_max_dBm=10; PHY_vars_UE_g[UE_id][CC_id]->rx_total_gain_dB=100; @@ -1525,7 +1525,7 @@ void update_ocm() //calc_path_loss (enb_data[eNB_id], ue_data[UE_id], eNB2UE[eNB_id][UE_id], oai_emulation.environment_system_config,0); UE2eNB[UE_id][eNB_id][CC_id]->path_loss_dB = eNB2UE[eNB_id][UE_id][CC_id]->path_loss_dB; // if (frame % 50 == 0) - LOG_I(OCM,"Path loss (CCid %d) between eNB %d at (%f,%f) and UE %d at (%f,%f) is %f, angle %f\n", + LOG_D(OCM,"Path loss (CCid %d) between eNB %d at (%f,%f) and UE %d at (%f,%f) is %f, angle %f\n", CC_id,eNB_id,enb_data[eNB_id]->x,enb_data[eNB_id]->y,UE_id,ue_data[UE_id]->x,ue_data[UE_id]->y, eNB2UE[eNB_id][UE_id][CC_id]->path_loss_dB, eNB2UE[eNB_id][UE_id][CC_id]->aoa); //double dx, dy, distance; From 9d5621e65cae7e830bfce656dc04434ccbc260b6 Mon Sep 17 00:00:00 2001 From: fnabet Date: Wed, 12 Oct 2016 17:47:31 +0200 Subject: [PATCH 244/413] [OAI-UE] SRS feature 1- Implement SRS procedures 2- Implement SRS procedures part2 --- openair1/PHY/INIT/lte_init.c | 3 ++- openair1/PHY/impl_defs_lte.h | 2 ++ openair1/SCHED/phy_procedures_lte_ue.c | 11 ++++++----- openair1/SCHED/srs_pc.c | 9 +++++---- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index d358329b63..cb299110f5 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -881,8 +881,9 @@ void phy_config_dedicated_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated) { + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srsConfigDedicatedSetup = 0; if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated->present == SchedulingRequestConfig_PR_setup) { - + phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srsConfigDedicatedSetup = 1; phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].duration = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.duration; phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].cyclicShift = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift; phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].freqDomainPosition = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition; diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h index 6813fe058f..4ec446cd5f 100644 --- a/openair1/PHY/impl_defs_lte.h +++ b/openair1/PHY/impl_defs_lte.h @@ -319,6 +319,8 @@ typedef struct { uint16_t srs_ConfigIndex; /// Parameter: \f$n^\text{CS}_\text{SRS}\f$. See TS 36.211 (5.5.3.1). \vr{[0..7]} \note the specification sais it is an enumerated value. uint8_t cyclicShift; + // Parameter: ue srs subframe for internal implementation + uint8_t srsConfigDedicatedSetup; // Parameter: cell srs subframe for internal implementation uint8_t srsCellSubframe; // Parameter: ue srs subframe for internal implementation diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index f15e4768c0..9670df5b4a 100755 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -502,7 +502,7 @@ void ue_compute_srs_occasion(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id if(frame_parms->soundingrs_ul_config_common.enabled_flag) { - LOG_D(PHY," SRS SUBFRAMECONFIG: %d, Isrs: %d \n", frame_parms->soundingrs_ul_config_common.srs_SubframeConfig, pSoundingrs_ul_config_dedicated->srs_ConfigIndex); + LOG_I(PHY," SRS SUBFRAMECONFIG: %d, Isrs: %d \n", frame_parms->soundingrs_ul_config_common.srs_SubframeConfig, pSoundingrs_ul_config_dedicated->srs_ConfigIndex); uint8_t TSFC; uint16_t deltaTSFC; // bitmap @@ -528,8 +528,6 @@ void ue_compute_srs_occasion(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id TSFC = deltaTSFCTabType2[srs_SubframeConfig][1]; } - LOG_D(PHY," ISTDD: %d, TSFC: %d, deltaTSFC: %d, AbsSubframeTX: %d\n", frame_parms->frame_type, TSFC, deltaTSFC, (((int)frame_tx*10)+(int)subframe_tx)); - // Sounding reference signal subframes are the subframes satisfying ns/2 mod TSFC (- deltaTSFC uint16_t tmp = (subframe_tx % TSFC); if((1<srsCellSubframe = 1; } + LOG_I(PHY," ISTDD: %d, TSFC: %d, deltaTSFC: %d, AbsSubframeTX: %d.%d, srsCellSubframe: %d \n", frame_parms->frame_type, TSFC, deltaTSFC, frame_tx, subframe_tx, pSoundingrs_ul_config_dedicated->srsCellSubframe); - + if(pSoundingrs_ul_config_dedicated->srsConfigDedicatedSetup) + { compute_srs_pos(frame_parms->frame_type, pSoundingrs_ul_config_dedicated->srs_ConfigIndex, &srsPeriodicity, &srsOffset); // transmit SRS if the four following constraints are respected: @@ -556,7 +556,8 @@ void ue_compute_srs_occasion(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id isSubframeSRSTx = 1; pSoundingrs_ul_config_dedicated->srsUeSubframe = 1; } - LOG_D(PHY," isSubframeSRS: %d, isSubframeSRSTx: %d \n", isSubframeSRS, isSubframeSRSTx); + LOG_I(PHY," isSubframeSRS: %d, isSubframeSRSTx: %d \n", isSubframeSRS, isSubframeSRSTx); + } } } diff --git a/openair1/SCHED/srs_pc.c b/openair1/SCHED/srs_pc.c index dc9b8fef46..3ec5f00f9a 100644 --- a/openair1/SCHED/srs_pc.c +++ b/openair1/SCHED/srs_pc.c @@ -59,7 +59,7 @@ void srs_power_cntl(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t uint8_t Bsrs = psoundingrs_ul_config_dedicated->srs_Bandwidth; uint8_t Csrs = pframe_parms->soundingrs_ul_config_common.srs_BandwidthConfig; - LOG_I(PHY," SRS Power Control; AbsSubframe %d.%d, eNB_id %d, srs_Bandwidth %d, srs_BandwidthConfig %d \n",proc->frame_tx,proc->subframe_tx,eNB_id,Bsrs,Csrs); + LOG_I(PHY," SRS Power Control; AbsSubframe %d.%d, eNB_id %d, N_RB_UL %d, srs_Bandwidth %d, srs_BandwidthConfig %d \n",proc->frame_tx,proc->subframe_tx,eNB_id,pframe_parms->N_RB_UL,Bsrs,Csrs); if (pframe_parms->N_RB_UL < 41) { @@ -88,12 +88,13 @@ void srs_power_cntl(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t PL = get_PL(ue->Mod_id,ue->CC_id,eNB_id); LOG_I(PHY," SRS Power Control; eNB_id %d, p0_NominalPUSCH %d, alpha %d \n",eNB_id,P_opusch,alpha); - LOG_I(PHY," SRS Power Control; eNB_id %d, pSRS_Offset %d, Msrs %d, PL %d, f_pusch %d \n",eNB_id,Psrs_offset,Msrs,PL,f_pusch); + LOG_I(PHY," SRS Power Control; eNB_id %d, pSRS_Offset[dB] %d, Msrs %d, PL %d, f_pusch %d \n",eNB_id,Psrs_offset,Msrs,PL,f_pusch); P_srs = P_opusch + Psrs_offset + f_pusch; P_srs += (((int32_t)alpha * (int32_t)PL) + hundred_times_log10_NPRB[Msrs-1])/100 ; - ue->ulsch[eNB_id]->Po_SRS = P_srs; + ue->ulsch[eNB_id]->Po_SRS = P_srs < ue->tx_power_max_dBm ? P_srs:ue->tx_power_max_dBm; // MIN(PcMax,Psrs) + pnb_rb_srs[0] = Msrs; - LOG_I(PHY," SRS Power Control; eNB_id %d, P_srs[dBm] %d\n",eNB_id,P_srs); + LOG_I(PHY," SRS Power Control; eNB_id %d, P_srs[dBm] %d, P_cmax[dBm] %d, Psrs[dBm] %d\n",eNB_id,P_srs,ue->tx_power_max_dBm,ue->ulsch[eNB_id]->Po_SRS); } From 9938bd5d05e52c1d41b940f5445ae17f2d57d62e Mon Sep 17 00:00:00 2001 From: fnabet Date: Tue, 18 Oct 2016 16:15:49 +0200 Subject: [PATCH 245/413] [OAI-UE] SRS feature 1- Implement SRS procedures 2- Implement SRS procedures part2 3- Implement SRS: SRS valid on CMW --- openair1/PHY/LTE_TRANSPORT/dci.c | 2 +- openair1/PHY/LTE_TRANSPORT/group_hopping.c | 6 ++ openair1/PHY/LTE_TRANSPORT/srs_modulation.c | 70 +++++++++------------ openair1/PHY/impl_defs_lte.h | 5 ++ openair1/SCHED/phy_procedures_lte_ue.c | 42 ++++++++----- openair1/SCHED/srs_pc.c | 26 +++++--- 6 files changed, 86 insertions(+), 65 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index ac081f840b..49966f9910 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -2865,7 +2865,7 @@ void dci_decoding_procedure0(LTE_UE_PDCCH **pdcch_vars, } } - LOG_D(PHY,"DCI decoding CRNTI [format_c: %d, nCCE[subframe: %d]: %d ]\n",format_c, subframe, pdcch_vars[eNB_id]->nCCE[subframe]); + LOG_D(PHY,"DCI decoding CRNTI [format: %d, nCCE[subframe: %d]: %d ], AggregationLevel %d \n",format_c, subframe, pdcch_vars[eNB_id]->nCCE[subframe],L2); // memcpy(&dci_alloc[*dci_cnt].dci_pdu[0],dci_decoded_output,sizeof_bytes); diff --git a/openair1/PHY/LTE_TRANSPORT/group_hopping.c b/openair1/PHY/LTE_TRANSPORT/group_hopping.c index 64c0830386..ed3cb11c08 100644 --- a/openair1/PHY/LTE_TRANSPORT/group_hopping.c +++ b/openair1/PHY/LTE_TRANSPORT/group_hopping.c @@ -50,6 +50,8 @@ void generate_grouphop(LTE_DL_FRAME_PARMS *frame_parms) // This is from Section 5.5.1.3 uint32_t fss_pusch = frame_parms->Nid_cell + frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH; + uint32_t fss_pucch = frame_parms->Nid_cell; + x2 = frame_parms->Nid_cell/30; #ifdef DEBUG_GROUPHOP printf("[PHY] GroupHop:"); @@ -57,7 +59,10 @@ void generate_grouphop(LTE_DL_FRAME_PARMS *frame_parms) for (ns=0; ns<20; ns++) { if (frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled == 0) + { frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.grouphop[ns] = fss_pusch%30; + frame_parms->pucch_config_common.grouphop[ns] = fss_pucch%30; + } else { if ((ns&3) == 0) { s = lte_gold_generic(&x1,&x2,reset); @@ -65,6 +70,7 @@ void generate_grouphop(LTE_DL_FRAME_PARMS *frame_parms) } frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.grouphop[ns] = (((uint8_t*)&s)[ns&3]+fss_pusch)%30; + frame_parms->pucch_config_common.grouphop[ns] = (((uint8_t*)&s)[ns&3]+fss_pucch)%30; } #ifdef DEBUG_GROUPHOP diff --git a/openair1/PHY/LTE_TRANSPORT/srs_modulation.c b/openair1/PHY/LTE_TRANSPORT/srs_modulation.c index cb5d653909..8f2ad8907a 100644 --- a/openair1/PHY/LTE_TRANSPORT/srs_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/srs_modulation.c @@ -137,11 +137,10 @@ int32_t generate_srs_tx(PHY_VARS_UE *ue, LTE_DL_FRAME_PARMS *frame_parms=&ue->frame_parms; SOUNDINGRS_UL_CONFIG_DEDICATED *soundingrs_ul_config_dedicated=&ue->soundingrs_ul_config_dedicated[eNB_id]; - int32_t *txdataF = ue->common_vars.txdataF[0]; + int32_t **txdataF = ue->common_vars.txdataF; uint16_t msrsb=0,Nb=0,nb,b,msrs0=0,k,Msc_RS,Msc_RS_idx,carrier_pos,symbol_offset; uint16_t *Msc_idx_ptr; int32_t k0; - uint32_t T_SFC; uint32_t subframe_offset; uint8_t Bsrs = soundingrs_ul_config_dedicated->srs_Bandwidth; uint8_t Csrs = frame_parms->soundingrs_ul_config_common.srs_BandwidthConfig; @@ -149,6 +148,16 @@ int32_t generate_srs_tx(PHY_VARS_UE *ue, uint8_t n_RRC = soundingrs_ul_config_dedicated->freqDomainPosition; uint8_t kTC = soundingrs_ul_config_dedicated->transmissionComb; + // u is the PUCCH sequence-group number defined in Section 5.5.1.3 + // ν is the base sequence number defined in Section 5.5.1.4 + uint32_t u=frame_parms->pucch_config_common.grouphop[1+(subframe<<1)];; + uint32_t v=frame_parms->pusch_config_common.ul_ReferenceSignalsPUSCH.seqhop[1+(subframe<<1)]; + + LOG_D(PHY,"SRS root sequence: u %d, v %d\n",u,v); + LOG_D(PHY,"CommonSrsConfig: Csrs %d, Ssrs %d, AnSrsSimultan %d \n",Csrs,Ssrs,frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission); + LOG_D(PHY,"DedicatedSrsConfig: Bsrs %d, bhop %d, nRRC %d, Isrs %d, kTC %d, n_SRS %d\n",Bsrs,soundingrs_ul_config_dedicated->srs_HoppingBandwidth,n_RRC + ,soundingrs_ul_config_dedicated->srs_ConfigIndex,kTC + ,soundingrs_ul_config_dedicated->cyclicShift); if (frame_parms->N_RB_UL < 41) { msrs0 = msrsb_6_40[Csrs][0]; @@ -169,7 +178,7 @@ int32_t generate_srs_tx(PHY_VARS_UE *ue, } Msc_RS = msrsb * 6; - k0 = (((frame_parms->N_RB_UL>>1)-(msrs0>>1))*12) + kTC; + k0 = ( ( (int16_t)(frame_parms->N_RB_UL>>1) - (int16_t)(msrs0>>1) ) * 12 ) + kTC; nb = (4*n_RRC/msrsb)%Nb; for (b=0; b<=Bsrs; b++) { @@ -208,53 +217,32 @@ int32_t generate_srs_tx(PHY_VARS_UE *ue, msg("generate_srs_tx: Msc_RS = %d, Msc_RS_idx = %d\n",Msc_RS, Msc_RS_idx); #endif - T_SFC = (Ssrs<=7 ? 5 : 10); + carrier_pos = (frame_parms->first_carrier_offset + k0); + if (carrier_pos>frame_parms->ofdm_symbol_size) { + carrier_pos -= frame_parms->ofdm_symbol_size; + } + uint16_t nsymb = (frame_parms->Ncp==0) ? 14:12; + symbol_offset = (int)frame_parms->ofdm_symbol_size*((subframe*nsymb)+(nsymb-1)); - if ((1<<(subframe%T_SFC))&transmission_offset_tdd[Ssrs]) { - -#ifndef IFFT_FPGA_UE - carrier_pos = (frame_parms->first_carrier_offset + k0) % frame_parms->ofdm_symbol_size; //msg("carrier_pos = %d\n",carrier_pos); + //subframe_offset = subframe*frame_parms->symbols_per_tti*frame_parms->ofdm_symbol_size; + //symbol_offset = subframe_offset+(frame_parms->symbols_per_tti-1)*frame_parms->ofdm_symbol_size; - subframe_offset = subframe*frame_parms->symbols_per_tti*frame_parms->ofdm_symbol_size; - symbol_offset = subframe_offset+(frame_parms->symbols_per_tti-1)*frame_parms->ofdm_symbol_size; + int32_t *txptr; + txptr = &txdataF[0][symbol_offset]; for (k=0; k>15); - ((short*) txdataF)[2*(symbol_offset + carrier_pos)+1] = (short) (((int32_t) amp * (int32_t) ul_ref_sigs[0][0][Msc_RS_idx][(k<<1)+1])>>15); - carrier_pos+=2; + int32_t real = ((int32_t) amp * (int32_t) ul_ref_sigs[u][v][Msc_RS_idx][k<<1]) >> 15; + int32_t imag = ((int32_t) amp * (int32_t) ul_ref_sigs[u][v][Msc_RS_idx][(k<<1)+1]) >> 15; + txptr[carrier_pos] = (real&0xFFFF) + ((imag<<16)&0xFFFF0000); + + + carrier_pos = carrier_pos+2; if (carrier_pos >= frame_parms->ofdm_symbol_size) - carrier_pos=1; + carrier_pos=carrier_pos-frame_parms->ofdm_symbol_size; } -#else - carrier_pos = (frame_parms->N_RB_UL*12/2 + k0) % (frame_parms->N_RB_UL*12); - //msg("carrier_pos = %d\n",carrier_pos); - - subframe_offset = subframe*frame_parms->symbols_per_tti*frame_parms->N_RB_UL*12; - symbol_offset = subframe_offset+(frame_parms->symbols_per_tti-1)*frame_parms->N_RB_UL*12; - - for (k=0; k= 0) && (ul_ref_sigs[0][0][Msc_RS_idx][(k<<1)+1] >= 0)) - txdataF[symbol_offset+carrier_pos] = (int32_t) 4; - else if ((ul_ref_sigs[0][0][Msc_RS_idx][k<<1] >= 0) && (ul_ref_sigs[0][0][Msc_RS_idx][(k<<1)+1] < 0)) - txdataF[symbol_offset+carrier_pos] = (int32_t) 2; - else if ((ul_ref_sigs[0][0][Msc_RS_idx][k<<1] < 0) && (ul_ref_sigs[0][0][Msc_RS_idx][(k<<1)+1] >= 0)) - txdataF[symbol_offset+carrier_pos] = (int32_t) 3; - else if ((ul_ref_sigs[0][0][Msc_RS_idx][k<<1] < 0) && (ul_ref_sigs[0][0][Msc_RS_idx][(k<<1)+1] < 0)) - txdataF[symbol_offset+carrier_pos] = (int32_t) 1; - - carrier_pos+=2; - - if (carrier_pos >= frame_parms->N_RB_UL*12) - carrier_pos=0; - } - -#endif - // write_output("srs_txF.m","srstxF",&txdataF[symbol_offset],512,1,1); - } - return(0); } diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h index 4ec446cd5f..30dbff7b86 100644 --- a/openair1/PHY/impl_defs_lte.h +++ b/openair1/PHY/impl_defs_lte.h @@ -148,6 +148,11 @@ typedef struct { uint8_t nCS_AN; /// Parameter: \f$N^{(1)}_\text{PUCCH}\f$ see TS 36.213 (10.1). \vr{[0..2047]} uint16_t n1PUCCH_AN; + + /// group hopping sequence for DRS \note not part of offical UL-PUCCH_CONFIG_COMMON ASN1 specification. + uint8_t grouphop[20]; + /// sequence hopping sequence for DRS \note not part of offical UL-PUCCH_CONFIG_COMMON ASN1 specification. + uint8_t seqhop[20]; } PUCCH_CONFIG_COMMON; /// UL-ReferenceSignalsPUSCH from 36.331 RRC spec diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 9670df5b4a..f3ed4ec645 100755 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -205,7 +205,6 @@ unsigned int get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb_rb int gain_dB = power_dBm - power_max_dBm; double gain_lin; - LOG_I(PHY,"Get Tx Amp; Gain[dB]: %d, AMP: %d\n",gain_dB,AMP); if (gain_dB < -20) return(AMP/10); @@ -492,17 +491,19 @@ void ue_compute_srs_occasion(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id int frame_tx = proc->frame_tx; int subframe_tx = proc->subframe_tx; uint8_t isSubframeSRS = 0; // SRS Cell Occasion - uint8_t isSubframeSRSTx = 0; // SRS UE Occasion SOUNDINGRS_UL_CONFIG_DEDICATED *pSoundingrs_ul_config_dedicated=&ue->soundingrs_ul_config_dedicated[eNB_id]; // check for SRS opportunity pSoundingrs_ul_config_dedicated->srsUeSubframe = 0; pSoundingrs_ul_config_dedicated->srsCellSubframe = 0; + + ue->ulsch[eNB_id]->srs_active = 0; + ue->ulsch[eNB_id]->Nsymb_pusch = 12-(frame_parms->Ncp<<1)- ue->ulsch[eNB_id]->srs_active; if(frame_parms->soundingrs_ul_config_common.enabled_flag) { - LOG_I(PHY," SRS SUBFRAMECONFIG: %d, Isrs: %d \n", frame_parms->soundingrs_ul_config_common.srs_SubframeConfig, pSoundingrs_ul_config_dedicated->srs_ConfigIndex); + LOG_D(PHY," SRS SUBFRAMECONFIG: %d, Isrs: %d \n", frame_parms->soundingrs_ul_config_common.srs_SubframeConfig, pSoundingrs_ul_config_dedicated->srs_ConfigIndex); uint8_t TSFC; uint16_t deltaTSFC; // bitmap @@ -536,12 +537,14 @@ void ue_compute_srs_occasion(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id isSubframeSRS = 1; pSoundingrs_ul_config_dedicated->srsCellSubframe = 1; } - LOG_I(PHY," ISTDD: %d, TSFC: %d, deltaTSFC: %d, AbsSubframeTX: %d.%d, srsCellSubframe: %d \n", frame_parms->frame_type, TSFC, deltaTSFC, frame_tx, subframe_tx, pSoundingrs_ul_config_dedicated->srsCellSubframe); - + LOG_D(PHY," ISTDD: %d, TSFC: %d, deltaTSFC: %d, AbsSubframeTX: %d.%d, srsCellSubframe: %d \n", frame_parms->frame_type, TSFC, deltaTSFC, frame_tx, subframe_tx, pSoundingrs_ul_config_dedicated->srsCellSubframe); + LOG_D(PHY," SrsDedicatedSetup: %d \n",pSoundingrs_ul_config_dedicated->srsConfigDedicatedSetup); if(pSoundingrs_ul_config_dedicated->srsConfigDedicatedSetup) { compute_srs_pos(frame_parms->frame_type, pSoundingrs_ul_config_dedicated->srs_ConfigIndex, &srsPeriodicity, &srsOffset); + LOG_D(PHY," srsPeriodicity: %d srsOffset: %d isSubframeSRS %d \n",srsPeriodicity,srsOffset,isSubframeSRS); + // transmit SRS if the four following constraints are respected: // - UE is configured to transmit SRS // - SRS are configured in current subframe @@ -553,11 +556,12 @@ void ue_compute_srs_occasion(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id //(! is_pucch_per_cqi_report)) ) { - isSubframeSRSTx = 1; pSoundingrs_ul_config_dedicated->srsUeSubframe = 1; + ue->ulsch[eNB_id]->srs_active = 1; + ue->ulsch[eNB_id]->Nsymb_pusch = 12-(frame_parms->Ncp<<1)- ue->ulsch[eNB_id]->srs_active; } - LOG_I(PHY," isSubframeSRS: %d, isSubframeSRSTx: %d \n", isSubframeSRS, isSubframeSRSTx); } + LOG_D(PHY," srsCellSubframe: %d, srsUeSubframe: %d, Nsymb-pusch: %d \n", pSoundingrs_ul_config_dedicated->srsCellSubframe, pSoundingrs_ul_config_dedicated->srsUeSubframe, ue->ulsch[eNB_id]->Nsymb_pusch); } } @@ -1289,14 +1293,21 @@ void ue_srs_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8 } #if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) + if (ue->mac_enabled==1) + { tx_amp = get_tx_amp(Po_SRS, ue->tx_power_max_dBm, ue->frame_parms.N_RB_UL, nb_rb_srs); + } + else + { + tx_amp = AMP; + } #else tx_amp = AMP; #endif - LOG_I(PHY,"SRS PROC; TX_MAX_POWER %d, Po_SRS %d, NB_RB_UL %d, NB_RB_SRS %d TX_AMPL %d\n",ue->tx_power_max_dBm, + LOG_D(PHY,"SRS PROC; TX_MAX_POWER %d, Po_SRS %d, NB_RB_UL %d, NB_RB_SRS %d TX_AMPL %d\n",ue->tx_power_max_dBm, Po_SRS, ue->frame_parms.N_RB_UL, nb_rb_srs, @@ -1323,7 +1334,7 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin int8_t Po_PUCCH; SOUNDINGRS_UL_CONFIG_DEDICATED *pSoundingrs_ul_config_dedicated=&ue->soundingrs_ul_config_dedicated[eNB_id]; - uint8_t isShortenPucch = pSoundingrs_ul_config_dedicated->srsCellSubframe; + uint8_t isShortenPucch = (pSoundingrs_ul_config_dedicated->srsCellSubframe && frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission); bundling_flag = ue->pucch_config_dedicated[eNB_id].tdd_AckNackFeedbackMode; @@ -1397,9 +1408,10 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin #endif if (SR_payload>0) { - LOG_I(PHY,"[UE %d][SR %x] Frame %d subframe %d Generating PUCCH 1a/1b payload %d,%d (with SR for PUSCH), shorten_pucch %d, n1_pucch %d, Po_PUCCH, amp %d\n", + LOG_D(PHY,"[UE %d][SR %x] Frame %d subframe %d Generating PUCCH 1a/1b payload %d,%d (with SR for PUSCH), an_srs_simultanous %d, shorten_pucch %d, n1_pucch %d, Po_PUCCH, amp %d\n", Mod_id, ue->dlsch[eNB_id][0]->rnti, + frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission, isShortenPucch, frame_tx, subframe_tx, pucch_ack_payload[0],pucch_ack_payload[1], @@ -1407,10 +1419,11 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin Po_PUCCH, tx_amp); } else { - LOG_I(PHY,"[UE %d][PDSCH %x] Frame %d subframe %d Generating PUCCH 1a/1b, shorten_pucch %d, n1_pucch %d, b[0]=%d,b[1]=%d (SR_Payload %d), Po_PUCCH %d, amp %d\n", + LOG_D(PHY,"[UE %d][PDSCH %x] Frame %d subframe %d Generating PUCCH 1a/1b, an_srs_simultanous %d, shorten_pucch %d, n1_pucch %d, b[0]=%d,b[1]=%d (SR_Payload %d), Po_PUCCH %d, amp %d\n", Mod_id, ue->dlsch[eNB_id][0]->rnti, frame_tx, subframe_tx, + frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission, isShortenPucch, n1_pucch,pucch_ack_payload[0],pucch_ack_payload[1],SR_payload, Po_PUCCH, @@ -1460,10 +1473,11 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin #else tx_amp = AMP; #endif - LOG_I(PHY,"[UE %d][SR %x] Frame %d subframe %d Generating PUCCH 1 (SR for PUSCH), shorten_pucch %d, n1_pucch %d, Po_PUCCH %d\n", + LOG_D(PHY,"[UE %d][SR %x] Frame %d subframe %d Generating PUCCH 1 (SR for PUSCH), an_srs_simultanous %d, shorten_pucch %d, n1_pucch %d, Po_PUCCH %d\n", Mod_id, ue->dlsch[eNB_id][0]->rnti, frame_tx, subframe_tx, + frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission, isShortenPucch, ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex, Po_PUCCH); @@ -1526,14 +1540,14 @@ void phy_procedures_UE_TX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,ui } if (ue->UE_mode[eNB_id] != PRACH) { + // check cell srs subframe and ue srs subframe. This has an impact on pusch encoding + ue_compute_srs_occasion(ue,proc,eNB_id); ue_ulsch_uespec_procedures(ue,proc,eNB_id,abstraction_flag); } if (ue->UE_mode[eNB_id] == PUSCH) { - // check cell srs subframe and ue srs subframe - ue_compute_srs_occasion(ue,proc,eNB_id); // check if we need to use PUCCH 1a/1b ue_pucch_procedures(ue,proc,eNB_id,abstraction_flag); // check if we need to use SRS diff --git a/openair1/SCHED/srs_pc.c b/openair1/SCHED/srs_pc.c index 3ec5f00f9a..461d230975 100644 --- a/openair1/SCHED/srs_pc.c +++ b/openair1/SCHED/srs_pc.c @@ -46,7 +46,8 @@ void srs_power_cntl(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t { int16_t PL; - int8_t P_opusch; + int8_t p0_NominalPUSCH; + int8_t p0_UE_PUSCH; int8_t Psrs_offset; int16_t P_srs; int16_t f_pusch; @@ -59,7 +60,7 @@ void srs_power_cntl(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t uint8_t Bsrs = psoundingrs_ul_config_dedicated->srs_Bandwidth; uint8_t Csrs = pframe_parms->soundingrs_ul_config_common.srs_BandwidthConfig; - LOG_I(PHY," SRS Power Control; AbsSubframe %d.%d, eNB_id %d, N_RB_UL %d, srs_Bandwidth %d, srs_BandwidthConfig %d \n",proc->frame_tx,proc->subframe_tx,eNB_id,pframe_parms->N_RB_UL,Bsrs,Csrs); + LOG_D(PHY," SRS Power Control; AbsSubframe %d.%d, eNB_id %d, N_RB_UL %d, srs_Bandwidth %d, srs_BandwidthConfig %d \n",proc->frame_tx,proc->subframe_tx,eNB_id,pframe_parms->N_RB_UL,Bsrs,Csrs); if (pframe_parms->N_RB_UL < 41) { @@ -81,20 +82,27 @@ void srs_power_cntl(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t // SRS Power control 36.213 5.1.3.1 // P_srs = P_srs_offset+ 10log10(Msrs) + P_opusch(j) + alpha*PL + f(i)) - Psrs_offset = (ue->ul_power_control_dedicated[eNB_id].pSRS_Offset - 3); - P_opusch = ue->frame_parms.ul_power_control_config_common.p0_NominalPUSCH; + p0_NominalPUSCH = ue->frame_parms.ul_power_control_config_common.p0_NominalPUSCH; + p0_UE_PUSCH = ue->ul_power_control_dedicated[eNB_id].p0_UE_PUSCH; + Psrs_offset = (ue->ul_power_control_dedicated[eNB_id].pSRS_Offset - 3); + + f_pusch = ue->ulsch[eNB_id]->f_pusch; alpha = alpha_lut[ue->frame_parms.ul_power_control_config_common.alpha]; PL = get_PL(ue->Mod_id,ue->CC_id,eNB_id); - LOG_I(PHY," SRS Power Control; eNB_id %d, p0_NominalPUSCH %d, alpha %d \n",eNB_id,P_opusch,alpha); - LOG_I(PHY," SRS Power Control; eNB_id %d, pSRS_Offset[dB] %d, Msrs %d, PL %d, f_pusch %d \n",eNB_id,Psrs_offset,Msrs,PL,f_pusch); + LOG_D(PHY," SRS Power Control; eNB_id %d, p0_NominalPUSCH %d, p0_UE_PUSCH %d, alpha %d \n",eNB_id,p0_NominalPUSCH,p0_UE_PUSCH,alpha); + LOG_D(PHY," SRS Power Control; eNB_id %d, pSRS_Offset[dB] %d, Msrs %d, PL %d, f_pusch %d \n",eNB_id,Psrs_offset,Msrs,PL,f_pusch); - P_srs = P_opusch + Psrs_offset + f_pusch; + P_srs = (p0_NominalPUSCH + p0_UE_PUSCH) + Psrs_offset + f_pusch; P_srs += (((int32_t)alpha * (int32_t)PL) + hundred_times_log10_NPRB[Msrs-1])/100 ; - ue->ulsch[eNB_id]->Po_SRS = P_srs < ue->tx_power_max_dBm ? P_srs:ue->tx_power_max_dBm; // MIN(PcMax,Psrs) + ue->ulsch[eNB_id]->Po_SRS = P_srs; + if(ue->ulsch[eNB_id]->Po_SRS > ue->tx_power_max_dBm) + { + ue->ulsch[eNB_id]->Po_SRS = ue->tx_power_max_dBm; + } pnb_rb_srs[0] = Msrs; - LOG_I(PHY," SRS Power Control; eNB_id %d, P_srs[dBm] %d, P_cmax[dBm] %d, Psrs[dBm] %d\n",eNB_id,P_srs,ue->tx_power_max_dBm,ue->ulsch[eNB_id]->Po_SRS); + LOG_D(PHY," SRS Power Control; eNB_id %d, Psrs_pc[dBm] %d, Pcmax[dBm] %d, Psrs[dBm] %d\n",eNB_id,P_srs,ue->tx_power_max_dBm,ue->ulsch[eNB_id]->Po_SRS); } From 9ed966cfe6d849f721eab5035a6a2c7a1106d1fe Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 19 Oct 2016 15:16:58 +0300 Subject: [PATCH 246/413] Added conf file for flexran oaisim --- ...enb.band7.flexran.oaisim.local_no_mme.conf | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.oaisim.local_no_mme.conf diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.oaisim.local_no_mme.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.oaisim.local_no_mme.conf new file mode 100644 index 0000000000..ca36fab455 --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.oaisim.local_no_mme.conf @@ -0,0 +1,160 @@ +Active_eNBs = ( "eNB_Eurecom_LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB_Eurecom_LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = "1"; + + mobile_country_code = "208"; + + mobile_network_code = "10"; + + ////////// Physical parameters: + + component_carriers = ( + { + node_function = "eNodeB_3GPP"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2680000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 2; + nb_antennas_tx = 2; + nb_antennas_rx = 2; + tx_gain = 25; + rx_gain = 20; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = 0; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 0; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -108; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -108; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 2; + rach_preambleInitialReceivedTargetPower = -100; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + + ue_TransmissionMode = 2; + } + ); + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "0.0.0.0"; + ipv6 = "0::0"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "none"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "0.0.0.0/24"; + + ENB_INTERFACE_NAME_FOR_S1U = "none"; + ENB_IPV4_ADDRESS_FOR_S1U = "0.0.0.0/24"; + ENB_PORT_FOR_S1U = 2153; # Spec 2152 + }; + + NETWORK_CONTROLLER : + { + ENB_AGENT_INTERFACE_NAME = "eth1"; + ENB_AGENT_IPV4_ADDRESS = "10.0.2.5/30"; + ENB_AGENT_PORT = 2210; + ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; + }; + + log_config : + { + global_log_level ="trace"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="trace"; + phy_log_verbosity ="medium"; + mac_log_level ="trace"; + mac_log_verbosity ="medium"; + rlc_log_level ="trace"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="trace"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="trace"; + rrc_log_verbosity ="medium"; + gtpu_log_level ="debug"; + gtpu_log_verbosity ="medium"; + udp_log_level ="debug"; + udp_log_verbosity ="medium"; + osa_log_level ="debug"; + osa_log_verbosity ="low"; + }; + + } +); From d8defff0fa8c2fe29c3d98b48fd1fc2b28cb0095 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Thu, 20 Oct 2016 06:32:33 -0700 Subject: [PATCH 247/413] periodic cqi procedures --- openair1/PHY/INIT/lte_init.c | 31 ++- openair1/PHY/LTE_TRANSPORT/proto.h | 18 ++ openair1/PHY/LTE_TRANSPORT/pucch.c | 14 +- openair1/PHY/LTE_TRANSPORT/uci_tools.c | 2 + openair1/PHY/impl_defs_lte.h | 14 +- openair1/SCHED/defs.h | 4 + openair1/SCHED/phy_procedures_lte_ue.c | 244 +++++++++++++++++- .../LAYER2/MAC/eNB_scheduler_primitives.c | 2 +- 8 files changed, 317 insertions(+), 12 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 3fb1d0c26b..268e2dcabd 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -742,7 +742,8 @@ void phy_config_dedicated_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, phy_vars_ue->dlsch_received_last[eNB_id]=0; phy_vars_ue->dlsch_fer[eNB_id]=0; - + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex = -1; + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex = -1; if (physicalConfigDedicated) { LOG_D(PHY,"[UE %d] Received physicalConfigDedicated from eNB %d\n",Mod_id, eNB_id); @@ -852,6 +853,31 @@ void phy_config_dedicated_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, } + if (physicalConfigDedicated->cqi_ReportConfig) { + if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic) { + // configure PUSCH CQI reporting + phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic = *physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic; + if ((phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic != rm12) && + (phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic != rm30) && + (phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic != rm31)) + LOG_E(PHY,"Unsupported Aperiodic CQI Feedback Mode : %d\n",phy_vars_ue->cqi_report_config[eNB_id].cqi_ReportModeAperiodic); + } + if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic) { + if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_setup) { + // configure PUCCH CQI reporting + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PUCCH_ResourceIndex = physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex = physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.cqi_pmi_ConfigIndex; + if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.ri_ConfigIndex) + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex = *physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.ri_ConfigIndex; + } + else if (physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_release) { + // handle release + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex = -1; + phy_vars_ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex = -1; + } + } + } + #ifdef CBA if (physicalConfigDedicated->pusch_CBAConfigDedicated_vlola) { @@ -868,6 +894,9 @@ void phy_config_dedicated_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, return; } + // fill cqi parameters for periodic CQI reporting + get_cqipmiri_params(phy_vars_ue,eNB_id); + } void phy_config_cba_rnti (module_id_t Mod_id,int CC_id,eNB_flag_t eNB_flag, uint8_t index, rnti_t cba_rnti, uint8_t cba_group_id, uint8_t num_active_cba_groups) diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h index 86bc3723af..7906d4bdd2 100644 --- a/openair1/PHY/LTE_TRANSPORT/proto.h +++ b/openair1/PHY/LTE_TRANSPORT/proto.h @@ -1445,6 +1445,9 @@ int32_t generate_ue_ulsch_params_from_rar(PHY_VARS_UE *phy_vars_ue, uint8_t eNB_id); double sinr_eff_cqi_calc(PHY_VARS_UE *phy_vars_ue, uint8_t eNB_id); + +uint8_t sinr2cqi(double sinr,uint8_t trans_mode); + int generate_eNB_ulsch_params_from_dci(PHY_VARS_eNB *PHY_vars_eNB, eNB_rxtx_proc_t *proc, void *dci_pdu, @@ -1712,6 +1715,21 @@ void generate_pucch1x(int32_t **txdataF, int16_t amp, uint8_t subframe); +void generate_pucch2x(int32_t **txdataF, + LTE_DL_FRAME_PARMS *fp, + uint8_t ncs_cell[20][7], + PUCCH_FMT_t fmt, + PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, + uint16_t n2_pucch, + uint8_t shortened_format, + uint16_t *payload, + int A, + int B2, + int16_t amp, + uint8_t subframe, + uint16_t rnti); + + void generate_pucch_emul(PHY_VARS_UE *phy_vars_ue, UE_rxtx_proc_t *proc, PUCCH_FMT_t format, diff --git a/openair1/PHY/LTE_TRANSPORT/pucch.c b/openair1/PHY/LTE_TRANSPORT/pucch.c index c0c54b9782..8ecde3747b 100644 --- a/openair1/PHY/LTE_TRANSPORT/pucch.c +++ b/openair1/PHY/LTE_TRANSPORT/pucch.c @@ -460,10 +460,13 @@ inline void pucch2x_modulation(uint8_t *btilde,int16_t *d,int16_t amp) { } + + uint32_t pucch_code[13] = {0xFFFFF,0x5A933,0x10E5A,0x6339C,0x73CE0, 0xFFC00,0xD8E64,0x4F6B0,0x218EC,0x1B746, 0x0FFFF,0x33FFF,0x3FFFC}; + void generate_pucch2x(int32_t **txdataF, LTE_DL_FRAME_PARMS *fp, uint8_t ncs_cell[20][7], @@ -471,7 +474,7 @@ void generate_pucch2x(int32_t **txdataF, PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, uint16_t n2_pucch, uint8_t shortened_format, - uint32_t *payload, + uint16_t *payload, int A, int B2, int16_t amp, @@ -559,10 +562,13 @@ void generate_pucch2x(int32_t **txdataF, nprime = (n2_pucch < 12*NRB2) ? n2_pucch % 12 : (n2_pucch+Ncs1 + 1)%12; - else + else { nprime = (n2_pucch < 12*NRB2) ? ((12*(nprime+1)) % 13)-1 : (10-n2_pucch)%12; + if (shortened_format == 1) + N_UL_symb--; + } //loop over symbols in slot for (l=0; lcqi_report_config[eNB_id].CQI_ReportPeriodic; + int cqi_PMI_ConfigIndex = cqirep->cqi_PMI_ConfigIndex; + + if (ue->frame_parms.frame_type == FDD) { + if (cqi_PMI_ConfigIndex <= 1) { // 2 ms CQI_PMI period + cqirep->Npd = 2; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex; + } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period + cqirep->Npd = 5; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-1; + } else if (cqi_PMI_ConfigIndex <=16) { // 10ms CQI_PMI period + cqirep->Npd = 10; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-6; + } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period + cqirep->Npd = 20; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-16; + } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period + cqirep->Npd = 40; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-36; + } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period + cqirep->Npd = 80; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-76; + } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period + cqirep->Npd = 160; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-156; + } + else if (cqi_PMI_ConfigIndex > 317) { + + if (cqi_PMI_ConfigIndex <= 349) { // 32 ms CQI_PMI period + cqirep->Npd = 32; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-316; + } + else if (cqi_PMI_ConfigIndex <= 413) { // 64 ms CQI_PMI period + cqirep->Npd = 64; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-349; + } + else if (cqi_PMI_ConfigIndex <= 541) { // 128 ms CQI_PMI period + cqirep->Npd = 128; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-413; + } + } + } + else { // TDD + if (cqi_PMI_ConfigIndex == 0) { // all UL subframes + cqirep->Npd = 1; + cqirep->N_OFFSET_CQI = 0; + } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period + cqirep->Npd = 5; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-1; + } else if (cqi_PMI_ConfigIndex <=16) { // 10ms CQI_PMI period + cqirep->Npd = 10; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-6; + } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period + cqirep->Npd = 20; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-16; + } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period + cqirep->Npd = 40; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-36; + } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period + cqirep->Npd = 80; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-76; + } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period + cqirep->Npd = 160; + cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-156; + } + } +} + +uint8_t is_cqi_TXOp(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id) +{ + int subframe = proc->subframe_tx; + int frame = proc->frame_tx; + CQI_REPORTPERIODIC *cqirep = &ue->cqi_report_config[eNB_id].CQI_ReportPeriodic; + + LOG_D(PHY,"[UE %d][SR %x] Frame %d subframe %d Checking for CQI TXOp (cqi_ConfigIndex %d)\n", + ue->Mod_id,ue->pdcch_vars[eNB_id]->crnti,frame,subframe, + cqirep->cqi_PMI_ConfigIndex); + + if (((10*frame + subframe) % cqirep->Npd) == cqirep->N_OFFSET_CQI) + return(1); + else + return(0); +} +uint8_t is_ri_TXOp(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id) +{ + + + int subframe = proc->subframe_tx; + int frame = proc->frame_tx; + CQI_REPORTPERIODIC *cqirep = &ue->cqi_report_config[eNB_id].CQI_ReportPeriodic; + int log2Mri = cqirep->ri_ConfigIndex/161; + int N_OFFSET_RI = cqirep->ri_ConfigIndex % 161; + + LOG_D(PHY,"[UE %d][SR %x] Frame %d subframe %d Checking for RI TXOp (ri_ConfigIndex %d)\n", + ue->Mod_id,ue->pdcch_vars[eNB_id]->crnti,frame,subframe, + cqirep->ri_ConfigIndex); + + if (((10*frame + subframe + cqirep->N_OFFSET_CQI - N_OFFSET_RI) % (cqirep->Npd<transmission_mode[eNB_id]<4)|| + (ue->transmission_mode[eNB_id]==7)) { // Mode 1-0 feedback + // 4-bit CQI message + *len=4; + return(sinr2cqi((double)ue->measurements.wideband_cqi_avg[eNB_id], + ue->transmission_mode[eNB_id])); + } + else { // Mode 1-1 feedback, later + *len=0; + // 2-antenna ports RI=1, 6 bits (2 PMI, 4 CQI) + + // 2-antenna ports RI=2, 8 bits (1 PMI, 7 CQI/DIFF CQI) + return(0); + } +} + + +int16_t get_pucch2_ri(PHY_VARS_UE *ue,int eNB_id) { + + return(1); +} + void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t abstraction_flag) { uint8_t pucch_ack_payload[2]; - uint8_t n1_pucch; + uint8_t n1_pucch,n2_pucch; ANFBmode_t bundling_flag; PUCCH_FMT_t format; + uint8_t SR_payload; + uint16_t CQI_payload; + uint16_t RI_payload; + LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; int frame_tx=proc->frame_tx; int subframe_tx=proc->subframe_tx; @@ -1210,7 +1344,7 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin #endif } } else if (SR_payload==1) { // no ACK/NAK but SR is triggered by MAC - + if (ue->mac_enabled == 1) { Po_PUCCH = pucch_power_cntl(ue,proc,subframe_tx,eNB_id,pucch_format1); } @@ -1258,6 +1392,107 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin } } // SR_Payload==1 + + // PUCCH 2x + + if (ue->generate_ul_signal[eNB_id] == 0) { // we have not generated ACK/NAK/SR in this subframe + + n2_pucch = ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PUCCH_ResourceIndex; + // only use format2 for now, i.e. now ACK/NAK - CQI multiplexing + format = pucch_format2; + + // Periodic CQI report + if ((ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex>0)&& + (is_cqi_TXOp(ue,proc,eNB_id)==1)){ + + if (ue->mac_enabled == 1) { + Po_PUCCH = pucch_power_cntl(ue,proc,subframe_tx,eNB_id,format); + } + else { + Po_PUCCH = ue->tx_power_max_dBm; + } + ue->tx_power_dBm[subframe_tx] = Po_PUCCH; + ue->tx_total_RE[subframe_tx] = 12; + +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) + tx_amp = get_tx_amp(Po_PUCCH, + ue->tx_power_max_dBm, + ue->frame_parms.N_RB_UL, + 1); +#else + tx_amp = AMP; +#endif + LOG_D(PHY,"[UE %d][SR %x] Frame %d subframe %d Generating PUCCH 2 (CQI), n2_pucch %d, Po_PUCCH %d\n", + Mod_id, + ue->dlsch[eNB_id][0]->rnti, + frame_tx, subframe_tx, + n2_pucch, + Po_PUCCH); + + int len; + // get the payload : < 12 bits, returned in len + CQI_payload = get_pucch2_cqi(ue,eNB_id,&len); + generate_pucch2x(ue->common_vars.txdataF, + &ue->frame_parms, + ue->ncs_cell, + format, + &ue->pucch_config_dedicated[eNB_id], + n2_pucch, + 1, // shortened format + &CQI_payload, + len, // A + 0, // B2 not needed + tx_amp, + subframe_tx, + ue->pdcch_vars[eNB_id]->crnti); + + } + // Periodic RI report + else if ((ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex>0) && + (is_ri_TXOp(ue,proc,eNB_id)==1)){ + + if (ue->mac_enabled == 1) { + Po_PUCCH = pucch_power_cntl(ue,proc,subframe_tx,eNB_id,format); + } + else { + Po_PUCCH = ue->tx_power_max_dBm; + } + ue->tx_power_dBm[subframe_tx] = Po_PUCCH; + ue->tx_total_RE[subframe_tx] = 12; + +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) + tx_amp = get_tx_amp(Po_PUCCH, + ue->tx_power_max_dBm, + ue->frame_parms.N_RB_UL, + 1); +#else + tx_amp = AMP; +#endif + LOG_D(PHY,"[UE %d][SR %x] Frame %d subframe %d Generating PUCCH 2 (RI), n2_pucch %d, Po_PUCCH %d\n", + Mod_id, + ue->dlsch[eNB_id][0]->rnti, + frame_tx, subframe_tx, + n2_pucch, + Po_PUCCH); + + RI_payload = get_pucch2_ri(ue,eNB_id); + + generate_pucch2x(ue->common_vars.txdataF, + &ue->frame_parms, + ue->ncs_cell, + format, + &ue->pucch_config_dedicated[eNB_id], + n2_pucch, + 1, // shortened format + &RI_payload, + 1, // A + 0, // B2 not needed + tx_amp, + subframe_tx, + ue->pdcch_vars[eNB_id]->crnti); + + } + } } void phy_procedures_UE_TX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t abstraction_flag,runmode_t mode,relaying_type_t r_type) { @@ -1299,7 +1534,10 @@ void phy_procedures_UE_TX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,ui } if (ue->UE_mode[eNB_id] == PUSCH) { // check if we need to use PUCCH 1a/1b - ue_pucch_procedures(ue,proc,eNB_id,abstraction_flag); + + ue_pucch_procedures(ue,proc,eNB_id,abstraction_flag); + + } // UE_mode==PUSCH diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 7946fdf663..2107ad0f9a 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -1006,7 +1006,7 @@ void dump_CCE_table(int *CCE_table,const int nCCE,const unsigned short rnti,cons for (i=0;i Date: Thu, 20 Oct 2016 16:36:43 +0300 Subject: [PATCH 248/413] Moved agent and protocol to flexran naming convention --- cmake_targets/CMakeLists.txt | 88 ++-- .../ENB_APP/MESSAGES/V2/config_common.proto | 142 +++--- .../ENB_APP/MESSAGES/V2/config_messages.proto | 44 +- .../MESSAGES/V2/control_delegation.proto | 4 +- .../MESSAGES/V2/controller_commands.proto | 26 +- openair2/ENB_APP/MESSAGES/V2/flexran.proto | 210 +++++++++ openair2/ENB_APP/MESSAGES/V2/header.proto | 38 +- .../ENB_APP/MESSAGES/V2/mac_primitives.proto | 48 +- openair2/ENB_APP/MESSAGES/V2/progran.proto | 210 --------- .../ENB_APP/MESSAGES/V2/stats_common.proto | 112 ++--- .../ENB_APP/MESSAGES/V2/stats_messages.proto | 60 +-- .../ENB_APP/MESSAGES/V2/time_common.proto | 20 +- openair2/ENB_APP/enb_agent.c | 16 +- openair2/ENB_APP/enb_agent_common.c | 406 ++++++++--------- openair2/ENB_APP/enb_agent_common.h | 76 ++-- openair2/ENB_APP/enb_agent_handler.c | 64 +-- openair2/ENB_APP/enb_agent_mac.c | 418 +++++++++--------- openair2/ENB_APP/enb_agent_mac.h | 34 +- openair2/ENB_APP/enb_agent_mac_defs.h | 12 +- openair2/ENB_APP/enb_agent_mac_internal.c | 166 +++---- openair2/ENB_APP/enb_agent_mac_internal.h | 32 +- openair2/ENB_APP/enb_agent_task_manager.c | 2 +- openair2/ENB_APP/enb_agent_task_manager.h | 8 +- .../MAC/eNB_agent_scheduler_dataplane.c | 84 ++-- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 64 +-- .../MAC/eNB_agent_scheduler_dlsch_ue_remote.c | 2 +- .../MAC/eNB_agent_scheduler_dlsch_ue_remote.h | 6 +- openair2/LAYER2/MAC/eNB_scheduler.c | 4 +- openair2/LAYER2/MAC/enb_agent_mac_proto.h | 10 +- ...onversions.h => flexran_dci_conversions.h} | 40 +- openair2/RRC/LITE/rrc_eNB.c | 4 +- 31 files changed, 1225 insertions(+), 1225 deletions(-) create mode 100644 openair2/ENB_APP/MESSAGES/V2/flexran.proto delete mode 100644 openair2/ENB_APP/MESSAGES/V2/progran.proto rename openair2/LAYER2/MAC/{progran_dci_conversions.h => flexran_dci_conversions.h} (58%) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index c93d7077fc..196baf166b 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -840,55 +840,55 @@ include_directories("${OPENAIR_DIR}") ################ if (ENB_AGENT_SB_IF) # set the version of protobuf messages, V3 not supported yet - add_list1_option(PRPT_VERSION V2 "PRPT MSG protobuf grammar version" V2 V3) + add_list1_option(FLPT_VERSION V2 "FLPT MSG protobuf grammar version" V2 V3) - if (${PRPT_VERSION} STREQUAL "V2") - set (PRPTDIR V2) - elseif (${PRPT_VERSION} STREQUAL "V3") - set (PRPTDIR V3) - endif(${PRPT_VERSION} STREQUAL "V2") + if (${FLPT_VERSION} STREQUAL "V2") + set (FLPTDIR V2) + elseif (${FLPT_VERSION} STREQUAL "V3") + set (FLPTDIR V3) + endif(${FLPT_VERSION} STREQUAL "V2") - set(PRPT_MSG_DIR ${OPENAIR2_DIR}/ENB_APP/MESSAGES/${PRPTDIR} ) - set(PRPT_MSG_FILES - ${PRPT_MSG_DIR}/header.proto - ${PRPT_MSG_DIR}/progran.proto - ${PRPT_MSG_DIR}/stats_common.proto - ${PRPT_MSG_DIR}/stats_messages.proto - ${PRPT_MSG_DIR}/time_common.proto - ${PRPT_MSG_DIR}/controller_commands.proto - ${PRPT_MSG_DIR}/mac_primitives.proto - ${PRPT_MSG_DIR}/config_messages.proto - ${PRPT_MSG_DIR}/config_common.proto - ${PRPT_MSG_DIR}/control_delegation.proto + set(FLPT_MSG_DIR ${OPENAIR2_DIR}/ENB_APP/MESSAGES/${FLPTDIR} ) + set(FLPT_MSG_FILES + ${FLPT_MSG_DIR}/header.proto + ${FLPT_MSG_DIR}/flexran.proto + ${FLPT_MSG_DIR}/stats_common.proto + ${FLPT_MSG_DIR}/stats_messages.proto + ${FLPT_MSG_DIR}/time_common.proto + ${FLPT_MSG_DIR}/controller_commands.proto + ${FLPT_MSG_DIR}/mac_primitives.proto + ${FLPT_MSG_DIR}/config_messages.proto + ${FLPT_MSG_DIR}/config_common.proto + ${FLPT_MSG_DIR}/control_delegation.proto ) - set(PRPT_C_DIR ${protobuf_generated_dir}/${PRPTDIR}) - #message("calling protoc_call=${protoc_call} PRPT_C_DIR=${PRPT_C_DIR} PRPT_MSG_FILES=${PRPT_MSG_FILES}") - execute_process(COMMAND ${protoc_call} ${PRPT_C_DIR} ${PRPT_MSG_DIR} ${PRPT_MSG_FILES}) - file(GLOB PRPT_source ${PRPT_C_DIR}/*.c) - set(PRPT_OAI_generated - ${PRPT_C_DIR}/header.pb-c.c - ${PRPT_C_DIR}/progran.pb-c.c - ${PRPT_C_DIR}/stats_common.pb-c.c - ${PRPT_C_DIR}/stats_messages.pb-c.c - ${PRPT_C_DIR}/time_common.pb-c.c - ${PRPT_C_DIR}/controller_commands.pb-c.c - ${PRPT_C_DIR}/mac_primitives.pb-c.c - ${PRPT_C_DIR}/config_messages.pb-c.c - ${PRPT_C_DIR}/config_common.pb-c.c - ${PRPT_C_DIR}/control_delegation.pb-c.c + set(FLPT_C_DIR ${protobuf_generated_dir}/${FLPTDIR}) + #message("calling protoc_call=${protoc_call} FLPT_C_DIR=${FLPT_C_DIR} FLPT_MSG_FILES=${FLPT_MSG_FILES}") + execute_process(COMMAND ${protoc_call} ${FLPT_C_DIR} ${FLPT_MSG_DIR} ${FLPT_MSG_FILES}) + file(GLOB FLPT_source ${FLPT_C_DIR}/*.c) + set(FLPT_OAI_generated + ${FLPT_C_DIR}/header.pb-c.c + ${FLPT_C_DIR}/flexran.pb-c.c + ${FLPT_C_DIR}/stats_common.pb-c.c + ${FLPT_C_DIR}/stats_messages.pb-c.c + ${FLPT_C_DIR}/time_common.pb-c.c + ${FLPT_C_DIR}/controller_commands.pb-c.c + ${FLPT_C_DIR}/mac_primitives.pb-c.c + ${FLPT_C_DIR}/config_messages.pb-c.c + ${FLPT_C_DIR}/config_common.pb-c.c + ${FLPT_C_DIR}/control_delegation.pb-c.c ) - file(GLOB prpt_h ${PRPT_C_DIR}/*.h) - set(prpt_h ${prpt_h} ) + file(GLOB flpt_h ${FLPT_C_DIR}/*.h) + set(flpt_h ${flpt_h} ) - add_library(PRPT_MSG - ${PRPT_OAI_generated} - ${PRPT_source} + add_library(FLPT_MSG + ${FLPT_OAI_generated} + ${FLPT_source} ) - set(PRPT_MSG_LIB PRPT_MSG) - #message("prpt c dir is : ${PRPT_C_DIR}") - include_directories (${PRPT_C_DIR}) + set(FLPT_MSG_LIB FLPT_MSG) + #message("prpt c dir is : ${FLPT_C_DIR}") + include_directories (${FLPT_C_DIR}) add_library(ASYNC_IF ${OPENAIR2_DIR}/UTIL/ASYNC_IF/socket_link.c @@ -1757,7 +1757,7 @@ add_executable(lte-softmodem target_link_libraries (lte-softmodem -ldl -Wl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} LFDS7 + RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} LFDS7 -Wl,--end-group ) target_link_libraries (lte-softmodem ${LIBXML2_LIBRARIES}) @@ -1791,7 +1791,7 @@ add_executable(lte-softmodem-nos1 ) target_link_libraries (lte-softmodem-nos1 -Wl,--start-group - RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} LFDS7 + RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} LFDS7 -Wl,--end-group ) target_link_libraries (lte-softmodem-nos1 ${LIBXML2_LIBRARIES}) @@ -1936,7 +1936,7 @@ add_executable(oaisim_nos1 target_include_directories(oaisim_nos1 PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim_nos1 -Wl,--start-group - RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${PRPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} LFDS7 + RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} LFDS7 -Wl,--end-group ) target_link_libraries (oaisim_nos1 ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) diff --git a/openair2/ENB_APP/MESSAGES/V2/config_common.proto b/openair2/ENB_APP/MESSAGES/V2/config_common.proto index cf07f423aa..51ae711277 100644 --- a/openair2/ENB_APP/MESSAGES/V2/config_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/config_common.proto @@ -5,64 +5,64 @@ package protocol; // Cell config related structures and enums // -message prp_si_config { +message flex_si_config { optional uint32 sfn = 1; optional uint32 sib1_length = 2; // The length of SIB1 in bytes optional uint32 si_window_length = 3; // The scheduling window for all SIs in SF - repeated prp_si_message si_message = 4; // List of SI messages to be sent. + repeated flex_si_message si_message = 4; // List of SI messages to be sent. // The index identifies the type of an SI message // 0 - SIB1 // 1..31 - SIx // 32..63 - PCCH } -message prp_si_message { +message flex_si_message { optional uint32 periodicity = 1; // Periodicity of SI msg in radio frames optional uint32 length = 2; // The length of the SI message in bytes } -enum prp_hopping_mode { - PRHM_INTER = 0; - PRHM_INTERINTRA = 1; +enum flex_hopping_mode { + FLHM_INTER = 0; + FLHM_INTERINTRA = 1; } -enum prp_phich_resource { - PRPR_ONE_SIXTH = 0; - PRPR_HALF = 1; - PRPR_ONE = 2; - PRPR_TWO = 3; +enum flex_phich_resource { + FLPR_ONE_SIXTH = 0; + FLPR_HALF = 1; + FLPR_ONE = 2; + FLPR_TWO = 3; } -enum prp_phich_duration { - PRPD_NORMAL = 0; - PRPD_EXTENDED = 1; +enum flex_phich_duration { + FLPD_NORMAL = 0; + FLPD_EXTENDED = 1; } -enum prp_ul_cyclic_prefix_length { - PRUCPL_NORMAL = 0; - PRUCPL_EXTENDED = 1; +enum flex_ul_cyclic_prefix_length { + FLUCPL_NORMAL = 0; + FLUCPL_EXTENDED = 1; } -enum prp_dl_cyclic_prefix_length { - PRDCPL_NORMAL = 0; - PRDCPL_EXTENDED = 1; +enum flex_dl_cyclic_prefix_length { + FLDCPL_NORMAL = 0; + FLDCPL_EXTENDED = 1; } -enum prp_duplex_mode { - PRDM_TDD = 0; - PRDM_FDD = 1; +enum flex_duplex_mode { + FLDM_TDD = 0; + FLDM_FDD = 1; } -enum prp_qam { - PREQ_MOD_16QAM = 0; - PREQ_MOD_64QAM = 1; +enum flex_qam { + FLEQ_MOD_16QAM = 0; + FLEQ_MOD_64QAM = 1; } // // UE config related structures and enums // -message prp_drx_config { +message flex_drx_config { optional uint32 on_duration_timer = 1; // Timer in SF. See TS 36.321 optional uint32 drx_inactivity_timer = 2; // Timer in SF. See TS 36.321 optional uint32 drx_retransmission_timer = 3; // Timer in SF. See TS 36.321 @@ -72,30 +72,30 @@ message prp_drx_config { optional uint32 drx_short_cycle_timer = 7; // Timer in subframes. See TS 36.321 } -message prp_sps_config { +message flex_sps_config { optional uint32 semi_persistent_sched_interval_UL = 1; // SPS UL scheduling interval in SF optional uint32 semi_persistent_sched_interval_DL = 2; // SPS DL scheduling interval in SF optional uint32 num_of_conf_sps_proc = 3; // Number of SPS HARQ processes. See TS 36.321 repeated uint32 n1_PUCCH_AN_persistent_element = 4;// See TS36.213. Ignored when config is used - // as part of PRPT_SET_UE_CONFIG + // as part of FLPT_SET_UE_CONFIG optional uint32 implicit_release_after = 5; // number of empty transmissions before release of SPS } -message prp_sr_config { +message flex_sr_config { optional uint32 sr_action = 1; // Indicates if SR config should be changed or released - // One of the PRSRA_* enum values + // One of the FLSRA_* enum values optional uint32 sched_interval = 2; // SR scheduling interval in SF optional uint32 dsr_trans_max = 3; // See TS 36.213 } -message prp_cqi_config { +message flex_cqi_config { optional uint32 cqi_action = 1; // Indicats if CQI changed or released. - // One of the PRSRA_* enum values + // One of the FLSRA_* enum values optional uint32 cqi_sched_interval = 2; // CQI scheduling interval in SF optional uint32 ri_sched_interval = 3; // RI scheduling interval in SF } -message prp_ue_capabilities { +message flex_ue_capabilities { optional uint32 half_duplex = 1; // Boolean value. Only half duplex support. FDD operation optional uint32 intra_SF_hopping = 2; // Support for intra-subframe hopping. Boolean value optional uint32 type2_sb_1 = 3; // Support for type 2 hopping with n_sb > 1 @@ -103,7 +103,7 @@ message prp_ue_capabilities { optional uint32 res_alloc_type1 = 5; // Boolean value. UE support for resource allocation type 1 } -message prp_scell_config { +message flex_scell_config { optional uint32 carrier_index = 1; // Id of the carrier component optional uint32 scell_index = 2; // Index of this Scell (RRC SCellIndex) optional uint32 use_ccs = 3; // Boolean value. Indicates if cross-carrier scheduling @@ -113,46 +113,46 @@ message prp_scell_config { optional uint32 pdsch_start = 5; // Starting OFDM symbol of PDSCH data region for this SCell } -enum prp_meas_gap_config_pattern { - PRMGCP_GP1 = 0; - PRMGCP_GP2 = 1; - PRMGCP_OFF = 2; +enum flex_meas_gap_config_pattern { + FLMGCP_GP1 = 0; + FLMGCP_GP2 = 1; + FLMGCP_OFF = 2; } -enum prp_setup_release_action { - PRSRA_SETUP = 0; - PRSRA_RELEASE = 1; +enum flex_setup_release_action { + FLSRA_SETUP = 0; + FLSRA_RELEASE = 1; } -enum prp_ue_transmission_antenna { - PRUTA_NONE = 0; - PRUTA_OPEN_LOOP = 1; - PRUTA_CLOSED_LOOP = 2; +enum flex_ue_transmission_antenna { + FLUTA_NONE = 0; + FLUTA_OPEN_LOOP = 1; + FLUTA_CLOSED_LOOP = 2; } -enum prp_aperiodic_cqi_report_mode { - PRACRM_RM12 = 0; - PRACRM_RM20 = 1; - PRACRM_RM22 = 2; - PRACRM_RM30 = 3; - PRACRM_RM31 = 4; - PRACRM_NONE = 5; +enum flex_aperiodic_cqi_report_mode { + FLACRM_RM12 = 0; + FLACRM_RM20 = 1; + FLACRM_RM22 = 2; + FLACRM_RM30 = 3; + FLACRM_RM31 = 4; + FLACRM_NONE = 5; } -enum prp_tdd_ack_nack_feedback_mode { - PRTANFM_BUNDLING = 0; - PRTANFM_MULTIPLEXING = 1; +enum flex_tdd_ack_nack_feedback_mode { + FLTANFM_BUNDLING = 0; + FLTANFM_MULTIPLEXING = 1; } // // Logical channel config related structures and enums // -message prp_lc_config { +message flex_lc_config { optional uint32 lcid = 1; // The logical channel id optional uint32 lcg = 2; // The logical channel group (0..3) the LC is mapped to - optional uint32 direction = 3; // The LC direction. One of the PRLCD_* enum values - optional uint32 qos_bearer_type = 4;// GBR or NGBR bearer. One of the PRQBT_* enum values + optional uint32 direction = 3; // The LC direction. One of the FLLCD_* enum values + optional uint32 qos_bearer_type = 4;// GBR or NGBR bearer. One of the FLQBT_* enum values optional uint32 qci = 5; // The QCI defined in TS 23.203, coded as defined in TS 36.413 // One less than the actual QCI value optional uint64 e_RAB_max_bitrate_UL = 6; // In bps (GBR only) @@ -161,20 +161,20 @@ message prp_lc_config { optional uint64 e_RAB_guaranteed_bitrate_DL = 9; // In bps (GBR only) } -enum prp_lc_direction { - PRLCD_UL = 0; - PRLCD_DL = 1; - PRLCD_BOTH = 2; +enum flex_lc_direction { + FLLCD_UL = 0; + FLLCD_DL = 1; + FLLCD_BOTH = 2; } -enum prp_qos_bearer_type { - PRQBT_NON_GBR = 0; - PRQBT_GBR = 1; +enum flex_qos_bearer_type { + FLQBT_NON_GBR = 0; + FLQBT_GBR = 1; } -enum prp_ue_state_change_type { - PRUESC_UPDATED = 0; - PRUESC_ACTIVATED = 1; - PRUESC_DEACTIVATED = 2; - PRUESC_MOVED = 3; +enum flex_ue_state_change_type { + FLUESC_UPDATED = 0; + FLUESC_ACTIVATED = 1; + FLUESC_DEACTIVATED = 2; + FLUESC_MOVED = 3; } \ No newline at end of file diff --git a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto index 4e1151a7e8..441e193569 100644 --- a/openair2/ENB_APP/MESSAGES/V2/config_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/config_messages.proto @@ -3,23 +3,23 @@ package protocol; import "config_common.proto"; -message prp_cell_config { +message flex_cell_config { optional uint32 phy_cell_id = 1; // The PCI of this cell optional uint32 cell_id = 2; // The PLMN cell id of this cell optional uint32 pusch_hopping_offset = 3; // PUSCH resources in RBs for hopping - optional uint32 hopping_mode = 4; // One of the PRHM_* enum values + optional uint32 hopping_mode = 4; // One of the FLHM_* enum values optional uint32 n_sb = 5; // The number of subbands optional uint32 phich_resource = 6; // The number of REGs used for PHICH - // One of the PRPR_* enum values - optional uint32 phich_duration = 7; // One of the PRPD_* enum values + // One of the FLPR_* enum values + optional uint32 phich_duration = 7; // One of the FLPD_* enum values optional uint32 init_nr_PDCCH_OFDM_sym = 8; // See TS 36.211, section 6.9 - optional prp_si_config si_config = 9; // The SI configuration + optional flex_si_config si_config = 9; // The SI configuration optional uint32 dl_bandwidth = 10; // The DL transmission bandwidth in RBs optional uint32 ul_bandwidth = 11; // The UL transmission bandwidth in RBs - optional uint32 ul_cyclic_prefix_length = 13; // One of the PRUCPL_* enum values - optional uint32 dl_cyclic_prefix_length = 14; // One of the PRDCPL_* enum values + optional uint32 ul_cyclic_prefix_length = 13; // One of the FLUCPL_* enum values + optional uint32 dl_cyclic_prefix_length = 14; // One of the FLDCPL_* enum values optional uint32 antenna_ports_count = 15; // Number of cell specific antenna ports - optional uint32 duplex_mode = 16; // One of the PRDM_* enum values + optional uint32 duplex_mode = 16; // One of the FLDM_* enum values optional uint32 subframe_assignment = 17; // DL/UL subframe assignment. TDD only optional uint32 special_subframe_patterns = 18; // TDD only. See TS 36.211, table 4.2.1 repeated uint32 mbsfn_subframe_config_rfperiod = 19; // The MBSFN radio frame period (Optional) @@ -36,30 +36,30 @@ message prp_cell_config { optional uint32 srs_subframe_config = 30; // See TS 36.211, table 5.5.3.3-1 and 2 optional uint32 srs_bw_config = 31; // See TS 36.211, section 5.5.3.2 optional uint32 srs_mac_up_pts = 32; // Boolean value. See TS 36.211, section 5.5.3.2. TDD only - optional uint32 enable_64QAM = 33; // One of the PREQ_* enum values + optional uint32 enable_64QAM = 33; // One of the FLEQ_* enum values optional uint32 carrier_index = 34; // Carrier component index } -message prp_ue_config { +message flex_ue_config { optional uint32 rnti = 1; - optional prp_drx_config drx_config = 2; // The DRX configuration (Optional) + optional flex_drx_config drx_config = 2; // The DRX configuration (Optional) optional uint32 time_alignment_timer = 3; // Timer in SF. Control the synchronization // status of the UE, not the actual advance procedure // See TS 36.321 optional uint32 meas_gap_config_pattern = 4; // Measurement gap configuration. - // One of the PRMGCP_* enum values + // One of the FLMGCP_* enum values // See TS 36.133 optional uint32 meas_gap_config_sf_offset = 5; // Measurement gap offset if applicable - optional prp_sps_config sps_config = 6; // The SPS configuration (Optional) - optional prp_sr_config sr_config = 7; // The SR configuration (Optional) - optional prp_cqi_config cqi_config = 8; // The CQI configuration (Optional) + optional flex_sps_config sps_config = 6; // The SPS configuration (Optional) + optional flex_sr_config sr_config = 7; // The SR configuration (Optional) + optional flex_cqi_config cqi_config = 8; // The CQI configuration (Optional) optional uint32 transmission_mode = 9; // The UE transmission mode optional uint64 ue_aggregated_max_bitrate_UL = 10; // Aggregated bit-rate of non-gbr bearer // per UE. See TS 36.413 optional uint64 ue_aggregated_max_bitrate_DL = 11; // Aggregated bit-rate of non-gbr bearer // per UE. See TS 36.413 - optional prp_ue_capabilities capabilities = 12; - optional uint32 ue_transmission_antenna = 13; // One of the PRUTA_* enum values + optional flex_ue_capabilities capabilities = 12; + optional uint32 ue_transmission_antenna = 13; // One of the FLUTA_* enum values optional uint32 tti_bundling = 14; // Boolean value. See TS 36.321 optional uint32 max_HARQ_tx = 15; // The max HARQ retransmission for UL optional uint32 beta_offset_ACK_index = 16; // See TS 36.213 @@ -67,20 +67,20 @@ message prp_ue_config { optional uint32 beta_offset_CQI_index = 18; // See TS 36.213 optional uint32 ack_nack_simultaneous_trans = 19;// Boolean. See TS 36.213 optional uint32 simultaneous_ack_nack_cqi = 20; // Boolean. See TS 36.213 - optional uint32 aperiodic_cqi_rep_mode = 21; // One of the PRACRM_* enum values - optional uint32 tdd_ack_nack_feedback = 22; // One of the PRTANFM_* enum values + optional uint32 aperiodic_cqi_rep_mode = 21; // One of the FLACRM_* enum values + optional uint32 tdd_ack_nack_feedback = 22; // One of the FLTANFM_* enum values optional uint32 ack_nack_repetition_factor = 23;// See TS 36.213, section 10.1 optional uint32 extended_bsr_size = 24; // Boolean for extended BSR size optional uint32 ca_support = 25; // Boolean. Support for carrier aggregation optional uint32 cross_carrier_sched_support = 26; // Boolean value optional uint32 pcell_carrier_index = 27; // Index of primary cell - repeated prp_scell_config scell_config = 28; // Secondary cells configuration + repeated flex_scell_config scell_config = 28; // Secondary cells configuration optional uint32 scell_deactivation_timer = 29;// Deactivation timer for secondary cell } -message prp_lc_ue_config { +message flex_lc_ue_config { optional uint32 rnti = 1; - repeated prp_lc_config lc_config = 2; // A list of LC configurations for the given UE + repeated flex_lc_config lc_config = 2; // A list of LC configurations for the given UE } diff --git a/openair2/ENB_APP/MESSAGES/V2/control_delegation.proto b/openair2/ENB_APP/MESSAGES/V2/control_delegation.proto index c5ce58d3a2..3a5efaf7d4 100644 --- a/openair2/ENB_APP/MESSAGES/V2/control_delegation.proto +++ b/openair2/ENB_APP/MESSAGES/V2/control_delegation.proto @@ -1,6 +1,6 @@ //'syntax = "proto2";' package protocol; -enum prp_control_delegation_type { - PRCDT_MAC_DL_UE_SCHEDULER = 1; // DL UE scheduler delegation +enum flex_control_delegation_type { + FLCDT_MAC_DL_UE_SCHEDULER = 1; // DL UE scheduler delegation } \ No newline at end of file diff --git a/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto b/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto index 4ef8c0a370..cbec332b30 100644 --- a/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto +++ b/openair2/ENB_APP/MESSAGES/V2/controller_commands.proto @@ -6,11 +6,11 @@ import "mac_primitives.proto"; // Body of UE DL MAC scheduling configuration info // -message prp_dl_data { +message flex_dl_data { optional uint32 rnti = 1; - optional prp_dl_dci dl_dci = 2; + optional flex_dl_dci dl_dci = 2; repeated uint32 ce_bitmap = 3; // list of 2 MAC CEs, one for each TB - repeated prp_rlc_pdu rlc_pdu = 4; // list of parameters for the creation of RLC PDUs. One for each lcid + repeated flex_rlc_pdu rlc_pdu = 4; // list of parameters for the creation of RLC PDUs. One for each lcid optional uint32 serv_cell_index = 5; optional uint32 act_deact_ce = 6; //Hex content of MAC CE for Activation/Deactivation in CA } @@ -18,10 +18,10 @@ message prp_dl_data { // // Body of the RAR scheduler configuration // -message prp_dl_rar { +message flex_dl_rar { optional uint32 rnti = 1; optional uint32 grant = 2; // The 20-bit UL grant. TS 36.213, sec 6.2 - optional prp_dl_dci rar_dci = 3; + optional flex_dl_dci rar_dci = 3; optional uint32 carrier_index = 4; // The carrier index for the RAR } @@ -29,13 +29,13 @@ message prp_dl_rar { // Body of the paging/broadcast configuration message // -message prp_dl_broadcast { - optional uint32 type = 1; // The PRBT_* values +message flex_dl_broadcast { + optional uint32 type = 1; // The FLBT_* values optional uint32 index = 2; // Index of the broadcast message: // 0 - SIB1, // 1..31 - Six, - // 32..63 - PCCH (PCCH index obtained from prp_paging_info) - optional prp_dl_dci broad_dci = 3; + // 32..63 - PCCH (PCCH index obtained from flex_paging_info) + optional flex_dl_dci broad_dci = 3; optional uint32 carrier_index = 4; // Index of the carrier for broadcast } @@ -43,7 +43,7 @@ message prp_dl_broadcast { // Body of the OFDM symbol count message // -message prp_pdcch_ofdm_sym_count { +message flex_pdcch_ofdm_sym_count { optional uint32 carrier_index = 1; optional uint32 num_pdcch_ofdm_symbols = 2; } @@ -52,7 +52,7 @@ message prp_pdcch_ofdm_sym_count { // Types of commands related enums // -enum prp_broadcast_type { - PRBT_BCCH = 0; - PRBT_PCCH = 1; +enum flex_broadcast_type { + FLBT_BCCH = 0; + FLBT_PCCH = 1; } \ No newline at end of file diff --git a/openair2/ENB_APP/MESSAGES/V2/flexran.proto b/openair2/ENB_APP/MESSAGES/V2/flexran.proto new file mode 100644 index 0000000000..3a1d40bca6 --- /dev/null +++ b/openair2/ENB_APP/MESSAGES/V2/flexran.proto @@ -0,0 +1,210 @@ +//'syntax = "proto2";' +package protocol; + +import "stats_messages.proto"; +import "header.proto"; +import "time_common.proto"; +import "config_messages.proto"; +import "controller_commands.proto"; +import "control_delegation.proto"; + +message flexran_message { + optional flexran_direction msg_dir = 100; + oneof msg { + flex_hello hello_msg = 1; + flex_echo_request echo_request_msg = 2; + flex_echo_reply echo_reply_msg = 3; + flex_stats_request stats_request_msg = 4; + flex_stats_reply stats_reply_msg = 5; + flex_sf_trigger sf_trigger_msg = 6; + flex_ul_sr_info ul_sr_info_msg = 7; + flex_enb_config_request enb_config_request_msg = 8; + flex_enb_config_reply enb_config_reply_msg = 9; + flex_ue_config_request ue_config_request_msg = 10; + flex_ue_config_reply ue_config_reply_msg = 11; + 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_ue_state_change ue_state_change_msg = 15; + flex_control_delegation control_delegation_msg = 16; + flex_agent_reconfiguration agent_reconfiguration_msg = 17; + } +} + +enum flexran_direction { + //option allow_alias = true; + NOT_SET = 0; + INITIATING_MESSAGE = 1; + SUCCESSFUL_OUTCOME=2; + UNSUCCESSFUL_OUTCOME=3; +} + +enum flexran_err { + option allow_alias = true; + // message errors + NO_ERR = 0; + MSG_DEQUEUING = -1; + MSG_ENQUEUING = -2; + MSG_DECODING = -3; + MSG_ENCODING = -4; + MSG_BUILD = -5; + MSG_NOT_SUPPORTED = -6; + MSG_NOT_HANDLED = -7; + MSG_NOT_VALIDATED = -8; + MSG_OUT_DATED = -9; + + + // other erros + UNEXPECTED = -100; +} + +// +// Maintenance and discovery messages +// + +message flex_hello { + optional flex_header header = 1; +} + +message flex_echo_request { + optional flex_header header = 1; + extensions 100 to 199; +} + + +message flex_echo_reply { + optional flex_header header = 1; + extensions 100 to 199; +} + + +// +// Statistics request and reply message +// + +message flex_stats_request { + optional flex_header header = 1; + optional flex_stats_type type = 2; + oneof body { + flex_complete_stats_request complete_stats_request = 3; + flex_cell_stats_request cell_stats_request = 4; + flex_ue_stats_request ue_stats_request = 5; + } +} + +message flex_stats_reply { + optional flex_header header = 1; + repeated flex_ue_stats_report ue_report = 2; + repeated flex_cell_stats_report cell_report = 3; +} + +// +// Time indication messages +// + +message flex_sf_trigger { + optional flex_header header = 1; + optional uint32 sfn_sf = 2; + repeated flex_dl_info dl_info = 3; + repeated flex_ul_info ul_info = 4; +} + +// +// Asynchronous messages +// + +message flex_ul_sr_info { + optional flex_header header = 1; + optional uint32 sfn_sf = 2; + repeated uint32 rnti = 3; +} + +// +// eNB configuration messages +// +message flex_enb_config_request { + optional flex_header header = 1; +} + +message flex_enb_config_reply { + optional flex_header header = 1; + optional uint32 eNB_id = 2; // Unique id to distinguish the eNB + repeated flex_cell_config cell_config = 3; +} + +message flex_ue_config_request { + optional flex_header header = 1; +} + +message flex_ue_config_reply { + optional flex_header header = 1; + repeated flex_ue_config ue_config = 2; +} + +message flex_lc_config_request { + optional flex_header header = 1; +} + +message flex_lc_config_reply { + optional flex_header header = 1; + repeated flex_lc_ue_config lc_ue_config = 2; +} + +// +// Controller command messages +// + +message flex_dl_mac_config { + optional flex_header header = 1; + optional uint32 sfn_sf = 2; + repeated flex_dl_data dl_ue_data = 3; + repeated flex_dl_rar dl_rar = 4; + repeated flex_dl_broadcast dl_broadcast = 5; + repeated flex_pdcch_ofdm_sym_count ofdm_sym = 6; // OFDM symbol count for each CC +} + +// +// UE state change message +// + +message flex_ue_state_change { + optional flex_header header = 1; + optional uint32 type = 2; // One of the FLUESC_* values + optional flex_ue_config config = 3; // Body of the message (based on type) +} + +// +// Control delegation message +// + +message flex_control_delegation { + optional flex_header header = 1; + optional uint32 delegation_type = 2; // Bitmap of FLCDT_* flags + optional bytes payload = 3; // Byte array of shared lib containing the delegated functions + optional string name = 4; // The delegated functions names ordered based on bitmap flags +} + +// +// Agent reconfiguration message +// + +message flex_agent_reconfiguration { + optional flex_header header = 1; + optional string policy = 2; // The policy changes using YAML syntax in string format +} + +// Extensions of the echo request and reply +// messages for carrying a latency value in ms +message flex_echo_request_latency { + extend flex_echo_request { + optional uint32 latency = 100; + } +} + +message flex_echo_reply_latency { + extend flex_echo_reply { + optional uint32 latency = 100; + } +} + + diff --git a/openair2/ENB_APP/MESSAGES/V2/header.proto b/openair2/ENB_APP/MESSAGES/V2/header.proto index 44ad93e16b..dfd5ea6c99 100644 --- a/openair2/ENB_APP/MESSAGES/V2/header.proto +++ b/openair2/ENB_APP/MESSAGES/V2/header.proto @@ -1,43 +1,43 @@ package protocol; -message prp_header { +message flex_header { optional uint32 version = 1; optional uint32 type = 2; optional uint32 xid = 4; } -enum prp_type { +enum flex_type { // Discovery and maintenance messages - PRPT_HELLO = 0; - PRPT_ECHO_REQUEST = 1; - PRPT_ECHO_REPLY = 2; + FLPT_HELLO = 0; + FLPT_ECHO_REQUEST = 1; + FLPT_ECHO_REPLY = 2; // Statistics and measurement messages - PRPT_STATS_REQUEST = 3; - PRPT_STATS_REPLY = 4; + FLPT_STATS_REQUEST = 3; + FLPT_STATS_REPLY = 4; // Time indication messages - PRPT_SF_TRIGGER = 5; + FLPT_SF_TRIGGER = 5; // Asynchronous messages - PRPT_UL_SR_INFO = 6; + FLPT_UL_SR_INFO = 6; // eNB configuration messages - PRPT_GET_ENB_CONFIG_REQUEST = 7; - PRPT_GET_ENB_CONFIG_REPLY = 8; - PRPT_GET_UE_CONFIG_REQUEST = 9; - PRPT_GET_UE_CONFIG_REPLY = 10; - PRPT_GET_LC_CONFIG_REQUEST = 11; - PRPT_GET_LC_CONFIG_REPLY = 12; + FLPT_GET_ENB_CONFIG_REQUEST = 7; + FLPT_GET_ENB_CONFIG_REPLY = 8; + FLPT_GET_UE_CONFIG_REQUEST = 9; + FLPT_GET_UE_CONFIG_REPLY = 10; + FLPT_GET_LC_CONFIG_REQUEST = 11; + FLPT_GET_LC_CONFIG_REPLY = 12; //Controller command messages - PRPT_DL_MAC_CONFIG = 13; + FLPT_DL_MAC_CONFIG = 13; // UE state change messages - PRPT_UE_STATE_CHANGE = 14; + FLPT_UE_STATE_CHANGE = 14; // Control delegation messages - PRPT_DELEGATE_CONTROL = 15; - PRPT_RECONFIGURE_AGENT = 16; + FLPT_DELEGATE_CONTROL = 15; + FLPT_RECONFIGURE_AGENT = 16; } diff --git a/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto index 4378e6d668..be7c72ab7b 100644 --- a/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto +++ b/openair2/ENB_APP/MESSAGES/V2/mac_primitives.proto @@ -4,7 +4,7 @@ package protocol; // Message containing the DL DCI info // -message prp_dl_dci { +message flex_dl_dci { optional uint32 rnti = 1; optional uint32 res_alloc = 2; // Type of resource allocation optional uint32 rb_bitmap = 3; // Bitmap for RB allocation @@ -17,17 +17,17 @@ message prp_dl_dci { optional uint32 aggr_level = 10; optional uint32 precoding_info = 11; // 2 antenna ports:0..6, // 4 antenna ports:0..50 - optional uint32 format = 12; // DCI format. A PRDCIF_* value + optional uint32 format = 12; // DCI format. A FLDCIF_* value optional uint32 tpc = 13; // TS 36.213, sec 5.1.1.1 optional uint32 harq_process = 14; // HARQ process ID optional uint32 dai = 15; // TDD only - optional uint32 vrb_format = 16; // One of the PRVRBF_* values + optional uint32 vrb_format = 16; // One of the FLVRBF_* values optional uint32 tb_swap = 17; // Boolean. TB to codeword swap flag optional uint32 sps_release = 18; // Flag value optional uint32 pdcch_order = 19; optional uint32 preamble_index = 20; // Only valid if pdcch_order = 1 optional uint32 prach_mask_index = 21; // Only valid if pdcch_order = 1 - optional uint32 n_gap = 22; // One of the PRNGV_* values + optional uint32 n_gap = 22; // One of the FLNGV_* values optional uint32 tbs_idx = 23; // The TBS index for Format 1A optional uint32 dl_power_offset = 24; // For format 1D optional uint32 pdcch_power_offset = 25; // DL PDCCH power boosting in dB @@ -39,11 +39,11 @@ message prp_dl_dci { // Messages related to the creation of RLC PDUs // -message prp_rlc_pdu { - repeated prp_rlc_pdu_tb rlc_pdu_tb = 1; // list of parameters for the creation of RLC PDUs. One for each TB +message flex_rlc_pdu { + repeated flex_rlc_pdu_tb rlc_pdu_tb = 1; // list of parameters for the creation of RLC PDUs. One for each TB } -message prp_rlc_pdu_tb { +message flex_rlc_pdu_tb { optional uint32 logical_channel_id = 1; optional uint32 size = 2; // Maximum RLC PDU to be created in bytes } @@ -52,25 +52,25 @@ message prp_rlc_pdu_tb { // MAC content types related enums // -enum prp_dci_format { - PRDCIF_1 = 0; - PRDCIF_1A = 1; - PRDCIF_1B = 2; - PRDCIF_1C = 3; - PRDCIF_1D = 4; - PRDCIF_2 = 5; - PRDCIF_2A = 6; - PRDCIF_2B = 7; - PRDCIF_3 = 8; - PRDCIF_3A = 9; +enum flex_dci_format { + FLDCIF_1 = 0; + FLDCIF_1A = 1; + FLDCIF_1B = 2; + FLDCIF_1C = 3; + FLDCIF_1D = 4; + FLDCIF_2 = 5; + FLDCIF_2A = 6; + FLDCIF_2B = 7; + FLDCIF_3 = 8; + FLDCIF_3A = 9; } -enum prp_vrb_format { - PRVRBF_LOCALIZED = 0; - PRVRBF_DISTRIBUTED = 1; +enum flex_vrb_format { + FLVRBF_LOCALIZED = 0; + FLVRBF_DISTRIBUTED = 1; } -enum prp_ngap_val { - PRNGV_1 = 0; - PRNGV_2 = 1; +enum flex_ngap_val { + FLNGV_1 = 0; + FLNGV_2 = 1; } \ No newline at end of file diff --git a/openair2/ENB_APP/MESSAGES/V2/progran.proto b/openair2/ENB_APP/MESSAGES/V2/progran.proto deleted file mode 100644 index 235aba4363..0000000000 --- a/openair2/ENB_APP/MESSAGES/V2/progran.proto +++ /dev/null @@ -1,210 +0,0 @@ -//'syntax = "proto2";' -package protocol; - -import "stats_messages.proto"; -import "header.proto"; -import "time_common.proto"; -import "config_messages.proto"; -import "controller_commands.proto"; -import "control_delegation.proto"; - -message progran_message { - optional progran_direction msg_dir = 100; - oneof msg { - prp_hello hello_msg = 1; - prp_echo_request echo_request_msg = 2; - prp_echo_reply echo_reply_msg = 3; - prp_stats_request stats_request_msg = 4; - prp_stats_reply stats_reply_msg = 5; - prp_sf_trigger sf_trigger_msg = 6; - prp_ul_sr_info ul_sr_info_msg = 7; - prp_enb_config_request enb_config_request_msg = 8; - prp_enb_config_reply enb_config_reply_msg = 9; - prp_ue_config_request ue_config_request_msg = 10; - prp_ue_config_reply ue_config_reply_msg = 11; - prp_lc_config_request lc_config_request_msg = 12; - prp_lc_config_reply lc_config_reply_msg = 13; - prp_dl_mac_config dl_mac_config_msg = 14; - prp_ue_state_change ue_state_change_msg = 15; - prp_control_delegation control_delegation_msg = 16; - prp_agent_reconfiguration agent_reconfiguration_msg = 17; - } -} - -enum progran_direction { - //option allow_alias = true; - NOT_SET = 0; - INITIATING_MESSAGE = 1; - SUCCESSFUL_OUTCOME=2; - UNSUCCESSFUL_OUTCOME=3; -} - -enum progran_err { - option allow_alias = true; - // message errors - NO_ERR = 0; - MSG_DEQUEUING = -1; - MSG_ENQUEUING = -2; - MSG_DECODING = -3; - MSG_ENCODING = -4; - MSG_BUILD = -5; - MSG_NOT_SUPPORTED = -6; - MSG_NOT_HANDLED = -7; - MSG_NOT_VALIDATED = -8; - MSG_OUT_DATED = -9; - - - // other erros - UNEXPECTED = -100; -} - -// -// Maintenance and discovery messages -// - -message prp_hello { - optional prp_header header = 1; -} - -message prp_echo_request { - optional prp_header header = 1; - extensions 100 to 199; -} - - -message prp_echo_reply { - optional prp_header header = 1; - extensions 100 to 199; -} - - -// -// Statistics request and reply message -// - -message prp_stats_request { - optional prp_header header = 1; - optional prp_stats_type type = 2; - oneof body { - prp_complete_stats_request complete_stats_request = 3; - prp_cell_stats_request cell_stats_request = 4; - prp_ue_stats_request ue_stats_request = 5; - } -} - -message prp_stats_reply { - optional prp_header header = 1; - repeated prp_ue_stats_report ue_report = 2; - repeated prp_cell_stats_report cell_report = 3; -} - -// -// Time indication messages -// - -message prp_sf_trigger { - optional prp_header header = 1; - optional uint32 sfn_sf = 2; - repeated prp_dl_info dl_info = 3; - repeated prp_ul_info ul_info = 4; -} - -// -// Asynchronous messages -// - -message prp_ul_sr_info { - optional prp_header header = 1; - optional uint32 sfn_sf = 2; - repeated uint32 rnti = 3; -} - -// -// eNB configuration messages -// -message prp_enb_config_request { - optional prp_header header = 1; -} - -message prp_enb_config_reply { - optional prp_header header = 1; - optional uint32 eNB_id = 2; // Unique id to distinguish the eNB - repeated prp_cell_config cell_config = 3; -} - -message prp_ue_config_request { - optional prp_header header = 1; -} - -message prp_ue_config_reply { - optional prp_header header = 1; - repeated prp_ue_config ue_config = 2; -} - -message prp_lc_config_request { - optional prp_header header = 1; -} - -message prp_lc_config_reply { - optional prp_header header = 1; - repeated prp_lc_ue_config lc_ue_config = 2; -} - -// -// Controller command messages -// - -message prp_dl_mac_config { - optional prp_header header = 1; - optional uint32 sfn_sf = 2; - repeated prp_dl_data dl_ue_data = 3; - repeated prp_dl_rar dl_rar = 4; - repeated prp_dl_broadcast dl_broadcast = 5; - repeated prp_pdcch_ofdm_sym_count ofdm_sym = 6; // OFDM symbol count for each CC -} - -// -// UE state change message -// - -message prp_ue_state_change { - optional prp_header header = 1; - optional uint32 type = 2; // One of the PRUESC_* values - optional prp_ue_config config = 3; // Body of the message (based on type) -} - -// -// Control delegation message -// - -message prp_control_delegation { - optional prp_header header = 1; - optional uint32 delegation_type = 2; // Bitmap of PRCDT_* flags - optional bytes payload = 3; // Byte array of shared lib containing the delegated functions - optional string name = 4; // The delegated functions names ordered based on bitmap flags -} - -// -// Agent reconfiguration message -// - -message prp_agent_reconfiguration { - optional prp_header header = 1; - optional string policy = 2; // The policy changes using YAML syntax in string format -} - -// Extensions of the echo request and reply -// messages for carrying a latency value in ms -message prp_echo_request_latency { - extend prp_echo_request { - optional uint32 latency = 100; - } -} - -message prp_echo_reply_latency { - extend prp_echo_reply { - optional uint32 latency = 100; - } -} - - diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto index 50d66a620c..70f99618ac 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_common.proto @@ -5,7 +5,7 @@ package protocol; // // RLC buffer status for a specific logical channel of a UE -message prp_rlc_bsr { +message flex_rlc_bsr { optional uint32 lc_id = 1; optional uint32 tx_queue_size = 2; optional uint32 tx_queue_hol_delay = 3; @@ -15,39 +15,39 @@ message prp_rlc_bsr { } // Flags for MAC Control Elements -enum prp_ce_type { - PRPCET_TA = 1; - PRPCET_DRX = 2; - PRPCET_CR = 4; - PRPCET_CA = 8; +enum flex_ce_type { + FLPCET_TA = 1; + FLPCET_DRX = 2; + FLPCET_CR = 4; + FLPCET_CA = 8; } // Types of DL CSI reports -enum prp_csi_type { - PRCSIT_P10 = 0; - PRCSIT_P11 = 1; - PRCSIT_P20 = 2; - PRCSIT_P21 = 3; - PRCSIT_A12 = 4; - PRCSIT_A22 = 5; - PRCSIT_A20 = 6; - PRCSIT_A30 = 7; - PRCSIT_A31 = 8; +enum flex_csi_type { + FLCSIT_P10 = 0; + FLCSIT_P11 = 1; + FLCSIT_P20 = 2; + FLCSIT_P21 = 3; + FLCSIT_A12 = 4; + FLCSIT_A22 = 5; + FLCSIT_A20 = 6; + FLCSIT_A30 = 7; + FLCSIT_A31 = 8; } // CSI type P10 -message prp_csi_p10 { +message flex_csi_p10 { optional uint32 wb_cqi = 1; } // CSI type P11 -message prp_csi_p11 { +message flex_csi_p11 { repeated uint32 wb_cqi = 1; optional uint32 wb_pmi = 2; } // CSI type P20 -message prp_csi_p20 { +message flex_csi_p20 { optional uint32 wb_cqi = 1; optional uint32 sb_cqi = 2; optional uint32 bandwidth_part_index = 3; @@ -55,7 +55,7 @@ message prp_csi_p20 { } // CSI type P21 -message prp_csi_p21 { +message flex_csi_p21 { repeated uint32 wb_cqi = 1; optional uint32 wb_pmi = 2; repeated uint32 sb_cqi = 3; @@ -64,13 +64,13 @@ message prp_csi_p21 { } // CSI type A12 -message prp_csi_a12 { +message flex_csi_a12 { repeated uint32 wb_cqi = 1; repeated uint32 sb_pmi = 2; } // CSI type A22 -message prp_csi_a22 { +message flex_csi_a22 { repeated uint32 wb_cqi = 1; repeated uint32 sb_cqi = 2; optional uint32 wb_pmi = 3; @@ -79,56 +79,56 @@ message prp_csi_a22 { } // CSI type A20 -message prp_csi_a20 { +message flex_csi_a20 { optional uint32 wb_cqi = 1; optional uint32 sb_cqi = 2; repeated uint32 sb_list = 3; } // CSI type A30 -message prp_csi_a30 { +message flex_csi_a30 { optional uint32 wb_cqi = 1; repeated uint32 sb_cqi = 2; } // CSI type A31 -message prp_csi_a31 { +message flex_csi_a31 { repeated uint32 wb_cqi = 1; - repeated prp_msb_cqi sb_cqi = 2; + repeated flex_msb_cqi sb_cqi = 2; optional uint32 wb_pmi = 3; } // The CQI for the M-preffered subband -message prp_msb_cqi { +message flex_msb_cqi { repeated uint32 sb_cqi = 1; } // The CSI report of the UE for a specific servCellIndex -message prp_dl_csi { +message flex_dl_csi { optional uint32 serv_cell_index = 1; optional uint32 ri = 2; - optional prp_csi_type type = 3; + optional flex_csi_type type = 3; oneof report { - prp_csi_p10 p10csi = 4; - prp_csi_p11 p11csi = 5; - prp_csi_p20 p20csi = 6; - prp_csi_p21 p21csi = 7; - prp_csi_a12 a12csi = 8; - prp_csi_a22 a22csi = 9; - prp_csi_a20 a20csi = 10; - prp_csi_a30 a30csi = 11; - prp_csi_a31 a31csi = 12; + flex_csi_p10 p10csi = 4; + flex_csi_p11 p11csi = 5; + flex_csi_p20 p20csi = 6; + flex_csi_p21 p21csi = 7; + flex_csi_a12 a12csi = 8; + flex_csi_a22 a22csi = 9; + flex_csi_a20 a20csi = 10; + flex_csi_a30 a30csi = 11; + flex_csi_a31 a31csi = 12; } } // The full DL CQI report for all CC of a UE -message prp_dl_cqi_report { +message flex_dl_cqi_report { optional uint32 sfn_sn = 1; - repeated prp_dl_csi csi_report = 2; + repeated flex_dl_csi csi_report = 2; } // Paging message info -message prp_paging_info { +message flex_paging_info { optional uint32 paging_index = 1; optional uint32 paging_message_size = 2; optional uint32 paging_subframe = 3; @@ -136,34 +136,34 @@ message prp_paging_info { } // Report for the paging buffer status -message prp_paging_buffer_report { - repeated prp_paging_info paging_info = 1; +message flex_paging_buffer_report { + repeated flex_paging_info paging_info = 1; } // The type of UL CQI -enum prp_ul_cqi_type { - PRUCT_SRS = 0; - PRUCT_PUSCH = 1; - PRUCT_PUCCH_1 = 2; - PRUCT_PUCCH_2 = 3; - PRUCT_PRACH = 4; +enum flex_ul_cqi_type { + FLUCT_SRS = 0; + FLUCT_PUSCH = 1; + FLUCT_PUCCH_1 = 2; + FLUCT_PUCCH_2 = 3; + FLUCT_PRACH = 4; } // UL CQI report for a specific UE for a given report type -message prp_ul_cqi { - optional prp_ul_cqi_type type = 1; +message flex_ul_cqi { + optional flex_ul_cqi_type type = 1; repeated uint32 sinr = 2; optional uint32 serv_cell_index = 3; } // Full UL CQI report for a specific UE -message prp_ul_cqi_report { +message flex_ul_cqi_report { optional uint32 sfn_sn = 1; - repeated prp_ul_cqi cqi_meas = 2; - repeated prp_pucch_dbm pucch_dbm = 3; + repeated flex_ul_cqi cqi_meas = 2; + repeated flex_pucch_dbm pucch_dbm = 3; } -message prp_pucch_dbm { +message flex_pucch_dbm { optional int32 p0_pucch_dbm = 1; optional uint32 serv_cell_index = 2; } @@ -173,7 +173,7 @@ message prp_pucch_dbm { // // The UL noise and interference report for a UE -message prp_noise_interference_report { +message flex_noise_interference_report { optional uint32 sfn_sf = 1; optional uint32 rip = 2; optional uint32 tnp = 3; diff --git a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto index 5ec7ae690c..1b1567dda1 100644 --- a/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto +++ b/openair2/ENB_APP/MESSAGES/V2/stats_messages.proto @@ -7,19 +7,19 @@ import "stats_common.proto"; // Bodies of statistics report requests // -message prp_complete_stats_request { - optional prp_stats_report_freq report_frequency = 1; +message flex_complete_stats_request { + optional flex_stats_report_freq report_frequency = 1; optional uint32 sf = 2; optional uint32 cell_report_flags = 3; optional uint32 ue_report_flags = 4; } -message prp_cell_stats_request { +message flex_cell_stats_request { repeated uint32 cell = 1; optional uint32 flags = 2; } -message prp_ue_stats_request { +message flex_ue_stats_request { repeated uint32 rnti = 1; optional uint32 flags = 2; } @@ -29,23 +29,23 @@ message prp_ue_stats_request { // // The full statistics report for a specific cell -message prp_cell_stats_report { +message flex_cell_stats_report { optional uint32 carrier_index = 1; optional uint32 flags = 2; - optional prp_noise_interference_report noise_inter_report = 3; + optional flex_noise_interference_report noise_inter_report = 3; } // Statistics report for a specific UE -message prp_ue_stats_report { +message flex_ue_stats_report { optional uint32 rnti = 1; optional uint32 flags = 2; repeated uint32 bsr = 3; optional uint32 phr = 4; - repeated prp_rlc_bsr rlc_report = 5; + repeated flex_rlc_bsr rlc_report = 5; optional uint32 pending_mac_ces = 6; - optional prp_dl_cqi_report dl_cqi_report = 7; - optional prp_paging_buffer_report pbr = 8; - optional prp_ul_cqi_report ul_cqi_report = 9; + 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; } // @@ -54,33 +54,33 @@ message prp_ue_stats_report { //Types of statistics requested by the controller -enum prp_stats_type { - PRST_COMPLETE_STATS = 0; - PRST_CELL_STATS = 1; - PRST_UE_STATS = 2; +enum flex_stats_type { + FLST_COMPLETE_STATS = 0; + FLST_CELL_STATS = 1; + FLST_UE_STATS = 2; } // Report frequency for the requested statistics -enum prp_stats_report_freq { - PRSRF_ONCE = 0; - PRSRF_PERIODICAL = 1; - PRSRF_CONTINUOUS = 2; - PRSRF_OFF = 3; +enum flex_stats_report_freq { + FLSRF_ONCE = 0; + FLSRF_PERIODICAL = 1; + FLSRF_CONTINUOUS = 2; + FLSRF_OFF = 3; } // Flags for cell statistics -enum prp_cell_stats_type { - PRCST_NOISE_INTERFERENCE = 1; +enum flex_cell_stats_type { + FLCST_NOISE_INTERFERENCE = 1; } // Flags for UE-related statistics -enum prp_ue_stats_type { - PRUST_BSR = 1; - PRUST_PRH = 2; - PRUST_RLC_BS = 4; - PRUST_MAC_CE_BS = 8; - PRUST_DL_CQI = 16; - PRUST_PBS = 32; - PRUST_UL_CQI = 64; +enum flex_ue_stats_type { + FLUST_BSR = 1; + FLUST_PRH = 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 diff --git a/openair2/ENB_APP/MESSAGES/V2/time_common.proto b/openair2/ENB_APP/MESSAGES/V2/time_common.proto index 4c3ac4911e..30a56bb776 100644 --- a/openair2/ENB_APP/MESSAGES/V2/time_common.proto +++ b/openair2/ENB_APP/MESSAGES/V2/time_common.proto @@ -1,25 +1,25 @@ package protocol; -enum prp_harq_status { - PRHS_ACK = 0; - PRHS_NACK = 1; - PRHS_DTX = 2; +enum flex_harq_status { + FLHS_ACK = 0; + FLHS_NACK = 1; + FLHS_DTX = 2; } -enum prp_reception_status { - PRRS_OK = 0; - PRRS_NOT_OK = 1; - PRRS_NOT_VALID = 2; +enum flex_reception_status { + FLRS_OK = 0; + FLRS_NOT_OK = 1; + FLRS_NOT_VALID = 2; } -message prp_dl_info { +message flex_dl_info { optional uint32 rnti = 1; optional uint32 harq_process_id = 2; repeated uint32 harq_status = 3; optional uint32 serv_cell_index = 4; } -message prp_ul_info { +message flex_ul_info { optional uint32 rnti = 1; repeated uint32 ul_reception = 2; optional uint32 reception_status = 3; diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index 6a9bcad878..8286771104 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -29,7 +29,7 @@ /*! \file enb_agent.h * \brief top level enb agent receive thread and itti task - * \author Navid Nikaein and Xenofon Foukas + * \author Xenofon Foukas and Navid Nikaein * \date 2016 * \version 0.1 */ @@ -57,7 +57,7 @@ char local_cache[40]; void *send_thread(void *args); void *receive_thread(void *args); pthread_t new_thread(void *(*f)(void *), void *b); -Protocol__ProgranMessage *enb_agent_timeout(void* args); +Protocol__FlexranMessage *enb_agent_timeout(void* args); int agent_task_created = 0; @@ -68,7 +68,7 @@ int agent_task_created = 0; void *enb_agent_task(void *args){ //enb_agent_instance_t *d = (enb_agent_instance_t *) args; - Protocol__ProgranMessage *msg; + Protocol__FlexranMessage *msg; void *data; int size; err_code_t err_code; @@ -104,7 +104,7 @@ void *enb_agent_task(void *args){ data=enb_agent_pack_message(msg,&size); elem = get_timer_entry(msg_p->ittiMsg.timer_has_expired.timer_id); if (enb_agent_msg_send(elem->agent_id, ENB_AGENT_DEFAULT, data, size, priority)) { - err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } @@ -135,11 +135,11 @@ void *receive_thread(void *args) { int priority; err_code_t err_code; - Protocol__ProgranMessage *msg; + Protocol__FlexranMessage *msg; while (1) { //if (enb_agent_msg_recv(d->enb_id, ENB_AGENT_DEFAULT, &data, &size, &priority)) { - // err_code = PROTOCOL__PROGRAN_ERR__MSG_DEQUEUING; + // err_code = PROTOCOL__FLEXRAN_ERR__MSG_DEQUEUING; // goto error; //} @@ -157,7 +157,7 @@ void *receive_thread(void *args) { data=enb_agent_pack_message(msg,&size); if (enb_agent_msg_send(d->enb_id, ENB_AGENT_DEFAULT, data, size, priority)) { - err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } @@ -337,7 +337,7 @@ error: -Protocol__ProgranMessage *enb_agent_timeout(void* args){ +Protocol__FlexranMessage *enb_agent_timeout(void* args){ // enb_agent_timer_args_t *timer_args = calloc(1, sizeof(*timer_args)); //memcpy (timer_args, args, sizeof(*timer_args)); diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 0f148d82dd..2baecd6041 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -29,7 +29,7 @@ /*! \file enb_agent_common.c * \brief common primitives for all agents - * \author Navid Nikaein and Xenofon Foukas + * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein * \date 2016 * \version 0.1 */ @@ -55,15 +55,15 @@ void * enb_rrc[NUM_MAX_ENB]; * message primitives */ -int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int *size) { +int enb_agent_serialize_message(Protocol__FlexranMessage *msg, void **buf, int *size) { - *size = protocol__progran_message__get_packed_size(msg); + *size = protocol__flexran_message__get_packed_size(msg); *buf = malloc(*size); if (buf == NULL) goto error; - protocol__progran_message__pack(msg, *buf); + protocol__flexran_message__pack(msg, *buf); return 0; @@ -76,8 +76,8 @@ int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int * /* We assume that the buffer size is equal to the message size. Should be chekced durint Tx/Rx */ -int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage **msg) { - *msg = protocol__progran_message__unpack(NULL, size, data); +int enb_agent_deserialize_message(void *data, int size, Protocol__FlexranMessage **msg) { + *msg = protocol__flexran_message__unpack(NULL, size, data); if (*msg == NULL) goto error; @@ -90,14 +90,14 @@ int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage -int prp_create_header(xid_t xid, Protocol__PrpType type, Protocol__PrpHeader **header) { +int flex_create_header(xid_t xid, Protocol__FlexType type, Protocol__FlexHeader **header) { - *header = malloc(sizeof(Protocol__PrpHeader)); + *header = malloc(sizeof(Protocol__FlexHeader)); if(*header == NULL) goto error; - protocol__prp_header__init(*header); - (*header)->version = PROGRAN_VERSION; + protocol__flex_header__init(*header); + (*header)->version = FLEXRAN_VERSION; (*header)->has_version = 1; // check if the type is set (*header)->type = type; @@ -112,28 +112,28 @@ int prp_create_header(xid_t xid, Protocol__PrpType type, Protocol__PrpHeader ** } -int enb_agent_hello(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { +int enb_agent_hello(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { - Protocol__PrpHeader *header; + Protocol__FlexHeader *header; /*TODO: Need to set random xid or xid from received hello message*/ xid_t xid = 1; - if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_HELLO, &header) != 0) + if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_HELLO, &header) != 0) goto error; - Protocol__PrpHello *hello_msg; - hello_msg = malloc(sizeof(Protocol__PrpHello)); + Protocol__FlexHello *hello_msg; + hello_msg = malloc(sizeof(Protocol__FlexHello)); if(hello_msg == NULL) goto error; - protocol__prp_hello__init(hello_msg); + protocol__flex_hello__init(hello_msg); hello_msg->header = header; - *msg = malloc(sizeof(Protocol__ProgranMessage)); + *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_HELLO_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; (*msg)->has_msg_dir = 1; (*msg)->hello_msg = hello_msg; return 0; @@ -150,9 +150,9 @@ int enb_agent_hello(mid_t mod_id, const void *params, Protocol__ProgranMessage * } -int enb_agent_destroy_hello(Protocol__ProgranMessage *msg) { +int enb_agent_destroy_hello(Protocol__FlexranMessage *msg) { - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG) + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_HELLO_MSG) goto error; free(msg->hello_msg->header); @@ -166,26 +166,26 @@ int enb_agent_destroy_hello(Protocol__ProgranMessage *msg) { } -int enb_agent_echo_request(mid_t mod_id, const void* params, Protocol__ProgranMessage **msg) { - Protocol__PrpHeader *header; +int enb_agent_echo_request(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg) { + Protocol__FlexHeader *header; /*TODO: Need to set a random xid*/ xid_t xid = 1; - if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REQUEST, &header) != 0) + if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_ECHO_REQUEST, &header) != 0) goto error; - Protocol__PrpEchoRequest *echo_request_msg; - echo_request_msg = malloc(sizeof(Protocol__PrpEchoRequest)); + Protocol__FlexEchoRequest *echo_request_msg; + echo_request_msg = malloc(sizeof(Protocol__FlexEchoRequest)); if(echo_request_msg == NULL) goto error; - protocol__prp_echo_request__init(echo_request_msg); + protocol__flex_echo_request__init(echo_request_msg); echo_request_msg->header = header; - *msg = malloc(sizeof(Protocol__ProgranMessage)); + *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REQUEST_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_ECHO_REQUEST_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; (*msg)->echo_request_msg = echo_request_msg; return 0; @@ -201,8 +201,8 @@ int enb_agent_echo_request(mid_t mod_id, const void* params, Protocol__ProgranMe } -int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg) { - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REQUEST_MSG) +int enb_agent_destroy_echo_request(Protocol__FlexranMessage *msg) { + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_ECHO_REQUEST_MSG) goto error; free(msg->echo_request_msg->header); @@ -217,30 +217,30 @@ int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg) { -int enb_agent_echo_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { +int enb_agent_echo_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { xid_t xid; - Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; - Protocol__PrpEchoRequest *echo_req = input->echo_request_msg; + Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; + Protocol__FlexEchoRequest *echo_req = input->echo_request_msg; xid = (echo_req->header)->xid; - Protocol__PrpHeader *header; - if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_ECHO_REPLY, &header) != 0) + Protocol__FlexHeader *header; + if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_ECHO_REPLY, &header) != 0) goto error; - Protocol__PrpEchoReply *echo_reply_msg; - echo_reply_msg = malloc(sizeof(Protocol__PrpEchoReply)); + Protocol__FlexEchoReply *echo_reply_msg; + echo_reply_msg = malloc(sizeof(Protocol__FlexEchoReply)); if(echo_reply_msg == NULL) goto error; - protocol__prp_echo_reply__init(echo_reply_msg); + protocol__flex_echo_reply__init(echo_reply_msg); echo_reply_msg->header = header; - *msg = malloc(sizeof(Protocol__ProgranMessage)); + *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_ECHO_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; (*msg)->has_msg_dir = 1; (*msg)->echo_reply_msg = echo_reply_msg; return 0; @@ -257,8 +257,8 @@ int enb_agent_echo_reply(mid_t mod_id, const void *params, Protocol__ProgranMess } -int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg) { - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG) +int enb_agent_destroy_echo_reply(Protocol__FlexranMessage *msg) { + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_ECHO_REPLY_MSG) goto error; free(msg->echo_reply_msg->header); @@ -272,12 +272,12 @@ int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg) { } -int enb_agent_destroy_enb_config_reply(Protocol__ProgranMessage *msg) { - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG) +int enb_agent_destroy_enb_config_reply(Protocol__FlexranMessage *msg) { + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG) goto error; free(msg->enb_config_reply_msg->header); int i, j; - Protocol__PrpEnbConfigReply *reply = msg->enb_config_reply_msg; + Protocol__FlexEnbConfigReply *reply = msg->enb_config_reply_msg; for(i = 0; i < reply->n_cell_config;i++){ free(reply->cell_config[i]->mbsfn_subframe_config_rfoffset); @@ -302,12 +302,12 @@ int enb_agent_destroy_enb_config_reply(Protocol__ProgranMessage *msg) { return -1; } -int enb_agent_destroy_ue_config_reply(Protocol__ProgranMessage *msg) { - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG) +int enb_agent_destroy_ue_config_reply(Protocol__FlexranMessage *msg) { + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG) goto error; free(msg->ue_config_reply_msg->header); int i, j; - Protocol__PrpUeConfigReply *reply = msg->ue_config_reply_msg; + Protocol__FlexUeConfigReply *reply = msg->ue_config_reply_msg; for(i = 0; i < reply->n_ue_config;i++){ free(reply->ue_config[i]->capabilities); @@ -323,8 +323,8 @@ int enb_agent_destroy_ue_config_reply(Protocol__ProgranMessage *msg) { return -1; } -int enb_agent_destroy_lc_config_reply(Protocol__ProgranMessage *msg) { - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG) +int enb_agent_destroy_lc_config_reply(Protocol__FlexranMessage *msg) { + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG) goto error; int i, j; @@ -345,8 +345,8 @@ int enb_agent_destroy_lc_config_reply(Protocol__ProgranMessage *msg) { return -1; } -int enb_agent_destroy_ue_state_change(Protocol__ProgranMessage *msg) { - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG) +int enb_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 @@ -359,8 +359,8 @@ int enb_agent_destroy_ue_state_change(Protocol__ProgranMessage *msg) { return -1; } -int enb_agent_destroy_enb_config_request(Protocol__ProgranMessage *msg) { - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG) +int enb_agent_destroy_enb_config_request(Protocol__FlexranMessage *msg) { + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG) goto error; free(msg->enb_config_request_msg->header); free(msg->enb_config_request_msg); @@ -372,12 +372,12 @@ int enb_agent_destroy_enb_config_request(Protocol__ProgranMessage *msg) { return -1; } -int enb_agent_destroy_ue_config_request(Protocol__ProgranMessage *msg) { +int enb_agent_destroy_ue_config_request(Protocol__FlexranMessage *msg) { /* TODO: Deallocate memory for a dynamically allocated UE config message */ return 0; } -int enb_agent_destroy_lc_config_request(Protocol__ProgranMessage *msg) { +int enb_agent_destroy_lc_config_request(Protocol__FlexranMessage *msg) { /* TODO: Deallocate memory for a dynamically allocated LC config message */ return 0; } @@ -397,10 +397,10 @@ long timer_end(struct timespec start_time){ return diffInNanos; } -int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { +int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { - Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; - Protocol__PrpControlDelegation *control_delegation_msg = input->control_delegation_msg; + Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; + Protocol__FlexControlDelegation *control_delegation_msg = input->control_delegation_msg; uint32_t delegation_type = control_delegation_msg->delegation_type; @@ -428,13 +428,13 @@ int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__Pro return -1; } -int enb_agent_destroy_control_delegation(Protocol__ProgranMessage *msg) { +int enb_agent_destroy_control_delegation(Protocol__FlexranMessage *msg) { /*TODO: Dealocate memory for a dynamically allocated control delegation message*/ } -int enb_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { - Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; - Protocol__PrpAgentReconfiguration *agent_reconfiguration_msg = input->agent_reconfiguration_msg; +int enb_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { + Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; + Protocol__FlexAgentReconfiguration *agent_reconfiguration_msg = input->agent_reconfiguration_msg; apply_reconfiguration_policy(mod_id, agent_reconfiguration_msg->policy, strlen(agent_reconfiguration_msg->policy)); @@ -442,7 +442,7 @@ int enb_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__Progra return 0; } -int enb_agent_destroy_agent_reconfiguration(Protocol__ProgranMessage *msg) { +int enb_agent_destroy_agent_reconfiguration(Protocol__FlexranMessage *msg) { /*TODO: Dealocate memory for a dynamically allocated agent reconfiguration message*/ } @@ -949,11 +949,11 @@ int get_meas_gap_config(mid_t mod_id, mid_t ue_id) { 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__PRP_MEAS_GAP_CONFIG_PATTERN__PRMGCP_GP1; + 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__PRP_MEAS_GAP_CONFIG_PATTERN__PRMGCP_GP2; + return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP2; } else { - return PROTOCOL__PRP_MEAS_GAP_CONFIG_PATTERN__PRMGCP_OFF; + return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF; } } } @@ -1258,38 +1258,38 @@ int get_direction(mid_t ue_id, mid_t lc_id) int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { int size; - Protocol__ProgranMessage *msg; - Protocol__PrpHeader *header; + Protocol__FlexranMessage *msg; + Protocol__FlexHeader *header; void *data; int priority; err_code_t err_code; int xid = 0; - if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_UE_STATE_CHANGE, &header) != 0) + if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UE_STATE_CHANGE, &header) != 0) goto error; - Protocol__PrpUeStateChange *ue_state_change_msg; - ue_state_change_msg = malloc(sizeof(Protocol__PrpUeStateChange)); + Protocol__FlexUeStateChange *ue_state_change_msg; + ue_state_change_msg = malloc(sizeof(Protocol__FlexUeStateChange)); if(ue_state_change_msg == NULL) { goto error; } - protocol__prp_ue_state_change__init(ue_state_change_msg); + 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__PrpUeConfig *config; - config = malloc(sizeof(Protocol__PrpUeConfig)); + Protocol__FlexUeConfig *config; + config = malloc(sizeof(Protocol__FlexUeConfig)); if (config == NULL) { goto error; } - protocol__prp_ue_config__init(config); - if (state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_DEACTIVATED) { + 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__PRP_UE_STATE_CHANGE_TYPE__PRUESC_UPDATED - || state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_ACTIVATED) { + } 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; @@ -1305,7 +1305,7 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) } //TODO: Set the measurement gap offset if applicable if(config->has_meas_gap_config_pattern == 1 && - config->meas_gap_config_pattern != PROTOCOL__PRP_MEAS_GAP_CONFIG_PATTERN__PRMGCP_OFF) { + config->meas_gap_config_pattern != PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF) { config->meas_gap_config_sf_offset = get_meas_gap_config_offset(mod_id,i); config->has_meas_gap_config_sf_offset = 1; } @@ -1333,9 +1333,9 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) config->has_ue_aggregated_max_bitrate_dl = 1; //TODO: Set the UE capabilities - Protocol__PrpUeCapabilities *c_capabilities; - c_capabilities = malloc(sizeof(Protocol__PrpUeCapabilities)); - protocol__prp_ue_capabilities__init(c_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 = 1; c_capabilities->half_duplex = 1;//get_half_duplex(i); @@ -1353,7 +1353,7 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) c_capabilities->res_alloc_type1 = 1;//get_res_alloc_type1(i); //Set the capabilites to the message config->capabilities = c_capabilities; - //TODO: Set UE transmission antenna. One of the PRUTA_* values + //TODO: Set UE transmission antenna. One of the FLUTA_* values if(get_ue_transmission_antenna(mod_id,i) != -1){ config->has_ue_transmission_antenna = 1; config->ue_transmission_antenna = get_ue_transmission_antenna(mod_id,i); @@ -1398,7 +1398,7 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) config->has_aperiodic_cqi_rep_mode = 1; int mode = get_aperiodic_cqi_rep_mode(mod_id,i); if (mode > 4) { - config->aperiodic_cqi_rep_mode = PROTOCOL__PRP_APERIODIC_CQI_REPORT_MODE__PRACRM_NONE; + config->aperiodic_cqi_rep_mode = PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_NONE; } else { config->aperiodic_cqi_rep_mode = mode; } @@ -1435,24 +1435,24 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) config->has_scell_deactivation_timer = 1; config->scell_deactivation_timer = 1; } - } else if (state_change == PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_MOVED) { + } 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__ProgranMessage)); + msg = malloc(sizeof(Protocol__FlexranMessage)); if (msg == NULL) { goto error; } - protocol__progran_message__init(msg); - msg->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG; - msg->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + 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 = enb_agent_pack_message(msg, &size); /*Send sr info using the MAC channel of the eNB*/ if (enb_agent_msg_send(mod_id, ENB_AGENT_DEFAULT, data, size, priority)) { - err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } @@ -1466,38 +1466,38 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) * timer primitives */ -int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { +int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { xid_t xid; - Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; - Protocol__PrpLcConfigRequest *lc_config_request_msg = input->lc_config_request_msg; + Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; + Protocol__FlexLcConfigRequest *lc_config_request_msg = input->lc_config_request_msg; xid = (lc_config_request_msg->header)->xid; int i, j; - Protocol__PrpHeader *header; - if(prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_GET_LC_CONFIG_REPLY, &header) != 0) + Protocol__FlexHeader *header; + if(flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_GET_LC_CONFIG_REPLY, &header) != 0) goto error; - Protocol__PrpLcConfigReply *lc_config_reply_msg; - lc_config_reply_msg = malloc(sizeof(Protocol__PrpLcConfigReply)); + Protocol__FlexLcConfigReply *lc_config_reply_msg; + lc_config_reply_msg = malloc(sizeof(Protocol__FlexLcConfigReply)); if(lc_config_reply_msg == NULL) goto error; - protocol__prp_lc_config_reply__init(lc_config_reply_msg); + protocol__flex_lc_config_reply__init(lc_config_reply_msg); lc_config_reply_msg->header = header; //TODO: Fill in the actual number of UEs that we are going to report LC configs about lc_config_reply_msg->n_lc_ue_config = get_num_ues(mod_id); - Protocol__PrpLcUeConfig **lc_ue_config; + Protocol__FlexLcUeConfig **lc_ue_config; if (lc_config_reply_msg->n_lc_ue_config > 0) { - lc_ue_config = malloc(sizeof(Protocol__PrpLcUeConfig *) * lc_config_reply_msg->n_lc_ue_config); + lc_ue_config = malloc(sizeof(Protocol__FlexLcUeConfig *) * lc_config_reply_msg->n_lc_ue_config); if (lc_ue_config == NULL) { goto error; } // Fill the config for each UE for (i = 0; i < lc_config_reply_msg->n_lc_ue_config; i++) { - lc_ue_config[i] = malloc(sizeof(Protocol__PrpLcUeConfig)); - protocol__prp_lc_ue_config__init(lc_ue_config[i]); + lc_ue_config[i] = malloc(sizeof(Protocol__FlexLcUeConfig)); + protocol__flex_lc_ue_config__init(lc_ue_config[i]); //TODO: Set the RNTI of the UE lc_ue_config[i]->has_rnti = 1; lc_ue_config[i]->rnti = get_ue_crnti(mod_id,i); @@ -1512,15 +1512,15 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Progra } else { lc_ue_config[i]->n_lc_config = 3; } - Protocol__PrpLcConfig **lc_config; + Protocol__FlexLcConfig **lc_config; if (lc_ue_config[i]->n_lc_config > 0) { - lc_config = malloc(sizeof(Protocol__PrpLcConfig *) * lc_ue_config[i]->n_lc_config); + lc_config = malloc(sizeof(Protocol__FlexLcConfig *) * lc_ue_config[i]->n_lc_config); if (lc_config == NULL) { goto error; } for (j = 0; j < lc_ue_config[i]->n_lc_config; j++) { - lc_config[j] = malloc(sizeof(Protocol__PrpLcConfig)); - protocol__prp_lc_config__init(lc_config[j]); + lc_config[j] = malloc(sizeof(Protocol__FlexLcConfig)); + protocol__flex_lc_config__init(lc_config[j]); //TODO: Set the LC id lc_config[j]->has_lcid = 1; lc_config[j]->lcid = j+1; @@ -1533,14 +1533,14 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Progra //TODO: Set the LC direction lc_config[j]->has_direction = 1; lc_config[j]->direction = get_direction(i,j+1); - //TODO: Bearer type. One of PRQBT_* values + //TODO: Bearer type. One of FLQBT_* values lc_config[j]->has_qos_bearer_type = 1; - lc_config[j]->qos_bearer_type = PROTOCOL__PRP_QOS_BEARER_TYPE__PRQBT_NON_GBR; + lc_config[j]->qos_bearer_type = PROTOCOL__FLEX_QOS_BEARER_TYPE__FLQBT_NON_GBR; //TODO: Set the QCI defined in TS 23.203, coded as defined in TS 36.413 // One less than the actual QCI value lc_config[j]->has_qci = 1; lc_config[j]->qci = 1; - if (lc_config[j]->direction == PROTOCOL__PRP_QOS_BEARER_TYPE__PRQBT_GBR) { + if (lc_config[j]->direction == PROTOCOL__FLEX_QOS_BEARER_TYPE__FLQBT_GBR) { //TODO: Set the max bitrate (UL) lc_config[j]->has_e_rab_max_bitrate_ul = 1; lc_config[j]->e_rab_max_bitrate_ul = 1; @@ -1560,12 +1560,12 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Progra } // end for UE lc_config_reply_msg->lc_ue_config = lc_ue_config; } // lc_config_reply_msg->n_lc_ue_config > 0 - *msg = malloc(sizeof(Protocol__ProgranMessage)); + *msg = malloc(sizeof(Protocol__FlexranMessage)); if (*msg == NULL) goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; (*msg)->lc_config_reply_msg = lc_config_reply_msg; return 0; @@ -1588,38 +1588,38 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Progra * ************************************ */ -int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { +int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { xid_t xid; - Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; - Protocol__PrpUeConfigRequest *ue_config_request_msg = input->ue_config_request_msg; + Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; + Protocol__FlexUeConfigRequest *ue_config_request_msg = input->ue_config_request_msg; xid = (ue_config_request_msg->header)->xid; int i; - Protocol__PrpHeader *header; - if(prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_GET_UE_CONFIG_REPLY, &header) != 0) + Protocol__FlexHeader *header; + if(flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_GET_UE_CONFIG_REPLY, &header) != 0) goto error; - Protocol__PrpUeConfigReply *ue_config_reply_msg; - ue_config_reply_msg = malloc(sizeof(Protocol__PrpUeConfigReply)); + Protocol__FlexUeConfigReply *ue_config_reply_msg; + ue_config_reply_msg = malloc(sizeof(Protocol__FlexUeConfigReply)); if(ue_config_reply_msg == NULL) goto error; - protocol__prp_ue_config_reply__init(ue_config_reply_msg); + protocol__flex_ue_config_reply__init(ue_config_reply_msg); ue_config_reply_msg->header = header; //TODO: Fill in the actual number of UEs that are currently connected ue_config_reply_msg->n_ue_config = get_num_ues(mod_id); - Protocol__PrpUeConfig **ue_config; + Protocol__FlexUeConfig **ue_config; if (ue_config_reply_msg->n_ue_config > 0) { - ue_config = malloc(sizeof(Protocol__PrpUeConfig *) * ue_config_reply_msg->n_ue_config); + ue_config = malloc(sizeof(Protocol__FlexUeConfig *) * ue_config_reply_msg->n_ue_config); if (ue_config == NULL) { goto error; } for (i = 0; i < ue_config_reply_msg->n_ue_config; i++) { - ue_config[i] = malloc(sizeof(Protocol__PrpUeConfig)); - protocol__prp_ue_config__init(ue_config[i]); + ue_config[i] = malloc(sizeof(Protocol__FlexUeConfig)); + protocol__flex_ue_config__init(ue_config[i]); //TODO: Set the RNTI of the ue with id i ue_config[i]->rnti = get_ue_crnti(mod_id,i); ue_config[i]->has_rnti = 1; @@ -1638,7 +1638,7 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra } //TODO: Set the measurement gap offset if applicable if(ue_config[i]->has_meas_gap_config_pattern == 1 && - ue_config[i]->meas_gap_config_pattern != PROTOCOL__PRP_MEAS_GAP_CONFIG_PATTERN__PRMGCP_OFF) { + ue_config[i]->meas_gap_config_pattern != PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF) { ue_config[i]->meas_gap_config_sf_offset = get_meas_gap_config_offset(mod_id,i); ue_config[i]->has_meas_gap_config_sf_offset = 1; } @@ -1666,9 +1666,9 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra ue_config[i]->has_ue_aggregated_max_bitrate_dl = 1; //TODO: Set the UE capabilities - Protocol__PrpUeCapabilities *capabilities; - capabilities = malloc(sizeof(Protocol__PrpUeCapabilities)); - protocol__prp_ue_capabilities__init(capabilities); + Protocol__FlexUeCapabilities *capabilities; + capabilities = malloc(sizeof(Protocol__FlexUeCapabilities)); + protocol__flex_ue_capabilities__init(capabilities); //TODO: Set half duplex (FDD operation) capabilities->has_half_duplex = 1; capabilities->half_duplex = 1;//get_half_duplex(i); @@ -1686,7 +1686,7 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra capabilities->res_alloc_type1 = 1;//get_res_alloc_type1(i); //Set the capabilites to the message ue_config[i]->capabilities = capabilities; - //TODO: Set UE transmission antenna. One of the PRUTA_* values + //TODO: Set UE transmission antenna. One of the FLUTA_* values if(get_ue_transmission_antenna(mod_id,i) != -1){ ue_config[i]->has_ue_transmission_antenna = 1; ue_config[i]->ue_transmission_antenna = get_ue_transmission_antenna(mod_id,i); @@ -1726,12 +1726,12 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra ue_config[i]->has_simultaneous_ack_nack_cqi = 1; ue_config[i]->simultaneous_ack_nack_cqi = get_simultaneous_ack_nack_cqi(mod_id,i); } - //TODO: Set PRACRM_* value regarding aperiodic cqi report mode + //TODO: Set FLACRM_* value regarding aperiodic cqi report mode if(get_aperiodic_cqi_rep_mode(mod_id,i) != -1){ ue_config[i]->has_aperiodic_cqi_rep_mode = 1; int mode = get_aperiodic_cqi_rep_mode(mod_id,i); if (mode > 4) { - ue_config[i]->aperiodic_cqi_rep_mode = PROTOCOL__PRP_APERIODIC_CQI_REPORT_MODE__PRACRM_NONE; + ue_config[i]->aperiodic_cqi_rep_mode = PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_NONE; } else { ue_config[i]->aperiodic_cqi_rep_mode = mode; } @@ -1770,12 +1770,12 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra } ue_config_reply_msg->ue_config = ue_config; } - *msg = malloc(sizeof(Protocol__ProgranMessage)); + *msg = malloc(sizeof(Protocol__FlexranMessage)); if (*msg == NULL) goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; (*msg)->ue_config_reply_msg = ue_config_reply_msg; return 0; @@ -1798,29 +1798,29 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Progra * ************************************ */ -int enb_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__ProgranMessage **msg) { +int enb_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg) { - Protocol__PrpHeader *header; + Protocol__FlexHeader *header; xid_t xid = 1; - if(prp_create_header(xid,PROTOCOL__PRP_TYPE__PRPT_GET_ENB_CONFIG_REQUEST, &header) != 0) + if(flex_create_header(xid,PROTOCOL__FLEX_TYPE__FLPT_GET_ENB_CONFIG_REQUEST, &header) != 0) goto error; - Protocol__PrpEnbConfigRequest *enb_config_request_msg; - enb_config_request_msg = malloc(sizeof(Protocol__PrpEnbConfigRequest)); + Protocol__FlexEnbConfigRequest *enb_config_request_msg; + enb_config_request_msg = malloc(sizeof(Protocol__FlexEnbConfigRequest)); if(enb_config_request_msg == NULL) goto error; - protocol__prp_enb_config_request__init(enb_config_request_msg); + protocol__flex_enb_config_request__init(enb_config_request_msg); enb_config_request_msg->header = header; - *msg = malloc(sizeof(Protocol__ProgranMessage)); + *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; (*msg)->enb_config_request_msg = enb_config_request_msg; return 0; @@ -1836,26 +1836,26 @@ int enb_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__Pro return -1; } -int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { +int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { xid_t xid; - Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; - Protocol__PrpEnbConfigRequest *enb_config_req_msg = input->enb_config_request_msg; + Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; + Protocol__FlexEnbConfigRequest *enb_config_req_msg = input->enb_config_request_msg; xid = (enb_config_req_msg->header)->xid; int i, j, k; int cc_id = 0; int enb_id = mod_id; - Protocol__PrpHeader *header; - if(prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_GET_ENB_CONFIG_REPLY, &header) != 0) + Protocol__FlexHeader *header; + if(flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_GET_ENB_CONFIG_REPLY, &header) != 0) goto error; - Protocol__PrpEnbConfigReply *enb_config_reply_msg; - enb_config_reply_msg = malloc(sizeof(Protocol__PrpEnbConfigReply)); + Protocol__FlexEnbConfigReply *enb_config_reply_msg; + enb_config_reply_msg = malloc(sizeof(Protocol__FlexEnbConfigReply)); if(enb_config_reply_msg == NULL) goto error; - protocol__prp_enb_config_reply__init(enb_config_reply_msg); + protocol__flex_enb_config_reply__init(enb_config_reply_msg); enb_config_reply_msg->header = header; enb_config_reply_msg->enb_id = mod_id; @@ -1863,14 +1863,14 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Progr enb_config_reply_msg->n_cell_config = MAX_NUM_CCs; - Protocol__PrpCellConfig **cell_conf; + Protocol__FlexCellConfig **cell_conf; if(enb_config_reply_msg->n_cell_config > 0){ - cell_conf = malloc(sizeof(Protocol__PrpCellConfig *) * enb_config_reply_msg->n_cell_config); + cell_conf = malloc(sizeof(Protocol__FlexCellConfig *) * enb_config_reply_msg->n_cell_config); if(cell_conf == NULL) goto error; for(i = 0; i < enb_config_reply_msg->n_cell_config; i++){ - cell_conf[i] = malloc(sizeof(Protocol__PrpCellConfig)); - protocol__prp_cell_config__init(cell_conf[i]); + cell_conf[i] = malloc(sizeof(Protocol__FlexCellConfig)); + protocol__flex_cell_config__init(cell_conf[i]); //TODO: Fill in with actual value, the PCI of this cell cell_conf[i]->phy_cell_id = 1; cell_conf[i]->has_phy_cell_id = get_cell_id(enb_id,i); @@ -1882,41 +1882,41 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Progr cell_conf[i]->has_pusch_hopping_offset = 1; //TODO: Fill in with actual value if(get_hopping_mode(enb_id,i) == 0){ - cell_conf[i]->hopping_mode = PROTOCOL__PRP_HOPPING_MODE__PRHM_INTER; + cell_conf[i]->hopping_mode = PROTOCOL__FLEX_HOPPING_MODE__FLHM_INTER; }else if(get_hopping_mode(enb_id,i) == 1){ - cell_conf[i]->hopping_mode = PROTOCOL__PRP_HOPPING_MODE__PRHM_INTERINTRA; + cell_conf[i]->hopping_mode = PROTOCOL__FLEX_HOPPING_MODE__FLHM_INTERINTRA; } cell_conf[i]->has_hopping_mode = 1; //TODO: Fill in with actual value, the number of subbands cell_conf[i]->n_sb = get_n_SB(enb_id,i); cell_conf[i]->has_n_sb = 1; - //TODO: Fill in with actual value, The number of resource element groups used for PHICH. One of PRPR_ + //TODO: Fill in with actual value, The number of resource element groups used for PHICH. One of FLPR_ if(get_phich_resource(enb_id,i) == 0){ - cell_conf[i]->phich_resource = PROTOCOL__PRP_PHICH_RESOURCE__PRPR_ONE_SIXTH; //0 + cell_conf[i]->phich_resource = PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_ONE_SIXTH; //0 }else if (get_phich_resource(enb_id,i) == 1){ - cell_conf[i]->phich_resource = PROTOCOL__PRP_PHICH_RESOURCE__PRPR_HALF; //1 + cell_conf[i]->phich_resource = PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_HALF; //1 }else if (get_phich_resource(enb_id,i) == 2){ - cell_conf[i]->phich_resource = PROTOCOL__PRP_PHICH_RESOURCE__PRPR_ONE; // 2 + cell_conf[i]->phich_resource = PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_ONE; // 2 }else if (get_phich_resource(enb_id,i) == 3){ - cell_conf[i]->phich_resource = PROTOCOL__PRP_PHICH_RESOURCE__PRPR_TWO;//3 + cell_conf[i]->phich_resource = PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_TWO;//3 } cell_conf[i]->has_phich_resource = 1; - //TODO: Fill in with actual value, one of the PRPD_ values + //TODO: Fill in with actual value, one of the FLPD_ values if(get_phich_duration(enb_id,i) == 0){ - cell_conf[i]->phich_duration = PROTOCOL__PRP_PHICH_DURATION__PRPD_NORMAL; + cell_conf[i]->phich_duration = PROTOCOL__FLEX_PHICH_DURATION__FLPD_NORMAL; }else if(get_phich_duration(enb_id,i) == 1){ - cell_conf[i]->phich_duration = PROTOCOL__PRP_PHICH_DURATION__PRPD_EXTENDED; + cell_conf[i]->phich_duration = PROTOCOL__FLEX_PHICH_DURATION__FLPD_EXTENDED; } cell_conf[i]->has_phich_duration = 1; //TODO: Fill in with actual value, See TS 36.211, section 6.9 cell_conf[i]->init_nr_pdcch_ofdm_sym = get_num_pdcch_symb(enb_id,i); cell_conf[i]->has_init_nr_pdcch_ofdm_sym = 1; //TODO: Fill in with actual value - /* Protocol__PrpSiConfig *si_config; */ - /* si_config = malloc(sizeof(Protocol__PrpSiConfig)); */ + /* Protocol__FlexSiConfig *si_config; */ + /* si_config = malloc(sizeof(Protocol__FlexSiConfig)); */ /* if(si_config == NULL) */ /* goto error; */ - /* protocol__prp_si_config__init(si_config); */ + /* protocol__flex_si_config__init(si_config); */ /* //TODO: Fill in with actual value, Frame number to apply the SI configuration */ /* si_config->sfn = 1; */ /* si_config->has_sfn = 1; */ @@ -1928,15 +1928,15 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Progr /* si_config->has_si_window_length = 1; */ /* //TODO: Fill in with actual value, the number of SI messages */ /* si_config->n_si_message=1; */ - /* Protocol__PrpSiMessage **si_message; */ - /* si_message = malloc(sizeof(Protocol__PrpSiMessage *) * si_config->n_si_message); */ + /* Protocol__FlexSiMessage **si_message; */ + /* si_message = malloc(sizeof(Protocol__FlexSiMessage *) * si_config->n_si_message); */ /* if(si_message == NULL) */ /* goto error; */ /* for(j = 0; j < si_config->n_si_message; j++){ */ - /* si_message[j] = malloc(sizeof(Protocol__PrpSiMessage)); */ + /* si_message[j] = malloc(sizeof(Protocol__FlexSiMessage)); */ /* if(si_message[j] == NULL) */ /* goto error; */ - /* protocol__prp_si_message__init(si_message[j]); */ + /* protocol__flex_si_message__init(si_message[j]); */ /* //TODO: Fill in with actual value, Periodicity of SI msg in radio frames */ /* si_message[j]->periodicity = 1; //SIPeriod */ /* si_message[j]->has_periodicity = 1; */ @@ -1955,29 +1955,29 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Progr //TODO: Fill in with actual value, the UL transmission bandwidth in RBs cell_conf[i]->ul_bandwidth = get_N_RB_UL(enb_id,i); cell_conf[i]->has_ul_bandwidth = 1; - //TODO: Fill in with actual value, one of PRUCPL values + //TODO: Fill in with actual value, one of FLUCPL values if(get_ul_cyclic_prefix_length(enb_id,i) == 0){ - cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__PRP_UL_CYCLIC_PREFIX_LENGTH__PRUCPL_NORMAL; + cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_UL_CYCLIC_PREFIX_LENGTH__FLUCPL_NORMAL; }else if(get_ul_cyclic_prefix_length(enb_id,i) == 1){ - cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__PRP_UL_CYCLIC_PREFIX_LENGTH__PRUCPL_EXTENDED; + cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_UL_CYCLIC_PREFIX_LENGTH__FLUCPL_EXTENDED; } cell_conf[i]->has_ul_cyclic_prefix_length = 1; - //TODO: Fill in with actual value, one of PRUCPL values + //TODO: Fill in with actual value, one of FLUCPL values if(get_ul_cyclic_prefix_length(enb_id,i) == 0){ - cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__PRP_DL_CYCLIC_PREFIX_LENGTH__PRDCPL_NORMAL; + cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_DL_CYCLIC_PREFIX_LENGTH__FLDCPL_NORMAL; }else if(get_ul_cyclic_prefix_length(enb_id,i) == 1){ - cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__PRP_DL_CYCLIC_PREFIX_LENGTH__PRDCPL_EXTENDED; + cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_DL_CYCLIC_PREFIX_LENGTH__FLDCPL_EXTENDED; } cell_conf[i]->has_dl_cyclic_prefix_length = 1; //TODO: Fill in with actual value, number of cell specific antenna ports cell_conf[i]->antenna_ports_count = 1; cell_conf[i]->has_antenna_ports_count = 1; - //TODO: Fill in with actual value, one of PRDM values + //TODO: Fill in with actual value, one of FLDM values if(get_duplex_mode(enb_id,i) == 1){ - cell_conf[i]->duplex_mode = PROTOCOL__PRP_DUPLEX_MODE__PRDM_FDD; + cell_conf[i]->duplex_mode = PROTOCOL__FLEX_DUPLEX_MODE__FLDM_FDD; }else if(get_duplex_mode(enb_id,i) == 0){ - cell_conf[i]->duplex_mode = PROTOCOL__PRP_DUPLEX_MODE__PRDM_TDD; + cell_conf[i]->duplex_mode = PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD; } cell_conf[i]->has_duplex_mode = 1; //TODO: Fill in with actual value, DL/UL subframe assignment. TDD only @@ -2052,11 +2052,11 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Progr //TODO: Fill in with actual value, Boolean value. See TS 36.211, section 5.5.3.2. TDD only cell_conf[i]->srs_mac_up_pts = get_srs_MaxUpPts(enb_id,i); cell_conf[i]->has_srs_mac_up_pts = 1; - //TODO: Fill in with actual value, One of the PREQ_ values + //TODO: Fill in with actual value, One of the FLEQ_ values if(get_enable64QAM(enb_id,i) == 0){ - cell_conf[i]->enable_64qam = PROTOCOL__PRP_QAM__PREQ_MOD_16QAM; + cell_conf[i]->enable_64qam = PROTOCOL__FLEX_QAM__FLEQ_MOD_16QAM; }else if(get_enable64QAM(enb_id,i) == 1){ - cell_conf[i]->enable_64qam = PROTOCOL__PRP_QAM__PREQ_MOD_64QAM; + cell_conf[i]->enable_64qam = PROTOCOL__FLEX_QAM__FLEQ_MOD_64QAM; } cell_conf[i]->has_enable_64qam = 1; //TODO: Fill in with actual value, Carrier component index @@ -2065,12 +2065,12 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Progr } enb_config_reply_msg->cell_config=cell_conf; } - *msg = malloc(sizeof(Protocol__ProgranMessage)); + *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; (*msg)->enb_config_reply_msg = enb_config_reply_msg; return 0; @@ -2104,7 +2104,7 @@ err_code_t enb_agent_init_timer(void){ memset(&e, 0, sizeof(enb_agent_timer_element_t)); RB_INSERT(enb_agent_map, &agent_map, &e); */ - return PROTOCOL__PROGRAN_ERR__NO_ERR; + return PROTOCOL__FLEXRAN_ERR__NO_ERR; } RB_GENERATE(enb_agent_map,enb_agent_timer_element_s, entry, enb_agent_compare_timer); @@ -2190,7 +2190,7 @@ err_code_t enb_agent_destroy_timer(long timer_id){ if (e != NULL ) { RB_REMOVE(enb_agent_map, &timer_instance.enb_agent_head, e); - enb_agent_destroy_progran_message(e->timer_args->msg); + enb_agent_destroy_flexran_message(e->timer_args->msg); free(e); } @@ -2211,7 +2211,7 @@ err_code_t enb_agent_destroy_timer_by_task_id(xid_t xid) { if (e->xid == xid) { timer_id = e->timer_id; RB_REMOVE(enb_agent_map, &timer_instance.enb_agent_head, e); - enb_agent_destroy_progran_message(e->timer_args->msg); + enb_agent_destroy_flexran_message(e->timer_args->msg); free(e); if (timer_remove(timer_id) < 0 ) { goto error; @@ -2232,7 +2232,7 @@ err_code_t enb_agent_destroy_timers(void){ RB_FOREACH(e, enb_agent_map, &timer_instance.enb_agent_head) { RB_REMOVE(enb_agent_map, &timer_instance.enb_agent_head, e); timer_remove(e->timer_id); - enb_agent_destroy_progran_message(e->timer_args->msg); + enb_agent_destroy_flexran_message(e->timer_args->msg); free(e); } @@ -2310,7 +2310,7 @@ err_code_t enb_agent_restart_timer(uint32_t *timer_id){ } if (ret < 0 ) { - return PROTOCOL__PROGRAN_ERR__TIMER_SETUP_FAILED; + return PROTOCOL__FLEXRAN_ERR__TIMER_SETUP_FAILED; } return 0; diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index 18c9129989..b5a35ec338 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -29,7 +29,7 @@ /*! \file enb_agent_common.h * \brief common message primitves and utilities - * \author Navid Nikaein and Xenofon Foukas + * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein * \date 2016 * \version 0.1 */ @@ -42,7 +42,7 @@ #include #include "header.pb-c.h" -#include "progran.pb-c.h" +#include "flexran.pb-c.h" #include "stats_messages.pb-c.h" #include "stats_common.pb-c.h" @@ -56,72 +56,72 @@ # include "intertask_interface.h" # include "timer.h" -#define PROGRAN_VERSION 0 +#define FLEXRAN_VERSION 0 typedef int (*enb_agent_message_decoded_callback)( mid_t mod_id, const void *params, - Protocol__ProgranMessage **msg + Protocol__FlexranMessage **msg ); typedef int (*enb_agent_message_destruction_callback)( - Protocol__ProgranMessage *msg + Protocol__FlexranMessage *msg ); /********************************** - * progRAN protocol messages helper + * FlexRAN protocol messages helper * functions and generic handlers **********************************/ -int enb_agent_serialize_message(Protocol__ProgranMessage *msg, void **buf, int *size); -int enb_agent_deserialize_message(void *data, int size, Protocol__ProgranMessage **msg); +int enb_agent_serialize_message(Protocol__FlexranMessage *msg, void **buf, int *size); +int enb_agent_deserialize_message(void *data, int size, Protocol__FlexranMessage **msg); -void * enb_agent_pack_message(Protocol__ProgranMessage *msg, +void * enb_agent_pack_message(Protocol__FlexranMessage *msg, uint32_t * size); -err_code_t enb_agent_destroy_progran_message(Protocol__ProgranMessage *msg); +err_code_t enb_agent_destroy_flexran_message(Protocol__FlexranMessage *msg); -int prp_create_header(xid_t xid, Protocol__PrpType type, Protocol__PrpHeader **header); +int flex_create_header(xid_t xid, Protocol__FlexType type, Protocol__FlexHeader **header); -int enb_agent_hello(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); -int enb_agent_destroy_hello(Protocol__ProgranMessage *msg); +int enb_agent_hello(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int enb_agent_destroy_hello(Protocol__FlexranMessage *msg); -int enb_agent_echo_request(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); -int enb_agent_destroy_echo_request(Protocol__ProgranMessage *msg); +int enb_agent_echo_request(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int enb_agent_destroy_echo_request(Protocol__FlexranMessage *msg); -int enb_agent_echo_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); -int enb_agent_destroy_echo_reply(Protocol__ProgranMessage *msg); +int enb_agent_echo_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int enb_agent_destroy_echo_reply(Protocol__FlexranMessage *msg); -int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); -int enb_agent_destroy_enb_config_reply(Protocol__ProgranMessage *msg); +int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int enb_agent_destroy_enb_config_reply(Protocol__FlexranMessage *msg); -int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); -int enb_agent_destroy_ue_config_reply(Protocol__ProgranMessage *msg); +int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int enb_agent_destroy_ue_config_reply(Protocol__FlexranMessage *msg); -int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); -int enb_agent_destroy_lc_config_reply(Protocol__ProgranMessage *msg); +int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int enb_agent_destroy_lc_config_reply(Protocol__FlexranMessage *msg); -int enb_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__ProgranMessage **msg); -int enb_agent_destroy_enb_config_request(Protocol__ProgranMessage *msg); +int enb_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg); +int enb_agent_destroy_enb_config_request(Protocol__FlexranMessage *msg); -int enb_agent_destroy_ue_config_request(Protocol__ProgranMessage *msg); +int enb_agent_destroy_ue_config_request(Protocol__FlexranMessage *msg); -int enb_agent_destroy_lc_config_request(Protocol__ProgranMessage *msg); +int enb_agent_destroy_lc_config_request(Protocol__FlexranMessage *msg); int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change); -int enb_agent_destroy_ue_state_change(Protocol__ProgranMessage *msg); +int enb_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg); -int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); -int enb_agent_destroy_control_delegation(Protocol__ProgranMessage *msg); +int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int enb_agent_destroy_control_delegation(Protocol__FlexranMessage *msg); -int enb_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); -int enb_agent_destroy_agent_reconfiguration(Protocol__ProgranMessage *msg); +int enb_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int enb_agent_destroy_agent_reconfiguration(Protocol__FlexranMessage *msg); -Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, +Protocol__FlexranMessage* enb_agent_handle_message (mid_t mod_id, uint8_t *data, uint32_t size); -Protocol__ProgranMessage *enb_agent_handle_timed_task(void *args); +Protocol__FlexranMessage *enb_agent_handle_timed_task(void *args); @@ -145,7 +145,7 @@ unsigned int get_current_system_frame_num(mid_t mod_id); unsigned int 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 progRAN protocol*/ + Bits 0-3 subframe, rest for frame. Required by FlexRAN protocol*/ uint16_t get_sfn_sf (mid_t mod_id); uint16_t get_future_sfn_sf(mid_t mod_id, int ahead_of_time); @@ -287,7 +287,7 @@ int get_direction(mid_t ue_id, mid_t lc_id); /* Type of the callback executed when the timer expired */ -typedef Protocol__ProgranMessage *(*enb_agent_timer_callback_t)(void*); +typedef Protocol__FlexranMessage *(*enb_agent_timer_callback_t)(void*); typedef enum { /* oneshot timer: */ @@ -319,7 +319,7 @@ typedef enum { typedef struct enb_agent_timer_args_s{ mid_t mod_id; - Protocol__ProgranMessage *msg; + Protocol__FlexranMessage *msg; } enb_agent_timer_args_t; @@ -371,7 +371,7 @@ err_code_t enb_agent_restart_timer(long *timer_id); struct enb_agent_timer_element_s * get_timer_entry(long timer_id); -Protocol__ProgranMessage * enb_agent_process_timeout(long timer_id, void* timer_args); +Protocol__FlexranMessage * enb_agent_process_timeout(long timer_id, void* timer_args); int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b); diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/enb_agent_handler.c index da53343818..46459f98bc 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/enb_agent_handler.c @@ -29,7 +29,7 @@ /*! \file enb_agent_handler.c * \brief enb agent tx and rx message handler - * \author Navid Nikaein and Xenofon Foukas + * \author Xenofon Foukas and Navid Nikaein * \date 2016 * \version 0.1 */ @@ -42,23 +42,23 @@ #include "assertions.h" enb_agent_message_decoded_callback agent_messages_callback[][3] = { - {enb_agent_hello, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_HELLO_MSG*/ - {enb_agent_echo_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REQUEST_MSG*/ - {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ECHO_REPLY_MSG*/ //Must add handler when receiving echo reply - {enb_agent_mac_handle_stats, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG*/ - {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG*/ - {0, 0, 0}, /*PROTOCOK__PROGRAN_MESSAGE__MSG_SF_TRIGGER_MSG*/ - {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_UL_SR_INFO_MSG*/ - {enb_agent_enb_config_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG*/ - {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG*/ - {enb_agent_ue_config_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_UE_CONFIG_REQUEST_MSG*/ - {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG*/ - {enb_agent_lc_config_reply, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REQUEST_MSG*/ - {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG*/ - {enb_agent_mac_handle_dl_mac_config, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG*/ - {0, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG*/ - {enb_agent_control_delegation, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_CONTROL_DELEGATION_MSG*/ - {enb_agent_reconfiguration, 0, 0}, /*PROTOCOL__PROGRAN_MESSAGE__MSG_AGENT_RECONFIGURATION_MSG*/ + {enb_agent_hello, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_HELLO_MSG*/ + {enb_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 + {enb_agent_mac_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*/ + {enb_agent_enb_config_reply, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG*/ + {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG*/ + {enb_agent_ue_config_reply, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_CONFIG_REQUEST_MSG*/ + {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG*/ + {enb_agent_lc_config_reply, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_LC_CONFIG_REQUEST_MSG*/ + {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG*/ + {enb_agent_mac_handle_dl_mac_config, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG*/ + {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG*/ + {enb_agent_control_delegation, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_CONTROL_DELEGATION_MSG*/ + {enb_agent_reconfiguration, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_AGENT_RECONFIGURATION_MSG*/ }; enb_agent_message_destruction_callback message_destruction_callback[] = { @@ -89,27 +89,27 @@ static const char *enb_agent_direction2String[] = { }; -Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, +Protocol__FlexranMessage* enb_agent_handle_message (mid_t mod_id, uint8_t *data, uint32_t size){ - Protocol__ProgranMessage *decoded_message, *reply_message; + Protocol__FlexranMessage *decoded_message, *reply_message; err_code_t err_code; DevAssert(data != NULL); if (enb_agent_deserialize_message(data, size, &decoded_message) < 0) { - err_code= PROTOCOL__PROGRAN_ERR__MSG_DECODING; + err_code= PROTOCOL__FLEXRAN_ERR__MSG_DECODING; goto error; } if ((decoded_message->msg_case > sizeof(agent_messages_callback) / (3*sizeof(enb_agent_message_decoded_callback))) || - (decoded_message->msg_dir > PROTOCOL__PROGRAN_DIRECTION__UNSUCCESSFUL_OUTCOME)){ - err_code= PROTOCOL__PROGRAN_ERR__MSG_NOT_HANDLED; + (decoded_message->msg_dir > PROTOCOL__FLEXRAN_DIRECTION__UNSUCCESSFUL_OUTCOME)){ + err_code= PROTOCOL__FLEXRAN_ERR__MSG_NOT_HANDLED; goto error; } if (agent_messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1] == NULL) { - err_code= PROTOCOL__PROGRAN_ERR__MSG_NOT_SUPPORTED; + err_code= PROTOCOL__FLEXRAN_ERR__MSG_NOT_SUPPORTED; goto error; } @@ -118,7 +118,7 @@ Protocol__ProgranMessage* enb_agent_handle_message (mid_t mod_id, if ( err_code < 0 ){ goto error; } else if (err_code == 1) { //If err_code > 1, we do not want to dispose the message yet - protocol__progran_message__free_unpacked(decoded_message, NULL); + protocol__flexran_message__free_unpacked(decoded_message, NULL); } return reply_message; @@ -130,14 +130,14 @@ error: -void * enb_agent_pack_message(Protocol__ProgranMessage *msg, +void * enb_agent_pack_message(Protocol__FlexranMessage *msg, uint32_t * size){ void * buffer; - err_code_t err_code = PROTOCOL__PROGRAN_ERR__NO_ERR; + err_code_t err_code = PROTOCOL__FLEXRAN_ERR__NO_ERR; if (enb_agent_serialize_message(msg, &buffer, size) < 0 ) { - err_code = PROTOCOL__PROGRAN_ERR__MSG_ENCODING; + err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENCODING; goto error; } @@ -157,11 +157,11 @@ void * enb_agent_pack_message(Protocol__ProgranMessage *msg, return NULL; } -Protocol__ProgranMessage *enb_agent_handle_timed_task(void *args) { +Protocol__FlexranMessage *enb_agent_handle_timed_task(void *args) { err_code_t err_code; enb_agent_timer_args_t *timer_args = (enb_agent_timer_args_t *) args; - Protocol__ProgranMessage *timed_task, *reply_message; + Protocol__FlexranMessage *timed_task, *reply_message; timed_task = timer_args->msg; err_code = ((*agent_messages_callback[timed_task->msg_case-1][timed_task->msg_dir-1])(timer_args->mod_id, (void *) timed_task, &reply_message)); if ( err_code < 0 ){ @@ -175,7 +175,7 @@ Protocol__ProgranMessage *enb_agent_handle_timed_task(void *args) { return NULL; } -Protocol__ProgranMessage* enb_agent_process_timeout(long timer_id, void* timer_args){ +Protocol__FlexranMessage* enb_agent_process_timeout(long timer_id, void* timer_args){ struct enb_agent_timer_element_s *found = get_timer_entry(timer_id); @@ -192,6 +192,6 @@ Protocol__ProgranMessage* enb_agent_process_timeout(long timer_id, void* timer_a return TIMER_ELEMENT_NOT_FOUND; } -err_code_t enb_agent_destroy_progran_message(Protocol__ProgranMessage *msg) { +err_code_t enb_agent_destroy_flexran_message(Protocol__FlexranMessage *msg) { return ((*message_destruction_callback[msg->msg_case-1])(msg)); } diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 744768135e..d040622a02 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -29,7 +29,7 @@ /*! \file enb_agent_mac.c * \brief enb agent message handler for MAC layer - * \author Navid Nikaein and Xenofon Foukas + * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein * \date 2016 * \version 0.1 */ @@ -61,7 +61,7 @@ struct lfds700_ringbuffer_element *dl_mac_config_array[NUM_MAX_ENB]; struct lfds700_ringbuffer_state ringbuffer_state[NUM_MAX_ENB]; -int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg){ +int enb_agent_mac_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 @@ -86,16 +86,16 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr uint32_t ue_flags = 0; uint32_t c_flags = 0; - Protocol__ProgranMessage *input = (Protocol__ProgranMessage *)params; + Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; - Protocol__PrpStatsRequest *stats_req = input->stats_request_msg; + 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__PRP_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ; - Protocol__PrpCompleteStatsRequest *comp_req = stats_req->complete_stats_request; - if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_OFF) { + 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*/ enb_agent_disable_cont_mac_stats_update(mod_id); enb_agent_destroy_timer_by_task_id(xid); @@ -133,12 +133,12 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr report_config.cc_report_type[i].cc_report_flags = c_flags; } /* Check if request was periodical */ - if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_PERIODICAL) { - /* Create a one off progran message as an argument for the periodical task */ - Protocol__ProgranMessage *timer_msg; + 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__PRP_STATS_TYPE__PRST_COMPLETE_STATS; - request_config.report_frequency = PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_ONCE; + 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) { @@ -170,13 +170,13 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr usec_interval = usec_interval%(1000*1000); } enb_agent_create_timer(sec_interval, usec_interval, ENB_AGENT_DEFAULT, enb_id, ENB_AGENT_TIMER_TYPE_PERIODIC, xid, enb_agent_handle_timed_task,(void*) timer_args, &timer_id); - } else if (comp_req->report_frequency == PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_CONTINUOUS) { + } 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*/ enb_agent_disable_cont_mac_stats_update(mod_id); stats_request_config_t request_config; - request_config.report_type = PROTOCOL__PRP_STATS_TYPE__PRST_COMPLETE_STATS; - request_config.report_frequency = PROTOCOL__PRP_STATS_REPORT_FREQ__PRSRF_ONCE; + 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) { @@ -195,8 +195,8 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr } } break; - case PROTOCOL__PRP_STATS_REQUEST__BODY_CELL_STATS_REQUEST:; - Protocol__PrpCellStatsRequest *cell_req = stats_req->cell_stats_request; + 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; @@ -213,8 +213,8 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr report_config.cc_report_type[i].cc_report_flags = cell_req->flags; } break; - case PROTOCOL__PRP_STATS_REQUEST__BODY_UE_STATS_REQUEST:; - Protocol__PrpUeStatsRequest *ue_req = stats_req->ue_stats_request; + 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; @@ -237,7 +237,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr } if (enb_agent_mac_stats_reply(enb_id, xid, &report_config, msg) < 0 ){ - err_code = PROTOCOL__PROGRAN_ERR__MSG_BUILD; + err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; goto error; } @@ -254,32 +254,32 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Progr int enb_agent_mac_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, - Protocol__ProgranMessage **msg) { - Protocol__PrpHeader *header; + Protocol__FlexranMessage **msg) { + Protocol__FlexHeader *header; int i; - if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_STATS_REQUEST, &header) != 0) + if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REQUEST, &header) != 0) goto error; - Protocol__PrpStatsRequest *stats_request_msg; - stats_request_msg = malloc(sizeof(Protocol__PrpStatsRequest)); + Protocol__FlexStatsRequest *stats_request_msg; + stats_request_msg = malloc(sizeof(Protocol__FlexStatsRequest)); if(stats_request_msg == NULL) goto error; - protocol__prp_stats_request__init(stats_request_msg); + protocol__flex_stats_request__init(stats_request_msg); 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__PRP_STATS_TYPE__PRST_COMPLETE_STATS: - stats_request_msg->body_case = PROTOCOL__PRP_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST; - Protocol__PrpCompleteStatsRequest *complete_stats; - complete_stats = malloc(sizeof(Protocol__PrpCompleteStatsRequest)); + 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__prp_complete_stats_request__init(complete_stats); + 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; @@ -294,13 +294,13 @@ int enb_agent_mac_stats_request(mid_t mod_id, } stats_request_msg->complete_stats_request = complete_stats; break; - case PROTOCOL__PRP_STATS_TYPE__PRST_CELL_STATS: - stats_request_msg->body_case = PROTOCOL__PRP_STATS_REQUEST__BODY_CELL_STATS_REQUEST; - Protocol__PrpCellStatsRequest *cell_stats; - cell_stats = malloc(sizeof(Protocol__PrpCellStatsRequest)); + 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__prp_cell_stats_request__init(cell_stats); + 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) { @@ -314,13 +314,13 @@ int enb_agent_mac_stats_request(mid_t mod_id, } stats_request_msg->cell_stats_request = cell_stats; break; - case PROTOCOL__PRP_STATS_TYPE__PRST_UE_STATS: - stats_request_msg->body_case = PROTOCOL__PRP_STATS_REQUEST__BODY_UE_STATS_REQUEST; - Protocol__PrpUeStatsRequest *ue_stats; - ue_stats = malloc(sizeof(Protocol__PrpUeStatsRequest)); + 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__prp_ue_stats_request__init(ue_stats); + 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) { @@ -337,12 +337,12 @@ int enb_agent_mac_stats_request(mid_t mod_id, default: goto error; } - *msg = malloc(sizeof(Protocol__ProgranMessage)); + *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + 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; @@ -358,14 +358,14 @@ int enb_agent_mac_stats_request(mid_t mod_id, return -1; } -int enb_agent_mac_destroy_stats_request(Protocol__ProgranMessage *msg) { - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REQUEST_MSG) +int enb_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__PRP_STATS_REQUEST__BODY_CELL_STATS_REQUEST) { + 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__PRP_STATS_REQUEST__BODY_UE_STATS_REQUEST) { + 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); @@ -380,8 +380,8 @@ int enb_agent_mac_destroy_stats_request(Protocol__ProgranMessage *msg) { int enb_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *report_config, - Protocol__ProgranMessage **msg) { - Protocol__PrpHeader *header; + Protocol__FlexranMessage **msg) { + Protocol__FlexHeader *header; int i, j, k; int cc_id = 0; int enb_id = mod_id; @@ -389,31 +389,31 @@ int enb_agent_mac_stats_reply(mid_t mod_id, //UE_list_t *eNB_UE_list= &eNB->UE_list; - if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_STATS_REPLY, &header) != 0) + if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) goto error; - Protocol__PrpStatsReply *stats_reply_msg; - stats_reply_msg = malloc(sizeof(Protocol__PrpStatsReply)); + Protocol__FlexStatsReply *stats_reply_msg; + stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply)); if (stats_reply_msg == NULL) goto error; - protocol__prp_stats_reply__init(stats_reply_msg); + 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; - Protocol__PrpUeStatsReport **ue_report; - Protocol__PrpCellStatsReport **cell_report; + 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__PrpUeStatsReport *) * report_config->nr_ue); + 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__PrpUeStatsReport)); - protocol__prp_ue_stats_report__init(ue_report[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; @@ -421,9 +421,9 @@ int enb_agent_mac_stats_reply(mid_t mod_id, /* 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__PRP_UE_STATS_TYPE__PRUST_BSR) { - //TODO: Create a report for each LCG (4 elements). See prp_ue_stats_report of - // progRAN specifications for more details + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_BSR) { + //TODO: Create a report for each LCG (4 elements). See flex_ue_stats_report of + // FlexRAN specifications for more details ue_report[i]->n_bsr = 4; uint32_t *elem; elem = (uint32_t *) malloc(sizeof(uint32_t)*ue_report[i]->n_bsr); @@ -438,28 +438,28 @@ int enb_agent_mac_stats_reply(mid_t mod_id, } /* Check flag for creation of PRH report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PRH) { + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PRH) { // TODO: Fill in the actual power headroom value for the RNTI ue_report[i]->phr = 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__PRP_UE_STATS_TYPE__PRUST_RLC_BS) { + if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RLC_BS) { // TODO: Fill in the actual RLC buffer status reports ue_report[i]->n_rlc_report = 3; // Set this to the number of LCs for this UE - Protocol__PrpRlcBsr ** rlc_reports; - rlc_reports = malloc(sizeof(Protocol__PrpRlcBsr *) * ue_report[i]->n_rlc_report); + Protocol__FlexRlcBsr ** rlc_reports; + rlc_reports = malloc(sizeof(Protocol__FlexRlcBsr *) * ue_report[i]->n_rlc_report); if (rlc_reports == NULL) goto error; // Fill the buffer status report for each logical channel of the UE // 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__PrpRlcBsr)); + rlc_reports[j] = malloc(sizeof(Protocol__FlexRlcBsr)); if (rlc_reports[j] == NULL) goto error; - protocol__prp_rlc_bsr__init(rlc_reports[j]); + protocol__flex_rlc_bsr__init(rlc_reports[j]); //TODO:Set logical channel id rlc_reports[j]->lc_id = j+1; rlc_reports[j]->has_lc_id = 1; @@ -485,38 +485,38 @@ int enb_agent_mac_stats_reply(mid_t mod_id, } /* Check flag for creation of MAC CE buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_MAC_CE_BS) { + 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 = (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__PRP_CE_TYPE__PRPCET_ values + PROTOCOL__FLEX_CE_TYPE__FLPCET_ values found in stats_common.pb-c.h. See - prp_ce_type in progRAN specification */ + flex_ce_type in FlexRAN specification */ ue_report[i]->has_pending_mac_ces = 1; } /* Check flag for creation of DL CQI report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI) { + 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__PrpDlCqiReport * dl_report; - dl_report = malloc(sizeof(Protocol__PrpDlCqiReport)); + Protocol__FlexDlCqiReport * dl_report; + dl_report = malloc(sizeof(Protocol__FlexDlCqiReport)); if (dl_report == NULL) goto error; - protocol__prp_dl_cqi_report__init(dl_report); + protocol__flex_dl_cqi_report__init(dl_report); //TODO:Set the SFN and SF of the last report held in the agent. dl_report->sfn_sn = get_sfn_sf(enb_id); dl_report->has_sfn_sn = 1; //TODO:Set the number of DL CQI reports for this UE. One for each CC dl_report->n_csi_report = get_active_CC(enb_id,i); //TODO:Create the actual CSI reports. - Protocol__PrpDlCsi **csi_reports; - csi_reports = malloc(sizeof(Protocol__PrpDlCsi *)*dl_report->n_csi_report); + 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__PrpDlCsi)); + csi_reports[j] = malloc(sizeof(Protocol__FlexDlCsi)); if (csi_reports[j] == NULL) goto error; - protocol__prp_dl_csi__init(csi_reports[j]); + protocol__flex_dl_csi__init(csi_reports[j]); //TODO: the servCellIndex for this report csi_reports[j]->serv_cell_index = j; csi_reports[j]->has_serv_cell_index = 1; @@ -526,16 +526,16 @@ int enb_agent_mac_stats_reply(mid_t mod_id, //TODO: the type of CSI report based on the configuration of the UE //For this example we use 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 progRAN specifications - csi_reports[j]->type = PROTOCOL__PRP_CSI_TYPE__PRCSIT_P10; + //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__PRP_DL_CSI__REPORT_P10CSI; - if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_P10CSI){ - Protocol__PrpCsiP10 *csi10; - csi10 = malloc(sizeof(Protocol__PrpCsiP10)); + 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__prp_csi_p10__init(csi10); + protocol__flex_csi_p10__init(csi10); //TODO: set the wideband value // NN: this is also depends on cc_id csi10->wb_cqi = get_ue_wcqi (enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].dl_cqi; @@ -543,28 +543,28 @@ int enb_agent_mac_stats_reply(mid_t mod_id, //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__PRP_DL_CSI__REPORT_P11CSI){ + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P11CSI){ } - else if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_P20CSI){ + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P20CSI){ } - else if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_P21CSI){ + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P21CSI){ } - else if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_A12CSI){ + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A12CSI){ } - else if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_A22CSI){ + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A22CSI){ } - else if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_A20CSI){ + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A20CSI){ } - else if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_A30CSI){ + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A30CSI){ } - else if(csi_reports[j]->report_case == PROTOCOL__PRP_DL_CSI__REPORT_A31CSI){ + else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A31CSI){ } } @@ -575,26 +575,26 @@ int enb_agent_mac_stats_reply(mid_t mod_id, } /* Check flag for creation of paging buffer status report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PBS) { + 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__PrpPagingBufferReport *paging_report; - paging_report = malloc(sizeof(Protocol__PrpPagingBufferReport)); + Protocol__FlexPagingBufferReport *paging_report; + paging_report = malloc(sizeof(Protocol__FlexPagingBufferReport)); if (paging_report == NULL) goto error; - protocol__prp_paging_buffer_report__init(paging_report); + 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__PrpPagingInfo **p_info; - p_info = malloc(sizeof(Protocol__PrpPagingInfo *) * paging_report->n_paging_info); + 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__PrpPagingInfo)); + p_info[j] = malloc(sizeof(Protocol__FlexPagingInfo)); if(p_info[j] == NULL) goto error; - protocol__prp_paging_info__init(p_info[j]); + 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; @@ -616,35 +616,35 @@ int enb_agent_mac_stats_reply(mid_t mod_id, } /* Check flag for creation of UL CQI report */ - if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_UL_CQI) { + 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__PrpUlCqiReport *full_ul_report; - full_ul_report = malloc(sizeof(Protocol__PrpUlCqiReport)); + Protocol__FlexUlCqiReport *full_ul_report; + full_ul_report = malloc(sizeof(Protocol__FlexUlCqiReport)); if(full_ul_report == NULL) goto error; - protocol__prp_ul_cqi_report__init(full_ul_report); + protocol__flex_ul_cqi_report__init(full_ul_report); //TODO:Set the SFN and SF of the generated report full_ul_report->sfn_sn = 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__PrpUlCqi **ul_report; - ul_report = malloc(sizeof(Protocol__PrpUlCqi *) * full_ul_report->n_cqi_meas); + 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__PrpUlCqi)); + ul_report[j] = malloc(sizeof(Protocol__FlexUlCqi)); if(ul_report[j] == NULL) goto error; - protocol__prp_ul_cqi__init(ul_report[j]); + 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 prp_ul_cqi_type in progRAN specification for more details - ul_report[j]->type = PROTOCOL__PRP_UL_CQI_TYPE__PRUCT_SRS; + // 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 prp_ul_cqi in progRAN specification for more details + //See struct flex_ul_cqi in FlexRAN specification for more details ul_report[j]->n_sinr = 100; uint32_t *sinr_meas; sinr_meas = (uint32_t *) malloc(sizeof(uint32_t) * ul_report[j]->n_sinr); @@ -663,11 +663,11 @@ int enb_agent_mac_stats_reply(mid_t mod_id, full_ul_report->cqi_meas = ul_report; full_ul_report->n_pucch_dbm = MAX_NUM_CCs; - full_ul_report->pucch_dbm = malloc(sizeof(Protocol__PrpPucchDbm *) * full_ul_report->n_pucch_dbm); + 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__PrpPucchDbm)); - protocol__prp_pucch_dbm__init(full_ul_report->pucch_dbm[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(get_p0_pucch_dbm(enb_id,i, j) != -1){ @@ -687,28 +687,28 @@ int enb_agent_mac_stats_reply(mid_t mod_id, /* Allocate memory for list of cell reports */ if (report_config->nr_cc > 0) { - cell_report = malloc(sizeof(Protocol__PrpCellStatsReport *) * report_config->nr_cc); + 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__PrpCellStatsReport)); + cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport)); if(cell_report[i] == NULL) goto error; - protocol__prp_cell_stats_report__init(cell_report[i]); + 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; /* Check flag for creation of noise and interference report */ - if(report_config->cc_report_type[i].cc_report_flags & PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE) { + 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__PrpNoiseInterferenceReport *ni_report; - ni_report = malloc(sizeof(Protocol__PrpNoiseInterferenceReport)); + Protocol__FlexNoiseInterferenceReport *ni_report; + ni_report = malloc(sizeof(Protocol__FlexNoiseInterferenceReport)); if(ni_report == NULL) goto error; - protocol__prp_noise_interference_report__init(ni_report); + protocol__flex_noise_interference_report__init(ni_report); // Current frame and subframe number ni_report->sfn_sf = get_sfn_sf(enb_id); ni_report->has_sfn_sf = 1; @@ -728,12 +728,12 @@ int enb_agent_mac_stats_reply(mid_t mod_id, stats_reply_msg->cell_report = cell_report; } - *msg = malloc(sizeof(Protocol__ProgranMessage)); + *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + 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; @@ -749,17 +749,17 @@ int enb_agent_mac_stats_reply(mid_t mod_id, return -1; } -int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg) { +int enb_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg) { //TODO: Need to deallocate memory for the stats reply message - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG) + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG) goto error; free(msg->stats_reply_msg->header); int i, j, k; - Protocol__PrpStatsReply *reply = msg->stats_reply_msg; - Protocol__PrpDlCqiReport *dl_report; - Protocol__PrpUlCqiReport *ul_report; - Protocol__PrpPagingBufferReport *paging_report; + Protocol__FlexStatsReply *reply = msg->stats_reply_msg; + Protocol__FlexDlCqiReport *dl_report; + Protocol__FlexUlCqiReport *ul_report; + Protocol__FlexPagingBufferReport *paging_report; // Free the memory for the UE reports for (i = 0; i < reply->n_ue_report; i++) { @@ -769,47 +769,47 @@ int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg) { } free(reply->ue_report[i]->rlc_report); // If DL CQI report flag was set - if (reply->ue_report[i]->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI) { + if (reply->ue_report[i]->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_DL_CQI) { dl_report = reply->ue_report[i]->dl_cqi_report; // Delete all CSI reports for (j = 0; j < dl_report->n_csi_report; j++) { //Must free memory based on the type of report switch(dl_report->csi_report[j]->report_case) { - case PROTOCOL__PRP_DL_CSI__REPORT_P10CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI: free(dl_report->csi_report[j]->p10csi); break; - case PROTOCOL__PRP_DL_CSI__REPORT_P11CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_P11CSI: free(dl_report->csi_report[j]->p11csi->wb_cqi); free(dl_report->csi_report[j]->p11csi); break; - case PROTOCOL__PRP_DL_CSI__REPORT_P20CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_P20CSI: free(dl_report->csi_report[j]->p20csi); break; - case PROTOCOL__PRP_DL_CSI__REPORT_P21CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_P21CSI: free(dl_report->csi_report[j]->p21csi->wb_cqi); free(dl_report->csi_report[j]->p21csi->sb_cqi); free(dl_report->csi_report[j]->p21csi); break; - case PROTOCOL__PRP_DL_CSI__REPORT_A12CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_A12CSI: free(dl_report->csi_report[j]->a12csi->wb_cqi); free(dl_report->csi_report[j]->a12csi->sb_pmi); free(dl_report->csi_report[j]->a12csi); break; - case PROTOCOL__PRP_DL_CSI__REPORT_A22CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_A22CSI: free(dl_report->csi_report[j]->a22csi->wb_cqi); free(dl_report->csi_report[j]->a22csi->sb_cqi); free(dl_report->csi_report[j]->a22csi->sb_list); free(dl_report->csi_report[j]->a22csi); break; - case PROTOCOL__PRP_DL_CSI__REPORT_A20CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_A20CSI: free(dl_report->csi_report[j]->a20csi->sb_list); free(dl_report->csi_report[j]->a20csi); break; - case PROTOCOL__PRP_DL_CSI__REPORT_A30CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_A30CSI: free(dl_report->csi_report[j]->a30csi->sb_cqi); free(dl_report->csi_report[j]->a30csi); break; - case PROTOCOL__PRP_DL_CSI__REPORT_A31CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_A31CSI: free(dl_report->csi_report[j]->a31csi->wb_cqi); for (k = 0; k < dl_report->csi_report[j]->a31csi->n_sb_cqi; k++) { free(dl_report->csi_report[j]->a31csi->sb_cqi[k]); @@ -824,7 +824,7 @@ int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg) { free(dl_report); } // If Paging buffer report flag was set - if (reply->ue_report[i]->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PBS) { + if (reply->ue_report[i]->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PBS) { paging_report = reply->ue_report[i]->pbr; // Delete all paging buffer reports for (j = 0; j < paging_report->n_paging_info; j++) { @@ -834,7 +834,7 @@ int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg) { free(paging_report); } // If UL CQI report flag was set - if (reply->ue_report[i]->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_UL_CQI) { + if (reply->ue_report[i]->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_UL_CQI) { ul_report = reply->ue_report[i]->ul_cqi_report; for (j = 0; j < ul_report->n_cqi_meas; j++) { free(ul_report->cqi_meas[j]->sinr); @@ -866,19 +866,19 @@ int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg) { return -1; } -int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { - Protocol__PrpHeader *header; +int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { + Protocol__FlexHeader *header; int i; const int xid = *((int *)params); - if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_UL_SR_INFO, &header) != 0) + if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UL_SR_INFO, &header) != 0) goto error; - Protocol__PrpUlSrInfo *ul_sr_info_msg; - ul_sr_info_msg = malloc(sizeof(Protocol__PrpUlSrInfo)); + Protocol__FlexUlSrInfo *ul_sr_info_msg; + ul_sr_info_msg = malloc(sizeof(Protocol__FlexUlSrInfo)); if (ul_sr_info_msg == NULL) { goto error; } - protocol__prp_ul_sr_info__init(ul_sr_info_msg); + protocol__flex_ul_sr_info__init(ul_sr_info_msg); ul_sr_info_msg->header = header; ul_sr_info_msg->has_sfn_sf = 1; @@ -895,12 +895,12 @@ int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__ProgranMes ul_sr_info_msg->rnti[i] = 1; } - *msg = malloc(sizeof(Protocol__ProgranMessage)); + *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_UL_SR_INFO_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_UL_SR_INFO_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; (*msg)->ul_sr_info_msg = ul_sr_info_msg; return 0; @@ -918,8 +918,8 @@ int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__ProgranMes return -1; } -int enb_agent_mac_destroy_sr_info(Protocol__ProgranMessage *msg) { - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_UL_SR_INFO_MSG) +int enb_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg) { + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_UL_SR_INFO_MSG) goto error; free(msg->ul_sr_info_msg->header); @@ -933,19 +933,19 @@ int enb_agent_mac_destroy_sr_info(Protocol__ProgranMessage *msg) { return -1; } -int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { - Protocol__PrpHeader *header; +int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { + Protocol__FlexHeader *header; int i,j; const int xid = *((int *)params); - if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_SF_TRIGGER, &header) != 0) + if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_SF_TRIGGER, &header) != 0) goto error; - Protocol__PrpSfTrigger *sf_trigger_msg; - sf_trigger_msg = malloc(sizeof(Protocol__PrpSfTrigger)); + Protocol__FlexSfTrigger *sf_trigger_msg; + sf_trigger_msg = malloc(sizeof(Protocol__FlexSfTrigger)); if (sf_trigger_msg == NULL) { goto error; } - protocol__prp_sf_trigger__init(sf_trigger_msg); + protocol__flex_sf_trigger__init(sf_trigger_msg); frame_t frame; sub_frame_t subframe; @@ -974,18 +974,18 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran */ sf_trigger_msg->n_dl_info = get_num_ues(mod_id); - Protocol__PrpDlInfo **dl_info = NULL; + Protocol__FlexDlInfo **dl_info = NULL; if (sf_trigger_msg->n_dl_info > 0) { - dl_info = malloc(sizeof(Protocol__PrpDlInfo *) * sf_trigger_msg->n_dl_info); + dl_info = malloc(sizeof(Protocol__FlexDlInfo *) * sf_trigger_msg->n_dl_info); if(dl_info == NULL) goto error; //Fill the status of the current HARQ process for each UE for(i = 0; i < sf_trigger_msg->n_dl_info; i++) { - dl_info[i] = malloc(sizeof(Protocol__PrpDlInfo)); + dl_info[i] = malloc(sizeof(Protocol__FlexDlInfo)); if(dl_info[i] == NULL) goto error; - protocol__prp_dl_info__init(dl_info[i]); + protocol__flex_dl_info__init(dl_info[i]); dl_info[i]->rnti = get_ue_crnti(mod_id, i); dl_info[i]->has_rnti = 1; /*TODO: fill in the right id of this round's HARQ process for this UE*/ @@ -1000,9 +1000,9 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran for (j = 0; j < dl_info[i]->n_harq_status; j++) { // TODO: This should be different per TB if(harq_status == 0) - dl_info[i]->harq_status[j] = PROTOCOL__PRP_HARQ_STATUS__PRHS_ACK; + dl_info[i]->harq_status[j] = PROTOCOL__FLEX_HARQ_STATUS__FLHS_ACK; else if (harq_status == 1) - dl_info[i]->harq_status[j] = PROTOCOL__PRP_HARQ_STATUS__PRHS_NACK; + dl_info[i]->harq_status[j] = PROTOCOL__FLEX_HARQ_STATUS__FLHS_NACK; } /*TODO: fill in the serving cell index for this UE */ dl_info[i]->serv_cell_index = UE_PCCID(mod_id,i); @@ -1017,18 +1017,18 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran */ sf_trigger_msg->n_ul_info = get_num_ues(mod_id); - Protocol__PrpUlInfo **ul_info = NULL; + Protocol__FlexUlInfo **ul_info = NULL; if (sf_trigger_msg->n_ul_info > 0) { - ul_info = malloc(sizeof(Protocol__PrpUlInfo *) * sf_trigger_msg->n_ul_info); + ul_info = malloc(sizeof(Protocol__FlexUlInfo *) * sf_trigger_msg->n_ul_info); if(ul_info == NULL) goto error; //Fill the reception info for each transmitting UE for(i = 0; i < sf_trigger_msg->n_ul_info; i++) { - ul_info[i] = malloc(sizeof(Protocol__PrpUlInfo)); + ul_info[i] = malloc(sizeof(Protocol__FlexUlInfo)); if(ul_info[i] == NULL) goto error; - protocol__prp_ul_info__init(ul_info[i]); + protocol__flex_ul_info__init(ul_info[i]); ul_info[i]->rnti = get_ue_crnti(mod_id, i); ul_info[i]->has_rnti = 1; /*TODO: fill in the Tx power control command for this UE (if available)*/ @@ -1048,7 +1048,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran ul_info[i]->ul_reception[j] = 100; } /*TODO: Fill in the reception status for each UEs data*/ - ul_info[i]->reception_status = PROTOCOL__PRP_RECEPTION_STATUS__PRRS_OK; + ul_info[i]->reception_status = PROTOCOL__FLEX_RECEPTION_STATUS__FLRS_OK; ul_info[i]->has_reception_status = 1; /*TODO: fill in the serving cell index for this UE */ ul_info[i]->serv_cell_index = UE_PCCID(mod_id,i); @@ -1058,12 +1058,12 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran sf_trigger_msg->ul_info = ul_info; - *msg = malloc(sizeof(Protocol__ProgranMessage)); + *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_SF_TRIGGER_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_SF_TRIGGER_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; (*msg)->sf_trigger_msg = sf_trigger_msg; return 0; @@ -1087,9 +1087,9 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Progran return -1; } -int enb_agent_mac_destroy_sf_trigger(Protocol__ProgranMessage *msg) { +int enb_agent_mac_destroy_sf_trigger(Protocol__FlexranMessage *msg) { int i; - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_SF_TRIGGER_MSG) + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_SF_TRIGGER_MSG) goto error; free(msg->sf_trigger_msg->header); @@ -1113,30 +1113,30 @@ int enb_agent_mac_destroy_sf_trigger(Protocol__ProgranMessage *msg) { return -1; } -int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__ProgranMessage **msg) { +int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage **msg) { int xid = 0; - Protocol__PrpHeader *header; - if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_DL_MAC_CONFIG, &header) != 0) + Protocol__FlexHeader *header; + if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_DL_MAC_CONFIG, &header) != 0) goto error; - Protocol__PrpDlMacConfig *dl_mac_config_msg; - dl_mac_config_msg = malloc(sizeof(Protocol__PrpDlMacConfig)); + Protocol__FlexDlMacConfig *dl_mac_config_msg; + dl_mac_config_msg = malloc(sizeof(Protocol__FlexDlMacConfig)); if (dl_mac_config_msg == NULL) { goto error; } - protocol__prp_dl_mac_config__init(dl_mac_config_msg); + protocol__flex_dl_mac_config__init(dl_mac_config_msg); dl_mac_config_msg->header = header; dl_mac_config_msg->has_sfn_sf = 1; dl_mac_config_msg->sfn_sf = get_sfn_sf(mod_id); - *msg = malloc(sizeof(Protocol__ProgranMessage)); + *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; - protocol__progran_message__init(*msg); - (*msg)->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG; - (*msg)->msg_dir = PROTOCOL__PROGRAN_DIRECTION__INITIATING_MESSAGE; + protocol__flexran_message__init(*msg); + (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG; + (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; (*msg)->dl_mac_config_msg = dl_mac_config_msg; return 0; @@ -1145,12 +1145,12 @@ int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__ProgranMessage return -1; } -int enb_agent_mac_destroy_dl_config(Protocol__ProgranMessage *msg) { +int enb_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg) { int i,j, k; - if(msg->msg_case != PROTOCOL__PROGRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG) + if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG) goto error; - Protocol__PrpDlDci *dl_dci; + Protocol__FlexDlDci *dl_dci; free(msg->dl_mac_config_msg->header); for (i = 0; i < msg->dl_mac_config_msg->n_dl_ue_data; i++) { @@ -1208,7 +1208,7 @@ int enb_agent_mac_destroy_dl_config(Protocol__ProgranMessage *msg) { return -1; } -void enb_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__ProgranMessage **msg) { +void enb_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__FlexranMessage **msg) { struct lfds700_misc_prng_state ls; @@ -1220,11 +1220,11 @@ void enb_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__ProgranMessage } } -int enb_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg) { +int enb_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { struct lfds700_misc_prng_state ls; enum lfds700_misc_flag overwrite_occurred_flag; - Protocol__ProgranMessage *overwritten_dl_config; + Protocol__FlexranMessage *overwritten_dl_config; LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; lfds700_misc_prng_init(&ls); @@ -1264,7 +1264,7 @@ void enb_agent_init_mac_agent(mid_t mod_id) { void enb_agent_send_sr_info(mid_t mod_id) { int size; - Protocol__ProgranMessage *msg; + Protocol__FlexranMessage *msg; void *data; int priority; err_code_t err_code; @@ -1281,7 +1281,7 @@ void enb_agent_send_sr_info(mid_t mod_id) { data=enb_agent_pack_message(msg, &size); /*Send sr info using the MAC channel of the eNB*/ if (enb_agent_msg_send(mod_id, ENB_AGENT_MAC, data, size, priority)) { - err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } @@ -1294,7 +1294,7 @@ void enb_agent_send_sr_info(mid_t mod_id) { void enb_agent_send_sf_trigger(mid_t mod_id) { int size; - Protocol__ProgranMessage *msg; + Protocol__FlexranMessage *msg; void *data; int priority; err_code_t err_code; @@ -1311,7 +1311,7 @@ void enb_agent_send_sf_trigger(mid_t mod_id) { data=enb_agent_pack_message(msg, &size); /*Send sr info using the MAC channel of the eNB*/ if (enb_agent_msg_send(mod_id, ENB_AGENT_MAC, data, size, priority)) { - err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } @@ -1324,7 +1324,7 @@ void enb_agent_send_sf_trigger(mid_t mod_id) { void enb_agent_send_update_mac_stats(mid_t mod_id) { - Protocol__ProgranMessage *current_report = NULL, *msg; + Protocol__FlexranMessage *current_report = NULL, *msg; void *data; int size; err_code_t err_code; @@ -1352,7 +1352,7 @@ void enb_agent_send_update_mac_stats(mid_t mod_id) { /* msg = enb_agent_generate_diff_mac_stats_report(current_report, mac_stats_context[mod_id].prev_stats_reply); */ /* /\*Destroy the old stats*\/ */ - /* enb_agent_destroy_progran_message(mac_stats_context[mod_id].prev_stats_reply); */ + /* enb_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; */ @@ -1366,7 +1366,7 @@ void enb_agent_send_update_mac_stats(mid_t mod_id) { data=enb_agent_pack_message(current_report, &size); /*Send any stats updates using the MAC channel of the eNB*/ if (enb_agent_msg_send(mod_id, ENB_AGENT_MAC, data, size, priority)) { - err_code = PROTOCOL__PROGRAN_ERR__MSG_ENQUEUING; + err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } @@ -1447,8 +1447,8 @@ err_code_t enb_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; - enb_agent_destroy_progran_message(mac_stats_context[mod_id].stats_req); - enb_agent_destroy_progran_message(mac_stats_context[mod_id].prev_stats_reply); + enb_agent_destroy_flexran_message(mac_stats_context[mod_id].stats_req); + enb_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); free(mac_stats_context[mod_id].mutex); mac_agent_registered[mod_id] = NULL; @@ -1463,7 +1463,7 @@ err_code_t enb_agent_enable_cont_mac_stats_update(mid_t mod_id, goto error; } - Protocol__ProgranMessage *req_msg; + Protocol__FlexranMessage *req_msg; enb_agent_mac_stats_request(mod_id, xid, stats_req, &req_msg); mac_stats_context[mod_id].stats_req = req_msg; @@ -1490,10 +1490,10 @@ err_code_t enb_agent_disable_cont_mac_stats_update(mid_t mod_id) { mac_stats_context[mod_id].cont_update = 0; mac_stats_context[mod_id].xid = 0; if (mac_stats_context[mod_id].stats_req != NULL) { - enb_agent_destroy_progran_message(mac_stats_context[mod_id].stats_req); + enb_agent_destroy_flexran_message(mac_stats_context[mod_id].stats_req); } if (mac_stats_context[mod_id].prev_stats_reply != NULL) { - enb_agent_destroy_progran_message(mac_stats_context[mod_id].prev_stats_reply); + enb_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); } if (pthread_mutex_unlock(mac_stats_context[mod_id].mutex)) { goto error; diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index 2a8f4c3a40..a6b9a0fe80 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -29,7 +29,7 @@ /*! \file enb_agent_mac.h * \brief enb agent message handler APIs for MAC layer - * \author Navid Nikaein and Xenofon Foukas + * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein * \date 2016 * \version 0.1 */ @@ -38,7 +38,7 @@ #define ENB_AGENT_MAC_H_ #include "header.pb-c.h" -#include "progran.pb-c.h" +#include "flexran.pb-c.h" #include "stats_messages.pb-c.h" #include "stats_common.pb-c.h" @@ -52,14 +52,14 @@ typedef struct { uint16_t ue_rnti; uint32_t ue_report_flags; /* Indicates the report elements required for this UE id. See - ProgRAN specification 1.2.4.2 */ + 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 - ProgRAN specification 1.2.4.3 */ + FlexRAN specification 1.2.4.3 */ } cc_report_type_t; typedef struct { @@ -79,29 +79,29 @@ typedef struct stats_request_config_s{ /* Initialization function for the agent structures etc */ void enb_agent_init_mac_agent(mid_t mod_id); -int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); -int enb_agent_mac_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__ProgranMessage **msg); +int enb_agent_mac_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); -int enb_agent_mac_destroy_stats_request(Protocol__ProgranMessage *msg); +int enb_agent_mac_destroy_stats_request(Protocol__FlexranMessage *msg); -int enb_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *report_config, Protocol__ProgranMessage **msg); +int enb_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg); -int enb_agent_mac_destroy_stats_reply(Protocol__ProgranMessage *msg); +int enb_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg); -int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); -int enb_agent_mac_destroy_sr_info(Protocol__ProgranMessage *msg); +int enb_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg); -int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); -int enb_agent_mac_destroy_sf_trigger(Protocol__ProgranMessage *msg); +int enb_agent_mac_destroy_sf_trigger(Protocol__FlexranMessage *msg); -int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__ProgranMessage **msg); +int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage **msg); -int enb_agent_mac_destroy_dl_config(Protocol__ProgranMessage *msg); +int enb_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg); -int enb_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protocol__ProgranMessage **msg); +int enb_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); /********************************** @@ -119,7 +119,7 @@ void enb_agent_send_sf_trigger(mid_t mod_id); void enb_agent_send_update_mac_stats(mid_t mod_id); /// Provide to the scheduler a pending dl_mac_config message -void enb_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__ProgranMessage **msg); +void enb_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__FlexranMessage **msg); /*Register technology specific interface callbacks*/ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface); diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/enb_agent_mac_defs.h index 1511ee7262..cf473cae7d 100644 --- a/openair2/ENB_APP/enb_agent_mac_defs.h +++ b/openair2/ENB_APP/enb_agent_mac_defs.h @@ -39,7 +39,7 @@ #define __ENB_AGENT_MAC_PRIMITIVES_H__ #include "enb_agent_defs.h" -#include "progran.pb-c.h" +#include "flexran.pb-c.h" #include "header.pb-c.h" #define RINGBUFFER_SIZE 100 @@ -60,13 +60,13 @@ typedef struct { /// Provide to the scheduler a pending dl_mac_config message void (*enb_agent_get_pending_dl_mac_config)(mid_t mod_id, - Protocol__ProgranMessage **msg); + Protocol__FlexranMessage **msg); - /// Run the UE DL scheduler and fill the Protocol__ProgranMessage. Assumes that - /// dl_info is already initialized as prp_dl_mac_config and fills the - /// prp_dl_data part of it + /// Run the UE DL scheduler and fill the Protocol__FlexranMessage. Assumes that + /// dl_info is already initialized as flex_dl_mac_config and fills the + /// flex_dl_data part of it void (*enb_agent_schedule_ue_spec)(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__ProgranMessage **dl_info); + int *mbsfn_flag, Protocol__FlexranMessage **dl_info); /// Notify the controller for a state change of a particular UE, by sending the proper diff --git a/openair2/ENB_APP/enb_agent_mac_internal.c b/openair2/ENB_APP/enb_agent_mac_internal.c index 4d5ba34610..b42b3ac79b 100644 --- a/openair2/ENB_APP/enb_agent_mac_internal.c +++ b/openair2/ENB_APP/enb_agent_mac_internal.c @@ -39,20 +39,20 @@ #include "enb_agent_mac_internal.h" -Protocol__ProgranMessage * enb_agent_generate_diff_mac_stats_report(Protocol__ProgranMessage *new_message, - Protocol__ProgranMessage *old_message) { +Protocol__FlexranMessage * enb_agent_generate_diff_mac_stats_report(Protocol__FlexranMessage *new_message, + Protocol__FlexranMessage *old_message) { int i, j; - Protocol__PrpStatsReply *old_report, *new_report; + Protocol__FlexStatsReply *old_report, *new_report; - Protocol__PrpStatsReply *stats_reply_msg = NULL; - Protocol__ProgranMessage *msg = NULL; + Protocol__FlexStatsReply *stats_reply_msg = NULL; + Protocol__FlexranMessage *msg = NULL; - Protocol__PrpUeStatsReport **ue_report; - Protocol__PrpUeStatsReport *tmp_ue_report[NUM_MAX_UE]; - Protocol__PrpCellStatsReport **cell_report; - Protocol__PrpCellStatsReport *tmp_cell_report[NUM_MAX_UE]; + Protocol__FlexUeStatsReport **ue_report; + Protocol__FlexUeStatsReport *tmp_ue_report[NUM_MAX_UE]; + Protocol__FlexCellStatsReport **cell_report; + Protocol__FlexCellStatsReport *tmp_cell_report[NUM_MAX_UE]; old_report = old_message->stats_reply_msg; new_report = new_message->stats_reply_msg; @@ -113,7 +113,7 @@ Protocol__ProgranMessage * enb_agent_generate_diff_mac_stats_report(Protocol__Pr /*TODO: create the reply message based on the findings*/ /*Create ue report list*/ if (n_ue_report > 0) { - ue_report = malloc(sizeof(Protocol__PrpUeStatsReport *)); + ue_report = malloc(sizeof(Protocol__FlexUeStatsReport *)); for (i = 0; i 0) { - cell_report = malloc(sizeof(Protocol__PrpCellStatsReport *)); + cell_report = malloc(sizeof(Protocol__FlexCellStatsReport *)); for (i = 0; i 0 || n_ue_report > 0) { /*Create header*/ int xid = old_report->header->xid; - Protocol__PrpHeader *header; - if (prp_create_header(xid, PROTOCOL__PRP_TYPE__PRPT_STATS_REPLY, &header) != 0) { + Protocol__FlexHeader *header; + if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) { goto error; } - stats_reply_msg = malloc(sizeof(Protocol__PrpStatsReply)); - protocol__prp_stats_reply__init(stats_reply_msg); + stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply)); + protocol__flex_stats_reply__init(stats_reply_msg); stats_reply_msg->header = header; stats_reply_msg->n_ue_report = n_ue_report; stats_reply_msg->ue_report = ue_report; stats_reply_msg->n_cell_report = n_cell_report; stats_reply_msg->cell_report = cell_report; - msg = malloc(sizeof(Protocol__ProgranMessage)); + msg = malloc(sizeof(Protocol__FlexranMessage)); if(msg == NULL) goto error; - protocol__progran_message__init(msg); - msg->msg_case = PROTOCOL__PROGRAN_MESSAGE__MSG_STATS_REPLY_MSG; - msg->msg_dir = PROTOCOL__PROGRAN_DIRECTION__SUCCESSFUL_OUTCOME; + 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 msg; @@ -155,28 +155,28 @@ Protocol__ProgranMessage * enb_agent_generate_diff_mac_stats_report(Protocol__Pr return NULL; } -int compare_ue_stats_reports(Protocol__PrpUeStatsReport *rep1, - Protocol__PrpUeStatsReport *rep2) { +int compare_ue_stats_reports(Protocol__FlexUeStatsReport *rep1, + Protocol__FlexUeStatsReport *rep2) { return 1; } -int compare_cell_stats_reports(Protocol__PrpCellStatsReport *rep1, - Protocol__PrpCellStatsReport *rep2) { +int compare_cell_stats_reports(Protocol__FlexCellStatsReport *rep1, + Protocol__FlexCellStatsReport *rep2) { return 1; } -Protocol__PrpUeStatsReport * copy_ue_stats_report(Protocol__PrpUeStatsReport * original) { +Protocol__FlexUeStatsReport * copy_ue_stats_report(Protocol__FlexUeStatsReport * original) { int i; - Protocol__PrpUeStatsReport *copy = malloc(sizeof(Protocol__PrpUeStatsReport)); + Protocol__FlexUeStatsReport *copy = malloc(sizeof(Protocol__FlexUeStatsReport)); if (copy == NULL) goto error; - protocol__prp_ue_stats_report__init(copy); + protocol__flex_ue_stats_report__init(copy); copy->rnti = original->rnti; copy->has_rnti = original->has_rnti; copy->flags = original->flags; copy->has_flags = original->has_flags; - if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_BSR) { + if (copy->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_BSR) { copy->n_bsr = original->n_bsr; if (copy->n_bsr > 0) { uint32_t *elem; @@ -190,16 +190,16 @@ Protocol__PrpUeStatsReport * copy_ue_stats_report(Protocol__PrpUeStatsReport * o } } - if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PRH) { + if (copy->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PRH) { copy->has_phr = original->has_phr; copy->phr = original->phr; } - if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_RLC_BS) { + if (copy->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RLC_BS) { copy->n_rlc_report = original->n_rlc_report; if (copy->n_rlc_report > 0) { - Protocol__PrpRlcBsr ** rlc_reports; - rlc_reports = malloc(sizeof(Protocol__PrpRlcBsr) * copy->n_rlc_report); + Protocol__FlexRlcBsr ** rlc_reports; + rlc_reports = malloc(sizeof(Protocol__FlexRlcBsr) * copy->n_rlc_report); if (rlc_reports == NULL) goto error; for (i = 0; i < copy->n_rlc_report; i++) { @@ -209,22 +209,22 @@ Protocol__PrpUeStatsReport * copy_ue_stats_report(Protocol__PrpUeStatsReport * o } } - if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_MAC_CE_BS) { + if (copy->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_CE_BS) { copy->has_pending_mac_ces = original->has_pending_mac_ces; copy->pending_mac_ces = original->pending_mac_ces; } - if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_DL_CQI) { + if (copy->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_DL_CQI) { copy->dl_cqi_report = copy_dl_cqi_report(original->dl_cqi_report); } - if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_PBS) { + if (copy->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PBS) { /*Copy the Paging Buffer report*/ copy->pbr = copy_paging_buffer_report(original->pbr); } - if (copy->flags & PROTOCOL__PRP_UE_STATS_TYPE__PRUST_UL_CQI) { + if (copy->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_UL_CQI) { /*TODO: Copy the UL report*/ copy->ul_cqi_report = copy_ul_cqi_report(original->ul_cqi_report); } @@ -235,11 +235,11 @@ Protocol__PrpUeStatsReport * copy_ue_stats_report(Protocol__PrpUeStatsReport * o return NULL; } -Protocol__PrpRlcBsr * copy_rlc_report(Protocol__PrpRlcBsr * original) { - Protocol__PrpRlcBsr * copy = malloc(sizeof(Protocol__PrpRlcBsr)); +Protocol__FlexRlcBsr * copy_rlc_report(Protocol__FlexRlcBsr * original) { + Protocol__FlexRlcBsr * copy = malloc(sizeof(Protocol__FlexRlcBsr)); if (copy == NULL) goto error; - protocol__prp_rlc_bsr__init(copy); + protocol__flex_rlc_bsr__init(copy); copy->lc_id = original->lc_id; copy->has_lc_id = original->has_lc_id; copy->tx_queue_size = original->tx_queue_size; @@ -259,30 +259,30 @@ Protocol__PrpRlcBsr * copy_rlc_report(Protocol__PrpRlcBsr * original) { return NULL; } -Protocol__PrpUlCqiReport * copy_ul_cqi_report(Protocol__PrpUlCqiReport * original) { +Protocol__FlexUlCqiReport * copy_ul_cqi_report(Protocol__FlexUlCqiReport * original) { int i, j; //Fill in the full UL CQI report of the UE - Protocol__PrpUlCqiReport *full_ul_report; - full_ul_report = malloc(sizeof(Protocol__PrpUlCqiReport)); + Protocol__FlexUlCqiReport *full_ul_report; + full_ul_report = malloc(sizeof(Protocol__FlexUlCqiReport)); if(full_ul_report == NULL) { goto error; } - protocol__prp_ul_cqi_report__init(full_ul_report); + protocol__flex_ul_cqi_report__init(full_ul_report); //TODO:Set the SFN and SF of the generated report full_ul_report->sfn_sn = original->sfn_sn; full_ul_report->has_sfn_sn = original->has_sfn_sn; full_ul_report->n_cqi_meas = original->n_cqi_meas; - Protocol__PrpUlCqi **ul_report; - ul_report = malloc(sizeof(Protocol__PrpUlCqi *) * full_ul_report->n_cqi_meas); + Protocol__FlexUlCqi **ul_report; + ul_report = malloc(sizeof(Protocol__FlexUlCqi *) * full_ul_report->n_cqi_meas); if(ul_report == NULL) goto error; for(i = 0; i++; i < full_ul_report->n_cqi_meas) { - ul_report[i] = malloc(sizeof(Protocol__PrpUlCqi)); + ul_report[i] = malloc(sizeof(Protocol__FlexUlCqi)); if(ul_report[i] == NULL) goto error; - protocol__prp_ul_cqi__init(ul_report[i]); + protocol__flex_ul_cqi__init(ul_report[i]); ul_report[i]->type = original->cqi_meas[i]->type; ul_report[i]->has_type = original->cqi_meas[i]->has_type; ul_report[i]->n_sinr = original->cqi_meas[i]->n_sinr; @@ -305,21 +305,21 @@ Protocol__PrpUlCqiReport * copy_ul_cqi_report(Protocol__PrpUlCqiReport * origina return NULL; } -Protocol__PrpDlCqiReport * copy_dl_cqi_report(Protocol__PrpDlCqiReport * original) { +Protocol__FlexDlCqiReport * copy_dl_cqi_report(Protocol__FlexDlCqiReport * original) { int i; /*Copy the DL report*/ - Protocol__PrpDlCqiReport * dl_report; - dl_report = malloc(sizeof(Protocol__PrpDlCqiReport)); + Protocol__FlexDlCqiReport * dl_report; + dl_report = malloc(sizeof(Protocol__FlexDlCqiReport)); if (dl_report == NULL) goto error; - protocol__prp_dl_cqi_report__init(dl_report); + protocol__flex_dl_cqi_report__init(dl_report); dl_report->sfn_sn = original->sfn_sn; dl_report->has_sfn_sn = original->has_sfn_sn; dl_report->n_csi_report = original->n_csi_report; - Protocol__PrpDlCsi **csi_reports; - csi_reports = malloc(sizeof(Protocol__PrpDlCsi *) * dl_report->n_csi_report); + Protocol__FlexDlCsi **csi_reports; + csi_reports = malloc(sizeof(Protocol__FlexDlCsi *) * dl_report->n_csi_report); if (csi_reports == NULL) goto error; @@ -334,26 +334,26 @@ Protocol__PrpDlCqiReport * copy_dl_cqi_report(Protocol__PrpDlCqiReport * origina return NULL; } -Protocol__PrpPagingBufferReport * copy_paging_buffer_report(Protocol__PrpPagingBufferReport *original) { +Protocol__FlexPagingBufferReport * copy_paging_buffer_report(Protocol__FlexPagingBufferReport *original) { int i; - Protocol__PrpPagingBufferReport *copy; - copy = malloc(sizeof(Protocol__PrpPagingBufferReport)); + Protocol__FlexPagingBufferReport *copy; + copy = malloc(sizeof(Protocol__FlexPagingBufferReport)); if (copy == NULL) goto error; - protocol__prp_paging_buffer_report__init(copy); + protocol__flex_paging_buffer_report__init(copy); copy->n_paging_info = original->n_paging_info; - Protocol__PrpPagingInfo **p_info; - p_info = malloc(sizeof(Protocol__PrpPagingInfo *) * copy->n_paging_info); + Protocol__FlexPagingInfo **p_info; + p_info = malloc(sizeof(Protocol__FlexPagingInfo *) * copy->n_paging_info); if (p_info == NULL) goto error; for (i = 0; i < copy->n_paging_info; i++) { - p_info[i] = malloc(sizeof(Protocol__PrpPagingInfo)); + p_info[i] = malloc(sizeof(Protocol__FlexPagingInfo)); if(p_info[i] == NULL) goto error; - protocol__prp_paging_info__init(p_info[i]); + protocol__flex_paging_info__init(p_info[i]); p_info[i]->paging_index = original->paging_info[i]->paging_index; p_info[i]->has_paging_index = original->paging_info[i]->has_paging_index;; p_info[i]->paging_message_size = original->paging_info[i]->paging_message_size; @@ -371,12 +371,12 @@ Protocol__PrpPagingBufferReport * copy_paging_buffer_report(Protocol__PrpPagingB return NULL; } -Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original) { +Protocol__FlexDlCsi * copy_csi_report(Protocol__FlexDlCsi * original) { int i, j; - Protocol__PrpDlCsi *copy = malloc(sizeof(Protocol__PrpDlCsi)); + Protocol__FlexDlCsi *copy = malloc(sizeof(Protocol__FlexDlCsi)); if (copy == NULL) goto error; - protocol__prp_dl_csi__init(copy); + protocol__flex_dl_csi__init(copy); copy->serv_cell_index = original->serv_cell_index; copy->has_serv_cell_index = original->has_serv_cell_index; copy->ri = original->ri; @@ -387,11 +387,11 @@ Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original) { copy->report_case = original->report_case; switch (copy->report_case) { - case PROTOCOL__PRP_DL_CSI__REPORT_P10CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI: copy->p10csi->wb_cqi = original->p10csi->wb_cqi; copy->p10csi->has_wb_cqi = original->p10csi->has_wb_cqi; break; - case PROTOCOL__PRP_DL_CSI__REPORT_P11CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_P11CSI: copy->p11csi->n_wb_cqi = original->p11csi->n_wb_cqi; copy->p11csi->wb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->p11csi->n_wb_cqi); for (i = 0; i < copy->p11csi->n_wb_cqi; i++) { @@ -400,7 +400,7 @@ Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original) { copy->p11csi->has_wb_pmi = original->p11csi->has_wb_pmi; copy->p11csi->wb_pmi = original->p11csi->wb_pmi; break; - case PROTOCOL__PRP_DL_CSI__REPORT_P20CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_P20CSI: copy->p20csi->has_wb_cqi = original->p20csi->has_wb_cqi; copy->p20csi->wb_cqi = original->p20csi->wb_cqi; copy->p20csi->has_sb_cqi = original->p20csi->has_sb_cqi; @@ -410,7 +410,7 @@ Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original) { copy->p20csi->has_sb_index = original->p20csi->has_sb_index; copy->p20csi->sb_index = original->p20csi->sb_index; break; - case PROTOCOL__PRP_DL_CSI__REPORT_P21CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_P21CSI: copy->p21csi->n_wb_cqi = original->p21csi->n_wb_cqi; copy->p21csi->wb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->p21csi->n_wb_cqi); for (i = 0; i < copy->p21csi->n_wb_cqi; i++) { @@ -428,7 +428,7 @@ Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original) { copy->p21csi->has_sb_index = original->p21csi->has_sb_index; copy->p21csi->sb_index = original->p21csi->sb_index; break; - case PROTOCOL__PRP_DL_CSI__REPORT_A12CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_A12CSI: copy->a12csi->n_wb_cqi = original->a12csi->n_wb_cqi; copy->a12csi->wb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->a12csi->n_wb_cqi); for (i = 0; i < copy->a12csi->n_wb_cqi; i++) { @@ -440,7 +440,7 @@ Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original) { copy->a12csi->sb_pmi[i] = original->a12csi->sb_pmi[i]; } break; - case PROTOCOL__PRP_DL_CSI__REPORT_A22CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_A22CSI: copy->a22csi->n_wb_cqi = original->a22csi->n_wb_cqi; copy->a22csi->wb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->a22csi->n_wb_cqi); for (i = 0; i < copy->a22csi->n_wb_cqi; i++) { @@ -461,7 +461,7 @@ Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original) { copy->a22csi->sb_list[i] = original->a22csi->sb_list[i]; } break; - case PROTOCOL__PRP_DL_CSI__REPORT_A20CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_A20CSI: copy->a20csi->has_wb_cqi = original->a20csi->has_wb_cqi; copy->a20csi->wb_cqi = original->a20csi->wb_cqi; copy->a20csi->has_sb_cqi = original->a20csi->has_sb_cqi; @@ -472,7 +472,7 @@ Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original) { copy->a20csi->sb_list[i] = original->a20csi->sb_list[i]; } break; - case PROTOCOL__PRP_DL_CSI__REPORT_A30CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_A30CSI: copy->a30csi->has_wb_cqi = original->a30csi->has_wb_cqi; copy->a30csi->wb_cqi = original->a30csi->wb_cqi; copy->a30csi->n_sb_cqi = original->a30csi->n_sb_cqi; @@ -481,7 +481,7 @@ Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original) { copy->a30csi->sb_cqi[i] = original->a30csi->sb_cqi[i]; } break; - case PROTOCOL__PRP_DL_CSI__REPORT_A31CSI: + case PROTOCOL__FLEX_DL_CSI__REPORT_A31CSI: copy->a31csi->n_wb_cqi = original->a31csi->n_wb_cqi; copy->a31csi->wb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->a31csi->n_wb_cqi); for (i = 0; i < copy->a31csi->n_wb_cqi; i++) { @@ -490,16 +490,16 @@ Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original) { copy->a31csi->has_wb_pmi = original->a31csi->has_wb_pmi; copy->a31csi->wb_pmi = original->a31csi->wb_pmi; copy->a31csi->n_sb_cqi = original->a31csi->n_sb_cqi; - copy->a31csi->sb_cqi = malloc(sizeof(Protocol__PrpMsbCqi *) * copy->a31csi->n_sb_cqi); + copy->a31csi->sb_cqi = malloc(sizeof(Protocol__FlexMsbCqi *) * copy->a31csi->n_sb_cqi); if (copy->a31csi == NULL) { goto error; } for (i = 0; i < copy->a31csi->n_sb_cqi; i++) { - copy->a31csi->sb_cqi[i] = malloc(sizeof(Protocol__PrpMsbCqi)); + copy->a31csi->sb_cqi[i] = malloc(sizeof(Protocol__FlexMsbCqi)); if (copy->a31csi->sb_cqi[i] == NULL) { goto error; } - protocol__prp_msb_cqi__init(copy->a31csi->sb_cqi[i]); + protocol__flex_msb_cqi__init(copy->a31csi->sb_cqi[i]); copy->a31csi->sb_cqi[i]->n_sb_cqi = original->a31csi->sb_cqi[i]->n_sb_cqi; copy->a31csi->sb_cqi[i]->sb_cqi = (uint32_t *) malloc(sizeof(uint32_t) * copy->a31csi->sb_cqi[i]->n_sb_cqi); for (j = 0; j < copy->a31csi->sb_cqi[i]->n_sb_cqi; j++) { @@ -516,20 +516,20 @@ Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original) { return NULL; } -Protocol__PrpCellStatsReport * copy_cell_stats_report(Protocol__PrpCellStatsReport *original) { +Protocol__FlexCellStatsReport * copy_cell_stats_report(Protocol__FlexCellStatsReport *original) { - Protocol__PrpCellStatsReport * copy = malloc(sizeof(Protocol__PrpCellStatsReport)); + Protocol__FlexCellStatsReport * copy = malloc(sizeof(Protocol__FlexCellStatsReport)); if(copy == NULL) { goto error; } - protocol__prp_cell_stats_report__init(copy); + protocol__flex_cell_stats_report__init(copy); copy->carrier_index = original->carrier_index; copy->has_carrier_index = original->has_carrier_index; copy->flags = original->flags; copy->has_flags = original->has_flags; - if(copy->flags & PROTOCOL__PRP_CELL_STATS_TYPE__PRCST_NOISE_INTERFERENCE) { + if(copy->flags & PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE) { copy->noise_inter_report = copy_noise_inter_report(original->noise_inter_report); } @@ -539,13 +539,13 @@ Protocol__PrpCellStatsReport * copy_cell_stats_report(Protocol__PrpCellStatsRepo return NULL; } -Protocol__PrpNoiseInterferenceReport * copy_noise_inter_report(Protocol__PrpNoiseInterferenceReport *original) { - Protocol__PrpNoiseInterferenceReport *ni_report; - ni_report = malloc(sizeof(Protocol__PrpNoiseInterferenceReport)); +Protocol__FlexNoiseInterferenceReport * copy_noise_inter_report(Protocol__FlexNoiseInterferenceReport *original) { + Protocol__FlexNoiseInterferenceReport *ni_report; + ni_report = malloc(sizeof(Protocol__FlexNoiseInterferenceReport)); if(ni_report == NULL) { goto error; } - protocol__prp_noise_interference_report__init(ni_report); + protocol__flex_noise_interference_report__init(ni_report); // Current frame and subframe number ni_report->sfn_sf = original->sfn_sf; ni_report->has_sfn_sf = original->sfn_sf; diff --git a/openair2/ENB_APP/enb_agent_mac_internal.h b/openair2/ENB_APP/enb_agent_mac_internal.h index 4a76f0ed38..86a021f946 100644 --- a/openair2/ENB_APP/enb_agent_mac_internal.h +++ b/openair2/ENB_APP/enb_agent_mac_internal.h @@ -53,8 +53,8 @@ typedef struct { uint8_t is_initialized; volatile uint8_t cont_update; xid_t xid; - Protocol__ProgranMessage *stats_req; - Protocol__ProgranMessage *prev_stats_reply; + Protocol__FlexranMessage *stats_req; + Protocol__FlexranMessage *prev_stats_reply; pthread_mutex_t *mutex; } mac_stats_updates_context_t; @@ -75,30 +75,30 @@ err_code_t enb_agent_enable_cont_mac_stats_update(mid_t mod_id, xid_t xid, err_code_t enb_agent_disable_cont_mac_stats_update(mid_t mod_id); -Protocol__ProgranMessage * enb_agent_generate_diff_mac_stats_report(Protocol__ProgranMessage *new_report, - Protocol__ProgranMessage *old_report); +Protocol__FlexranMessage * enb_agent_generate_diff_mac_stats_report(Protocol__FlexranMessage *new_report, + Protocol__FlexranMessage *old_report); -Protocol__PrpUeStatsReport * copy_ue_stats_report(Protocol__PrpUeStatsReport * original); +Protocol__FlexUeStatsReport * copy_ue_stats_report(Protocol__FlexUeStatsReport * original); -Protocol__PrpCellStatsReport * copy_cell_stats_report(Protocol__PrpCellStatsReport *original); +Protocol__FlexCellStatsReport * copy_cell_stats_report(Protocol__FlexCellStatsReport *original); -Protocol__PrpRlcBsr * copy_rlc_report(Protocol__PrpRlcBsr * original); +Protocol__FlexRlcBsr * copy_rlc_report(Protocol__FlexRlcBsr * original); -Protocol__PrpUlCqiReport * copy_ul_cqi_report(Protocol__PrpUlCqiReport * original); +Protocol__FlexUlCqiReport * copy_ul_cqi_report(Protocol__FlexUlCqiReport * original); -Protocol__PrpDlCqiReport * copy_dl_cqi_report(Protocol__PrpDlCqiReport * original); +Protocol__FlexDlCqiReport * copy_dl_cqi_report(Protocol__FlexDlCqiReport * original); -Protocol__PrpPagingBufferReport * copy_paging_buffer_report(Protocol__PrpPagingBufferReport *original); +Protocol__FlexPagingBufferReport * copy_paging_buffer_report(Protocol__FlexPagingBufferReport *original); -Protocol__PrpDlCsi * copy_csi_report(Protocol__PrpDlCsi * original); +Protocol__FlexDlCsi * copy_csi_report(Protocol__FlexDlCsi * original); -Protocol__PrpNoiseInterferenceReport * copy_noise_inter_report(Protocol__PrpNoiseInterferenceReport *original); +Protocol__FlexNoiseInterferenceReport * copy_noise_inter_report(Protocol__FlexNoiseInterferenceReport *original); -int compare_ue_stats_reports(Protocol__PrpUeStatsReport *rep1, - Protocol__PrpUeStatsReport *rep2); +int compare_ue_stats_reports(Protocol__FlexUeStatsReport *rep1, + Protocol__FlexUeStatsReport *rep2); -int compare_cell_stats_reports(Protocol__PrpCellStatsReport *rep1, - Protocol__PrpCellStatsReport *rep2); +int compare_cell_stats_reports(Protocol__FlexCellStatsReport *rep1, + Protocol__FlexCellStatsReport *rep2); /* Functions for parsing the MAC agent policy reconfiguration command */ diff --git a/openair2/ENB_APP/enb_agent_task_manager.c b/openair2/ENB_APP/enb_agent_task_manager.c index e2c31319e4..9b4be2ff6a 100644 --- a/openair2/ENB_APP/enb_agent_task_manager.c +++ b/openair2/ENB_APP/enb_agent_task_manager.c @@ -48,7 +48,7 @@ #define RIGHT(x) (2 * (x) + 2) #define PARENT(x) ((x - 1) / 2) -enb_agent_task_t *enb_agent_task_create(Protocol__ProgranMessage *msg, +enb_agent_task_t *enb_agent_task_create(Protocol__FlexranMessage *msg, uint16_t frame_num, uint8_t subframe_num) { enb_agent_task_t *task = NULL; task = malloc(sizeof(enb_agent_task_t)); diff --git a/openair2/ENB_APP/enb_agent_task_manager.h b/openair2/ENB_APP/enb_agent_task_manager.h index ef60152b27..0c458061cf 100644 --- a/openair2/ENB_APP/enb_agent_task_manager.h +++ b/openair2/ENB_APP/enb_agent_task_manager.h @@ -41,7 +41,7 @@ #include #include -#include "progran.pb-c.h" +#include "flexran.pb-c.h" #include "enb_agent_common.h" @@ -59,8 +59,8 @@ typedef struct enb_agent_task_s { uint16_t frame_num; /* The subframe in which the task needs to be executed */ uint8_t subframe_num; - /* The task to be executed in the form of a Protocol__ProgranMessage */ - Protocol__ProgranMessage *task; + /* The task to be executed in the form of a Protocol__FlexranMessage */ + Protocol__FlexranMessage *task; } enb_agent_task_t; /** @@ -95,7 +95,7 @@ typedef enum { /** * Allocate memory for a task in the queue */ -enb_agent_task_t *enb_agent_task_create(Protocol__ProgranMessage *msg, +enb_agent_task_t *enb_agent_task_create(Protocol__FlexranMessage *msg, uint16_t frame_num, uint8_t subframe_num); /** diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c index b2a66bfe2d..b75b0467b1 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c @@ -48,7 +48,7 @@ #include "LAYER2/MAC/defs.h" #include "LAYER2/MAC/proto.h" #include "LAYER2/MAC/extern.h" -#include "LAYER2/MAC/progran_dci_conversions.h" +#include "LAYER2/MAC/flexran_dci_conversions.h" #include "UTIL/LOG/log.h" #include "UTIL/LOG/vcd_signal_dumper.h" @@ -60,7 +60,7 @@ #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" #include "header.pb-c.h" -#include "progran.pb-c.h" +#include "flexran.pb-c.h" #include "SIMULATION/TOOLS/defs.h" // for taus @@ -69,9 +69,9 @@ void apply_dl_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, - const Protocol__ProgranMessage *dl_scheduling_info) { + const Protocol__FlexranMessage *dl_scheduling_info) { - Protocol__PrpDlMacConfig *mac_config = dl_scheduling_info->dl_mac_config_msg; + Protocol__FlexDlMacConfig *mac_config = dl_scheduling_info->dl_mac_config_msg; // Check if there is anything to schedule for random access if (mac_config->n_dl_rar > 0) { @@ -97,7 +97,7 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, uint32_t subframe, int *mbsfn_flag, uint32_t n_dl_ue_data, - const Protocol__PrpDlData **dl_ue_data) { + const Protocol__FlexDlData **dl_ue_data) { uint8_t CC_id; int UE_id; @@ -128,8 +128,8 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, int i; - Protocol__PrpDlData *dl_data; - Protocol__PrpDlDci *dl_dci; + Protocol__FlexDlData *dl_data; + Protocol__FlexDlDci *dl_dci; uint32_t rlc_size, n_lc, lcid; @@ -161,7 +161,7 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, if (dl_data->n_ce_bitmap > 0) { //Check if there is TA command and set the length appropriately - ta_len = (dl_data->ce_bitmap[0] & PROTOCOL__PRP_CE_TYPE__PRPCET_TA) ? 2 : 0; + ta_len = (dl_data->ce_bitmap[0] & PROTOCOL__FLEX_CE_TYPE__FLPCET_TA) ? 2 : 0; } if (ta_len > 0) { @@ -359,7 +359,7 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, } void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, - const Protocol__PrpDlDci *dl_dci) { + const Protocol__FlexDlDci *dl_dci) { void *DLSCH_dci = NULL; DCI_PDU *DCI_pdu; @@ -397,92 +397,92 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, switch (frame_parms[CC_id]->N_RB_DL) { case 6: if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { FILL_DCI_TDD_1(DCI1_1_5MHz_TDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_1_5MHz_TDD_t); size_bits = sizeof_DCI1_1_5MHz_TDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { //TODO } } else { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { FILL_DCI_FDD_1(DCI1_1_5MHz_FDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_1_5MHz_FDD_t); size_bits = sizeof_DCI1_1_5MHz_FDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { //TODO } } break; case 25: if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { FILL_DCI_TDD_1(DCI1_5MHz_TDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_5MHz_TDD_t); size_bits = sizeof_DCI1_5MHz_TDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { //TODO } } else { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { FILL_DCI_FDD_1(DCI1_5MHz_FDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_5MHz_FDD_t); size_bits = sizeof_DCI1_5MHz_FDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { //TODO } } break; case 50: if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { FILL_DCI_TDD_1(DCI1_10MHz_TDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_10MHz_TDD_t); size_bits = sizeof_DCI1_10MHz_TDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { //TODO } } else { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { FILL_DCI_FDD_1(DCI1_10MHz_FDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_10MHz_FDD_t); size_bits = sizeof_DCI1_10MHz_FDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { //TODO } } break; case 100: if (frame_parms[CC_id]->frame_type == TDD) { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { FILL_DCI_TDD_1(DCI1_20MHz_TDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_20MHz_TDD_t); size_bits = sizeof_DCI1_20MHz_TDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { //TODO } } else { - if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) { + if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1) { FILL_DCI_FDD_1(DCI1_20MHz_FDD_t, DLSCH_dci, dl_dci); size_bytes = sizeof(DCI1_20MHz_FDD_t); size_bits = sizeof_DCI1_20MHz_FDD_t; - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A) { //TODO - } else if (dl_dci->format == PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) { + } else if (dl_dci->format == PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D) { //TODO } } @@ -491,31 +491,31 @@ void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, //Set format to the proper type switch(dl_dci->format) { - case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1: + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1: format = format1; break; - case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1A: + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1A: format = format1A; break; - case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1B: + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1B: format = format1B; break; - case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1C: + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1C: format = format1C; break; - case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D: + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D: format = format1E_2A_M10PRB; break; - case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2: + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2: format = format2; break; - case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A: + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A: format = format2A; break; - case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2B: + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2B: format = format2B; break; - case PROTOCOL__PRP_DCI_FORMAT__PRDCIF_3: + case PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_3: format = 3; break; default: diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index e1e22de549..90d5ad5f1b 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -63,7 +63,7 @@ #include "pdcp.h" #include "header.pb-c.h" -#include "progran.pb-c.h" +#include "flexran.pb-c.h" #include "enb_agent_mac.h" #include "SIMULATION/TOOLS/defs.h" // for taus @@ -81,7 +81,7 @@ schedule_ue_spec_default( uint32_t frame, uint32_t subframe, int *mbsfn_flag, - Protocol__ProgranMessage **dl_info + Protocol__FlexranMessage **dl_info ) //------------------------------------------------------------------------------ { @@ -109,14 +109,14 @@ schedule_ue_spec_default( static int32_t tpc_accumulated=0; UE_sched_ctrl *ue_sched_ctl; - Protocol__PrpDlData *dl_data[NUM_MAX_UE]; + Protocol__FlexDlData *dl_data[NUM_MAX_UE]; int num_ues_added = 0; int channels_added = 0; - Protocol__PrpDlDci *dl_dci; - Protocol__PrpRlcPdu *rlc_pdus[11]; + Protocol__FlexDlDci *dl_dci; + Protocol__FlexRlcPdu *rlc_pdus[11]; uint32_t *ce_bitmap; - Protocol__PrpRlcPdu **rlc_pdu; + Protocol__FlexRlcPdu **rlc_pdu; int num_tb; uint32_t ce_flags = 0; @@ -216,8 +216,8 @@ schedule_ue_spec_default( channels_added = 0; // After this point all the UEs will be scheduled - dl_data[num_ues_added] = (Protocol__PrpDlData *) malloc(sizeof(Protocol__PrpDlData)); - protocol__prp_dl_data__init(dl_data[num_ues_added]); + dl_data[num_ues_added] = (Protocol__FlexDlData *) malloc(sizeof(Protocol__FlexDlData)); + protocol__flex_dl_data__init(dl_data[num_ues_added]); dl_data[num_ues_added]->has_rnti = 1; dl_data[num_ues_added]->rnti = rnti; dl_data[num_ues_added]->n_rlc_pdu = 0; @@ -258,8 +258,8 @@ schedule_ue_spec_default( eNB_UE_stats->DL_cqi[0], mcs, UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); - dl_dci = (Protocol__PrpDlDci*) malloc(sizeof(Protocol__PrpDlDci)); - protocol__prp_dl_dci__init(dl_dci); + dl_dci = (Protocol__FlexDlDci*) malloc(sizeof(Protocol__FlexDlDci)); + protocol__flex_dl_dci__init(dl_dci); dl_data[num_ues_added]->dl_dci = dl_dci; @@ -353,12 +353,12 @@ schedule_ue_spec_default( dl_data[num_ues_added]->ce_bitmap = (uint32_t *) malloc(sizeof(uint32_t) * 2); if (ta_len > 0) { - ce_flags |= PROTOCOL__PRP_CE_TYPE__PRPCET_TA; + ce_flags |= PROTOCOL__FLEX_CE_TYPE__FLPCET_TA; } /*TODO: Add other flags if DRX and other CE are required*/ - // Add the control element flags to the progran message + // Add the control element flags to the flexran message dl_data[num_ues_added]->ce_bitmap[0] = ce_flags; dl_data[num_ues_added]->ce_bitmap[1] = ce_flags; @@ -394,18 +394,18 @@ schedule_ue_spec_default( data_to_request++; //It is not correct but fixes some RLC bug for DCCH } LOG_D(MAC, "[TEST]Will request %d from DCCH\n", data_to_request); - rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); - protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]); + rlc_pdus[channels_added] = (Protocol__FlexRlcPdu *) malloc(sizeof(Protocol__FlexRlcPdu)); + protocol__flex_rlc_pdu__init(rlc_pdus[channels_added]); rlc_pdus[channels_added]->n_rlc_pdu_tb = 2; - rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); - rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]); + rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__FlexRlcPduTb **) malloc(sizeof(Protocol__FlexRlcPduTb *) * 2); + rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__FlexRlcPduTb *) malloc(sizeof(Protocol__FlexRlcPduTb)); + protocol__flex_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]); rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_logical_channel_id = 1; rlc_pdus[channels_added]->rlc_pdu_tb[0]->logical_channel_id = j; rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_size = 1; rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = data_to_request; - rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); - protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]); + rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__FlexRlcPduTb *) malloc(sizeof(Protocol__FlexRlcPduTb)); + protocol__flex_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]); rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_logical_channel_id = 1; rlc_pdus[channels_added]->rlc_pdu_tb[1]->logical_channel_id = j; rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_size = 1; @@ -422,7 +422,7 @@ schedule_ue_spec_default( } // End of iterating the logical channels // Add rlc_pdus to the dl_data message - dl_data[num_ues_added]->rlc_pdu = (Protocol__PrpRlcPdu **) malloc(sizeof(Protocol__PrpRlcPdu *) * + dl_data[num_ues_added]->rlc_pdu = (Protocol__FlexRlcPdu **) malloc(sizeof(Protocol__FlexRlcPdu *) * dl_data[num_ues_added]->n_rlc_pdu); for (i = 0; i < dl_data[num_ues_added]->n_rlc_pdu; i++) { dl_data[num_ues_added]->rlc_pdu[i] = rlc_pdus[i]; @@ -595,9 +595,9 @@ schedule_ue_spec_default( dl_dci->has_res_alloc = 1; dl_dci->res_alloc = 0; dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1; dl_dci->has_rb_bitmap = 1; dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); dl_dci->has_rb_shift = 1; @@ -625,9 +625,9 @@ schedule_ue_spec_default( dl_dci->has_res_alloc = 1; dl_dci->res_alloc = 0; dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A; dl_dci->has_rb_bitmap = 1; dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); dl_dci->has_rb_shift = 1; @@ -659,9 +659,9 @@ schedule_ue_spec_default( dl_dci->has_res_alloc = 1; dl_dci->res_alloc = 0; dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_2A; dl_dci->has_rb_bitmap = 1; dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); dl_dci->has_rb_shift = 1; @@ -693,9 +693,9 @@ schedule_ue_spec_default( dl_dci->has_res_alloc = 1; dl_dci->res_alloc = 0; dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D; dl_dci->has_rb_bitmap = 1; dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); dl_dci->has_rb_shift = 1; @@ -733,9 +733,9 @@ schedule_ue_spec_default( dl_dci->has_res_alloc = 1; dl_dci->res_alloc = 0; dl_dci->has_vrb_format = 1; - dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->vrb_format = PROTOCOL__FLEX_VRB_FORMAT__FLVRBF_LOCALIZED; dl_dci->has_format = 1; - dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; + dl_dci->format = PROTOCOL__FLEX_DCI_FORMAT__FLDCIF_1D; dl_dci->has_rb_bitmap = 1; dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); dl_dci->has_rb_shift = 1; @@ -770,9 +770,9 @@ schedule_ue_spec_default( } // UE_id loop } // CC_id loop - // Add all the dl_data elements to the progran message + // Add all the dl_data elements to the flexran message (*dl_info)->dl_mac_config_msg->n_dl_ue_data = num_ues_added; - (*dl_info)->dl_mac_config_msg->dl_ue_data = (Protocol__PrpDlData **) malloc(sizeof(Protocol__PrpDlData *) * num_ues_added); + (*dl_info)->dl_mac_config_msg->dl_ue_data = (Protocol__FlexDlData **) malloc(sizeof(Protocol__FlexDlData *) * num_ues_added); for (i = 0; i < num_ues_added; i++) { (*dl_info)->dl_mac_config_msg->dl_ue_data[i] = dl_data[i]; } diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c index d8d2373332..b5882c84e3 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c @@ -53,7 +53,7 @@ int queue_initialized = 0; //uint32_t sched [] = {1, 2, 3}; void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__ProgranMessage **dl_info) { + int *mbsfn_flag, Protocol__FlexranMessage **dl_info) { //if ((subframe == skip_subframe) && (frame % period == 0)) { diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h index 7d2c2cbc6f..9ff750969b 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h @@ -40,7 +40,7 @@ #ifndef __LAYER2_MAC_ENB_AGENT_SCHEDULER_DLSCH_UE_REMOTE_H__ #define __LAYER2_MAC_ENB_AGENT_SCHEDULER_DLSCH_UE_REMOTE_H___ -#include "progran.pb-c.h" +#include "flexran.pb-c.h" #include "header.pb-c.h" #include "ENB_APP/enb_agent_defs.h" @@ -54,7 +54,7 @@ #define SCHED_AHEAD_SUBFRAMES 20 typedef struct dl_mac_config_element_s { - Protocol__ProgranMessage *dl_info; + Protocol__FlexranMessage *dl_info; TAILQ_ENTRY(dl_mac_config_element_s) configs; } dl_mac_config_element_t; @@ -64,7 +64,7 @@ TAILQ_HEAD(DlMacConfigHead, dl_mac_config_element_s); * Default scheduler used by the eNB agent */ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__ProgranMessage **dl_info); + int *mbsfn_flag, Protocol__FlexranMessage **dl_info); // Find the difference in subframes from the given subframe diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index f83606eddf..b57f5e965b 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -103,7 +103,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, void *DLSCH_dci=NULL; int size_bits=0,size_bytes=0; - Protocol__ProgranMessage *msg; + Protocol__FlexranMessage *msg; LOG_D(MAC,"[eNB %d] Frame %d, Subframe %d, entering MAC scheduler (UE_list->head %d)\n",module_idP, frameP, subframeP,UE_list->head); @@ -143,7 +143,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, if (mac_agent_registered[module_idP]) { agent_mac_xface[module_idP]->enb_agent_notify_ue_state_change(module_idP, rnti, - PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_DEACTIVATED); + PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); } } else { diff --git a/openair2/LAYER2/MAC/enb_agent_mac_proto.h b/openair2/LAYER2/MAC/enb_agent_mac_proto.h index f453fa2fa3..3c2d36e678 100644 --- a/openair2/LAYER2/MAC/enb_agent_mac_proto.h +++ b/openair2/LAYER2/MAC/enb_agent_mac_proto.h @@ -42,29 +42,29 @@ #include "enb_agent_defs.h" #include "header.pb-c.h" -#include "progran.pb-c.h" +#include "flexran.pb-c.h" /* * Default scheduler used by the eNB agent */ void schedule_ue_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__ProgranMessage **dl_info); + int *mbsfn_flag, Protocol__FlexranMessage **dl_info); /* * Data plane function for applying the DL decisions of the scheduler */ void apply_dl_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, - const Protocol__ProgranMessage *dl_scheduling_info); + const Protocol__FlexranMessage *dl_scheduling_info); /* * Data plane function for applying the UE specific DL decisions of the scheduler */ void apply_ue_spec_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, - uint32_t n_dl_ue_data, const Protocol__PrpDlData **dl_ue_data); + uint32_t n_dl_ue_data, const Protocol__FlexDlData **dl_ue_data); /* * Data plane function for filling the DCI structure */ -void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, const Protocol__PrpDlDci *dl_dci); +void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, const Protocol__FlexDlDci *dl_dci); #endif diff --git a/openair2/LAYER2/MAC/progran_dci_conversions.h b/openair2/LAYER2/MAC/flexran_dci_conversions.h similarity index 58% rename from openair2/LAYER2/MAC/progran_dci_conversions.h rename to openair2/LAYER2/MAC/flexran_dci_conversions.h index 90324fdb30..e9d9494a1a 100644 --- a/openair2/LAYER2/MAC/progran_dci_conversions.h +++ b/openair2/LAYER2/MAC/flexran_dci_conversions.h @@ -28,32 +28,32 @@ *******************************************************************************/ /*! \file dci_conversions.h - * \brief Conversion helpers from progran messages to OAI formats DCI + * \brief Conversion helpers from flexran messages to OAI formats DCI * \author Xenofon Foukas * \date 2016 * \version 0.1 */ -#ifndef LAYER2_MAC_PROGRAN_DCI_CONVERISIONS_H__ -#define LAYER2_MAC_DCI_PROGRAN_CONVERISIONS_H__ +#ifndef LAYER2_MAC_FLEXRAN_DCI_CONVERISIONS_H__ +#define LAYER2_MAC_DCI_FLEXRAN_CONVERISIONS_H__ -#define FILL_DCI_FDD_1(TYPE, DCI, PROGRAN_DCI) \ - ((TYPE*)DCI)->harq_pid = PROGRAN_DCI->harq_process; \ - ((TYPE*)DCI)->rv = PROGRAN_DCI->rv[0]; \ - ((TYPE*)DCI)->rballoc = PROGRAN_DCI->rb_bitmap; \ - ((TYPE*)DCI)->rah = PROGRAN_DCI->res_alloc; \ - ((TYPE*)DCI)->mcs = PROGRAN_DCI->mcs[0]; \ - ((TYPE*)DCI)->TPC = PROGRAN_DCI->tpc; \ - ((TYPE*)DCI)->ndi = PROGRAN_DCI->ndi[0]; +#define FILL_DCI_FDD_1(TYPE, DCI, FLEXRAN_DCI) \ + ((TYPE*)DCI)->harq_pid = FLEXRAN_DCI->harq_process; \ + ((TYPE*)DCI)->rv = FLEXRAN_DCI->rv[0]; \ + ((TYPE*)DCI)->rballoc = FLEXRAN_DCI->rb_bitmap; \ + ((TYPE*)DCI)->rah = FLEXRAN_DCI->res_alloc; \ + ((TYPE*)DCI)->mcs = FLEXRAN_DCI->mcs[0]; \ + ((TYPE*)DCI)->TPC = FLEXRAN_DCI->tpc; \ + ((TYPE*)DCI)->ndi = FLEXRAN_DCI->ndi[0]; -#define FILL_DCI_TDD_1(TYPE, DCI, PROGRAN_DCI) \ - ((TYPE*)DCI)->harq_pid = PROGRAN_DCI->harq_process; \ - ((TYPE*)DCI)->rv = PROGRAN_DCI->rv[0]; \ - ((TYPE*)DCI)->dai = PROGRAN_DCI->dai; \ - ((TYPE*)DCI)->rballoc = PROGRAN_DCI->rb_bitmap; \ - ((TYPE*)DCI)->rah = PROGRAN_DCI->res_alloc; \ - ((TYPE*)DCI)->mcs = PROGRAN_DCI->mcs[0]; \ - ((TYPE*)DCI)->TPC = PROGRAN_DCI->tpc; \ - ((TYPE*)DCI)->ndi = PROGRAN_DCI->ndi[0]; +#define FILL_DCI_TDD_1(TYPE, DCI, FLEXRAN_DCI) \ + ((TYPE*)DCI)->harq_pid = FLEXRAN_DCI->harq_process; \ + ((TYPE*)DCI)->rv = FLEXRAN_DCI->rv[0]; \ + ((TYPE*)DCI)->dai = FLEXRAN_DCI->dai; \ + ((TYPE*)DCI)->rballoc = FLEXRAN_DCI->rb_bitmap; \ + ((TYPE*)DCI)->rah = FLEXRAN_DCI->res_alloc; \ + ((TYPE*)DCI)->mcs = FLEXRAN_DCI->mcs[0]; \ + ((TYPE*)DCI)->TPC = FLEXRAN_DCI->tpc; \ + ((TYPE*)DCI)->ndi = FLEXRAN_DCI->ndi[0]; #endif diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 655c8d4c02..2b075a7ed3 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -4545,7 +4545,7 @@ rrc_eNB_decode_dcch( if (mac_agent_registered[ctxt_pP->module_id]) { agent_mac_xface[ctxt_pP->eNB_index]->enb_agent_notify_ue_state_change(ctxt_pP->module_id, ue_context_p->ue_id_rnti, - PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_UPDATED); + PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_UPDATED); } } #if defined(ENABLE_ITTI) @@ -4646,7 +4646,7 @@ rrc_eNB_decode_dcch( if (mac_agent_registered[ctxt_pP->module_id]) { agent_mac_xface[ctxt_pP->eNB_index]->enb_agent_notify_ue_state_change(ctxt_pP->module_id, ue_context_p->ue_id_rnti, - PROTOCOL__PRP_UE_STATE_CHANGE_TYPE__PRUESC_ACTIVATED); + PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED); } } } From 948f2df9f1b00805f30ff0858c3d2ee9bd485a31 Mon Sep 17 00:00:00 2001 From: calvin wang Date: Fri, 21 Oct 2016 18:26:50 +0800 Subject: [PATCH 249/413] modify BSR code according comments --- openair2/LAYER2/MAC/config.c | 2 +- openair2/LAYER2/MAC/defs.h | 2 +- openair2/LAYER2/MAC/proto.h | 4 +- openair2/LAYER2/MAC/ra_procedures.c | 2 +- openair2/LAYER2/MAC/ue_procedures.c | 206 ++++++++++++---------------- 5 files changed, 90 insertions(+), 126 deletions(-) diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 030ac7a9f3..90889d6381 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -233,7 +233,7 @@ rrc_mac_config_req( if (mac_MainConfig->ext1 && mac_MainConfig->ext1->sr_ProhibitTimer_r9) { UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = (uint16_t) *mac_MainConfig->ext1->sr_ProhibitTimer_r9; } else { - UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = (uint16_t) 0; + UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = 0; } if (mac_MainConfig->ext2 && mac_MainConfig->ext2->mac_MainConfig_v1020) { diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 4edfef1677..8f0d4f5951 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -941,7 +941,7 @@ typedef enum { typedef struct { /// buffer status for each lcgid uint8_t BSR[MAX_NUM_LCGID]; // should be more for mesh topology - /// keep the number of bytes in rlc buffer for each lcid + /// keep the number of bytes in rlc buffer for each lcgid uint16_t BSR_bytes[MAX_NUM_LCGID]; /// buffer status for each lcid uint8_t LCID_status[MAX_NUM_LCID]; diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 4133d6a2eb..0bc3eb00ec 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -548,7 +548,7 @@ int cba_access(module_id_t module_idP,frame_t frameP,sub_frame_t subframe, uint8 \param[in] Mod_id instance of the UE \param[out] lcgid */ -int get_bsr_lcgid (module_id_t module_idP, int *num_lcgid); +int get_bsr_lcgid (module_id_t module_idP); /*! \fn uint8_t get_bsr_len (module_id_t module_idP,uint16_t bufflen); \brief determine whether the bsr is short or long assuming that the MAC pdu is built @@ -556,7 +556,7 @@ int get_bsr_lcgid (module_id_t module_idP, int *num_lcgid); \param[in] bufflen size of phy transport block \param[out] bsr_len size of bsr control element */ -uint8_t get_bsr_len (module_id_t module_idP, uint16_t buflen); +uint8_t get_bsr_len (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint16_t buflen); /*! \fn BSR_SHORT * get_bsr_short(module_id_t module_idP, uint8_t bsr_len) \brief get short bsr level diff --git a/openair2/LAYER2/MAC/ra_procedures.c b/openair2/LAYER2/MAC/ra_procedures.c index 669077bf4f..e60dfc6292 100644 --- a/openair2/LAYER2/MAC/ra_procedures.c +++ b/openair2/LAYER2/MAC/ra_procedures.c @@ -399,7 +399,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP, 1); //post_padding return(&UE_mac_inst[module_idP].RA_prach_resources); - } else if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DCCH] > 0) { + } 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, diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 6fc95f55d5..97b7e433c4 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -133,7 +133,7 @@ void ue_init_mac(module_id_t module_idP) UE_mac_inst[module_idP].scheduling_info.LCGID[i]=1; } - UE_mac_inst[module_idP].scheduling_info.LCID_status[i]=0; + UE_mac_inst[module_idP].scheduling_info.LCID_status[i]=LCID_EMPTY; } #ifdef CBA @@ -1202,10 +1202,9 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf uint8_t payload_offset=0,num_sdus=0; uint8_t ulsch_buff[MAX_ULSCH_PAYLOAD_BYTES]; uint16_t sdu_length_total=0; - BSR_SHORT bsr_short,bsr_truncated; + BSR_SHORT bsr_short; BSR_LONG bsr_long; BSR_SHORT *bsr_s=&bsr_short; - BSR_SHORT *bsr_t=&bsr_truncated; BSR_LONG *bsr_l=&bsr_long; POWER_HEADROOM_CMD phr; POWER_HEADROOM_CMD *phr_p=&phr; @@ -1214,7 +1213,6 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf int j; // used for padding // Compute header length int all_pdu_len; - int num_lcgid=0; if (CC_id>0) { LOG_E(MAC,"Transmission on secondary CCs is not supported yet\n"); @@ -1249,18 +1247,9 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len=(buflen > 128 ) ? 3 : 2 ; //sizeof(SCH_SUBHEADER_LONG)-1 : sizeof(SCH_SUBHEADER_SHORT); bsr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); phr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); - phr_ce_len = (UE_mac_inst[module_idP].PHR_reporting_active == 1) ? 1 /* sizeof(POWER_HEADROOM_CMD)*/: 0; - if (phr_ce_len > 0) { - phr_len = phr_ce_len + phr_header_len; - LOG_D(MAC,"[UE %d] header size info: PHR len %d (ce%d,hdr%d) buff_len %d\n", - module_idP, phr_len, phr_ce_len, phr_header_len, buflen); - } else { - phr_len=0; - } - - bsr_ce_len = get_bsr_len (module_idP, buflen-phr_len); - // retxBSR-Timer expires or periodicBSR-Timer expires and UE has data available for transmission + bsr_ce_len = get_bsr_len (module_idP, eNB_index, frameP, buflen); + // retxBSR-Timer expires or periodicBSR-Timer expires and Regular BSR trigger if ((bsr_ce_len > 0 ) && (UE_mac_inst[module_idP].BSR_reporting_active > 0)) { bsr_len = bsr_ce_len + bsr_header_len; LOG_D(MAC,"[UE %d] header size info: dcch %d, dcch1 %d, dtch %d, bsr (ce%d,hdr%d) buff_len %d\n", @@ -1272,6 +1261,15 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf //bsr_len = bsr_ce_len + bsr_header_len; } + phr_ce_len = (UE_mac_inst[module_idP].PHR_reporting_active == 1) ? 1 /* sizeof(POWER_HEADROOM_CMD)*/: 0; + if (phr_ce_len > 0) { + phr_len = phr_ce_len + phr_header_len; + LOG_D(MAC,"[UE %d] header size info: PHR len %d (ce%d,hdr%d) buff_len %d\n", + module_idP, phr_len, phr_ce_len, phr_header_len, buflen); + } else { + phr_len=0; + } + // check for UL bandwidth requests and add SR control element // check for UL bandwidth requests and add SR control element @@ -1305,8 +1303,9 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf sdu_lcids[0] = DCCH; LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH\n",module_idP,sdu_lengths[0]); num_sdus = 1; - update_bsr(module_idP, frameP, eNB_index, DCCH, UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]); + //update_bsr(module_idP, frameP, eNB_index, DCCH, UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]); //header_len +=2; + UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH] = LCID_EMPTY; } else { dcch_header_len=0; num_sdus = 0; @@ -1345,6 +1344,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf num_sdus++; //update_bsr(module_idP, frameP, DCCH1); //dcch_header_len +=2; // include dcch1 + UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH1] = LCID_EMPTY; } else { dcch1_header_len =0; } @@ -1379,7 +1379,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf LOG_D(MAC,"[UE %d] Frame %d : UL-DTCH -> ULSCH%d, %d bytes to send (Transport Block size %d, mac header len %d, BSR byte[%d] %d)\n", module_idP,frameP, lcid, rlc_status.bytes_in_buffer,buflen,dtch_header_len, - lcid, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcid]); + lcid, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); if (rlc_status.bytes_in_buffer > 0) { sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, @@ -1400,62 +1400,54 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len_last --; } num_sdus++; - UE_mac_inst[module_idP].ul_active = update_bsr(module_idP, frameP, eNB_index,lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); + //UE_mac_inst[module_idP].ul_active = update_bsr(module_idP, frameP, eNB_index,lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); } else { dtch_header_len -= 3; } + UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_EMPTY; } else { // no rlc pdu : generate the dummy header dtch_header_len -= 3; } } - lcgid= get_bsr_lcgid(module_idP, &num_lcgid); + lcgid= get_bsr_lcgid(module_idP); - if (num_lcgid == 0 ) { + if (lcgid < 0 ) { bsr_s = NULL; - bsr_t = NULL; + bsr_l = NULL ; + } else if ((lcgid ==MAX_NUM_LCGID) && (bsr_ce_len == sizeof(BSR_LONG))) { + bsr_s = NULL; + bsr_l->Buffer_size0 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]; + bsr_l->Buffer_size1 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]; + bsr_l->Buffer_size2 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]; + bsr_l->Buffer_size3 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]; + + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID0] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID1] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID2] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID3] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] = 0; + + LOG_D(MAC, "[UE %d] Frame %d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP, + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2], + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]); + } else if (bsr_ce_len == sizeof(BSR_SHORT)) { bsr_l = NULL; - } else if (num_lcgid == 1){ - if (bsr_ce_len == sizeof(BSR_SHORT)){ - bsr_l = NULL; - bsr_t = NULL; - bsr_s->LCGID = lcgid; - bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]; - LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n", - module_idP, frameP, UE_mac_inst[module_idP].scheduling_info.BSR[lcgid],lcgid); - } else { - bsr_s = NULL; - bsr_t = NULL; - bsr_l = NULL; - } - } else if (num_lcgid > 1) { - if (bsr_ce_len == sizeof(BSR_LONG)){ - bsr_t = NULL; - bsr_s = NULL; - bsr_l->Buffer_size0 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]; - bsr_l->Buffer_size1 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]; - bsr_l->Buffer_size2 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]; - bsr_l->Buffer_size3 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]; - LOG_D(MAC, "[UE %d] Frame %d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP, - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2], - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]); - } else if (bsr_ce_len == sizeof(BSR_SHORT)){ - bsr_l = NULL; - bsr_s = NULL; - bsr_t->LCGID = lcgid; - bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]; - LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n", + bsr_s->LCGID = lcgid; + bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]; + + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] = 0; + + LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n", module_idP, frameP, UE_mac_inst[module_idP].scheduling_info.BSR[lcgid],lcgid); - } else { - bsr_s = NULL; - bsr_t = NULL; - bsr_l = NULL; - } } else { bsr_s = NULL; - bsr_t = NULL; bsr_l = NULL; } @@ -1517,7 +1509,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf sdu_lcids, // sdu lcid phr_p, // power headroom NULL, // crnti - bsr_t, // truncated bsr + NULL, // truncated bsr bsr_s, // short bsr bsr_l, post_padding); // long_bsr @@ -1719,7 +1711,7 @@ ue_scheduler( } // Get RLC status info and update Bj for all lcids that are active - for (lcid=DCCH; lcid <= DTCH; lcid++ ) { + for (lcid=DCCH; lcid < MAX_NUM_LCID; lcid++ ) { if ((lcid == 0) ||(UE_mac_inst[module_idP].logicalChannelConfig[lcid])) { // meausre the Bj if ((directionP == SF_UL)&& (UE_mac_inst[module_idP].scheduling_info.Bj[lcid] >= 0)) { @@ -1740,6 +1732,8 @@ ue_scheduler( if (update_bsr(module_idP,frameP, eNB_indexP, lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid])) { UE_mac_inst[module_idP].scheduling_info.SR_pending= 1; + // Regular BSR trigger + UE_mac_inst[module_idP].BSR_reporting_active = 1; LOG_D(MAC,"[UE %d][SR] Frame %d subframe %d SR for PUSCH is pending for LCGID %d with BSR level %d (%d bytes in RLC)\n", module_idP, frameP,subframeP,UE_mac_inst[module_idP].scheduling_info.LCGID[lcid], UE_mac_inst[module_idP].scheduling_info.BSR[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], @@ -1960,75 +1954,49 @@ int cba_access(module_id_t module_idP,frame_t frameP,sub_frame_t subframe, uint8 } #endif -int get_bsr_lcgid (module_id_t module_idP, int *num_lcgid) +int get_bsr_lcgid (module_id_t module_idP) { int lcgid, lcgid_tmp=-1; int num_active_lcgid = 0; for (lcgid = 0 ; lcgid < MAX_NUM_LCGID; lcgid++) { if (UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] > 0 ) { - if (lcgid_tmp == -1){ - // first priority lcgid - lcgid_tmp = lcgid; - } + lcgid_tmp = lcgid; num_active_lcgid+=1; } } - *num_lcgid = num_active_lcgid; - + if (num_active_lcgid == 0) { - return -1; // no data + return -1; + } else if (num_active_lcgid == 1) { + return lcgid_tmp; } else { - return lcgid_tmp;//only one lcgid, report short bsr + return MAX_NUM_LCGID; } } -uint8_t get_bsr_len (module_id_t module_idP, uint16_t buflen) +uint8_t get_bsr_len (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint16_t buflen) { - int lcgid=0; - uint8_t bsr_len=0, num_lcgid=0; + int lcid; + uint8_t bsr_len=0, num_lcid=0; int pdu = 0; - int long_bsr_plus_subheader_length = sizeof(BSR_LONG)+sizeof(SCH_SUBHEADER_FIXED); - int short_bsr_plus_subheader_length = sizeof(BSR_SHORT)+sizeof(SCH_SUBHEADER_FIXED); + mac_rlc_status_resp_t rlc_status; - // check how many lcg have data to report - for (lcgid=0; lcgid < MAX_NUM_LCGID; lcgid++ ) { - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 0 ) { - num_lcgid ++; - pdu += (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] + sizeof(SCH_SUBHEADER_SHORT)); + for (lcid=DCCH; lcid 0 ) { + pdu += rlc_status.bytes_in_buffer + sizeof(SCH_SUBHEADER_SHORT) + bsr_len; + if (rlc_status.bytes_in_buffer > 128 ) { + pdu += 1; //sizeof(SCH_SUBHEADER_LONG) + } } - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 128 ) { // long header size: adjust the header size - pdu += 1; - } - LOG_D(MAC,"BSR Bytes %d for lcgid %d num lcgid %d\n", UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid], lcgid, num_lcgid); - } - // current phy buff can not transport all sdu for this lcgid -> transmit a bsr for this lcgid - if (buflen < pdu) { - if (num_lcgid > 0) { - bsr_len = sizeof(BSR_SHORT); - } else { - bsr_len = 0; - } - } - // padding larger then long bsr - if (buflen > (pdu + long_bsr_plus_subheader_length)) { - if (num_lcgid > 1) { - bsr_len = sizeof(BSR_LONG); - } else if (num_lcgid > 0) { - bsr_len = sizeof(BSR_SHORT); - } else { - bsr_len = 0; - } - } - // padding larger then short bsr and shorter then long bsr - if ((buflen < (pdu + long_bsr_plus_subheader_length)) && - (buflen > (pdu + short_bsr_plus_subheader_length))) { - if (num_lcgid > 0) { - bsr_len = sizeof(BSR_SHORT); - } else { - bsr_len = 0; + if ( (pdu > buflen) && (rlc_status.bytes_in_buffer > 0 ) ) { + num_lcid +=1; + bsr_len = (num_lcid >= 2 ) ? sizeof(BSR_LONG) : sizeof(BSR_SHORT) ; } + LOG_D(MAC,"LC buffer Bytes %d for lcid %d bsr len %d num lcid %d\n", rlc_status.bytes_in_buffer, lcid, bsr_len, num_lcid); } + if ( bsr_len > 0 ) LOG_D(MAC,"[UE %d] Prepare a %s (Transport Block Size %d, MAC pdu Size %d) \n", module_idP, map_int_to_str(BSR_names, bsr_len), buflen, pdu); @@ -2036,16 +2004,15 @@ uint8_t get_bsr_len (module_id_t module_idP, uint16_t buflen) return bsr_len; } - boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_index, uint8_t lcid, uint8_t lcg_id) { mac_rlc_status_resp_t rlc_status; - boolean_t Bsr_pending = FALSE; + boolean_t sr_pending = FALSE; if ((lcg_id < 0) || (lcg_id >= MAX_NUM_LCGID) ) { - return Bsr_pending; + return sr_pending; } // fixme: need a better way to reset @@ -2062,14 +2029,11 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in if (rlc_status.bytes_in_buffer > 0 ) { //BSR trigger SR - Bsr_pending = TRUE; + sr_pending = TRUE; UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_NOT_EMPTY; - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id] = rlc_status.bytes_in_buffer; - if (UE_mac_inst[module_idP].scheduling_info.extendedBSR_Sizes_r10 == TRUE){ - UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = locate_BsrIndexByBufferSize(Extended_BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); - } else { - UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); - } + // sum lcid buffer which has same lcgid + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id] += rlc_status.bytes_in_buffer; + UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); // UE_mac_inst[module_idP].scheduling_info.BSR_short_lcid = lcid; // only applicable to short bsr LOG_D(MAC,"[UE %d] BSR level %d (LCGID %d, rlc buffer %d byte)\n", module_idP, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id],lcg_id, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); @@ -2079,7 +2043,7 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in } //} - return Bsr_pending; + return sr_pending; } uint8_t locate_BsrIndexByBufferSize (const uint32_t *table, int size, int value) From 15e299bd114bc7ec181793834f5a6d6a486387c7 Mon Sep 17 00:00:00 2001 From: fnabet Date: Fri, 21 Oct 2016 15:09:42 +0200 Subject: [PATCH 250/413] [OAI-UE] Authetification XOR Algo for usim test --- openair2/RRC/LITE/MESSAGES/asn1_msg.c | 6 +- openair3/NAS/TOOLS/usim_data.c | 1 + openair3/NAS/UE/API/USIM/usim_api.c | 193 +++++++++++++++++- openair3/NAS/UE/API/USIM/usim_api.h | 5 + openair3/NAS/UE/EMM/Authentication.c | 11 +- .../UE/EMM/SAP/EmmDeregisteredNormalService.c | 10 +- openair3/NAS/UE/EMM/emm_main.c | 2 + targets/RT/USER/lte-softmodem.c | 7 + 8 files changed, 231 insertions(+), 4 deletions(-) diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index e0556b92bf..3fe10c92f8 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -117,6 +117,7 @@ typedef struct xer_sprint_string_s { } xer_sprint_string_t; extern unsigned char NB_eNB_INST; +extern uint8_t usim_test; uint16_t two_tier_hexagonal_cellIds[7] = {0,1,2,4,5,7,8}; uint16_t two_tier_hexagonal_adjacent_cellIds[7][6] = {{1,2,4,5,7,8}, // CellId 0 @@ -1268,7 +1269,10 @@ uint8_t do_RRCConnectionSetupComplete(uint8_t Mod_id, uint8_t *buffer, const uin rrcConnectionSetupComplete->criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8.nonCriticalExtension=CALLOC(1, sizeof(*rrcConnectionSetupComplete->criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8.nonCriticalExtension)); - rrcConnectionSetupComplete->criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8.selectedPLMN_Identity=2; + if(usim_test == 0) + rrcConnectionSetupComplete->criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8.selectedPLMN_Identity= 2; + else + rrcConnectionSetupComplete->criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8.selectedPLMN_Identity= 1; rrcConnectionSetupComplete->criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8.registeredMME = NULL;//calloc(1,sizeof(*rrcConnectionSetupComplete->criticalExtensions.choice.c1.choice.rrcConnectionSetupComplete_r8.registeredMME)); diff --git a/openair3/NAS/TOOLS/usim_data.c b/openair3/NAS/TOOLS/usim_data.c index 1835f0b8b1..126ff4f78c 100644 --- a/openair3/NAS/TOOLS/usim_data.c +++ b/openair3/NAS/TOOLS/usim_data.c @@ -227,6 +227,7 @@ int main (int argc, const char* argv[]) usim_data.imsi.u.num.digit13 = 3; usim_data.imsi.u.num.digit14 = 4; usim_data.imsi.u.num.digit15 = 0xF; + usim_data.usimtestmode = 1; // set usim in test mode in order to get the CMW500 K key #endif /* * Ciphering and Integrity Keys diff --git a/openair3/NAS/UE/API/USIM/usim_api.c b/openair3/NAS/UE/API/USIM/usim_api.c index b0ccbf9504..df7d22db8e 100644 --- a/openair3/NAS/UE/API/USIM/usim_api.c +++ b/openair3/NAS/UE/API/USIM/usim_api.c @@ -79,6 +79,7 @@ Description Implements the API used by the NAS layer to read/write #define USIM_API_K_SIZE 16 //#define USIM_API_K_VALUE "fec86ba6eb707ed08905757b1bb44b8f" #define USIM_API_K_VALUE "8BAF473F2F8FD09487CCCBD7097C6862" +#define TEST_USIM_API_K_VALUE "000102030405060708090a0b0c0d0e0f" // CMW500 K key static uint8_t _usim_api_k[USIM_API_K_SIZE]; @@ -143,7 +144,14 @@ int usim_api_read(usim_data_t* data) } /* initialize the subscriber authentication security key */ - _usim_api_hex_string_to_hex_value(_usim_api_k, USIM_API_K_VALUE, USIM_API_K_SIZE); + if(data->usimtestmode == 0) + { + _usim_api_hex_string_to_hex_value(_usim_api_k, USIM_API_K_VALUE, USIM_API_K_SIZE); + } + else + { + _usim_api_hex_string_to_hex_value(_usim_api_k, TEST_USIM_API_K_VALUE, USIM_API_K_SIZE); + } free(path); LOG_FUNC_RETURN (RETURNok); @@ -188,6 +196,189 @@ int usim_api_write(const usim_data_t* data) LOG_FUNC_RETURN (RETURNok); } +/**************************************************************************** + ** ** + ** Name: usim_api_authenticate_test() ** + ** ** + ** Description: Performs mutual authentication of the USIM to the network,** + ** checking whether authentication token AUTN can be accep- ** + ** ted. If so, returns an authentication response RES and ** + ** the ciphering and integrity keys. ** + ** In case of synch failure, returns a re-synchronization ** + ** token AUTS. ** + ** ** + ** Key Generation for Test USIM based on 34.108 ** + ** ** + ** Authentication and key generating function algorithms are ** + ** specified in 3GPP TS 35.206. ** + ** ** + ** Inputs: rand_pP: Random challenge number ** + ** autn_pP: Authentication token ** + ** AUTN = (SQN xor AK) || AMF || MAC ** + ** 48 16 64 bits ** + ** Others: Security key ** + ** ** + ** Outputs: auts_pP: Re-synchronization token ** + ** res_pP: Authentication response ** + ** ck_pP: Ciphering key ** + ** ik_pP Integrity key ** + ** ** + ** Return: RETURNerror, RETURNok ** + ** Others: None ** + ** ** + ***************************************************************************/ +int usim_api_authenticate_test(const OctetString* rand_pP, const OctetString* autn_pP, + OctetString* auts_pP, OctetString* res_pP, + OctetString* ck_pP, OctetString* ik_pP) +{ + LOG_FUNC_IN; + + int rc; + int i; + + LOG_TRACE(INFO, "USIM-API - rand :%s",dump_octet_string(rand_pP)); + LOG_TRACE(INFO, "USIM-API - autn :%s",dump_octet_string(autn_pP)); + + //step1: XDOUT = RAND xor K + // RES = XDOUT + for (i=0; ivalue[i] = rand_pP->value[i] ^ _usim_api_k[i]; + } + + //step2: res = f2(xdout,n) + // ck = f3(xdout) + // ik = f4(xdout) + // ak = f5(xdout) + u8 ak[USIM_API_AK_SIZE]; + for (i=0; i<15; i++) + { + ck_pP->value[i] = res_pP->value[i+1]; + } + ck_pP->value[15] = res_pP->value[0]; + + for (i=0; i<14; i++) + { + ik_pP->value[i] = res_pP->value[i+2]; + } + ik_pP->value[14] = res_pP->value[0]; + ik_pP->value[15] = res_pP->value[1]; + + for (i=0; ivalue[i+3]; + } + LOG_TRACE(INFO, "USIM-API - res(f2) :%s",dump_octet_string(res_pP)); + LOG_TRACE(INFO, "USIM-API - ck(f3) :%s",dump_octet_string(ck_pP)); + LOG_TRACE(INFO, "USIM-API - ik(f4) :%s",dump_octet_string(ik_pP)); + LOG_TRACE(INFO, "USIM-API - ak(f5) : %02X%02X%02X%02X%02X%02X", + ak[0],ak[1],ak[2],ak[3],ak[4],ak[5]); + + //step3: concatenate SQN with AMP SQN||AMF + // SQN = AUTN xor ak + u8 sqn[USIM_API_SQN_SIZE]; + for (i = 0; i < USIM_API_SQN_SIZE; i++) { + sqn[i] = autn_pP->value[i] ^ ak[i]; + } + LOG_TRACE(INFO, "USIM-API - Retrieved SQN %02X%02X%02X%02X%02X%02X", + sqn[0],sqn[1],sqn[2],sqn[3],sqn[4],sqn[5]); + LOG_TRACE(INFO, "USIM-API - Retrieved AMF %02X%02X", + autn_pP->value[USIM_API_SQN_SIZE],autn_pP->value[USIM_API_SQN_SIZE+1]); + +#define USIM_API_XMAC_SIZE 8 + u8 cdout[USIM_API_XMAC_SIZE]; + for (i = 0; i < USIM_API_XMAC_SIZE; i++) + { + if(i < USIM_API_SQN_SIZE) + { + cdout[i] = sqn[i]; + } + else + { + cdout[i] = autn_pP->value[i]; + } + } + LOG_TRACE(INFO, "USIM-API - Retrieved CDOUT %02X%02X%02X%02X%02X%02X%02X%02X", + cdout[0],cdout[1],cdout[2],cdout[3],cdout[4],cdout[5],cdout[6],cdout[7]); + + //step4:calculate XMAC from cdout and xdout + u8 xmac[USIM_API_XMAC_SIZE]; + for(i = 0; i < USIM_API_XMAC_SIZE; i++) + { + xmac[i] = res_pP->value[i] ^ cdout[i]; + } + LOG_TRACE(INFO, + "USIM-API - Computed XMAC %02X%02X%02X%02X%02X%02X%02X%02X", + xmac[0],xmac[1],xmac[2],xmac[3], + xmac[4],xmac[5],xmac[6],xmac[7]); + + /* Compare the XMAC with the MAC included in AUTN */ +#define USIM_API_AMF_SIZE 2 + + if ( memcmp(xmac, &autn_pP->value[USIM_API_SQN_SIZE + USIM_API_AMF_SIZE], + USIM_API_XMAC_SIZE) != 0 ) { + LOG_TRACE(INFO, + "USIM-API - Comparing the XMAC with the MAC included in AUTN Failed"); + rc = RETURNerror; + //LOG_FUNC_RETURN (RETURNerror); + } else { + LOG_TRACE(INFO, + "USIM-API - Comparing the XMAC with the MAC included in AUTN Succeeded"); + /* Verify that the received sequence number SQN is in the correct range */ + rc = _usim_api_check_sqn(*(uint32_t*)(sqn), sqn[USIM_API_SQN_SIZE - 1]); + } + + + if (rc != RETURNok) { + /* Synchronisation failure; compute the AUTS parameter */ + + /* Concealed value of the counter SQNms in the USIM: + * Conc(SQNMS) = SQNMS ⊕ f5*K(RAND) */ + f5star(_usim_api_k, rand_pP->value, ak); + + + u8 sqn_ms[USIM_API_SQNMS_SIZE]; + memset(sqn_ms, 0, USIM_API_SQNMS_SIZE); + + //#define USIM_API_SQN_MS_SIZE 3 + printf("_usim_api_data.sqn_ms %p\n",_usim_api_data.sqn_ms); + for (i = 0; i < USIM_API_SQNMS_SIZE; i++) { + //#warning "LG:BUG HERE TODO" + printf("i %d: ((uint8_t*)(_usim_api_data.sqn_ms))[USIM_API_SQNMS_SIZE - i] %d\n",i, ((uint8_t*)(_usim_api_data.sqn_ms))[USIM_API_SQNMS_SIZE - i]); + sqn_ms[USIM_API_SQNMS_SIZE - i] = + ((uint8_t*)(_usim_api_data.sqn_ms))[USIM_API_SQNMS_SIZE - i]; + } + + u8 sqnms[USIM_API_SQNMS_SIZE]; + + for (i = 0; i < USIM_API_SQNMS_SIZE; i++) { + sqnms[i] = sqn_ms[i] ^ ak[i]; + } + + LOG_TRACE(DEBUG, "USIM-API - SQNms %02X%02X%02X%02X%02X%02X", + sqnms[0],sqnms[1],sqnms[2],sqnms[3],sqnms[4],sqnms[5]); + + /* Synchronisation message authentication code: + * MACS = f1*K(SQNMS || RAND || AMF) */ +#define USIM_API_MACS_SIZE USIM_API_XMAC_SIZE + u8 macs[USIM_API_MACS_SIZE]; + f1star(_usim_api_k, rand_pP->value, sqn_ms, + &rand_pP->value[USIM_API_SQN_SIZE], macs); + LOG_TRACE(DEBUG, "USIM-API - MACS %02X%02X%02X%02X%02X%02X%02X%02X", + macs[0],macs[1],macs[2],macs[3], + macs[4],macs[5],macs[6],macs[7]); + + /* Synchronisation authentication token: + * AUTS = Conc(SQNMS) || MACS */ + memcpy(&auts_pP->value[0], sqnms, USIM_API_SQNMS_SIZE); + memcpy(&auts_pP->value[USIM_API_SQNMS_SIZE], macs, USIM_API_MACS_SIZE); + auts_pP->length = USIM_API_SQNMS_SIZE + USIM_API_MACS_SIZE; + LOG_FUNC_RETURN (RETURNerror); + } + + LOG_FUNC_RETURN (RETURNok); +} + /**************************************************************************** ** ** ** Name: usim_api_authenticate() ** diff --git a/openair3/NAS/UE/API/USIM/usim_api.h b/openair3/NAS/UE/API/USIM/usim_api.h index f7e85f95e7..fd4b3e3301 100644 --- a/openair3/NAS/UE/API/USIM/usim_api.h +++ b/openair3/NAS/UE/API/USIM/usim_api.h @@ -334,6 +334,8 @@ typedef struct { usim_epsloci_t epsloci; /* Non-Access Stratum configuration */ usim_nasconfig_t nasconfig; + /* usim test mode */ + uint8_t usimtestmode; } usim_data_t; /****************************************************************************/ @@ -351,5 +353,8 @@ int usim_api_write(const usim_data_t* data); int usim_api_authenticate(const OctetString* rand, const OctetString* autn, OctetString* auts, OctetString* res, OctetString* ck, OctetString* ik); +int usim_api_authenticate_test(const OctetString* rand, const OctetString* autn, + OctetString* auts, OctetString* res, + OctetString* ck, OctetString* ik); #endif /* __USIM_API_H__*/ diff --git a/openair3/NAS/UE/EMM/Authentication.c b/openair3/NAS/UE/EMM/Authentication.c index 6285534450..96f28d7e86 100755 --- a/openair3/NAS/UE/EMM/Authentication.c +++ b/openair3/NAS/UE/EMM/Authentication.c @@ -86,6 +86,8 @@ extern void *_emm_service_t3417_handler(void *); extern void *_emm_detach_t3421_handler(void *); extern void *_emm_tau_t3430_handler(void *); +extern uint8_t usim_test; + /****************************************************************************/ /******************* L O C A L D E F I N I T I O N S *******************/ /****************************************************************************/ @@ -240,7 +242,14 @@ int emm_proc_authentication_request(int native_ksi, int ksi, * of the core network by means of the received AUTN parameter and * request the USIM to compute RES, CK and IK for given RAND */ - rc = usim_api_authenticate(rand, autn, &auts, &res, &ck, &ik); + if(usim_test == 0) + { + rc = usim_api_authenticate(rand, autn, &auts, &res, &ck, &ik); + } + else + { + rc = usim_api_authenticate_test(rand, autn, &auts, &res, &ck, &ik); // XOR algo for autentication on usim test mode + } } if (rc != RETURNok) { diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c index 25924fd9f2..167c80ee51 100755 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c @@ -62,6 +62,7 @@ Description Implements the EPS Mobility Management procedures executed /****************************************************************************/ /**************** E X T E R N A L D E F I N I T I O N S ****************/ /****************************************************************************/ +extern uint8_t usim_test; /****************************************************************************/ /******************* L O C A L D E F I N I T I O N S *******************/ @@ -116,7 +117,14 @@ int EmmDeregisteredNormalService(const emm_reg_t *evt) /* * Initiate the attach procedure for EPS services */ - rc = emm_proc_attach(EMM_ATTACH_TYPE_EPS); + if(usim_test == 0) + { + rc = emm_proc_attach(EMM_ATTACH_TYPE_EPS); + } + else + { + rc = emm_proc_attach(EMM_ATTACH_TYPE_IMSI); // CMW500 IMSI initial attach expected + } break; case _EMMREG_ATTACH_REQ: diff --git a/openair3/NAS/UE/EMM/emm_main.c b/openair3/NAS/UE/EMM/emm_main.c index dbeacaa149..3ec9aa5cac 100755 --- a/openair3/NAS/UE/EMM/emm_main.c +++ b/openair3/NAS/UE/EMM/emm_main.c @@ -59,6 +59,7 @@ Description Defines the EPS Mobility Management procedure call manager, /****************************************************************************/ /**************** E X T E R N A L D E F I N I T I O N S ****************/ /****************************************************************************/ +extern uint8_t usim_test; /****************************************************************************/ /******************* L O C A L D E F I N I T I O N S *******************/ @@ -166,6 +167,7 @@ void emm_main_initialize(emm_indication_callback_t cb, const char *imei) /* * Get USIM application data */ + _usim_data.usimtestmode = usim_test; if ( usim_api_read(&_usim_data) != RETURNok ) { /* The USIM application may not be present or not valid */ LOG_TRACE(WARNING, "EMM-MAIN - Failed to read USIM application data"); diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index d055eea3ad..ba4988cbfa 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -212,6 +212,7 @@ char rf_config_file[1024]; int chain_offset=0; int phy_test = 0; +uint8_t usim_test = 0; char ref[128] = "internal"; @@ -387,6 +388,7 @@ void help (void) { printf(" --loop-memory get softmodem (UE) to loop through memory instead of acquiring from HW\n"); printf(" --mmapped-dma sets flag for improved EXMIMO UE performance\n"); printf(" --single-thread runs lte-softmodem in only one thread\n"); + printf(" --usim-test use XOR autentication algo in case of test usim mode\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"); @@ -693,6 +695,7 @@ static void get_options (int argc, char **argv) LONG_OPTION_DUMP_FRAME, LONG_OPTION_LOOPMEMORY, LONG_OPTION_PHYTEST, + LONG_OPTION_USIMTEST, LONG_OPTION_MMAPPED_DMA, LONG_OPTION_SINGLE_THREAD, #if T_TRACER @@ -719,6 +722,7 @@ static void get_options (int argc, char **argv) {"ue-dump-frame", no_argument, NULL, LONG_OPTION_DUMP_FRAME}, {"loop-memory", required_argument, NULL, LONG_OPTION_LOOPMEMORY}, {"phy-test", no_argument, NULL, LONG_OPTION_PHYTEST}, + {"usim-test", no_argument, NULL, LONG_OPTION_USIMTEST}, {"mmapped-dma", no_argument, NULL, LONG_OPTION_MMAPPED_DMA}, {"single-thread", no_argument, NULL, LONG_OPTION_SINGLE_THREAD}, #if T_TRACER @@ -818,6 +822,9 @@ static void get_options (int argc, char **argv) phy_test = 1; break; + case LONG_OPTION_USIMTEST: + usim_test = 1; + break; case LONG_OPTION_MMAPPED_DMA: mmapped_dma = 1; break; From b6c7909d03f740a2b390cf2bc6c7c8af62bda476 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 24 Oct 2016 19:14:07 +0300 Subject: [PATCH 251/413] Fixed bugs related to MAC padding and RLC requests in AM mode --- .../MAC/eNB_agent_scheduler_dataplane.c | 29 ++- .../LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c | 12 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 2 +- .../enb.band7.flexran.50PRB.usrpb210.conf | 182 ++++++++++++++++++ 4 files changed, 209 insertions(+), 16 deletions(-) create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.50PRB.usrpb210.conf diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c index b75b0467b1..a4d4d79250 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c @@ -126,6 +126,8 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, static int32_t tpc_accumulated=0; UE_sched_ctrl *ue_sched_ctl; + int last_sdu_header_len = 0; + int i; Protocol__FlexDlData *dl_data; @@ -161,18 +163,21 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, if (dl_data->n_ce_bitmap > 0) { //Check if there is TA command and set the length appropriately - ta_len = (dl_data->ce_bitmap[0] & PROTOCOL__FLEX_CE_TYPE__FLPCET_TA) ? 2 : 0; + ta_len = (dl_data->ce_bitmap[0] & PROTOCOL__FLEX_CE_TYPE__FLPCET_TA) ? 1 : 0; } + + num_sdus = 0; + sdu_length_total = 0; if (ta_len > 0) { // Reset the measurement ue_sched_ctl->ta_timer = 20; eNB_UE_stats->timing_advance_update = 0; + header_len = ta_len; + last_sdu_header_len = ta_len; } - + n_lc = dl_data->n_rlc_pdu; - num_sdus = 0; - sdu_length_total = 0; // Go through each one of the channel commands and create SDUs for (i = 0; i < n_lc; i++) { lcid = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->logical_channel_id; @@ -192,6 +197,10 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, if (rlc_status.bytes_in_buffer > 0) { + if (rlc_size <= 2) { + rlc_size = 3; + } + rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, @@ -223,12 +232,13 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, 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[i]; - if (sdu_lengths[i] < 128) { + if (sdu_lengths[i] <= 128) { header_len += 2; + last_sdu_header_len = 2; } else { header_len += 3; + last_sdu_header_len = 3; } - num_sdus++; } } @@ -238,13 +248,14 @@ void apply_ue_spec_scheduling_decisions(mid_t mod_id, if (((sdu_length_total + header_len) > 0)) { - header_len_tmp = header_len; + // header_len_tmp = header_len; // If we have only a single SDU, header length becomes 1 - if (header_len == 2 || header_len == 3) { + if ((num_sdus + ta_len) == 1) { + //if (header_len == 2 || header_len == 3) { header_len = 1; } else { - header_len--; + header_len = (header_len - last_sdu_header_len) + 1; } // there is a payload diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c index 90d5ad5f1b..4572e73def 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -371,7 +371,7 @@ schedule_ue_spec_default( // Need to see if we have space for data from this channel if (dci_tbs - ta_len - header_len > 0) { - LOG_D(MAC, "[TEST]Requested %d bytes from RLC buffer if channel %d during first call\n", dci_tbs-ta_len-header_len); + LOG_D(MAC, "[TEST]Requested %d bytes from RLC buffer on channel %d during first call\n", dci_tbs-ta_len-header_len); //If we have space, we need to see how much data we can request at most (if any available) rlc_status = mac_rlc_status_ind(mod_id, rnti, @@ -390,10 +390,10 @@ schedule_ue_spec_default( if (data_to_request < 128) { //The header will be one byte less header_len--; } - if (j == 1 || j == 2) { - data_to_request++; //It is not correct but fixes some RLC bug for DCCH - } - LOG_D(MAC, "[TEST]Will request %d from DCCH\n", data_to_request); + /* if (j == 1 || j == 2) { */ + /* data_to_request+=0; + /* } */ + LOG_D(MAC, "[TEST]Will request %d from channel %d\n", data_to_request, j); rlc_pdus[channels_added] = (Protocol__FlexRlcPdu *) malloc(sizeof(Protocol__FlexRlcPdu)); protocol__flex_rlc_pdu__init(rlc_pdus[channels_added]); rlc_pdus[channels_added]->n_rlc_pdu_tb = 2; @@ -523,7 +523,7 @@ schedule_ue_spec_default( if (frame_parms[CC_id]->frame_type == TDD) { UE_list->UE_template[CC_id][UE_id].DAI++; // printf("DAI update: subframeP %d: UE %d, DAI %d\n",subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); -#warning only for 5MHz channel + //#warning only for 5MHz channel update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 7946fdf663..a5c1e90147 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -146,7 +146,7 @@ rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP) return (rnti); } - LOG_E(MAC,"[eNB %d] Couldn't find RNTI for UE %d\n",mod_idP,ue_idP); + LOG_D(MAC,"[eNB %d] Couldn't find RNTI for UE %d\n",mod_idP,ue_idP); //display_backtrace(); return(NOT_A_RNTI); } diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.50PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.50PRB.usrpb210.conf new file mode 100644 index 0000000000..f73a78b3b0 --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.50PRB.usrpb210.conf @@ -0,0 +1,182 @@ +Active_eNBs = ( "eNB_Eurecom_LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB_Eurecom_LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = "1"; + + mobile_country_code = "208"; + + mobile_network_code = "95"; + + ////////// Physical parameters: + + component_carriers = ( + { + node_function = "eNodeB_3GPP"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2660000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 0; + N_RB_DL = 50; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 1; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 125; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = -27; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -96; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -100; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -104; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + + ue_TransmissionMode = 1; + } + ); + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.100.101"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.106/24"; + + ENB_INTERFACE_NAME_FOR_S1U = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.106/24"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + NETWORK_CONTROLLER : + { + ENB_AGENT_INTERFACE_NAME = "eth1"; + ENB_AGENT_IPV4_ADDRESS = "10.0.2.5/30"; + ENB_AGENT_PORT = 2210; + ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; + }; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + } +); From c37446507ae21aff9fd4364ba8d63b19fcf66799 Mon Sep 17 00:00:00 2001 From: ROBERT Benoit Date: Tue, 25 Oct 2016 16:51:37 +0200 Subject: [PATCH 252/413] Add testing capabilities for OAI UE in autotest framework Autotest Framework modifications: -> paramiko.Transport((hostname, ports)) : issue on my configuration -> add --test-suite command line parameter to select a different test suite XML file (default is test_case_list.xml) -> add patch file functionnality when installing remote machine : required to add LOG printing for pass/fail evaluation -> add lte-softmodem-noS1 test class - fork of lte-softmodem with the following modification - no EPC management on lte-softmodem-noS1 class - add cell synchronization detection as a precondition for test results analysis - add metric extraction for pass/fail criteria (metrics are defined in XML file) - generate graphics for performances metrics (used in the HTML report -> not available in this delivery) Patch files: -> autotest_ue_cell_synch_event.patch : Add log for cell synchronization detection -> autotest_ue_dlsch_bitrate_metric.patch : Add log for DLSCH bitrate capture -> 3gpplte_turbo_decoder_sse_8bit.patch : hotfix for turbo decoder in autotest (issue followed in oai1B project) -> phy_test__target_dl_mcs.patch : hotfix for --phy-test configuration (MCS) --- cmake_targets/autotests/autotest_analyser.py | 161 + .../autotests/lib_autotest_analyser.py | 414 +++ .../3gpplte_turbo_decoder_sse_8bit.patch | 25 + .../autotest_ue_cell_synch_event.patch | 18 + .../autotest_ue_dlsch_bitrate_metric.patch | 19 + .../patches/phy_test__target_dl_mcs.patch | 17 + .../autotests/run_exec_lte-softmodem_tests.py | 664 +++- .../autotests/run_lte-softmodem-nos1_tests.py | 2785 ++++++++++++++ .../autotests/testsuite_ue_noS1_eurecom.xml | 3214 +++++++++++++++++ 9 files changed, 7315 insertions(+), 2 deletions(-) create mode 100755 cmake_targets/autotests/autotest_analyser.py create mode 100644 cmake_targets/autotests/lib_autotest_analyser.py create mode 100644 cmake_targets/autotests/patches/3gpplte_turbo_decoder_sse_8bit.patch create mode 100644 cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch create mode 100644 cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch create mode 100644 cmake_targets/autotests/patches/phy_test__target_dl_mcs.patch create mode 100755 cmake_targets/autotests/run_lte-softmodem-nos1_tests.py create mode 100644 cmake_targets/autotests/testsuite_ue_noS1_eurecom.xml diff --git a/cmake_targets/autotests/autotest_analyser.py b/cmake_targets/autotests/autotest_analyser.py new file mode 100755 index 0000000000..a75727ad65 --- /dev/null +++ b/cmake_targets/autotests/autotest_analyser.py @@ -0,0 +1,161 @@ +#! /usr/bin/python +#****************************************************************************** +# +# \file autotest_analyser.py +# +# \par Informations +# - \b Project : UED Autotest Framework +# - \b Software : +# +# \date 16 september 2016 +# +# \version 0.1 +# +# \brief helper to test lib_autotest_analyser.py +# +# \author Benoit ROBERT (benoit.robert@syrtem.com) +# +# \par Statement of Ownership +# COPYRIGHT (c) 2016 BY SYRTEM S.A.R.L +# This software is furnished under license and may be used and copied +# only in accordance with the terms of such license and with the inclusion +# of the above COPYRIGHT notice. This SOFTWARE or any other copies thereof +# may not be provided or otherwise made available to any other person. +# No title to and ownership of the SOFTWARE is hereby transferred. +# +# The information in this SOFTWARE is subject to change without notice +# and should not be constructed as a commitment by SYRTEM. +# SYRTEM assumes no responsibility for the use or reliability of its +# SOFTWARE on equipment or platform not explicitly validated by SYRTEM. +# +# ******************************************************************************* + +import os +import getopt +import sys +from subprocess import call + + + +#test_cases = ('030001', '030901', '031001', '031601', '031701', '031801', '031901', '032001', '032101', '032201', '032301', '032501', '032601', '032801') +test_cases = ('030030' , '030030' ) + +nb_run = 3 + +def error_opt(msg): + print("Option error: " + msg) + + +def main(args): + try: + analyser = __import__("lib_autotest_analyser") + except ImportError as err: + print('Import error: ' + str(err)) + exit(0) + + + log_path = 'log_save_2016-08-14/log/' + + + + metric = {} + metric['id'] = 'UE_DLSCH_BITRATE' + metric['description'] = 'UE downlink physical throughput' + metric['regex'] = '(UE_DLSCH_BITRATE) =\s+(\d+\.\d+) kbps.+frame = (\d+)\)' + metric['unit_of_meas'] = 'kbps' + metric['min_limit'] = 14668.8 + + +#report_path = log_path+'/report/' + +#os.system(' mkdir -p ' + report_path) + +#analyser.create_report_html(report_path) + +#return(0) + + for test_case in test_cases: + +# print test_case + if test_case == '030001': + metric['min_limit'] = 500.0 + if test_case == '030901': + metric['min_limit'] = 640.0 + if test_case == '031001': + metric['min_limit'] = 3200.0 + if test_case == '031601': + metric['min_limit'] = 5920.0 + if test_case == '031701': + metric['min_limit'] = 6000.0 + if test_case == '031801': + metric['min_limit'] = 6200.0 + if test_case == '031901': + metric['min_limit'] = 7000.0 + if test_case == '032001': + metric['min_limit'] = 7800.0 + if test_case == '032101': + metric['min_limit'] = 8000.0 + if test_case == '032201': + metric['min_limit'] = 9000.0 + if test_case == '032301': + metric['min_limit'] = 10000.0 + if test_case == '032501': + metric['min_limit'] = 11000.0 + if test_case == '032601': + metric['min_limit'] = 12000.0 + if test_case == '032801': + metric['min_limit'] = 12500.0 + + if test_case == '035201': + metric['min_limit'] = 14668.8 + if test_case == '036001': + metric['min_limit'] = 25363.2 + + + + for i in range(0, nb_run): + fname = 'log//'+test_case+'/run_'+str(i)+'/UE_exec_'+str(i)+'_.log' + args = {'metric' : metric, + 'file' : fname } + + cell_synch_status = analyser.check_cell_synchro(fname) + if cell_synch_status == 'CELL_SYNCH': + print '!!!!!!!!!!!!!! Cell synchronized !!!!!!!!!!!' + metric_checks_flag = 0 + else : + print '!!!!!!!!!!!!!! Cell NOT NOT synchronized !!!!!!!!!!!' + +# metric_extracted = analyser.do_extract_metrics(args) + +# print "min = "+ str( metric_extracted['metric_min'] ) +# print "min_index = "+ str( metric_extracted['metric_min_index'] ) +# print "max = "+ str( metric_extracted['metric_max'] ) +# print "max_index = "+ str( metric_extracted['metric_max_index'] ) +# print "mean = "+ str( metric_extracted['metric_mean'] ) +# print "median = "+ str( metric_extracted['metric_median'] ) + +# verdict = analyser.do_check_verdict(metric, metric_extracted) +# print verdict + +# fname= 'report/2016-9-8_toto/'+test_case+'/UE_metric_UE_DLSCH_BITRATE_'+str(i)+'_.png' +# fname= 'report/UE_metric_UE_DLSCH_BITRATE_'+test_case+'_'+str(i)+'.png' + +# print fname +# analyser.do_img_metrics(metric, metric_extracted, fname) + +# fname = 'log//'+test_case+'/run_'+str(i)+'/UE_traffic_'+str(i)+'_.log' + +# args = {'file' : fname } + +# traffic_metrics = analyser.do_extract_traffic_metrics(args) + +# fname= 'report/iperf_'+test_case+'_'+str(i)+'.png' + +# print fname +# analyser.do_img_traffic(traffic_metrics, fname) + + + +if __name__ == "__main__": + main(sys.argv) + diff --git a/cmake_targets/autotests/lib_autotest_analyser.py b/cmake_targets/autotests/lib_autotest_analyser.py new file mode 100644 index 0000000000..92dcc31e48 --- /dev/null +++ b/cmake_targets/autotests/lib_autotest_analyser.py @@ -0,0 +1,414 @@ +#****************************************************************************** +# +# \file lib_autotest_analyser.py +# +# \par Informations +# - \b Project : UED Autotest Framework +# - \b Software : +# +# \date 16 september 2016 +# +# \version 0.1 +# +# \brief library to extract metrics from autotest logs and assign a verdict +# +# \author Benoit ROBERT (benoit.robert@syrtem.com) +# +# \par Statement of Ownership +# COPYRIGHT (c) 2016 BY SYRTEM S.A.R.L +# This software is furnished under license and may be used and copied +# only in accordance with the terms of such license and with the inclusion +# of the above COPYRIGHT notice. This SOFTWARE or any other copies thereof +# may not be provided or otherwise made available to any other person. +# No title to and ownership of the SOFTWARE is hereby transferred. +# +# The information in this SOFTWARE is subject to change without notice +# and should not be constructed as a commitment by SYRTEM. +# SYRTEM assumes no responsibility for the use or reliability of its +# SOFTWARE on equipment or platform not explicitly validated by SYRTEM. +# +# ******************************************************************************* + + +import re +from pylab import * +from matplotlib.font_manager import FontProperties + +import os +from jinja2 import Environment, FileSystemLoader + + +PATH = os.path.dirname(os.path.abspath(__file__)) +TEMPLATE_ENVIRONMENT = Environment( + autoescape=False, + loader=FileSystemLoader(os.path.join(PATH, 'templates')), + trim_blocks=False) + + +def render_template(template_filename, context): + return TEMPLATE_ENVIRONMENT.get_template(template_filename).render(context) + + + +def init(args = None): + return + + +# +# +# +def do_extract_metrics(args): + +# print "" +# print "do_extract_metrics ... " + + fname = args['file'] + metric = args['metric'] +# print(fname) +# print 'metric id = ' + metric['id'] +# print 'metric regex = ' + metric['regex'] + + count = 0 + mmin = 0 + mmin_index = 0 + mmax = 0 + mmax_index = 0 + mean = 0 + median = 0 + + + output = np.fromregex(fname,metric['regex'], [('id', 'S20'), ('metric', np.float), ('frame', np.int)] ) +# print 'T0T0 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' +# print output + count = output['metric'].size +# print count + if count > 0: + mmin = np.amin(output['metric']); + mmin_index = np.argmin(output['metric']); + mmax = np.amax(output['metric']); + mmax_index = np.argmax(output['metric']); + mean = np.mean(output['metric']); + median = np.median(output['metric']); + +# print ( ( (metric['min_limit'] > output['metric']).sum() / float(output['metric'].size) ) * 100 ) + + ret = { 'metric_count' : count, + 'metric_buf' : output, + 'metric_min' : mmin, + 'metric_min_index' : mmin_index, + 'metric_max' : mmax, + 'metric_max_index' : mmax_index, + 'metric_mean' : mean, + 'metric_median' : median, + } + return(ret) + +# +# +# +def do_check_verdict(metric_def, metric_data): + verdict = 'INCON' + + pass_fail_stat = metric_def['pass_fail_stat'] + + if pass_fail_stat == 'max_value': + metric_stat = metric_data['metric_max'] + elif pass_fail_stat == 'min_value': + metric_stat = metric_data['metric_min'] + elif pass_fail_stat == 'mean_value': + metric_stat = metric_data['metric_mean'] + elif pass_fail_stat == 'median_value': + metric_stat = metric_data['metric_median'] + else : + print "do_check_verdict -> undef metric stat (pass_fail_stat in xml file)" + return verdict + + if 'max_limit' in metric_def: + if metric_stat > metric_def['max_limit']: + verdict = 'FAIL' + else: + verdict = 'PASS' + + if 'min_limit' in metric_def: + if metric_stat < metric_def['min_limit']: + verdict = 'FAIL' + else: + verdict = 'PASS' + return verdict + + +def do_print_metrics(metric_def, metric_data): + + + if metric_data['metric_count'] > 0 : + +# output = np.array( metric_data['metric_buf'] , [('id', 'S20'), ('metric', np.float), ('frame', np.int)]) + output = metric_data['metric_buf'] +# print output + + fontP = FontProperties() + fontP.set_size('small') + + plt.scatter(output['frame'], output['metric'], color='b', alpha=0.33, s = 1 ) + plt.plot([0, output['frame'][metric_data['metric_count']-1]],[ metric_def['min_limit'],metric_def['min_limit']], 'r-', lw=2) # Red straight line + + plt.title('Physical throughput ') + plt.xlabel('frame') + plt.ylabel(metric_def['id']) + plt.legend(prop=fontP) + mng = plt.get_current_fig_manager() + plt.show() + +def do_img_metrics(metric_def, metric_data, fname): + + + if metric_data['metric_count'] > 0 : + +# output = np.array( metric_data['metric_buf'] , [('id', 'S20'), ('metric', np.float), ('frame', np.int)]) + output = metric_data['metric_buf'] +# print 'TITI !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' +# print output + +# print metric_def['min_limit'] +# print metric_data['metric_count'] +# print output['frame'][metric_data['metric_count']-1] + + fontP = FontProperties() + fontP.set_size('small') + + plt.figure() + +# print output['frame'].size +# print output['metric'].size + + plt.scatter(output['frame'], output['metric'], color='b', alpha=0.33, s = 1 , label=metric_def['id']) + plt.plot([0, output['frame'][metric_data['metric_count']-1]],[ metric_def['min_limit'],metric_def['min_limit']], 'r-', lw=2, label='min limit') # Red straight line + + plt.title('Physical throughput ('+metric_def['unit_of_meas']+')') + plt.xlabel('frame') + plt.ylabel(metric_def['id']) + + # Set graphic minimum Y axis + # ------------------------- + if metric_data['metric_min'] == 0 : + plt.ylim(ymin=-metric_def['min_limit']/10) + else : + plt.ylim(ymin=0) + + y_axis_max = 0 + if metric_data['metric_max'] > metric_def['min_limit']: + y_axis_max =metric_data['metric_max']+metric_data['metric_max']/10 + else: + y_axis_max =metric_def['min_limit']+metric_def['min_limit']/10 + + plt.ylim(ymax=y_axis_max) + + lgd = plt.legend(prop=fontP, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) + mng = plt.get_current_fig_manager() + plt.savefig(fname, bbox_extra_artists=(lgd,), bbox_inches='tight') + plt.close() + +# with open(fname, 'r') as f: +# for line in f: +# m = re.search(metric['regex'], line) +# if m : +# print m.group(1) + " -> "+m.group(2) + + + + +def do_extract_traffic_metrics(args): + + print "" + print "do_extract_traffic_metrics ... " + + fname = args['file'] + +# print(fname) +# print 'metric id = ' + metric['id'] + +#[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams +#[ 3] 0.0- 1.0 sec 238 KBytes 1.95 Mbits/sec 0.980 ms 2/ 174 (1.1%) +# [ 3] 0.0- 1.0 sec 63.2 KBytes 517 Kbits/sec 0.146 ms 1/ 45 (2.2%) + +# iperf_regex = '[\s*(\d+)]\s+\d+\.\d+-\s*(\d+\.\d+)\s+sec\s+(\d+).+(\d+\.\d+).+(\d+\.\d+).+(\d+)\/\s*(\d+)\s+\((\d+\.\d+)\%\)' + # ID 0.0 1.0 63.2 KByte 517 Kbits/s 0.146 + iperf_regex = '\[\s*(\d+)\]\s+(\d+\.*\d*)-\s*(\d+\.*\d*)\s+sec\s+(\d+\.*\d*)\s+(\D+)\s+(\d+\.*\d*)\s+(\D+)\s+(\d+\.*\d*)\s+ms\s+(\d+)\/\s*(\d+)\s+\((\d+\.*\d*)\%\)' +# print 'iperf regex = ' + iperf_regex + + count = 0 + bw_min = 0 + bw_max = 0 + bw_mean = 0 + bw_median = 0 + jitter_min = 0 + jitter_max = 0 + jitter_mean = 0 + jitter_median = 0 + + rl_min = 0 + rl_max = 0 + rl_mean = 0 + rl_median = 0 + + interval_stop_max = 0 + + output = np.fromregex(fname,iperf_regex, [('id', np.int) , ('interval_start', np.float), ('interval_stop', np.float), ('transfer', np.float), ('transfer_uom', 'S20') ,('bandwidth', np.float), ('bandwidth_uom', 'S20') ,('jitter', np.float), ('lost', np.int) , ('total', np.int), ('rate_lost', np.float) ] ) + + count = output['id'].size -1 + # remove last line that is an iperf result resume + + if count > 0: + + output= np.delete(output, (count), axis=0 ) +# print output + + bw_min = np.amin(output['bandwidth']); + bw_max = np.amax(output['bandwidth']); + bw_mean = np.mean(output['bandwidth']); + bw_median = np.median(output['bandwidth']); + + jitter_min = np.amin(output['jitter']); + jitter_max = np.amax(output['jitter']); + jitter_mean = np.mean(output['jitter']); + jitter_median = np.median(output['jitter']); + + rl_min = np.amin(output['rate_lost']); + rl_max = np.amax(output['rate_lost']); + rl_mean = np.mean(output['rate_lost']); + rl_median = np.median(output['rate_lost']); + + interval_stop_max = np.amax(output['interval_stop']); + + else : + count = 0 + + + ret = { 'traffic_count' : count, + 'traffic_buf' : output, + 'bw_min' : bw_min, + 'bw_max' : bw_max, + 'bw_mean' : bw_mean, + 'bw_median' : bw_median, + 'jitter_min' : jitter_min, + 'jitter_max' : jitter_max, + 'jitter_mean' : jitter_mean, + 'jitter_median' : jitter_median, + 'rl_min' : rl_min, + 'rl_max' : rl_max, + 'rl_mean' : rl_mean, + 'rl_median' : rl_median, + 'interval_stop_max' : interval_stop_max + } + return(ret) + + + + +def do_img_traffic(traffic_data, fname): + + + if traffic_data['traffic_count'] > 0 : + + output = traffic_data['traffic_buf'] + + + fontP = FontProperties() + fontP.set_size('small') + + fig = plt.figure(1) + + ax1= plt.subplot(311) + plt.plot(output['interval_stop'], output['bandwidth'], color='b' ) + ax1.set_title('Bandwidth (Mbits/s)') + ax1.set_ylim(ymin=-1) + ax1.set_xlim(xmax=np.amax(output['interval_stop'])) + text='min: '+str(traffic_data['bw_min'])+'\nmax: '+str(traffic_data['bw_max'])+'\nmean: '+str(traffic_data['bw_mean'])+'\nmedian: '+str(traffic_data['bw_median']) + ax1.text( np.amax(output['interval_stop'])+10,0,text) + + + ax2=plt.subplot(312) + plt.plot(output['interval_stop'], output['jitter'], color='b' ) + ax2.set_title('Jitter (ms)') + ax2.set_xlim(xmax=np.amax(output['interval_stop'])) + ax2.set_ylim(ymin=-1) + text='min: '+str(traffic_data['jitter_min'])+'\nmax: '+str(traffic_data['jitter_max'])+'\nmean: '+str(traffic_data['jitter_mean'])+'\nmedian: '+str(traffic_data['jitter_median']) + ax2.text( np.amax(output['interval_stop'])+10,0,text) + + ax3=plt.subplot(313) + plt.plot(output['interval_stop'], output['rate_lost'], color='b') + ax3.set_title('Loss rate %') + ax3.set_xlim(xmax=np.amax(output['interval_stop'])) + ax3.set_ylim(ymin=-1) + text='min: '+str(traffic_data['rl_min'])+'\nmax: '+str(traffic_data['rl_max'])+'\nmean: '+str(traffic_data['rl_mean'])+'\nmedian: '+str(traffic_data['rl_median']) + ax3.text( np.amax(output['interval_stop'])+10,0,text) + + +# plt.title('Physical throughput ('+metric_def['unit_of_meas']+')') + plt.xlabel('time (s)') +# plt.ylabel(metric_def['id']) + + # Set graphic minimum Y axis + # ------------------------- +# if traffic_data['bw_min'] == 0 : +# plt.ylim(ymin=-metric_def['min_limit']/10) +# else : +# plt.ylim(ymin=0) + +# y_axis_max = 0 +# if traffic_data['metric_max'] > metric_def['min_limit']: +# y_axis_max =traffic_data['metric_max']+traffic_data['metric_max']/10 +# else: +# y_axis_max =metric_def['min_limit']+metric_def['min_limit']/10 +# +# plt.ylim(ymax=y_axis_max) + + plt.tight_layout() + + lgd = plt.legend(prop=fontP, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) + mng = plt.get_current_fig_manager() + plt.savefig(fname, bbox_inches='tight') + plt.close() + + + + +def create_report_html(context): + fname = context['report_path']+"/index.html" + + # + with open(fname, 'w') as f: + html = render_template('index.html', context) + f.write(html) + + +def create_test_report_detailed_html(context, fname ): + with open(fname, 'w') as f: + html = render_template('testcase_report.html', context) + f.write(html) + + +def check_cell_synchro(fname): + + with open(fname, 'r') as f: + for line in f: + + m = re.search('AUTOTEST Cell Sync \:', line) + if m : + print line + return 'CELL_SYNCH' + + return 'CELL_NOT_SYNCH' + + +def check_exec_seg_fault(fname): + + with open(fname, 'r') as f: + for line in f: + m = re.search('Segmentation fault', line) + if m : + print line + return 'SEG_FAULT' + + return 'NO_SEG_FAULT' + diff --git a/cmake_targets/autotests/patches/3gpplte_turbo_decoder_sse_8bit.patch b/cmake_targets/autotests/patches/3gpplte_turbo_decoder_sse_8bit.patch new file mode 100644 index 0000000000..957778f332 --- /dev/null +++ b/cmake_targets/autotests/patches/3gpplte_turbo_decoder_sse_8bit.patch @@ -0,0 +1,25 @@ +diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +index d2c7ac6..0853373 100644 +--- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c ++++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +@@ -493,7 +493,7 @@ void compute_beta8(llr_t* alpha,llr_t* beta,llr_t *m_11,llr_t* m_10,unsigned sho + + #endif + +- if (frame_length > 6143) { ++ if (frame_length > 6144) { + LOG_E(PHY,"compute_beta: frame_length %d\n",frame_length); + return; + } +@@ -979,6 +979,11 @@ unsigned char phy_threegpplte_turbo_decoder8(short *y, + } else + n2 = n; + ++ if(n2<256) ++ { ++ printf("phy_threegpplte_turbo_decoder8 : frame length < 256\n"); ++ return 255; ++ } + + for (iind=0; iind < 188 && f1f2mat[iind].nb_bits != n; iind++); + diff --git a/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch b/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch new file mode 100644 index 0000000000..8c80d55871 --- /dev/null +++ b/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch @@ -0,0 +1,18 @@ +diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c +index 71372d9..763397b 100644 +--- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c ++++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c +@@ -477,6 +477,13 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) + //#endif + + if (ue->UE_scan_carrier == 0) { ++ ++ /* SYRTEM */ ++ printf("AUTOTEST Cell Sync : frame = %d, rx_offset %d, freq_offset %d \n", ++ ue->proc.proc_rxtx[0].frame_rx, ++ ue->rx_offset, ++ ue->common_vars.freq_offset ); ++ + if (ue->mac_enabled==1) { + LOG_I(PHY,"[UE%d] Sending synch status to higher layers\n",ue->Mod_id); + //mac_resynch(); diff --git a/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch b/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch new file mode 100644 index 0000000000..e8213960e1 --- /dev/null +++ b/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch @@ -0,0 +1,19 @@ +diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c +index 3ed4c79..da88000 100644 +--- a/openair1/SCHED/phy_procedures_lte_ue.c ++++ b/openair1/SCHED/phy_procedures_lte_ue.c +@@ -2944,6 +2944,14 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin + LOG_D(PHY,"[UE %d] Calculating bitrate Frame %d: total_TBS = %d, total_TBS_last = %d, bitrate %f kbits\n", + ue->Mod_id,frame_rx,ue->total_TBS[eNB_id], + ue->total_TBS_last[eNB_id],(float) ue->bitrate[eNB_id]/1000.0); ++ ++ /* SYRTEM */ ++ if ((frame_rx % 100 == 0)) { ++ printf("AUTOTEST Metric : UE_DLSCH_BITRATE = %5.2f kbps (frame = %d) \n", (float) ue->bitrate[eNB_id]/1000.0, frame_rx); ++ /* End of SYRTEM */ ++ } ++ ++ + } + + diff --git a/cmake_targets/autotests/patches/phy_test__target_dl_mcs.patch b/cmake_targets/autotests/patches/phy_test__target_dl_mcs.patch new file mode 100644 index 0000000000..ec8c43cb72 --- /dev/null +++ b/cmake_targets/autotests/patches/phy_test__target_dl_mcs.patch @@ -0,0 +1,17 @@ + +diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c +index 96645f8..a7f1dfb 100644 +--- a/targets/RT/USER/lte-softmodem.c ++++ b/targets/RT/USER/lte-softmodem.c +@@ -1602,6 +1602,11 @@ int main( int argc, char **argv ) + PHY_vars_eNB_g[0][CC_id] = init_lte_eNB(frame_parms[CC_id],0,frame_parms[CC_id]->Nid_cell,abstraction_flag); + PHY_vars_eNB_g[0][CC_id]->CC_id = CC_id; + ++ PHY_vars_eNB_g[0][CC_id]->ue_dl_rb_alloc=0x1fff; ++ PHY_vars_eNB_g[0][CC_id]->target_ue_dl_mcs=target_dl_mcs; ++ PHY_vars_eNB_g[0][CC_id]->ue_ul_nb_rb=6; ++ PHY_vars_eNB_g[0][CC_id]->target_ue_ul_mcs=target_ul_mcs; ++ + if (phy_test==1) PHY_vars_eNB_g[0][CC_id]->mac_enabled = 0; + else PHY_vars_eNB_g[0][CC_id]->mac_enabled = 1; + diff --git a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py index 1dfd67b682..796235a77f 100755 --- a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py +++ b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py @@ -37,6 +37,8 @@ import math #from time import clock import xml.etree.ElementTree as ET import re +from colorama import Fore, Back, Style + import numpy as np import log @@ -167,7 +169,7 @@ def sftp_module (username, password, hostname, ports, paramList,logfile): #paramiko logfile path should not be changed with multiple calls. The logs seem to in first file regardless error = "" #The lines below are outside exception loop to be sure to terminate the test case if the network connectivity goes down or there is authentication failure - transport = paramiko.Transport(hostname, ports) + transport = paramiko.Transport((hostname, ports)) transport.connect(username = username, password = password) sftp = paramiko.SFTPClient.from_transport(transport) # index =0 @@ -1042,6 +1044,609 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , write_file(xmlFile, xml, mode="w") + + +# \brief handler for executing test cases (lte-softmodem-noS1) +# \param testcase name of testcase +# \param oldprogramList list of programs which must be terminated before running a test case +# \param logdirOAI5GRepo directory on remote machine which has openairinterface5g repo installed +# \param logdirOpenaircnRepo directory on remote machine which has openair-cn repo installed +# \param MachineList list of all machines on which test cases can be run +# \param user username with which to login +# \param password password with which to login +# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) +# \param ExmimoRfStop command to stop EXMIMO Card +# \param nruns_lte-softmodem global parameter to override number of runs (nruns) within the test case +def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRepo , logdirOpenaircnRepo, MachineList, user, password, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, timeout_cmd): + #We ignore the password sent to this function for secuirity reasons for password present in log files + #It is recommended to add a line in /etc/sudoers that looks something like below. The line below will run sudo without password prompt + # your_user_name ALL=(ALL:ALL) NOPASSWD: ALL + + indent="\t" + threads=[] + + # + # Test case parameters + # ----------------------------------------------------------------------------- + testcase_verdict = 'PASS' + testcase_time_start = datetime.datetime.now() + testcase_name = testcase.get('id') + testcase_class = testcase.findtext('class',default='') + testcase_desc = testcase.findtext('desc',default='') + if timeout_cmd == '': + timeout_cmd = testcase.findtext('TimeOut_cmd',default='') + timeout_cmd = int(float(timeout_cmd)) + timeout_thread = timeout_cmd + 60 #Timeout_thread is more than that of cmd to have room for compilation time, etc + if nruns_lte_softmodem == '': + nruns = testcase.findtext('nruns',default='') + else: + nruns = nruns_lte_softmodem + nruns = int(float(nruns)) + tags = testcase.findtext('tags',default='') + + max_ntries = testcase.findtext('max_ntries',default='') + if max_ntries : + max_ntries = int(float(max_ntries)) + else : + max_ntries = nruns + + print( indent + "> testcase time start : " + str(testcase_time_start) ) + print( indent + "> testcase class : " + testcase_class ) + print( indent + "> testcase description : " + testcase_desc ) + print( indent + "> testcase timeout : " + str(timeout_cmd) ) + print( indent + "> testcase thread timeout : " + str(timeout_thread) ) + print( indent + "> number of runs : " + str(nruns) ) + print( indent + "> number of max tries : " + str(max_ntries) ) + print( indent + "> testcase tags : " + tags ) + + logdir_local_testcase = openairdir_local + '/cmake_targets/autotests/log/'+ testcasename + logdir_eNB_testcase = logdirOAI5GRepo +'/cmake_targets/autotests/log/'+ testcasename + logdir_UE_testcase = logdirOAI5GRepo +'/cmake_targets/autotests/log/'+ testcasename + + # + # Local checks for test cases + # ----------------------------------------------- + + # Logging directory + if (not os.path.exists(logdir_local_testcase)): + os.system('mkdir -p ' + logdir_local_testcase) + + # + # REMOTE MACHINE COMPILATION + # ------------------------------------------------ + + eNBMachine = testcase.findtext('eNB',default='') + eNB_config_file = testcase.findtext('eNB_config_file',default='') + eNB_compile_prog = testcase.findtext('eNB_compile_prog',default='') + eNB_compile_prog_args = testcase.findtext('eNB_compile_prog_args',default='') + + logfile_compile_eNB = logdir_eNB_testcase + '/eNB_compile.log' + logfile_task_eNB_compile_out = logdir_eNB_testcase + '/eNB_task_compile_out.log' + logfile_task_eNB_compile = logdir_local_testcase + '/eNB_task_compile.log' + + # Check that machine is in test setup machine list + print( Fore.WHITE + indent + "> testcase eNB machine :"), + if (eNBMachine not in MachineList): + print( Fore.RED + eNBMachine + " not in test setup machine list") + testcase_verdict = 'INCON' + else : + print eNBMachine, + # get machine description + eNBMachineDesc = MachineDescDic[eNBMachine] + index_eNBMachine = MachineList.index(eNBMachine) + # check that openairinterface is installed on machine + oai_eNB = openair('localdomain', eNBMachine) + oai_eNB.connect(user, password) + cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep --color=never OPENAIR' + res= oai_eNB.send_recv(cmd) + m = re.search('OPENAIR_HOME', res, re.DOTALL) + if m: + print + # Create testcase directory on remote eNB + cmd = 'rm -fr ' + logdir_eNB_testcase + ' ; mkdir -p ' + logdir_eNB_testcase + result = oai_eNB.send_recv(cmd) + + # Check if we need to compile lte-softmodem-noS1 on remote machine + eNB_compile_cmd = eNB_compile_prog + ' '+ eNB_compile_prog_args + if ('last_compile_prog' in eNBMachineDesc) and eNBMachineDesc['last_compile_prog'] == eNB_compile_cmd: + print( Fore.WHITE + indent + "> eNB machine compilation : skipped -> "+eNB_compile_cmd ) + else: + print( Fore.WHITE + indent + "> eNB machine compilation : triggered -> "+eNB_compile_cmd ) + eNBMachineDesc['last_compile_prog'] = eNB_compile_prog + ' '+ eNB_compile_prog_args # if last compilation is the same do not compile again + task_eNB_compile = ' ( uname -a ; date \n' + task_eNB_compile = task_eNB_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_eNB_compile = task_eNB_compile + 'env |grep OPENAIR \n' + task_eNB_compile = task_eNB_compile + update_config_file(oai_eNB, eNB_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' + if eNB_compile_cmd != "": + task_eNB_compile = task_eNB_compile + ' ( ' + eNB_compile_cmd + ' ) > ' + logfile_compile_eNB + ' 2>&1 \n' + task_eNB_compile = task_eNB_compile + ' date ) > ' + logfile_task_eNB_compile_out + ' 2>&1 ' + write_file(logfile_task_eNB_compile, task_eNB_compile, mode="w") + + + thread_eNB = oaiThread(1, "eNB_thread_compile", eNBMachine, user, password , task_eNB_compile, False, timeout_thread) + threads.append(thread_eNB) + thread_eNB.start() + + else: + print( Fore.RED + " -> OAI5G not properly setup ! please check REMOTE MACHINE PREPARATION step") + testcase_verdict = 'INCON' + + + UEMachine = testcase.findtext('UE',default='') + UE_config_file = testcase.findtext('UE_config_file',default='') + UE_compile_prog = testcase.findtext('UE_compile_prog',default='') + UE_compile_prog_args = testcase.findtext('UE_compile_prog_args',default='') + + logfile_compile_UE = logdir_UE_testcase + '/UE_compile.log' + logfile_task_UE_compile_out = logdir_UE_testcase + '/UE_task_compile_out.log' + logfile_task_UE_compile = logdir_local_testcase + '/UE_task_compile.log' + + # Check that machine is in test setup machine list + print( Fore.WHITE + indent + "> testcase UE machine :"), + if (UEMachine not in MachineList): + print( Fore.RED + UEMachine + " not in test setup machine list") + testcase_verdict = 'INCON' + else : + print UEMachine, + # get machine description + UEMachineDesc = MachineDescDic[UEMachine] + index_UEMachine = MachineList.index(UEMachine) + # check that openairinterface is installed on machine + oai_UE = openair('localdomain', UEMachine) + oai_UE.connect(user, password) + cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep --color=never OPENAIR' + res= oai_UE.send_recv(cmd) + m = re.search('OPENAIR_HOME', res, re.DOTALL) + if m: + print + # Create testcase directory on remote UE + cmd = 'rm -fr ' + logdir_UE_testcase + ' ; mkdir -p ' + logdir_UE_testcase + result = oai_UE.send_recv(cmd) + + # Check if we need to compile lte-softmodem-noS1 on remote machine + UE_compile_cmd = UE_compile_prog + ' '+ UE_compile_prog_args + if ('last_compile_prog' in UEMachineDesc) and UEMachineDesc['last_compile_prog'] == UE_compile_cmd: + print( Fore.WHITE + indent + "> UE machine compilation : skipped -> "+UE_compile_cmd ) + else: + print( Fore.WHITE + indent + "> UE machine compilation : triggered -> "+UE_compile_cmd ) + UEMachineDesc['last_compile_prog'] = UE_compile_prog + ' '+ UE_compile_prog_args + task_UE_compile = ' ( uname -a ; date \n' + task_UE_compile = task_UE_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_UE_compile = task_UE_compile + 'env |grep OPENAIR \n' + task_UE_compile = task_UE_compile + update_config_file(oai_UE, UE_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' + if UE_compile_cmd != "": + task_UE_compile = task_UE_compile + ' ( ' + UE_compile_cmd + ' ) > ' + logfile_compile_UE + ' 2>&1 \n' + task_UE_compile = task_UE_compile + ' date ) > ' + logfile_task_UE_compile_out + ' 2>&1 ' + write_file(logfile_task_UE_compile, task_UE_compile, mode="w") + + thread_UE = oaiThread(2, "UE_thread_compile", UEMachine, user, password , task_UE_compile, False, timeout_thread) + threads.append(thread_UE) + thread_UE.start() + + else: + print( Fore.RED + " -> OAI5G not properly setup ! please check REMOTE MACHINE PREPARATION step") + testcase_verdict = 'INCON' + + + + + + + # Wait for Compilation thread to terminate + #----------------------------------------- + for t in threads: + t.join() + + # TODO check that compilation is succeed + + #first we compile all the programs +# thread_UE = oaiThread(3, "UE_thread", UEMachine, user, password , task_UE_compile, False, timeout_thread) +# threads.append(thread_UE) +# thread_UE.start() + + + + + +# index_UEMachine = MachineList.index(UEMachine) +# oai_UE = openair('localdomain', UEMachine) +# oai_UE.connect(user, password) +# res = oai_UE.send_recv(cmd) +# res = oai_eNB.send_recv(cmd) + + + + # + # RUN LOOP + # ------------------------------------------------ + if testcase_verdict != 'PASS': # if something went wrong to not run test cases + max_ntries=0 + + runs_results = [] + nb_runs = 0 + nb_run_pass = 0 + nb_run_failed = 0 + nb_run_inc = 0 + nb_run_skip = 0 + + nb_seg_fault = 0 + + for run in range(0,max_ntries): + + if nruns == nb_run_pass + nb_run_failed: + break + + nb_runs += 1 + + # + # RUN initialization + # ---------------------------------------------------- + print (Fore.WHITE + indent + "> RUN_"+str(run).zfill(2)+" : " ), + + sys.stdout.flush() + + run_start_time=datetime.datetime.now() + + logdir_local_run = openairdir_local + '/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) + logdir_eNB_run = logdirOAI5GRepo +'/cmake_targets/autotests/log/' + testcasename + '/run_' + str(run) + logdir_UE_run = logdirOAI5GRepo +'/cmake_targets/autotests/log/' + testcasename + '/run_' + str(run) + + cmd = 'rm -fr ' + logdir_eNB_run + ' ; mkdir -p ' + logdir_eNB_run + result = oai_eNB.send_recv(cmd) + cmd = 'rm -fr ' + logdir_UE_run + ' ; mkdir -p ' + logdir_UE_run + result = oai_UE.send_recv(cmd) + cmd = ' rm -fr ' + logdir_local_run + ' ; mkdir -p ' + logdir_local_run + result = os.system(cmd) + + + # + # RUN parametrization + # ---------------------------------------------------- + eNB_pre_exec = testcase.findtext('eNB_pre_exec',default='') + eNB_pre_exec_args = testcase.findtext('eNB_pre_exec_args',default='') + eNB_main_exec = testcase.findtext('eNB_main_exec',default='') + eNB_main_exec_args = testcase.findtext('eNB_main_exec_args',default='') + eNB_traffic_exec = testcase.findtext('eNB_traffic_exec',default='') + eNB_traffic_exec_args = testcase.findtext('eNB_traffic_exec_args',default='') + eNB_terminate_missing_procs = testcase.findtext('eNB_terminate_missing_procs',default='True') + + logfile_exec_eNB = logdir_eNB_run + '/eNB_exec' + '_' + str(run) + '_.log' + logfile_pre_exec_eNB = logdir_eNB_run + '/eNB_pre_exec' + '_' + str(run) + '_.log' + logfile_task_eNB_out = logdir_eNB_run + '/eNB_task_out' + '_' + str(run) + '_.log' + logfile_traffic_eNB = logdir_eNB_run + '/eNB_traffic' + '_' + str(run) + '_.log' + logfile_task_eNB = logdir_local_run + '/eNB_task' + '_' + str(run) + '_.log' + + task_eNB = ' ( uname -a ; date \n' + task_eNB = task_eNB + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_eNB = task_eNB + 'env |grep OPENAIR \n' + 'array_exec_pid=() \n' + if eNB_pre_exec != "": + task_eNB = task_eNB + ' ( date; ' + eNB_pre_exec + ' '+ eNB_pre_exec_args + ' ) > ' + logfile_pre_exec_eNB + ' 2>&1 \n' + if eNB_main_exec != "": + task_eNB = task_eNB + ' ( date; ' + addsudo(eNB_main_exec + ' ' + eNB_main_exec_args, '') + ' ) > ' + logfile_exec_eNB + ' 2>&1 & \n' + task_eNB = task_eNB + 'array_exec_pid+=($!) \n' + task_eNB = task_eNB + 'echo eNB_main_exec PID = $! \n' + if eNB_traffic_exec != "": + cmd_traffic = eNB_traffic_exec + ' ' + eNB_traffic_exec_args + if cmd_traffic.find('-c') >= 0: + cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 80) + task_eNB = task_eNB + ' (date; ' + cmd_traffic + ' ) > ' + logfile_traffic_eNB + ' 2>&1 & \n' + task_eNB = task_eNB + 'array_exec_pid+=($!) \n' + task_eNB = task_eNB + 'echo eNB_traffic_exec PID = $! \n' + #terminate the eNB test case after timeout_cmd seconds + task_eNB = task_eNB + finalize_deploy_script (timeout_cmd, eNB_terminate_missing_procs) + ' \n' + #task_eNB = task_eNB + 'sleep ' + str(timeout_cmd) + ' \n' + task_eNB = task_eNB + 'handle_ctrl_c' + '\n' + task_eNB = task_eNB + ' ) > ' + logfile_task_eNB_out + ' 2>&1 ' + write_file(logfile_task_eNB, task_eNB, mode="w") + + + UE_pre_exec = testcase.findtext('UE_pre_exec',default='') + UE_pre_exec_args = testcase.findtext('UE_pre_exec_args',default='') + UE_main_exec = testcase.findtext('UE_main_exec',default='') + UE_main_exec_args = testcase.findtext('UE_main_exec_args',default='') + UE_traffic_exec = testcase.findtext('UE_traffic_exec',default='') + UE_traffic_exec_args = testcase.findtext('UE_traffic_exec_args',default='') + UE_terminate_missing_procs = testcase.findtext('UE_terminate_missing_procs',default='True') + UE_search_expr_true = testcase.findtext('UE_search_expr_true','') + + logfile_exec_UE = logdir_UE_run + '/UE_exec' + '_' + str(run) + '_.log' + logfile_pre_exec_UE = logdir_UE_run + '/UE_pre_exec' + '_' + str(run) + '_.log' + logfile_task_UE_out = logdir_UE_run + '/UE_task_out' + '_' + str(run) + '_.log' + logfile_traffic_UE = logdir_UE_run + '/UE_traffic' + '_' + str(run) + '_.log' + logfile_task_UE = logdir_local_run + '/UE_task' + '_' + str(run) + '_.log' + + + task_UE = ' ( uname -a ; date \n' + task_UE = task_UE + 'array_exec_pid=()' + '\n' + task_UE = task_UE + 'cd ' + logdirOAI5GRepo + '\n' + task_UE = task_UE + 'source oaienv \n' + task_UE = task_UE + 'source cmake_targets/tools/build_helper \n' + task_UE = task_UE + 'env |grep OPENAIR \n' + if UE_pre_exec != "": + task_UE = task_UE + ' ( date; ' + UE_pre_exec + ' '+ UE_pre_exec_args + ' ) > ' + logfile_pre_exec_UE + ' 2>&1 \n' + if UE_main_exec != "": + task_UE = task_UE + ' ( date; ' + addsudo(UE_main_exec + ' ' + UE_main_exec_args, '') + ' ) > ' + logfile_exec_UE + ' 2>&1 & \n' + task_UE = task_UE + 'array_exec_pid+=($!) \n' + task_UE = task_UE + 'echo UE_main_exec PID = $! \n' + if UE_traffic_exec != "": + cmd_traffic = UE_traffic_exec + ' ' + UE_traffic_exec_args + if cmd_traffic.find('-c') >= 0: + cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 60) + task_UE = task_UE + ' ( date; ' + cmd_traffic + ' ) >' + logfile_traffic_UE + ' 2>&1 & \n' + task_UE = task_UE + 'array_exec_pid+=($!) \n' + task_UE = task_UE + 'echo UE_traffic_exec PID = $! \n' + #terminate the UE test case after timeout_cmd seconds + task_UE = task_UE + finalize_deploy_script (timeout_cmd, UE_terminate_missing_procs) + ' \n' + #task_UE = task_UE + 'sleep ' + str(timeout_cmd) + ' \n' + task_UE = task_UE + 'handle_ctrl_c' + '\n' + task_UE = task_UE + ' ) > ' + logfile_task_UE_out + ' 2>&1 ' + write_file(logfile_task_UE, task_UE, mode="w") + #task_UE = 'echo \" ' + task_UE + '\" > ' + logfile_script_UE + ' 2>&1 ; ' + task_UE + + + + + + + + # + # RUN work + # ---------------------------------------------------- + thread_eNB = oaiThread(1, "eNB_thread", eNBMachine, user, password , task_eNB, False, timeout_thread) + thread_UE = oaiThread(2, "UE_thread", UEMachine, user, password , task_UE, False, timeout_thread) + threads=[] + threads.append(thread_eNB) + threads.append(thread_UE) + thread_eNB.start() + thread_UE.start() + for t in threads: + t.join() + + # + # + #----------------------------------------------------- + cleanOldProgramsAllMachines([oai_eNB, oai_UE] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB_run, logdir_UE_run], logdirOAI5GRepo) + + SSHSessionWrapper(eNBMachine, user, None, password, logdir_eNB_run, logdir_local_testcase, "get_all") + #print "Copying files from UEMachine : " + UEMachine + "logdir_UE = " + logdir_UE + SSHSessionWrapper(UEMachine, user, None, password, logdir_UE_run, logdir_local_testcase, "get_all") + + metric_checks_flag = 1 + + fname = logdir_local_run+ '/UE_exec' + '_' + str(run) + '_.log' + cell_synch_status = analyser.check_cell_synchro(fname) + if cell_synch_status == 'CELL_SYNCH': + print '!!!!!!!!!!!!!! Cell synchronized !!!!!!!!!!!' + else : + print '!!!!!!!!!!!!!! Cell NOT NOT synchronized !!!!!!!!!!!' + metric_checks_flag = 0 + + ue_seg_fault_status = analyser.check_exec_seg_fault(fname) + if ue_seg_fault_status == 'SEG_FAULT' : + nb_seg_fault += 1 + + # + # Check metrics + #---------------------------------------------------- + runs_metrics = [] + run_traffic = [] + + if metric_checks_flag : + verdict = 'PASS' + + # UE side metrics + metricList=testcase.findall('UE_metric') + for metric in metricList: + metric_def = {} + metric_def['id'] = metric.get('id') + metric_def['description'] = metric.get('description') + metric_def['regex'] = metric.get('regex') + metric_def['unit_of_meas'] = metric.get('unit_of_meas') + metric_def['pass_fail_stat']= metric.get('pass_fail_stat') + metric_min_lim = metric.get('min_limit') + if metric_min_lim: + metric_def['min_limit'] = float(metric_min_lim) + metric_max_lim = metric.get('max_limit') + if metric_max_lim: + metric_def['max_limit'] = float(metric_max_lim) + + fname = logdir_local_run+ '/UE_exec' + '_' + str(run) + '_.log' + + args = {'metric' : metric_def, + 'file' : fname } + + metric_extracted = analyser.do_extract_metrics(args) + + print "\t > Metric "+metric_def['id']+" :" + print "\t\t> min = "+ str( metric_extracted['metric_min'] ) + print "\t\t> min_index = "+ str( metric_extracted['metric_min_index'] ) + print "\t\t> max = "+ str( metric_extracted['metric_max'] ) + print "\t\t> max_index = "+ str( metric_extracted['metric_max_index'] ) + print "\t\t> mean = "+ str( metric_extracted['metric_mean'] ) + print "\t\t> median = "+ str( metric_extracted['metric_median'] ) + + verdict = analyser.do_check_verdict(metric_def, metric_extracted) + + metric_fig = logdir_local_run+ '/UE_metric_'+ metric_def['id']+'_' + str(run) + '_.png' + analyser.do_img_metrics(metric_def, metric_extracted, metric_fig) + + + metric_fig_report = '../log/'+ testcasename + '/run_' + str(run) + '/UE_metric_'+ metric_def['id']+'_' + str(run) + '_.png' + + run_metrics = dict( metric_id = metric_def['id'], + metric_desc = metric_def['description'], + metric_uom = metric_def['unit_of_meas'], + metric_min = metric_extracted['metric_min'], + metric_min_index= metric_extracted['metric_min_index'], + metric_max = metric_extracted['metric_max'], + metric_max_index= metric_extracted['metric_max_index'], + metric_mean = metric_extracted['metric_mean'], + metric_median = metric_extracted['metric_median'], + metric_fig = metric_fig_report) + + if metric_def['pass_fail_stat'] : + run_metrics['pass_fail_stat'] = metric_def['pass_fail_stat'] + if metric_min_lim : + run_metrics['pass_fail_min_limit'] = metric_def['min_limit'] + if metric_max_lim : + run_metrics['pass_fail_max_limit'] = metric_def['max_limit'] + + runs_metrics.append(run_metrics) + + # Traffic analysis + if UE_traffic_exec != "": + + fname = logdir_local_run+ '/UE_traffic' + '_' + str(run) + '_.log' + args = {'file' : fname } + traffic_metrics = analyser.do_extract_traffic_metrics(args) + traffic_fig = logdir_local_run+ '/UE_traffic'+'_' + str(run) + '_.png' + analyser.do_img_traffic(traffic_metrics, traffic_fig) + + traffic_fig_report= '../log/'+ testcasename + '/run_' + str(run) + '/UE_traffic'+'_' + str(run) + '_.png' + + dur_pass_fail_crit = 'none' + if traffic_metrics['traffic_count'] == 0 : + verdict = 'FAIL' + elif UE_search_expr_true != "": + traffic_duration_limit = float(UE_search_expr_true) + dur_pass_fail_crit = str(traffic_duration_limit) + # print 'traffic_duration_limit = '+str(traffic_duration_limit) + # print 'traffic_metrics[interval_stop_max] = '+str(traffic_metrics['interval_stop_max']) + if traffic_metrics['interval_stop_max'] < traffic_duration_limit : + verdict = 'FAIL' + + + run_traffic = dict( traffic_count = traffic_metrics['traffic_count'], + bw_min = traffic_metrics['bw_min'], + bw_max = traffic_metrics['bw_max'], + bw_mean = traffic_metrics['bw_mean'], + bw_median = traffic_metrics['bw_median'], + jitter_min = traffic_metrics['jitter_min'], + jitter_max = traffic_metrics['jitter_max'], + jitter_mean = traffic_metrics['jitter_mean'], + jitter_median = traffic_metrics['jitter_median'], + rl_min = traffic_metrics['rl_min'], + rl_max = traffic_metrics['rl_max'], + rl_mean = traffic_metrics['rl_mean'], + rl_median = traffic_metrics['rl_median'], + iperf_duration = traffic_metrics['interval_stop_max'], + dur_pass_fail_crit = dur_pass_fail_crit, + traffic_fig = traffic_fig_report ) + else: + run_traffic = dict( traffic_count = 0) + + else : + verdict = 'SKIP' + + + + # + # RUN verdict and finalization + # ---------------------------------------------------- + run_stop_time=datetime.datetime.now() + run_duration = run_stop_time-run_start_time +# print (Fore.WHITE + ("duration=" :"), + print (Fore.WHITE + indent + "> RUN duration : "+ str(run_duration) +"s" ) + + print (Fore.WHITE + indent + "> RUN verdict :"), + + if verdict == 'PASS': + nb_run_pass += 1 + print ( Fore.GREEN + verdict) + elif verdict == 'FAIL': + nb_run_failed += 1 + testcase_verdict = 'FAIL' + print ( Fore.RED + verdict) + elif verdict == 'SKIP': + nb_run_skip += 1 + print ( Fore.YELLOW + verdict) + else: + nb_run_inc += 1 + if testcase_verdict == 'PASS' : testcase_verdict = 'INCON' + print (Fore.YELLOW+'INCONCLUSIVE') + + run_results = dict( run_id=str(run), + run_start_time = run_start_time, + run_stop_time = run_stop_time , + run_verdict = verdict, + ue_seg_fault_status = ue_seg_fault_status, + run_duration = run_duration, + runs_metrics = runs_metrics, + run_traffic = run_traffic) + runs_results.append(run_results) + + # END RUN LOOP + #---------------------------------------------------- + + # Test case duration + # ---------------------------------- + testcase_time_stop = datetime.datetime.now() + print(Fore.WHITE + indent + "> testcase time stop : " + str(testcase_time_start) ), + print " -> TestCase duration = "+str(testcase_time_stop - testcase_time_start) + + # Save remote log files + # ----------------------------------- + #Now we change the permissions of the logfiles to avoid some of them being with root permissions + cmd = 'sudo -E chown -R ' + user + ' ' + logdir_eNB_testcase + res= oai_eNB.send_recv(cmd) + cmd = 'sudo -E chown -R ' + user + ' ' + logdir_UE_testcase + res= oai_UE.send_recv(cmd) + + # Save remote log files on MTC + #print "Copying files from eNBMachine " + eNBMachine + "logdir_eNB = " + logdir_eNB + SSHSessionWrapper(eNBMachine, user, None, password, logdir_eNB_testcase, openairdir_local + '/cmake_targets/autotests/log/', "get_all") + #print "Copying files from UEMachine : " + UEMachine + "logdir_UE = " + logdir_UE + SSHSessionWrapper(UEMachine, user, None, password, logdir_UE_testcase, openairdir_local + '/cmake_targets/autotests/log/', "get_all") + + oai_eNB.disconnect() + oai_UE.disconnect() + + # Set test case final verdict + # ----------------------------------- + test_result_string = 'do be completed' + + if testcase_verdict == 'PASS': + if nb_run_pass == 0 : + testcase_verdict = 'INCON' + + print(Fore.WHITE + indent + "> testcase final verdict :"), + if testcase_verdict == 'PASS': + print ( Fore.GREEN + testcase_verdict) + elif testcase_verdict == 'FAIL': + print ( Fore.RED + testcase_verdict) + else: + print (Fore.YELLOW+'INCONCLUSIVE') + + duration= testcase_time_stop - testcase_time_start + xmlFile = logdir_local_testcase + '/test.' + testcasename + '.xml' + xml="\n \n" + write_file(xmlFile, xml, mode="w") + + + test_result = dict(testcase_name=testcasename, + testcaseclass=testcaseclass, + testcase_verdict = testcase_verdict, + testcase_time_start=testcase_time_start, + testcase_time_stop=testcase_time_stop, + tags=tags, + nruns=nb_runs, + nb_run_pass = nb_run_pass, + nb_run_skip = nb_run_skip, + nb_run_failed = nb_run_failed, + nb_run_inc=nb_run_inc, + nb_seg_fault = nb_seg_fault, + testcase_timeout=timeout_cmd, + testcase_duration = duration, + testcase_eNBMachine =eNBMachine, + testcase_UEMachine =UEMachine, + runs_results = runs_results) + #test_results.append(test_result) + + return testcase_verdict + + + + # \brief This function searches if test case is present in list of test cases that need to be executed by user # \param testcasename the test case to search for # \param testcasegroup list that is passed from the arguments @@ -1149,12 +1754,14 @@ if openairdir_local is None: locallogdir = openairdir_local + '/cmake_targets/autotests/log' MachineList = '' MachineListGeneric='' +MachineDescDic={} flag_remove_logdir=False flag_start_testcase=False nruns_lte_softmodem='' flag_skip_git_head_check=False flag_skip_oai_install=False Timeout_cmd='' +xmlInputFile='' print "Number of arguments argc = " + str(len(sys.argv)) #for index in range(1,len(sys.argv) ): # print "argv_" + str(index) + " : " + sys.argv[index] @@ -1218,6 +1825,9 @@ while i < len (sys.argv): i = i +1 elif arg == '--skip-oai-install': flag_skip_oai_install=True + elif arg == '--test-suite' : + xmlInputFile = sys.argv[i+1] + i = i +1 elif arg == '-h' : print "-s: This flag *MUST* be set to start the test cases" print "-r: Remove the log directory in autotests" @@ -1235,6 +1845,7 @@ while i < len (sys.argv): print "--skip-git-head-check: skip checking of GitHead remote/local branch (only for debugging)" print "--timeout_cmd: Override the default parameter (timeout_cmd) in test_case_list.xml. This parameter is in seconds and should be > 120" print "--skip-oai-install: Skips the openairinterface5g installer" + print "--test-suite: Select a XML test-suite file" sys.exit() else : print "Unrecongnized Option: <" + arg + ">. Use -h to see valid options" @@ -1264,6 +1875,13 @@ cmd='ps aux |grep \"/usr/bin/ssh -q -l guptar\"| awk \'{print $2}\' | sudo xargs os.system(cmd) +try: + analyser = __import__("lib_autotest_analyser") +except ImportError as err: + print('Import error: ' + str(err)) + exit(0) + + if flag_start_testcase == False: print "You need to start the testcase by passing option -s. Use -h to see all options. Aborting now..." sys.exit(1) @@ -1286,12 +1904,14 @@ os.system(cmd) print "host = " + host print "user = " + user -xmlInputFile=os.environ.get('OPENAIR_DIR')+"/cmake_targets/autotests/test_case_list.xml" +if xmlInputFile == '': + xmlInputFile=os.environ.get('OPENAIR_DIR')+"/cmake_targets/autotests/test_case_list.xml" NFSResultsDir = '/mnt/sradio' cleanupOldProgramsScript = '$OPENAIR_DIR/cmake_targets/autotests/tools/remove_old_programs.bash' logdir = '/tmp/' + 'OAITestFrameWork-' + user + '/' logdirOAI5GRepo = logdir + 'openairinterface5g/' logdirOpenaircnRepo = logdir + 'openair-cn/' +patchdir = logdirOAI5GRepo + 'cmake_targets/autotests/patches/' if flag_remove_logdir == True: print "Removing directory: " + locallogdir @@ -1333,6 +1953,8 @@ ExmimoRfStop = xmlRoot.findtext('ExmimoRfStop',default='') if nruns_lte_softmodem == '': nruns_lte_softmodem = xmlRoot.findtext('nruns_lte-softmodem',default='') +OAI5GpatchFileList=xmlRoot.findall('OAI5GPatchFile') + print "MachineList = " + MachineList print "GitOpenair-cnRepo = " + GitOpenaircnRepo print "GitOAI5GRepo = " + GitOAI5GRepo @@ -1365,6 +1987,7 @@ MachineListGeneric = MachineListGeneric.split() #index=0 for machine in MachineList: oai_list.append( openair('localdomain',machine)) + MachineDescDic[machine]={} #index = index + 1 @@ -1475,6 +2098,7 @@ for oai in oai_list: cmd = cmd + 'git checkout ' + GitOpenaircnRepoBranch + '\n' cmd = cmd + 'env |grep OPENAIR' + '\n' cmd = cmd + ' cd ' + logdir + '\n' + cmd = cmd + 'mkdir -p ' + patchdir + '\n' cmd = cmd + ' ) > ' + setuplogfile + ' 2>&1 \n' #cmd = cmd + 'echo \' ' + cmd + '\' > ' + setup_script + ' 2>&1 \n ' #result = oai_list[index].send_recv(cmd, False, 300 ) @@ -1500,8 +2124,27 @@ for t in threads_init_setup: localfile = locallogdir + '/setup_log_' + MachineList[index] + '_.txt' remotefile = logdir + '/setup_log_' + MachineList[index] + '_.txt' port = 22 + + #Now we copy patch files and apply them + print "Installating patch files on machine " + MachineList[index] + for patchFile in OAI5GpatchFileList: + localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/patches/')+patchFile.get('name') + remotefile = logdirOAI5GRepo + '/cmake_targets/autotests/patches/'+patchFile.get('name') + if patchFile.get('machine') == MachineList[index] or patchFile.get('machine') == None: + if os.path.isfile(localfile): + print "\t> PATCH FILE :"+localfile + paramList=[] + paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) + sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) + cmd = ' cd ' + logdirOAI5GRepo + ' ;git apply cmake_targets/autotests/patches/'+patchFile.get('name') + res = oai_list[index].send_recv(cmd) paramList=[] + + setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' + setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' + localfile = locallogdir + '/setup_log_' + MachineList[index] + '_.txt' + remotefile = logdir + '/setup_log_' + MachineList[index] + '_.txt' sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') paramList.append ( {"operation":'get', "localfile":localfile, "remotefile":remotefile} ) #sftp_module (user, pw, MachineList[index], port, localfile, remotefile, sftp_log, "get") @@ -1574,6 +2217,23 @@ for testcase in testcaseList: SSHSessionWrapper('localhost', user, None, pw , NFSTestsResultsDir , locallogdir, "put_all") oai_localhost.disconnect() + elif testcaseclass == 'lte-softmodem-noS1' : + eNBMachine = testcase.findtext('eNB',default='') + UEMachine = testcase.findtext('UE',default='') + if (eNBMachine not in MachineList)|(UEMachine not in MachineList): + print "One of the machines is not in the machine list" + print "eNBMachine : " + eNBMachine + "UEMachine : " + UEMachine + "MachineList : " + ','.join(MachineList) + print "testcasename = " + testcasename + " class = " + testcaseclass + threadListGlobal = wait_testcaseclass_generic_threads(threadListGlobal, Timeout_execution) + + handle_testcaseclass_softmodem_noS1 (testcase, CleanUpOldProgs, logdirOAI5GRepo, logdirOpenaircnRepo, MachineList, user, pw, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, Timeout_cmd ) + + #The lines below are copied from below to trace the failure of some of the machines in test setup. These lines below need to be removed in long term + print "Creating xml file for overall results..." + cmd = "cat $OPENAIR_DIR/cmake_targets/autotests/log/*/*.xml > $OPENAIR_DIR/cmake_targets/autotests/log/results_autotests.xml " + res=os.system(cmd) + os.system('sync') + elif (testcaseclass == 'compilation'): threadListGlobal = handle_testcaseclass_generic (testcasename, threadListGlobal, CleanUpOldProgs, logdirOAI5GRepo, MachineListGeneric, user, pw, CleanUpAluLteBox,Timeout_execution, ExmimoRfStop) elif (testcaseclass == 'execution'): diff --git a/cmake_targets/autotests/run_lte-softmodem-nos1_tests.py b/cmake_targets/autotests/run_lte-softmodem-nos1_tests.py new file mode 100755 index 0000000000..19939f0d5c --- /dev/null +++ b/cmake_targets/autotests/run_lte-softmodem-nos1_tests.py @@ -0,0 +1,2785 @@ +#! /usr/bin/python +#****************************************************************************** + +# 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +# *******************************************************************************/ +# \author Rohit Gupta +# \version 0.1 +# @ingroup _test + + +#****************************************************************************** +# +# \file run_lte-softmodem-nos1_tests.py +# +# \par Informations +# - \b Project : UED Autotest Framework +# - \b Software : +# +# \date 16 september 2016 +# +# \version 0.1 +# +# \brief master test script to run test class 'handle_testcaseclass_softmodem_noS1' +# This script is largely inspired by 'run_exec_lte-softmodem_tests.py', and +# reused parts of it. +# +# \author Benoit ROBERT (benoit.robert@syrtem.com) +# +# \par Statement of Ownership +# COPYRIGHT (c) 2016 BY SYRTEM S.A.R.L +# This software is furnished under license and may be used and copied +# only in accordance with the terms of such license and with the inclusion +# of the above COPYRIGHT notice. This SOFTWARE or any other copies thereof +# may not be provided or otherwise made available to any other person. +# No title to and ownership of the SOFTWARE is hereby transferred. +# +# The information in this SOFTWARE is subject to change without notice +# and should not be constructed as a commitment by SYRTEM. +# SYRTEM assumes no responsibility for the use or reliability of its +# SOFTWARE on equipment or platform not explicitly validated by SYRTEM. +# +# ******************************************************************************* + +import tempfile +import threading +import sys +import traceback +import wave +import os +import time +import datetime +import getpass +import math #from time import clock +import xml.etree.ElementTree as ET +import re + +from colorama import Fore, Back, Style + +import numpy as np + +import log + +from openair import * + +import paramiko + +import subprocess +import commands +sys.path.append('/opt/ssh') +sys.path.append(os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/tools/')) + +from lib_autotest import * +import ssh +from ssh import SSHSession +import argparse + + +def exit_prog(exit_val): + print(Style.RESET_ALL), + sys.exit(exit_val) + +# \brief write a string to a file +# \param filename name of file +# \param string string to write +# \mode file opening mode (default=write) +def write_file(filename, string, mode="w"): + text_file = open(filename, mode) + text_file.write(string) + text_file.close() + +# \brief function to check if test case passed throughput test +# \param filename name of file which has throughput results (usually from iperf -s ... +# \param min_tput minimum throughput +# \param max_tuput maximum throughput +# \param average average throughput +# \param min_duration minimum duration of throughput +#The throughput values found in file must be higher than values from from arguments 2,3,4,5 +#The function returns True if throughput conditions are saisfied else it returns fails +def tput_test(filename, min_tput, max_tput, average, min_duration): + + if os.path.exists(filename): + with open (filename, "r") as myfile: + data=myfile.read() + p=re.compile('(\d*.\d*) Mbits/sec') + array=p.findall(data) + array = [ float(x) for x in array ] + duration = array.__len__() + if duration !=0: + min_list = min(array) + max_list = max(array) + average_list = np.mean(array) + else: + min_list = 0 + max_list = 0 + average_list=0 + tput_string=' ( '+ "min=%0.2f" % min_list + ' Mbps / ' + "max=%0.2f" % max_list + ' Mbps / ' + "avg=%0.2f" % average_list + ' Mbps / ' + "dur=%0.2f" % duration + ' s) ' + if (min_list >= min_tput and max_list >= max_tput and average_list >= average and duration >= min_duration): + return True , tput_string + else: + return False , tput_string + else: + return False , tput_string + +# \brief Convert string to float or return None if there is exception +def try_convert_to_float(string, fail=None): + try: + return float(string) + except Exception: + return fail; + +# \brief get throughput statistics from log file +# \param search_expr search expression found in test_case_list.xml file +# \param logfile_traffic logfile which has traffic statistics +def tput_test_search_expr (search_expr, logfile_traffic): + result=0 + tput_string='' + if search_expr !='': + if search_expr.find('throughput_test')!= -1 : + p= re.compile('min\s*=\s*(\d*.\d*)\s*Mbits/sec') + min_tput=p.findall(search_expr) + if min_tput.__len__()==1: + min_tput = min_tput[0] + else: + min_tput = None + + p= re.compile('max\s*=\s*(\d*.\d*)\s*Mbits/sec') + max_tput=p.findall(search_expr) + if max_tput.__len__()==1: + max_tput = max_tput[0] + else: + max_tput = None + + p= re.compile('average\s*=\s*(\d*.\d*)\s*Mbits/sec') + avg_tput=p.findall(search_expr) + if avg_tput.__len__()==1: + avg_tput=avg_tput[0] + else: + avg_tput = None + + p= re.compile('duration\s*=\s*(\d*.\d*)\s*s') + duration=p.findall(search_expr) + if duration.__len__()==1: + duration = duration[0] + else: + duration = None + + min_tput = try_convert_to_float(min_tput) + max_tput = try_convert_to_float(max_tput) + avg_tput = try_convert_to_float(avg_tput) + duration = try_convert_to_float(duration) + + if (min_tput != None and max_tput != None and avg_tput != None and duration != None ): + result, tput_string = tput_test(logfile_traffic, min_tput, max_tput, avg_tput, duration) + else: + result=1 + + return result, tput_string + +# \brief function to copy files to/from remote machine +# \param username user with which to make sftp connection +# \param password password of user +# \param hostname host to connect +# \ports port of remote machine on which server is listening +# \paramList This is list of operations as a set {operation: "get/put", localfile: "filename", remotefile: "filename" +# \param logfile Ignored currently and set once at the beginning of program +def sftp_module (username, password, hostname, ports, paramList,logfile): + #localD = localfile + #remoteD = remotefile + #fd, paramiko_logfile = tempfile.mkstemp() + #res = os.close(fd ) + #paramiko logfile path should not be changed with multiple calls. The logs seem to in first file regardless + error = "" + #The lines below are outside exception loop to be sure to terminate the test case if the network connectivity goes down or there is authentication failure + transport = paramiko.Transport((hostname, ports)) + transport.connect(username = username, password = password) + sftp = paramiko.SFTPClient.from_transport(transport) + # index =0 + for param in paramList: + try: + operation = param["operation"] + localD = param["localfile"] + remoteD = param["remotefile"] + if operation == "put": + sftp.put(remotepath=remoteD, localpath=localD) + elif operation == "get": + sftp.get(remotepath=remoteD, localpath=localD) + else : + print "sftp_module: unidentified operation:<" + operation + "> Exiting now" + print "hostname = " + hostname + print "ports = " + ports + print "localfile = " + localD + print "remotefile = " + remoteD + print "operation = " + operation + sys.exit() + except Exception, e: + error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) + error = error + '\n username = ' + username + '\n hostname = ' + hostname + '\n localfile = ' + localD + '\n remotefile = ' + remoteD + '\n operation = ' + operation + '\nlogfile = ' + logfile + '\n ports = ' + str(ports) + '\n' + error = error + traceback.format_exc() + print error + + sftp.close() + transport.close() + res = os.system('\n echo \'SFTP Module Log for Machine: <' + hostname + '> starts...\' >> ' + logfile + ' 2>&1 ') + res = os.system('cat ' + paramiko_logfile + ' >> ' + logfile + ' 2>&1 \n') + write_file(logfile, error, "a") + res = os.system('\n echo \'SFTP Module Log for Machine: <' + hostname + '> ends...\' >> ' + logfile + ' 2>&1 \n') + +# \brief bash script stub put at the end of scripts to terminate it +# \param timeout_cmd terminate script after timeout_cmd seconds +# \param terminate_missing_procs if True terminate all the processes launched by script if one of them terminates prematurely (due to error) +def finalize_deploy_script (timeout_cmd, terminate_missing_procs='False'): + cmd = 'declare -i timeout_cmd='+str(timeout_cmd) + '\n' + if terminate_missing_procs == 'True': + cmd = cmd + """ + #The code below checks if one the processes launched in background has crashed. + #If it does, then the code below terminates all the child processes created by this script + declare -i wakeup_interval=1 + declare -i step=0 + echo \"Array pid = ${array_exec_pid[@]}\" + while [ "$step" -lt "$timeout_cmd" ] + do + declare -i break_while_loop=0 + #Iterate over each process ID in array_exec_pid + for i in "${array_exec_pid[@]}" + do + numchild=`pstree -p $i | perl -ne 's/\((\d+)\)/print " $1"/ge' |wc -w` + echo "PID = $i, numchild = $numchild" + if [ "$numchild" -eq "0" ] ; then + echo "Process ID $i has finished unexpectedly. Now preparing to kill all the processes " + break_while_loop=1 + break + fi + done + if [ "$break_while_loop" -eq "1" ] ; then + break + fi + step=$(( step + wakeup_interval )) + sleep $wakeup_interval + done + echo "Final time step (Duration of test case) = $step " + date + """ + else: + #We do not terminate the script if one of the processes has existed prematurely + cmd = cmd + 'sleep ' + str(timeout_cmd) + ' ; date \n' + + return cmd + +# \brief run python script and update config file params of test case +# \param oai module with already open connection +# \param config_string config string taken from xml file +# \param logdirRepo directory of remote repository +# \param python_script python script location +def update_config_file(oai, config_string, logdirRepo, python_script): + cmd="" + if config_string : + stringArray = config_string.splitlines() + #python_script = '$OPENAIR_DIR/targets/autotests/tools/search_repl.py' + for string in stringArray: + #split the string based on space now + string1=string.split() + cmd = cmd + 'python ' + python_script + ' ' + logdirRepo+'/'+string1[0] + ' ' + string1[1] + ' '+ string1[2] + '\n' + #cmd = cmd + 'perl -p -i -e \'s/'+ string1[1] + '\\s*=\\s*"\\S*"\\s*/' + string1[1] + ' = "' + string1[2] +'"' + '/g\' ' + logdirRepo + '/' +string1[0] + '\n' + return cmd + #result = oai.send_recv(cmd) + +# \brief thread safe sshsession wrapper due to occasional connection issues with ssh +# \param machine name of machine +# \param username user login for remote machine +# \param key_file file name which has keys to enable passwordless login +# \param password password for remote machine +# \param logdir_remote remote directory +# \param logdir_local_base local directory +# \param operation operation to perform (get_all, put_all) transfers recursively for directories +def SSHSessionWrapper(machine, username, key_file, password, logdir_remote, logdir_local_base, operation): + max_tries = 100 + i=0 + while i <= max_tries: + i = i +1 + try: + ssh = SSHSession(machine , username, key_file, password) + if operation == "get_all": + ssh.get_all(logdir_remote , logdir_local_base) + elif operation == "put_all": + ssh.put_all(logdir_local_base, logdir_remote ) + else: + print "Error: Uknown operation in SSHSessionWrapper. Exiting now..." + sys.exit(1) + break + except Exception, e: + error='' + error = error + ' In Class = function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) + error = error + '\n username = ' + username + '\n machine = ' + machine + '\n logdir_remote = ' + logdir_remote + '\n logdir_local_base = ' + logdir_local_base + error = error + traceback.format_exc() + print error + print " Retrying again in 1 seconds" + time.sleep(1) + print "Continuing ..." + if i ==max_tries: + print "Fatal Error: Max no of retries reached. Exiting now..." + sys.exit(1) + + + +# \briefFunction to clean old programs that might be running from earlier execution +# \param oai - parameter for making connection to machine +# \parm programList list of programs that must be terminated before execution of any test case +# \param CleanUpAluLteBox program to terminate AlU Bell Labs LTE Box +# \param ExmimoRfStop String to stop EXMIMO card (specified in test_case_list.xml) +def cleanOldPrograms(oai, programList, CleanUpAluLteBox, ExmimoRfStop, logdir, logdirOAI5GRepo): + cmd = 'killall -9 ' + programList + result = oai.send(cmd, True) +# print "\t\t > "+cmd +# print "\t\t < "+result + +# print "Killing old programs on ..." + result + programArray = programList.split() + programListJoin = '|'.join(programArray) + cmd = " ( date ;echo \"Starting cleaning old programs.. \" ; dmesg|tail ; echo \"Current disk space.. \" ; df -h )>& " + logdir + "/oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync" + result=oai.send_recv(cmd) +# print "\t\t > "+cmd +# print "\t\t < "+result + + cmd = cleanupOldProgramsScript + ' ' + '\''+programListJoin+'\'' + #result = oai.send_recv(cmd) + #print result + result = oai.send_expect_false(cmd, 'Match found', False) +# print "\t\t > "+cmd +# print "\t\t < "+result + +# print "Looking for old programs..." + result + res=oai.send_recv(CleanUpAluLteBox, True) +# print "\t\t > "+CleanUpAluLteBox +# print "\t\t < "+res + cmd= " echo \"Starting EXmimoRF Stop... \" >> " + logdir + "/oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync "; + result = oai.send_recv(cmd) +# print "\t\t > "+cmd +# print "\t\t < "+result + cmd = "( " + "cd " + logdirOAI5GRepo + " ; source oaienv ; " + ExmimoRfStop + " ) >> " + logdir + "/oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync " +# print "cleanoldprograms cmd = " + cmd + res=oai.send_recv(cmd, False, timeout=600) +# print "\t\t > "+cmd +# print "\t\t < "+res + + cmd= " echo \"Stopping EXmimoRF Stop... \" >> " + logdir + "/oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync "; + result = oai.send_recv(cmd) +# print "\t\t > "+cmd +# print "\t\t < "+result + + #res = oai.send_recv(ExmimoRfStop, False) + cmd = " ( date ;echo \"Finished cleaning old programs.. \" ; dmesg | tail)>> $HOME/.oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync" + res=oai.send_recv(cmd) +# print "\t\t > "+cmd +# print "\t\t < "+res + +# \brief Class thread to launch a generic command on remote machine +# \param threadID number of thread (for book keeping) +# \param threadname string of threadname (for book keeping) +# \param machine machine name on which to run the command +# \param username username with which to login +# \param password password with which to login +# \param cmd command as a string to run on remote machine +# \parma sudo if True sudo is set +# \param timeout timeout of command in seconds +class oaiThread (threading.Thread): + def __init__(self, threadID, threadname, machine, username, password, cmd, sudo, timeout): + threading.Thread.__init__(self) + self.threadID = threadID + self.threadname = threadname + self.machine = machine + self.username = username + self.password = password + self.cmd = cmd + self.sudo = sudo + self.timeout = timeout + def run(self): + try: + oai = openair('localdomain',self.machine) + oai.connect(self.username, self.password) + # print "Starting " + self.threadname + " on machine " + self.machine + result = oai.send_recv(self.cmd, self.sudo, self.timeout) + #print "result = " + result + #print "Exiting " + self.threadname + oai.disconnect() + except Exception, e: + error='' + error = error + ' In class oaiThread, function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) + error = error + '\n threadID = ' + str(self.threadID) + '\n threadname = ' + self.threadname + '\n timeout = ' + str(self.timeout) + '\n machine = ' + self.machine + '\n cmd = ' + self.cmd + '\n timeout = ' + str(self.timeout) + '\n username = ' + self.username + '\n' + error = error + traceback.format_exc() + print error + + +# \brief This class runs test cases with class {execution, compilatation} +# \param threadID number of thread (for book keeping) +# \param name string of threadname (for book keeping) +# \param machine machine name on which to run the command +# \param logdirOAI5GRepo directory on remote machine which as openairinterface5g repo installed +# \param testcasename name of test case to run on remote machine +# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) +# \param user username with which to login +# \param password password with which to login +# \param timeout timeout of command in seconds +# \param ExmimoRfStop command to stop EXMIMO Card +class testCaseThread_generic (threading.Thread): + def __init__(self, threadID, name, machine, logdirOAI5GRepo, testcasename,oldprogramList, CleanupAluLteBox, user, password, timeout, ExmimoRfStop): + threading.Thread.__init__(self) + self.threadID = threadID + self.name = name + self.testcasename = testcasename + self.timeout = timeout + self.machine = machine + self.logdirOAI5GRepo = logdirOAI5GRepo + self.oldprogramList = oldprogramList + self.CleanupAluLteBox = CleanupAluLteBox + self.password=password + self.ExmimoRfStop = ExmimoRfStop + self.user = user + def run(self): + try: + mypassword='' + #addsudo = 'echo \'' + mypassword + '\' | sudo -S -E ' + addpass = 'echo \'' + mypassword + '\' | ' + #user = getpass.getuser() + print "Starting test case : " + self.testcasename + " On machine " + self.machine + " timeout = " + str(self.timeout) + oai = openair('localdomain',self.machine) + oai.connect(self.user, self.password) + #cleanOldPrograms(oai, self.oldprogramList, self.CleanupAluLteBox, self.ExmimoRfStop) + logdir_local = os.environ.get('OPENAIR_DIR') + logdir_local_testcase = logdir_local +'/cmake_targets/autotests/log/'+ self.testcasename + logdir_local_base = logdir_local +'/cmake_targets/autotests/log/' + logdir_remote_testcase = self.logdirOAI5GRepo + '/cmake_targets/autotests/log/' + self.testcasename + logdir_remote = self.logdirOAI5GRepo + '/cmake_targets/autotests/log/' + logfile_task_testcasename = logdir_local_testcase + '/test_task' + '_' + self.testcasename + '_.log' + logfile_task_testcasename_out = logdir_remote + '/test_task_out' + '_' + self.testcasename + '_.log' + #print "logdir_local_testcase = " + logdir_local_testcase + #print "logdir_remote_testcase = " + logdir_remote_testcase + #if os.path.exists(logdir_local_testcase) == True : + # os.removedirs(logdir_local_testcase) + #os.mkdir(logdir_local_testcase) + os.system("rm -fr " + logdir_local_testcase ) + os.system("mkdir -p " + logdir_local_testcase) + cmd = "mkdir -p " + logdir_remote_testcase + res = oai.send_recv(cmd, False, self.timeout) + #print "res = " + res + + cmd = "( cd " + self.logdirOAI5GRepo + " \n " + cmd = cmd + "source oaienv \n" + cmd = cmd + "$OPENAIR_DIR/cmake_targets/autotests/run_exec_autotests.bash --run-group \"" + self.testcasename + "\" -p \'\'" + cmd = cmd + " ) >& " + logfile_task_testcasename_out + " ; " + "mkdir -p " + logdir_remote_testcase + "; mv " + logfile_task_testcasename_out + " " +logdir_remote_testcase + + #print "cmd = " + cmd + res = oai.send_recv(cmd, False, self.timeout) + #print "res = " + res + #print "ThreadID = " + str(self.threadID) + "ThreadName: " + self.name + " testcasename: " + self.testcasename + "Execution Result = " + res + write_file(logfile_task_testcasename, cmd, mode="w") + #Now we copy all the remote files + #ssh = SSHSession(self.machine , username=user, key_file=None, password=self.password) + #ssh.get_all(logdir_remote_testcase , logdir_local_base) + SSHSessionWrapper(self.machine, self.user, None, self.password, logdir_remote_testcase, logdir_local_base, "get_all") + print "Finishing test case : " + self.testcasename + " On machine " + self.machine + #cleanOldPrograms(oai, self.oldprogramList, self.CleanupAluLteBox, self.ExmimoRfStop) + #oai.kill(user,mypassword) + oai.disconnect() + except Exception, e: + error='' + error = error + ' In Class = testCaseThread_generic, function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) + error = error + '\n threadID = ' + str(self.threadID) + '\n threadName = ' + self.name + '\n testcasename = ' + self.testcasename + '\n machine = ' + self.machine + '\n logdirOAI5GRepo = ' + self.logdirOAI5GRepo + '\n' + '\n timeout = ' + str(self.timeout) + '\n user = ' + self.user + error = error + traceback.format_exc() + print error + print "Continuing with next test case..." + #sys.exit() + + + +# \bried function to run a command as a sudo +# \param cmd command as a string +# \param password password to be supplied +def addsudo (cmd, password=""): + cmd = 'echo \'' + password + '\' | sudo -S -E bash -c \' ' + cmd + '\' ' + return cmd + +# \brief handler for executing test cases (compilation, execution) +# \param name of testcase +# \param threadListGeneric list of threads which are already running on remote machines +# \param oldprogramList list of programs which must be terminated before running a test case +# \param logdirOAI5GRepo directory on remote machine which as openairinterface5g repo installed +# \param MachineList list of all machines on which generic test cases can be run +# \param user username with which to login +# \param password password with which to login +# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) +# \param timeout timeout of command in seconds +# \param ExmimoRfStop command to stop EXMIMO Card +def handle_testcaseclass_generic (testcasename, threadListGeneric, oldprogramList, logdirOAI5GRepo, MachineList, user, password, CleanupAluLteBox,timeout, ExmimoRfStop): + try: + mypassword=password + MachineListFree=[] + threadListNew=[] + while MachineListFree.__len__() == 0 : + MachineListBusy=[] + MachineListFree=[] + threadListNew=[] + #first we need to find the list of free machines that we could run our test case + if threadListGeneric.__len__() ==0 : + #This means no thread is started yet + MachineListFree = MachineList[:] + else : + for param in threadListGeneric : + thread_id = param["thread_id"] + machine = param["Machine"] + testcasenameold = param["testcasename"] + thread_id.join(1) + if thread_id.isAlive() == True: + threadListNew.append(param) + print "thread_id is alive: testcasename: " + testcasenameold + " on machine "+ machine + if machine not in MachineListBusy: + MachineListBusy.append(machine) + else : + print "thread_id is finished: testcasename: " + testcasenameold + " on machine " + machine + #threadListGeneric.remove(param) + #if machine not in MachineListFree: + # MachineListFree.append(machine) + #Now we check if there is at least one free machine + MachineListFree = MachineList[:] + for machine in MachineListBusy: + if machine in MachineListFree: + MachineListFree.remove(machine) + print "MachineListFree = " + ','.join(MachineListFree) + print "MachineListBusy = " + ','.join(MachineListBusy) + print "MachineList = " + ','.join(MachineList) + machine = MachineListFree[0] + thread = testCaseThread_generic(1,"Generic Thread_"+testcasename+"_"+ "machine_", machine, logdirOAI5GRepo, testcasename, oldprogramList, CleanupAluLteBox, user, password, timeout, ExmimoRfStop) + param={"thread_id":thread, "Machine":machine, "testcasename":testcasename} + thread.start() + threadListNew.append(param) + return threadListNew + except Exception, e: + error='' + error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) + error = error + '\n testcasename = ' + testcasename + '\n logdirOAI5GRepo = ' + logdirOAI5GRepo + '\n MachineList = ' + ','.join(MachineList) + '\n timeout = ' + str(timeout) + '\n' + 'user = ' + user + error = error + traceback.format_exc() + print error + print "Continuing..." + #sys.exit(1) + +# \brief Blocking wait for all threads related to generic testcase execution, class (compilation and execution) +# \param threadListGeneric list of threads which are running on remote machines +# \param timeout time to wait on threads in seconds +def wait_testcaseclass_generic_threads(threadListGeneric, timeout = 1): + threadListGenericNew=[] + for param in threadListGeneric: + thread_id = param["thread_id"] + machine = param["Machine"] + testcasenameold = param["testcasename"] + thread_id.join(timeout) + if thread_id.isAlive() == True: + threadListGenericNew.append(param) + print "thread_id on machine: " + machine + " is still alive: testcasename: " + testcasenameold + print " Exiting now..." + sys.exit(1) + else: + print "thread_id on machine: " + machine + " is stopped: testcasename: " + testcasenameold + #threadListGeneric.remove(param) + return threadListGenericNew + + +# \brief handler for executing test cases (lte-softmodem) +# \param testcase name of testcase +# \param oldprogramList list of programs which must be terminated before running a test case +# \param logdirOAI5GRepo directory on remote machine which has openairinterface5g repo installed +# \param logdirOpenaircnRepo directory on remote machine which has openair-cn repo installed +# \param MachineList list of all machines on which test cases can be run +# \param user username with which to login +# \param password password with which to login +# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) +# \param ExmimoRfStop command to stop EXMIMO Card +# \param nruns_lte-softmodem global parameter to override number of runs (nruns) within the test case +def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , logdirOpenaircnRepo, MachineList, user, password, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, timeout_cmd): + #We ignore the password sent to this function for secuirity reasons for password present in log files + #It is recommended to add a line in /etc/sudoers that looks something like below. The line below will run sudo without password prompt + # your_user_name ALL=(ALL:ALL) NOPASSWD: ALL + mypassword='' + #addsudo = 'echo \'' + mypassword + '\' | sudo -S -E ' + addpass = 'echo \'' + mypassword + '\' | ' + #user = getpass.getuser() + testcasename = testcase.get('id') + testcaseclass = testcase.findtext('class',default='') + if timeout_cmd == '': + timeout_cmd = testcase.findtext('TimeOut_cmd',default='') + timeout_cmd = int(float(timeout_cmd)) + #Timeout_thread is more than that of cmd to have room for compilation time, etc + timeout_thread = timeout_cmd + 300 + if nruns_lte_softmodem == '': + nruns = testcase.findtext('nruns',default='') + else: + nruns = nruns_lte_softmodem + nruns = int(float(nruns)) + tags = testcase.findtext('tags',default='') + + RRHMachine = testcase.findtext('RRH',default='') + RRH_compile_prog = testcase.findtext('RRH_compile_prog',default='') + RRH_compile_prog_args = testcase.findtext('RRH_compile_prog_args',default='') + RRH_pre_exec = testcase.findtext('RRH_pre_exec',default='') + RRH_pre_exec_args = testcase.findtext('RRH_pre_exec_args',default='') + RRH_main_exec = testcase.findtext('RRH_main_exec',default='') + RRH_main_exec_args = testcase.findtext('RRH_main_exec_args',default='') + RRH_terminate_missing_procs = testcase.findtext('RRH_terminate_missing_procs',default='True') + + + eNBMachine = testcase.findtext('eNB',default='') + eNB_config_file = testcase.findtext('eNB_config_file',default='') + eNB_compile_prog = testcase.findtext('eNB_compile_prog',default='') + eNB_compile_prog_args = testcase.findtext('eNB_compile_prog_args',default='') + eNB_pre_exec = testcase.findtext('eNB_pre_exec',default='') + eNB_pre_exec_args = testcase.findtext('eNB_pre_exec_args',default='') + eNB_main_exec = testcase.findtext('eNB_main_exec',default='') + eNB_main_exec_args = testcase.findtext('eNB_main_exec_args',default='') + eNB_traffic_exec = testcase.findtext('eNB_traffic_exec',default='') + eNB_traffic_exec_args = testcase.findtext('eNB_traffic_exec_args',default='') + eNB_terminate_missing_procs = testcase.findtext('eNB_terminate_missing_procs',default='True') + eNB_search_expr_true = testcase.findtext('eNB_search_expr_true','') + if re.compile('\w+').match(eNB_search_expr_true) != None: + eNB_search_expr_true = eNB_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' + + UEMachine = testcase.findtext('UE',default='') + UE_config_file = testcase.findtext('UE_config_file',default='') + UE_compile_prog = testcase.findtext('UE_compile_prog',default='') + UE_compile_prog_args = testcase.findtext('UE_compile_prog_args',default='') + UE_pre_exec = testcase.findtext('UE_pre_exec',default='') + UE_pre_exec_args = testcase.findtext('UE_pre_exec_args',default='') + UE_main_exec = testcase.findtext('UE_main_exec',default='') + UE_main_exec_args = testcase.findtext('UE_main_exec_args',default='') + UE_traffic_exec = testcase.findtext('UE_traffic_exec',default='') + UE_traffic_exec_args = testcase.findtext('UE_traffic_exec_args',default='') + UE_terminate_missing_procs = testcase.findtext('UE_terminate_missing_procs',default='True') + UE_search_expr_true = testcase.findtext('UE_search_expr_true','') + UE_stop_script = testcase.findtext('UE_stop_script','') + if re.compile('\w+').match(UE_search_expr_true) != None: + UE_search_expr_true = UE_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' + + EPCMachine = testcase.findtext('EPC',default='') + EPC_config_file = testcase.findtext('EPC_config_file',default='') + EPC_compile_prog = testcase.findtext('EPC_compile_prog',default='') + EPC_compile_prog_args = testcase.findtext('EPC_compile_prog_args',default='') + HSS_compile_prog = testcase.findtext('HSS_compile_prog',default='') + HSS_compile_prog_args = testcase.findtext('HSS_compile_prog_args',default='') + + EPC_pre_exec= testcase.findtext('EPC_pre_exec',default='') + EPC_pre_exec_args = testcase.findtext('EPC_pre_exec_args',default='') + EPC_main_exec= testcase.findtext('EPC_main_exec',default='') + EPC_main_exec_args = testcase.findtext('EPC_main_exec_args',default='') + HSS_main_exec= testcase.findtext('HSS_main_exec',default='') + HSS_main_exec_args = testcase.findtext('HSS_main_exec_args',default='') + EPC_traffic_exec = testcase.findtext('EPC_traffic_exec',default='') + EPC_traffic_exec_args = testcase.findtext('EPC_traffic_exec_args',default='') + EPC_terminate_missing_procs = testcase.findtext('EPC_terminate_missing_procs',default='True') + EPC_search_expr_true = testcase.findtext('EPC_search_expr_true','') + if re.compile('\w+').match(EPC_search_expr_true) != None: + EPC_search_expr_true = EPC_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' + + index_eNBMachine = MachineList.index(eNBMachine) + index_UEMachine = MachineList.index(UEMachine) +# index_EPCMachine = MachineList.index(EPCMachine) + cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep OPENAIR' + oai_eNB = openair('localdomain', eNBMachine) + oai_eNB.connect(user, password) + res= oai_eNB.send_recv(cmd) + oai_UE = openair('localdomain', UEMachine) + oai_UE.connect(user, password) +# print cmd + res = oai_UE.send_recv(cmd) +# print res +# oai_EPC = openair('localdomain', EPCMfachine) +# oai_EPC.connect(user, password) + res = oai_eNB.send_recv(cmd) + if RRHMachine != '': + cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep OPENAIR' + index_RRHMachine = MachineList.index(RRHMachine) + oai_RRH = openair('localdomain', RRHMachine) + oai_RRH.connect(user, password) + res= oai_RRH.send_recv(cmd) + #cleanOldPrograms(oai_eNB, oldprogramList, CleanUpAluLteBox, ExmimoRfStop) + #cleanOldPrograms(oai_UE, oldprogramList, CleanUpAluLteBox, ExmimoRfStop) + #cleanOldPrograms(oai_EPC, oldprogramList, CleanUpAluLteBox, ExmimoRfStop) + logdir_local = os.environ.get('OPENAIR_DIR') + if logdir_local is None: + print "Environment variable OPENAIR_DIR not set correctly" + sys.exit() + + #Make the log directory of test case + #cmd = 'mkdir -p ' + logdir_eNB + #result = oai_eNB.send_recv(cmd) + #cmd = 'mkdir -p ' + logdir_UE + #print cmd + #result = oai_UE.send_recv(cmd) + #print result + #cmd = 'mkdir -p ' + logdir_EPC + #result = oai_EPC.send_recv(cmd) + + print "Updating the config files for ENB/UE/EPC..." + #updating the eNB/UE/EPC configuration file from the test case + #update_config_file(oai_eNB, eNB_config_file, logdirOAI5GRepo) + #update_config_file(oai_UE, UE_config_file, logdirOAI5GRepo) + #update_config_file(oai_EPC, EPC_config_file, logdirOpenaircnRepo) + test_result=1 + test_result_string='' + start_time=time.time() + for run in range(0,nruns): + run_result=1 + run_result_string='' + logdir_eNB = logdirOAI5GRepo+'/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) + logdir_RRH = logdirOAI5GRepo+'/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) + logdir_UE = logdirOAI5GRepo+'/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) + logdir_EPC = logdirOpenaircnRepo+'/TEST/autotests/log/'+ testcasename + '/run_' + str(run) + logdir_local_testcase = logdir_local + '/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) + #Make the log directory of test case + if RRHMachine != '': + cmd = 'rm -fr ' + logdir_RRH + ' ; mkdir -p ' + logdir_RRH + result = oai_RRH.send_recv(cmd) + cmd = 'rm -fr ' + logdir_eNB + ' ; mkdir -p ' + logdir_eNB + result = oai_eNB.send_recv(cmd) + cmd = 'rm -fr ' + logdir_UE + ' ; mkdir -p ' + logdir_UE +# print cmd + result = oai_UE.send_recv(cmd) + # print result + cmd = 'rm -fr ' + logdir_EPC + '; mkdir -p ' + logdir_EPC +# result = oai_EPC.send_recv(cmd) + cmd = ' rm -fr ' + logdir_local_testcase + ' ; mkdir -p ' + logdir_local_testcase + result = os.system(cmd) + + if RRHMachine != '': + logfile_compile_RRH = logdir_RRH + '/RRH_compile' + '_' + str(run) + '_.log' + logfile_exec_RRH = logdir_RRH + '/RRH_exec' + '_' + str(run) + '_.log' + logfile_pre_exec_RRH = logdir_RRH + '/RRH_pre_exec' + '_' + str(run) + '_.log' + logfile_task_RRH_compile_out = logdir_RRH + '/RRH_task_compile_out' + '_' + str(run) + '_.log' + logfile_task_RRH_compile = logdir_local_testcase + '/RRH_task_compile' + '_' + str(run) + '_.log' + logfile_task_RRH_out = logdir_RRH + '/RRH_task_out' + '_' + str(run) + '_.log' + logfile_task_RRH = logdir_local_testcase + '/RRH_task' + '_' + str(run) + '_.log' + task_RRH_compile = ' ( uname -a ; date \n' + task_RRH_compile = task_RRH_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_RRH_compile = task_RRH_compile + 'env |grep OPENAIR \n' + if RRH_compile_prog != "": + task_RRH_compile = task_RRH_compile + ' ( ' + RRH_compile_prog + ' '+ RRH_compile_prog_args + ' ) > ' + logfile_compile_RRH + ' 2>&1 \n' + task_RRH_compile = task_RRH_compile + ' date ) > ' + logfile_task_RRH_compile_out + ' 2>&1 ' + write_file(logfile_task_RRH_compile, task_RRH_compile, mode="w") + + task_RRH = ' ( uname -a ; date \n' + task_RRH = task_RRH + ' export OPENAIR_TESTDIR=' + logdir_RRH + '\n' + task_RRH = task_RRH + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_RRH = task_RRH + 'env |grep OPENAIR \n' + 'array_exec_pid=() \n' + + if RRH_pre_exec != "": + task_RRH = task_RRH + ' ( date; ' + RRH_pre_exec + ' '+ RRH_pre_exec_args + ' ) > ' + logfile_pre_exec_RRH + ' 2>&1 \n' + if RRH_main_exec != "": + task_RRH = task_RRH + ' ( date; ' + addsudo(RRH_main_exec + ' ' + RRH_main_exec_args, mypassword) + ' ) > ' + logfile_exec_RRH + ' 2>&1 & \n' + task_RRH = task_RRH + 'array_exec_pid+=($!) \n' + task_RRH = task_RRH + 'echo eNB_main_exec PID = $! \n' + #terminate the eNB test case after timeout_cmd seconds + task_RRH = task_RRH + finalize_deploy_script (timeout_cmd, RRH_terminate_missing_procs) + ' \n' + task_RRH = task_RRH + 'handle_ctrl_c' + '\n' + task_RRH = task_RRH + ' ) > ' + logfile_task_RRH_out + ' 2>&1 ' + write_file(logfile_task_RRH, task_RRH, mode="w") + + logfile_compile_eNB = logdir_eNB + '/eNB_compile' + '_' + str(run) + '_.log' + logfile_exec_eNB = logdir_eNB + '/eNB_exec' + '_' + str(run) + '_.log' + logfile_pre_exec_eNB = logdir_eNB + '/eNB_pre_exec' + '_' + str(run) + '_.log' + logfile_traffic_eNB = logdir_eNB + '/eNB_traffic' + '_' + str(run) + '_.log' + logfile_task_eNB_compile_out = logdir_eNB + '/eNB_task_compile_out' + '_' + str(run) + '_.log' + logfile_task_eNB_compile = logdir_local_testcase + '/eNB_task_compile' + '_' + str(run) + '_.log' + logfile_task_eNB_out = logdir_eNB + '/eNB_task_out' + '_' + str(run) + '_.log' + logfile_task_eNB = logdir_local_testcase + '/eNB_task' + '_' + str(run) + '_.log' + logfile_local_traffic_eNB_out = logdir_local_testcase + '/eNB_traffic' + '_' + str(run) + '_.log' + logfile_tshark_eNB = logdir_eNB + '/eNB_tshark' + '_' + str(run) + '_.log' + logfile_pcap_eNB = logdir_eNB + '/eNB_tshark' + '_' + str(run) + '_.pcap' + logfile_pcap_zip_eNB = logdir_eNB + '/eNB_tshark' + '_' + str(run) + '_.pcap.zip' + logfile_pcap_tmp_eNB = '/tmp/' + '/eNB_tshark' + '_' + str(run) + '_.pcap' + + task_eNB_compile = ' ( uname -a ; date \n' + task_eNB_compile = task_eNB_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_eNB_compile = task_eNB_compile + 'env |grep OPENAIR \n' + task_eNB_compile = task_eNB_compile + update_config_file(oai_eNB, eNB_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' + if eNB_compile_prog != "": + task_eNB_compile = task_eNB_compile + ' ( ' + eNB_compile_prog + ' '+ eNB_compile_prog_args + ' ) > ' + logfile_compile_eNB + ' 2>&1 \n' + task_eNB_compile = task_eNB_compile + ' date ) > ' + logfile_task_eNB_compile_out + ' 2>&1 ' + write_file(logfile_task_eNB_compile, task_eNB_compile, mode="w") + + task_eNB = ' ( uname -a ; date \n' + task_eNB = task_eNB + ' export OPENAIR_TESTDIR=' + logdir_eNB + '\n' + task_eNB = task_eNB + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_eNB = task_eNB + 'env |grep OPENAIR \n' + 'array_exec_pid=() \n' + + if eNB_pre_exec != "": + task_eNB = task_eNB + ' ( date; ' + eNB_pre_exec + ' '+ eNB_pre_exec_args + ' ) > ' + logfile_pre_exec_eNB + ' 2>&1 \n' + if eNB_main_exec != "": + task_eNB = task_eNB + ' ( date; ' + addsudo(eNB_main_exec + ' ' + eNB_main_exec_args, mypassword) + ' ) > ' + logfile_exec_eNB + ' 2>&1 & \n' + task_eNB = task_eNB + 'array_exec_pid+=($!) \n' + task_eNB = task_eNB + 'echo eNB_main_exec PID = $! \n' + if eNB_traffic_exec != "": + cmd_traffic = eNB_traffic_exec + ' ' + eNB_traffic_exec_args + if cmd_traffic.find('-c') >= 0: + cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 60) + task_eNB = task_eNB + ' (date; ' + cmd_traffic + ' ) > ' + logfile_traffic_eNB + ' 2>&1 & \n' + task_eNB = task_eNB + 'array_exec_pid+=($!) \n' + task_eNB = task_eNB + 'echo eNB_traffic_exec PID = $! \n' + + task_eNB = task_eNB + ' (date; sudo rm -f ' + logfile_pcap_tmp_eNB + ' ; sudo -E tshark -i lo -s 65535 -a duration:' + str(timeout_cmd-10)+ ' -w ' + logfile_pcap_tmp_eNB+ ' ; sudo -E chown ' + user + ' ' + logfile_pcap_tmp_eNB + ' ; zip -j -9 ' + logfile_pcap_zip_eNB + ' ' + logfile_pcap_tmp_eNB + ' ) > ' + logfile_tshark_eNB + ' 2>&1 & \n ' + task_eNB = task_eNB + 'array_exec_pid+=($!) \n' + task_eNB = task_eNB + 'echo eNB_tshark_exec PID = $! \n' + #terminate the eNB test case after timeout_cmd seconds + task_eNB = task_eNB + finalize_deploy_script (timeout_cmd, eNB_terminate_missing_procs) + ' \n' + #task_eNB = task_eNB + 'sleep ' + str(timeout_cmd) + ' \n' + task_eNB = task_eNB + 'handle_ctrl_c' + '\n' + task_eNB = task_eNB + ' ) > ' + logfile_task_eNB_out + ' 2>&1 ' + write_file(logfile_task_eNB, task_eNB, mode="w") + + #task_eNB = 'echo \" ' + task_eNB + '\" > ' + logfile_script_eNB + ' 2>&1 ; ' + task_eNB + logfile_compile_UE = logdir_UE + '/UE_compile' + '_' + str(run) + '_.log' + logfile_exec_UE = logdir_UE + '/UE_exec' + '_' + str(run) + '_.log' + logfile_pre_exec_UE = logdir_UE + '/UE_pre_exec' + '_' + str(run) + '_.log' + logfile_traffic_UE = logdir_UE + '/UE_traffic' + '_' + str(run) + '_.log' + logfile_task_UE_out = logdir_UE + '/UE_task_out' + '_' + str(run) + '_.log' + logfile_task_UE = logdir_local_testcase + '/UE_task' + '_' + str(run) + '_.log' + logfile_task_UE_compile_out = logdir_UE + '/UE_task_compile_out' + '_' + str(run) + '_.log' + logfile_task_UE_compile = logdir_local_testcase + '/UE_task_compile' + '_' + str(run) + '_.log' + logfile_local_traffic_UE_out = logdir_local_testcase + '/UE_traffic' + '_' + str(run) + '_.log' + + task_UE_compile = ' ( uname -a ; date \n' + task_UE_compile = task_UE_compile + 'array_exec_pid=()' + '\n' + task_UE_compile = task_UE_compile + 'cd ' + logdirOAI5GRepo + '\n' + task_UE_compile = task_UE_compile + 'source oaienv \n' + task_UE_compile = task_UE_compile + 'source cmake_targets/tools/build_helper \n' + task_UE_compile = task_UE_compile + 'env |grep OPENAIR \n' + task_UE_compile = task_UE_compile + update_config_file(oai_UE, UE_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' + if UE_compile_prog != "": + task_UE_compile = task_UE_compile + ' ( ' + UE_compile_prog + ' '+ UE_compile_prog_args + ' ) > ' + logfile_compile_UE + ' 2>&1 \n' + task_UE_compile = task_UE_compile + ' ) > ' + logfile_task_UE_compile_out + ' 2>&1 ' + write_file(logfile_task_UE_compile, task_UE_compile, mode="w") + + task_UE = ' ( uname -a ; date \n' + task_UE = task_UE + 'array_exec_pid=()' + '\n' + task_UE = task_UE + 'cd ' + logdirOAI5GRepo + '\n' + task_UE = task_UE + 'source oaienv \n' + task_UE = task_UE + 'source cmake_targets/tools/build_helper \n' + task_UE = task_UE + 'env |grep OPENAIR \n' + if UE_pre_exec != "": + task_UE = task_UE + ' ( date; ' + UE_pre_exec + ' '+ UE_pre_exec_args + ' ) > ' + logfile_pre_exec_UE + ' 2>&1 \n' + if UE_main_exec != "": + task_UE = task_UE + ' ( date; ' + addsudo(UE_main_exec + ' ' + UE_main_exec_args, mypassword) + ' ) > ' + logfile_exec_UE + ' 2>&1 & \n' + task_UE = task_UE + 'array_exec_pid+=($!) \n' + task_UE = task_UE + 'echo UE_main_exec PID = $! \n' + if UE_traffic_exec != "": + cmd_traffic = UE_traffic_exec + ' ' + UE_traffic_exec_args + if cmd_traffic.find('-c') >= 0: + cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 60) + task_UE = task_UE + ' ( date; ' + cmd_traffic + ' ) >' + logfile_traffic_UE + ' 2>&1 & \n' + task_UE = task_UE + 'array_exec_pid+=($!) \n' + task_UE = task_UE + 'echo UE_traffic_exec PID = $! \n' + #terminate the UE test case after timeout_cmd seconds + task_UE = task_UE + finalize_deploy_script (timeout_cmd, UE_terminate_missing_procs) + ' \n' + #task_UE = task_UE + 'sleep ' + str(timeout_cmd) + ' \n' + task_UE = task_UE + 'handle_ctrl_c' + '\n' + task_UE = task_UE + ' ) > ' + logfile_task_UE_out + ' 2>&1 ' + write_file(logfile_task_UE, task_UE, mode="w") + #task_UE = 'echo \" ' + task_UE + '\" > ' + logfile_script_UE + ' 2>&1 ; ' + task_UE + + logfile_compile_EPC = logdir_EPC + '/EPC_compile' + '_' + str(run) + '_.log' + logfile_compile_HSS = logdir_EPC + '/HSS_compile' + '_' + str(run) + '_.log' + logfile_exec_EPC = logdir_EPC + '/EPC_exec' + '_' + str(run) + '_.log' + logfile_pre_exec_EPC = logdir_EPC + '/EPC_pre_exec' + '_' + str(run) + '_.log' + logfile_exec_HSS = logdir_EPC + '/HSS_exec' + '_' + str(run) + '_.log' + logfile_traffic_EPC = logdir_EPC + '/EPC_traffic' + '_' + str(run) + '_.log' + logfile_task_EPC_out = logdir_EPC + '/EPC_task_out' + '_' + str(run) + '_.log' + logfile_task_EPC = logdir_local_testcase + '/EPC_task' + '_' + str(run) + '_.log' + logfile_task_EPC_compile_out = logdir_EPC + '/EPC_task_compile_out' + '_' + str(run) + '_.log' + logfile_task_EPC_compile = logdir_local_testcase + '/EPC_task_compile' + '_' + str(run) + '_.log' + logfile_local_traffic_EPC_out = logdir_local_testcase + '/EPC_traffic' + '_' + str(run) + '_.log' + +# task_EPC_compile = ' ( uname -a ; date \n' +# task_EPC_compile = task_EPC_compile + 'array_exec_pid=()' + '\n' +# task_EPC_compile = task_EPC_compile + 'cd ' + logdirOpenaircnRepo + ' ; source oaienv \n' +# task_EPC_compile = task_EPC_compile + update_config_file(oai_EPC, EPC_config_file, logdirOpenaircnRepo, logdirOpenaircnRepo+'/TEST/autotests/tools/search_repl.py') + '\n' +# task_EPC_compile = task_EPC_compile + 'source BUILD/TOOLS/build_helper \n' +# if EPC_compile_prog != "": +# task_EPC_compile = task_EPC_compile + '(' + EPC_compile_prog + ' ' + EPC_compile_prog_args + ' ) > ' + logfile_compile_EPC + ' 2>&1 \n' +# if HSS_compile_prog != "": +# task_EPC_compile = task_EPC_compile + '(' + HSS_compile_prog + ' ' + HSS_compile_prog_args + ' ) > ' + logfile_compile_HSS + ' 2>&1 \n' +# task_EPC_compile = task_EPC_compile + ' ) > ' + logfile_task_EPC_compile_out + ' 2>&1 ' +# write_file(logfile_task_EPC_compile, task_EPC_compile, mode="w") + + task_EPC = ' ( uname -a ; date \n' + task_EPC = task_EPC + ' export OPENAIRCN_TESTDIR=' + logdir_EPC + '\n' + task_EPC = task_EPC + 'array_exec_pid=()' + '\n' + task_EPC = task_EPC + 'cd ' + logdirOpenaircnRepo + '; source oaienv\n' + task_EPC = task_EPC + 'source BUILD/TOOLS/build_helper \n' + if EPC_pre_exec != "": + task_EPC = task_EPC + ' ( date; ' + EPC_pre_exec + ' '+ EPC_pre_exec_args + ' ) > ' + logfile_pre_exec_EPC + ' 2>&1 \n' + if HSS_main_exec != "": + task_EPC = task_EPC + '( date; ' + addsudo (HSS_main_exec + ' ' + HSS_main_exec_args, mypassword) + ' ) > ' + logfile_exec_HSS + ' 2>&1 & \n' + task_EPC = task_EPC + 'array_exec_pid+=($!) \n' + task_EPC = task_EPC + 'echo HSS_main_exec PID = $! \n' + if EPC_main_exec != "": + task_EPC = task_EPC + '( date; ' + addsudo (EPC_main_exec + ' ' + EPC_main_exec_args, mypassword) + ' ) > ' + logfile_exec_EPC + ' 2>&1 & \n' + task_EPC = task_EPC + 'array_exec_pid+=($!) \n' + task_EPC = task_EPC + 'echo EPC_main_exec PID = $! \n' + if EPC_traffic_exec != "": + cmd_traffic = EPC_traffic_exec + ' ' + EPC_traffic_exec_args + if cmd_traffic.find('-c') >= 0: + cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 60) + task_EPC = task_EPC + '( date; ' + cmd_traffic + ' ) > ' + logfile_traffic_EPC + ' 2>&1 & \n' + task_EPC = task_EPC + 'array_exec_pid+=($!) \n' + task_EPC = task_EPC + 'echo EPC_traffic_exec PID = $! \n' + #terminate the EPC test case after timeout_cmd seconds + task_EPC = task_EPC + finalize_deploy_script (timeout_cmd, EPC_terminate_missing_procs) + '\n' + #task_EPC = task_EPC + 'sleep ' + str(timeout_cmd) + '\n' + task_EPC = task_EPC + 'handle_ctrl_c' '\n' + task_EPC = task_EPC + ' ) > ' + logfile_task_EPC_out + ' 2>&1 ' + write_file(logfile_task_EPC, task_EPC, mode="w") + + #first we compile all the programs +# thread_EPC = oaiThread(1, "EPC_thread", EPCMachine, user, password , task_EPC_compile, False, timeout_thread) + thread_eNB = oaiThread(2, "eNB_thread", eNBMachine, user, password , task_eNB_compile, False, timeout_thread) + thread_UE = oaiThread(3, "UE_thread", UEMachine, user, password , task_UE_compile, False, timeout_thread) + if RRHMachine != '': + thread_RRH = oaiThread(4, "RRH_thread", RRHMachine, user, password , task_RRH_compile, False, timeout_thread) + threads=[] + threads.append(thread_eNB) + threads.append(thread_UE) +# threads.append(thread_EPC) + if RRHMachine != '': + threads.append(thread_RRH) + # Start new Threads + thread_eNB.start() + thread_UE.start() +# thread_EPC.start() + if RRHMachine != '': + thread_RRH.start() + #Wait for all the compile threads to complete + for t in threads: + t.join() + + #Now we execute all the threads +# thread_EPC = oaiThread(1, "EPC_thread", EPCMachine, user, password , task_EPC, False, timeout_thread) + thread_eNB = oaiThread(2, "eNB_thread", eNBMachine, user, password , task_eNB, False, timeout_thread) + thread_UE = oaiThread(3, "UE_thread", UEMachine, user, password , task_UE, False, timeout_thread) + if RRHMachine != '': + thread_RRH = oaiThread(4, "RRH_thread", RRHMachine, user, password , task_RRH, False, timeout_thread) + threads=[] + threads.append(thread_eNB) + threads.append(thread_UE) +# threads.append(thread_EPC) + if RRHMachine != '': + threads.append(thread_RRH) + # Start new Threads + + thread_eNB.start() + thread_UE.start() +# thread_EPC.start() + if RRHMachine != '': + thread_RRH.start() + #Wait for all the compile threads to complete + for t in threads: + t.join() + #Now we get the log files from remote machines on the local machine + if RRHMachine != '': + cleanOldProgramsAllMachines([oai_eNB, oai_UE, oai_EPC, oai_RRH] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB, logdir_UE, logdir_EPC, logdir_RRH], logdirOAI5GRepo) + else: + cleanOldProgramsAllMachines([oai_eNB, oai_UE] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB, logdir_UE, logdir_EPC], logdirOAI5GRepo) +# cleanOldProgramsAllMachines([oai_eNB, oai_UE, oai_EPC] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB, logdir_UE, logdir_EPC], logdirOAI5GRepo) + logfile_UE_stop_script_out = logdir_UE + '/UE_stop_script_out' + '_' + str(run) + '_.log' + logfile_UE_stop_script = logdir_local_testcase + '/UE_stop_script' + '_' + str(run) + '_.log' + + if UE_stop_script != "": + cmd = ' ( uname -a ; date \n' + cmd = cmd + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + cmd = cmd + 'env |grep OPENAIR \n' + 'array_exec_pid=() \n' + cmd = cmd + UE_stop_script + '\n' + cmd = cmd + ') > ' + logfile_UE_stop_script_out + ' 2>&1 ' + write_file(logfile_UE_stop_script , cmd, mode="w") +# thread_UE = oaiThread(4, "UE_thread", UEMachine, user, password , cmd, False, timeout_thread) +# thread_UE.start() +# thread_UE.join() + + #Now we change the permissions of the logfiles to avoid some of them being with root permissions + cmd = 'sudo -E chown -R ' + user + ' ' + logdir_eNB + res= oai_eNB.send_recv(cmd) +# print "Changing permissions of logdir <" + logdir_eNB + "> in eNB machine..." + res + + cmd = 'sudo -E chown -R ' + user + ' ' + logdir_UE +# print cmd + res= oai_UE.send_recv(cmd) +# print res +# print "Changing permissions of logdir <" + logdir_UE + "> in UE machine..." + res + + cmd = 'sudo -E chown -R ' + user + ' ' + logdir_EPC +# res= oai_EPC.send_recv(cmd) +# print "Changing permissions of logdir <" + logdir_EPC + "> in EPC machine..." + res + + if RRHMachine != '': + cmd = 'sudo -E chown -R ' + user + ' ' + logdir_RRH + res= oai_RRH.send_recv(cmd) +# print "Changing permissions of logdir <" + logdir_RRH + "> in RRH machine..." + res + + print "Copying files from EPCMachine : " + EPCMachine + "logdir_EPC = " + logdir_EPC +# SSHSessionWrapper(EPCMachine, user, None, password, logdir_EPC, logdir_local + '/cmake_targets/autotests/log/'+ testcasename, "get_all") + + print "Copying files from eNBMachine " + eNBMachine + "logdir_eNB = " + logdir_eNB + SSHSessionWrapper(eNBMachine, user, None, password, logdir_eNB, logdir_local + '/cmake_targets/autotests/log/'+ testcasename, "get_all") + + print "Copying files from UEMachine : " + UEMachine + "logdir_UE = " + logdir_UE + SSHSessionWrapper(UEMachine, user, None, password, logdir_UE, logdir_local + '/cmake_targets/autotests/log/'+ testcasename, "get_all") + + if RRHMachine != '': + print "Copying files from RRHMachine : " + RRHMachine + "logdir_RRH = " + logdir_RRH + SSHSessionWrapper(RRHMachine, user, None, password, logdir_RRH, logdir_local + '/cmake_targets/autotests/log/'+ testcasename, "get_all") + + + #Currently we only perform throughput tests + tput_run_string='' + result, tput_string = tput_test_search_expr(eNB_search_expr_true, logfile_local_traffic_eNB_out) + tput_run_string = tput_run_string + tput_string + run_result=run_result&result + result, tput_string = tput_test_search_expr(EPC_search_expr_true, logfile_local_traffic_EPC_out) + run_result=run_result&result + tput_run_string = tput_run_string + tput_string + result, tput_string = tput_test_search_expr(UE_search_expr_true, logfile_local_traffic_UE_out) + run_result=run_result&result + tput_run_string = tput_run_string + tput_string + + if run_result == 1: + run_result_string = ' RUN_'+str(run) + ' = PASS' + else: + run_result_string = ' RUN_'+str(run) + ' = FAIL' + + #If there is assertion, we mark the test case as failure as most likely eNB crashed + cmd = "grep -ilr \"assertion\" " + logdir_local_testcase + " | cat " + cmd_out = subprocess.check_output ([cmd], shell=True) + if len(cmd_out) !=0 : + run_result=0 + run_result_string = ' RUN_'+str(run) + ' = FAIL(Assert)' + + #If there is thread busy error, we mark the test case as failure as most likely eNB crashed + cmd = "grep -ilr \"thread busy\" " + logdir_local_testcase + " | cat " + cmd_out = subprocess.check_output ([cmd], shell=True) + if len(cmd_out) !=0: + run_result=0 + run_result_string = ' RUN_'+str(run) + ' = FAIL(Thread_Busy)' + + run_result_string = run_result_string + tput_run_string + + test_result=test_result & run_result + test_result_string=test_result_string + run_result_string + + oai_eNB.disconnect() + oai_UE.disconnect() +# oai_EPC.disconnect() + #We need to close the new ssh session that was created + #if index_eNBMachine == index_EPCMachine: + # oai_EPC.disconnect() + #Now we finalize the xml file of the test case + end_time=time.time() + duration= end_time - start_time + xmlFile = logdir_local + '/cmake_targets/autotests/log/'+ testcasename + '/test.' + testcasename + '.xml' + if test_result ==0: + result='FAIL' + else: + result = 'PASS' + xml="\n \n" + write_file(xmlFile, xml, mode="w") + + + +# \brief handler for executing test cases (lte-softmodem-noS1) +# \param testcase name of testcase +# \param oldprogramList list of programs which must be terminated before running a test case +# \param logdirOAI5GRepo directory on remote machine which has openairinterface5g repo installed +# \param logdirOpenaircnRepo directory on remote machine which has openair-cn repo installed +# \param MachineList list of all machines on which test cases can be run +# \param user username with which to login +# \param password password with which to login +# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) +# \param ExmimoRfStop command to stop EXMIMO Card +# \param nruns_lte-softmodem global parameter to override number of runs (nruns) within the test case +def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRepo , logdirOpenaircnRepo, MachineList, user, password, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, timeout_cmd): + #We ignore the password sent to this function for secuirity reasons for password present in log files + #It is recommended to add a line in /etc/sudoers that looks something like below. The line below will run sudo without password prompt + # your_user_name ALL=(ALL:ALL) NOPASSWD: ALL + + indent="\t" + threads=[] + + # + # Test case parameters + # ----------------------------------------------------------------------------- + testcase_verdict = 'PASS' + testcase_time_start = datetime.datetime.now() + testcase_name = testcase.get('id') + testcase_class = testcase.findtext('class',default='') + testcase_desc = testcase.findtext('desc',default='') + if timeout_cmd == '': + timeout_cmd = testcase.findtext('TimeOut_cmd',default='') + timeout_cmd = int(float(timeout_cmd)) + timeout_thread = timeout_cmd + 60 #Timeout_thread is more than that of cmd to have room for compilation time, etc + if nruns_lte_softmodem == '': + nruns = testcase.findtext('nruns',default='') + else: + nruns = nruns_lte_softmodem + nruns = int(float(nruns)) + tags = testcase.findtext('tags',default='') + + max_ntries = testcase.findtext('max_ntries',default='') + if max_ntries : + max_ntries = int(float(max_ntries)) + else : + max_ntries = nruns + + print( indent + "> testcase time start : " + str(testcase_time_start) ) + print( indent + "> testcase class : " + testcase_class ) + print( indent + "> testcase description : " + testcase_desc ) + print( indent + "> testcase timeout : " + str(timeout_cmd) ) + print( indent + "> testcase thread timeout : " + str(timeout_thread) ) + print( indent + "> number of runs : " + str(nruns) ) + print( indent + "> number of max tries : " + str(max_ntries) ) + print( indent + "> testcase tags : " + tags ) + + logdir_local_testcase = openairdir_local + '/cmake_targets/autotests/log/'+ testcasename + logdir_eNB_testcase = logdirOAI5GRepo +'/cmake_targets/autotests/log/'+ testcasename + logdir_UE_testcase = logdirOAI5GRepo +'/cmake_targets/autotests/log/'+ testcasename + + # + # Local checks for test cases + # ----------------------------------------------- + + # Logging directory + if (not os.path.exists(logdir_local_testcase)): + os.system('mkdir -p ' + logdir_local_testcase) + + # + # REMOTE MACHINE COMPILATION + # ------------------------------------------------ + + eNBMachine = testcase.findtext('eNB',default='') + eNB_config_file = testcase.findtext('eNB_config_file',default='') + eNB_compile_prog = testcase.findtext('eNB_compile_prog',default='') + eNB_compile_prog_args = testcase.findtext('eNB_compile_prog_args',default='') + + logfile_compile_eNB = logdir_eNB_testcase + '/eNB_compile.log' + logfile_task_eNB_compile_out = logdir_eNB_testcase + '/eNB_task_compile_out.log' + logfile_task_eNB_compile = logdir_local_testcase + '/eNB_task_compile.log' + + # Check that machine is in test setup machine list + print( Fore.WHITE + indent + "> testcase eNB machine :"), + if (eNBMachine not in MachineList): + print( Fore.RED + eNBMachine + " not in test setup machine list") + testcase_verdict = 'INCON' + else : + print eNBMachine, + # get machine description + eNBMachineDesc = MachineDescDic[eNBMachine] + index_eNBMachine = MachineList.index(eNBMachine) + # check that openairinterface is installed on machine + oai_eNB = openair('localdomain', eNBMachine) + oai_eNB.connect(user, password) + cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep --color=never OPENAIR' + res= oai_eNB.send_recv(cmd) + m = re.search('OPENAIR_HOME', res, re.DOTALL) + if m: + print + # Create testcase directory on remote eNB + cmd = 'rm -fr ' + logdir_eNB_testcase + ' ; mkdir -p ' + logdir_eNB_testcase + result = oai_eNB.send_recv(cmd) + + # Check if we need to compile lte-softmodem-noS1 on remote machine + eNB_compile_cmd = eNB_compile_prog + ' '+ eNB_compile_prog_args + if ('last_compile_prog' in eNBMachineDesc) and eNBMachineDesc['last_compile_prog'] == eNB_compile_cmd: + print( Fore.WHITE + indent + "> eNB machine compilation : skipped -> "+eNB_compile_cmd ) + else: + print( Fore.WHITE + indent + "> eNB machine compilation : triggered -> "+eNB_compile_cmd ) + eNBMachineDesc['last_compile_prog'] = eNB_compile_prog + ' '+ eNB_compile_prog_args # if last compilation is the same do not compile again + task_eNB_compile = ' ( uname -a ; date \n' + task_eNB_compile = task_eNB_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_eNB_compile = task_eNB_compile + 'env |grep OPENAIR \n' + task_eNB_compile = task_eNB_compile + update_config_file(oai_eNB, eNB_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' + if eNB_compile_cmd != "": + task_eNB_compile = task_eNB_compile + ' ( ' + eNB_compile_cmd + ' ) > ' + logfile_compile_eNB + ' 2>&1 \n' + task_eNB_compile = task_eNB_compile + ' date ) > ' + logfile_task_eNB_compile_out + ' 2>&1 ' + write_file(logfile_task_eNB_compile, task_eNB_compile, mode="w") + + + thread_eNB = oaiThread(1, "eNB_thread_compile", eNBMachine, user, password , task_eNB_compile, False, timeout_thread) + threads.append(thread_eNB) + thread_eNB.start() + + else: + print( Fore.RED + " -> OAI5G not properly setup ! please check REMOTE MACHINE PREPARATION step") + testcase_verdict = 'INCON' + + + UEMachine = testcase.findtext('UE',default='') + UE_config_file = testcase.findtext('UE_config_file',default='') + UE_compile_prog = testcase.findtext('UE_compile_prog',default='') + UE_compile_prog_args = testcase.findtext('UE_compile_prog_args',default='') + + logfile_compile_UE = logdir_UE_testcase + '/UE_compile.log' + logfile_task_UE_compile_out = logdir_UE_testcase + '/UE_task_compile_out.log' + logfile_task_UE_compile = logdir_local_testcase + '/UE_task_compile.log' + + # Check that machine is in test setup machine list + print( Fore.WHITE + indent + "> testcase UE machine :"), + if (UEMachine not in MachineList): + print( Fore.RED + UEMachine + " not in test setup machine list") + testcase_verdict = 'INCON' + else : + print UEMachine, + # get machine description + UEMachineDesc = MachineDescDic[UEMachine] + index_UEMachine = MachineList.index(UEMachine) + # check that openairinterface is installed on machine + oai_UE = openair('localdomain', UEMachine) + oai_UE.connect(user, password) + cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep --color=never OPENAIR' + res= oai_UE.send_recv(cmd) + m = re.search('OPENAIR_HOME', res, re.DOTALL) + if m: + print + # Create testcase directory on remote UE + cmd = 'rm -fr ' + logdir_UE_testcase + ' ; mkdir -p ' + logdir_UE_testcase + result = oai_UE.send_recv(cmd) + + # Check if we need to compile lte-softmodem-noS1 on remote machine + UE_compile_cmd = UE_compile_prog + ' '+ UE_compile_prog_args + if ('last_compile_prog' in UEMachineDesc) and UEMachineDesc['last_compile_prog'] == UE_compile_cmd: + print( Fore.WHITE + indent + "> UE machine compilation : skipped -> "+UE_compile_cmd ) + else: + print( Fore.WHITE + indent + "> UE machine compilation : triggered -> "+UE_compile_cmd ) + UEMachineDesc['last_compile_prog'] = UE_compile_prog + ' '+ UE_compile_prog_args + task_UE_compile = ' ( uname -a ; date \n' + task_UE_compile = task_UE_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_UE_compile = task_UE_compile + 'env |grep OPENAIR \n' + task_UE_compile = task_UE_compile + update_config_file(oai_UE, UE_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' + if UE_compile_cmd != "": + task_UE_compile = task_UE_compile + ' ( ' + UE_compile_cmd + ' ) > ' + logfile_compile_UE + ' 2>&1 \n' + task_UE_compile = task_UE_compile + ' date ) > ' + logfile_task_UE_compile_out + ' 2>&1 ' + write_file(logfile_task_UE_compile, task_UE_compile, mode="w") + + thread_UE = oaiThread(2, "UE_thread_compile", UEMachine, user, password , task_UE_compile, False, timeout_thread) + threads.append(thread_UE) + thread_UE.start() + + else: + print( Fore.RED + " -> OAI5G not properly setup ! please check REMOTE MACHINE PREPARATION step") + testcase_verdict = 'INCON' + + + + + + + # Wait for Compilation thread to terminate + #----------------------------------------- + for t in threads: + t.join() + + # TODO check that compilation is succeed + + #first we compile all the programs +# thread_UE = oaiThread(3, "UE_thread", UEMachine, user, password , task_UE_compile, False, timeout_thread) +# threads.append(thread_UE) +# thread_UE.start() + + + + + +# index_UEMachine = MachineList.index(UEMachine) +# oai_UE = openair('localdomain', UEMachine) +# oai_UE.connect(user, password) +# res = oai_UE.send_recv(cmd) +# res = oai_eNB.send_recv(cmd) + + + + # + # RUN LOOP + # ------------------------------------------------ + if testcase_verdict != 'PASS': # if something went wrong to not run test cases + max_ntries=0 + + runs_results = [] + nb_runs = 0 + nb_run_pass = 0 + nb_run_failed = 0 + nb_run_inc = 0 + nb_run_skip = 0 + + nb_seg_fault = 0 + + for run in range(0,max_ntries): + + if nruns == nb_run_pass + nb_run_failed: + break + + nb_runs += 1 + + # + # RUN initialization + # ---------------------------------------------------- + print (Fore.WHITE + indent + "> RUN_"+str(run).zfill(2)+" : " ), + + sys.stdout.flush() + + run_start_time=datetime.datetime.now() + + logdir_local_run = openairdir_local + '/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) + logdir_eNB_run = logdirOAI5GRepo +'/cmake_targets/autotests/log/' + testcasename + '/run_' + str(run) + logdir_UE_run = logdirOAI5GRepo +'/cmake_targets/autotests/log/' + testcasename + '/run_' + str(run) + + cmd = 'rm -fr ' + logdir_eNB_run + ' ; mkdir -p ' + logdir_eNB_run + result = oai_eNB.send_recv(cmd) + cmd = 'rm -fr ' + logdir_UE_run + ' ; mkdir -p ' + logdir_UE_run + result = oai_UE.send_recv(cmd) + cmd = ' rm -fr ' + logdir_local_run + ' ; mkdir -p ' + logdir_local_run + result = os.system(cmd) + + + # + # RUN parametrization + # ---------------------------------------------------- + eNB_pre_exec = testcase.findtext('eNB_pre_exec',default='') + eNB_pre_exec_args = testcase.findtext('eNB_pre_exec_args',default='') + eNB_main_exec = testcase.findtext('eNB_main_exec',default='') + eNB_main_exec_args = testcase.findtext('eNB_main_exec_args',default='') + eNB_traffic_exec = testcase.findtext('eNB_traffic_exec',default='') + eNB_traffic_exec_args = testcase.findtext('eNB_traffic_exec_args',default='') + eNB_terminate_missing_procs = testcase.findtext('eNB_terminate_missing_procs',default='True') + + logfile_exec_eNB = logdir_eNB_run + '/eNB_exec' + '_' + str(run) + '_.log' + logfile_pre_exec_eNB = logdir_eNB_run + '/eNB_pre_exec' + '_' + str(run) + '_.log' + logfile_task_eNB_out = logdir_eNB_run + '/eNB_task_out' + '_' + str(run) + '_.log' + logfile_traffic_eNB = logdir_eNB_run + '/eNB_traffic' + '_' + str(run) + '_.log' + logfile_task_eNB = logdir_local_run + '/eNB_task' + '_' + str(run) + '_.log' + + task_eNB = ' ( uname -a ; date \n' + task_eNB = task_eNB + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_eNB = task_eNB + 'env |grep OPENAIR \n' + 'array_exec_pid=() \n' + if eNB_pre_exec != "": + task_eNB = task_eNB + ' ( date; ' + eNB_pre_exec + ' '+ eNB_pre_exec_args + ' ) > ' + logfile_pre_exec_eNB + ' 2>&1 \n' + if eNB_main_exec != "": + task_eNB = task_eNB + ' ( date; ' + addsudo(eNB_main_exec + ' ' + eNB_main_exec_args, '') + ' ) > ' + logfile_exec_eNB + ' 2>&1 & \n' + task_eNB = task_eNB + 'array_exec_pid+=($!) \n' + task_eNB = task_eNB + 'echo eNB_main_exec PID = $! \n' + if eNB_traffic_exec != "": + cmd_traffic = eNB_traffic_exec + ' ' + eNB_traffic_exec_args + if cmd_traffic.find('-c') >= 0: + cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 80) + task_eNB = task_eNB + ' (date; ' + cmd_traffic + ' ) > ' + logfile_traffic_eNB + ' 2>&1 & \n' + task_eNB = task_eNB + 'array_exec_pid+=($!) \n' + task_eNB = task_eNB + 'echo eNB_traffic_exec PID = $! \n' + #terminate the eNB test case after timeout_cmd seconds + task_eNB = task_eNB + finalize_deploy_script (timeout_cmd, eNB_terminate_missing_procs) + ' \n' + #task_eNB = task_eNB + 'sleep ' + str(timeout_cmd) + ' \n' + task_eNB = task_eNB + 'handle_ctrl_c' + '\n' + task_eNB = task_eNB + ' ) > ' + logfile_task_eNB_out + ' 2>&1 ' + write_file(logfile_task_eNB, task_eNB, mode="w") + + + UE_pre_exec = testcase.findtext('UE_pre_exec',default='') + UE_pre_exec_args = testcase.findtext('UE_pre_exec_args',default='') + UE_main_exec = testcase.findtext('UE_main_exec',default='') + UE_main_exec_args = testcase.findtext('UE_main_exec_args',default='') + UE_traffic_exec = testcase.findtext('UE_traffic_exec',default='') + UE_traffic_exec_args = testcase.findtext('UE_traffic_exec_args',default='') + UE_terminate_missing_procs = testcase.findtext('UE_terminate_missing_procs',default='True') + UE_search_expr_true = testcase.findtext('UE_search_expr_true','') + + logfile_exec_UE = logdir_UE_run + '/UE_exec' + '_' + str(run) + '_.log' + logfile_pre_exec_UE = logdir_UE_run + '/UE_pre_exec' + '_' + str(run) + '_.log' + logfile_task_UE_out = logdir_UE_run + '/UE_task_out' + '_' + str(run) + '_.log' + logfile_traffic_UE = logdir_UE_run + '/UE_traffic' + '_' + str(run) + '_.log' + logfile_task_UE = logdir_local_run + '/UE_task' + '_' + str(run) + '_.log' + + + task_UE = ' ( uname -a ; date \n' + task_UE = task_UE + 'array_exec_pid=()' + '\n' + task_UE = task_UE + 'cd ' + logdirOAI5GRepo + '\n' + task_UE = task_UE + 'source oaienv \n' + task_UE = task_UE + 'source cmake_targets/tools/build_helper \n' + task_UE = task_UE + 'env |grep OPENAIR \n' + if UE_pre_exec != "": + task_UE = task_UE + ' ( date; ' + UE_pre_exec + ' '+ UE_pre_exec_args + ' ) > ' + logfile_pre_exec_UE + ' 2>&1 \n' + if UE_main_exec != "": + task_UE = task_UE + ' ( date; ' + addsudo(UE_main_exec + ' ' + UE_main_exec_args, '') + ' ) > ' + logfile_exec_UE + ' 2>&1 & \n' + task_UE = task_UE + 'array_exec_pid+=($!) \n' + task_UE = task_UE + 'echo UE_main_exec PID = $! \n' + if UE_traffic_exec != "": + cmd_traffic = UE_traffic_exec + ' ' + UE_traffic_exec_args + if cmd_traffic.find('-c') >= 0: + cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 60) + task_UE = task_UE + ' ( date; ' + cmd_traffic + ' ) >' + logfile_traffic_UE + ' 2>&1 & \n' + task_UE = task_UE + 'array_exec_pid+=($!) \n' + task_UE = task_UE + 'echo UE_traffic_exec PID = $! \n' + #terminate the UE test case after timeout_cmd seconds + task_UE = task_UE + finalize_deploy_script (timeout_cmd, UE_terminate_missing_procs) + ' \n' + #task_UE = task_UE + 'sleep ' + str(timeout_cmd) + ' \n' + task_UE = task_UE + 'handle_ctrl_c' + '\n' + task_UE = task_UE + ' ) > ' + logfile_task_UE_out + ' 2>&1 ' + write_file(logfile_task_UE, task_UE, mode="w") + #task_UE = 'echo \" ' + task_UE + '\" > ' + logfile_script_UE + ' 2>&1 ; ' + task_UE + + + + + + + + # + # RUN work + # ---------------------------------------------------- + thread_eNB = oaiThread(1, "eNB_thread", eNBMachine, user, password , task_eNB, False, timeout_thread) + thread_UE = oaiThread(2, "UE_thread", UEMachine, user, password , task_UE, False, timeout_thread) + threads=[] + threads.append(thread_eNB) + threads.append(thread_UE) + thread_eNB.start() + thread_UE.start() + for t in threads: + t.join() + + # + # + #----------------------------------------------------- + cleanOldProgramsAllMachines([oai_eNB, oai_UE] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB_run, logdir_UE_run], logdirOAI5GRepo) + + SSHSessionWrapper(eNBMachine, user, None, password, logdir_eNB_run, logdir_local_testcase, "get_all") + #print "Copying files from UEMachine : " + UEMachine + "logdir_UE = " + logdir_UE + SSHSessionWrapper(UEMachine, user, None, password, logdir_UE_run, logdir_local_testcase, "get_all") + + metric_checks_flag = 1 + + fname = logdir_local_run+ '/UE_exec' + '_' + str(run) + '_.log' + cell_synch_status = analyser.check_cell_synchro(fname) + if cell_synch_status == 'CELL_SYNCH': + print '!!!!!!!!!!!!!! Cell synchronized !!!!!!!!!!!' + else : + print '!!!!!!!!!!!!!! Cell NOT NOT synchronized !!!!!!!!!!!' + metric_checks_flag = 0 + + ue_seg_fault_status = analyser.check_exec_seg_fault(fname) + if ue_seg_fault_status == 'SEG_FAULT' : + nb_seg_fault += 1 + + # + # Check metrics + #---------------------------------------------------- + runs_metrics = [] + run_traffic = [] + + if metric_checks_flag : + verdict = 'PASS' + + # UE side metrics + metricList=testcase.findall('UE_metric') + for metric in metricList: + metric_def = {} + metric_def['id'] = metric.get('id') + metric_def['description'] = metric.get('description') + metric_def['regex'] = metric.get('regex') + metric_def['unit_of_meas'] = metric.get('unit_of_meas') + metric_def['pass_fail_stat']= metric.get('pass_fail_stat') + metric_min_lim = metric.get('min_limit') + if metric_min_lim: + metric_def['min_limit'] = float(metric_min_lim) + metric_max_lim = metric.get('max_limit') + if metric_max_lim: + metric_def['max_limit'] = float(metric_max_lim) + + fname = logdir_local_run+ '/UE_exec' + '_' + str(run) + '_.log' + + args = {'metric' : metric_def, + 'file' : fname } + + metric_extracted = analyser.do_extract_metrics(args) + + print "\t > Metric "+metric_def['id']+" :" + print "\t\t> min = "+ str( metric_extracted['metric_min'] ) + print "\t\t> min_index = "+ str( metric_extracted['metric_min_index'] ) + print "\t\t> max = "+ str( metric_extracted['metric_max'] ) + print "\t\t> max_index = "+ str( metric_extracted['metric_max_index'] ) + print "\t\t> mean = "+ str( metric_extracted['metric_mean'] ) + print "\t\t> median = "+ str( metric_extracted['metric_median'] ) + + verdict = analyser.do_check_verdict(metric_def, metric_extracted) + + metric_fig = logdir_local_run+ '/UE_metric_'+ metric_def['id']+'_' + str(run) + '_.png' + analyser.do_img_metrics(metric_def, metric_extracted, metric_fig) + + + metric_fig_report = '../log/'+ testcasename + '/run_' + str(run) + '/UE_metric_'+ metric_def['id']+'_' + str(run) + '_.png' + + run_metrics = dict( metric_id = metric_def['id'], + metric_desc = metric_def['description'], + metric_uom = metric_def['unit_of_meas'], + metric_min = metric_extracted['metric_min'], + metric_min_index= metric_extracted['metric_min_index'], + metric_max = metric_extracted['metric_max'], + metric_max_index= metric_extracted['metric_max_index'], + metric_mean = metric_extracted['metric_mean'], + metric_median = metric_extracted['metric_median'], + metric_fig = metric_fig_report) + + if metric_def['pass_fail_stat'] : + run_metrics['pass_fail_stat'] = metric_def['pass_fail_stat'] + if metric_min_lim : + run_metrics['pass_fail_min_limit'] = metric_def['min_limit'] + if metric_max_lim : + run_metrics['pass_fail_max_limit'] = metric_def['max_limit'] + + runs_metrics.append(run_metrics) + + # Traffic analysis + if UE_traffic_exec != "": + + fname = logdir_local_run+ '/UE_traffic' + '_' + str(run) + '_.log' + args = {'file' : fname } + traffic_metrics = analyser.do_extract_traffic_metrics(args) + traffic_fig = logdir_local_run+ '/UE_traffic'+'_' + str(run) + '_.png' + analyser.do_img_traffic(traffic_metrics, traffic_fig) + + traffic_fig_report= '../log/'+ testcasename + '/run_' + str(run) + '/UE_traffic'+'_' + str(run) + '_.png' + + dur_pass_fail_crit = 'none' + if traffic_metrics['traffic_count'] == 0 : + verdict = 'FAIL' + elif UE_search_expr_true != "": + traffic_duration_limit = float(UE_search_expr_true) + dur_pass_fail_crit = str(traffic_duration_limit) + # print 'traffic_duration_limit = '+str(traffic_duration_limit) + # print 'traffic_metrics[interval_stop_max] = '+str(traffic_metrics['interval_stop_max']) + if traffic_metrics['interval_stop_max'] < traffic_duration_limit : + verdict = 'FAIL' + + + run_traffic = dict( traffic_count = traffic_metrics['traffic_count'], + bw_min = traffic_metrics['bw_min'], + bw_max = traffic_metrics['bw_max'], + bw_mean = traffic_metrics['bw_mean'], + bw_median = traffic_metrics['bw_median'], + jitter_min = traffic_metrics['jitter_min'], + jitter_max = traffic_metrics['jitter_max'], + jitter_mean = traffic_metrics['jitter_mean'], + jitter_median = traffic_metrics['jitter_median'], + rl_min = traffic_metrics['rl_min'], + rl_max = traffic_metrics['rl_max'], + rl_mean = traffic_metrics['rl_mean'], + rl_median = traffic_metrics['rl_median'], + iperf_duration = traffic_metrics['interval_stop_max'], + dur_pass_fail_crit = dur_pass_fail_crit, + traffic_fig = traffic_fig_report ) + else: + run_traffic = dict( traffic_count = 0) + + else : + verdict = 'SKIP' + + + + # + # RUN verdict and finalization + # ---------------------------------------------------- + run_stop_time=datetime.datetime.now() + run_duration = run_stop_time-run_start_time +# print (Fore.WHITE + ("duration=" :"), + print (Fore.WHITE + indent + "> RUN duration : "+ str(run_duration) +"s" ) + + print (Fore.WHITE + indent + "> RUN verdict :"), + + if verdict == 'PASS': + nb_run_pass += 1 + print ( Fore.GREEN + verdict) + elif verdict == 'FAIL': + nb_run_failed += 1 + testcase_verdict = 'FAIL' + print ( Fore.RED + verdict) + elif verdict == 'SKIP': + nb_run_skip += 1 + print ( Fore.YELLOW + verdict) + else: + nb_run_inc += 1 + if testcase_verdict == 'PASS' : testcase_verdict = 'INCON' + print (Fore.YELLOW+'INCONCLUSIVE') + + run_results = dict( run_id=str(run), + run_start_time = run_start_time, + run_stop_time = run_stop_time , + run_verdict = verdict, + ue_seg_fault_status = ue_seg_fault_status, + run_duration = run_duration, + runs_metrics = runs_metrics, + run_traffic = run_traffic) + runs_results.append(run_results) + + # END RUN LOOP + #---------------------------------------------------- + + # Test case duration + # ---------------------------------- + testcase_time_stop = datetime.datetime.now() + print(Fore.WHITE + indent + "> testcase time stop : " + str(testcase_time_start) ), + print " -> TestCase duration = "+str(testcase_time_stop - testcase_time_start) + + # Save remote log files + # ----------------------------------- + #Now we change the permissions of the logfiles to avoid some of them being with root permissions + cmd = 'sudo -E chown -R ' + user + ' ' + logdir_eNB_testcase + res= oai_eNB.send_recv(cmd) + cmd = 'sudo -E chown -R ' + user + ' ' + logdir_UE_testcase + res= oai_UE.send_recv(cmd) + + # Save remote log files on MTC + #print "Copying files from eNBMachine " + eNBMachine + "logdir_eNB = " + logdir_eNB + SSHSessionWrapper(eNBMachine, user, None, password, logdir_eNB_testcase, openairdir_local + '/cmake_targets/autotests/log/', "get_all") + #print "Copying files from UEMachine : " + UEMachine + "logdir_UE = " + logdir_UE + SSHSessionWrapper(UEMachine, user, None, password, logdir_UE_testcase, openairdir_local + '/cmake_targets/autotests/log/', "get_all") + + oai_eNB.disconnect() + oai_UE.disconnect() + + # Set test case final verdict + # ----------------------------------- + test_result_string = 'do be completed' + + if testcase_verdict == 'PASS': + if nb_run_pass == 0 : + testcase_verdict = 'INCON' + + print(Fore.WHITE + indent + "> testcase final verdict :"), + if testcase_verdict == 'PASS': + print ( Fore.GREEN + testcase_verdict) + elif testcase_verdict == 'FAIL': + print ( Fore.RED + testcase_verdict) + else: + print (Fore.YELLOW+'INCONCLUSIVE') + + duration= testcase_time_stop - testcase_time_start + xmlFile = logdir_local_testcase + '/test.' + testcasename + '.xml' + xml="\n \n" + write_file(xmlFile, xml, mode="w") + + + test_result = dict(testcase_name=testcasename, + testcaseclass=testcaseclass, + testcase_verdict = testcase_verdict, + testcase_time_start=testcase_time_start, + testcase_time_stop=testcase_time_stop, + tags=tags, + nruns=nb_runs, + nb_run_pass = nb_run_pass, + nb_run_skip = nb_run_skip, + nb_run_failed = nb_run_failed, + nb_run_inc=nb_run_inc, + nb_seg_fault = nb_seg_fault, + testcase_timeout=timeout_cmd, + testcase_duration = duration, + testcase_eNBMachine =eNBMachine, + testcase_UEMachine =UEMachine, + runs_results = runs_results) + test_results.append(test_result) + + return testcase_verdict + + + +# mypassword='' +# #addsudo = 'echo \'' + mypassword + '\' | sudo -S -E ' +# addpass = 'echo \'' + mypassword + '\' | ' +# #user = getpass.getuser() + + + + + + + +# eNB_traffic_exec = testcase.findtext('eNB_traffic_exec',default='') +# eNB_traffic_exec_args = testcase.findtext('eNB_traffic_exec_args',default='') +# eNB_terminate_missing_procs = testcase.findtext('eNB_terminate_missing_procs',default='True') +# eNB_search_expr_true = testcase.findtext('eNB_search_expr_true','') +# if re.compile('\w+').match(eNB_search_expr_true) != None: +# eNB_search_expr_true = eNB_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' + + + +# UE_traffic_exec = testcase.findtext('UE_traffic_exec',default='') +# UE_traffic_exec_args = testcase.findtext('UE_traffic_exec_args',default='') +# +# UE_search_expr_true = testcase.findtext('UE_search_expr_true','') +# UE_stop_script = testcase.findtext('UE_stop_script','') +# if re.compile('\w+').match(UE_search_expr_true) != None: +# UE_search_expr_true = UE_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' + + + +# #cleanOldPrograms(oai_eNB, oldprogramList, CleanUpAluLteBox, ExmimoRfStop) +# #cleanOldPrograms(oai_UE, oldprogramList, CleanUpAluLteBox, ExmimoRfStop) +# #cleanOldPrograms(oai_EPC, oldprogramList, CleanUpAluLteBox, ExmimoRfStop) +# logdir_local = os.environ.get('OPENAIR_DIR') +# if logdir_local is None: +# print "Environment variable OPENAIR_DIR not set correctly" +# sys.exit() + + +# print "Updating the config files for ENB/UE/EPC..." +# #updating the eNB/UE/EPC configuration file from the test case +# #update_config_file(oai_eNB, eNB_config_file, logdirOAI5GRepo) +# #update_config_file(oai_UE, UE_config_file, logdirOAI5GRepo) +# #update_config_file(oai_EPC, EPC_config_file, logdirOpenaircnRepo) + +# test_result=1 +# test_result_string='' +# start_time=time.time() + +# for run in range(0,nruns): +# run_result=1 +# run_result_string='' +# logdir_eNB = logdirOAI5GRepo+'/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) +# logdir_UE = logdirOAI5GRepo+'/cmake_targets/autotests/log/'+ testcasename + + + + + +# logfile_traffic_eNB = logdir_eNB + '/eNB_traffic' + '_' + str(run) + '_.log' + + +# logfile_local_traffic_eNB_out = logdir_local_testcase + '/eNB_traffic' + '_' + str(run) + '_.log' +# logfile_tshark_eNB = logdir_eNB + '/eNB_tshark' + '_' + str(run) + '_.log' +# logfile_pcap_eNB = logdir_eNB + '/eNB_tshark' + '_' + str(run) + '_.pcap' +# logfile_pcap_zip_eNB = logdir_eNB + '/eNB_tshark' + '_' + str(run) + '_.pcap.zip' +# logfile_pcap_tmp_eNB = '/tmp/' + '/eNB_tshark' + '_' + str(run) + '_.pcap' + +# task_eNB_compile = ' ( uname -a ; date \n' +# task_eNB_compile = task_eNB_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' +# task_eNB_compile = task_eNB_compile + 'env |grep OPENAIR \n' +# task_eNB_compile = task_eNB_compile + update_config_file(oai_eNB, eNB_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' +# if eNB_compile_prog != "": +# task_eNB_compile = task_eNB_compile + ' ( ' + eNB_compile_prog + ' '+ eNB_compile_prog_args + ' ) > ' + logfile_compile_eNB + ' 2>&1 \n' +# task_eNB_compile = task_eNB_compile + ' date ) > ' + logfile_task_eNB_compile_out + ' 2>&1 ' +# write_file(logfile_task_eNB_compile, task_eNB_compile, mode="w") + + + +# #task_eNB = 'echo \" ' + task_eNB + '\" > ' + logfile_script_eNB + ' 2>&1 ; ' + task_eNB +# logfile_compile_UE = logdir_UE + '/UE_compile' + '_' + str(run) + '_.log' +# logfile_exec_UE = logdir_UE + '/UE_exec' + '_' + str(run) + '_.log' + + + + +# #Now we execute all the threads + + +# #Now we get the log files from remote machines on the local machine +# cleanOldProgramsAllMachines([oai_eNB, oai_UE] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB, logdir_UE, logdir_EPC], logdirOAI5GRepo) + +# logfile_UE_stop_script_out = logdir_UE + '/UE_stop_script_out' + '_' + str(run) + '_.log' +# logfile_UE_stop_script = logdir_local_testcase + '/UE_stop_script' + '_' + str(run) + '_.log' + +# if UE_stop_script != "": +# cmd = ' ( uname -a ; date \n' +# cmd = cmd + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' +# cmd = cmd + 'env |grep OPENAIR \n' + 'array_exec_pid=() \n' +# cmd = cmd + UE_stop_script + '\n' +# cmd = cmd + ') > ' + logfile_UE_stop_script_out + ' 2>&1 ' +# write_file(logfile_UE_stop_script , cmd, mode="w") +# # thread_UE = oaiThread(4, "UE_thread", UEMachine, user, password , cmd, False, timeout_thread) +# # thread_UE.start() +# # thread_UE.join() + + + + +# #Currently we only perform throughput tests +# tput_run_string='' +# result, tput_string = tput_test_search_expr(eNB_search_expr_true, logfile_local_traffic_eNB_out) +# tput_run_string = tput_run_string + tput_string +# run_result=run_result&result +# result, tput_string = tput_test_search_expr(EPC_search_expr_true, logfile_local_traffic_EPC_out) +# run_result=run_result&result +# tput_run_string = tput_run_string + tput_string +# result, tput_string = tput_test_search_expr(UE_search_expr_true, logfile_local_traffic_UE_out) +# run_result=run_result&result +# tput_run_string = tput_run_string + tput_string + +# if run_result == 1: +# run_result_string = ' RUN_'+str(run) + ' = PASS' +# else: +# run_result_string = ' RUN_'+str(run) + ' = FAIL' + +# #If there is assertion, we mark the test case as failure as most likely eNB crashed +# cmd = "grep -ilr \"assertion\" " + logdir_local_testcase + " | cat " +# cmd_out = subprocess.check_output ([cmd], shell=True) +# if len(cmd_out) !=0 : +# run_result=0 +# run_result_string = ' RUN_'+str(run) + ' = FAIL(Assert)' + +# #If there is thread busy error, we mark the test case as failure as most likely eNB crashed +# cmd = "grep -ilr \"thread busy\" " + logdir_local_testcase + " | cat " +# cmd_out = subprocess.check_output ([cmd], shell=True) +# if len(cmd_out) !=0: +# run_result=0 +# run_result_string = ' RUN_'+str(run) + ' = FAIL(Thread_Busy)' + +# run_result_string = run_result_string + tput_run_string + +# test_result=test_result & run_result +# test_result_string=test_result_string + run_result_string + + + + + + + + + +# \brief This function searches if test case is present in list of test cases that need to be executed by user +# \param testcasename the test case to search for +# \param testcasegroup list that is passed from the arguments +# \param test_case_exclude list of test cases excluded from execution (specified in test_case_list.xml) +def search_test_case_group(testcasename, testcasegroup, test_case_exclude): + + if test_case_exclude != "": + testcase_exclusion_list=test_case_exclude.split() + for entry in testcase_exclusion_list: + if entry.find('+') >=0: + match = re.search(entry, testcasename) + if match: + #print "\nSkipping test case as it is found in black list: " + testcasename + return False + else: + match = entry.find(testcasename) + if match >=0: + #print "\nSkipping test case as it is found in black list: " + testcasename + return False + if testcasegroup == '': + return True + else: + testcaselist = testcasegroup.split() + for entry in testcaselist: + if entry.find('+') >=0: + match = re.search(entry, testcasename) + if match: + return True + else: + match = testcasename.find(entry) + if match >=0: + return True + return False + +# \brief thread that cleans up remote machines from pre-existing test case executions +# \param threadID number of thread (for book keeping) +# \param threadname name of thread (for book keeping) +# \param oai handler that can be used to execute programs on remote machines +# \param CleanUpOldProgs list of programs which must be terminated before running a test case (specified in test_case_list.xml) +# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) +# \param ExmimoRfStop command to stop EXMIMO Card +class oaiCleanOldProgramThread (threading.Thread): + def __init__(self, threadID, threadname, oai, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop, logdir, logdirOAI5GRepo): + threading.Thread.__init__(self) + self.threadID = threadID + self.threadname = threadname + self.oai = oai + self.CleanUpOldProgs = CleanUpOldProgs + self.CleanUpAluLteBox = CleanUpAluLteBox + self.ExmimoRfStop = ExmimoRfStop + self.logdir = logdir + self.logdirOAI5GRepo = logdirOAI5GRepo + def run(self): + try: + cleanOldPrograms(self.oai, self.CleanUpOldProgs, self.CleanUpAluLteBox, self.ExmimoRfStop, self.logdir, self.logdirOAI5GRepo) + except Exception, e: + error='' + error = error + ' In class oaiCleanOldProgramThread, function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) + error = error + '\n threadID = ' + str(self.threadID) + '\n threadname = ' + self.threadname + '\n CleanUpOldProgs = ' + self.CleanUpOldProgs + '\n CleanUpAluLteBox = ' + self.CleanUpAluLteBox + '\n ExmimoRfStop = ' + self.ExmimoRfStop + '\n' + error = error + traceback.format_exc() + print error + print "There is error in cleaning up old programs....." + #sys.exit(1) + +# \brief Run parallel threads in all machines for clean up old execution of test cases +# \param oai_list list of handlers that can be used to execute programs on remote machines +# \param CleanUpOldProgs list of programs which must be terminated before running a test case (specified in test_case_list.xml) +# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) +# \param ExmimoRfStop command to stop EXMIMO Card +def cleanOldProgramsAllMachines(oai_list, CleanOldProgs, CleanUpAluLteBox, ExmimoRfStop, logdir_list, logdirOAI5GRepo): + threadId=0 + threadList=[] + index=0 + if len(oai_list)!=len(logdir_list) : + logdir_list=[logdir[0]]*len(oai_list) + + for oai in oai_list: + threadName="cleanup_thread_"+str(threadId) + thread=oaiCleanOldProgramThread(threadId, threadName, oai, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop, logdir_list[index],logdirOAI5GRepo) + threadList.append(thread) + thread.start() + threadId = threadId + 1 + index = index+1 + for t in threadList: + t.join() + + +debug = 0 +pw ='' +i = 0 +dlsim=0 +localshell=0 +GitOAI5GRepo='' +GitOAI5GRepoBranch='' +GitOAI5GHeadVersion='' +user='' +pw='' +testcasegroup='' +NFSResultsShare='' +cleanUpRemoteMachines=False +openairdir_local = os.environ.get('OPENAIR_DIR') +if openairdir_local is None: + print "Environment variable OPENAIR_DIR not set correctly" + sys.exit() +locallogdir = openairdir_local + '/cmake_targets/autotests/log' +reportdir = openairdir_local + '/cmake_targets/autotests/report' +MachineList = '' +MachineListGeneric='' +MachineDescDic={} +flag_remove_logdir=False +flag_start_testcase=False +nruns_lte_softmodem='' +flag_skip_git_head_check=False +flag_skip_oai_install=False +flag_skip_machine_preparation=False +flag_skip_sanity_check=False +Timeout_cmd='' +xmlInputFile=os.environ.get('OPENAIR_DIR')+"/cmake_targets/autotests/testsuite_ue_noS1.xml" + +#print "Number of arguments argc = " + str(len(sys.argv)) +#for index in range(1,len(sys.argv) ): +# print "argv_" + str(index) + " : " + sys.argv[index] + +oai_list = [] + + +i=1 +while i < len (sys.argv): + arg=sys.argv[i] + if arg == '-r': + flag_remove_logdir=True + elif arg == '-s' : + flag_start_testcase=True + elif arg == '-g' : + testcasegroup = sys.argv[i+1].replace("\"","") + i = i +1 + elif arg == '-c': + cleanUpRemoteMachines=True + elif arg == '-5GRepo': + GitOAI5GRepo = sys.argv[i+1] + i = i +1 + elif arg == '-5GRepoBranch': + GitOAI5GRepoBranch = sys.argv[i+1] + i = i +1 + elif arg == '-5GRepoHeadVersion': + GitOAI5GHeadVersion = sys.argv[i+1] + #We now find the branch that corresponds to this Git Head Commit + cmd = "git show-ref --head " + " | grep " + GitOAI5GHeadVersion + cmd_out = subprocess.check_output ([cmd], shell=True) + cmd_out=cmd_out.replace("\n","") + cmd_out = cmd_out.split('/') + GitOAI5GRepoBranch = cmd_out[-1] + if GitOAI5GRepoBranch == '': + print "Error extracting GitBranch from head commit. Exiting now..." + sys.exit(1) + i = i +1 + elif arg == '-u': + user = sys.argv[i+1] + i = i +1 + elif arg == '-p': + pw = sys.argv[i+1] + i = i +1 + elif arg == '-n': + NFSResultsShare = sys.argv[i+1] + i = i +1 + elif arg == '--nrun_lte_softmodem': + nruns_lte_softmodem = sys.argv[i+1] + i = i +1 + elif arg == '-MachineList': + MachineList = sys.argv[i+1] + MachineList = MachineList.replace("\"","") + MachineList = MachineList.replace("\'","") + i = i +1 + elif arg == '-MachineListGeneric': + MachineListGeneric = sys.argv[i+1] + MachineListGeneric = MachineListGeneric.replace("\"","") + MachineListGeneric = MachineListGeneric.replace("\'","") + i = i +1 + elif arg == '--skip-git-head-check': + flag_skip_git_head_check=True + elif arg == '--timeout_cmd': + Timeout_cmd = sys.argv[i+1] + i = i +1 + elif arg == '--skip-oai-install': + flag_skip_oai_install=True + elif arg == '--skip-machine-preparation': + flag_skip_machine_preparation=True + elif arg == '--skip-sanity-check': + flag_skip_sanity_check=True + elif arg == '-h' : + print "-s: This flag *MUST* be set to start the test cases" + print "-r: Remove the log directory in autotests" + print "-g: Run test cases in a group" + print "-c: Run cleanup scripts on remote machines and exit" + print "-5GRepo: Repository for OAI 5G to use to run tests (overrides GitOAI5GRepo in test_case_list.xml)" + print "-5GRepoBranch: Branch for OAI 5G Repository to run tests (overrides the branch in test_case_list.xml)" + print "-5GRepoHeadVersion: Head commit on which to run tests (overrides the branch in test_case_list.xml)" + print "-u: use the user name passed as argument" + print "-p: use the password passed as an argument" + print "-n: Set the NFS share passed as an argument" + print "--nrun_lte_softmodem: Set the number of runs for lte-softmodem test case class" + print "-MachineList : overrides the MachineList parameter in test_case_list.xml" + print "-MachineListGeneric : overrides the MachineListGeneric parameter in test_case_list.xml" + print "--skip-git-head-check: skip checking of GitHead remote/local branch (only for debugging)" + print "--timeout_cmd: Override the default parameter (timeout_cmd) in test_case_list.xml. This parameter is in seconds and should be > 120" + print "--skip-oai-install: Skips the openairinterface5g installer" + print "--skip-machine-preparation: skipp the whole system preparation -> direct to test cases" + print "--skip-sanity-check: skipp the machine sanity checks" + sys.exit() + else : + print "Unrecongnized Option: <" + arg + ">. Use -h to see valid options" + sys.exit() + i= i + 1 + +logdir = '/tmp/' + 'OAITestFrameWork-' + user + '/' +logdirOAI5GRepo = logdir + 'openairinterface5g/' +logdirOpenaircnRepo = logdir + 'openair-cn/' +patchdir = logdirOAI5GRepo + 'cmake_targets/autotests/patches/' +NFSResultsDir = '/mnt/sradio' +cleanupOldProgramsScript = '$OPENAIR_DIR/cmake_targets/autotests/tools/remove_old_programs.bash' + +#Now we parse the xml file for basic configuration +xmlTree = ET.parse(xmlInputFile) +xmlRoot = xmlTree.getroot() + +# +# Read test session configuration +# --------------------------------------------------------------------------------- +print (Fore.YELLOW + '\nStep 0.1 - Read test session configuration') +print (Fore.YELLOW + '-------------------------------------------------') + +test_session_start_time = datetime.datetime.now() +print (Fore.WHITE + ' - start time : '+ str(test_session_start_time)) + +host = os.uname()[1] +print (Fore.WHITE + ' - MTC host : '+host) + + +if user=='': + user = getpass.getuser() +print (Fore.WHITE + ' - user : '+user) + +if pw=='': + pw = getpass.getpass() +print (Fore.WHITE + ' - password : '+pw) + +print (Fore.WHITE + ' - cmd line flags : ') +print (Fore.WHITE + ' + -s : '+str(flag_start_testcase)) +print (Fore.WHITE + ' + -r : '+str(flag_remove_logdir)) +print (Fore.WHITE + ' + -c : '+str(cleanUpRemoteMachines)) +print (Fore.WHITE + ' + --skip-git-head-check : '+str(flag_skip_git_head_check)) +print (Fore.WHITE + ' + --skip-oai-install : '+str(flag_skip_oai_install)) +print (Fore.WHITE + ' + --skip-machine-preparation : '+str(flag_skip_machine_preparation)) +print (Fore.WHITE + ' + --skip-sanity-check : '+str(flag_skip_sanity_check)) + + +print (Fore.WHITE + ' - Test setup basic config : (* -> overwrite by cmd line parameter)') +print (Fore.WHITE + ' + test setup config file : '+str(xmlInputFile)) +print (Fore.WHITE + ' + remote setup dir : '+str(logdir)) +print (Fore.WHITE + ' + remote OAI5G repo : '+str(logdirOAI5GRepo)) +print (Fore.WHITE + ' + remote OpenAirCN repo : '+str(logdirOpenaircnRepo)) + + +if MachineList =='': + MachineList = xmlRoot.findtext('MachineList',default='') +NFSResultsShare = xmlRoot.findtext('NFSResultsShare',default='') +GitOpenaircnRepo = xmlRoot.findtext('GitOpenair-cnRepo',default='') + +if GitOAI5GRepo == '': + GitOAI5GRepo = xmlRoot.findtext('GitOAI5GRepo',default='') + +if GitOAI5GRepoBranch == '': + GitOAI5GRepoBranch = xmlRoot.findtext('GitOAI5GRepoBranch',default='') +if GitOAI5GHeadVersion == '': + GitOAI5GHeadVersion = xmlRoot.findtext('GitOAI5GHeadVersion',default='') + +GitOpenaircnRepoBranch = xmlRoot.findtext('GitOpenair-cnRepoBranch',default='') +CleanUpOldProgs = xmlRoot.findtext('CleanUpOldProgs',default='') +CleanUpAluLteBox = xmlRoot.findtext('CleanUpAluLteBox',default='') +Timeout_execution = int (xmlRoot.findtext('Timeout_execution')) +if MachineListGeneric == '': + MachineListGeneric = xmlRoot.findtext('MachineListGeneric',default='') +TestCaseExclusionList = xmlRoot.findtext('TestCaseExclusionList',default='') +ExmimoRfStop = xmlRoot.findtext('ExmimoRfStop',default='') +if nruns_lte_softmodem == '': + nruns_lte_softmodem = xmlRoot.findtext('nruns_lte-softmodem',default='') + +print (Fore.WHITE + ' + MachineList : '+ MachineList) +print (Fore.WHITE + ' + GitOpenair-cnRepo : '+ GitOpenaircnRepo) +print (Fore.WHITE + ' + GitOAI5GRepo : '+ GitOAI5GRepo) +print (Fore.WHITE + ' + GitOAI5GBranch : '+ GitOAI5GRepoBranch) +print (Fore.WHITE + ' + GitOpenaircnRepoBranch : '+ GitOpenaircnRepoBranch) +print (Fore.WHITE + ' + NFSResultsShare : '+ NFSResultsShare) +print (Fore.WHITE + ' + nruns_lte_softmodem : '+ nruns_lte_softmodem) +print (Fore.WHITE + ' + Timeout_cmd : '+ Timeout_cmd) + + +if GitOAI5GHeadVersion == '': + cmd = "git log --pretty=format:\'%H\' -n 1 origin/"+ GitOAI5GRepoBranch +# cmd = "git show-ref --heads -s "+ GitOAI5GRepoBranch + GitOAI5GHeadVersion = subprocess.check_output ([cmd], shell=True) + GitOAI5GHeadVersion=GitOAI5GHeadVersion.replace("\n","") + + # Print commiter and date : git log -1 --pretty=format:"%an %ad" + +print (Fore.WHITE + ' + GitOAI5GHeadVersion : '+ GitOAI5GHeadVersion) +#print "CleanUpOldProgs = " + CleanUpOldProgs +print (Fore.WHITE + ' + Timeout_execution (s) : '+ str(Timeout_execution)) + +if GitOAI5GHeadVersion == '': + print "Error getting the OAI5GBranch Head version...Exiting" + sys.exit() + +NFSTestsResultsDir = NFSResultsShare + '/'+ GitOAI5GRepoBranch + '/' + GitOAI5GHeadVersion + +#print "NFSTestsResultsDir = " + NFSTestsResultsDir + +OAI5GpatchFileList=xmlRoot.findall('OAI5GPatchFile') + + + +MachineList = MachineList.split() +MachineListGeneric = MachineListGeneric.split() + + +MachineDescDic + + +# +# 'Check Mater Test Controller sanity (MTC)' +# --------------------------------------------------------------------------------- +print (Fore.YELLOW + '\nStep 0.2 - Check Mater Test Controller sanity (MTC)') +print (Fore.YELLOW + '-------------------------------------------------') + +try: + print (Fore.WHITE + ' - check OpenAirInterface environment variable OPENAIR1_DIR... '), + os.environ["OPENAIR1_DIR"] +except KeyError: + print (Fore.RED + 'FAILED') + print "Please set the environment variable OPENAIR1_DIR in the .bashrc or run 'source oaienv' " + exit_prog(1) +print (Fore.GREEN + 'OK') + +try: + print (Fore.WHITE + ' - check OpenAirInterface environment variable OPENAIR2_DIR... '), + os.environ["OPENAIR2_DIR"] +except KeyError: + print (Fore.RED + 'FAILED') + print "Please set the environment variable OPENAIR2_DIR in the .bashrc or run 'source oaienv' " + exit_prog(1) +print (Fore.GREEN + 'OK') + +try: + os.environ["OPENAIR_TARGETS"] +except KeyError: + print "Please set the environment variable OPENAIR_TARGETS in the .bashrc or run 'source oaienv' " + sexit_prog(1) + +print (Fore.WHITE + ' - kill zombie ssh sessions from earlier sessions... '), +cmd='ps aux |grep \"/usr/bin/ssh -q -l ' + user + '\"| tr -s \" \" :| cut -f 2 -d :| xargs kill -9 ' +os.system(cmd) +print (Fore.GREEN + 'DONE') + +if flag_start_testcase == False: + print "You need to start the testcase by passing option -s. Use -h to see all options. Aborting now..." + exit_prog(1) + + +#print "Killing zombie ssh sessions from earlier sessions..." +#cmd='ps aux |grep \"/usr/bin/ssh -q -l guptar\"|tr -s \" \" :|cut -f 2 -d :|xargs kill -9 ' +#cmd = cmd + '; ps aux |grep \"/usr/bin/ssh -q -l ' + user + '\"| tr -s \" \" :| cut -f 2 -d :| xargs kill -9 ' +#os.system(cmd) +#print cmd + +try: + analyser = __import__("lib_autotest_analyser") +except ImportError as err: + print('Import error: ' + str(err)) + exit(0) + +if flag_remove_logdir == True: + print "Removing directory: " + locallogdir + os.system(' rm -fr ' + locallogdir + '; mkdir -p ' + locallogdir ) + +if not os.path.exists(locallogdir): + os.system('mkdir -p ' + locallogdir ) + + +paramiko_logfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/log/paramiko.log') +res=os.system(' echo > ' + paramiko_logfile) +paramiko.util.log_to_file(paramiko_logfile) + + +# +# 'REMOTE MACHINE SANITY CHEKS' +# --------------------------------------------------------------------------------- +print (Fore.YELLOW + '\nStep 0.3 - REMOTE MACHINE SANITY CHEKS') +print (Fore.YELLOW + '-------------------------------------------------') + + +for machine in MachineList: + oai_list.append( openair('localdomain',machine)) + MachineDescDic[machine]={} + + +if not flag_skip_sanity_check: + + if localshell == 0: + try: + index=0 + for machine in MachineList: + print (Fore.WHITE + " - Check sanity for remote machine "+machine) + + oai_list[index].connect(user,pw) + print (Fore.WHITE + " > Checking for sudo permissions for user "+user+ " : "), + result = oai_list[index].send_expect_false('sudo -S -v','may not run sudo',True) + if (result == 'OK'): + print (Fore.GREEN + result ) + else: + print (Fore.RED + result ) + + print (Fore.WHITE + " > Cleaning Older running programs : "), + cleanOldPrograms(oai_list[index], CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop, '$HOME', '/tmp') + print (Fore.WHITE + " Done") + + #result = oai_list[index].send('mount ' + NFSResultsDir, True) + #print "Mounting NFS Share " + NFSResultsDir + "..." + result + + # Check if NFS share is mounted correctly. + #print 'Checking if NFS Share<' + NFSResultsDir + '> is mounted correctly...' + #cmd = 'if grep -qs '+NFSResultsDir+ ' /proc/mounts; then echo \'' + NFSResultsDir + ' is mounted\' ; fi' + #search_expr = NFSResultsDir + ' is mounted' + #print "cmd = " + cmd + #print "search_expr = " + search_expr + #result = oai_list[index].send_expect(cmd, search_expr) + #print "Mount NFS_Results_Dir..." + result + index = index + 1 + + #oai.connect2(user,pw) + #oai.get_shell() + except : + print 'Fail to connect to the machine: '+ machine + sys.exit(1) + else: + pw = '' + oai_list[0].connect_localshell() +else: + print (Fore.RED + " Skipping Machine sanity check...") + + +# +# 'REMOTE MACHINE TEST SETUP CONFIGURATION' +# --------------------------------------------------------------------------------- +print (Fore.YELLOW + '\nStep 0.4 - REMOTE MACHINE PREPARATION') +print (Fore.YELLOW + '-------------------------------------------------') + +if not flag_skip_machine_preparation: + index=0 + threads_init_setup=[] + for oai in oai_list: + try: + print "setting up machine: " + MachineList[index] + #print oai_list[oai].send_recv('echo \''+pw+'\' |sudo -S -v') + #print oai_list[oai].send_recv('sudo su') + #print oai_list[oai].send_recv('who am i') + #cleanUpPrograms(oai_list[oai] + cmd = 'sudo -S -E rm -fr ' + logdir + ' ; mkdir -p ' + logdir + result = oai.send_recv(cmd) + print cmd + + setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' + setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' + cmd = ' ( \n' + #cmd = cmd + 'rm -fR ' + logdir + '\n' + #cmd = cmd + 'mkdir -p ' + logdir + '\n' + cmd = cmd + 'cd '+ logdir + '\n' + cmd = cmd + 'git config --global http.sslVerify false \n' + cmd = cmd + 'git clone '+ GitOAI5GRepo +' \n' + cmd = cmd + 'git clone '+ GitOpenaircnRepo + ' \n' + cmd = cmd + 'cd ' + logdirOAI5GRepo + '\n' + cmd = cmd + 'git checkout ' + GitOAI5GRepoBranch + '\n' + if GitOAI5GHeadVersion : + cmd = cmd + 'git checkout ' + GitOAI5GHeadVersion + '\n' + cmd = cmd + 'git_head=`git ls-remote |grep \'' + GitOAI5GRepoBranch + '\'` \n' + cmd = cmd + 'git_head=($git_head) \n' + cmd = cmd + 'git_head=${git_head[0]} \n' + cmd = cmd + 'echo \"GitOAI5GHeadVersion_remote = $git_head\" \n' + cmd = cmd + 'echo \"GitOAI5GHeadVersion_local = ' + GitOAI5GHeadVersion + '\" \n' + if flag_skip_git_head_check==True: + cmd = cmd + 'echo \"skipping GitHead check...\" \n ' + else: + cmd = cmd + 'if [ \"$git_head\" != \"'+ GitOAI5GHeadVersion + '\" ]; then echo \"error: Git openairinterface5g head version does not match\" ; fi \n' + cmd = cmd + 'source oaienv' + '\n' + if flag_skip_oai_install == False: + cmd = cmd + 'source $OPENAIR_DIR/cmake_targets/tools/build_helper \n' + cmd = cmd + 'echo \"Installing core OAI dependencies...Start\" \n' + cmd = cmd + '$OPENAIR_DIR/cmake_targets/build_oai -I --install-optional-packages \n' + cmd = cmd + 'echo \"Installing core OAI dependencies...Finished\" \n' + #cmd = cmd + 'echo \"Installing BLADERF OAI dependencies...Start\" \n' + #cmd = cmd + 'check_install_bladerf_driver \n' + #cmd = cmd + 'echo \"Installing BLADERF OAI dependencies...Finished\" \n' + #cmd = cmd + 'echo \"Installing USRP OAI dependencies...Start\" \n' + #cmd = cmd + 'check_install_usrp_uhd_driver \n' + #cmd = cmd + 'echo \"Installing USRP OAI dependencies...Finished\" \n' + cmd = cmd + 'cd ' + logdirOpenaircnRepo + '\n' + cmd = cmd + 'git checkout ' + GitOpenaircnRepoBranch + '\n' + cmd = cmd + 'env |grep OPENAIR' + '\n' + cmd = cmd + ' cd ' + logdir + '\n' + cmd = cmd + 'mkdir -p ' + patchdir + '\n' + cmd = cmd + ' ) > ' + setuplogfile + ' 2>&1 \n' + #cmd = cmd + 'echo \' ' + cmd + '\' > ' + setup_script + ' 2>&1 \n ' + #result = oai_list[index].send_recv(cmd, False, 300 ) + write_file(setup_script, cmd, mode="w") + tempThread = oaiThread(index, 'thread_setup_'+str(index)+'_' + MachineList[index] , MachineList[index] , user, pw, cmd, False, 3000) + threads_init_setup.append(tempThread ) + tempThread.start() + index = index + 1 + except Exception, e: + print 'There is error in one of the commands to setup the machine '+ MachineList[index] + error='' + error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) + error = error + traceback.format_exc() + print error + sys.exit(1) + + #Now we wait for all the threads to complete + index = 0 + for t in threads_init_setup: + t.join() + + port = 22 + paramList=[] + sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') + + #Now we copy patch files for u + print( Fore.WHITE + " - Installating patch files on machine " + MachineList[index]) + #Now we copy patch files for u + for patchFile in OAI5GpatchFileList: + localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/patches/')+patchFile.get('name') + remotefile = logdirOAI5GRepo + '/cmake_targets/autotests/patches/'+patchFile.get('name') + if patchFile.get('machine') == MachineList[index] or patchFile.get('machine') == None: + if os.path.isfile(localfile): + print( Fore.WHITE + "\t> PATCH FILE :"+localfile) + paramList=[] + paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) + sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) + cmd = ' cd ' + logdirOAI5GRepo + ' ;git apply cmake_targets/autotests/patches/'+patchFile.get('name') + res = oai_list[index].send_recv(cmd) + #print res + + paramList=[] + + #Now we copy test_case_list.xml on the remote machines + localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/test_case_list.xml') + remotefile = logdirOAI5GRepo + '/cmake_targets/autotests/test_case_list.xml' + # paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) + # sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) + + setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' + setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' + localfile = locallogdir + '/setup_log_' + MachineList[index] + '_.txt' + remotefile = logdir + '/setup_log_' + MachineList[index] + '_.txt' + + sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') + paramList.append ( {"operation":'get', "localfile":localfile, "remotefile":remotefile} ) + sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) + + + cmd = ' cd ' + logdirOAI5GRepo + ' ; source oaienv ; env|grep OPENAIR \n' + res = oai_list[index].send_recv(cmd) + index = index +1 + if os.path.exists(localfile) == 0: + print "Setup log file <" + localfile + "> missing for machine <" + MachineList[index] + ">. Please check the setup log files. Exiting now" + sys.exit(1) + + #Now we process all the test cases + #Now we check if there was error in setup files + + status, out = commands.getstatusoutput('grep ' + ' -il \'error\' ' + locallogdir + '/setup_log*') + if (out != '') : + print "There is error in setup of machines" + print "status = " + str(status) + "\n Check files for error = " + out + print "Exiting now..." + sys.exit(1) + + cleanOldProgramsAllMachines(oai_list, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop, '$HOME' , logdirOAI5GRepo) + if cleanUpRemoteMachines == True: + print "Error while cleaning Remote machines" + print "Exiting now..." + sys.exit(0) + +else: + print (Fore.RED + " Skipping Machine preparation...") + +# ************************************************************************** +# ************************************************************************** +# STEP 2 - TEST SELECTION AND PARAMETRIZATION +# ************************************************************************** +# ************************************************************************** + +print (Fore.YELLOW + '\nStep 2 - TEST SELECTION') +print (Fore.YELLOW + '-------------------------------------------------') + +print (Fore.WHITE + " Parsing test case list for test selection...") +print (Fore.WHITE + " - TestCaseExclusionList : "+TestCaseExclusionList) +print (Fore.WHITE + " - testcasegroup : "+testcasegroup) + + + + +testcaseList=xmlRoot.findall('testCase') + +nb_total_testcases = 0 +nb_total_testcases_softmodem = 0 +nb_total_testcases_softmodem_noS1 = 0 +nb_total_testcases_compilation = 0 +nb_total_testcases_execution = 0 + +nb_run_testcases = 0 +nb_run_testcases_softmodem = 0 +nb_run_testcases_softmodem_noS1 = 0 +nb_run_testcases_compilation = 0 +nb_run_testcases_execution = 0 + + +for testcase in testcaseList: + try: + testcasename = testcase.get('id') + testcaseclass = testcase.findtext('class',default='') + desc = testcase.findtext('desc',default='') + nb_total_testcases+=1 + + run_flag = search_test_case_group(testcasename, testcasegroup, TestCaseExclusionList) + if (run_flag): + nb_run_testcases+=1 + + if testcaseclass == 'lte-softmodem' : + nb_total_testcases_softmodem+=1 + if (run_flag): nb_run_testcases_softmodem+=1 + elif testcaseclass == 'lte-softmodem-noS1': + nb_total_testcases_softmodem_noS1+=1 + if (run_flag): nb_run_testcases_softmodem_noS1+=1 + elif testcaseclass == 'compilation': + nb_total_testcases_compilation+=1 + if (run_flag): nb_run_testcases_compilation+=1 + elif testcaseclass == 'execution': + nb_total_testcases_execution+=1 + if (run_flag): nb_run_testcases_execution+=1 + else : + print "Unknown test case class: " + testcaseclass + sys.exit() + + except Exception, e: + error='' + error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) + error = error + '\n testcasename = ' + testcasename + '\n testcaseclass = ' + testcaseclass + '\n desc = ' + 'desc' + '\n' + error = error + traceback.format_exc() + print error + print "Continuing to next test case..." + +print (Fore.WHITE + " Parsing done...") + +print (Fore.WHITE + " - Total number of test cases : "+str(nb_total_testcases)) +print (Fore.WHITE + " - Total number class softmodem : "+str(nb_total_testcases_softmodem)) +print (Fore.WHITE + " - Total number class softmodem-noS1 : "+str(nb_total_testcases_softmodem_noS1)) +print (Fore.WHITE + " - Total number class compilation : "+str(nb_total_testcases_compilation)) +print (Fore.WHITE + " - Total number class execution : "+str(nb_total_testcases_execution)) +print +print (Fore.WHITE + " - Selected number of test cases : "+str(nb_run_testcases)) +print (Fore.WHITE + " - Selected class softmodem : "+str(nb_run_testcases_softmodem)) +print (Fore.WHITE + " - Selected class softmodem_noS1 : "+str(nb_run_testcases_softmodem_noS1)) +print (Fore.WHITE + " - Selected class compilation : "+str(nb_run_testcases_compilation)) +print (Fore.WHITE + " - Selected class execution : "+str(nb_run_testcases_execution)) + +# ************************************************************************** +# ************************************************************************** +# STEP 3 - TEST CAMPAIGNS +# ************************************************************************** +# ************************************************************************** + +test_results = [] + + +print (Fore.YELLOW + '\nStep 3 - TEST CAMPAIGNS') +print (Fore.YELLOW + '-------------------------------------------------') + +print (Fore.WHITE + " Start test campaign...") + +run_count = 0 +for testcase in testcaseList: + try: + testcasename = testcase.get('id') + testcaseclass = testcase.findtext('class',default='') + + if (search_test_case_group(testcasename, testcasegroup, TestCaseExclusionList)): + run_count+=1 + print (Fore.WHITE + " ("+str(run_count).zfill(3)+"/"+str(nb_run_testcases).zfill(3)+") - test case "+testcasename+" : "), + if testcaseclass == 'lte-softmodem' : + print (Fore.RED + "skipped - lte-softmodem class not supported") + elif testcaseclass == 'lte-softmodem-noS1': + print + handle_testcaseclass_softmodem_noS1 (testcase, CleanUpOldProgs, logdirOAI5GRepo, logdirOpenaircnRepo, MachineList, user, pw, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, Timeout_cmd ) + elif testcaseclass == 'compilation': + print (Fore.RED + "skipped - compilation class not supported") + elif testcaseclass == 'execution': + print (Fore.RED + "skipped - execution class not supported") + else : + print (Fore.RED + "Unknown test case class: " + testcaseclass) + sys.exit() + + except Exception, e: + error='' + error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) + error = error + '\n testcasename = ' + testcasename + '\n testcaseclass = ' + testcaseclass + '\n desc = ' + 'desc' + '\n' + error = error + traceback.format_exc() + print error + print "Continuing to next test case..." + +threadListGlobal=[] + + +# ************************************************************************** +# ************************************************************************** +# STEP 4 - TEST REPORT PRODUCTION +# ************************************************************************** +# ************************************************************************** + + + +test_session_stop_time = datetime.datetime.now() + +print (Fore.YELLOW + '\nStep 4 - TEST REPORT PRODUCTION') +print (Fore.YELLOW + '-------------------------------------------------') + +report_dir = reportdir + '/'+ test_session_start_time.strftime("%Y-%m-%d_%H-%M")+"_"+host + +cmd = 'mkdir -p ' + report_dir +result = os.system(cmd) + +cmd = 'cp -r '+locallogdir+' '+report_dir +result = os.system(cmd) + +context = { + 'report_path' : report_dir, + 'test_session_start_time' : test_session_start_time, + 'test_session_stop_time' : test_session_stop_time, + 'test_session_duration' : test_session_stop_time-test_session_start_time, + 'mtc_host' : host, + 'user' : user, + 'password' : pw, + 'test_results' : test_results, +} + +for test_result in test_results: + cmd = 'mkdir -p ' + report_dir + '/'+ test_result['testcase_name'] + result = os.system(cmd) + + report_file = report_dir + '/'+ test_result['testcase_name'] + '/'+ test_result['testcase_name']+ '_report.html' + + analyser.create_test_report_detailed_html(test_result, report_file ) + + print test_result + + +analyser.create_report_html(context) + +exit_prog(0) + +#print testcaseList +for testcase in testcaseList: + try: + testcasename = testcase.get('id') + testcaseclass = testcase.findtext('class',default='') + desc = testcase.findtext('desc',default='') + #print "Machine list top level = " + ','.join(MachineList) + if search_test_case_group(testcasename, testcasegroup, TestCaseExclusionList) == True: + if testcaseclass == 'lte-softmodem' : + eNBMachine = testcase.findtext('eNB',default='') + UEMachine = testcase.findtext('UE',default='') + EPCMachine = testcase.findtext('EPC',default='') + #index_eNBMachine = MachineList.index(eNBMachine) + #index_UEMachine = MachineList.index(UEMachine) + #index_EPCMachine = MachineList.index(EPCMachine) + if (eNBMachine not in MachineList)|(UEMachine not in MachineList)|(UEMachine not in MachineList): + print "One of the machines is not in the machine list" + print "eNBMachine : " + eNBMachine + "UEMachine : " + UEMachine + "EPCMachine : " + EPCMachine + "MachineList : " + ','.join(MachineList) + print "testcasename = " + testcasename + " class = " + testcaseclass + threadListGlobal = wait_testcaseclass_generic_threads(threadListGlobal, Timeout_execution) + #cleanOldProgramsAllMachines(oai_list, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop) + #handle_testcaseclass_softmodem (testcase, CleanUpOldProgs, logdirOAI5GRepo, logdirOpenaircnRepo, MachineList, user, pw, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, Timeout_cmd ) + + #The lines below are copied from below to trace the failure of some of the machines in test setup. These lines below need to be removed in long term +# print "Creating xml file for overall results..." +# cmd = "cat $OPENAIR_DIR/cmake_targets/autotests/log/*/*.xml > $OPENAIR_DIR/cmake_targets/autotests/log/results_autotests.xml " +# res=os.system(cmd) +# os.system('sync') +# print "Now copying files to NFS Share" +# oai_localhost = openair('localdomain','localhost') +# oai_localhost.connect(user,pw) +# cmd = ' mkdir -p ' + NFSTestsResultsDir +# print cmd +# res = oai_localhost.send_recv(cmd) +# print res + + # print "Copying files from GilabCI Runner Machine : " + host + " .locallogdir = " + locallogdir + ", NFSTestsResultsDir = " + NFSTestsResultsDir + # SSHSessionWrapper('localhost', user, None, pw , NFSTestsResultsDir , locallogdir, "put_all") + # oai_localhost.disconnect() + + elif (testcaseclass == 'compilation'): + threadListGlobal = handle_testcaseclass_generic (testcasename, threadListGlobal, CleanUpOldProgs, logdirOAI5GRepo, MachineListGeneric, user, pw, CleanUpAluLteBox,Timeout_execution, ExmimoRfStop) + elif (testcaseclass == 'execution'): + threadListGlobal = handle_testcaseclass_generic (testcasename, threadListGlobal, CleanUpOldProgs, logdirOAI5GRepo, MachineListGeneric, user, pw, CleanUpAluLteBox, Timeout_execution, ExmimoRfStop) + else : + print "Unknown test case class: " + testcaseclass + sys.exit() + + except Exception, e: + error='' + error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) + error = error + '\n testcasename = ' + testcasename + '\n testcaseclass = ' + testcaseclass + '\n desc = ' + 'desc' + '\n' + error = error + traceback.format_exc() + print error + print "Continuing to next test case..." + #sys.exit(1) + + +print "Exiting the test cases execution now. Waiting for existing threads to complete..." + +for param in threadListGlobal: + thread_id = param["thread_id"] + thread_id.join() + +print "Creating xml file for overall results..." +cmd = "cat $OPENAIR_DIR/cmake_targets/autotests/log/*/*.xml > $OPENAIR_DIR/cmake_targets/autotests/log/results_autotests.xml " +res=os.system(cmd) + +print "Now copying files to NFS Share" +oai_localhost = openair('localdomain','localhost') +oai_localhost.connect(user,pw) +cmd = 'mkdir -p ' + NFSTestsResultsDir +print cmd +res = oai_localhost.send_recv(cmd) +print res + +print "Copying files from GilabCI Runner Machine : " + host + " .locallogdir = " + locallogdir + ", NFSTestsResultsDir = " + NFSTestsResultsDir +SSHSessionWrapper('localhost', user, None, pw , NFSTestsResultsDir , locallogdir, "put_all") + +cmd = "cat " + NFSTestsResultsDir + "/log/*/*.xml > " + NFSTestsResultsDir + "/log/results_autotests.xml" +res = oai_localhost.send_recv(cmd) + +oai_localhost.disconnect() + +sys.exit() + + + + + + + +run_count = 0 +for testcase in testcaseList: + try: + testcasename = testcase.get('id') + testcaseclass = testcase.findtext('class',default='') + + if (search_test_case_group(testcasename, testcasegroup, TestCaseExclusionList)): + run_count+=1 + print (Fore.WHITE + " ("+str(run_count).zfill(3)+"/"+str(nb_run_testcases).zfill(3)+") - test case "+testcasename+" : "), + if testcaseclass == 'lte-softmodem' : + print (Fore.RED + "skipped - lte-softmodem class not supported") + elif testcaseclass == 'lte-softmodem-noS1': + print + + testcase_verdict = 'PASS' + testcase_time_start = datetime.datetime.now() + testcase_name = testcase.get('id') + testcase_desc = testcase.findtext('desc',default='') + timeout_cmd = testcase.findtext('TimeOut_cmd',default='') + timeout_cmd = int(float(timeout_cmd)) + timeout_thread = timeout_cmd + 300 #Timeout_thread is more than that of cmd to have room for compilation time, etc + if nruns_lte_softmodem == '': + nruns = testcase.findtext('nruns',default='') + else: + nruns = nruns_lte_softmodem + nruns = int(float(nruns)) + tags = testcase.findtext('tags',default='') + testcase_time_stop = datetime.datetime.now() + + test_result = dict(testcase_name=testcase_name, + testcaseclass=testcaseclass, + testcase_verdict = testcase_verdict, + testcase_time_start=testcase_time_start, + testcase_time_stop=testcase_time_stop, + tags=tags, + nruns=nruns, + testcase_timeout=timeout_cmd, + testcase_duration = testcase_time_stop-testcase_time_start, + testcase_eNBMachine ="TOTO", + testcase_UEMachine ="TITI") + test_results.append(test_result) + + + elif testcaseclass == 'compilation': + print (Fore.RED + "skipped - compilation class not supported") + elif testcaseclass == 'execution': + print (Fore.RED + "skipped - execution class not supported") + else : + print (Fore.RED + "Unknown test case class: " + testcaseclass) + sys.exit() + + except Exception, e: + error='' + error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) + error = error + '\n testcasename = ' + testcasename + '\n testcaseclass = ' + testcaseclass + '\n desc = ' + 'desc' + '\n' + error = error + traceback.format_exc() + print error + print "Continuing to next test case..." diff --git a/cmake_targets/autotests/testsuite_ue_noS1_eurecom.xml b/cmake_targets/autotests/testsuite_ue_noS1_eurecom.xml new file mode 100644 index 0000000000..25a4a652e5 --- /dev/null +++ b/cmake_targets/autotests/testsuite_ue_noS1_eurecom.xml @@ -0,0 +1,3214 @@ + + +imb182-desktop yanbo-M4HM87P-00 + /mnt/sradio/TEST_RESULTS/ + https://gitlab.eurecom.fr/oai/openairinterface5g.git + https://gitlab.eurecom.fr/oai/openair-cn.git --> + develop + + + + + + + + + develop + oaisim oaisim_nos1 lte-softmodem lte-softmodem-nos1 mme_gw run_epc auth_request run_hss oai_hss mme spgw hss hss_sim configure_cots* wvdial iperf iperf_script iperf_script_phone ping tshark rrh_gw iperf3 iperf3_script iperf3_script_phone pppd + sudo -S -E /opt/ltebox/tools/stop_ltebox +$OPENAIR_DIR/cmake_targets/build_oai -w EXMIMO -c; sudo -S -E $OPENAIR_DIR/cmake_targets/tools/stop_exmimo2; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_huaweiE398_ue.py --reset-ue; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue; uname -a; sudo -E dmesg + 36000 + + + yanbo-M4HM87P-00 + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS00 + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS00 + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 1 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS01 + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 1 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS01 + 36 + + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS09 + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS09 + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS16 + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS16 + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS10 + + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS10 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS17 + + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS17 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 18 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS18 + + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 18 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS18 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS19 + + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS19 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 20 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS20 + + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 20 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS20 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 21 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS21 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 21 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS21 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 22 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS22 + + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 22 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS22 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 23 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS23 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 23 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS23 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 24 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS24 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 24 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS24 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 25 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS25 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 25 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS25 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 26 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS26 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 26 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS26 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS27 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS27 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS28 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS28 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 18000 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_STAB.BAND7.5MHZ.MCS27 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_STAB.BAND7.5MHZ.MCS27 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 50 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r50 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.10MHZ.MCS27 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 50 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r50 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.10MHZ.MCS27 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 50 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r50 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.10MHZ.MCS28 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 50 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r50 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.10MHZ.MCS19 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 512K + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS00 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 512K + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS00 + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS09 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS09 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS10 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS10 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS16 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS16 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS17 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS17 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS19 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS19 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS27 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 3600 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 + + iperf -s -i 1 -u + + 2800 + + False + UE_USRP.NOS1.DATA_IPERF_STAB.BAND7.5MHZ.MCS27 + 16 + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 + source ./targets/bin/init_nas_nos1 UE + + sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS27 + 36 + + + From 0277475bef1d06cc8926a7d7ec740fff70823c2b Mon Sep 17 00:00:00 2001 From: ROBERT Benoit Date: Tue, 25 Oct 2016 17:47:58 +0200 Subject: [PATCH 253/413] during 'harmony' developments initialisation of some --phy-test parameters were removed --- targets/RT/USER/lte-softmodem.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 117beb68d7..1692c2164f 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1608,6 +1608,11 @@ int main( int argc, char **argv ) PHY_vars_eNB_g[0][CC_id] = init_lte_eNB(frame_parms[CC_id],0,frame_parms[CC_id]->Nid_cell,abstraction_flag); PHY_vars_eNB_g[0][CC_id]->CC_id = CC_id; + PHY_vars_eNB_g[0][CC_id]->ue_dl_rb_alloc=0x1fff; + PHY_vars_eNB_g[0][CC_id]->target_ue_dl_mcs=target_dl_mcs; + PHY_vars_eNB_g[0][CC_id]->ue_ul_nb_rb=6; + PHY_vars_eNB_g[0][CC_id]->target_ue_ul_mcs=target_ul_mcs; + if (phy_test==1) PHY_vars_eNB_g[0][CC_id]->mac_enabled = 0; else PHY_vars_eNB_g[0][CC_id]->mac_enabled = 1; From 2ace4029f37a323c0238cd0bfd87b2b4cdf1b226 Mon Sep 17 00:00:00 2001 From: ROBERT Benoit Date: Tue, 25 Oct 2016 18:09:59 +0200 Subject: [PATCH 254/413] Update 3gpplte_turbo_decoder_sse_8bit.c maximum frame length is 6144 --- openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c index b56aae4598..1343aee07c 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c @@ -486,7 +486,7 @@ void compute_beta8(llr_t* alpha,llr_t* beta,llr_t *m_11,llr_t* m_10,unsigned sho #endif - if (frame_length > 6143) { + if (frame_length > 6144) { LOG_E(PHY,"compute_beta: frame_length %d\n",frame_length); return; } From 7e6a74d5be20128ab47cc9bfc8a1fd647b7e83d4 Mon Sep 17 00:00:00 2001 From: calvin wang Date: Wed, 26 Oct 2016 13:21:26 +0800 Subject: [PATCH 255/413] change debug info --- openair2/LAYER2/MAC/ue_procedures.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 97b7e433c4..8773186382 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -1422,6 +1422,12 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf bsr_l->Buffer_size2 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]; bsr_l->Buffer_size3 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]; + LOG_D(MAC, "[UE %d] Frame %d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP, + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2], + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]); + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID0] = 0; UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID1] = 0; UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID2] = 0; @@ -1430,12 +1436,6 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1] = 0; UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2] = 0; UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] = 0; - - LOG_D(MAC, "[UE %d] Frame %d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP, - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2], - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]); } else if (bsr_ce_len == sizeof(BSR_SHORT)) { bsr_l = NULL; bsr_s->LCGID = lcgid; From 6644204765a129610a4b8ec035c5ff90250d077c Mon Sep 17 00:00:00 2001 From: calvin wang Date: Thu, 27 Oct 2016 11:47:17 +0800 Subject: [PATCH 256/413] add BSR trigger code for interoperability test --- openair2/LAYER2/MAC/defs.h | 4 ++++ openair2/LAYER2/MAC/ue_procedures.c | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index e3be4bad6d..d38ca05362 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -947,6 +947,10 @@ typedef struct { uint8_t BSR[MAX_NUM_LCGID]; // should be more for mesh topology /// keep the number of bytes in rlc buffer for each lcgid uint16_t BSR_bytes[MAX_NUM_LCGID]; +#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 + /// after multiplexing buffer remain for each lcid + uint16_t LCID_buffer_remain[MAX_NUM_LCID]; +#endif /// buffer status for each lcid uint8_t LCID_status[MAX_NUM_LCID]; /// SR pending as defined in 36.321 diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 082b61445f..c24702b3b5 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -1356,6 +1356,9 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf //update_bsr(module_idP, frameP, eNB_index, DCCH, UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]); //header_len +=2; UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH] = LCID_EMPTY; +#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH] = rlc_status.bytes_in_buffer-sdu_lengths[0]; +#endif } else { dcch_header_len=0; num_sdus = 0; @@ -1391,10 +1394,13 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf sdu_length_total += sdu_lengths[num_sdus]; sdu_lcids[num_sdus] = DCCH1; LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH1\n",module_idP,sdu_lengths[num_sdus]); - num_sdus++; //update_bsr(module_idP, frameP, DCCH1); //dcch_header_len +=2; // include dcch1 UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH1] = LCID_EMPTY; +#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1] = rlc_status.bytes_in_buffer-sdu_lengths[num_sdus]; +#endif + num_sdus++; } else { dcch1_header_len =0; } @@ -1449,6 +1455,9 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len --; dtch_header_len_last --; } +#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] = rlc_status.bytes_in_buffer-sdu_lengths[num_sdus]; +#endif num_sdus++; //UE_mac_inst[module_idP].ul_active = update_bsr(module_idP, frameP, eNB_index,lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); } else { @@ -2077,7 +2086,11 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in lcid, 0); - if (rlc_status.bytes_in_buffer > 0 ) { + if ((rlc_status.bytes_in_buffer > 0 ) +#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 + && (rlc_status.bytes_in_buffer > UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]) +#endif + ){ //BSR trigger SR sr_pending = TRUE; UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_NOT_EMPTY; From 4eb3774a743dc17c1d746f21de0290bb0553c22b Mon Sep 17 00:00:00 2001 From: hbilel Date: Fri, 28 Oct 2016 09:56:31 +0200 Subject: [PATCH 257/413] [OAI-UE] add featureGroup to UeCapability (only for usim test mode) --- openair2/RRC/LITE/MESSAGES/asn1_msg.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index fb8f2a426f..d212415461 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -2663,6 +2663,21 @@ OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname) // UE_EUTRA_Capability->measParameters.bandListEUTRA.list.count = 0; // no measurements on other bands // UE_EUTRA_Capability->featureGroupIndicators // null + + // featureGroup is mandatory for CMW tests + // featureGroup is filled only for usim-test mode + BIT_STRING_t *bit_string; + uint32_t featrG; + bit_string = CALLOC(1, sizeof(*bit_string)); + featrG = 0x04000800; + if(usim_test == 0) + { + bit_string->buf = &featrG; + bit_string->size = 4; + bit_string->bits_unused = 0; + UE_EUTRA_Capability->featureGroupIndicators = bit_string; + } + // UE_EUTRA_Capability->interRAT_Parameters // null } else { From 81837312cb54fcab47fdb0952728f9c063985c33 Mon Sep 17 00:00:00 2001 From: hbilel Date: Thu, 3 Nov 2016 15:29:33 +0100 Subject: [PATCH 258/413] [OAI-UE] RRCConnectionReconf fixes 1- SRB2 fix 2- attach accept, support type of list 0 with number of element = 1 --- openair2/RRC/LITE/MESSAGES/asn1_msg.c | 2 +- openair2/RRC/LITE/rrc_UE.c | 242 ++++++++++++++++++++++++-- openair3/NAS/UE/EMM/SAP/emm_recv.c | 11 +- 3 files changed, 238 insertions(+), 17 deletions(-) diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index d212415461..7d2fc3a3d8 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -2670,7 +2670,7 @@ OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname) uint32_t featrG; bit_string = CALLOC(1, sizeof(*bit_string)); featrG = 0x04000800; - if(usim_test == 0) + if(usim_test == 1) { bit_string->buf = &featrG; bit_string->size = 4; diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index a41a664c18..1b22ae5d0b 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -817,6 +817,7 @@ rrc_ue_process_measConfig( } } + LOG_I(RRC,"call rrc_mac_config_req \n"); rrc_mac_config_req(ctxt_pP->module_id,0,ENB_FLAG_NO,0,eNB_index, (RadioResourceConfigCommonSIB_t *)NULL, (struct PhysicalConfigDedicated *)NULL, @@ -963,6 +964,199 @@ rrc_ue_process_measConfig( } } + +void +rrc_ue_update_radioResourceConfigDedicated(RadioResourceConfigDedicated_t* radioResourceConfigDedicated, + const protocol_ctxt_t* const ctxt_pP, + uint8_t eNB_index) +{ + PhysicalConfigDedicated_t* physicalConfigDedicated2 = NULL; + + physicalConfigDedicated2 = CALLOC(1,sizeof(*physicalConfigDedicated2)); + physicalConfigDedicated2->pdsch_ConfigDedicated = CALLOC(1,sizeof(*physicalConfigDedicated2->pdsch_ConfigDedicated)); + 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->soundingRS_UL_ConfigDedicated = CALLOC(1,sizeof(*physicalConfigDedicated2->soundingRS_UL_ConfigDedicated)); + physicalConfigDedicated2->schedulingRequestConfig = CALLOC(1,sizeof(*physicalConfigDedicated2->schedulingRequestConfig)); + physicalConfigDedicated2->antennaInfo = CALLOC(1,sizeof(*physicalConfigDedicated2->antennaInfo)); + + physicalConfigDedicated2->uplinkPowerControlDedicated = CALLOC(1,sizeof(*physicalConfigDedicated2->uplinkPowerControlDedicated)); + physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH = CALLOC(1,sizeof(*physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH)); + physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH = CALLOC(1,sizeof(*physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH)); + + // Update pdsch_ConfigDedicated + if(radioResourceConfigDedicated->physicalConfigDedicated->pdsch_ConfigDedicated != NULL) + { + LOG_I(RRC,"Update pdsch_ConfigDedicated config \n"); + + if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pdsch_ConfigDedicated == NULL) + UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pdsch_ConfigDedicated = CALLOC(1,sizeof(PDSCH_ConfigDedicated_t)); + + memcpy((char*)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pdsch_ConfigDedicated, + (char*)radioResourceConfigDedicated->physicalConfigDedicated->pdsch_ConfigDedicated, + sizeof(physicalConfigDedicated2->pdsch_ConfigDedicated)); + } + else + { + LOG_I(RRC,"Keep old config for pdsch_ConfigDedicated\n"); + } + + // Update pusch_ConfigDedicated + if(radioResourceConfigDedicated->physicalConfigDedicated->pusch_ConfigDedicated != NULL) + { + LOG_I(RRC,"Update pusch_ConfigDedicated config \n"); + + if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pusch_ConfigDedicated == NULL) + UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pusch_ConfigDedicated = CALLOC(1,sizeof(PUSCH_ConfigDedicated_t)); + + memcpy((char*)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pusch_ConfigDedicated, + (char*)radioResourceConfigDedicated->physicalConfigDedicated->pusch_ConfigDedicated, + sizeof(physicalConfigDedicated2->pusch_ConfigDedicated)); + } + else + { + LOG_I(RRC,"Keep old config for pusch_ConfigDedicated\n"); + } + + // Update pucch_ConfigDedicated + if(radioResourceConfigDedicated->physicalConfigDedicated->pucch_ConfigDedicated != NULL) + { + LOG_I(RRC,"Update pucch_ConfigDedicated config \n"); + if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pucch_ConfigDedicated == NULL) + UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pucch_ConfigDedicated = CALLOC(1,sizeof(PUCCH_ConfigDedicated_t)); + + memcpy((char*)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->pucch_ConfigDedicated, + (char*)radioResourceConfigDedicated->physicalConfigDedicated->pucch_ConfigDedicated, + sizeof(physicalConfigDedicated2->pucch_ConfigDedicated)); + } + else + { + LOG_I(RRC,"Keep old config for pucch_ConfigDedicated\n"); + } + + // Update cqi_ReportConfig + if(radioResourceConfigDedicated->physicalConfigDedicated->cqi_ReportConfig != NULL) + { + LOG_I(RRC,"Update cqi_ReportConfig config \n"); + + 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)); + } + else + { + LOG_I(RRC,"Keep old config for cqi_ReportConfig\n"); + } + + // Update schedulingRequestConfig + if(radioResourceConfigDedicated->physicalConfigDedicated->schedulingRequestConfig != NULL) + { + LOG_I(RRC,"Update schedulingRequestConfig config \n"); + + if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->schedulingRequestConfig == NULL) + UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->schedulingRequestConfig = CALLOC(1,sizeof(SchedulingRequestConfig_t)); + + memcpy((char*)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->schedulingRequestConfig, + (char*)radioResourceConfigDedicated->physicalConfigDedicated->schedulingRequestConfig, + sizeof(physicalConfigDedicated2->schedulingRequestConfig)); + } + else + { + LOG_I(RRC,"Keep old config for schedulingRequestConfig\n"); + } + + // Update soundingRS_UL_ConfigDedicated + if(radioResourceConfigDedicated->physicalConfigDedicated->soundingRS_UL_ConfigDedicated != NULL) + { + LOG_I(RRC,"Update soundingRS_UL_ConfigDedicated config \n"); + + if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->soundingRS_UL_ConfigDedicated == NULL) + UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->soundingRS_UL_ConfigDedicated = CALLOC(1,sizeof(SoundingRS_UL_ConfigDedicated_t)); + + memcpy((char*)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->soundingRS_UL_ConfigDedicated, + (char*)radioResourceConfigDedicated->physicalConfigDedicated->soundingRS_UL_ConfigDedicated, + sizeof(physicalConfigDedicated2->soundingRS_UL_ConfigDedicated)); + } + else + { + LOG_I(RRC,"Keep old config for soundingRS_UL_ConfigDedicated\n"); + } + + // Update antennaInfo + if(radioResourceConfigDedicated->physicalConfigDedicated->antennaInfo != NULL) + { + LOG_I(RRC,"Update antennaInfo config \n"); + + if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->antennaInfo == NULL) + UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->antennaInfo = CALLOC(1,sizeof(struct PhysicalConfigDedicated__antennaInfo)); + + memcpy((char*)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->antennaInfo, + (char*)radioResourceConfigDedicated->physicalConfigDedicated->antennaInfo, + sizeof(physicalConfigDedicated2->antennaInfo)); + } + else + { + LOG_I(RRC,"Keep old config for antennaInfo\n"); + } + + + // Update uplinkPowerControlDedicated + if(radioResourceConfigDedicated->physicalConfigDedicated->uplinkPowerControlDedicated != NULL) + { + LOG_I(RRC,"Update uplinkPowerControlDedicated config \n"); + + if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->uplinkPowerControlDedicated == NULL) + UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->uplinkPowerControlDedicated = CALLOC(1,sizeof(UplinkPowerControlDedicated_t)); + + memcpy((char*)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->uplinkPowerControlDedicated, + (char*)radioResourceConfigDedicated->physicalConfigDedicated->uplinkPowerControlDedicated, + sizeof(physicalConfigDedicated2->uplinkPowerControlDedicated)); + } + else + { + LOG_I(RRC,"Keep old config for uplinkPowerControlDedicated\n"); + } + + // Update tpc_PDCCH_ConfigPUCCH + if(radioResourceConfigDedicated->physicalConfigDedicated->tpc_PDCCH_ConfigPUCCH != NULL) + { + LOG_I(RRC,"Update tpc_PDCCH_ConfigPUCCH config \n"); + + if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->tpc_PDCCH_ConfigPUCCH == NULL) + UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->tpc_PDCCH_ConfigPUCCH = CALLOC(1,sizeof(TPC_PDCCH_Config_t)); + + memcpy((char*)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->tpc_PDCCH_ConfigPUCCH, + (char*)radioResourceConfigDedicated->physicalConfigDedicated->tpc_PDCCH_ConfigPUCCH, + sizeof(physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH)); + } + else + { + LOG_I(RRC,"Keep old config for tpc_PDCCH_ConfigPUCCH\n"); + } + + // Update tpc_PDCCH_ConfigPUSCH + if(radioResourceConfigDedicated->physicalConfigDedicated->tpc_PDCCH_ConfigPUSCH != NULL) + { + LOG_I(RRC,"Update tpc_PDCCH_ConfigPUSCH config \n"); + + if(UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->tpc_PDCCH_ConfigPUSCH == NULL) + UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->tpc_PDCCH_ConfigPUSCH = CALLOC(1,sizeof(TPC_PDCCH_Config_t)); + + memcpy((char*)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]->tpc_PDCCH_ConfigPUSCH, + (char*)radioResourceConfigDedicated->physicalConfigDedicated->tpc_PDCCH_ConfigPUSCH, + sizeof(physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH)); + + } + else + { + LOG_I(RRC,"Keep old config for tpc_PDCCH_ConfigPUSCH\n"); + } + +} //----------------------------------------------------------------------------- void rrc_ue_process_radioResourceConfigDedicated( @@ -983,11 +1177,17 @@ rrc_ue_process_radioResourceConfigDedicated( // Save physicalConfigDedicated if present if (radioResourceConfigDedicated->physicalConfigDedicated) { + LOG_I(RRC,"Save physicalConfigDedicated if present \n"); + if (UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index]) { +#if 1 + rrc_ue_update_radioResourceConfigDedicated(radioResourceConfigDedicated, ctxt_pP, eNB_index); +#else memcpy((char*)UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index],(char*)radioResourceConfigDedicated->physicalConfigDedicated, sizeof(struct PhysicalConfigDedicated)); - +#endif } else { + LOG_I(RRC,"Init physicalConfigDedicated UE_rrc_inst to radioResourceConfigDedicated->physicalConfigDedicated\n"); UE_rrc_inst[ctxt_pP->module_id].physicalConfigDedicated[eNB_index] = radioResourceConfigDedicated->physicalConfigDedicated; } } @@ -1105,7 +1305,7 @@ rrc_ue_process_radioResourceConfigDedicated( SRB1_logicalChannelConfig = &SRB1_logicalChannelConfig_defaultValue; } - LOG_D(RRC, "[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ (SRB1 eNB %d) --->][MAC_UE][MOD %02d][]\n", + LOG_I(RRC, "[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ (SRB1 eNB %d) --->][MAC_UE][MOD %02d][]\n", ctxt_pP->frame, ctxt_pP->module_id, eNB_index, ctxt_pP->module_id); rrc_mac_config_req(ctxt_pP->module_id,0,ENB_FLAG_NO,0,eNB_index, (RadioResourceConfigCommonSIB_t *)NULL, @@ -1160,7 +1360,7 @@ rrc_ue_process_radioResourceConfigDedicated( SRB2_logicalChannelConfig = &SRB2_logicalChannelConfig_defaultValue; } - LOG_D(RRC, "[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ (SRB2 eNB %d) --->][MAC_UE][MOD %02d][]\n", + LOG_I(RRC, "[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ (SRB2 eNB %d) --->][MAC_UE][MOD %02d][]\n", ctxt_pP->frame, ctxt_pP->module_id, eNB_index, @@ -1267,7 +1467,7 @@ rrc_ue_process_radioResourceConfigDedicated( UE_rrc_inst[ctxt_pP->module_id].DRB_config[eNB_index][DRB_id] = radioResourceConfigDedicated->drb_ToAddModList->list.array[i]; rrc_ue_establish_drb(ctxt_pP->module_id,ctxt_pP->frame,eNB_index,radioResourceConfigDedicated->drb_ToAddModList->list.array[i]); // MAC/PHY Configuration - LOG_D(RRC, "[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ (DRB %d eNB %d) --->][MAC_UE][MOD %02d][]\n", + LOG_I(RRC, "[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ (DRB %d eNB %d) --->][MAC_UE][MOD %02d][]\n", ctxt_pP->frame, ctxt_pP->module_id, radioResourceConfigDedicated->drb_ToAddModList->list.array[i]->drb_Identity, eNB_index, @@ -1825,7 +2025,7 @@ rrc_ue_process_mobilityControlInfo( UE_rrc_inst[ue_mod_idP].DRB_config[eNB_index][0] = NULL; */ //Synchronisation to DL of target cell - LOG_D(RRC, + LOG_I(RRC, "HO: Reset PDCP and RLC for configured RBs.. \n[FRAME %05d][RRC_UE][MOD %02d][][--- MAC_CONFIG_REQ (SRB2 eNB %d) --->][MAC_UE][MOD %02d][]\n", ctxt_pP->frame, ctxt_pP->module_id, eNB_index, ctxt_pP->module_id); @@ -2685,7 +2885,7 @@ static int decode_SIB1( const protocol_ctxt_t* const ctxt_pP, const uint8_t eNB_ UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIperiod = siPeriod_int[sib1->schedulingInfoList.list.array[0]->si_Periodicity]; UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIwindowsize = siWindowLength_int[sib1->si_WindowLength]; - LOG_D( RRC, "[FRAME unknown][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB1 params eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n", + LOG_I( RRC, "[FRAME unknown][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB1 params eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n", ctxt_pP->module_id, eNB_index, ctxt_pP->module_id ); rrc_mac_config_req(ctxt_pP->module_id, 0, ENB_FLAG_NO, 0, eNB_index, @@ -3499,7 +3699,7 @@ static int decode_SI( const protocol_ctxt_t* const ctxt_pP, const uint8_t eNB_in LOG_I( RRC, "[UE %"PRIu8"] Frame %"PRIu32" Found SIB13 from eNB %"PRIu8"\n", ctxt_pP->module_id, ctxt_pP->frame, eNB_index ); dump_sib13( UE_rrc_inst[ctxt_pP->module_id].sib13[eNB_index] ); // adding here function to store necessary parameters for using in decode_MCCH_Message + maybe transfer to PHY layer - LOG_D( RRC, "[FRAME %05"PRIu32"][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB13 params eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n", + LOG_I( RRC, "[FRAME %05"PRIu32"][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB13 params eNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n", ctxt_pP->frame, ctxt_pP->module_id, eNB_index, ctxt_pP->module_id); rrc_mac_config_req(ctxt_pP->module_id,0,ENB_FLAG_NO,0,eNB_index, (RadioResourceConfigCommonSIB_t *)NULL, @@ -3956,7 +4156,7 @@ static void decode_MBSFNAreaConfiguration( module_id_t ue_mod_idP, uint8_t eNB_i { protocol_ctxt_t ctxt; - LOG_D(RRC,"[UE %d] Frame %d : Number of MCH(s) in the MBSFN Sync Area %d is %d\n", + LOG_I(RRC,"[UE %d] Frame %d : Number of MCH(s) in the MBSFN Sync Area %d is %d\n", ue_mod_idP, frameP, mbsfn_sync_area, UE_rrc_inst[ue_mod_idP].mcch_message[eNB_index]->pmch_InfoList_r9.list.count); // store to MAC/PHY necessary parameters for receiving MTCHs rrc_mac_config_req(ue_mod_idP,0,ENB_FLAG_NO,0,eNB_index, @@ -4301,12 +4501,26 @@ void *rrc_ue_task( void *args_p ) /* Transfer data to PDCP */ PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, ue_mod_id, ENB_FLAG_NO, UE_rrc_inst[ue_mod_id].Info[0].rnti, 0, 0,0); - rrc_data_req (&ctxt, - DCCH, - rrc_mui++, - SDU_CONFIRM_NO, - length, buffer, - PDCP_TRANSMISSION_MODE_CONTROL); + + // check if SRB2 is created, if yes request data_req on DCCH1 (SRB2) + if(UE_rrc_inst[ue_mod_id].SRB2_config[0] == NULL) + { + rrc_data_req (&ctxt, + DCCH, + rrc_mui++, + SDU_CONFIRM_NO, + length, buffer, + PDCP_TRANSMISSION_MODE_CONTROL); + } + else + { + rrc_data_req (&ctxt, + DCCH1, + rrc_mui++, + SDU_CONFIRM_NO, + length, buffer, + PDCP_TRANSMISSION_MODE_CONTROL); + } break; } diff --git a/openair3/NAS/UE/EMM/SAP/emm_recv.c b/openair3/NAS/UE/EMM/SAP/emm_recv.c index 32e8e1ec30..6162b5ea2b 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_recv.c +++ b/openair3/NAS/UE/EMM/SAP/emm_recv.c @@ -137,8 +137,15 @@ int emm_recv_attach_accept(attach_accept_msg *msg, int *emm_cause) /* * Message checking */ - if (msg->tailist.typeoflist != - TRACKING_AREA_IDENTITY_LIST_ONE_PLMN_CONSECUTIVE_TACS) { + // supported cases: + // typeoflist = 1 Or + // typeoflist = 0 and numberofelements = 1 (ie numberofelements equal to zero see 3gpp 24.301 9.9.3.33.1) + LOG_D(NAS,"attach accept type of list: %d, number of element: %d\n",msg->tailist.typeoflist, msg->tailist.numberofelements); + if (!( (msg->tailist.typeoflist == TRACKING_AREA_IDENTITY_LIST_ONE_PLMN_CONSECUTIVE_TACS) || + ((msg->tailist.typeoflist == 0) && ( (msg->tailist.numberofelements + 1) == 1)) + ) + ) + { /* Only list of TACs belonging to one PLMN with consecutive * TAC values is supported */ *emm_cause = EMM_CAUSE_IE_NOT_IMPLEMENTED; From 9fbbd0678a236ea9e7878f83fe7327dd29b26854 Mon Sep 17 00:00:00 2001 From: hbilel Date: Thu, 3 Nov 2016 15:53:06 +0100 Subject: [PATCH 259/413] [OAI-UE] attach accept fix --- openair3/NAS/UE/EMM/SAP/emm_recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/NAS/UE/EMM/SAP/emm_recv.c b/openair3/NAS/UE/EMM/SAP/emm_recv.c index 6162b5ea2b..a79a14d9c1 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_recv.c +++ b/openair3/NAS/UE/EMM/SAP/emm_recv.c @@ -142,7 +142,7 @@ int emm_recv_attach_accept(attach_accept_msg *msg, int *emm_cause) // typeoflist = 0 and numberofelements = 1 (ie numberofelements equal to zero see 3gpp 24.301 9.9.3.33.1) LOG_D(NAS,"attach accept type of list: %d, number of element: %d\n",msg->tailist.typeoflist, msg->tailist.numberofelements); if (!( (msg->tailist.typeoflist == TRACKING_AREA_IDENTITY_LIST_ONE_PLMN_CONSECUTIVE_TACS) || - ((msg->tailist.typeoflist == 0) && ( (msg->tailist.numberofelements + 1) == 1)) + ((msg->tailist.typeoflist == 0) && ( msg->tailist.numberofelements == 0)) ) ) { From 535755a528937ceb1ba3df6da24b25f403934513 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Thu, 3 Nov 2016 17:02:06 +0100 Subject: [PATCH 260/413] resetting two files to their state in develop --- targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m | 14 +++++++------- .../CONF/enb.band7.tm1.exmimo2.conf | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m index 254a940886..97fad27531 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m +++ b/targets/ARCH/EXMIMO/USERSPACE/OCTAVE/txsig.m @@ -1,4 +1,4 @@ -fc = 2655000000; +fc = 2560000000 %fc = 1907600000; %fc = 859.5e6; @@ -8,9 +8,9 @@ eNB_flag = 0; card = 0; active_rf = [1 0 0 0]; autocal = [1 1 1 1]; -resampling_factor = [0 0 0 0]; +resampling_factor = [2 2 2 2]; limeparms; -rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF10+RXLPFNORM+RXLPFEN+RXLPF10+LNA1ON+LNAMax+RFBBNORM) * active_rf; +rf_mode = (RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAMax+RFBBNORM) * active_rf; rf_mode = rf_mode + (DMAMODE_RX + DMAMODE_TX)*active_rf; %rf_mode = rf_mode + (DMAMODE_TX)*active_rf + DMAMODE_RX*active_rf; %rf_mode = RXEN+TXEN+TXLPFNORM+TXLPFEN+TXLPF25+RXLPFNORM+RXLPFEN+RXLPF25+LNA1ON+LNAByp+RFBBLNA1; @@ -56,10 +56,10 @@ case 0 s(:,4) = amp * ones(1,length); case 1 - s(:,1) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/256))); - s(:,2) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/256))); - s(:,3) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/256))); - s(:,4) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/256))); + s(:,1) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/4))); + s(:,2) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/4))); + s(:,3) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/4))); + s(:,4) = floor(amp * (exp(1i*2*pi*(0:((length)-1))/4))); case 2 s(38400+128,1)= 80-1j*40; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf index 66a2d98ce0..a2234cf515 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf @@ -34,12 +34,12 @@ eNBs = downlink_frequency = 2680000000L; uplink_frequency_offset = -120000000; Nid_cell = 0; - N_RB_DL = 50; + N_RB_DL = 25; Nid_cell_mbsfn = 0; nb_antenna_ports = 1; nb_antennas_tx = 1; nb_antennas_rx = 1; - tx_gain = 0; + tx_gain = 25; rx_gain = 20; prach_root = 0; prach_config_index = 0; From 057de0719255abf6e6e56161df64dd831fe1ef90 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Thu, 3 Nov 2016 21:20:29 +0100 Subject: [PATCH 261/413] Merge bugfix-137-uplink-fixes and update README --- README.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/README.txt b/README.txt index 2a08ae60fb..04d02bf9c7 100644 --- a/README.txt +++ b/README.txt @@ -38,3 +38,4 @@ v0.2 -> Merge of enhancement-10-harmony to include NGFI RRH + New Interface for v0.3 -> Last stable commit on develop branch before the merge of feature-131-new-license. This is the last commit with GPL License v0.4 -> Merge of feature-131-new-license. It closes issue#131 and changes the license to OAI Public License V1.0 v0.5 -> Merge of enhancement-10-harmony-lts. It includes fixes for Ubuntu 16.04 support +v0.5.1 -> Merge of bugfix-137-uplink-fixes. It includes stablity fixes for eNB From 5bbdefeee84373eab2215fb40454cbce9d0cfdc5 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Thu, 3 Nov 2016 21:32:12 +0100 Subject: [PATCH 262/413] add installation of colorama --- cmake_targets/tools/build_helper | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index ac9739e589..388fcfeba9 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -229,7 +229,7 @@ check_install_additional_tools (){ ntp $SUDO pip install paramiko - $SUDO pip install pyroute2 + $SUDO pip install pyroute2 colorama $SUDO rm -fr /opt/ssh $SUDO GIT_SSL_NO_VERIFY=true git clone https://gitlab.eurecom.fr/oai/ssh.git /opt/ssh From 65f047094cd996ef09c809318b3557a93614a01f Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Thu, 3 Nov 2016 21:40:04 +0100 Subject: [PATCH 263/413] [Gitlab CI]: additional packages for pylab support for autotest --- cmake_targets/tools/build_helper | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 388fcfeba9..c5f2b87704 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -223,10 +223,12 @@ check_install_additional_tools (){ android-tools-adb \ wvdial \ python-numpy \ - sshpass \ - nscd \ - bc \ - ntp + sshpass \ + nscd \ + bc \ + ntp \ + python-scipy \ + python-matplotlib $SUDO pip install paramiko $SUDO pip install pyroute2 colorama From eff2887d9289c6e863a0c89326560bdd3403aadb Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Thu, 3 Nov 2016 23:27:08 +0100 Subject: [PATCH 264/413] [Gitlab CI]: Move autotest library to tools --- cmake_targets/autotests/{ => tools}/autotest_analyser.py | 0 cmake_targets/autotests/{ => tools}/lib_autotest_analyser.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename cmake_targets/autotests/{ => tools}/autotest_analyser.py (100%) rename cmake_targets/autotests/{ => tools}/lib_autotest_analyser.py (100%) diff --git a/cmake_targets/autotests/autotest_analyser.py b/cmake_targets/autotests/tools/autotest_analyser.py similarity index 100% rename from cmake_targets/autotests/autotest_analyser.py rename to cmake_targets/autotests/tools/autotest_analyser.py diff --git a/cmake_targets/autotests/lib_autotest_analyser.py b/cmake_targets/autotests/tools/lib_autotest_analyser.py similarity index 100% rename from cmake_targets/autotests/lib_autotest_analyser.py rename to cmake_targets/autotests/tools/lib_autotest_analyser.py From 8031eaa05cd515e4f0422891d26bb1b86ec72995 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Fri, 4 Nov 2016 01:24:29 +0100 Subject: [PATCH 265/413] [Gitlab-CI]: Merge from Enhancement-142-OAI_UE_autotest_framework --- .../autotests/run_exec_lte-softmodem_tests.py | 664 +++++++++++++++++- .../autotests/tools/autotest_analyser.py | 161 +++++ .../autotests/tools/lib_autotest_analyser.py | 414 +++++++++++ cmake_targets/tools/build_helper | 12 +- 4 files changed, 1244 insertions(+), 7 deletions(-) create mode 100755 cmake_targets/autotests/tools/autotest_analyser.py create mode 100644 cmake_targets/autotests/tools/lib_autotest_analyser.py diff --git a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py index 1dfd67b682..796235a77f 100755 --- a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py +++ b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py @@ -37,6 +37,8 @@ import math #from time import clock import xml.etree.ElementTree as ET import re +from colorama import Fore, Back, Style + import numpy as np import log @@ -167,7 +169,7 @@ def sftp_module (username, password, hostname, ports, paramList,logfile): #paramiko logfile path should not be changed with multiple calls. The logs seem to in first file regardless error = "" #The lines below are outside exception loop to be sure to terminate the test case if the network connectivity goes down or there is authentication failure - transport = paramiko.Transport(hostname, ports) + transport = paramiko.Transport((hostname, ports)) transport.connect(username = username, password = password) sftp = paramiko.SFTPClient.from_transport(transport) # index =0 @@ -1042,6 +1044,609 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , write_file(xmlFile, xml, mode="w") + + +# \brief handler for executing test cases (lte-softmodem-noS1) +# \param testcase name of testcase +# \param oldprogramList list of programs which must be terminated before running a test case +# \param logdirOAI5GRepo directory on remote machine which has openairinterface5g repo installed +# \param logdirOpenaircnRepo directory on remote machine which has openair-cn repo installed +# \param MachineList list of all machines on which test cases can be run +# \param user username with which to login +# \param password password with which to login +# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) +# \param ExmimoRfStop command to stop EXMIMO Card +# \param nruns_lte-softmodem global parameter to override number of runs (nruns) within the test case +def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRepo , logdirOpenaircnRepo, MachineList, user, password, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, timeout_cmd): + #We ignore the password sent to this function for secuirity reasons for password present in log files + #It is recommended to add a line in /etc/sudoers that looks something like below. The line below will run sudo without password prompt + # your_user_name ALL=(ALL:ALL) NOPASSWD: ALL + + indent="\t" + threads=[] + + # + # Test case parameters + # ----------------------------------------------------------------------------- + testcase_verdict = 'PASS' + testcase_time_start = datetime.datetime.now() + testcase_name = testcase.get('id') + testcase_class = testcase.findtext('class',default='') + testcase_desc = testcase.findtext('desc',default='') + if timeout_cmd == '': + timeout_cmd = testcase.findtext('TimeOut_cmd',default='') + timeout_cmd = int(float(timeout_cmd)) + timeout_thread = timeout_cmd + 60 #Timeout_thread is more than that of cmd to have room for compilation time, etc + if nruns_lte_softmodem == '': + nruns = testcase.findtext('nruns',default='') + else: + nruns = nruns_lte_softmodem + nruns = int(float(nruns)) + tags = testcase.findtext('tags',default='') + + max_ntries = testcase.findtext('max_ntries',default='') + if max_ntries : + max_ntries = int(float(max_ntries)) + else : + max_ntries = nruns + + print( indent + "> testcase time start : " + str(testcase_time_start) ) + print( indent + "> testcase class : " + testcase_class ) + print( indent + "> testcase description : " + testcase_desc ) + print( indent + "> testcase timeout : " + str(timeout_cmd) ) + print( indent + "> testcase thread timeout : " + str(timeout_thread) ) + print( indent + "> number of runs : " + str(nruns) ) + print( indent + "> number of max tries : " + str(max_ntries) ) + print( indent + "> testcase tags : " + tags ) + + logdir_local_testcase = openairdir_local + '/cmake_targets/autotests/log/'+ testcasename + logdir_eNB_testcase = logdirOAI5GRepo +'/cmake_targets/autotests/log/'+ testcasename + logdir_UE_testcase = logdirOAI5GRepo +'/cmake_targets/autotests/log/'+ testcasename + + # + # Local checks for test cases + # ----------------------------------------------- + + # Logging directory + if (not os.path.exists(logdir_local_testcase)): + os.system('mkdir -p ' + logdir_local_testcase) + + # + # REMOTE MACHINE COMPILATION + # ------------------------------------------------ + + eNBMachine = testcase.findtext('eNB',default='') + eNB_config_file = testcase.findtext('eNB_config_file',default='') + eNB_compile_prog = testcase.findtext('eNB_compile_prog',default='') + eNB_compile_prog_args = testcase.findtext('eNB_compile_prog_args',default='') + + logfile_compile_eNB = logdir_eNB_testcase + '/eNB_compile.log' + logfile_task_eNB_compile_out = logdir_eNB_testcase + '/eNB_task_compile_out.log' + logfile_task_eNB_compile = logdir_local_testcase + '/eNB_task_compile.log' + + # Check that machine is in test setup machine list + print( Fore.WHITE + indent + "> testcase eNB machine :"), + if (eNBMachine not in MachineList): + print( Fore.RED + eNBMachine + " not in test setup machine list") + testcase_verdict = 'INCON' + else : + print eNBMachine, + # get machine description + eNBMachineDesc = MachineDescDic[eNBMachine] + index_eNBMachine = MachineList.index(eNBMachine) + # check that openairinterface is installed on machine + oai_eNB = openair('localdomain', eNBMachine) + oai_eNB.connect(user, password) + cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep --color=never OPENAIR' + res= oai_eNB.send_recv(cmd) + m = re.search('OPENAIR_HOME', res, re.DOTALL) + if m: + print + # Create testcase directory on remote eNB + cmd = 'rm -fr ' + logdir_eNB_testcase + ' ; mkdir -p ' + logdir_eNB_testcase + result = oai_eNB.send_recv(cmd) + + # Check if we need to compile lte-softmodem-noS1 on remote machine + eNB_compile_cmd = eNB_compile_prog + ' '+ eNB_compile_prog_args + if ('last_compile_prog' in eNBMachineDesc) and eNBMachineDesc['last_compile_prog'] == eNB_compile_cmd: + print( Fore.WHITE + indent + "> eNB machine compilation : skipped -> "+eNB_compile_cmd ) + else: + print( Fore.WHITE + indent + "> eNB machine compilation : triggered -> "+eNB_compile_cmd ) + eNBMachineDesc['last_compile_prog'] = eNB_compile_prog + ' '+ eNB_compile_prog_args # if last compilation is the same do not compile again + task_eNB_compile = ' ( uname -a ; date \n' + task_eNB_compile = task_eNB_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_eNB_compile = task_eNB_compile + 'env |grep OPENAIR \n' + task_eNB_compile = task_eNB_compile + update_config_file(oai_eNB, eNB_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' + if eNB_compile_cmd != "": + task_eNB_compile = task_eNB_compile + ' ( ' + eNB_compile_cmd + ' ) > ' + logfile_compile_eNB + ' 2>&1 \n' + task_eNB_compile = task_eNB_compile + ' date ) > ' + logfile_task_eNB_compile_out + ' 2>&1 ' + write_file(logfile_task_eNB_compile, task_eNB_compile, mode="w") + + + thread_eNB = oaiThread(1, "eNB_thread_compile", eNBMachine, user, password , task_eNB_compile, False, timeout_thread) + threads.append(thread_eNB) + thread_eNB.start() + + else: + print( Fore.RED + " -> OAI5G not properly setup ! please check REMOTE MACHINE PREPARATION step") + testcase_verdict = 'INCON' + + + UEMachine = testcase.findtext('UE',default='') + UE_config_file = testcase.findtext('UE_config_file',default='') + UE_compile_prog = testcase.findtext('UE_compile_prog',default='') + UE_compile_prog_args = testcase.findtext('UE_compile_prog_args',default='') + + logfile_compile_UE = logdir_UE_testcase + '/UE_compile.log' + logfile_task_UE_compile_out = logdir_UE_testcase + '/UE_task_compile_out.log' + logfile_task_UE_compile = logdir_local_testcase + '/UE_task_compile.log' + + # Check that machine is in test setup machine list + print( Fore.WHITE + indent + "> testcase UE machine :"), + if (UEMachine not in MachineList): + print( Fore.RED + UEMachine + " not in test setup machine list") + testcase_verdict = 'INCON' + else : + print UEMachine, + # get machine description + UEMachineDesc = MachineDescDic[UEMachine] + index_UEMachine = MachineList.index(UEMachine) + # check that openairinterface is installed on machine + oai_UE = openair('localdomain', UEMachine) + oai_UE.connect(user, password) + cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep --color=never OPENAIR' + res= oai_UE.send_recv(cmd) + m = re.search('OPENAIR_HOME', res, re.DOTALL) + if m: + print + # Create testcase directory on remote UE + cmd = 'rm -fr ' + logdir_UE_testcase + ' ; mkdir -p ' + logdir_UE_testcase + result = oai_UE.send_recv(cmd) + + # Check if we need to compile lte-softmodem-noS1 on remote machine + UE_compile_cmd = UE_compile_prog + ' '+ UE_compile_prog_args + if ('last_compile_prog' in UEMachineDesc) and UEMachineDesc['last_compile_prog'] == UE_compile_cmd: + print( Fore.WHITE + indent + "> UE machine compilation : skipped -> "+UE_compile_cmd ) + else: + print( Fore.WHITE + indent + "> UE machine compilation : triggered -> "+UE_compile_cmd ) + UEMachineDesc['last_compile_prog'] = UE_compile_prog + ' '+ UE_compile_prog_args + task_UE_compile = ' ( uname -a ; date \n' + task_UE_compile = task_UE_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_UE_compile = task_UE_compile + 'env |grep OPENAIR \n' + task_UE_compile = task_UE_compile + update_config_file(oai_UE, UE_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' + if UE_compile_cmd != "": + task_UE_compile = task_UE_compile + ' ( ' + UE_compile_cmd + ' ) > ' + logfile_compile_UE + ' 2>&1 \n' + task_UE_compile = task_UE_compile + ' date ) > ' + logfile_task_UE_compile_out + ' 2>&1 ' + write_file(logfile_task_UE_compile, task_UE_compile, mode="w") + + thread_UE = oaiThread(2, "UE_thread_compile", UEMachine, user, password , task_UE_compile, False, timeout_thread) + threads.append(thread_UE) + thread_UE.start() + + else: + print( Fore.RED + " -> OAI5G not properly setup ! please check REMOTE MACHINE PREPARATION step") + testcase_verdict = 'INCON' + + + + + + + # Wait for Compilation thread to terminate + #----------------------------------------- + for t in threads: + t.join() + + # TODO check that compilation is succeed + + #first we compile all the programs +# thread_UE = oaiThread(3, "UE_thread", UEMachine, user, password , task_UE_compile, False, timeout_thread) +# threads.append(thread_UE) +# thread_UE.start() + + + + + +# index_UEMachine = MachineList.index(UEMachine) +# oai_UE = openair('localdomain', UEMachine) +# oai_UE.connect(user, password) +# res = oai_UE.send_recv(cmd) +# res = oai_eNB.send_recv(cmd) + + + + # + # RUN LOOP + # ------------------------------------------------ + if testcase_verdict != 'PASS': # if something went wrong to not run test cases + max_ntries=0 + + runs_results = [] + nb_runs = 0 + nb_run_pass = 0 + nb_run_failed = 0 + nb_run_inc = 0 + nb_run_skip = 0 + + nb_seg_fault = 0 + + for run in range(0,max_ntries): + + if nruns == nb_run_pass + nb_run_failed: + break + + nb_runs += 1 + + # + # RUN initialization + # ---------------------------------------------------- + print (Fore.WHITE + indent + "> RUN_"+str(run).zfill(2)+" : " ), + + sys.stdout.flush() + + run_start_time=datetime.datetime.now() + + logdir_local_run = openairdir_local + '/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) + logdir_eNB_run = logdirOAI5GRepo +'/cmake_targets/autotests/log/' + testcasename + '/run_' + str(run) + logdir_UE_run = logdirOAI5GRepo +'/cmake_targets/autotests/log/' + testcasename + '/run_' + str(run) + + cmd = 'rm -fr ' + logdir_eNB_run + ' ; mkdir -p ' + logdir_eNB_run + result = oai_eNB.send_recv(cmd) + cmd = 'rm -fr ' + logdir_UE_run + ' ; mkdir -p ' + logdir_UE_run + result = oai_UE.send_recv(cmd) + cmd = ' rm -fr ' + logdir_local_run + ' ; mkdir -p ' + logdir_local_run + result = os.system(cmd) + + + # + # RUN parametrization + # ---------------------------------------------------- + eNB_pre_exec = testcase.findtext('eNB_pre_exec',default='') + eNB_pre_exec_args = testcase.findtext('eNB_pre_exec_args',default='') + eNB_main_exec = testcase.findtext('eNB_main_exec',default='') + eNB_main_exec_args = testcase.findtext('eNB_main_exec_args',default='') + eNB_traffic_exec = testcase.findtext('eNB_traffic_exec',default='') + eNB_traffic_exec_args = testcase.findtext('eNB_traffic_exec_args',default='') + eNB_terminate_missing_procs = testcase.findtext('eNB_terminate_missing_procs',default='True') + + logfile_exec_eNB = logdir_eNB_run + '/eNB_exec' + '_' + str(run) + '_.log' + logfile_pre_exec_eNB = logdir_eNB_run + '/eNB_pre_exec' + '_' + str(run) + '_.log' + logfile_task_eNB_out = logdir_eNB_run + '/eNB_task_out' + '_' + str(run) + '_.log' + logfile_traffic_eNB = logdir_eNB_run + '/eNB_traffic' + '_' + str(run) + '_.log' + logfile_task_eNB = logdir_local_run + '/eNB_task' + '_' + str(run) + '_.log' + + task_eNB = ' ( uname -a ; date \n' + task_eNB = task_eNB + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_eNB = task_eNB + 'env |grep OPENAIR \n' + 'array_exec_pid=() \n' + if eNB_pre_exec != "": + task_eNB = task_eNB + ' ( date; ' + eNB_pre_exec + ' '+ eNB_pre_exec_args + ' ) > ' + logfile_pre_exec_eNB + ' 2>&1 \n' + if eNB_main_exec != "": + task_eNB = task_eNB + ' ( date; ' + addsudo(eNB_main_exec + ' ' + eNB_main_exec_args, '') + ' ) > ' + logfile_exec_eNB + ' 2>&1 & \n' + task_eNB = task_eNB + 'array_exec_pid+=($!) \n' + task_eNB = task_eNB + 'echo eNB_main_exec PID = $! \n' + if eNB_traffic_exec != "": + cmd_traffic = eNB_traffic_exec + ' ' + eNB_traffic_exec_args + if cmd_traffic.find('-c') >= 0: + cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 80) + task_eNB = task_eNB + ' (date; ' + cmd_traffic + ' ) > ' + logfile_traffic_eNB + ' 2>&1 & \n' + task_eNB = task_eNB + 'array_exec_pid+=($!) \n' + task_eNB = task_eNB + 'echo eNB_traffic_exec PID = $! \n' + #terminate the eNB test case after timeout_cmd seconds + task_eNB = task_eNB + finalize_deploy_script (timeout_cmd, eNB_terminate_missing_procs) + ' \n' + #task_eNB = task_eNB + 'sleep ' + str(timeout_cmd) + ' \n' + task_eNB = task_eNB + 'handle_ctrl_c' + '\n' + task_eNB = task_eNB + ' ) > ' + logfile_task_eNB_out + ' 2>&1 ' + write_file(logfile_task_eNB, task_eNB, mode="w") + + + UE_pre_exec = testcase.findtext('UE_pre_exec',default='') + UE_pre_exec_args = testcase.findtext('UE_pre_exec_args',default='') + UE_main_exec = testcase.findtext('UE_main_exec',default='') + UE_main_exec_args = testcase.findtext('UE_main_exec_args',default='') + UE_traffic_exec = testcase.findtext('UE_traffic_exec',default='') + UE_traffic_exec_args = testcase.findtext('UE_traffic_exec_args',default='') + UE_terminate_missing_procs = testcase.findtext('UE_terminate_missing_procs',default='True') + UE_search_expr_true = testcase.findtext('UE_search_expr_true','') + + logfile_exec_UE = logdir_UE_run + '/UE_exec' + '_' + str(run) + '_.log' + logfile_pre_exec_UE = logdir_UE_run + '/UE_pre_exec' + '_' + str(run) + '_.log' + logfile_task_UE_out = logdir_UE_run + '/UE_task_out' + '_' + str(run) + '_.log' + logfile_traffic_UE = logdir_UE_run + '/UE_traffic' + '_' + str(run) + '_.log' + logfile_task_UE = logdir_local_run + '/UE_task' + '_' + str(run) + '_.log' + + + task_UE = ' ( uname -a ; date \n' + task_UE = task_UE + 'array_exec_pid=()' + '\n' + task_UE = task_UE + 'cd ' + logdirOAI5GRepo + '\n' + task_UE = task_UE + 'source oaienv \n' + task_UE = task_UE + 'source cmake_targets/tools/build_helper \n' + task_UE = task_UE + 'env |grep OPENAIR \n' + if UE_pre_exec != "": + task_UE = task_UE + ' ( date; ' + UE_pre_exec + ' '+ UE_pre_exec_args + ' ) > ' + logfile_pre_exec_UE + ' 2>&1 \n' + if UE_main_exec != "": + task_UE = task_UE + ' ( date; ' + addsudo(UE_main_exec + ' ' + UE_main_exec_args, '') + ' ) > ' + logfile_exec_UE + ' 2>&1 & \n' + task_UE = task_UE + 'array_exec_pid+=($!) \n' + task_UE = task_UE + 'echo UE_main_exec PID = $! \n' + if UE_traffic_exec != "": + cmd_traffic = UE_traffic_exec + ' ' + UE_traffic_exec_args + if cmd_traffic.find('-c') >= 0: + cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 60) + task_UE = task_UE + ' ( date; ' + cmd_traffic + ' ) >' + logfile_traffic_UE + ' 2>&1 & \n' + task_UE = task_UE + 'array_exec_pid+=($!) \n' + task_UE = task_UE + 'echo UE_traffic_exec PID = $! \n' + #terminate the UE test case after timeout_cmd seconds + task_UE = task_UE + finalize_deploy_script (timeout_cmd, UE_terminate_missing_procs) + ' \n' + #task_UE = task_UE + 'sleep ' + str(timeout_cmd) + ' \n' + task_UE = task_UE + 'handle_ctrl_c' + '\n' + task_UE = task_UE + ' ) > ' + logfile_task_UE_out + ' 2>&1 ' + write_file(logfile_task_UE, task_UE, mode="w") + #task_UE = 'echo \" ' + task_UE + '\" > ' + logfile_script_UE + ' 2>&1 ; ' + task_UE + + + + + + + + # + # RUN work + # ---------------------------------------------------- + thread_eNB = oaiThread(1, "eNB_thread", eNBMachine, user, password , task_eNB, False, timeout_thread) + thread_UE = oaiThread(2, "UE_thread", UEMachine, user, password , task_UE, False, timeout_thread) + threads=[] + threads.append(thread_eNB) + threads.append(thread_UE) + thread_eNB.start() + thread_UE.start() + for t in threads: + t.join() + + # + # + #----------------------------------------------------- + cleanOldProgramsAllMachines([oai_eNB, oai_UE] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB_run, logdir_UE_run], logdirOAI5GRepo) + + SSHSessionWrapper(eNBMachine, user, None, password, logdir_eNB_run, logdir_local_testcase, "get_all") + #print "Copying files from UEMachine : " + UEMachine + "logdir_UE = " + logdir_UE + SSHSessionWrapper(UEMachine, user, None, password, logdir_UE_run, logdir_local_testcase, "get_all") + + metric_checks_flag = 1 + + fname = logdir_local_run+ '/UE_exec' + '_' + str(run) + '_.log' + cell_synch_status = analyser.check_cell_synchro(fname) + if cell_synch_status == 'CELL_SYNCH': + print '!!!!!!!!!!!!!! Cell synchronized !!!!!!!!!!!' + else : + print '!!!!!!!!!!!!!! Cell NOT NOT synchronized !!!!!!!!!!!' + metric_checks_flag = 0 + + ue_seg_fault_status = analyser.check_exec_seg_fault(fname) + if ue_seg_fault_status == 'SEG_FAULT' : + nb_seg_fault += 1 + + # + # Check metrics + #---------------------------------------------------- + runs_metrics = [] + run_traffic = [] + + if metric_checks_flag : + verdict = 'PASS' + + # UE side metrics + metricList=testcase.findall('UE_metric') + for metric in metricList: + metric_def = {} + metric_def['id'] = metric.get('id') + metric_def['description'] = metric.get('description') + metric_def['regex'] = metric.get('regex') + metric_def['unit_of_meas'] = metric.get('unit_of_meas') + metric_def['pass_fail_stat']= metric.get('pass_fail_stat') + metric_min_lim = metric.get('min_limit') + if metric_min_lim: + metric_def['min_limit'] = float(metric_min_lim) + metric_max_lim = metric.get('max_limit') + if metric_max_lim: + metric_def['max_limit'] = float(metric_max_lim) + + fname = logdir_local_run+ '/UE_exec' + '_' + str(run) + '_.log' + + args = {'metric' : metric_def, + 'file' : fname } + + metric_extracted = analyser.do_extract_metrics(args) + + print "\t > Metric "+metric_def['id']+" :" + print "\t\t> min = "+ str( metric_extracted['metric_min'] ) + print "\t\t> min_index = "+ str( metric_extracted['metric_min_index'] ) + print "\t\t> max = "+ str( metric_extracted['metric_max'] ) + print "\t\t> max_index = "+ str( metric_extracted['metric_max_index'] ) + print "\t\t> mean = "+ str( metric_extracted['metric_mean'] ) + print "\t\t> median = "+ str( metric_extracted['metric_median'] ) + + verdict = analyser.do_check_verdict(metric_def, metric_extracted) + + metric_fig = logdir_local_run+ '/UE_metric_'+ metric_def['id']+'_' + str(run) + '_.png' + analyser.do_img_metrics(metric_def, metric_extracted, metric_fig) + + + metric_fig_report = '../log/'+ testcasename + '/run_' + str(run) + '/UE_metric_'+ metric_def['id']+'_' + str(run) + '_.png' + + run_metrics = dict( metric_id = metric_def['id'], + metric_desc = metric_def['description'], + metric_uom = metric_def['unit_of_meas'], + metric_min = metric_extracted['metric_min'], + metric_min_index= metric_extracted['metric_min_index'], + metric_max = metric_extracted['metric_max'], + metric_max_index= metric_extracted['metric_max_index'], + metric_mean = metric_extracted['metric_mean'], + metric_median = metric_extracted['metric_median'], + metric_fig = metric_fig_report) + + if metric_def['pass_fail_stat'] : + run_metrics['pass_fail_stat'] = metric_def['pass_fail_stat'] + if metric_min_lim : + run_metrics['pass_fail_min_limit'] = metric_def['min_limit'] + if metric_max_lim : + run_metrics['pass_fail_max_limit'] = metric_def['max_limit'] + + runs_metrics.append(run_metrics) + + # Traffic analysis + if UE_traffic_exec != "": + + fname = logdir_local_run+ '/UE_traffic' + '_' + str(run) + '_.log' + args = {'file' : fname } + traffic_metrics = analyser.do_extract_traffic_metrics(args) + traffic_fig = logdir_local_run+ '/UE_traffic'+'_' + str(run) + '_.png' + analyser.do_img_traffic(traffic_metrics, traffic_fig) + + traffic_fig_report= '../log/'+ testcasename + '/run_' + str(run) + '/UE_traffic'+'_' + str(run) + '_.png' + + dur_pass_fail_crit = 'none' + if traffic_metrics['traffic_count'] == 0 : + verdict = 'FAIL' + elif UE_search_expr_true != "": + traffic_duration_limit = float(UE_search_expr_true) + dur_pass_fail_crit = str(traffic_duration_limit) + # print 'traffic_duration_limit = '+str(traffic_duration_limit) + # print 'traffic_metrics[interval_stop_max] = '+str(traffic_metrics['interval_stop_max']) + if traffic_metrics['interval_stop_max'] < traffic_duration_limit : + verdict = 'FAIL' + + + run_traffic = dict( traffic_count = traffic_metrics['traffic_count'], + bw_min = traffic_metrics['bw_min'], + bw_max = traffic_metrics['bw_max'], + bw_mean = traffic_metrics['bw_mean'], + bw_median = traffic_metrics['bw_median'], + jitter_min = traffic_metrics['jitter_min'], + jitter_max = traffic_metrics['jitter_max'], + jitter_mean = traffic_metrics['jitter_mean'], + jitter_median = traffic_metrics['jitter_median'], + rl_min = traffic_metrics['rl_min'], + rl_max = traffic_metrics['rl_max'], + rl_mean = traffic_metrics['rl_mean'], + rl_median = traffic_metrics['rl_median'], + iperf_duration = traffic_metrics['interval_stop_max'], + dur_pass_fail_crit = dur_pass_fail_crit, + traffic_fig = traffic_fig_report ) + else: + run_traffic = dict( traffic_count = 0) + + else : + verdict = 'SKIP' + + + + # + # RUN verdict and finalization + # ---------------------------------------------------- + run_stop_time=datetime.datetime.now() + run_duration = run_stop_time-run_start_time +# print (Fore.WHITE + ("duration=" :"), + print (Fore.WHITE + indent + "> RUN duration : "+ str(run_duration) +"s" ) + + print (Fore.WHITE + indent + "> RUN verdict :"), + + if verdict == 'PASS': + nb_run_pass += 1 + print ( Fore.GREEN + verdict) + elif verdict == 'FAIL': + nb_run_failed += 1 + testcase_verdict = 'FAIL' + print ( Fore.RED + verdict) + elif verdict == 'SKIP': + nb_run_skip += 1 + print ( Fore.YELLOW + verdict) + else: + nb_run_inc += 1 + if testcase_verdict == 'PASS' : testcase_verdict = 'INCON' + print (Fore.YELLOW+'INCONCLUSIVE') + + run_results = dict( run_id=str(run), + run_start_time = run_start_time, + run_stop_time = run_stop_time , + run_verdict = verdict, + ue_seg_fault_status = ue_seg_fault_status, + run_duration = run_duration, + runs_metrics = runs_metrics, + run_traffic = run_traffic) + runs_results.append(run_results) + + # END RUN LOOP + #---------------------------------------------------- + + # Test case duration + # ---------------------------------- + testcase_time_stop = datetime.datetime.now() + print(Fore.WHITE + indent + "> testcase time stop : " + str(testcase_time_start) ), + print " -> TestCase duration = "+str(testcase_time_stop - testcase_time_start) + + # Save remote log files + # ----------------------------------- + #Now we change the permissions of the logfiles to avoid some of them being with root permissions + cmd = 'sudo -E chown -R ' + user + ' ' + logdir_eNB_testcase + res= oai_eNB.send_recv(cmd) + cmd = 'sudo -E chown -R ' + user + ' ' + logdir_UE_testcase + res= oai_UE.send_recv(cmd) + + # Save remote log files on MTC + #print "Copying files from eNBMachine " + eNBMachine + "logdir_eNB = " + logdir_eNB + SSHSessionWrapper(eNBMachine, user, None, password, logdir_eNB_testcase, openairdir_local + '/cmake_targets/autotests/log/', "get_all") + #print "Copying files from UEMachine : " + UEMachine + "logdir_UE = " + logdir_UE + SSHSessionWrapper(UEMachine, user, None, password, logdir_UE_testcase, openairdir_local + '/cmake_targets/autotests/log/', "get_all") + + oai_eNB.disconnect() + oai_UE.disconnect() + + # Set test case final verdict + # ----------------------------------- + test_result_string = 'do be completed' + + if testcase_verdict == 'PASS': + if nb_run_pass == 0 : + testcase_verdict = 'INCON' + + print(Fore.WHITE + indent + "> testcase final verdict :"), + if testcase_verdict == 'PASS': + print ( Fore.GREEN + testcase_verdict) + elif testcase_verdict == 'FAIL': + print ( Fore.RED + testcase_verdict) + else: + print (Fore.YELLOW+'INCONCLUSIVE') + + duration= testcase_time_stop - testcase_time_start + xmlFile = logdir_local_testcase + '/test.' + testcasename + '.xml' + xml="\n \n" + write_file(xmlFile, xml, mode="w") + + + test_result = dict(testcase_name=testcasename, + testcaseclass=testcaseclass, + testcase_verdict = testcase_verdict, + testcase_time_start=testcase_time_start, + testcase_time_stop=testcase_time_stop, + tags=tags, + nruns=nb_runs, + nb_run_pass = nb_run_pass, + nb_run_skip = nb_run_skip, + nb_run_failed = nb_run_failed, + nb_run_inc=nb_run_inc, + nb_seg_fault = nb_seg_fault, + testcase_timeout=timeout_cmd, + testcase_duration = duration, + testcase_eNBMachine =eNBMachine, + testcase_UEMachine =UEMachine, + runs_results = runs_results) + #test_results.append(test_result) + + return testcase_verdict + + + + # \brief This function searches if test case is present in list of test cases that need to be executed by user # \param testcasename the test case to search for # \param testcasegroup list that is passed from the arguments @@ -1149,12 +1754,14 @@ if openairdir_local is None: locallogdir = openairdir_local + '/cmake_targets/autotests/log' MachineList = '' MachineListGeneric='' +MachineDescDic={} flag_remove_logdir=False flag_start_testcase=False nruns_lte_softmodem='' flag_skip_git_head_check=False flag_skip_oai_install=False Timeout_cmd='' +xmlInputFile='' print "Number of arguments argc = " + str(len(sys.argv)) #for index in range(1,len(sys.argv) ): # print "argv_" + str(index) + " : " + sys.argv[index] @@ -1218,6 +1825,9 @@ while i < len (sys.argv): i = i +1 elif arg == '--skip-oai-install': flag_skip_oai_install=True + elif arg == '--test-suite' : + xmlInputFile = sys.argv[i+1] + i = i +1 elif arg == '-h' : print "-s: This flag *MUST* be set to start the test cases" print "-r: Remove the log directory in autotests" @@ -1235,6 +1845,7 @@ while i < len (sys.argv): print "--skip-git-head-check: skip checking of GitHead remote/local branch (only for debugging)" print "--timeout_cmd: Override the default parameter (timeout_cmd) in test_case_list.xml. This parameter is in seconds and should be > 120" print "--skip-oai-install: Skips the openairinterface5g installer" + print "--test-suite: Select a XML test-suite file" sys.exit() else : print "Unrecongnized Option: <" + arg + ">. Use -h to see valid options" @@ -1264,6 +1875,13 @@ cmd='ps aux |grep \"/usr/bin/ssh -q -l guptar\"| awk \'{print $2}\' | sudo xargs os.system(cmd) +try: + analyser = __import__("lib_autotest_analyser") +except ImportError as err: + print('Import error: ' + str(err)) + exit(0) + + if flag_start_testcase == False: print "You need to start the testcase by passing option -s. Use -h to see all options. Aborting now..." sys.exit(1) @@ -1286,12 +1904,14 @@ os.system(cmd) print "host = " + host print "user = " + user -xmlInputFile=os.environ.get('OPENAIR_DIR')+"/cmake_targets/autotests/test_case_list.xml" +if xmlInputFile == '': + xmlInputFile=os.environ.get('OPENAIR_DIR')+"/cmake_targets/autotests/test_case_list.xml" NFSResultsDir = '/mnt/sradio' cleanupOldProgramsScript = '$OPENAIR_DIR/cmake_targets/autotests/tools/remove_old_programs.bash' logdir = '/tmp/' + 'OAITestFrameWork-' + user + '/' logdirOAI5GRepo = logdir + 'openairinterface5g/' logdirOpenaircnRepo = logdir + 'openair-cn/' +patchdir = logdirOAI5GRepo + 'cmake_targets/autotests/patches/' if flag_remove_logdir == True: print "Removing directory: " + locallogdir @@ -1333,6 +1953,8 @@ ExmimoRfStop = xmlRoot.findtext('ExmimoRfStop',default='') if nruns_lte_softmodem == '': nruns_lte_softmodem = xmlRoot.findtext('nruns_lte-softmodem',default='') +OAI5GpatchFileList=xmlRoot.findall('OAI5GPatchFile') + print "MachineList = " + MachineList print "GitOpenair-cnRepo = " + GitOpenaircnRepo print "GitOAI5GRepo = " + GitOAI5GRepo @@ -1365,6 +1987,7 @@ MachineListGeneric = MachineListGeneric.split() #index=0 for machine in MachineList: oai_list.append( openair('localdomain',machine)) + MachineDescDic[machine]={} #index = index + 1 @@ -1475,6 +2098,7 @@ for oai in oai_list: cmd = cmd + 'git checkout ' + GitOpenaircnRepoBranch + '\n' cmd = cmd + 'env |grep OPENAIR' + '\n' cmd = cmd + ' cd ' + logdir + '\n' + cmd = cmd + 'mkdir -p ' + patchdir + '\n' cmd = cmd + ' ) > ' + setuplogfile + ' 2>&1 \n' #cmd = cmd + 'echo \' ' + cmd + '\' > ' + setup_script + ' 2>&1 \n ' #result = oai_list[index].send_recv(cmd, False, 300 ) @@ -1500,8 +2124,27 @@ for t in threads_init_setup: localfile = locallogdir + '/setup_log_' + MachineList[index] + '_.txt' remotefile = logdir + '/setup_log_' + MachineList[index] + '_.txt' port = 22 + + #Now we copy patch files and apply them + print "Installating patch files on machine " + MachineList[index] + for patchFile in OAI5GpatchFileList: + localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/patches/')+patchFile.get('name') + remotefile = logdirOAI5GRepo + '/cmake_targets/autotests/patches/'+patchFile.get('name') + if patchFile.get('machine') == MachineList[index] or patchFile.get('machine') == None: + if os.path.isfile(localfile): + print "\t> PATCH FILE :"+localfile + paramList=[] + paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) + sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) + cmd = ' cd ' + logdirOAI5GRepo + ' ;git apply cmake_targets/autotests/patches/'+patchFile.get('name') + res = oai_list[index].send_recv(cmd) paramList=[] + + setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' + setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' + localfile = locallogdir + '/setup_log_' + MachineList[index] + '_.txt' + remotefile = logdir + '/setup_log_' + MachineList[index] + '_.txt' sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') paramList.append ( {"operation":'get', "localfile":localfile, "remotefile":remotefile} ) #sftp_module (user, pw, MachineList[index], port, localfile, remotefile, sftp_log, "get") @@ -1574,6 +2217,23 @@ for testcase in testcaseList: SSHSessionWrapper('localhost', user, None, pw , NFSTestsResultsDir , locallogdir, "put_all") oai_localhost.disconnect() + elif testcaseclass == 'lte-softmodem-noS1' : + eNBMachine = testcase.findtext('eNB',default='') + UEMachine = testcase.findtext('UE',default='') + if (eNBMachine not in MachineList)|(UEMachine not in MachineList): + print "One of the machines is not in the machine list" + print "eNBMachine : " + eNBMachine + "UEMachine : " + UEMachine + "MachineList : " + ','.join(MachineList) + print "testcasename = " + testcasename + " class = " + testcaseclass + threadListGlobal = wait_testcaseclass_generic_threads(threadListGlobal, Timeout_execution) + + handle_testcaseclass_softmodem_noS1 (testcase, CleanUpOldProgs, logdirOAI5GRepo, logdirOpenaircnRepo, MachineList, user, pw, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, Timeout_cmd ) + + #The lines below are copied from below to trace the failure of some of the machines in test setup. These lines below need to be removed in long term + print "Creating xml file for overall results..." + cmd = "cat $OPENAIR_DIR/cmake_targets/autotests/log/*/*.xml > $OPENAIR_DIR/cmake_targets/autotests/log/results_autotests.xml " + res=os.system(cmd) + os.system('sync') + elif (testcaseclass == 'compilation'): threadListGlobal = handle_testcaseclass_generic (testcasename, threadListGlobal, CleanUpOldProgs, logdirOAI5GRepo, MachineListGeneric, user, pw, CleanUpAluLteBox,Timeout_execution, ExmimoRfStop) elif (testcaseclass == 'execution'): diff --git a/cmake_targets/autotests/tools/autotest_analyser.py b/cmake_targets/autotests/tools/autotest_analyser.py new file mode 100755 index 0000000000..a75727ad65 --- /dev/null +++ b/cmake_targets/autotests/tools/autotest_analyser.py @@ -0,0 +1,161 @@ +#! /usr/bin/python +#****************************************************************************** +# +# \file autotest_analyser.py +# +# \par Informations +# - \b Project : UED Autotest Framework +# - \b Software : +# +# \date 16 september 2016 +# +# \version 0.1 +# +# \brief helper to test lib_autotest_analyser.py +# +# \author Benoit ROBERT (benoit.robert@syrtem.com) +# +# \par Statement of Ownership +# COPYRIGHT (c) 2016 BY SYRTEM S.A.R.L +# This software is furnished under license and may be used and copied +# only in accordance with the terms of such license and with the inclusion +# of the above COPYRIGHT notice. This SOFTWARE or any other copies thereof +# may not be provided or otherwise made available to any other person. +# No title to and ownership of the SOFTWARE is hereby transferred. +# +# The information in this SOFTWARE is subject to change without notice +# and should not be constructed as a commitment by SYRTEM. +# SYRTEM assumes no responsibility for the use or reliability of its +# SOFTWARE on equipment or platform not explicitly validated by SYRTEM. +# +# ******************************************************************************* + +import os +import getopt +import sys +from subprocess import call + + + +#test_cases = ('030001', '030901', '031001', '031601', '031701', '031801', '031901', '032001', '032101', '032201', '032301', '032501', '032601', '032801') +test_cases = ('030030' , '030030' ) + +nb_run = 3 + +def error_opt(msg): + print("Option error: " + msg) + + +def main(args): + try: + analyser = __import__("lib_autotest_analyser") + except ImportError as err: + print('Import error: ' + str(err)) + exit(0) + + + log_path = 'log_save_2016-08-14/log/' + + + + metric = {} + metric['id'] = 'UE_DLSCH_BITRATE' + metric['description'] = 'UE downlink physical throughput' + metric['regex'] = '(UE_DLSCH_BITRATE) =\s+(\d+\.\d+) kbps.+frame = (\d+)\)' + metric['unit_of_meas'] = 'kbps' + metric['min_limit'] = 14668.8 + + +#report_path = log_path+'/report/' + +#os.system(' mkdir -p ' + report_path) + +#analyser.create_report_html(report_path) + +#return(0) + + for test_case in test_cases: + +# print test_case + if test_case == '030001': + metric['min_limit'] = 500.0 + if test_case == '030901': + metric['min_limit'] = 640.0 + if test_case == '031001': + metric['min_limit'] = 3200.0 + if test_case == '031601': + metric['min_limit'] = 5920.0 + if test_case == '031701': + metric['min_limit'] = 6000.0 + if test_case == '031801': + metric['min_limit'] = 6200.0 + if test_case == '031901': + metric['min_limit'] = 7000.0 + if test_case == '032001': + metric['min_limit'] = 7800.0 + if test_case == '032101': + metric['min_limit'] = 8000.0 + if test_case == '032201': + metric['min_limit'] = 9000.0 + if test_case == '032301': + metric['min_limit'] = 10000.0 + if test_case == '032501': + metric['min_limit'] = 11000.0 + if test_case == '032601': + metric['min_limit'] = 12000.0 + if test_case == '032801': + metric['min_limit'] = 12500.0 + + if test_case == '035201': + metric['min_limit'] = 14668.8 + if test_case == '036001': + metric['min_limit'] = 25363.2 + + + + for i in range(0, nb_run): + fname = 'log//'+test_case+'/run_'+str(i)+'/UE_exec_'+str(i)+'_.log' + args = {'metric' : metric, + 'file' : fname } + + cell_synch_status = analyser.check_cell_synchro(fname) + if cell_synch_status == 'CELL_SYNCH': + print '!!!!!!!!!!!!!! Cell synchronized !!!!!!!!!!!' + metric_checks_flag = 0 + else : + print '!!!!!!!!!!!!!! Cell NOT NOT synchronized !!!!!!!!!!!' + +# metric_extracted = analyser.do_extract_metrics(args) + +# print "min = "+ str( metric_extracted['metric_min'] ) +# print "min_index = "+ str( metric_extracted['metric_min_index'] ) +# print "max = "+ str( metric_extracted['metric_max'] ) +# print "max_index = "+ str( metric_extracted['metric_max_index'] ) +# print "mean = "+ str( metric_extracted['metric_mean'] ) +# print "median = "+ str( metric_extracted['metric_median'] ) + +# verdict = analyser.do_check_verdict(metric, metric_extracted) +# print verdict + +# fname= 'report/2016-9-8_toto/'+test_case+'/UE_metric_UE_DLSCH_BITRATE_'+str(i)+'_.png' +# fname= 'report/UE_metric_UE_DLSCH_BITRATE_'+test_case+'_'+str(i)+'.png' + +# print fname +# analyser.do_img_metrics(metric, metric_extracted, fname) + +# fname = 'log//'+test_case+'/run_'+str(i)+'/UE_traffic_'+str(i)+'_.log' + +# args = {'file' : fname } + +# traffic_metrics = analyser.do_extract_traffic_metrics(args) + +# fname= 'report/iperf_'+test_case+'_'+str(i)+'.png' + +# print fname +# analyser.do_img_traffic(traffic_metrics, fname) + + + +if __name__ == "__main__": + main(sys.argv) + diff --git a/cmake_targets/autotests/tools/lib_autotest_analyser.py b/cmake_targets/autotests/tools/lib_autotest_analyser.py new file mode 100644 index 0000000000..92dcc31e48 --- /dev/null +++ b/cmake_targets/autotests/tools/lib_autotest_analyser.py @@ -0,0 +1,414 @@ +#****************************************************************************** +# +# \file lib_autotest_analyser.py +# +# \par Informations +# - \b Project : UED Autotest Framework +# - \b Software : +# +# \date 16 september 2016 +# +# \version 0.1 +# +# \brief library to extract metrics from autotest logs and assign a verdict +# +# \author Benoit ROBERT (benoit.robert@syrtem.com) +# +# \par Statement of Ownership +# COPYRIGHT (c) 2016 BY SYRTEM S.A.R.L +# This software is furnished under license and may be used and copied +# only in accordance with the terms of such license and with the inclusion +# of the above COPYRIGHT notice. This SOFTWARE or any other copies thereof +# may not be provided or otherwise made available to any other person. +# No title to and ownership of the SOFTWARE is hereby transferred. +# +# The information in this SOFTWARE is subject to change without notice +# and should not be constructed as a commitment by SYRTEM. +# SYRTEM assumes no responsibility for the use or reliability of its +# SOFTWARE on equipment or platform not explicitly validated by SYRTEM. +# +# ******************************************************************************* + + +import re +from pylab import * +from matplotlib.font_manager import FontProperties + +import os +from jinja2 import Environment, FileSystemLoader + + +PATH = os.path.dirname(os.path.abspath(__file__)) +TEMPLATE_ENVIRONMENT = Environment( + autoescape=False, + loader=FileSystemLoader(os.path.join(PATH, 'templates')), + trim_blocks=False) + + +def render_template(template_filename, context): + return TEMPLATE_ENVIRONMENT.get_template(template_filename).render(context) + + + +def init(args = None): + return + + +# +# +# +def do_extract_metrics(args): + +# print "" +# print "do_extract_metrics ... " + + fname = args['file'] + metric = args['metric'] +# print(fname) +# print 'metric id = ' + metric['id'] +# print 'metric regex = ' + metric['regex'] + + count = 0 + mmin = 0 + mmin_index = 0 + mmax = 0 + mmax_index = 0 + mean = 0 + median = 0 + + + output = np.fromregex(fname,metric['regex'], [('id', 'S20'), ('metric', np.float), ('frame', np.int)] ) +# print 'T0T0 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' +# print output + count = output['metric'].size +# print count + if count > 0: + mmin = np.amin(output['metric']); + mmin_index = np.argmin(output['metric']); + mmax = np.amax(output['metric']); + mmax_index = np.argmax(output['metric']); + mean = np.mean(output['metric']); + median = np.median(output['metric']); + +# print ( ( (metric['min_limit'] > output['metric']).sum() / float(output['metric'].size) ) * 100 ) + + ret = { 'metric_count' : count, + 'metric_buf' : output, + 'metric_min' : mmin, + 'metric_min_index' : mmin_index, + 'metric_max' : mmax, + 'metric_max_index' : mmax_index, + 'metric_mean' : mean, + 'metric_median' : median, + } + return(ret) + +# +# +# +def do_check_verdict(metric_def, metric_data): + verdict = 'INCON' + + pass_fail_stat = metric_def['pass_fail_stat'] + + if pass_fail_stat == 'max_value': + metric_stat = metric_data['metric_max'] + elif pass_fail_stat == 'min_value': + metric_stat = metric_data['metric_min'] + elif pass_fail_stat == 'mean_value': + metric_stat = metric_data['metric_mean'] + elif pass_fail_stat == 'median_value': + metric_stat = metric_data['metric_median'] + else : + print "do_check_verdict -> undef metric stat (pass_fail_stat in xml file)" + return verdict + + if 'max_limit' in metric_def: + if metric_stat > metric_def['max_limit']: + verdict = 'FAIL' + else: + verdict = 'PASS' + + if 'min_limit' in metric_def: + if metric_stat < metric_def['min_limit']: + verdict = 'FAIL' + else: + verdict = 'PASS' + return verdict + + +def do_print_metrics(metric_def, metric_data): + + + if metric_data['metric_count'] > 0 : + +# output = np.array( metric_data['metric_buf'] , [('id', 'S20'), ('metric', np.float), ('frame', np.int)]) + output = metric_data['metric_buf'] +# print output + + fontP = FontProperties() + fontP.set_size('small') + + plt.scatter(output['frame'], output['metric'], color='b', alpha=0.33, s = 1 ) + plt.plot([0, output['frame'][metric_data['metric_count']-1]],[ metric_def['min_limit'],metric_def['min_limit']], 'r-', lw=2) # Red straight line + + plt.title('Physical throughput ') + plt.xlabel('frame') + plt.ylabel(metric_def['id']) + plt.legend(prop=fontP) + mng = plt.get_current_fig_manager() + plt.show() + +def do_img_metrics(metric_def, metric_data, fname): + + + if metric_data['metric_count'] > 0 : + +# output = np.array( metric_data['metric_buf'] , [('id', 'S20'), ('metric', np.float), ('frame', np.int)]) + output = metric_data['metric_buf'] +# print 'TITI !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' +# print output + +# print metric_def['min_limit'] +# print metric_data['metric_count'] +# print output['frame'][metric_data['metric_count']-1] + + fontP = FontProperties() + fontP.set_size('small') + + plt.figure() + +# print output['frame'].size +# print output['metric'].size + + plt.scatter(output['frame'], output['metric'], color='b', alpha=0.33, s = 1 , label=metric_def['id']) + plt.plot([0, output['frame'][metric_data['metric_count']-1]],[ metric_def['min_limit'],metric_def['min_limit']], 'r-', lw=2, label='min limit') # Red straight line + + plt.title('Physical throughput ('+metric_def['unit_of_meas']+')') + plt.xlabel('frame') + plt.ylabel(metric_def['id']) + + # Set graphic minimum Y axis + # ------------------------- + if metric_data['metric_min'] == 0 : + plt.ylim(ymin=-metric_def['min_limit']/10) + else : + plt.ylim(ymin=0) + + y_axis_max = 0 + if metric_data['metric_max'] > metric_def['min_limit']: + y_axis_max =metric_data['metric_max']+metric_data['metric_max']/10 + else: + y_axis_max =metric_def['min_limit']+metric_def['min_limit']/10 + + plt.ylim(ymax=y_axis_max) + + lgd = plt.legend(prop=fontP, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) + mng = plt.get_current_fig_manager() + plt.savefig(fname, bbox_extra_artists=(lgd,), bbox_inches='tight') + plt.close() + +# with open(fname, 'r') as f: +# for line in f: +# m = re.search(metric['regex'], line) +# if m : +# print m.group(1) + " -> "+m.group(2) + + + + +def do_extract_traffic_metrics(args): + + print "" + print "do_extract_traffic_metrics ... " + + fname = args['file'] + +# print(fname) +# print 'metric id = ' + metric['id'] + +#[ ID] Interval Transfer Bandwidth Jitter Lost/Total Datagrams +#[ 3] 0.0- 1.0 sec 238 KBytes 1.95 Mbits/sec 0.980 ms 2/ 174 (1.1%) +# [ 3] 0.0- 1.0 sec 63.2 KBytes 517 Kbits/sec 0.146 ms 1/ 45 (2.2%) + +# iperf_regex = '[\s*(\d+)]\s+\d+\.\d+-\s*(\d+\.\d+)\s+sec\s+(\d+).+(\d+\.\d+).+(\d+\.\d+).+(\d+)\/\s*(\d+)\s+\((\d+\.\d+)\%\)' + # ID 0.0 1.0 63.2 KByte 517 Kbits/s 0.146 + iperf_regex = '\[\s*(\d+)\]\s+(\d+\.*\d*)-\s*(\d+\.*\d*)\s+sec\s+(\d+\.*\d*)\s+(\D+)\s+(\d+\.*\d*)\s+(\D+)\s+(\d+\.*\d*)\s+ms\s+(\d+)\/\s*(\d+)\s+\((\d+\.*\d*)\%\)' +# print 'iperf regex = ' + iperf_regex + + count = 0 + bw_min = 0 + bw_max = 0 + bw_mean = 0 + bw_median = 0 + jitter_min = 0 + jitter_max = 0 + jitter_mean = 0 + jitter_median = 0 + + rl_min = 0 + rl_max = 0 + rl_mean = 0 + rl_median = 0 + + interval_stop_max = 0 + + output = np.fromregex(fname,iperf_regex, [('id', np.int) , ('interval_start', np.float), ('interval_stop', np.float), ('transfer', np.float), ('transfer_uom', 'S20') ,('bandwidth', np.float), ('bandwidth_uom', 'S20') ,('jitter', np.float), ('lost', np.int) , ('total', np.int), ('rate_lost', np.float) ] ) + + count = output['id'].size -1 + # remove last line that is an iperf result resume + + if count > 0: + + output= np.delete(output, (count), axis=0 ) +# print output + + bw_min = np.amin(output['bandwidth']); + bw_max = np.amax(output['bandwidth']); + bw_mean = np.mean(output['bandwidth']); + bw_median = np.median(output['bandwidth']); + + jitter_min = np.amin(output['jitter']); + jitter_max = np.amax(output['jitter']); + jitter_mean = np.mean(output['jitter']); + jitter_median = np.median(output['jitter']); + + rl_min = np.amin(output['rate_lost']); + rl_max = np.amax(output['rate_lost']); + rl_mean = np.mean(output['rate_lost']); + rl_median = np.median(output['rate_lost']); + + interval_stop_max = np.amax(output['interval_stop']); + + else : + count = 0 + + + ret = { 'traffic_count' : count, + 'traffic_buf' : output, + 'bw_min' : bw_min, + 'bw_max' : bw_max, + 'bw_mean' : bw_mean, + 'bw_median' : bw_median, + 'jitter_min' : jitter_min, + 'jitter_max' : jitter_max, + 'jitter_mean' : jitter_mean, + 'jitter_median' : jitter_median, + 'rl_min' : rl_min, + 'rl_max' : rl_max, + 'rl_mean' : rl_mean, + 'rl_median' : rl_median, + 'interval_stop_max' : interval_stop_max + } + return(ret) + + + + +def do_img_traffic(traffic_data, fname): + + + if traffic_data['traffic_count'] > 0 : + + output = traffic_data['traffic_buf'] + + + fontP = FontProperties() + fontP.set_size('small') + + fig = plt.figure(1) + + ax1= plt.subplot(311) + plt.plot(output['interval_stop'], output['bandwidth'], color='b' ) + ax1.set_title('Bandwidth (Mbits/s)') + ax1.set_ylim(ymin=-1) + ax1.set_xlim(xmax=np.amax(output['interval_stop'])) + text='min: '+str(traffic_data['bw_min'])+'\nmax: '+str(traffic_data['bw_max'])+'\nmean: '+str(traffic_data['bw_mean'])+'\nmedian: '+str(traffic_data['bw_median']) + ax1.text( np.amax(output['interval_stop'])+10,0,text) + + + ax2=plt.subplot(312) + plt.plot(output['interval_stop'], output['jitter'], color='b' ) + ax2.set_title('Jitter (ms)') + ax2.set_xlim(xmax=np.amax(output['interval_stop'])) + ax2.set_ylim(ymin=-1) + text='min: '+str(traffic_data['jitter_min'])+'\nmax: '+str(traffic_data['jitter_max'])+'\nmean: '+str(traffic_data['jitter_mean'])+'\nmedian: '+str(traffic_data['jitter_median']) + ax2.text( np.amax(output['interval_stop'])+10,0,text) + + ax3=plt.subplot(313) + plt.plot(output['interval_stop'], output['rate_lost'], color='b') + ax3.set_title('Loss rate %') + ax3.set_xlim(xmax=np.amax(output['interval_stop'])) + ax3.set_ylim(ymin=-1) + text='min: '+str(traffic_data['rl_min'])+'\nmax: '+str(traffic_data['rl_max'])+'\nmean: '+str(traffic_data['rl_mean'])+'\nmedian: '+str(traffic_data['rl_median']) + ax3.text( np.amax(output['interval_stop'])+10,0,text) + + +# plt.title('Physical throughput ('+metric_def['unit_of_meas']+')') + plt.xlabel('time (s)') +# plt.ylabel(metric_def['id']) + + # Set graphic minimum Y axis + # ------------------------- +# if traffic_data['bw_min'] == 0 : +# plt.ylim(ymin=-metric_def['min_limit']/10) +# else : +# plt.ylim(ymin=0) + +# y_axis_max = 0 +# if traffic_data['metric_max'] > metric_def['min_limit']: +# y_axis_max =traffic_data['metric_max']+traffic_data['metric_max']/10 +# else: +# y_axis_max =metric_def['min_limit']+metric_def['min_limit']/10 +# +# plt.ylim(ymax=y_axis_max) + + plt.tight_layout() + + lgd = plt.legend(prop=fontP, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) + mng = plt.get_current_fig_manager() + plt.savefig(fname, bbox_inches='tight') + plt.close() + + + + +def create_report_html(context): + fname = context['report_path']+"/index.html" + + # + with open(fname, 'w') as f: + html = render_template('index.html', context) + f.write(html) + + +def create_test_report_detailed_html(context, fname ): + with open(fname, 'w') as f: + html = render_template('testcase_report.html', context) + f.write(html) + + +def check_cell_synchro(fname): + + with open(fname, 'r') as f: + for line in f: + + m = re.search('AUTOTEST Cell Sync \:', line) + if m : + print line + return 'CELL_SYNCH' + + return 'CELL_NOT_SYNCH' + + +def check_exec_seg_fault(fname): + + with open(fname, 'r') as f: + for line in f: + m = re.search('Segmentation fault', line) + if m : + print line + return 'SEG_FAULT' + + return 'NO_SEG_FAULT' + diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index ac9739e589..c5f2b87704 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -223,13 +223,15 @@ check_install_additional_tools (){ android-tools-adb \ wvdial \ python-numpy \ - sshpass \ - nscd \ - bc \ - ntp + sshpass \ + nscd \ + bc \ + ntp \ + python-scipy \ + python-matplotlib $SUDO pip install paramiko - $SUDO pip install pyroute2 + $SUDO pip install pyroute2 colorama $SUDO rm -fr /opt/ssh $SUDO GIT_SSL_NO_VERIFY=true git clone https://gitlab.eurecom.fr/oai/ssh.git /opt/ssh From 92fda18ab6313eedde9287af92d4f024995ee2ff Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 4 Nov 2016 12:40:37 +0200 Subject: [PATCH 266/413] Added brief documentation of agent API functions --- openair2/ENB_APP/enb_agent.c | 26 +- openair2/ENB_APP/enb_agent.h | 7 +- openair2/ENB_APP/enb_agent_async.h | 4 + openair2/ENB_APP/enb_agent_common.c | 456 +++++++++++--------------- openair2/ENB_APP/enb_agent_common.h | 115 ++++++- openair2/ENB_APP/enb_agent_extern.h | 3 + openair2/ENB_APP/enb_agent_mac.c | 68 ++-- openair2/ENB_APP/enb_agent_mac.h | 10 +- openair2/ENB_APP/enb_agent_net_comm.h | 1 - 9 files changed, 347 insertions(+), 343 deletions(-) diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index 8286771104..179392b3a2 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -138,16 +138,12 @@ void *receive_thread(void *args) { Protocol__FlexranMessage *msg; while (1) { - //if (enb_agent_msg_recv(d->enb_id, ENB_AGENT_DEFAULT, &data, &size, &priority)) { - // err_code = PROTOCOL__FLEXRAN_ERR__MSG_DEQUEUING; - // goto error; - //} while (enb_agent_msg_recv(d->enb_id, ENB_AGENT_DEFAULT, &data, &size, &priority) == 0) { LOG_D(ENB_AGENT,"received message with size %d\n", size); - + // Invoke the message handler msg=enb_agent_handle_message(d->enb_id, data, size); free(data); @@ -317,26 +313,6 @@ error: } - - -/* int enb_agent_stop(mid_t mod_id){ */ - -/* int i=0; */ - -/* enb_agent_destroy_timers(); */ -/* for ( i =0; i < enb_agent_info.nb_modules; i++) { */ - -/* destroy_link_manager(enb_agent[i].manager); */ - -/* destroy_message_queue(enb_agent[i].send_queue); */ -/* destroy_message_queue(enb_agent[i].receive_queue); */ - -/* close_link(enb_agent[i].link); */ -/* } */ -/* } */ - - - Protocol__FlexranMessage *enb_agent_timeout(void* args){ // enb_agent_timer_args_t *timer_args = calloc(1, sizeof(*timer_args)); diff --git a/openair2/ENB_APP/enb_agent.h b/openair2/ENB_APP/enb_agent.h index 1a53841d45..a75790d8b0 100644 --- a/openair2/ENB_APP/enb_agent.h +++ b/openair2/ENB_APP/enb_agent.h @@ -41,10 +41,15 @@ #include "enb_config.h" // for enb properties #include "enb_agent_common.h" -int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties); +/* Initiation and termination of the eNodeB agent */ +int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties); int enb_agent_stop(mid_t mod_id); +/* + * enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller + * and can interact with other itti tasks +*/ void *enb_agent_task(void *args); #endif diff --git a/openair2/ENB_APP/enb_agent_async.h b/openair2/ENB_APP/enb_agent_async.h index d722f92a8e..a8c4ae90fe 100644 --- a/openair2/ENB_APP/enb_agent_async.h +++ b/openair2/ENB_APP/enb_agent_async.h @@ -47,12 +47,16 @@ typedef struct { link_manager_t *manager; } enb_agent_async_channel_t; +/* Create a new channel for a given destination ip and destination port */ enb_agent_async_channel_t * enb_agent_async_channel_info(mid_t mod_id, char *dst_ip, uint16_t dst_port); +/* Send a message to the given channel */ int enb_agent_async_msg_send(void *data, int size, int priority, void *channel_info); +/* Receive a message from a given channel */ int enb_agent_async_msg_recv(void **data, int *size, int *priority, void *channel_info); +/* Release a channel */ void enb_agent_async_release(enb_agent_channel_t *channel); diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/enb_agent_common.c index 2baecd6041..51ade8d851 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/enb_agent_common.c @@ -51,6 +51,7 @@ void * enb[NUM_MAX_ENB]; void * enb_ue[NUM_MAX_ENB]; void * enb_rrc[NUM_MAX_ENB]; + /* * message primitives */ @@ -446,6 +447,7 @@ int enb_agent_destroy_agent_reconfiguration(Protocol__FlexranMessage *msg) { /*TODO: Dealocate memory for a dynamically allocated agent reconfiguration message*/ } + /* * get generic info from RAN */ @@ -541,7 +543,7 @@ int get_num_ues (mid_t mod_id){ return ((UE_list_t *)enb_ue[mod_id])->num_UEs; } -int get_ue_crnti (mid_t mod_id, mid_t ue_id){ +int get_ue_crnti (mid_t mod_id, mid_t ue_id) { return UE_RNTI(mod_id, ue_id); } @@ -608,13 +610,12 @@ int get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) else return 0; } -int get_active_CC(mid_t mod_id, mid_t ue_id) -{ + +int get_active_CC(mid_t mod_id, mid_t ue_id) { return ((UE_list_t *)enb_ue[mod_id])->numactiveCCs[ue_id]; } -int get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) -{ +int get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) { LTE_eNB_UE_stats *eNB_UE_stats = NULL; int pCCid = UE_PCCID(mod_id,ue_id); @@ -629,8 +630,7 @@ int get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) return eNB_UE_stats[CC_id].rank; } -int get_tpc(mid_t mod_id, mid_t ue_id) -{ +int 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; @@ -660,8 +660,7 @@ int get_tpc(mid_t mod_id, mid_t ue_id) return tpc; } -int get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, const int frame, const uint8_t subframe, int *id, int *status) //flag_id_status = 0 then id, else status -{ +int get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, const int frame, const uint8_t subframe, int *id, int *status) { //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];*/ @@ -684,8 +683,7 @@ int get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, const i return 0; } -int get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id) -{ +int 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 = get_ue_crnti(mod_id,ue_id); @@ -703,8 +701,7 @@ int get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id) return -1; } -int get_p0_nominal_pucch(mid_t mod_id, int CC_id) -{ +int 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; } @@ -716,43 +713,42 @@ int get_p0_nominal_pucch(mid_t mod_id, int CC_id) * ************************************ */ -int get_hopping_offset(mid_t mod_id, int CC_id) -{ +int 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 get_hopping_mode(mid_t mod_id, int CC_id) -{ + +int 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 get_n_SB(mid_t mod_id, int CC_id) -{ + +int 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 get_enable64QAM(mid_t mod_id, int CC_id) -{ + +int 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 get_phich_duration(mid_t mod_id, int CC_id) -{ + +int 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 get_phich_resource(mid_t mod_id, int CC_id) -{ + +int 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); @@ -767,132 +763,132 @@ int get_phich_resource(mid_t mod_id, int CC_id) return -1; } -int get_n1pucch_an(mid_t mod_id, int CC_id) -{ + +int 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 get_nRB_CQI(mid_t mod_id, int CC_id) -{ + +int 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 get_deltaPUCCH_Shift(mid_t mod_id, int CC_id) -{ + +int 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 get_prach_ConfigIndex(mid_t mod_id, int CC_id) -{ + +int 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 get_prach_FreqOffset(mid_t mod_id, int CC_id) -{ + +int 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 get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id) -{ + +int 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 get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id) -{ + +int 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 get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id) -{ + +int 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 get_cell_id(mid_t mod_id, int CC_id) -{ + +int 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 get_srs_BandwidthConfig(mid_t mod_id, int CC_id) -{ + +int 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 get_srs_SubframeConfig(mid_t mod_id, int CC_id) -{ + +int 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 get_srs_MaxUpPts(mid_t mod_id, int CC_id) -{ + +int 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 get_N_RB_DL(mid_t mod_id, int CC_id) -{ + +int 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 get_N_RB_UL(mid_t mod_id, int CC_id) -{ + +int 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 get_subframe_assignment(mid_t mod_id, int CC_id) -{ + +int 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 get_special_subframe_assignment(mid_t mod_id, int CC_id) -{ + +int 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 get_ra_ResponseWindowSize(mid_t mod_id, int CC_id) -{ + +int get_ra_ResponseWindowSize(mid_t mod_id, int CC_id) { Enb_properties_array_t *enb_properties; enb_properties = enb_config_get(); return enb_properties->properties[mod_id]->rach_raResponseWindowSize[CC_id]; } -int get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id) -{ + +int get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id) { Enb_properties_array_t *enb_properties; enb_properties = enb_config_get(); return enb_properties->properties[mod_id]->rach_macContentionResolutionTimer[CC_id]; } -int get_duplex_mode(mid_t mod_id, int CC_id) -{ + +int 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); @@ -903,21 +899,23 @@ int get_duplex_mode(mid_t mod_id, int CC_id) return -1; } -long get_si_window_length(mid_t mod_id, int CC_id) -{ + +long 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 get_sib1_length(mid_t mod_id, int CC_id) -{ + +int get_sib1_length(mid_t mod_id, int CC_id) { return ((eNB_RRC_INST *)enb_rrc[mod_id])->carrier[CC_id].sizeof_SIB1; } -int get_num_pdcch_symb(mid_t mod_id, int CC_id) -{ + +int 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 @@ -925,8 +923,7 @@ int get_num_pdcch_symb(mid_t mod_id, int CC_id) */ -int get_time_alignment_timer(mid_t mod_id, mid_t ue_id) -{ +int 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 = get_ue_crnti(mod_id,ue_id); @@ -982,18 +979,16 @@ int get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) { return -1; } -int get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id) -{ +int 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 get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id) -{ +int 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 get_half_duplex(mid_t ue_id) -{ +int 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++){ @@ -1003,37 +998,32 @@ int get_half_duplex(mid_t ue_id) //return halfduplex; } -int get_intra_sf_hopping(mid_t ue_id) -{ +int 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))); } -int get_type2_sb_1(mid_t ue_id) -{ +int 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))); } -int get_ue_category(mid_t ue_id) -{ +int 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); } -int get_res_alloc_type1(mid_t ue_id) -{ +int 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))); } -int get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) -{ +int 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 = get_ue_crnti(mod_id,ue_id); @@ -1049,8 +1039,7 @@ int get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) return -1; } -int get_tti_bundling(mid_t mod_id, mid_t ue_id) -{ +int get_tti_bundling(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = get_ue_crnti(mod_id,ue_id); @@ -1078,8 +1067,7 @@ int get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) { return -1; } -int get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) -{ +int 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 = get_ue_crnti(mod_id,ue_id); @@ -1094,8 +1082,7 @@ int get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) return -1; } -int get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) -{ +int 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 = get_ue_crnti(mod_id,ue_id); @@ -1110,8 +1097,7 @@ int get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) return -1; } -int get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) -{ +int 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 = get_ue_crnti(mod_id,ue_id); @@ -1126,8 +1112,7 @@ int get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) return -1; } -int get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) -{ +int 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 = get_ue_crnti(mod_id,ue_id); @@ -1142,8 +1127,7 @@ int get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) return -1; } -int get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id) -{ +int 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; } @@ -1161,8 +1145,7 @@ int get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id) { return -1; } -int get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) -{ +int get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; uint32_t rntiP = get_ue_crnti(mod_id,ue_id); @@ -1178,8 +1161,7 @@ int get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) return -1; } -int get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) -{ +int 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 = get_ue_crnti(mod_id,ue_id); @@ -1213,8 +1195,7 @@ int get_extended_bsr_size(mid_t mod_id, mid_t ue_id) { return -1; } -int get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) -{ +int 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 = get_ue_crnti(mod_id,ue_id); @@ -1235,8 +1216,7 @@ int get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) return -1; } -int get_lcg(mid_t ue_id, mid_t lc_id) -{ +int get_lcg(mid_t ue_id, mid_t lc_id) { if (UE_mac_inst == NULL) { return -1; } @@ -1247,8 +1227,7 @@ int get_lcg(mid_t ue_id, mid_t lc_id) } } -int get_direction(mid_t ue_id, mid_t lc_id) -{ +int 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; @@ -1293,43 +1272,37 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) int i =find_UE_id(mod_id,rnti); config->has_rnti = 1; config->rnti = rnti; - //TODO: Set the time_alignment_timer if(get_time_alignment_timer(mod_id,i) != -1){ config->time_alignment_timer = get_time_alignment_timer(mod_id,i); config->has_time_alignment_timer = 1; } - //TODO: Set the measurement gap configuration pattern if(get_meas_gap_config(mod_id,i) != -1){ config->meas_gap_config_pattern = get_meas_gap_config(mod_id,i); config->has_meas_gap_config_pattern = 1; } - //TODO: Set the measurement gap offset if applicable 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 = 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 noe, so we do not set it + //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 - - //TODO: Set the transmission mode - if(get_ue_transmission_mode(mod_id,i) != -1){ + + if(get_ue_transmission_mode(mod_id,i) != -1){ config->transmission_mode = get_ue_transmission_mode(mod_id,i); config->has_transmission_mode = 1; } - //TODO: Set the aggregated bit-rate of the non-gbr bearer (UL) - config->ue_aggregated_max_bitrate_ul = get_ue_aggregated_max_bitrate_ul(mod_id,i); + config->ue_aggregated_max_bitrate_ul = get_ue_aggregated_max_bitrate_ul(mod_id,i); config->has_ue_aggregated_max_bitrate_ul = 1; - //TODO: Set the aggregated bit-rate of the non-gbr bearer (DL) - config->ue_aggregated_max_bitrate_dl = get_ue_aggregated_max_bitrate_dl(mod_id,i); + config->ue_aggregated_max_bitrate_dl = get_ue_aggregated_max_bitrate_dl(mod_id,i); config->has_ue_aggregated_max_bitrate_dl = 1; //TODO: Set the UE capabilities @@ -1337,63 +1310,63 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) c_capabilities = malloc(sizeof(Protocol__FlexUeCapabilities)); protocol__flex_ue_capabilities__init(c_capabilities); //TODO: Set half duplex (FDD operation) - c_capabilities->has_half_duplex = 1; + c_capabilities->has_half_duplex = 0; c_capabilities->half_duplex = 1;//get_half_duplex(i); //TODO: Set intra-frame hopping flag - c_capabilities->has_intra_sf_hopping = 1; + c_capabilities->has_intra_sf_hopping = 0; c_capabilities->intra_sf_hopping = 1;//get_intra_sf_hopping(i); //TODO: Set support for type 2 hopping with n_sb > 1 - c_capabilities->has_type2_sb_1 = 1; + c_capabilities->has_type2_sb_1 = 0; c_capabilities->type2_sb_1 = 1;//get_type2_sb_1(i); //TODO: Set ue category - c_capabilities->has_ue_category = 1; + c_capabilities->has_ue_category = 0; c_capabilities->ue_category = 1;//get_ue_category(i); //TODO: Set UE support for resource allocation type 1 - c_capabilities->has_res_alloc_type1 = 1; + c_capabilities->has_res_alloc_type1 = 0; c_capabilities->res_alloc_type1 = 1;//get_res_alloc_type1(i); //Set the capabilites to the message config->capabilities = c_capabilities; - //TODO: Set UE transmission antenna. One of the FLUTA_* values + if(get_ue_transmission_antenna(mod_id,i) != -1){ config->has_ue_transmission_antenna = 1; config->ue_transmission_antenna = get_ue_transmission_antenna(mod_id,i); } - //TODO: Set tti bundling flag (See ts 36.321) + if(get_tti_bundling(mod_id,i) != -1){ config->has_tti_bundling = 1; config->tti_bundling = get_tti_bundling(mod_id,i); } - //TODO: Set the max HARQ retransmission for the UL + if(get_maxHARQ_TX(mod_id,i) != -1){ config->has_max_harq_tx = 1; config->max_harq_tx = get_maxHARQ_TX(mod_id,i); } - //TODO: Fill beta_offset_ack_index (TS 36.213) + if(get_beta_offset_ack_index(mod_id,i) != -1){ config->has_beta_offset_ack_index = 1; config->beta_offset_ack_index = get_beta_offset_ack_index(mod_id,i); } - //TODO: Fill beta_offset_ri_index (TS 36.213) + if(get_beta_offset_ri_index(mod_id,i) != -1){ config->has_beta_offset_ri_index = 1; config->beta_offset_ri_index = get_beta_offset_ri_index(mod_id,i); } - //TODO: Fill beta_offset_cqi_index (TS 36.213) + if(get_beta_offset_cqi_index(mod_id,i) != -1){ config->has_beta_offset_cqi_index = 1; config->beta_offset_cqi_index = get_beta_offset_cqi_index(mod_id,i); } - //TODO: Fill ack_nack_simultaneous_trans (TS 36.213) + if(get_ack_nack_simultaneous_trans(mod_id,i) != -1){ config->has_ack_nack_simultaneous_trans = 1; config->ack_nack_simultaneous_trans = get_ack_nack_simultaneous_trans(mod_id,i); } - //TODO: Fill simultaneous_ack_nack_cqi (TS 36.213) + if(get_simultaneous_ack_nack_cqi(mod_id,i) != -1){ config->has_simultaneous_ack_nack_cqi = 1; config->simultaneous_ack_nack_cqi = get_simultaneous_ack_nack_cqi(mod_id,i); } - //TODO: Set PRACRM_* value regarding aperiodic cqi report mode + if(get_aperiodic_cqi_rep_mode(mod_id,i) != -1){ config->has_aperiodic_cqi_rep_mode = 1; int mode = get_aperiodic_cqi_rep_mode(mod_id,i); @@ -1403,22 +1376,22 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) config->aperiodic_cqi_rep_mode = mode; } } - //TODO: Set tdd_ack_nack_feedback + if(get_tdd_ack_nack_feedback(mod_id, i) != -1){ config->has_tdd_ack_nack_feedback = 1; config->tdd_ack_nack_feedback = get_tdd_ack_nack_feedback(mod_id,i); } - //TODO: Set ack_nack_repetition factor + if(get_ack_nack_repetition_factor(mod_id, i) != -1){ config->has_ack_nack_repetition_factor = 1; config->ack_nack_repetition_factor = get_ack_nack_repetition_factor(mod_id,i); } - //TODO: Set extended BSR size + if(get_extended_bsr_size(mod_id, i) != -1){ config->has_extended_bsr_size = 1; config->extended_bsr_size = get_extended_bsr_size(mod_id,i); } - //TODO: Set index of primary cell + config->has_pcell_carrier_index = 1; config->pcell_carrier_index = UE_PCCID(mod_id, i); //TODO: Set carrier aggregation support (boolean) @@ -1432,8 +1405,8 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) // We do not set it for now. No carrier aggregation support //TODO: Set deactivation timer for secondary cell - config->has_scell_deactivation_timer = 1; - config->scell_deactivation_timer = 1; + 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 @@ -1462,9 +1435,7 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) LOG_D(ENB_AGENT, "Could not send UE state message\n"); } -/* - * timer primitives - */ + int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { @@ -1485,7 +1456,6 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Flexra protocol__flex_lc_config_reply__init(lc_config_reply_msg); lc_config_reply_msg->header = header; - //TODO: Fill in the actual number of UEs that we are going to report LC configs about lc_config_reply_msg->n_lc_ue_config = get_num_ues(mod_id); Protocol__FlexLcUeConfig **lc_ue_config; @@ -1498,9 +1468,10 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Flexra for (i = 0; i < lc_config_reply_msg->n_lc_ue_config; i++) { lc_ue_config[i] = malloc(sizeof(Protocol__FlexLcUeConfig)); protocol__flex_lc_ue_config__init(lc_ue_config[i]); - //TODO: Set the RNTI of the UE + lc_ue_config[i]->has_rnti = 1; lc_ue_config[i]->rnti = get_ue_crnti(mod_id,i); + //TODO: Set the number of LC configurations that will be reported for this UE //Set this according to the current state of the UE. This is only a temporary fix int status = 0; @@ -1512,6 +1483,7 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Flexra } else { lc_ue_config[i]->n_lc_config = 3; } + Protocol__FlexLcConfig **lc_config; if (lc_ue_config[i]->n_lc_config > 0) { lc_config = malloc(sizeof(Protocol__FlexLcConfig *) * lc_ue_config[i]->n_lc_config); @@ -1521,38 +1493,39 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Flexra for (j = 0; j < lc_ue_config[i]->n_lc_config; j++) { lc_config[j] = malloc(sizeof(Protocol__FlexLcConfig)); protocol__flex_lc_config__init(lc_config[j]); - //TODO: Set the LC id + lc_config[j]->has_lcid = 1; lc_config[j]->lcid = j+1; - //TODO: Set the LCG of the channel + int lcg = get_lcg(i, j+1); if (lcg >= 0 && lcg <= 3) { lc_config[j]->has_lcg = 1; lc_config[j]->lcg = get_lcg(i,j+1); } - //TODO: Set the LC direction + lc_config[j]->has_direction = 1; lc_config[j]->direction = get_direction(i,j+1); - //TODO: Bearer type. One of FLQBT_* values + //TODO: Bearer type. One of FLQBT_* values. Currently only default bearer supported lc_config[j]->has_qos_bearer_type = 1; lc_config[j]->qos_bearer_type = PROTOCOL__FLEX_QOS_BEARER_TYPE__FLQBT_NON_GBR; + //TODO: Set the QCI defined in TS 23.203, coded as defined in TS 36.413 - // One less than the actual QCI value + // One less than the actual QCI value. Needs to be generalized lc_config[j]->has_qci = 1; lc_config[j]->qci = 1; if (lc_config[j]->direction == PROTOCOL__FLEX_QOS_BEARER_TYPE__FLQBT_GBR) { //TODO: Set the max bitrate (UL) - lc_config[j]->has_e_rab_max_bitrate_ul = 1; - lc_config[j]->e_rab_max_bitrate_ul = 1; + lc_config[j]->has_e_rab_max_bitrate_ul = 0; + lc_config[j]->e_rab_max_bitrate_ul = 0; //TODO: Set the max bitrate (DL) - lc_config[j]->has_e_rab_max_bitrate_dl = 1; - lc_config[j]->e_rab_max_bitrate_dl = 1; + lc_config[j]->has_e_rab_max_bitrate_dl = 0; + lc_config[j]->e_rab_max_bitrate_dl = 0; //TODO: Set the guaranteed bitrate (UL) - lc_config[j]->has_e_rab_guaranteed_bitrate_ul = 1; - lc_config[j]->e_rab_guaranteed_bitrate_ul = 1; + lc_config[j]->has_e_rab_guaranteed_bitrate_ul = 0; + lc_config[j]->e_rab_guaranteed_bitrate_ul = 0; //TODO: Set the guaranteed bitrate (DL) - lc_config[j]->has_e_rab_guaranteed_bitrate_dl = 1; - lc_config[j]->e_rab_guaranteed_bitrate_dl = 1; + lc_config[j]->has_e_rab_guaranteed_bitrate_dl = 0; + lc_config[j]->e_rab_guaranteed_bitrate_dl = 0; } } lc_ue_config[i]->lc_config = lc_config; @@ -1608,7 +1581,6 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Flexra protocol__flex_ue_config_reply__init(ue_config_reply_msg); ue_config_reply_msg->header = header; - //TODO: Fill in the actual number of UEs that are currently connected ue_config_reply_msg->n_ue_config = get_num_ues(mod_id); Protocol__FlexUeConfig **ue_config; @@ -1620,23 +1592,22 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Flexra for (i = 0; i < ue_config_reply_msg->n_ue_config; i++) { ue_config[i] = malloc(sizeof(Protocol__FlexUeConfig)); protocol__flex_ue_config__init(ue_config[i]); - //TODO: Set the RNTI of the ue with id i + ue_config[i]->rnti = get_ue_crnti(mod_id,i); ue_config[i]->has_rnti = 1; //TODO: Set the DRX configuration (optional) //Not supported for now, so we do not set it - //TODO: Set the time_alignment_timer if(get_time_alignment_timer(mod_id,i) != -1){ ue_config[i]->time_alignment_timer = get_time_alignment_timer(mod_id,i); ue_config[i]->has_time_alignment_timer = 1; } - //TODO: Set the measurement gap configuration pattern + if(get_meas_gap_config(mod_id,i) != -1){ ue_config[i]->meas_gap_config_pattern = get_meas_gap_config(mod_id,i); ue_config[i]->has_meas_gap_config_pattern = 1; } - //TODO: Set the measurement gap offset if applicable + if(ue_config[i]->has_meas_gap_config_pattern == 1 && ue_config[i]->meas_gap_config_pattern != PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF) { ue_config[i]->meas_gap_config_sf_offset = get_meas_gap_config_offset(mod_id,i); @@ -1651,82 +1622,78 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Flexra //TODO: Set the CQI configuration (Optional) //We do not set it for now - //TODO: Set the transmission mode if(get_ue_transmission_mode(mod_id,i) != -1){ ue_config[i]->transmission_mode = get_ue_transmission_mode(mod_id,i); ue_config[i]->has_transmission_mode = 1; } - //TODO: Set the aggregated bit-rate of the non-gbr bearer (UL) ue_config[i]->ue_aggregated_max_bitrate_ul = get_ue_aggregated_max_bitrate_ul(mod_id,i); ue_config[i]->has_ue_aggregated_max_bitrate_ul = 1; - //TODO: Set the aggregated bit-rate of the non-gbr bearer (DL) ue_config[i]->ue_aggregated_max_bitrate_dl = get_ue_aggregated_max_bitrate_dl(mod_id,i); ue_config[i]->has_ue_aggregated_max_bitrate_dl = 1; - //TODO: Set the UE capabilities Protocol__FlexUeCapabilities *capabilities; capabilities = malloc(sizeof(Protocol__FlexUeCapabilities)); protocol__flex_ue_capabilities__init(capabilities); //TODO: Set half duplex (FDD operation) - capabilities->has_half_duplex = 1; - capabilities->half_duplex = 1;//get_half_duplex(i); + capabilities->has_half_duplex = 0; + capabilities->half_duplex = 0;//get_half_duplex(i); //TODO: Set intra-frame hopping flag - capabilities->has_intra_sf_hopping = 1; + capabilities->has_intra_sf_hopping = 0; capabilities->intra_sf_hopping = 1;//get_intra_sf_hopping(i); //TODO: Set support for type 2 hopping with n_sb > 1 - capabilities->has_type2_sb_1 = 1; + capabilities->has_type2_sb_1 = 0; capabilities->type2_sb_1 = 1;//get_type2_sb_1(i); //TODO: Set ue category - capabilities->has_ue_category = 1; + capabilities->has_ue_category = 0; capabilities->ue_category = 1;//get_ue_category(i); //TODO: Set UE support for resource allocation type 1 - capabilities->has_res_alloc_type1 = 1; + capabilities->has_res_alloc_type1 = 0; capabilities->res_alloc_type1 = 1;//get_res_alloc_type1(i); //Set the capabilites to the message ue_config[i]->capabilities = capabilities; - //TODO: Set UE transmission antenna. One of the FLUTA_* values + if(get_ue_transmission_antenna(mod_id,i) != -1){ ue_config[i]->has_ue_transmission_antenna = 1; ue_config[i]->ue_transmission_antenna = get_ue_transmission_antenna(mod_id,i); } - //TODO: Set tti bundling flag (See ts 36.321) + if(get_tti_bundling(mod_id,i) != -1){ ue_config[i]->has_tti_bundling = 1; ue_config[i]->tti_bundling = get_tti_bundling(mod_id,i); } - //TODO: Set the max HARQ retransmission for the UL + if(get_maxHARQ_TX(mod_id,i) != -1){ ue_config[i]->has_max_harq_tx = 1; ue_config[i]->max_harq_tx = get_maxHARQ_TX(mod_id,i); } - //TODO: Fill beta_offset_ack_index (TS 36.213) + if(get_beta_offset_ack_index(mod_id,i) != -1){ ue_config[i]->has_beta_offset_ack_index = 1; ue_config[i]->beta_offset_ack_index = get_beta_offset_ack_index(mod_id,i); } - //TODO: Fill beta_offset_ri_index (TS 36.213) + if(get_beta_offset_ri_index(mod_id,i) != -1){ ue_config[i]->has_beta_offset_ri_index = 1; ue_config[i]->beta_offset_ri_index = get_beta_offset_ri_index(mod_id,i); } - //TODO: Fill beta_offset_cqi_index (TS 36.213) + if(get_beta_offset_cqi_index(mod_id,i) != -1){ ue_config[i]->has_beta_offset_cqi_index = 1; ue_config[i]->beta_offset_cqi_index = get_beta_offset_cqi_index(mod_id,i); - } - //TODO: Fill ack_nack_simultaneous_trans (TS 36.213) + } + if(get_ack_nack_simultaneous_trans(mod_id,i) != -1){ ue_config[i]->has_ack_nack_simultaneous_trans = 1; ue_config[i]->ack_nack_simultaneous_trans = get_ack_nack_simultaneous_trans(mod_id,i); } - //TODO: Fill simultaneous_ack_nack_cqi (TS 36.213) + if(get_simultaneous_ack_nack_cqi(mod_id,i) != -1){ ue_config[i]->has_simultaneous_ack_nack_cqi = 1; ue_config[i]->simultaneous_ack_nack_cqi = get_simultaneous_ack_nack_cqi(mod_id,i); } - //TODO: Set FLACRM_* value regarding aperiodic cqi report mode + if(get_aperiodic_cqi_rep_mode(mod_id,i) != -1){ ue_config[i]->has_aperiodic_cqi_rep_mode = 1; int mode = get_aperiodic_cqi_rep_mode(mod_id,i); @@ -1736,17 +1703,17 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Flexra ue_config[i]->aperiodic_cqi_rep_mode = mode; } } - //TODO: Set tdd_ack_nack_feedback + if(get_tdd_ack_nack_feedback(mod_id, i) != -1){ ue_config[i]->has_tdd_ack_nack_feedback = 1; ue_config[i]->tdd_ack_nack_feedback = get_tdd_ack_nack_feedback(mod_id,i); } - //TODO: Set ack_nack_repetition factor + if(get_ack_nack_repetition_factor(mod_id, i) != -1){ ue_config[i]->has_ack_nack_repetition_factor = 1; ue_config[i]->ack_nack_repetition_factor = get_ack_nack_repetition_factor(mod_id,i); } - //TODO: Set extended BSR size + if(get_extended_bsr_size(mod_id, i) != -1){ ue_config[i]->has_extended_bsr_size = 1; ue_config[i]->extended_bsr_size = get_extended_bsr_size(mod_id,i); @@ -1754,18 +1721,18 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Flexra //TODO: Set carrier aggregation support (boolean) ue_config[i]->has_ca_support = 0; ue_config[i]->ca_support = 0; - //TODO: Set index of primary cell + ue_config[i]->has_pcell_carrier_index = 1; ue_config[i]->pcell_carrier_index = UE_PCCID(mod_id, i); if(ue_config[i]->has_ca_support){ //TODO: Set cross carrier scheduling support (boolean) - ue_config[i]->has_cross_carrier_sched_support = 1; + ue_config[i]->has_cross_carrier_sched_support = 0; ue_config[i]->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 - ue_config[i]->has_scell_deactivation_timer = 1; - ue_config[i]->scell_deactivation_timer = 1; + ue_config[i]->has_scell_deactivation_timer = 0; + ue_config[i]->scell_deactivation_timer = 0; } } ue_config_reply_msg->ue_config = ue_config; @@ -1871,26 +1838,26 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr for(i = 0; i < enb_config_reply_msg->n_cell_config; i++){ cell_conf[i] = malloc(sizeof(Protocol__FlexCellConfig)); protocol__flex_cell_config__init(cell_conf[i]); - //TODO: Fill in with actual value, the PCI of this cell + cell_conf[i]->phy_cell_id = 1; cell_conf[i]->has_phy_cell_id = get_cell_id(enb_id,i); - //TODO: Fill in with actual value, the PLMN cell id of this cell + cell_conf[i]->cell_id = i; cell_conf[i]->has_cell_id = 1; - //TODO: Fill in with actual value, PUSCH resources in RBs for hopping + cell_conf[i]->pusch_hopping_offset = get_hopping_offset(enb_id,i); cell_conf[i]->has_pusch_hopping_offset = 1; - //TODO: Fill in with actual value + if(get_hopping_mode(enb_id,i) == 0){ cell_conf[i]->hopping_mode = PROTOCOL__FLEX_HOPPING_MODE__FLHM_INTER; }else if(get_hopping_mode(enb_id,i) == 1){ cell_conf[i]->hopping_mode = PROTOCOL__FLEX_HOPPING_MODE__FLHM_INTERINTRA; } cell_conf[i]->has_hopping_mode = 1; - //TODO: Fill in with actual value, the number of subbands + cell_conf[i]->n_sb = get_n_SB(enb_id,i); cell_conf[i]->has_n_sb = 1; - //TODO: Fill in with actual value, The number of resource element groups used for PHICH. One of FLPR_ + if(get_phich_resource(enb_id,i) == 0){ cell_conf[i]->phich_resource = PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_ONE_SIXTH; //0 }else if (get_phich_resource(enb_id,i) == 1){ @@ -1901,7 +1868,7 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr cell_conf[i]->phich_resource = PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_TWO;//3 } cell_conf[i]->has_phich_resource = 1; - //TODO: Fill in with actual value, one of the FLPD_ values + if(get_phich_duration(enb_id,i) == 0){ cell_conf[i]->phich_duration = PROTOCOL__FLEX_PHICH_DURATION__FLPD_NORMAL; }else if(get_phich_duration(enb_id,i) == 1){ @@ -1910,7 +1877,7 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr cell_conf[i]->has_phich_duration = 1; //TODO: Fill in with actual value, See TS 36.211, section 6.9 cell_conf[i]->init_nr_pdcch_ofdm_sym = get_num_pdcch_symb(enb_id,i); - cell_conf[i]->has_init_nr_pdcch_ofdm_sym = 1; + cell_conf[i]->has_init_nr_pdcch_ofdm_sym = 0; //TODO: Fill in with actual value /* Protocol__FlexSiConfig *si_config; */ /* si_config = malloc(sizeof(Protocol__FlexSiConfig)); */ @@ -1949,20 +1916,19 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr /* } */ /* cell_conf[i]->si_config = si_config; */ - //TODO: Fill in with actual value, the DL transmission bandwidth in RBs cell_conf[i]->dl_bandwidth = get_N_RB_DL(enb_id,i); cell_conf[i]->has_dl_bandwidth = 1; - //TODO: Fill in with actual value, the UL transmission bandwidth in RBs + cell_conf[i]->ul_bandwidth = get_N_RB_UL(enb_id,i); cell_conf[i]->has_ul_bandwidth = 1; - //TODO: Fill in with actual value, one of FLUCPL values + if(get_ul_cyclic_prefix_length(enb_id,i) == 0){ cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_UL_CYCLIC_PREFIX_LENGTH__FLUCPL_NORMAL; }else if(get_ul_cyclic_prefix_length(enb_id,i) == 1){ cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_UL_CYCLIC_PREFIX_LENGTH__FLUCPL_EXTENDED; } cell_conf[i]->has_ul_cyclic_prefix_length = 1; - //TODO: Fill in with actual value, one of FLUCPL values + if(get_ul_cyclic_prefix_length(enb_id,i) == 0){ cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_DL_CYCLIC_PREFIX_LENGTH__FLDCPL_NORMAL; }else if(get_ul_cyclic_prefix_length(enb_id,i) == 1){ @@ -1970,10 +1936,10 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr } cell_conf[i]->has_dl_cyclic_prefix_length = 1; - //TODO: Fill in with actual value, number of cell specific antenna ports + //TODO: Fill in with actual value, number of cell specific antenna ports. Currently single port support cell_conf[i]->antenna_ports_count = 1; cell_conf[i]->has_antenna_ports_count = 1; - //TODO: Fill in with actual value, one of FLDM values + if(get_duplex_mode(enb_id,i) == 1){ cell_conf[i]->duplex_mode = PROTOCOL__FLEX_DUPLEX_MODE__FLDM_FDD; }else if(get_duplex_mode(enb_id,i) == 0){ @@ -1982,10 +1948,10 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr cell_conf[i]->has_duplex_mode = 1; //TODO: Fill in with actual value, DL/UL subframe assignment. TDD only cell_conf[i]->subframe_assignment = get_subframe_assignment(enb_id,i); - cell_conf[i]->has_subframe_assignment = 1; + cell_conf[i]->has_subframe_assignment = 0; //TODO: Fill in with actual value, TDD only. See TS 36.211, table 4.2.1 cell_conf[i]->special_subframe_patterns = get_special_subframe_assignment(enb_id,i); - cell_conf[i]->has_special_subframe_patterns = 1; + cell_conf[i]->has_special_subframe_patterns = 0; //TODO: Fill in with actual value, The MBSFN radio frame period cell_conf[i]->n_mbsfn_subframe_config_rfperiod = 5; uint32_t *elem_rfperiod; @@ -2019,47 +1985,46 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr } cell_conf[i]->mbsfn_subframe_config_sfalloc = elem_sfalloc; - //TODO: Fill in with actual value, See TS 36.211, section 5.7.1 cell_conf[i]->prach_config_index = get_prach_ConfigIndex(enb_id,i); cell_conf[i]->has_prach_config_index = 1; - //TODO: Fill in with actual value, See TS 36.211, section 5.7.1 + cell_conf[i]->prach_freq_offset = get_prach_FreqOffset(enb_id,i); cell_conf[i]->has_prach_freq_offset = 1; - //TODO: Fill in with actual value, Duration of RA response window in SF + cell_conf[i]->ra_response_window_size = get_ra_ResponseWindowSize(enb_id,i); cell_conf[i]->has_ra_response_window_size = 1; - //TODO: Fill in with actual value, Timer used for RA + cell_conf[i]->mac_contention_resolution_timer = get_mac_ContentionResolutionTimer(enb_id,i); cell_conf[i]->has_mac_contention_resolution_timer = 1; - //TODO: Fill in with actual value, See TS 36.321 + cell_conf[i]->max_harq_msg3tx = get_maxHARQ_Msg3Tx(enb_id,i); cell_conf[i]->has_max_harq_msg3tx = 1; - //TODO: Fill in with actual value, See TS 36.213, section 10.1 + cell_conf[i]->n1pucch_an = get_n1pucch_an(enb_id,i); cell_conf[i]->has_n1pucch_an = 1; - //TODO: Fill in with actual value, See TS 36.211, section 5.4 + cell_conf[i]->deltapucch_shift = get_deltaPUCCH_Shift(enb_id,i); cell_conf[i]->has_deltapucch_shift = 1; - //TODO: Fill in with actual value, See TS 36.211, section 5.4 + cell_conf[i]->nrb_cqi = get_nRB_CQI(enb_id,i); cell_conf[i]->has_nrb_cqi = 1; - //TODO: Fill in with actual value, See TS 36.211, table 5.5.3.3-1 and 2 + cell_conf[i]->srs_subframe_config = get_srs_SubframeConfig(enb_id,i); cell_conf[i]->has_srs_subframe_config = 1; - //TODO: Fill in with actual value, See TS 36.211, section 5.5.3.2 + cell_conf[i]->srs_bw_config = get_srs_BandwidthConfig(enb_id,i); cell_conf[i]->has_srs_bw_config = 1; - //TODO: Fill in with actual value, Boolean value. See TS 36.211, section 5.5.3.2. TDD only + cell_conf[i]->srs_mac_up_pts = get_srs_MaxUpPts(enb_id,i); cell_conf[i]->has_srs_mac_up_pts = 1; - //TODO: Fill in with actual value, One of the FLEQ_ values + if(get_enable64QAM(enb_id,i) == 0){ cell_conf[i]->enable_64qam = PROTOCOL__FLEX_QAM__FLEQ_MOD_16QAM; }else if(get_enable64QAM(enb_id,i) == 1){ cell_conf[i]->enable_64qam = PROTOCOL__FLEX_QAM__FLEQ_MOD_64QAM; } cell_conf[i]->has_enable_64qam = 1; - //TODO: Fill in with actual value, Carrier component index + cell_conf[i]->carrier_index = i; cell_conf[i]->has_carrier_index = 1; } @@ -2088,6 +2053,11 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr } + +/* + * timer primitives + */ + //struct enb_agent_map agent_map; enb_agent_timer_instance_t timer_instance; int agent_timer_init = 0; @@ -2099,11 +2069,6 @@ err_code_t enb_agent_init_timer(void){ agent_timer_init = 1; } - /* - struct enb_agent_timer_element_s e; - memset(&e, 0, sizeof(enb_agent_timer_element_t)); - RB_INSERT(enb_agent_map, &agent_map, &e); - */ return PROTOCOL__FLEXRAN_ERR__NO_ERR; } @@ -2249,13 +2214,6 @@ void enb_agent_sleep_until(struct timespec *ts, int delay) { clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts, NULL); } -/* - int i =0; - RB_FOREACH(e, enb_agent_map, &enb_agent_head) { - printf("%d: %p\n", i, e); i++; - } -*/ - err_code_t enb_agent_stop_timer(long timer_id){ @@ -2283,39 +2241,3 @@ struct enb_agent_timer_element_s * get_timer_entry(long timer_id) { return RB_FIND(enb_agent_map, &timer_instance.enb_agent_head, &search); } - -/* -// this will change the timer_id -err_code_t enb_agent_restart_timer(uint32_t *timer_id){ - - struct enb_agent_timer_element_s *e=NULL; - - RB_FOREACH(e, enb_agent_map, &enb_agent_head) { - if (e->timer_id == timer_id) - break; - } - - if (e != NULL ) { - e->state = ENB_AGENT_TIMER_STATE_ACTIVE; - } - - ret = timer_setup(e->interval_sec, - e->interval_usec, - e->agent_id, - e->instance, - e->type, - e->timer_args, - &timer_id); - - } - - if (ret < 0 ) { - return PROTOCOL__FLEXRAN_ERR__TIMER_SETUP_FAILED; - } - - return 0; - -} - -*/ - diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/enb_agent_common.h index b5a35ec338..6664958ed9 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/enb_agent_common.h @@ -73,54 +73,75 @@ typedef int (*enb_agent_message_destruction_callback)( * functions and generic handlers **********************************/ +/* Helper functions for message (de)serialization */ int enb_agent_serialize_message(Protocol__FlexranMessage *msg, void **buf, int *size); int enb_agent_deserialize_message(void *data, int size, Protocol__FlexranMessage **msg); +/* Serialize message and then destroy the input flexran msg. Should be called when protocol + message is created dynamically */ void * enb_agent_pack_message(Protocol__FlexranMessage *msg, uint32_t * size); +/* Calls destructor of the given message */ err_code_t enb_agent_destroy_flexran_message(Protocol__FlexranMessage *msg); +/* Function to create the header for any FlexRAN protocol message */ int flex_create_header(xid_t xid, Protocol__FlexType type, Protocol__FlexHeader **header); +/* Hello protocol message constructor and destructor */ int enb_agent_hello(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int enb_agent_destroy_hello(Protocol__FlexranMessage *msg); +/* Echo request protocol message constructor and destructor */ int enb_agent_echo_request(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int enb_agent_destroy_echo_request(Protocol__FlexranMessage *msg); +/* Echo reply protocol message constructor and destructor */ int enb_agent_echo_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int enb_agent_destroy_echo_reply(Protocol__FlexranMessage *msg); +/* eNodeB configuration reply message constructor and destructor */ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int enb_agent_destroy_enb_config_reply(Protocol__FlexranMessage *msg); +/* UE configuration reply message constructor and destructor */ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int enb_agent_destroy_ue_config_reply(Protocol__FlexranMessage *msg); +/* Logical channel reply configuration message constructor and destructor */ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int enb_agent_destroy_lc_config_reply(Protocol__FlexranMessage *msg); +/* eNodeB configuration request message constructor and destructor */ int enb_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg); int enb_agent_destroy_enb_config_request(Protocol__FlexranMessage *msg); +/* UE configuration request message constructor */ +/* TODO: Need to define and implement destructor */ int enb_agent_destroy_ue_config_request(Protocol__FlexranMessage *msg); +/* Logical channel configuration request message constructor */ +/* TODO: Need to define and implement destructor */ int enb_agent_destroy_lc_config_request(Protocol__FlexranMessage *msg); +/* UE state change message constructor and destructor */ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change); int enb_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg); +/* Control delegation message constructor and destructor */ int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int enb_agent_destroy_control_delegation(Protocol__FlexranMessage *msg); +/* Policy reconfiguration message constructor and destructor */ int enb_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int enb_agent_destroy_agent_reconfiguration(Protocol__FlexranMessage *msg); +/* FlexRAN protocol message dispatcher function */ Protocol__FlexranMessage* enb_agent_handle_message (mid_t mod_id, uint8_t *data, uint32_t size); +/* Function to be used to send a message to a dispatcher once the appropriate event is triggered. */ Protocol__FlexranMessage *enb_agent_handle_timed_task(void *args); @@ -148,73 +169,113 @@ unsigned int get_current_subframe(mid_t mod_id); Bits 0-3 subframe, rest for frame. Required by FlexRAN protocol*/ uint16_t 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 get_future_sfn_sf(mid_t mod_id, int ahead_of_time); +/* Return the number of attached UEs */ int get_num_ues(mid_t mod_id); +/* Get the rnti of a UE with id ue_id */ int 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 get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid); +/* Get power headroom of UE with id ue_id */ int get_ue_phr (mid_t mod_id, mid_t ue_id); +/* Get the UE wideband CQI */ int 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 get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); +/* Return timing advance MAC control element for a designated cell and UE */ int 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 get_active_CC(mid_t mod_id, mid_t ue_id); +/* Get the rank indicator for a designated cell and UE */ int get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id); +/* See TS 36.213, section 10.1 */ int get_n1pucch_an(mid_t mod_id, int CC_id); +/* See TS 36.211, section 5.4 */ int get_nRB_CQI(mid_t mod_id, int CC_id); +/* See TS 36.211, section 5.4 */ int get_deltaPUCCH_Shift(mid_t mod_id, int CC_id); +/* See TS 36.211, section 5.7.1 */ int get_prach_ConfigIndex(mid_t mod_id, int CC_id); +/* See TS 36.211, section 5.7.1 */ int get_prach_FreqOffset(mid_t mod_id, int CC_id); +/* See TS 36.321 */ int get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id); +/* Get the length of the UL cyclic prefix */ int get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id); +/* Get the length of the DL cyclic prefix */ int get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id); +/* Get the physical cell id of a cell */ int get_cell_id(mid_t mod_id, int CC_id); +/* See TS 36.211, section 5.5.3.2 */ int get_srs_BandwidthConfig(mid_t mod_id, int CC_id); +/* See TS 36.211, table 5.5.3.3-1 and 2 */ int get_srs_SubframeConfig(mid_t mod_id, int CC_id); +/* Boolean value. See TS 36.211, + section 5.5.3.2. TDD only */ int get_srs_MaxUpPts(mid_t mod_id, int CC_id); +/* Get number of DL resource blocks */ int get_N_RB_DL(mid_t mod_id, int CC_id); +/* Get number of UL resource blocks */ int get_N_RB_UL(mid_t mod_id, int CC_id); +/* Get DL/UL subframe assignment. TDD only */ int get_subframe_assignment(mid_t mod_id, int CC_id); +/* TDD only. See TS 36.211, table 4.2.1 */ int get_special_subframe_assignment(mid_t mod_id, int CC_id); +/* Get the duration of the random access response window in subframes */ int get_ra_ResponseWindowSize(mid_t mod_id, int CC_id); +/* Get timer used for random access */ int get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id); +/* Get type of duplex mode (FDD/TDD) */ int get_duplex_mode(mid_t mod_id, int CC_id); +/* Get the SI window length */ long get_si_window_length(mid_t mod_id, int CC_id); +/* Get the number of PDCCH symbols configured for the cell */ int get_num_pdcch_symb(mid_t mod_id, int CC_id); +/* See TS 36.213, sec 5.1.1.1 */ int 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 get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, const int frame, const uint8_t subframe, int *id, int *status); +/* Reported values for uplink power control */ int get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id); int get_p0_nominal_pucch(mid_t mod_id, int CC_id); @@ -225,54 +286,88 @@ int get_p0_nominal_pucch(mid_t mod_id, int CC_id); * ************************************ */ +/* Get timer in subframes. Controls the synchronization + status of the UE, not the actual timing + advance procedure. See TS 36.321 */ int get_time_alignment_timer(mid_t mod_id, mid_t ue_id); +/* Get measurement gap configuration. See TS 36.133 */ int get_meas_gap_config(mid_t mod_id, mid_t ue_id); +/* Get measurement gap configuration offset if applicable */ int 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 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 get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id); +/* Only half-duplex support. FDD + operation. Boolean value */ int get_half_duplex(mid_t ue_id); +/* Support of intra-subframe hopping. + Boolean value */ int get_intra_sf_hopping(mid_t ue_id); +/* UE support for type 2 hopping with + n_sb>1 */ int get_type2_sb_1(mid_t ue_id); +/* Get the UE category */ int get_ue_category(mid_t ue_id); +/* UE support for resource allocation + type 1 */ int get_res_alloc_type1(mid_t ue_id); +/* Get UE transmission mode */ int get_ue_transmission_mode(mid_t mod_id, mid_t ue_id); +/* Boolean value. See TS 36.321 */ int get_tti_bundling(mid_t mod_id, mid_t ue_id); +/* The max HARQ retransmission for UL. + See TS 36.321 */ int get_maxHARQ_TX(mid_t mod_id, mid_t ue_id); +/* See TS 36.213 */ int get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id); +/* See TS 36.213 */ int get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id); +/* See TS 36.213 */ int get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id); +/* Boolean. See TS36.213, Section 10.1 */ int get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id); +/* Boolean. See TS 36.213, Section 8.2 */ int get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id); +/* Get aperiodic CQI report mode */ int get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id); +/* Get ACK/NACK feedback mode. TDD only */ int get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id); +/* See TS36.213, section 10.1 */ int get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id); +/* Boolean. Extended buffer status report size */ int get_extended_bsr_size(mid_t mod_id, mid_t ue_id); +/* Get number of UE transmission antennas */ int get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id); +/* Get logical channel group of a channel with id lc_id */ int get_lcg(mid_t ue_id, mid_t lc_id); +/* Get direction of logical channel with id lc_id */ int get_direction(mid_t ue_id, mid_t lc_id); /******************* @@ -349,8 +444,11 @@ typedef struct enb_agent_timer_instance_s{ RB_HEAD(enb_agent_map, enb_agent_timer_element_s) enb_agent_head; }enb_agent_timer_instance_t; + err_code_t enb_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 enb_agent_create_timer(uint32_t interval_sec, uint32_t interval_usec, agent_id_t agent_id, @@ -361,18 +459,28 @@ err_code_t enb_agent_create_timer(uint32_t interval_sec, void* timer_args, long *timer_id); +/* Destroy all existing timers */ err_code_t enb_agent_destroy_timers(void); + +/* Destroy the timer with the given timer_id */ err_code_t enb_agent_destroy_timer(long timer_id); + +/* Destroy the timer for task with id xid */ err_code_t enb_agent_destroy_timer_by_task_id(xid_t xid); +/* Stop a timer */ err_code_t enb_agent_stop_timer(long timer_id); +/* Restart the given timer */ err_code_t enb_agent_restart_timer(long *timer_id); +/* Find the timer with the given timer_id */ struct enb_agent_timer_element_s * get_timer_entry(long timer_id); +/* Obtain the protocol message stored in the given expired timer */ Protocol__FlexranMessage * enb_agent_process_timeout(long timer_id, void* timer_args); +/* Comparator function comparing two timers. Decides the ordering of the timers */ int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b); /*Specify a delay in nanoseconds to timespec and sleep until then*/ @@ -383,10 +491,3 @@ RB_PROTOTYPE(enb_agent_map, enb_agent_timer_element_s, entry, enb_agent_compare_ #endif - - - - - - - diff --git a/openair2/ENB_APP/enb_agent_extern.h b/openair2/ENB_APP/enb_agent_extern.h index 0dd7cfb90f..58f86dfe15 100644 --- a/openair2/ENB_APP/enb_agent_extern.h +++ b/openair2/ENB_APP/enb_agent_extern.h @@ -44,10 +44,13 @@ //extern msg_context_t shared_ctxt[NUM_MAX_ENB][ENB_AGENT_MAX]; +/* full path of the local cache for storing VSFs */ extern char local_cache[40]; +/* Control module interface for the communication of the MAC Control Module with the agent */ 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]; #endif diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index d040622a02..330dafad3a 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -422,62 +422,55 @@ int enb_agent_mac_stats_reply(mid_t mod_id, /* 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: Create a report for each LCG (4 elements). See flex_ue_stats_report of - // FlexRAN specifications for more details 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++; j < ue_report[i]->n_bsr) { - // Set the actual BSR for LCG j of the current UE // NN: we need to know the cc_id here, consider the first one - elem[j] = get_ue_bsr (enb_id, i, j); //eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].bsr_info[j]; + elem[j] = get_ue_bsr (enb_id, i, j); } ue_report[i]->bsr = elem; } /* Check flag for creation of PRH report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PRH) { - // TODO: Fill in the actual power headroom value for the RNTI ue_report[i]->phr = 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) { - // TODO: Fill in the actual RLC buffer status reports - ue_report[i]->n_rlc_report = 3; // Set this to the number of LCs for this UE + 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; - // Fill the buffer status report for each logical channel of the UE // 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]); - //TODO:Set logical channel id rlc_reports[j]->lc_id = j+1; rlc_reports[j]->has_lc_id = 1; - //TODO:Set tx queue size in bytes rlc_reports[j]->tx_queue_size = 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 = 100; - rlc_reports[j]->has_tx_queue_hol_delay = 1; + rlc_reports[j]->has_tx_queue_hol_delay = 0; //TODO:Set retransmission queue size in bytes rlc_reports[j]->retransmission_queue_size = 10; - rlc_reports[j]->has_retransmission_queue_size = 1; + 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 = 1; + 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 = 1; + 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) @@ -502,12 +495,13 @@ int enb_agent_mac_stats_reply(mid_t mod_id, if (dl_report == NULL) goto error; protocol__flex_dl_cqi_report__init(dl_report); - //TODO:Set the SFN and SF of the last report held in the agent. + dl_report->sfn_sn = get_sfn_sf(enb_id); dl_report->has_sfn_sn = 1; - //TODO:Set the number of DL CQI reports for this UE. One for each CC + //Set the number of DL CQI reports for this UE. One for each CC dl_report->n_csi_report = get_active_CC(enb_id,i); - //TODO:Create the actual CSI reports. + + //Create the actual CSI reports. Protocol__FlexDlCsi **csi_reports; csi_reports = malloc(sizeof(Protocol__FlexDlCsi *)*dl_report->n_csi_report); if (csi_reports == NULL) @@ -517,14 +511,14 @@ int enb_agent_mac_stats_reply(mid_t mod_id, if (csi_reports[j] == NULL) goto error; protocol__flex_dl_csi__init(csi_reports[j]); - //TODO: the servCellIndex for this report + //The servCellIndex for this report csi_reports[j]->serv_cell_index = j; csi_reports[j]->has_serv_cell_index = 1; - //TODO: the rank indicator value for this cc + //The rank indicator value for this cc csi_reports[j]->ri = 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 this example we use type P10, which only needs a wideband value + //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; @@ -598,16 +592,16 @@ int enb_agent_mac_stats_reply(mid_t mod_id, //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; + 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 = 1; + 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 = 1; + 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 = 1; + p_info[j]->has_carrier_index = 0; } //Add all paging info to the paging buffer rerport paging_report->paging_info = p_info; @@ -645,7 +639,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, 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 = 100; + 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) @@ -712,12 +706,12 @@ int enb_agent_mac_stats_reply(mid_t mod_id, // Current frame and subframe number ni_report->sfn_sf = get_sfn_sf(enb_id); ni_report->has_sfn_sf = 1; - // Received interference power in dbm + //TODO:Received interference power in dbm ni_report->rip = 0; - ni_report->has_rip = 1; - // Thermal noise power in dbm + ni_report->has_rip = 0; + //TODO:Thermal noise power in dbm ni_report->tnp = 0; - ni_report->has_tnp = 1; + ni_report->has_tnp = 0; ni_report->p0_nominal_pucch = get_p0_nominal_pucch(enb_id, 0); ni_report->has_p0_nominal_pucch = 1; @@ -988,13 +982,13 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Flexran protocol__flex_dl_info__init(dl_info[i]); dl_info[i]->rnti = get_ue_crnti(mod_id, i); dl_info[i]->has_rnti = 1; - /*TODO: fill in the right id of this round's HARQ process for this UE*/ + /*Fill in the right id of this round's HARQ process for this UE*/ int harq_id; int harq_status; get_harq(mod_id, UE_PCCID(mod_id,i), i, frame, subframe, &harq_id, &harq_status); dl_info[i]->harq_process_id = harq_id; dl_info[i]->has_harq_process_id = 1; - /*TODO: fill in the status of the HARQ process (2 TBs)*/ + /* Fill in the status of the HARQ process (2 TBs)*/ dl_info[i]->n_harq_status = 2; dl_info[i]->harq_status = malloc(sizeof(uint32_t) * dl_info[i]->n_harq_status); for (j = 0; j < dl_info[i]->n_harq_status; j++) { @@ -1004,7 +998,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Flexran else if (harq_status == 1) dl_info[i]->harq_status[j] = PROTOCOL__FLEX_HARQ_STATUS__FLHS_NACK; } - /*TODO: fill in the serving cell index for this UE */ + /*Fill in the serving cell index for this UE */ dl_info[i]->serv_cell_index = UE_PCCID(mod_id,i); dl_info[i]->has_serv_cell_index = 1; } @@ -1012,8 +1006,8 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Flexran sf_trigger_msg->dl_info = dl_info; - /*TODO: Fill in the number of UL reception status related info, based on the number of currently - *transmitting UEs + /* Fill in the number of UL reception status related info, based on the number of currently + * transmitting UEs */ sf_trigger_msg->n_ul_info = get_num_ues(mod_id); @@ -1031,7 +1025,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Flexran protocol__flex_ul_info__init(ul_info[i]); ul_info[i]->rnti = get_ue_crnti(mod_id, i); ul_info[i]->has_rnti = 1; - /*TODO: fill in the Tx power control command for this UE (if available)*/ + /*Fill in the Tx power control command for this UE (if available)*/ if(get_tpc(mod_id,i) != 1){ ul_info[i]->tpc = get_tpc(mod_id,i); ul_info[i]->has_tpc = 1; @@ -1042,7 +1036,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Flexran } /*TODO: fill in the amount of data in bytes in the MAC SDU received in this subframe for the given logical channel*/ - ul_info[i]->n_ul_reception = 11; + ul_info[i]->n_ul_reception = 0; ul_info[i]->ul_reception = malloc(sizeof(uint32_t) * ul_info[i]->n_ul_reception); for (j = 0; j < ul_info[i]->n_ul_reception; j++) { ul_info[i]->ul_reception[j] = 100; @@ -1050,7 +1044,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Flexran /*TODO: Fill in the reception status for each UEs data*/ ul_info[i]->reception_status = PROTOCOL__FLEX_RECEPTION_STATUS__FLRS_OK; ul_info[i]->has_reception_status = 1; - /*TODO: fill in the serving cell index for this UE */ + /*Fill in the serving cell index for this UE */ ul_info[i]->serv_cell_index = UE_PCCID(mod_id,i); ul_info[i]->has_serv_cell_index = 1; } diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index a6b9a0fe80..c5b257394b 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -81,24 +81,24 @@ void enb_agent_init_mac_agent(mid_t mod_id); int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +/* Statistics request protocol message constructor and destructor */ int enb_agent_mac_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); - int enb_agent_mac_destroy_stats_request(Protocol__FlexranMessage *msg); +/* Statistics reply protocol message constructor and destructor */ int enb_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg); - int enb_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg); +/* Scheduling request information protocol message constructor and estructor */ int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); - int enb_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg); +/* Subframe trigger protocol msssage constructor and destructor */ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); - int enb_agent_mac_destroy_sf_trigger(Protocol__FlexranMessage *msg); +/* int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage **msg); - int enb_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg); int enb_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); diff --git a/openair2/ENB_APP/enb_agent_net_comm.h b/openair2/ENB_APP/enb_agent_net_comm.h index ab42bdc34f..2a2268dc80 100644 --- a/openair2/ENB_APP/enb_agent_net_comm.h +++ b/openair2/ENB_APP/enb_agent_net_comm.h @@ -57,7 +57,6 @@ typedef struct enb_agent_channel_instance_s{ /*Send and receive messages using the channel registered for a specific agent*/ int enb_agent_msg_send(mid_t mod_id, agent_id_t agent_id, void *data, int size, int priority); - int enb_agent_msg_recv(mid_t mod_id, agent_id_t agent_id, void **data, int *size, int *priority); /*Register a channel to an agent. Use ENB_AGENT_MAX to register the From 0cee514c7316dbe7706e18ecd96e5bc61ea7e2f0 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 4 Nov 2016 13:19:08 +0200 Subject: [PATCH 267/413] Fixed problem with comment causing a bug in compilation --- openair2/ENB_APP/enb_agent_mac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/enb_agent_mac.h index c5b257394b..0716b739e5 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/enb_agent_mac.h @@ -97,7 +97,7 @@ int enb_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg); int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); int enb_agent_mac_destroy_sf_trigger(Protocol__FlexranMessage *msg); -/* +/* DL MAC scheduling decision protocol message constructor (empty command) and destructor */ int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage **msg); int enb_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg); From 8baf3e7e5786039e9c10e4c6579de15d13bf7b35 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 4 Nov 2016 17:28:04 +0200 Subject: [PATCH 268/413] Changed naming convention for flexran related calls --- cmake_targets/CMakeLists.txt | 42 +- openair1/SCHED/phy_procedures_lte_eNb.c | 8 +- openair2/COMMON/tasks_def.h | 2 +- openair2/ENB_APP/enb_app.c | 8 +- openair2/ENB_APP/enb_config.c | 56 +- openair2/ENB_APP/enb_config.h | 8 +- .../ENB_APP/{enb_agent.c => flexran_agent.c} | 138 +-- .../ENB_APP/{enb_agent.h => flexran_agent.h} | 16 +- ...nb_agent_async.c => flexran_agent_async.c} | 34 +- ...nb_agent_async.h => flexran_agent_async.h} | 20 +- ..._agent_common.c => flexran_agent_common.c} | 920 +++++++++--------- ..._agent_common.h => flexran_agent_common.h} | 276 +++--- ...rnal.c => flexran_agent_common_internal.c} | 6 +- ...rnal.h => flexran_agent_common_internal.h} | 8 +- ...{enb_agent_defs.h => flexran_agent_defs.h} | 58 +- ..._agent_extern.h => flexran_agent_extern.h} | 12 +- ...gent_handler.c => flexran_agent_handler.c} | 110 +-- .../{enb_agent_mac.c => flexran_agent_mac.c} | 246 ++--- .../{enb_agent_mac.h => flexran_agent_mac.h} | 52 +- ...nt_mac_defs.h => flexran_agent_mac_defs.h} | 32 +- ...nternal.c => flexran_agent_mac_internal.c} | 12 +- ...nternal.h => flexran_agent_mac_internal.h} | 26 +- ...nt_net_comm.c => flexran_agent_net_comm.c} | 90 +- ...nt_net_comm.h => flexran_agent_net_comm.h} | 56 +- ...manager.c => flexran_agent_task_manager.c} | 75 +- ...manager.h => flexran_agent_task_manager.h} | 53 +- openair2/LAYER2/MAC/eNB_scheduler.c | 546 +++++------ ..._mac_proto.h => flexran_agent_mac_proto.h} | 24 +- ....c => flexran_agent_scheduler_dataplane.c} | 30 +- ...e.c => flexran_agent_scheduler_dlsch_ue.c} | 22 +- ...flexran_agent_scheduler_dlsch_ue_remote.c} | 30 +- ...flexran_agent_scheduler_dlsch_ue_remote.h} | 14 +- openair2/LAYER2/MAC/flexran_dci_conversions.h | 2 +- openair2/RRC/LITE/rrc_eNB.c | 6 +- openair2/UTIL/LOG/log.c | 14 +- openair2/UTIL/LOG/log.h | 2 +- .../enb.band5.flexran.50PRB.usrpb210.conf | 182 ++++ .../CONF/enb.band5.flexran.usrpb210.conf | 182 ++++ .../enb.band7.flexran.50PRB.usrpb210.conf | 8 +- .../CONF/enb.band7.flexran.usrpb210.conf | 8 +- targets/SIMU/USER/oaisim.c | 8 +- 41 files changed, 1898 insertions(+), 1544 deletions(-) rename openair2/ENB_APP/{enb_agent.c => flexran_agent.c} (56%) rename openair2/ENB_APP/{enb_agent.h => flexran_agent.h} (83%) rename openair2/ENB_APP/{enb_agent_async.c => flexran_agent_async.c} (70%) rename openair2/ENB_APP/{enb_agent_async.h => flexran_agent_async.h} (75%) rename openair2/ENB_APP/{enb_agent_common.c => flexran_agent_common.c} (64%) rename openair2/ENB_APP/{enb_agent_common.h => flexran_agent_common.h} (51%) rename openair2/ENB_APP/{enb_agent_common_internal.c => flexran_agent_common_internal.c} (98%) rename openair2/ENB_APP/{enb_agent_common_internal.h => flexran_agent_common_internal.h} (94%) rename openair2/ENB_APP/{enb_agent_defs.h => flexran_agent_defs.h} (70%) rename openair2/ENB_APP/{enb_agent_extern.h => flexran_agent_extern.h} (87%) rename openair2/ENB_APP/{enb_agent_handler.c => flexran_agent_handler.c} (54%) rename openair2/ENB_APP/{enb_agent_mac.c => flexran_agent_mac.c} (84%) rename openair2/ENB_APP/{enb_agent_mac.h => flexran_agent_mac.h} (64%) rename openair2/ENB_APP/{enb_agent_mac_defs.h => flexran_agent_mac_defs.h} (75%) rename openair2/ENB_APP/{enb_agent_mac_internal.c => flexran_agent_mac_internal.c} (98%) rename openair2/ENB_APP/{enb_agent_mac_internal.h => flexran_agent_mac_internal.h} (82%) rename openair2/ENB_APP/{enb_agent_net_comm.c => flexran_agent_net_comm.c} (52%) rename openair2/ENB_APP/{enb_agent_net_comm.h => flexran_agent_net_comm.h} (54%) rename openair2/ENB_APP/{enb_agent_task_manager.c => flexran_agent_task_manager.c} (74%) rename openair2/ENB_APP/{enb_agent_task_manager.h => flexran_agent_task_manager.h} (68%) rename openair2/LAYER2/MAC/{enb_agent_mac_proto.h => flexran_agent_mac_proto.h} (68%) rename openair2/LAYER2/MAC/{eNB_agent_scheduler_dataplane.c => flexran_agent_scheduler_dataplane.c} (96%) rename openair2/LAYER2/MAC/{eNB_agent_scheduler_dlsch_ue.c => flexran_agent_scheduler_dlsch_ue.c} (98%) rename openair2/LAYER2/MAC/{eNB_agent_scheduler_dlsch_ue_remote.c => flexran_agent_scheduler_dlsch_ue_remote.c} (86%) rename openair2/LAYER2/MAC/{eNB_agent_scheduler_dlsch_ue_remote.h => flexran_agent_scheduler_dlsch_ue_remote.h} (85%) create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.flexran.50PRB.usrpb210.conf create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.flexran.usrpb210.conf diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 196baf166b..8f696ed653 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -621,7 +621,7 @@ add_boolean_option(MESSAGE_CHART_GENERATOR False "For generating sequenc add_boolean_option(MESSAGE_CHART_GENERATOR_RLC_MAC False "trace RLC-MAC exchanges in sequence diagrams") add_boolean_option(MESSAGE_CHART_GENERATOR_PHY False "trace some PHY exchanges in sequence diagrams") -add_boolean_option(ENB_AGENT_SB_IF True "enable eNB agent to inteface with a SDN contrller") +add_boolean_option(FLEXRAN_AGENT_SB_IF True "enable FlexRAN agent to inteface with a SDN contrller") ######################## # Include order @@ -838,7 +838,7 @@ include_directories("${OPENAIR_DIR}") # Utilities Library ################ -if (ENB_AGENT_SB_IF) +if (FLEXRAN_AGENT_SB_IF) # set the version of protobuf messages, V3 not supported yet add_list1_option(FLPT_VERSION V2 "FLPT MSG protobuf grammar version" V2 V3) @@ -899,18 +899,18 @@ if (ENB_AGENT_SB_IF) set(ASYNC_IF_LIB ASYNC_IF) include_directories(${OPENAIR2_DIR}/UTIL/ASYNC_IF) - add_library(ENB_AGENT - ${OPENAIR2_DIR}/ENB_APP/enb_agent_handler.c - ${OPENAIR2_DIR}/ENB_APP/enb_agent_common.c - ${OPENAIR2_DIR}/ENB_APP/enb_agent_common_internal.c - ${OPENAIR2_DIR}/ENB_APP/enb_agent_mac.c - ${OPENAIR2_DIR}/ENB_APP/enb_agent.c - ${OPENAIR2_DIR}/ENB_APP/enb_agent_task_manager.c - ${OPENAIR2_DIR}/ENB_APP/enb_agent_net_comm.c - ${OPENAIR2_DIR}/ENB_APP/enb_agent_async.c - ${OPENAIR2_DIR}/ENB_APP/enb_agent_mac_internal.c + 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_common_internal.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_mac.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 + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_async.c + ${OPENAIR2_DIR}/ENB_APP/flexran_agent_mac_internal.c ) - set(ENB_AGENT_LIB ENB_AGENT) + set(FLEXRAN_AGENT_LIB FLEXRAN_AGENT) #include_directories(${OPENAIR2_DIR}/ENB_APP) set(PROTOBUF_LIB "protobuf-c") @@ -1184,9 +1184,9 @@ set (MAC_SRC ${MAC_DIR}/eNB_scheduler_RA.c ${MAC_DIR}/pre_processor.c ${MAC_DIR}/config.c - ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue.c - ${MAC_DIR}/eNB_agent_scheduler_dataplane.c - ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue_remote.c + ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue.c + ${MAC_DIR}/flexran_agent_scheduler_dataplane.c + ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue_remote.c ) set (ENB_APP_SRC @@ -1201,8 +1201,8 @@ add_library(L2 # ${OPENAIR2_DIR}/RRC/L2_INTERFACE/openair_rrc_L2_interface.c) #Test for adding a shared library -add_library(default_sched SHARED ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue.c) -add_library(remote_sched SHARED ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue_remote.c) +add_library(default_sched SHARED ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue.c) +add_library(remote_sched SHARED ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue_remote.c) # L3 Libs ########################## @@ -1757,7 +1757,7 @@ add_executable(lte-softmodem target_link_libraries (lte-softmodem -ldl -Wl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} LFDS7 + RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 -Wl,--end-group ) target_link_libraries (lte-softmodem ${LIBXML2_LIBRARIES}) @@ -1791,7 +1791,7 @@ add_executable(lte-softmodem-nos1 ) target_link_libraries (lte-softmodem-nos1 -Wl,--start-group - RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} LFDS7 + RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 -Wl,--end-group ) target_link_libraries (lte-softmodem-nos1 ${LIBXML2_LIBRARIES}) @@ -1936,7 +1936,7 @@ add_executable(oaisim_nos1 target_include_directories(oaisim_nos1 PUBLIC ${OPENAIR_TARGETS}/SIMU/USER) target_link_libraries (oaisim_nos1 -Wl,--start-group - RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${ENB_AGENT_LIB} LFDS7 + RRC_LIB X2AP_LIB SECU_CN UTIL HASHTABLE SCHED_LIB PHY LFDS ${MSC_LIB} L2 ${RAL_LIB} SIMU SIMU_ETH SECU_OSA ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 -Wl,--end-group ) target_link_libraries (oaisim_nos1 ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES}) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index c9eaa0d4af..b5fd7efd70 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -63,9 +63,9 @@ //Agent-related headers -#include "ENB_APP/enb_agent_extern.h" -#include "ENB_APP/enb_agent_mac.h" -#include "LAYER2/MAC/enb_agent_mac_proto.h" +#include "ENB_APP/flexran_agent_extern.h" +#include "ENB_APP/flexran_agent_mac.h" +#include "LAYER2/MAC/flexran_agent_mac_proto.h" //#define DIAG_PHY @@ -1372,7 +1372,7 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, #ifndef DISABLE_SF_TRIGGER //Send subframe trigger to the controller if (mac_agent_registered[eNB->Mod_id]) { - agent_mac_xface[eNB->Mod_id]->enb_agent_send_sf_trigger(eNB->Mod_id); + agent_mac_xface[eNB->Mod_id]->flexran_agent_send_sf_trigger(eNB->Mod_id); } #endif diff --git a/openair2/COMMON/tasks_def.h b/openair2/COMMON/tasks_def.h index 7d093c4400..c9e210fd1f 100644 --- a/openair2/COMMON/tasks_def.h +++ b/openair2/COMMON/tasks_def.h @@ -56,7 +56,7 @@ TASK_DEF(TASK_SCTP, TASK_PRIORITY_MED, 200) /// eNB APP task TASK_DEF(TASK_ENB_APP, TASK_PRIORITY_MED, 200) /// eNB Agent task -TASK_DEF(TASK_ENB_AGENT, TASK_PRIORITY_MED, 200) +TASK_DEF(TASK_FLEXRAN_AGENT, TASK_PRIORITY_MED, 200) // UE tasks and sub-tasks: //// Layer 2 and Layer 1 sub-tasks diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index ce3b288388..3734bc4a2b 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -49,8 +49,8 @@ # include "gtpv1u_eNB_task.h" # endif -#if defined(ENB_AGENT_SB_IF) -# include "enb_agent.h" +#if defined(FLEXRAN_AGENT_SB_IF) +# include "flexran_agent.h" #endif extern unsigned char NB_eNB_INST; @@ -314,11 +314,11 @@ void *eNB_app_task(void *args_p) configure_rrc(enb_id, enb_properties_p); } -#if defined (ENB_AGENT_SB_IF) +#if defined (FLEXRAN_AGENT_SB_IF) for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) { printf("\n start enb agent %d\n", enb_id); - enb_agent_start(enb_id, enb_properties_p); + flexran_agent_start(enb_id, enb_properties_p); } #endif diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c index 92eefce7b0..fdf953597e 100644 --- a/openair2/ENB_APP/enb_config.c +++ b/openair2/ENB_APP/enb_config.c @@ -191,10 +191,10 @@ #define ENB_CONFIG_STRING_ENB_PORT_FOR_S1U "ENB_PORT_FOR_S1U" #define ENB_CONFIG_STRING_NETWORK_CONTROLLER_CONFIG "NETWORK_CONTROLLER" -#define ENB_CONFIG_STRING_ENB_AGENT_INTERFACE_NAME "ENB_AGENT_INTERFACE_NAME" -#define ENB_CONFIG_STRING_ENB_AGENT_IPV4_ADDRESS "ENB_AGENT_IPV4_ADDRESS" -#define ENB_CONFIG_STRING_ENB_AGENT_PORT "ENB_AGENT_PORT" -#define ENB_CONFIG_STRING_ENB_AGENT_CACHE "ENB_AGENT_CACHE" +#define ENB_CONFIG_STRING_FLEXRAN_AGENT_INTERFACE_NAME "FLEXRAN_AGENT_INTERFACE_NAME" +#define ENB_CONFIG_STRING_FLEXRAN_AGENT_IPV4_ADDRESS "FLEXRAN_AGENT_IPV4_ADDRESS" +#define ENB_CONFIG_STRING_FLEXRAN_AGENT_PORT "FLEXRAN_AGENT_PORT" +#define ENB_CONFIG_STRING_FLEXRAN_AGENT_CACHE "FLEXRAN_AGENT_CACHE" #define ENB_CONFIG_STRING_RRH_GW_CONFIG "rrh_gw_config" #define ENB_CONFIG_STRING_RRH_GW_LOCAL_IF_NAME "local_if_name" @@ -341,12 +341,12 @@ void enb_config_display(void) } } -#if defined(ENB_AGENT_SB_IF) - printf( "\nENB AGENT CONFIG : \n\n"); - printf( "\tInterface name: \t%s:\n",enb_properties.properties[i]->enb_agent_interface_name); - printf( "\tInterface IP Address: \t%s:\n",enb_properties.properties[i]->enb_agent_ipv4_address); - printf( "\tInterface PORT: \t%d:\n\n",enb_properties.properties[i]->enb_agent_port); - printf( "\tCache directory: \t%s:\n",enb_properties.properties[i]->enb_agent_cache); +#if defined(FLEXRAN_AGENT_SB_IF) + printf( "\nFLEXRAN AGENT CONFIG : \n\n"); + printf( "\tInterface name: \t%s:\n",enb_properties.properties[i]->flexran_agent_interface_name); + printf( "\tInterface IP Address: \t%s:\n",enb_properties.properties[i]->flexran_agent_ipv4_address); + printf( "\tInterface PORT: \t%d:\n\n",enb_properties.properties[i]->flexran_agent_port); + printf( "\tCache directory: \t%s:\n",enb_properties.properties[i]->flexran_agent_cache); #endif @@ -674,10 +674,10 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) char *address = NULL; char *cidr = NULL; char *astring = NULL; - char* enb_agent_interface_name = NULL; - char* enb_agent_ipv4_address = NULL; - libconfig_int enb_agent_port = 0; - char* enb_agent_cache = NULL; + char* flexran_agent_interface_name = NULL; + char* flexran_agent_ipv4_address = NULL; + libconfig_int flexran_agent_port = 0; + char* flexran_agent_cache = NULL; libconfig_int otg_ue_id = 0; char* otg_app_type = NULL; char* otg_bg_traffic = NULL; @@ -2481,26 +2481,26 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP) if (subsetting != NULL) { if ( ( - config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_AGENT_INTERFACE_NAME, - (const char **)&enb_agent_interface_name) - && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_AGENT_IPV4_ADDRESS, - (const char **)&enb_agent_ipv4_address) - && config_setting_lookup_int(subsetting, ENB_CONFIG_STRING_ENB_AGENT_PORT, - &enb_agent_port) - && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_AGENT_CACHE, - (const char **)&enb_agent_cache) + config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_INTERFACE_NAME, + (const char **)&flexran_agent_interface_name) + && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_IPV4_ADDRESS, + (const char **)&flexran_agent_ipv4_address) + && config_setting_lookup_int(subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_PORT, + &flexran_agent_port) + && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_FLEXRAN_AGENT_CACHE, + (const char **)&flexran_agent_cache) ) ) { - enb_properties.properties[enb_properties_index]->enb_agent_interface_name = strdup(enb_agent_interface_name); - cidr = enb_agent_ipv4_address; + enb_properties.properties[enb_properties_index]->flexran_agent_interface_name = strdup(flexran_agent_interface_name); + cidr = flexran_agent_ipv4_address; address = strtok(cidr, "/"); - enb_properties.properties[enb_properties_index]->enb_agent_ipv4_address = strdup(address); + enb_properties.properties[enb_properties_index]->flexran_agent_ipv4_address = strdup(address); /* if (address) { - IPV4_STR_ADDR_TO_INT_NWBO (address, enb_properties.properties[enb_properties_index]->enb_agent_ipv4_address, "BAD IP ADDRESS FORMAT FOR eNB Agent !\n" ); + IPV4_STR_ADDR_TO_INT_NWBO (address, enb_properties.properties[enb_properties_index]->flexran_agent_ipv4_address, "BAD IP ADDRESS FORMAT FOR eNB Agent !\n" ); }*/ - enb_properties.properties[enb_properties_index]->enb_agent_port = enb_agent_port; - enb_properties.properties[enb_properties_index]->enb_agent_cache = strdup(enb_agent_cache); + enb_properties.properties[enb_properties_index]->flexran_agent_port = flexran_agent_port; + enb_properties.properties[enb_properties_index]->flexran_agent_cache = strdup(flexran_agent_cache); } } diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h index 594db77a1f..fd53395311 100644 --- a/openair2/ENB_APP/enb_config.h +++ b/openair2/ENB_APP/enb_config.h @@ -228,10 +228,10 @@ typedef struct Enb_properties_s { char *enb_interface_name_for_S1_MME; in_addr_t enb_ipv4_address_for_S1_MME; - char *enb_agent_interface_name; - in_addr_t enb_agent_ipv4_address; - tcp_udp_port_t enb_agent_port; - char *enb_agent_cache; + char *flexran_agent_interface_name; + in_addr_t flexran_agent_ipv4_address; + tcp_udp_port_t flexran_agent_port; + char *flexran_agent_cache; /* Nb of RRH to connect to */ uint8_t nb_rrh_gw; diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/flexran_agent.c similarity index 56% rename from openair2/ENB_APP/enb_agent.c rename to openair2/ENB_APP/flexran_agent.c index 179392b3a2..8984e39971 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -27,28 +27,28 @@ *******************************************************************************/ -/*! \file enb_agent.h - * \brief top level enb agent receive thread and itti task +/*! \file flexran_agent.h + * \brief top level flexran agent receive thread and itti task * \author Xenofon Foukas and Navid Nikaein * \date 2016 * \version 0.1 */ -#include "enb_agent_common.h" +#include "flexran_agent_common.h" #include "log.h" -#include "enb_agent.h" -#include "enb_agent_mac_defs.h" +#include "flexran_agent.h" +#include "flexran_agent_mac_defs.h" -#include "enb_agent_extern.h" +#include "flexran_agent_extern.h" #include "assertions.h" -#include "enb_agent_net_comm.h" -#include "enb_agent_async.h" +#include "flexran_agent_net_comm.h" +#include "flexran_agent_async.h" //#define TEST_TIMER -enb_agent_instance_t enb_agent[NUM_MAX_ENB]; +flexran_agent_instance_t flexran_agent[NUM_MAX_ENB]; char in_ip[40]; static uint16_t in_port; @@ -57,7 +57,7 @@ char local_cache[40]; void *send_thread(void *args); void *receive_thread(void *args); pthread_t new_thread(void *(*f)(void *), void *b); -Protocol__FlexranMessage *enb_agent_timeout(void* args); +Protocol__FlexranMessage *flexran_agent_timeout(void* args); int agent_task_created = 0; @@ -65,9 +65,9 @@ int agent_task_created = 0; * enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller * and can interact with other itti tasks */ -void *enb_agent_task(void *args){ +void *flexran_agent_task(void *args){ - //enb_agent_instance_t *d = (enb_agent_instance_t *) args; + //flexran_agent_instance_t *d = (flexran_agent_instance_t *) args; Protocol__FlexranMessage *msg; void *data; int size; @@ -78,13 +78,13 @@ void *enb_agent_task(void *args){ const char *msg_name = NULL; instance_t instance; int result; - struct enb_agent_timer_element_s * elem = NULL; + struct flexran_agent_timer_element_s * elem = NULL; - itti_mark_task_ready(TASK_ENB_AGENT); + itti_mark_task_ready(TASK_FLEXRAN_AGENT); do { // Wait for a message - itti_receive_msg (TASK_ENB_AGENT, &msg_p); + itti_receive_msg (TASK_FLEXRAN_AGENT, &msg_p); DevAssert(msg_p != NULL); msg_name = ITTI_MSG_NAME (msg_p); instance = ITTI_MSG_INSTANCE (msg_p); @@ -95,25 +95,25 @@ void *enb_agent_task(void *args){ break; case MESSAGE_TEST: - LOG_I(ENB_AGENT, "Received %s\n", ITTI_MSG_NAME(msg_p)); + LOG_I(FLEXRAN_AGENT, "Received %s\n", ITTI_MSG_NAME(msg_p)); break; case TIMER_HAS_EXPIRED: - msg = enb_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, msg_p->ittiMsg.timer_has_expired.arg); + msg = flexran_agent_process_timeout(msg_p->ittiMsg.timer_has_expired.timer_id, msg_p->ittiMsg.timer_has_expired.arg); if (msg != NULL){ - data=enb_agent_pack_message(msg,&size); + data=flexran_agent_pack_message(msg,&size); elem = get_timer_entry(msg_p->ittiMsg.timer_has_expired.timer_id); - if (enb_agent_msg_send(elem->agent_id, ENB_AGENT_DEFAULT, data, size, priority)) { + if (flexran_agent_msg_send(elem->agent_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } - LOG_D(ENB_AGENT,"sent message with size %d\n", size); + LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); } break; default: - LOG_E(ENB_AGENT, "Received unexpected message %s\n", msg_name); + LOG_E(FLEXRAN_AGENT, "Received unexpected message %s\n", msg_name); break; } @@ -121,7 +121,7 @@ void *enb_agent_task(void *args){ AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); continue; error: - LOG_E(ENB_AGENT,"enb_agent_task: error %d occured\n",err_code); + LOG_E(FLEXRAN_AGENT,"flexran_agent_task: error %d occured\n",err_code); } while (1); return NULL; @@ -129,7 +129,7 @@ void *enb_agent_task(void *args){ void *receive_thread(void *args) { - enb_agent_instance_t *d = args; + flexran_agent_instance_t *d = args; void *data; int size; int priority; @@ -139,25 +139,25 @@ void *receive_thread(void *args) { while (1) { - while (enb_agent_msg_recv(d->enb_id, ENB_AGENT_DEFAULT, &data, &size, &priority) == 0) { + while (flexran_agent_msg_recv(d->enb_id, FLEXRAN_AGENT_DEFAULT, &data, &size, &priority) == 0) { - LOG_D(ENB_AGENT,"received message with size %d\n", size); + LOG_D(FLEXRAN_AGENT,"received message with size %d\n", size); // Invoke the message handler - msg=enb_agent_handle_message(d->enb_id, data, size); + msg=flexran_agent_handle_message(d->enb_id, data, size); free(data); // check if there is something to send back to the controller if (msg != NULL){ - data=enb_agent_pack_message(msg,&size); + data=flexran_agent_pack_message(msg,&size); - if (enb_agent_msg_send(d->enb_id, ENB_AGENT_DEFAULT, data, size, priority)) { + if (flexran_agent_msg_send(d->enb_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } - LOG_D(ENB_AGENT,"sent message with size %d\n", size); + LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); } } } @@ -165,7 +165,7 @@ void *receive_thread(void *args) { return NULL; error: - LOG_E(ENB_AGENT,"receive_thread: error %d occured\n",err_code); + LOG_E(FLEXRAN_AGENT,"receive_thread: error %d occured\n",err_code); return NULL; } @@ -203,37 +203,37 @@ pthread_t new_thread(void *(*f)(void *), void *b) { } int channel_container_init = 0; -int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ +int flexran_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ int channel_id; - set_enb_vars(mod_id, RAN_LTE_OAI); - enb_agent[mod_id].enb_id = mod_id; + flexran_set_enb_vars(mod_id, RAN_LTE_OAI); + flexran_agent[mod_id].enb_id = mod_id; /* * check the configuration */ - if (enb_properties->properties[mod_id]->enb_agent_cache != NULL) { - strncpy(local_cache, enb_properties->properties[mod_id]->enb_agent_cache, sizeof(local_cache)); + if (enb_properties->properties[mod_id]->flexran_agent_cache != NULL) { + strncpy(local_cache, enb_properties->properties[mod_id]->flexran_agent_cache, sizeof(local_cache)); local_cache[sizeof(local_cache) - 1] = 0; } else { - strcpy(local_cache, DEFAULT_ENB_AGENT_CACHE); + strcpy(local_cache, DEFAULT_FLEXRAN_AGENT_CACHE); } - if (enb_properties->properties[mod_id]->enb_agent_ipv4_address != NULL) { - strncpy(in_ip, enb_properties->properties[mod_id]->enb_agent_ipv4_address, sizeof(in_ip) ); + if (enb_properties->properties[mod_id]->flexran_agent_ipv4_address != NULL) { + strncpy(in_ip, enb_properties->properties[mod_id]->flexran_agent_ipv4_address, sizeof(in_ip) ); in_ip[sizeof(in_ip) - 1] = 0; // terminate string } else { - strcpy(in_ip, DEFAULT_ENB_AGENT_IPv4_ADDRESS ); + strcpy(in_ip, DEFAULT_FLEXRAN_AGENT_IPv4_ADDRESS ); } - if (enb_properties->properties[mod_id]->enb_agent_port != 0 ) { - in_port = enb_properties->properties[mod_id]->enb_agent_port; + if (enb_properties->properties[mod_id]->flexran_agent_port != 0 ) { + in_port = enb_properties->properties[mod_id]->flexran_agent_port; } else { - in_port = DEFAULT_ENB_AGENT_PORT ; + in_port = DEFAULT_FLEXRAN_AGENT_PORT ; } - LOG_I(ENB_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n", - enb_agent[mod_id].enb_id, + LOG_I(FLEXRAN_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n", + flexran_agent[mod_id].enb_id, in_ip, in_port); @@ -241,87 +241,87 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ * Initialize the channel container */ if (!channel_container_init) { - enb_agent_init_channel_container(); + flexran_agent_init_channel_container(); channel_container_init = 1; } /*Create the async channel info*/ - enb_agent_instance_t *channel_info = enb_agent_async_channel_info(mod_id, in_ip, in_port); + flexran_agent_instance_t *channel_info = flexran_agent_async_channel_info(mod_id, in_ip, in_port); /*Create a channel using the async channel info*/ - channel_id = enb_agent_create_channel((void *) channel_info, - enb_agent_async_msg_send, - enb_agent_async_msg_recv, - enb_agent_async_release); + channel_id = flexran_agent_create_channel((void *) channel_info, + flexran_agent_async_msg_send, + flexran_agent_async_msg_recv, + flexran_agent_async_release); if (channel_id <= 0) { goto error; } - enb_agent_channel_t *channel = get_channel(channel_id); + flexran_agent_channel_t *channel = get_channel(channel_id); if (channel == NULL) { goto error; } - /*Register the channel for all underlying agents (use ENB_AGENT_MAX)*/ - enb_agent_register_channel(mod_id, channel, ENB_AGENT_MAX); + /*Register the channel for all underlying agents (use FLEXRAN_AGENT_MAX)*/ + flexran_agent_register_channel(mod_id, channel, FLEXRAN_AGENT_MAX); /*Example of registration for a specific agent(MAC): - *enb_agent_register_channel(mod_id, channel, ENB_AGENT_MAC); + *flexran_agent_register_channel(mod_id, channel, FLEXRAN_AGENT_MAC); */ /*Initialize the continuous MAC stats update mechanism*/ - enb_agent_init_cont_mac_stats_update(mod_id); + flexran_agent_init_cont_mac_stats_update(mod_id); - new_thread(receive_thread, &enb_agent[mod_id]); + new_thread(receive_thread, &flexran_agent[mod_id]); /*Initialize and register the mac xface. Must be modified later *for more flexibility in agent management */ AGENT_MAC_xface *mac_agent_xface = (AGENT_MAC_xface *) malloc(sizeof(AGENT_MAC_xface)); - enb_agent_register_mac_xface(mod_id, mac_agent_xface); + flexran_agent_register_mac_xface(mod_id, mac_agent_xface); /* * initilize a timer */ - enb_agent_init_timer(); + flexran_agent_init_timer(); /* * Initialize the mac agent */ - enb_agent_init_mac_agent(mod_id); + flexran_agent_init_mac_agent(mod_id); /* * start the enb agent task for tx and interaction with the underlying network function */ if (!agent_task_created) { - if (itti_create_task (TASK_ENB_AGENT, enb_agent_task, (void *) &enb_agent[mod_id]) < 0) { - LOG_E(ENB_AGENT, "Create task for eNB Agent failed\n"); + if (itti_create_task (TASK_FLEXRAN_AGENT, flexran_agent_task, (void *) &flexran_agent[mod_id]) < 0) { + LOG_E(FLEXRAN_AGENT, "Create task for FlexRAN Agent failed\n"); return -1; } agent_task_created = 1; } - LOG_I(ENB_AGENT,"client ends\n"); + LOG_I(FLEXRAN_AGENT,"client ends\n"); return 0; error: - LOG_I(ENB_AGENT,"there was an error\n"); + LOG_I(FLEXRAN_AGENT,"there was an error\n"); return 1; } -Protocol__FlexranMessage *enb_agent_timeout(void* args){ +Protocol__FlexranMessage *flexran_agent_timeout(void* args){ - // enb_agent_timer_args_t *timer_args = calloc(1, sizeof(*timer_args)); + // flexran_agent_timer_args_t *timer_args = calloc(1, sizeof(*timer_args)); //memcpy (timer_args, args, sizeof(*timer_args)); - enb_agent_timer_args_t *timer_args = (enb_agent_timer_args_t *) args; + flexran_agent_timer_args_t *timer_args = (flexran_agent_timer_args_t *) args; - LOG_I(ENB_AGENT, "enb_agent %d timeout\n", timer_args->mod_id); - //LOG_I(ENB_AGENT, "eNB action %d ENB flags %d \n", timer_args->cc_actions,timer_args->cc_report_flags); - //LOG_I(ENB_AGENT, "UE action %d UE flags %d \n", timer_args->ue_actions,timer_args->ue_report_flags); + LOG_I(FLEXRAN_AGENT, "flexran_agent %d timeout\n", timer_args->mod_id); + //LOG_I(FLEXRAN_AGENT, "eNB action %d ENB flags %d \n", timer_args->cc_actions,timer_args->cc_report_flags); + //LOG_I(FLEXRAN_AGENT, "UE action %d UE flags %d \n", timer_args->ue_actions,timer_args->ue_report_flags); return NULL; } diff --git a/openair2/ENB_APP/enb_agent.h b/openair2/ENB_APP/flexran_agent.h similarity index 83% rename from openair2/ENB_APP/enb_agent.h rename to openair2/ENB_APP/flexran_agent.h index a75790d8b0..beed4b9885 100644 --- a/openair2/ENB_APP/enb_agent.h +++ b/openair2/ENB_APP/flexran_agent.h @@ -28,28 +28,28 @@ *******************************************************************************/ -/*! \file enb_agent.h - * \brief top level enb agent +/*! \file flexran_agent.h + * \brief top level flexran agent * \author Navid Nikaein and Xenofon Foukas * \date 2016 * \version 0.1 */ -#ifndef ENB_AGENT_H_ -#define ENB_AGENT_H_ +#ifndef FLEXRAN_AGENT_H_ +#define FLEXRAN_AGENT_H_ #include "enb_config.h" // for enb properties -#include "enb_agent_common.h" +#include "flexran_agent_common.h" /* Initiation and termination of the eNodeB agent */ -int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties); -int enb_agent_stop(mid_t mod_id); +int flexran_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties); +int flexran_agent_stop(mid_t mod_id); /* * enb agent task mainly wakes up the tx thread for periodic and oneshot messages to the controller * and can interact with other itti tasks */ -void *enb_agent_task(void *args); +void *flexran_agent_task(void *args); #endif diff --git a/openair2/ENB_APP/enb_agent_async.c b/openair2/ENB_APP/flexran_agent_async.c similarity index 70% rename from openair2/ENB_APP/enb_agent_async.c rename to openair2/ENB_APP/flexran_agent_async.c index a626566a8d..ae0273a668 100644 --- a/openair2/ENB_APP/enb_agent_async.c +++ b/openair2/ENB_APP/flexran_agent_async.c @@ -27,22 +27,22 @@ *******************************************************************************/ -/*! \file enb_agent_async.c +/*! \file flexran_agent_async.c * \brief channel implementation for async interface * \author Xenofon Foukas * \date 2016 * \version 0.1 */ -#include "enb_agent_async.h" -#include "enb_agent_defs.h" +#include "flexran_agent_async.h" +#include "flexran_agent_defs.h" #include "log.h" -enb_agent_async_channel_t * enb_agent_async_channel_info(mid_t mod_id, char *dst_ip, uint16_t dst_port) { +flexran_agent_async_channel_t * flexran_agent_async_channel_info(mid_t mod_id, char *dst_ip, uint16_t dst_port) { - enb_agent_async_channel_t *channel; - channel = (enb_agent_async_channel_t *) malloc(sizeof(enb_agent_channel_t)); + flexran_agent_async_channel_t *channel; + channel = (flexran_agent_async_channel_t *) malloc(sizeof(flexran_agent_channel_t)); if (channel == NULL) goto error; @@ -52,7 +52,7 @@ enb_agent_async_channel_t * enb_agent_async_channel_info(mid_t mod_id, char *dst channel->link = new_link_client(dst_ip, dst_port); if (channel->link == NULL) goto error; - LOG_I(ENB_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n", + LOG_I(FLEXRAN_AGENT,"starting enb agent client for module id %d on ipv4 %s, port %d\n", channel->enb_id, dst_ip, dst_port); @@ -75,27 +75,27 @@ enb_agent_async_channel_t * enb_agent_async_channel_info(mid_t mod_id, char *dst return channel; error: - LOG_I(ENB_AGENT,"there was an error\n"); + LOG_I(FLEXRAN_AGENT,"there was an error\n"); return 1; } -int enb_agent_async_msg_send(void *data, int size, int priority, void *channel_info) { - enb_agent_async_channel_t *channel; - channel = (enb_agent_channel_t *)channel_info; +int flexran_agent_async_msg_send(void *data, int size, int priority, void *channel_info) { + flexran_agent_async_channel_t *channel; + channel = (flexran_agent_channel_t *)channel_info; return message_put(channel->send_queue, data, size, priority); } -int enb_agent_async_msg_recv(void **data, int *size, int *priority, void *channel_info) { - enb_agent_async_channel_t *channel; - channel = (enb_agent_async_channel_t *)channel_info; +int flexran_agent_async_msg_recv(void **data, int *size, int *priority, void *channel_info) { + flexran_agent_async_channel_t *channel; + channel = (flexran_agent_async_channel_t *)channel_info; return message_get(channel->receive_queue, data, size, priority); } -void enb_agent_async_release(enb_agent_channel_t *channel) { - enb_agent_async_channel_t *channel_info; - channel_info = (enb_agent_async_channel_t *) channel->channel_info; +void flexran_agent_async_release(flexran_agent_channel_t *channel) { + flexran_agent_async_channel_t *channel_info; + channel_info = (flexran_agent_async_channel_t *) channel->channel_info; destroy_link_manager(channel_info->manager); diff --git a/openair2/ENB_APP/enb_agent_async.h b/openair2/ENB_APP/flexran_agent_async.h similarity index 75% rename from openair2/ENB_APP/enb_agent_async.h rename to openair2/ENB_APP/flexran_agent_async.h index a8c4ae90fe..3e5c21463a 100644 --- a/openair2/ENB_APP/enb_agent_async.h +++ b/openair2/ENB_APP/flexran_agent_async.h @@ -27,17 +27,17 @@ *******************************************************************************/ -/*! \file enb_agent_async.h +/*! \file flexran_agent_async.h * \brief channel implementation for async interface * \author Xenofon Foukas * \date 2016 * \version 0.1 */ -#ifndef ENB_AGENT_ASYNC_H_ -#define ENB_AGENT_ASYNC_H_ +#ifndef FLEXRAN_AGENT_ASYNC_H_ +#define FLEXRAN_AGENT_ASYNC_H_ -#include "enb_agent_net_comm.h" +#include "flexran_agent_net_comm.h" typedef struct { mid_t enb_id; @@ -45,19 +45,19 @@ typedef struct { message_queue_t *send_queue; message_queue_t *receive_queue; link_manager_t *manager; -} enb_agent_async_channel_t; +} flexran_agent_async_channel_t; /* Create a new channel for a given destination ip and destination port */ -enb_agent_async_channel_t * enb_agent_async_channel_info(mid_t mod_id, char *dst_ip, uint16_t dst_port); +flexran_agent_async_channel_t * flexran_agent_async_channel_info(mid_t mod_id, char *dst_ip, uint16_t dst_port); /* Send a message to the given channel */ -int enb_agent_async_msg_send(void *data, int size, int priority, void *channel_info); +int flexran_agent_async_msg_send(void *data, int size, int priority, void *channel_info); /* Receive a message from a given channel */ -int enb_agent_async_msg_recv(void **data, int *size, int *priority, void *channel_info); +int flexran_agent_async_msg_recv(void **data, int *size, int *priority, void *channel_info); /* Release a channel */ -void enb_agent_async_release(enb_agent_channel_t *channel); +void flexran_agent_async_release(flexran_agent_channel_t *channel); -#endif /*ENB_AGENT_ASYNC_H_*/ +#endif /*FLEXRAN_AGENT_ASYNC_H_*/ diff --git a/openair2/ENB_APP/enb_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c similarity index 64% rename from openair2/ENB_APP/enb_agent_common.c rename to openair2/ENB_APP/flexran_agent_common.c index 51ade8d851..302c792771 100644 --- a/openair2/ENB_APP/enb_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -27,7 +27,7 @@ *******************************************************************************/ -/*! \file enb_agent_common.c +/*! \file flexran_agent_common.c * \brief common primitives for all agents * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein * \date 2016 @@ -37,9 +37,9 @@ #include #include -#include "enb_agent_common.h" -#include "enb_agent_common_internal.h" -#include "enb_agent_extern.h" +#include "flexran_agent_common.h" +#include "flexran_agent_common_internal.h" +#include "flexran_agent_extern.h" #include "PHY/extern.h" #include "log.h" @@ -56,7 +56,7 @@ void * enb_rrc[NUM_MAX_ENB]; * message primitives */ -int enb_agent_serialize_message(Protocol__FlexranMessage *msg, void **buf, int *size) { +int flexran_agent_serialize_message(Protocol__FlexranMessage *msg, void **buf, int *size) { *size = protocol__flexran_message__get_packed_size(msg); @@ -69,7 +69,7 @@ int enb_agent_serialize_message(Protocol__FlexranMessage *msg, void **buf, int * return 0; error: - LOG_E(ENB_AGENT, "an error occured\n"); // change the com + LOG_E(FLEXRAN_AGENT, "an error occured\n"); // change the com return -1; } @@ -77,7 +77,7 @@ int enb_agent_serialize_message(Protocol__FlexranMessage *msg, void **buf, int * /* We assume that the buffer size is equal to the message size. Should be chekced durint Tx/Rx */ -int enb_agent_deserialize_message(void *data, int size, Protocol__FlexranMessage **msg) { +int flexran_agent_deserialize_message(void *data, int size, Protocol__FlexranMessage **msg) { *msg = protocol__flexran_message__unpack(NULL, size, data); if (*msg == NULL) goto error; @@ -91,7 +91,7 @@ int enb_agent_deserialize_message(void *data, int size, Protocol__FlexranMessage -int flex_create_header(xid_t xid, Protocol__FlexType type, Protocol__FlexHeader **header) { +int flexran_create_header(xid_t xid, Protocol__FlexType type, Protocol__FlexHeader **header) { *header = malloc(sizeof(Protocol__FlexHeader)); if(*header == NULL) @@ -108,17 +108,17 @@ int flex_create_header(xid_t xid, Protocol__FlexType type, Protocol__FlexHeader return 0; error: - LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + LOG_E(FLEXRAN_AGENT, "%s: an error occured\n", __FUNCTION__); return -1; } -int enb_agent_hello(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { +int flexran_agent_hello(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { Protocol__FlexHeader *header; /*TODO: Need to set random xid or xid from received hello message*/ xid_t xid = 1; - if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_HELLO, &header) != 0) + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_HELLO, &header) != 0) goto error; Protocol__FlexHello *hello_msg; @@ -146,12 +146,12 @@ int enb_agent_hello(mid_t mod_id, const void *params, Protocol__FlexranMessage * free(hello_msg); if(*msg != NULL) free(*msg); - LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + LOG_E(FLEXRAN_AGENT, "%s: an error occured\n", __FUNCTION__); return -1; } -int enb_agent_destroy_hello(Protocol__FlexranMessage *msg) { +int flexran_agent_destroy_hello(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_HELLO_MSG) goto error; @@ -162,16 +162,16 @@ int enb_agent_destroy_hello(Protocol__FlexranMessage *msg) { return 0; error: - LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + LOG_E(FLEXRAN_AGENT, "%s: an error occured\n", __FUNCTION__); return -1; } -int enb_agent_echo_request(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg) { +int flexran_agent_echo_request(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg) { Protocol__FlexHeader *header; /*TODO: Need to set a random xid*/ xid_t xid = 1; - if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_ECHO_REQUEST, &header) != 0) + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_ECHO_REQUEST, &header) != 0) goto error; Protocol__FlexEchoRequest *echo_request_msg; @@ -202,7 +202,7 @@ int enb_agent_echo_request(mid_t mod_id, const void* params, Protocol__FlexranMe } -int enb_agent_destroy_echo_request(Protocol__FlexranMessage *msg) { +int flexran_agent_destroy_echo_request(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_ECHO_REQUEST_MSG) goto error; @@ -212,13 +212,13 @@ int enb_agent_destroy_echo_request(Protocol__FlexranMessage *msg) { return 0; error: - LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + LOG_E(FLEXRAN_AGENT, "%s: an error occured\n", __FUNCTION__); return -1; } -int enb_agent_echo_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { +int flexran_agent_echo_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { xid_t xid; Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; @@ -226,7 +226,7 @@ int enb_agent_echo_reply(mid_t mod_id, const void *params, Protocol__FlexranMess xid = (echo_req->header)->xid; Protocol__FlexHeader *header; - if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_ECHO_REPLY, &header) != 0) + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_ECHO_REPLY, &header) != 0) goto error; Protocol__FlexEchoReply *echo_reply_msg; @@ -253,12 +253,12 @@ int enb_agent_echo_reply(mid_t mod_id, const void *params, Protocol__FlexranMess free(echo_reply_msg); if(*msg != NULL) free(*msg); - LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + LOG_E(FLEXRAN_AGENT, "%s: an error occured\n", __FUNCTION__); return -1; } -int enb_agent_destroy_echo_reply(Protocol__FlexranMessage *msg) { +int flexran_agent_destroy_echo_reply(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_ECHO_REPLY_MSG) goto error; @@ -268,19 +268,19 @@ int enb_agent_destroy_echo_reply(Protocol__FlexranMessage *msg) { return 0; error: - LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + LOG_E(FLEXRAN_AGENT, "%s: an error occured\n", __FUNCTION__); return -1; } -int enb_agent_destroy_enb_config_reply(Protocol__FlexranMessage *msg) { +int flexran_agent_destroy_enb_config_reply(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG) goto error; free(msg->enb_config_reply_msg->header); int i, j; Protocol__FlexEnbConfigReply *reply = msg->enb_config_reply_msg; - for(i = 0; i < reply->n_cell_config;i++){ + for(i = 0; i < reply->n_cell_config;i++) { free(reply->cell_config[i]->mbsfn_subframe_config_rfoffset); free(reply->cell_config[i]->mbsfn_subframe_config_rfperiod); free(reply->cell_config[i]->mbsfn_subframe_config_sfalloc); @@ -299,11 +299,11 @@ int enb_agent_destroy_enb_config_reply(Protocol__FlexranMessage *msg) { return 0; error: - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + //LOG_E(FLEXRAN_AGENT, "%s: an error occured\n", __FUNCTION__); return -1; } -int enb_agent_destroy_ue_config_reply(Protocol__FlexranMessage *msg) { +int flexran_agent_destroy_ue_config_reply(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG) goto error; free(msg->ue_config_reply_msg->header); @@ -320,11 +320,11 @@ int enb_agent_destroy_ue_config_reply(Protocol__FlexranMessage *msg) { return 0; error: - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + //LOG_E(FLEXRAN_AGENT, "%s: an error occured\n", __FUNCTION__); return -1; } -int enb_agent_destroy_lc_config_reply(Protocol__FlexranMessage *msg) { +int flexran_agent_destroy_lc_config_reply(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG) goto error; @@ -342,11 +342,11 @@ int enb_agent_destroy_lc_config_reply(Protocol__FlexranMessage *msg) { free(msg); return 0; error: - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + //LOG_E(FLEXRAN_AGENT, "%s: an error occured\n", __FUNCTION__); return -1; } -int enb_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg) { +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); @@ -360,7 +360,7 @@ int enb_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg) { return -1; } -int enb_agent_destroy_enb_config_request(Protocol__FlexranMessage *msg) { +int flexran_agent_destroy_enb_config_request(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG) goto error; free(msg->enb_config_request_msg->header); @@ -369,16 +369,16 @@ int enb_agent_destroy_enb_config_request(Protocol__FlexranMessage *msg) { return 0; error: - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + //LOG_E(FLEXRAN_AGENT, "%s: an error occured\n", __FUNCTION__); return -1; } -int enb_agent_destroy_ue_config_request(Protocol__FlexranMessage *msg) { +int flexran_agent_destroy_ue_config_request(Protocol__FlexranMessage *msg) { /* TODO: Deallocate memory for a dynamically allocated UE config message */ return 0; } -int enb_agent_destroy_lc_config_request(Protocol__FlexranMessage *msg) { +int flexran_agent_destroy_lc_config_request(Protocol__FlexranMessage *msg) { /* TODO: Deallocate memory for a dynamically allocated LC config message */ return 0; } @@ -398,7 +398,7 @@ long timer_end(struct timespec start_time){ return diffInNanos; } -int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { +int flexran_agent_control_delegation(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; Protocol__FlexControlDelegation *control_delegation_msg = input->control_delegation_msg; @@ -429,11 +429,11 @@ int enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__Fle return -1; } -int enb_agent_destroy_control_delegation(Protocol__FlexranMessage *msg) { +int flexran_agent_destroy_control_delegation(Protocol__FlexranMessage *msg) { /*TODO: Dealocate memory for a dynamically allocated control delegation message*/ } -int enb_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { +int flexran_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; Protocol__FlexAgentReconfiguration *agent_reconfiguration_msg = input->agent_reconfiguration_msg; @@ -443,7 +443,7 @@ int enb_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__Flexra return 0; } -int enb_agent_destroy_agent_reconfiguration(Protocol__FlexranMessage *msg) { +int flexran_agent_destroy_agent_reconfiguration(Protocol__FlexranMessage *msg) { /*TODO: Dealocate memory for a dynamically allocated agent reconfiguration message*/ } @@ -452,7 +452,7 @@ int enb_agent_destroy_agent_reconfiguration(Protocol__FlexranMessage *msg) { * get generic info from RAN */ -void set_enb_vars(mid_t mod_id, ran_name_t ran){ +void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran){ switch (ran){ case RAN_LTE_OAI : @@ -467,10 +467,10 @@ void set_enb_vars(mid_t mod_id, ran_name_t ran){ return; error: - LOG_E(ENB_AGENT, "unknown RAN name %d\n", ran); + LOG_E(FLEXRAN_AGENT, "unknown RAN name %d\n", ran); } -int get_current_time_ms (mid_t mod_id, int subframe_flag){ +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; @@ -480,31 +480,31 @@ int get_current_time_ms (mid_t mod_id, int subframe_flag){ } -unsigned int get_current_frame (mid_t mod_id) { +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 get_current_system_frame_num(mid_t mod_id) { - return (get_current_frame(mod_id) %1024); +unsigned int flexran_get_current_system_frame_num(mid_t mod_id) { + return (flexran_get_current_frame(mod_id) %1024); } -unsigned int get_current_subframe (mid_t mod_id) { +unsigned int flexran_get_current_subframe (mid_t mod_id) { return ((eNB_MAC_INST *)enb[mod_id])->subframe; } -uint16_t get_sfn_sf (mid_t mod_id) { +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) get_current_system_frame_num(mod_id); - subframe = (sub_frame_t) get_current_subframe(mod_id); + 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); @@ -512,14 +512,14 @@ uint16_t get_sfn_sf (mid_t mod_id) { return sfn_sf; } -uint16_t get_future_sfn_sf (mid_t mod_id, int ahead_of_time) { +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) get_current_system_frame_num(mod_id); - subframe = (sub_frame_t) get_current_subframe(mod_id); + 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); @@ -527,7 +527,7 @@ uint16_t get_future_sfn_sf (mid_t mod_id, int ahead_of_time) { frame = frame + full_frames_ahead; - if (subframe < get_current_subframe(mod_id)) { + if (subframe < flexran_get_current_subframe(mod_id)) { frame++; } @@ -538,40 +538,40 @@ uint16_t get_future_sfn_sf (mid_t mod_id, int ahead_of_time) { return sfn_sf; } -int get_num_ues (mid_t mod_id){ +int flexran_get_num_ues (mid_t mod_id){ return ((UE_list_t *)enb_ue[mod_id])->num_UEs; } -int get_ue_crnti (mid_t mod_id, mid_t ue_id) { +int flexran_get_ue_crnti (mid_t mod_id, mid_t ue_id) { return UE_RNTI(mod_id, ue_id); } -int get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid) { +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 get_ue_phr (mid_t mod_id, mid_t ue_id) { +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 get_ue_wcqi (mid_t mod_id, mid_t ue_id) { +int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id) { return ((UE_list_t *)enb_ue[mod_id])->eNB_UE_stats[UE_PCCID(mod_id,ue_id)][ue_id].dl_cqi; } -int get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) -{ - rnti_t rnti = get_ue_crnti(mod_id,ue_id); - uint16_t frame = (uint16_t) get_current_frame(mod_id); + +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 get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) +int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) { - rnti_t rnti = get_ue_crnti(mod_id,ue_id); + 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) { @@ -611,15 +611,15 @@ int get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) return 0; } -int get_active_CC(mid_t mod_id, mid_t ue_id) { +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 get_current_RI(mid_t mod_id, mid_t ue_id, int CC_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; int pCCid = UE_PCCID(mod_id,ue_id); - rnti_t rnti = get_ue_crnti(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,CC_id,rnti); @@ -630,13 +630,13 @@ int get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) { return eNB_UE_stats[CC_id].rank; } -int get_tpc(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(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); @@ -660,7 +660,7 @@ int get_tpc(mid_t mod_id, mid_t ue_id) { return tpc; } -int get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, const int frame, const uint8_t subframe, int *id, int *status) { //flag_id_status = 0 then id, else status +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, int *id, int *status) { //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];*/ @@ -669,7 +669,7 @@ int get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, const i uint8_t round; - uint16_t rnti = get_ue_crnti(mod_id,ue_id); + 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,&round,openair_harq_DL); @@ -683,9 +683,9 @@ int get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, const i return 0; } -int get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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); @@ -693,15 +693,14 @@ int get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id) { return -1; } - if(eNB_UE_stats->Po_PUCCH_update == 1) - { + if(eNB_UE_stats->Po_PUCCH_update == 1) { return eNB_UE_stats->Po_PUCCH_dBm; } else return -1; } -int get_p0_nominal_pucch(mid_t mod_id, int CC_id) { +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; } @@ -713,42 +712,42 @@ int get_p0_nominal_pucch(mid_t mod_id, int CC_id) { * ************************************ */ -int get_hopping_offset(mid_t mod_id, int CC_id) { +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 get_hopping_mode(mid_t mod_id, int CC_id) { +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 get_n_SB(mid_t mod_id, int CC_id) { +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 get_enable64QAM(mid_t mod_id, int CC_id) { +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 get_phich_duration(mid_t mod_id, int CC_id) { +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 get_phich_resource(mid_t mod_id, int CC_id) { +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); @@ -764,131 +763,131 @@ int get_phich_resource(mid_t mod_id, int CC_id) { return -1; } -int get_n1pucch_an(mid_t mod_id, int CC_id) { +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 get_nRB_CQI(mid_t mod_id, int CC_id) { +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 get_deltaPUCCH_Shift(mid_t mod_id, int CC_id) { +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 get_prach_ConfigIndex(mid_t mod_id, int CC_id) { +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 get_prach_FreqOffset(mid_t mod_id, int CC_id) { +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 get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id) { +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 get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id) { +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 get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id) { +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 get_cell_id(mid_t mod_id, int CC_id) { +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 get_srs_BandwidthConfig(mid_t mod_id, int CC_id) { +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 get_srs_SubframeConfig(mid_t mod_id, int CC_id) { +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 get_srs_MaxUpPts(mid_t mod_id, int CC_id) { +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 get_N_RB_DL(mid_t mod_id, int CC_id) { +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 get_N_RB_UL(mid_t mod_id, int CC_id) { +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 get_subframe_assignment(mid_t mod_id, int CC_id) { +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 get_special_subframe_assignment(mid_t mod_id, int CC_id) { +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 get_ra_ResponseWindowSize(mid_t mod_id, int CC_id) { +int flexran_get_ra_ResponseWindowSize(mid_t mod_id, int CC_id) { Enb_properties_array_t *enb_properties; enb_properties = enb_config_get(); return enb_properties->properties[mod_id]->rach_raResponseWindowSize[CC_id]; } -int get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id) { +int flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id) { Enb_properties_array_t *enb_properties; enb_properties = enb_config_get(); return enb_properties->properties[mod_id]->rach_macContentionResolutionTimer[CC_id]; } -int get_duplex_mode(mid_t mod_id, int 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); @@ -900,15 +899,15 @@ int get_duplex_mode(mid_t mod_id, int CC_id) { return -1; } -long get_si_window_length(mid_t mod_id, int CC_id) { +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 get_sib1_length(mid_t mod_id, int CC_id) { +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 get_num_pdcch_symb(mid_t mod_id, int CC_id) { +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); @@ -923,27 +922,26 @@ int get_num_pdcch_symb(mid_t mod_id, int CC_id) { */ -int get_time_alignment_timer(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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; + 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; + return -1; } -int get_meas_gap_config(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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 != 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; @@ -959,9 +957,9 @@ int get_meas_gap_config(mid_t mod_id, mid_t ue_id) { } -int get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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); @@ -979,15 +977,15 @@ int get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id) { return -1; } -int get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id) { +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 get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id) { +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 get_half_duplex(mid_t ue_id) { +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; @@ -998,65 +996,63 @@ int get_half_duplex(mid_t ue_id) { //return halfduplex; } -int get_intra_sf_hopping(mid_t ue_id) { +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))); } -int get_type2_sb_1(mid_t ue_id) { +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))); } -int get_ue_category(mid_t ue_id) { +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); } -int get_res_alloc_type1(mid_t ue_id) { +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))); } -int get_ue_transmission_mode(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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; - } + 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; + return -1; } -int get_tti_bundling(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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; - } + 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; + return -1; } -int get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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) { @@ -1067,54 +1063,51 @@ int get_maxHARQ_TX(mid_t mod_id, mid_t ue_id) { return -1; } -int get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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; - } + 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; + return -1; } -int get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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; - } + 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; + return -1; } -int get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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; - } + 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; + return -1; } -int get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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) { @@ -1127,13 +1120,13 @@ int get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id) { return -1; } -int get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id) { +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 get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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); @@ -1145,41 +1138,39 @@ int get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id) { return -1; } -int get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) { +int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id) { struct rrc_eNB_ue_context_s* ue_context_p = NULL; - uint32_t rntiP = get_ue_crnti(mod_id,ue_id); + 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; - } + 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; + return -1; } -int get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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; - } + 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; + return -1; } -int get_extended_bsr_size(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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) { @@ -1195,28 +1186,27 @@ int get_extended_bsr_size(mid_t mod_id, mid_t ue_id) { return -1; } -int get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id) { +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 = get_ue_crnti(mod_id,ue_id); + 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; - } + 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; + return -1; } -int get_lcg(mid_t ue_id, mid_t lc_id) { +int flexran_get_lcg(mid_t ue_id, mid_t lc_id) { if (UE_mac_inst == NULL) { return -1; } @@ -1227,15 +1217,15 @@ int get_lcg(mid_t ue_id, mid_t lc_id) { } } -int get_direction(mid_t ue_id, mid_t lc_id) { +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; + if(lc_id == DCCH | lc_id == DCCH1) + return 2; + else if(lc_id == DTCH) + return 1; } -int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { +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; @@ -1245,7 +1235,7 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) int xid = 0; - if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UE_STATE_CHANGE, &header) != 0) + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UE_STATE_CHANGE, &header) != 0) goto error; Protocol__FlexUeStateChange *ue_state_change_msg; @@ -1269,20 +1259,20 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) 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(get_time_alignment_timer(mod_id,i) != -1){ - config->time_alignment_timer = get_time_alignment_timer(mod_id,i); + 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(get_meas_gap_config(mod_id,i) != -1){ - config->meas_gap_config_pattern = get_meas_gap_config(mod_id,i); + 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 = get_meas_gap_config_offset(mod_id,i); + 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) @@ -1294,15 +1284,15 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) //TODO: Set the CQI configuration (Optional) //We do not set it for now - if(get_ue_transmission_mode(mod_id,i) != -1){ - config->transmission_mode = get_ue_transmission_mode(mod_id,i); + 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 = get_ue_aggregated_max_bitrate_ul(mod_id,i); + 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 = get_ue_aggregated_max_bitrate_dl(mod_id,i); + 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 @@ -1311,85 +1301,85 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) protocol__flex_ue_capabilities__init(c_capabilities); //TODO: Set half duplex (FDD operation) c_capabilities->has_half_duplex = 0; - c_capabilities->half_duplex = 1;//get_half_duplex(i); + 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;//get_intra_sf_hopping(i); + 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;//get_type2_sb_1(i); + 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;//get_ue_category(i); + 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;//get_res_alloc_type1(i); + c_capabilities->res_alloc_type1 = 1;//flexran_get_res_alloc_type1(i); //Set the capabilites to the message config->capabilities = c_capabilities; - if(get_ue_transmission_antenna(mod_id,i) != -1){ - config->has_ue_transmission_antenna = 1; - config->ue_transmission_antenna = get_ue_transmission_antenna(mod_id,i); + 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(get_tti_bundling(mod_id,i) != -1){ - config->has_tti_bundling = 1; - config->tti_bundling = get_tti_bundling(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(get_maxHARQ_TX(mod_id,i) != -1){ - config->has_max_harq_tx = 1; - config->max_harq_tx = get_maxHARQ_TX(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(get_beta_offset_ack_index(mod_id,i) != -1){ - config->has_beta_offset_ack_index = 1; - config->beta_offset_ack_index = get_beta_offset_ack_index(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(get_beta_offset_ri_index(mod_id,i) != -1){ - config->has_beta_offset_ri_index = 1; - config->beta_offset_ri_index = get_beta_offset_ri_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(get_beta_offset_cqi_index(mod_id,i) != -1){ - config->has_beta_offset_cqi_index = 1; - config->beta_offset_cqi_index = get_beta_offset_cqi_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(get_ack_nack_simultaneous_trans(mod_id,i) != -1){ - config->has_ack_nack_simultaneous_trans = 1; - config->ack_nack_simultaneous_trans = get_ack_nack_simultaneous_trans(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(get_simultaneous_ack_nack_cqi(mod_id,i) != -1){ - config->has_simultaneous_ack_nack_cqi = 1; - config->simultaneous_ack_nack_cqi = get_simultaneous_ack_nack_cqi(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(get_aperiodic_cqi_rep_mode(mod_id,i) != -1){ - config->has_aperiodic_cqi_rep_mode = 1; - int mode = 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_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(get_tdd_ack_nack_feedback(mod_id, i) != -1){ - config->has_tdd_ack_nack_feedback = 1; - config->tdd_ack_nack_feedback = get_tdd_ack_nack_feedback(mod_id,i); + 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(get_ack_nack_repetition_factor(mod_id, i) != -1){ - config->has_ack_nack_repetition_factor = 1; - config->ack_nack_repetition_factor = get_ack_nack_repetition_factor(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(get_extended_bsr_size(mod_id, i) != -1){ - config->has_extended_bsr_size = 1; - config->extended_bsr_size = get_extended_bsr_size(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; @@ -1398,15 +1388,15 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) 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; + //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 @@ -1422,22 +1412,22 @@ int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) msg->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; msg->ue_state_change_msg = ue_state_change_msg; - data = enb_agent_pack_message(msg, &size); + data = flexran_agent_pack_message(msg, &size); /*Send sr info using the MAC channel of the eNB*/ - if (enb_agent_msg_send(mod_id, ENB_AGENT_DEFAULT, data, size, priority)) { + if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } - LOG_D(ENB_AGENT,"sent message with size %d\n", size); + LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); return; error: - LOG_D(ENB_AGENT, "Could not send UE state message\n"); + LOG_D(FLEXRAN_AGENT, "Could not send UE state message\n"); } -int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { +int flexran_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { xid_t xid; Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; @@ -1446,7 +1436,7 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Flexra int i, j; Protocol__FlexHeader *header; - if(flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_GET_LC_CONFIG_REPLY, &header) != 0) + if(flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_GET_LC_CONFIG_REPLY, &header) != 0) goto error; Protocol__FlexLcConfigReply *lc_config_reply_msg; @@ -1456,7 +1446,7 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Flexra protocol__flex_lc_config_reply__init(lc_config_reply_msg); lc_config_reply_msg->header = header; - lc_config_reply_msg->n_lc_ue_config = get_num_ues(mod_id); + lc_config_reply_msg->n_lc_ue_config = flexran_get_num_ues(mod_id); Protocol__FlexLcUeConfig **lc_ue_config; if (lc_config_reply_msg->n_lc_ue_config > 0) { @@ -1470,12 +1460,12 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Flexra protocol__flex_lc_ue_config__init(lc_ue_config[i]); lc_ue_config[i]->has_rnti = 1; - lc_ue_config[i]->rnti = get_ue_crnti(mod_id,i); + lc_ue_config[i]->rnti = flexran_get_ue_crnti(mod_id,i); //TODO: Set the number of LC configurations that will be reported for this UE //Set this according to the current state of the UE. This is only a temporary fix int status = 0; - status = mac_eNB_get_rrc_status(mod_id, get_ue_crnti(mod_id, i)); + status = mac_eNB_get_rrc_status(mod_id, flexran_get_ue_crnti(mod_id, i)); if (status < RRC_CONNECTED) { lc_ue_config[i]->n_lc_config = 0; } else if (status == RRC_CONNECTED) { @@ -1497,14 +1487,14 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Flexra lc_config[j]->has_lcid = 1; lc_config[j]->lcid = j+1; - int lcg = get_lcg(i, j+1); + int lcg = flexran_get_lcg(i, j+1); if (lcg >= 0 && lcg <= 3) { lc_config[j]->has_lcg = 1; - lc_config[j]->lcg = get_lcg(i,j+1); + lc_config[j]->lcg = flexran_get_lcg(i,j+1); } lc_config[j]->has_direction = 1; - lc_config[j]->direction = get_direction(i,j+1); + lc_config[j]->direction = flexran_get_direction(i,j+1); //TODO: Bearer type. One of FLQBT_* values. Currently only default bearer supported lc_config[j]->has_qos_bearer_type = 1; lc_config[j]->qos_bearer_type = PROTOCOL__FLEX_QOS_BEARER_TYPE__FLQBT_NON_GBR; @@ -1551,7 +1541,7 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Flexra free(lc_config_reply_msg); if(*msg != NULL) free(*msg); - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + //LOG_E(FLEXRAN_AGENT, "%s: an error occured\n", __FUNCTION__); return -1; } @@ -1561,7 +1551,7 @@ int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__Flexra * ************************************ */ -int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { +int flexran_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { xid_t xid; Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; @@ -1571,7 +1561,7 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Flexra int i; Protocol__FlexHeader *header; - if(flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_GET_UE_CONFIG_REPLY, &header) != 0) + if(flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_GET_UE_CONFIG_REPLY, &header) != 0) goto error; Protocol__FlexUeConfigReply *ue_config_reply_msg; @@ -1581,7 +1571,7 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Flexra protocol__flex_ue_config_reply__init(ue_config_reply_msg); ue_config_reply_msg->header = header; - ue_config_reply_msg->n_ue_config = get_num_ues(mod_id); + ue_config_reply_msg->n_ue_config = flexran_get_num_ues(mod_id); Protocol__FlexUeConfig **ue_config; if (ue_config_reply_msg->n_ue_config > 0) { @@ -1593,24 +1583,24 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Flexra ue_config[i] = malloc(sizeof(Protocol__FlexUeConfig)); protocol__flex_ue_config__init(ue_config[i]); - ue_config[i]->rnti = get_ue_crnti(mod_id,i); + ue_config[i]->rnti = flexran_get_ue_crnti(mod_id,i); ue_config[i]->has_rnti = 1; //TODO: Set the DRX configuration (optional) //Not supported for now, so we do not set it - if(get_time_alignment_timer(mod_id,i) != -1){ - ue_config[i]->time_alignment_timer = get_time_alignment_timer(mod_id,i); + if (flexran_get_time_alignment_timer(mod_id,i) != -1) { + ue_config[i]->time_alignment_timer = flexran_get_time_alignment_timer(mod_id,i); ue_config[i]->has_time_alignment_timer = 1; - } + } - if(get_meas_gap_config(mod_id,i) != -1){ - ue_config[i]->meas_gap_config_pattern = get_meas_gap_config(mod_id,i); + if (flexran_get_meas_gap_config(mod_id,i) != -1) { + ue_config[i]->meas_gap_config_pattern = flexran_get_meas_gap_config(mod_id,i); ue_config[i]->has_meas_gap_config_pattern = 1; - } + } - if(ue_config[i]->has_meas_gap_config_pattern == 1 && + if (ue_config[i]->has_meas_gap_config_pattern == 1 && ue_config[i]->meas_gap_config_pattern != PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF) { - ue_config[i]->meas_gap_config_sf_offset = get_meas_gap_config_offset(mod_id,i); + ue_config[i]->meas_gap_config_sf_offset = flexran_get_meas_gap_config_offset(mod_id,i); ue_config[i]->has_meas_gap_config_sf_offset = 1; } //TODO: Set the SPS configuration (Optional) @@ -1622,15 +1612,15 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Flexra //TODO: Set the CQI configuration (Optional) //We do not set it for now - if(get_ue_transmission_mode(mod_id,i) != -1){ - ue_config[i]->transmission_mode = get_ue_transmission_mode(mod_id,i); - ue_config[i]->has_transmission_mode = 1; - } + if (flexran_get_ue_transmission_mode(mod_id,i) != -1) { + ue_config[i]->transmission_mode = flexran_get_ue_transmission_mode(mod_id,i); + ue_config[i]->has_transmission_mode = 1; + } - ue_config[i]->ue_aggregated_max_bitrate_ul = get_ue_aggregated_max_bitrate_ul(mod_id,i); + ue_config[i]->ue_aggregated_max_bitrate_ul = flexran_get_ue_aggregated_max_bitrate_ul(mod_id,i); ue_config[i]->has_ue_aggregated_max_bitrate_ul = 1; - ue_config[i]->ue_aggregated_max_bitrate_dl = get_ue_aggregated_max_bitrate_dl(mod_id,i); + ue_config[i]->ue_aggregated_max_bitrate_dl = flexran_get_ue_aggregated_max_bitrate_dl(mod_id,i); ue_config[i]->has_ue_aggregated_max_bitrate_dl = 1; Protocol__FlexUeCapabilities *capabilities; @@ -1638,85 +1628,85 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Flexra protocol__flex_ue_capabilities__init(capabilities); //TODO: Set half duplex (FDD operation) capabilities->has_half_duplex = 0; - capabilities->half_duplex = 0;//get_half_duplex(i); + capabilities->half_duplex = 0;//flexran_get_half_duplex(i); //TODO: Set intra-frame hopping flag capabilities->has_intra_sf_hopping = 0; - capabilities->intra_sf_hopping = 1;//get_intra_sf_hopping(i); + capabilities->intra_sf_hopping = 1;//flexran_get_intra_sf_hopping(i); //TODO: Set support for type 2 hopping with n_sb > 1 capabilities->has_type2_sb_1 = 0; - capabilities->type2_sb_1 = 1;//get_type2_sb_1(i); + capabilities->type2_sb_1 = 1;//flexran_get_type2_sb_1(i); //TODO: Set ue category capabilities->has_ue_category = 0; - capabilities->ue_category = 1;//get_ue_category(i); + capabilities->ue_category = 1;//flexran_get_ue_category(i); //TODO: Set UE support for resource allocation type 1 capabilities->has_res_alloc_type1 = 0; - capabilities->res_alloc_type1 = 1;//get_res_alloc_type1(i); + capabilities->res_alloc_type1 = 1;//flexran_get_res_alloc_type1(i); //Set the capabilites to the message ue_config[i]->capabilities = capabilities; - if(get_ue_transmission_antenna(mod_id,i) != -1){ - ue_config[i]->has_ue_transmission_antenna = 1; - ue_config[i]->ue_transmission_antenna = get_ue_transmission_antenna(mod_id,i); - } + if (flexran_get_ue_transmission_antenna(mod_id,i) != -1) { + ue_config[i]->has_ue_transmission_antenna = 1; + ue_config[i]->ue_transmission_antenna = flexran_get_ue_transmission_antenna(mod_id,i); + } - if(get_tti_bundling(mod_id,i) != -1){ - ue_config[i]->has_tti_bundling = 1; - ue_config[i]->tti_bundling = get_tti_bundling(mod_id,i); - } + if (flexran_get_tti_bundling(mod_id,i) != -1) { + ue_config[i]->has_tti_bundling = 1; + ue_config[i]->tti_bundling = flexran_get_tti_bundling(mod_id,i); + } - if(get_maxHARQ_TX(mod_id,i) != -1){ - ue_config[i]->has_max_harq_tx = 1; - ue_config[i]->max_harq_tx = get_maxHARQ_TX(mod_id,i); - } + if (flexran_get_maxHARQ_TX(mod_id,i) != -1) { + ue_config[i]->has_max_harq_tx = 1; + ue_config[i]->max_harq_tx = flexran_get_maxHARQ_TX(mod_id,i); + } - if(get_beta_offset_ack_index(mod_id,i) != -1){ - ue_config[i]->has_beta_offset_ack_index = 1; - ue_config[i]->beta_offset_ack_index = get_beta_offset_ack_index(mod_id,i); - } + if (flexran_get_beta_offset_ack_index(mod_id,i) != -1) { + ue_config[i]->has_beta_offset_ack_index = 1; + ue_config[i]->beta_offset_ack_index = flexran_get_beta_offset_ack_index(mod_id,i); + } - if(get_beta_offset_ri_index(mod_id,i) != -1){ - ue_config[i]->has_beta_offset_ri_index = 1; - ue_config[i]->beta_offset_ri_index = get_beta_offset_ri_index(mod_id,i); - } + if (flexran_get_beta_offset_ri_index(mod_id,i) != -1) { + ue_config[i]->has_beta_offset_ri_index = 1; + ue_config[i]->beta_offset_ri_index = flexran_get_beta_offset_ri_index(mod_id,i); + } - if(get_beta_offset_cqi_index(mod_id,i) != -1){ - ue_config[i]->has_beta_offset_cqi_index = 1; - ue_config[i]->beta_offset_cqi_index = get_beta_offset_cqi_index(mod_id,i); + if (flexran_get_beta_offset_cqi_index(mod_id,i) != -1) { + ue_config[i]->has_beta_offset_cqi_index = 1; + ue_config[i]->beta_offset_cqi_index = flexran_get_beta_offset_cqi_index(mod_id,i); } - if(get_ack_nack_simultaneous_trans(mod_id,i) != -1){ - ue_config[i]->has_ack_nack_simultaneous_trans = 1; - ue_config[i]->ack_nack_simultaneous_trans = get_ack_nack_simultaneous_trans(mod_id,i); - } - - if(get_simultaneous_ack_nack_cqi(mod_id,i) != -1){ - ue_config[i]->has_simultaneous_ack_nack_cqi = 1; - ue_config[i]->simultaneous_ack_nack_cqi = get_simultaneous_ack_nack_cqi(mod_id,i); - } - - if(get_aperiodic_cqi_rep_mode(mod_id,i) != -1){ - ue_config[i]->has_aperiodic_cqi_rep_mode = 1; - int mode = get_aperiodic_cqi_rep_mode(mod_id,i); - if (mode > 4) { - ue_config[i]->aperiodic_cqi_rep_mode = PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_NONE; - } else { - ue_config[i]->aperiodic_cqi_rep_mode = mode; - } + if (flexran_get_ack_nack_simultaneous_trans(mod_id,i) != -1) { + ue_config[i]->has_ack_nack_simultaneous_trans = 1; + ue_config[i]->ack_nack_simultaneous_trans = flexran_get_ack_nack_simultaneous_trans(mod_id,i); } - if(get_tdd_ack_nack_feedback(mod_id, i) != -1){ + if (flexran_get_simultaneous_ack_nack_cqi(mod_id,i) != -1) { + ue_config[i]->has_simultaneous_ack_nack_cqi = 1; + ue_config[i]->simultaneous_ack_nack_cqi = flexran_get_simultaneous_ack_nack_cqi(mod_id,i); + } + + if (flexran_get_aperiodic_cqi_rep_mode(mod_id,i) != -1) { + ue_config[i]->has_aperiodic_cqi_rep_mode = 1; + int mode = flexran_get_aperiodic_cqi_rep_mode(mod_id,i); + if (mode > 4) { + ue_config[i]->aperiodic_cqi_rep_mode = PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_NONE; + } else { + ue_config[i]->aperiodic_cqi_rep_mode = mode; + } + } + + if (flexran_get_tdd_ack_nack_feedback(mod_id, i) != -1) { ue_config[i]->has_tdd_ack_nack_feedback = 1; - ue_config[i]->tdd_ack_nack_feedback = get_tdd_ack_nack_feedback(mod_id,i); + ue_config[i]->tdd_ack_nack_feedback = flexran_get_tdd_ack_nack_feedback(mod_id,i); } - if(get_ack_nack_repetition_factor(mod_id, i) != -1){ + if(flexran_get_ack_nack_repetition_factor(mod_id, i) != -1) { ue_config[i]->has_ack_nack_repetition_factor = 1; - ue_config[i]->ack_nack_repetition_factor = get_ack_nack_repetition_factor(mod_id,i); + ue_config[i]->ack_nack_repetition_factor = flexran_get_ack_nack_repetition_factor(mod_id,i); } - if(get_extended_bsr_size(mod_id, i) != -1){ + if (flexran_get_extended_bsr_size(mod_id, i) != -1) { ue_config[i]->has_extended_bsr_size = 1; - ue_config[i]->extended_bsr_size = get_extended_bsr_size(mod_id,i); + ue_config[i]->extended_bsr_size = flexran_get_extended_bsr_size(mod_id,i); } //TODO: Set carrier aggregation support (boolean) ue_config[i]->has_ca_support = 0; @@ -1754,7 +1744,7 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Flexra free(ue_config_reply_msg); if(*msg != NULL) free(*msg); - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + //LOG_E(FLEXRAN_AGENT, "%s: an error occured\n", __FUNCTION__); return -1; } @@ -1765,25 +1755,25 @@ int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__Flexra * ************************************ */ -int enb_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg) { +int flexran_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg) { Protocol__FlexHeader *header; xid_t xid = 1; - if(flex_create_header(xid,PROTOCOL__FLEX_TYPE__FLPT_GET_ENB_CONFIG_REQUEST, &header) != 0) - goto error; + if(flexran_create_header(xid,PROTOCOL__FLEX_TYPE__FLPT_GET_ENB_CONFIG_REQUEST, &header) != 0) + goto error; Protocol__FlexEnbConfigRequest *enb_config_request_msg; enb_config_request_msg = malloc(sizeof(Protocol__FlexEnbConfigRequest)); if(enb_config_request_msg == NULL) - goto error; + goto error; protocol__flex_enb_config_request__init(enb_config_request_msg); enb_config_request_msg->header = header; *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) - goto error; + goto error; protocol__flexran_message__init(*msg); (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG; @@ -1803,7 +1793,7 @@ int enb_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__Fle return -1; } -int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { +int flexran_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { xid_t xid; Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; @@ -1815,10 +1805,10 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr int enb_id = mod_id; Protocol__FlexHeader *header; - if(flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_GET_ENB_CONFIG_REPLY, &header) != 0) + if(flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_GET_ENB_CONFIG_REPLY, &header) != 0) goto error; - Protocol__FlexEnbConfigReply *enb_config_reply_msg; + Protocol__FlexEnbConfigReply *enb_config_reply_msg; enb_config_reply_msg = malloc(sizeof(Protocol__FlexEnbConfigReply)); if(enb_config_reply_msg == NULL) goto error; @@ -1840,43 +1830,43 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr protocol__flex_cell_config__init(cell_conf[i]); cell_conf[i]->phy_cell_id = 1; - cell_conf[i]->has_phy_cell_id = get_cell_id(enb_id,i); + cell_conf[i]->has_phy_cell_id = flexran_get_cell_id(enb_id,i); cell_conf[i]->cell_id = i; cell_conf[i]->has_cell_id = 1; - cell_conf[i]->pusch_hopping_offset = get_hopping_offset(enb_id,i); + cell_conf[i]->pusch_hopping_offset = flexran_get_hopping_offset(enb_id,i); cell_conf[i]->has_pusch_hopping_offset = 1; - if(get_hopping_mode(enb_id,i) == 0){ - cell_conf[i]->hopping_mode = PROTOCOL__FLEX_HOPPING_MODE__FLHM_INTER; - }else if(get_hopping_mode(enb_id,i) == 1){ + if (flexran_get_hopping_mode(enb_id,i) == 0) { + cell_conf[i]->hopping_mode = PROTOCOL__FLEX_HOPPING_MODE__FLHM_INTER; + } else if(flexran_get_hopping_mode(enb_id,i) == 1) { cell_conf[i]->hopping_mode = PROTOCOL__FLEX_HOPPING_MODE__FLHM_INTERINTRA; } cell_conf[i]->has_hopping_mode = 1; - cell_conf[i]->n_sb = get_n_SB(enb_id,i); + cell_conf[i]->n_sb = flexran_get_n_SB(enb_id,i); cell_conf[i]->has_n_sb = 1; - if(get_phich_resource(enb_id,i) == 0){ + if (flexran_get_phich_resource(enb_id,i) == 0) { cell_conf[i]->phich_resource = PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_ONE_SIXTH; //0 - }else if (get_phich_resource(enb_id,i) == 1){ + } else if (flexran_get_phich_resource(enb_id,i) == 1) { cell_conf[i]->phich_resource = PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_HALF; //1 - }else if (get_phich_resource(enb_id,i) == 2){ + } else if (flexran_get_phich_resource(enb_id,i) == 2) { cell_conf[i]->phich_resource = PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_ONE; // 2 - }else if (get_phich_resource(enb_id,i) == 3){ + } else if (flexran_get_phich_resource(enb_id,i) == 3) { cell_conf[i]->phich_resource = PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_TWO;//3 } cell_conf[i]->has_phich_resource = 1; - if(get_phich_duration(enb_id,i) == 0){ + if (flexran_get_phich_duration(enb_id,i) == 0) { cell_conf[i]->phich_duration = PROTOCOL__FLEX_PHICH_DURATION__FLPD_NORMAL; - }else if(get_phich_duration(enb_id,i) == 1){ + } else if(flexran_get_phich_duration(enb_id,i) == 1) { cell_conf[i]->phich_duration = PROTOCOL__FLEX_PHICH_DURATION__FLPD_EXTENDED; } cell_conf[i]->has_phich_duration = 1; //TODO: Fill in with actual value, See TS 36.211, section 6.9 - cell_conf[i]->init_nr_pdcch_ofdm_sym = get_num_pdcch_symb(enb_id,i); + cell_conf[i]->init_nr_pdcch_ofdm_sym = flexran_get_num_pdcch_symb(enb_id,i); cell_conf[i]->has_init_nr_pdcch_ofdm_sym = 0; //TODO: Fill in with actual value /* Protocol__FlexSiConfig *si_config; */ @@ -1916,23 +1906,23 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr /* } */ /* cell_conf[i]->si_config = si_config; */ - cell_conf[i]->dl_bandwidth = get_N_RB_DL(enb_id,i); + cell_conf[i]->dl_bandwidth = flexran_get_N_RB_DL(enb_id,i); cell_conf[i]->has_dl_bandwidth = 1; - cell_conf[i]->ul_bandwidth = get_N_RB_UL(enb_id,i); + cell_conf[i]->ul_bandwidth = flexran_get_N_RB_UL(enb_id,i); cell_conf[i]->has_ul_bandwidth = 1; - if(get_ul_cyclic_prefix_length(enb_id,i) == 0){ - cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_UL_CYCLIC_PREFIX_LENGTH__FLUCPL_NORMAL; - }else if(get_ul_cyclic_prefix_length(enb_id,i) == 1){ + if (flexran_get_ul_cyclic_prefix_length(enb_id, i) == 0) { + cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_UL_CYCLIC_PREFIX_LENGTH__FLUCPL_NORMAL; + } else if(flexran_get_ul_cyclic_prefix_length(enb_id, i) == 1) { cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_UL_CYCLIC_PREFIX_LENGTH__FLUCPL_EXTENDED; } cell_conf[i]->has_ul_cyclic_prefix_length = 1; - if(get_ul_cyclic_prefix_length(enb_id,i) == 0){ - cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_DL_CYCLIC_PREFIX_LENGTH__FLDCPL_NORMAL; - }else if(get_ul_cyclic_prefix_length(enb_id,i) == 1){ - cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_DL_CYCLIC_PREFIX_LENGTH__FLDCPL_EXTENDED; + if (flexran_get_ul_cyclic_prefix_length(enb_id,i) == 0) { + cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_DL_CYCLIC_PREFIX_LENGTH__FLDCPL_NORMAL; + } else if (flexran_get_ul_cyclic_prefix_length(enb_id,i) == 1) { + cell_conf[i]->ul_cyclic_prefix_length = PROTOCOL__FLEX_DL_CYCLIC_PREFIX_LENGTH__FLDCPL_EXTENDED; } cell_conf[i]->has_dl_cyclic_prefix_length = 1; @@ -1940,20 +1930,20 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr cell_conf[i]->antenna_ports_count = 1; cell_conf[i]->has_antenna_ports_count = 1; - if(get_duplex_mode(enb_id,i) == 1){ + if (flexran_get_duplex_mode(enb_id,i) == 1) { cell_conf[i]->duplex_mode = PROTOCOL__FLEX_DUPLEX_MODE__FLDM_FDD; - }else if(get_duplex_mode(enb_id,i) == 0){ + } else if(flexran_get_duplex_mode(enb_id,i) == 0) { cell_conf[i]->duplex_mode = PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD; } cell_conf[i]->has_duplex_mode = 1; //TODO: Fill in with actual value, DL/UL subframe assignment. TDD only - cell_conf[i]->subframe_assignment = get_subframe_assignment(enb_id,i); + cell_conf[i]->subframe_assignment = flexran_get_subframe_assignment(enb_id, i); cell_conf[i]->has_subframe_assignment = 0; //TODO: Fill in with actual value, TDD only. See TS 36.211, table 4.2.1 - cell_conf[i]->special_subframe_patterns = get_special_subframe_assignment(enb_id,i); + cell_conf[i]->special_subframe_patterns = flexran_get_special_subframe_assignment(enb_id,i); cell_conf[i]->has_special_subframe_patterns = 0; //TODO: Fill in with actual value, The MBSFN radio frame period - cell_conf[i]->n_mbsfn_subframe_config_rfperiod = 5; + cell_conf[i]->n_mbsfn_subframe_config_rfperiod = 0; uint32_t *elem_rfperiod; elem_rfperiod = (uint32_t *) malloc(sizeof(uint32_t) *cell_conf[i]->n_mbsfn_subframe_config_rfperiod); if(elem_rfperiod == NULL) @@ -1964,7 +1954,7 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr cell_conf[i]->mbsfn_subframe_config_rfperiod = elem_rfperiod; //TODO: Fill in with actual value, The MBSFN radio frame offset - cell_conf[i]->n_mbsfn_subframe_config_rfoffset = 5; + cell_conf[i]->n_mbsfn_subframe_config_rfoffset = 0; uint32_t *elem_rfoffset; elem_rfoffset = (uint32_t *) malloc(sizeof(uint32_t) *cell_conf[i]->n_mbsfn_subframe_config_rfoffset); if(elem_rfoffset == NULL) @@ -1975,7 +1965,7 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr cell_conf[i]->mbsfn_subframe_config_rfoffset = elem_rfoffset; //TODO: Fill in with actual value, Bitmap indicating the MBSFN subframes - cell_conf[i]->n_mbsfn_subframe_config_sfalloc = 5; + cell_conf[i]->n_mbsfn_subframe_config_sfalloc = 0; uint32_t *elem_sfalloc; elem_sfalloc = (uint32_t *) malloc(sizeof(uint32_t) *cell_conf[i]->n_mbsfn_subframe_config_sfalloc); if(elem_sfalloc == NULL) @@ -1985,46 +1975,46 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr } cell_conf[i]->mbsfn_subframe_config_sfalloc = elem_sfalloc; - cell_conf[i]->prach_config_index = get_prach_ConfigIndex(enb_id,i); + cell_conf[i]->prach_config_index = flexran_get_prach_ConfigIndex(enb_id,i); cell_conf[i]->has_prach_config_index = 1; - cell_conf[i]->prach_freq_offset = get_prach_FreqOffset(enb_id,i); + cell_conf[i]->prach_freq_offset = flexran_get_prach_FreqOffset(enb_id,i); cell_conf[i]->has_prach_freq_offset = 1; - cell_conf[i]->ra_response_window_size = get_ra_ResponseWindowSize(enb_id,i); + cell_conf[i]->ra_response_window_size = flexran_get_ra_ResponseWindowSize(enb_id,i); cell_conf[i]->has_ra_response_window_size = 1; - cell_conf[i]->mac_contention_resolution_timer = get_mac_ContentionResolutionTimer(enb_id,i); + cell_conf[i]->mac_contention_resolution_timer = flexran_get_mac_ContentionResolutionTimer(enb_id,i); cell_conf[i]->has_mac_contention_resolution_timer = 1; - cell_conf[i]->max_harq_msg3tx = get_maxHARQ_Msg3Tx(enb_id,i); + cell_conf[i]->max_harq_msg3tx = flexran_get_maxHARQ_Msg3Tx(enb_id,i); cell_conf[i]->has_max_harq_msg3tx = 1; - cell_conf[i]->n1pucch_an = get_n1pucch_an(enb_id,i); + cell_conf[i]->n1pucch_an = flexran_get_n1pucch_an(enb_id,i); cell_conf[i]->has_n1pucch_an = 1; - cell_conf[i]->deltapucch_shift = get_deltaPUCCH_Shift(enb_id,i); + cell_conf[i]->deltapucch_shift = flexran_get_deltaPUCCH_Shift(enb_id,i); cell_conf[i]->has_deltapucch_shift = 1; - cell_conf[i]->nrb_cqi = get_nRB_CQI(enb_id,i); + cell_conf[i]->nrb_cqi = flexran_get_nRB_CQI(enb_id,i); cell_conf[i]->has_nrb_cqi = 1; - cell_conf[i]->srs_subframe_config = get_srs_SubframeConfig(enb_id,i); + cell_conf[i]->srs_subframe_config = flexran_get_srs_SubframeConfig(enb_id,i); cell_conf[i]->has_srs_subframe_config = 1; - cell_conf[i]->srs_bw_config = get_srs_BandwidthConfig(enb_id,i); + cell_conf[i]->srs_bw_config = flexran_get_srs_BandwidthConfig(enb_id,i); cell_conf[i]->has_srs_bw_config = 1; - cell_conf[i]->srs_mac_up_pts = get_srs_MaxUpPts(enb_id,i); + cell_conf[i]->srs_mac_up_pts = flexran_get_srs_MaxUpPts(enb_id,i); cell_conf[i]->has_srs_mac_up_pts = 1; - if(get_enable64QAM(enb_id,i) == 0){ + if (flexran_get_enable64QAM(enb_id,i) == 0) { cell_conf[i]->enable_64qam = PROTOCOL__FLEX_QAM__FLEQ_MOD_16QAM; - }else if(get_enable64QAM(enb_id,i) == 1){ + } else if(flexran_get_enable64QAM(enb_id,i) == 1) { cell_conf[i]->enable_64qam = PROTOCOL__FLEX_QAM__FLEQ_MOD_64QAM; } cell_conf[i]->has_enable_64qam = 1; - + cell_conf[i]->carrier_index = i; cell_conf[i]->has_carrier_index = 1; } @@ -2048,7 +2038,7 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr free(enb_config_reply_msg); if(*msg != NULL) free(*msg); - //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); + //LOG_E(FLEXRAN_AGENT, "%s: an error occured\n", __FUNCTION__); return -1; } @@ -2058,24 +2048,24 @@ int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__Flexr * timer primitives */ -//struct enb_agent_map agent_map; -enb_agent_timer_instance_t timer_instance; +//struct flexran_agent_map agent_map; +flexran_agent_timer_instance_t timer_instance; int agent_timer_init = 0; -err_code_t enb_agent_init_timer(void){ +err_code_t flexran_agent_init_timer(void){ - LOG_I(ENB_AGENT, "init RB tree\n"); + LOG_I(FLEXRAN_AGENT, "init RB tree\n"); if (!agent_timer_init) { - RB_INIT(&timer_instance.enb_agent_head); + RB_INIT(&timer_instance.flexran_agent_head); agent_timer_init = 1; } return PROTOCOL__FLEXRAN_ERR__NO_ERR; } -RB_GENERATE(enb_agent_map,enb_agent_timer_element_s, entry, enb_agent_compare_timer); +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 enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b){ +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; @@ -2084,17 +2074,17 @@ int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agen return 0; } -err_code_t enb_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, - enb_agent_timer_callback_t cb, - void* timer_args, - long *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){ - struct enb_agent_timer_element_s *e = calloc(1, sizeof(*e)); + struct flexran_agent_timer_element_s *e = calloc(1, sizeof(*e)); DevAssert(e != NULL); //uint32_t timer_id; @@ -2103,13 +2093,13 @@ err_code_t enb_agent_create_timer(uint32_t interval_sec, if ((interval_sec == 0) && (interval_usec == 0 )) return TIMER_NULL; - if (timer_type >= ENB_AGENT_TIMER_TYPE_MAX) + if (timer_type >= FLEXRAN_AGENT_TIMER_TYPE_MAX) return TIMER_TYPE_INVALIDE; - if (timer_type == ENB_AGENT_TIMER_TYPE_ONESHOT){ + if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_ONESHOT){ ret = timer_setup(interval_sec, interval_usec, - TASK_ENB_AGENT, + TASK_FLEXRAN_AGENT, instance, TIMER_ONE_SHOT, timer_args, @@ -2117,10 +2107,10 @@ err_code_t enb_agent_create_timer(uint32_t interval_sec, e->type = TIMER_ONE_SHOT; } - else if (timer_type == ENB_AGENT_TIMER_TYPE_PERIODIC ){ + else if (timer_type == FLEXRAN_AGENT_TIMER_TYPE_PERIODIC ){ ret = timer_setup(interval_sec, interval_usec, - TASK_ENB_AGENT, + TASK_FLEXRAN_AGENT, instance, TIMER_PERIODIC, timer_args, @@ -2135,27 +2125,27 @@ err_code_t enb_agent_create_timer(uint32_t interval_sec, e->agent_id = agent_id; e->instance = instance; - e->state = ENB_AGENT_TIMER_STATE_ACTIVE; + 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(enb_agent_map, &timer_instance.enb_agent_head, e); + RB_INSERT(flexran_agent_map, &timer_instance.flexran_agent_head, e); - LOG_I(ENB_AGENT,"Created a new timer with id 0x%lx for agent %d, instance %d \n", + 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 enb_agent_destroy_timer(long timer_id){ +err_code_t flexran_agent_destroy_timer(long timer_id){ - struct enb_agent_timer_element_s *e = get_timer_entry(timer_id); + struct flexran_agent_timer_element_s *e = get_timer_entry(timer_id); if (e != NULL ) { - RB_REMOVE(enb_agent_map, &timer_instance.enb_agent_head, e); - enb_agent_destroy_flexran_message(e->timer_args->msg); + RB_REMOVE(flexran_agent_map, &timer_instance.flexran_agent_head, e); + flexran_agent_destroy_flexran_message(e->timer_args->msg); free(e); } @@ -2165,18 +2155,18 @@ err_code_t enb_agent_destroy_timer(long timer_id){ return 0; error: - LOG_E(ENB_AGENT, "timer can't be removed\n"); + LOG_E(FLEXRAN_AGENT, "timer can't be removed\n"); return TIMER_REMOVED_FAILED ; } -err_code_t enb_agent_destroy_timer_by_task_id(xid_t xid) { - struct enb_agent_timer_element_s *e = NULL; +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, enb_agent_map, &timer_instance.enb_agent_head) { + RB_FOREACH(e, flexran_agent_map, &timer_instance.flexran_agent_head) { if (e->xid == xid) { timer_id = e->timer_id; - RB_REMOVE(enb_agent_map, &timer_instance.enb_agent_head, e); - enb_agent_destroy_flexran_message(e->timer_args->msg); + 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; @@ -2186,18 +2176,18 @@ err_code_t enb_agent_destroy_timer_by_task_id(xid_t xid) { return 0; error: - LOG_E(ENB_AGENT, "timer can't be removed\n"); + LOG_E(FLEXRAN_AGENT, "timer can't be removed\n"); return TIMER_REMOVED_FAILED ; } -err_code_t enb_agent_destroy_timers(void){ +err_code_t flexran_agent_destroy_timers(void){ - struct enb_agent_timer_element_s *e = NULL; + struct flexran_agent_timer_element_s *e = NULL; - RB_FOREACH(e, enb_agent_map, &timer_instance.enb_agent_head) { - RB_REMOVE(enb_agent_map, &timer_instance.enb_agent_head, e); + 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); - enb_agent_destroy_flexran_message(e->timer_args->msg); + flexran_agent_destroy_flexran_message(e->timer_args->msg); free(e); } @@ -2205,7 +2195,7 @@ err_code_t enb_agent_destroy_timers(void){ } -void enb_agent_sleep_until(struct timespec *ts, int delay) { +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; @@ -2215,17 +2205,17 @@ void enb_agent_sleep_until(struct timespec *ts, int delay) { } -err_code_t enb_agent_stop_timer(long timer_id){ +err_code_t flexran_agent_stop_timer(long timer_id){ - struct enb_agent_timer_element_s *e=NULL; - struct enb_agent_timer_element_s search; - memset(&search, 0, sizeof(struct enb_agent_timer_element_s)); + 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(enb_agent_map, &timer_instance.enb_agent_head, &search); + e = RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search); if (e != NULL ) { - e->state = ENB_AGENT_TIMER_STATE_STOPPED; + e->state = FLEXRAN_AGENT_TIMER_STATE_STOPPED; } timer_remove(timer_id); @@ -2233,11 +2223,11 @@ err_code_t enb_agent_stop_timer(long timer_id){ return 0; } -struct enb_agent_timer_element_s * get_timer_entry(long timer_id) { +struct flexran_agent_timer_element_s * get_timer_entry(long timer_id) { - struct enb_agent_timer_element_s search; - memset(&search, 0, sizeof(struct enb_agent_timer_element_s)); + 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(enb_agent_map, &timer_instance.enb_agent_head, &search); + return RB_FIND(flexran_agent_map, &timer_instance.flexran_agent_head, &search); } diff --git a/openair2/ENB_APP/enb_agent_common.h b/openair2/ENB_APP/flexran_agent_common.h similarity index 51% rename from openair2/ENB_APP/enb_agent_common.h rename to openair2/ENB_APP/flexran_agent_common.h index 6664958ed9..2156d50a0d 100644 --- a/openair2/ENB_APP/enb_agent_common.h +++ b/openair2/ENB_APP/flexran_agent_common.h @@ -27,7 +27,7 @@ *******************************************************************************/ -/*! \file enb_agent_common.h +/*! \file flexran_agent_common.h * \brief common message primitves and utilities * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein * \date 2016 @@ -36,8 +36,8 @@ -#ifndef ENB_AGENT_COMMON_H_ -#define ENB_AGENT_COMMON_H_ +#ifndef FLEXRAN_AGENT_COMMON_H_ +#define FLEXRAN_AGENT_COMMON_H_ #include @@ -46,7 +46,7 @@ #include "stats_messages.pb-c.h" #include "stats_common.pb-c.h" -# include "enb_agent_defs.h" +#include "flexran_agent_defs.h" #include "enb_config.h" #include "LAYER2/MAC/extern.h" @@ -58,13 +58,13 @@ #define FLEXRAN_VERSION 0 -typedef int (*enb_agent_message_decoded_callback)( +typedef int (*flexran_agent_message_decoded_callback)( mid_t mod_id, const void *params, Protocol__FlexranMessage **msg ); -typedef int (*enb_agent_message_destruction_callback)( +typedef int (*flexran_agent_message_destruction_callback)( Protocol__FlexranMessage *msg ); @@ -74,75 +74,75 @@ typedef int (*enb_agent_message_destruction_callback)( **********************************/ /* Helper functions for message (de)serialization */ -int enb_agent_serialize_message(Protocol__FlexranMessage *msg, void **buf, int *size); -int enb_agent_deserialize_message(void *data, int size, Protocol__FlexranMessage **msg); +int flexran_agent_serialize_message(Protocol__FlexranMessage *msg, void **buf, int *size); +int flexran_agent_deserialize_message(void *data, int size, Protocol__FlexranMessage **msg); /* Serialize message and then destroy the input flexran msg. Should be called when protocol message is created dynamically */ -void * enb_agent_pack_message(Protocol__FlexranMessage *msg, +void * flexran_agent_pack_message(Protocol__FlexranMessage *msg, uint32_t * size); /* Calls destructor of the given message */ -err_code_t enb_agent_destroy_flexran_message(Protocol__FlexranMessage *msg); +err_code_t flexran_agent_destroy_flexran_message(Protocol__FlexranMessage *msg); /* Function to create the header for any FlexRAN protocol message */ -int flex_create_header(xid_t xid, Protocol__FlexType type, Protocol__FlexHeader **header); +int flexran_create_header(xid_t xid, Protocol__FlexType type, Protocol__FlexHeader **header); /* Hello protocol message constructor and destructor */ -int enb_agent_hello(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); -int enb_agent_destroy_hello(Protocol__FlexranMessage *msg); +int flexran_agent_hello(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int flexran_agent_destroy_hello(Protocol__FlexranMessage *msg); /* Echo request protocol message constructor and destructor */ -int enb_agent_echo_request(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); -int enb_agent_destroy_echo_request(Protocol__FlexranMessage *msg); +int flexran_agent_echo_request(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int flexran_agent_destroy_echo_request(Protocol__FlexranMessage *msg); /* Echo reply protocol message constructor and destructor */ -int enb_agent_echo_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); -int enb_agent_destroy_echo_reply(Protocol__FlexranMessage *msg); +int flexran_agent_echo_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int flexran_agent_destroy_echo_reply(Protocol__FlexranMessage *msg); /* eNodeB configuration reply message constructor and destructor */ -int enb_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); -int enb_agent_destroy_enb_config_reply(Protocol__FlexranMessage *msg); +int flexran_agent_enb_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int flexran_agent_destroy_enb_config_reply(Protocol__FlexranMessage *msg); /* UE configuration reply message constructor and destructor */ -int enb_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); -int enb_agent_destroy_ue_config_reply(Protocol__FlexranMessage *msg); +int flexran_agent_ue_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int flexran_agent_destroy_ue_config_reply(Protocol__FlexranMessage *msg); /* Logical channel reply configuration message constructor and destructor */ -int enb_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); -int enb_agent_destroy_lc_config_reply(Protocol__FlexranMessage *msg); +int flexran_agent_lc_config_reply(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int flexran_agent_destroy_lc_config_reply(Protocol__FlexranMessage *msg); /* eNodeB configuration request message constructor and destructor */ -int enb_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg); -int enb_agent_destroy_enb_config_request(Protocol__FlexranMessage *msg); +int flexran_agent_enb_config_request(mid_t mod_id, const void* params, Protocol__FlexranMessage **msg); +int flexran_agent_destroy_enb_config_request(Protocol__FlexranMessage *msg); /* UE configuration request message constructor */ /* TODO: Need to define and implement destructor */ -int enb_agent_destroy_ue_config_request(Protocol__FlexranMessage *msg); +int flexran_agent_destroy_ue_config_request(Protocol__FlexranMessage *msg); /* Logical channel configuration request message constructor */ /* TODO: Need to define and implement destructor */ -int enb_agent_destroy_lc_config_request(Protocol__FlexranMessage *msg); +int flexran_agent_destroy_lc_config_request(Protocol__FlexranMessage *msg); /* UE state change message constructor and destructor */ -int enb_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change); -int enb_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg); +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 enb_agent_control_delegation(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); -int enb_agent_destroy_control_delegation(Protocol__FlexranMessage *msg); +int flexran_agent_control_delegation(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int flexran_agent_destroy_control_delegation(Protocol__FlexranMessage *msg); /* Policy reconfiguration message constructor and destructor */ -int enb_agent_reconfiguration(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); -int enb_agent_destroy_agent_reconfiguration(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); /* FlexRAN protocol message dispatcher function */ -Protocol__FlexranMessage* enb_agent_handle_message (mid_t mod_id, +Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id, uint8_t *data, uint32_t size); /* Function to be used to send a message to a dispatcher once the appropriate event is triggered. */ -Protocol__FlexranMessage *enb_agent_handle_timed_task(void *args); +Protocol__FlexranMessage *flexran_agent_handle_timed_task(void *args); @@ -151,134 +151,134 @@ Protocol__FlexranMessage *enb_agent_handle_timed_task(void *args); * get generic info from RAN ****************************/ -void set_enb_vars(mid_t mod_id, ran_name_t ran); +void flexran_set_enb_vars(mid_t mod_id, ran_name_t ran); -int get_current_time_ms (mid_t mod_id, int subframe_flag); +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 get_current_frame(mid_t mod_id); +unsigned int flexran_get_current_frame(mid_t mod_id); /*Return the current SFN (0-1023)*/ -unsigned int get_current_system_frame_num(mid_t mod_id); +unsigned int flexran_get_current_system_frame_num(mid_t mod_id); -unsigned int get_current_subframe(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 get_sfn_sf (mid_t mod_id); +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 get_future_sfn_sf(mid_t mod_id, int ahead_of_time); +uint16_t flexran_get_future_sfn_sf(mid_t mod_id, int ahead_of_time); /* Return the number of attached UEs */ -int get_num_ues(mid_t mod_id); +int flexran_get_num_ues(mid_t mod_id); /* Get the rnti of a UE with id ue_id */ -int get_ue_crnti (mid_t mod_id, mid_t 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 get_ue_bsr (mid_t mod_id, mid_t ue_id, lcid_t lcid); +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 get_ue_phr (mid_t mod_id, mid_t ue_id); +int flexran_get_ue_phr (mid_t mod_id, mid_t ue_id); /* Get the UE wideband CQI */ -int get_ue_wcqi (mid_t mod_id, mid_t ue_id); +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 get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); +int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id); /* Return timing advance MAC control element for a designated cell and UE */ -int get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, int CC_id); +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 get_active_CC(mid_t mod_id, mid_t ue_id); +int flexran_get_active_CC(mid_t mod_id, mid_t ue_id); /* Get the rank indicator for a designated cell and UE */ -int get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id); +int flexran_get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id); /* See TS 36.213, section 10.1 */ -int get_n1pucch_an(mid_t mod_id, int CC_id); +int flexran_get_n1pucch_an(mid_t mod_id, int CC_id); /* See TS 36.211, section 5.4 */ -int get_nRB_CQI(mid_t mod_id, int CC_id); +int flexran_get_nRB_CQI(mid_t mod_id, int CC_id); /* See TS 36.211, section 5.4 */ -int get_deltaPUCCH_Shift(mid_t mod_id, int CC_id); +int flexran_get_deltaPUCCH_Shift(mid_t mod_id, int CC_id); /* See TS 36.211, section 5.7.1 */ -int get_prach_ConfigIndex(mid_t mod_id, int CC_id); +int flexran_get_prach_ConfigIndex(mid_t mod_id, int CC_id); /* See TS 36.211, section 5.7.1 */ -int get_prach_FreqOffset(mid_t mod_id, int CC_id); +int flexran_get_prach_FreqOffset(mid_t mod_id, int CC_id); /* See TS 36.321 */ -int get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id); +int flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, int CC_id); /* Get the length of the UL cyclic prefix */ -int get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id); +int flexran_get_ul_cyclic_prefix_length(mid_t mod_id, int CC_id); /* Get the length of the DL cyclic prefix */ -int get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id); +int flexran_get_dl_cyclic_prefix_length(mid_t mod_id, int CC_id); /* Get the physical cell id of a cell */ -int get_cell_id(mid_t mod_id, int CC_id); +int flexran_get_cell_id(mid_t mod_id, int CC_id); /* See TS 36.211, section 5.5.3.2 */ -int get_srs_BandwidthConfig(mid_t mod_id, int CC_id); +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 get_srs_SubframeConfig(mid_t mod_id, int CC_id); +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 get_srs_MaxUpPts(mid_t mod_id, int CC_id); +int flexran_get_srs_MaxUpPts(mid_t mod_id, int CC_id); /* Get number of DL resource blocks */ -int get_N_RB_DL(mid_t mod_id, int CC_id); +int flexran_get_N_RB_DL(mid_t mod_id, int CC_id); /* Get number of UL resource blocks */ -int get_N_RB_UL(mid_t mod_id, int CC_id); +int flexran_get_N_RB_UL(mid_t mod_id, int CC_id); /* Get DL/UL subframe assignment. TDD only */ -int get_subframe_assignment(mid_t mod_id, int CC_id); +int flexran_get_subframe_assignment(mid_t mod_id, int CC_id); /* TDD only. See TS 36.211, table 4.2.1 */ -int get_special_subframe_assignment(mid_t mod_id, int CC_id); +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 get_ra_ResponseWindowSize(mid_t mod_id, int CC_id); +int flexran_get_ra_ResponseWindowSize(mid_t mod_id, int CC_id); /* Get timer used for random access */ -int get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id); +int flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, int CC_id); /* Get type of duplex mode (FDD/TDD) */ -int get_duplex_mode(mid_t mod_id, int CC_id); +int flexran_get_duplex_mode(mid_t mod_id, int CC_id); /* Get the SI window length */ -long get_si_window_length(mid_t mod_id, int CC_id); +long flexran_get_si_window_length(mid_t mod_id, int CC_id); /* Get the number of PDCCH symbols configured for the cell */ -int get_num_pdcch_symb(mid_t mod_id, int CC_id); +int flexran_get_num_pdcch_symb(mid_t mod_id, int CC_id); /* See TS 36.213, sec 5.1.1.1 */ -int get_tpc(mid_t mod_id, mid_t ue_id); +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 get_harq(const mid_t mod_id, const uint8_t CC_id, const mid_t ue_id, - const int frame, const uint8_t subframe, int *id, int *status); +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, int *id, int *status); /* Reported values for uplink power control */ -int get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id); +int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id); -int get_p0_nominal_pucch(mid_t mod_id, int CC_id); +int flexran_get_p0_nominal_pucch(mid_t mod_id, int CC_id); /* * ************************************ @@ -289,86 +289,86 @@ int get_p0_nominal_pucch(mid_t mod_id, int CC_id); /* Get timer in subframes. Controls the synchronization status of the UE, not the actual timing advance procedure. See TS 36.321 */ -int get_time_alignment_timer(mid_t mod_id, mid_t ue_id); +int flexran_get_time_alignment_timer(mid_t mod_id, mid_t ue_id); /* Get measurement gap configuration. See TS 36.133 */ -int get_meas_gap_config(mid_t mod_id, mid_t ue_id); +int flexran_get_meas_gap_config(mid_t mod_id, mid_t ue_id); /* Get measurement gap configuration offset if applicable */ -int get_meas_gap_config_offset(mid_t mod_id, mid_t ue_id); +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 get_ue_aggregated_max_bitrate_dl (mid_t mod_id, mid_t ue_id); +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 get_ue_aggregated_max_bitrate_ul (mid_t mod_id, mid_t ue_id); +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 get_half_duplex(mid_t ue_id); +int flexran_get_half_duplex(mid_t ue_id); /* Support of intra-subframe hopping. Boolean value */ -int get_intra_sf_hopping(mid_t ue_id); +int flexran_get_intra_sf_hopping(mid_t ue_id); /* UE support for type 2 hopping with n_sb>1 */ -int get_type2_sb_1(mid_t ue_id); +int flexran_get_type2_sb_1(mid_t ue_id); /* Get the UE category */ -int get_ue_category(mid_t ue_id); +int flexran_get_ue_category(mid_t ue_id); /* UE support for resource allocation type 1 */ -int get_res_alloc_type1(mid_t ue_id); +int flexran_get_res_alloc_type1(mid_t ue_id); /* Get UE transmission mode */ -int get_ue_transmission_mode(mid_t mod_id, mid_t ue_id); +int flexran_get_ue_transmission_mode(mid_t mod_id, mid_t ue_id); /* Boolean value. See TS 36.321 */ -int get_tti_bundling(mid_t mod_id, mid_t ue_id); +int flexran_get_tti_bundling(mid_t mod_id, mid_t ue_id); /* The max HARQ retransmission for UL. See TS 36.321 */ -int get_maxHARQ_TX(mid_t mod_id, mid_t ue_id); +int flexran_get_maxHARQ_TX(mid_t mod_id, mid_t ue_id); /* See TS 36.213 */ -int get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id); +int flexran_get_beta_offset_ack_index(mid_t mod_id, mid_t ue_id); /* See TS 36.213 */ -int get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id); +int flexran_get_beta_offset_ri_index(mid_t mod_id, mid_t ue_id); /* See TS 36.213 */ -int get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id); +int flexran_get_beta_offset_cqi_index(mid_t mod_id, mid_t ue_id); /* Boolean. See TS36.213, Section 10.1 */ -int get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id); +int flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, mid_t ue_id); /* Boolean. See TS 36.213, Section 8.2 */ -int get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id); +int flexran_get_ack_nack_simultaneous_trans(mid_t mod_id,mid_t ue_id); /* Get aperiodic CQI report mode */ -int get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id); +int flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id,mid_t ue_id); /* Get ACK/NACK feedback mode. TDD only */ -int get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id); +int flexran_get_tdd_ack_nack_feedback(mid_t mod_id, mid_t ue_id); /* See TS36.213, section 10.1 */ -int get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id); +int flexran_get_ack_nack_repetition_factor(mid_t mod_id, mid_t ue_id); /* Boolean. Extended buffer status report size */ -int get_extended_bsr_size(mid_t mod_id, mid_t ue_id); +int flexran_get_extended_bsr_size(mid_t mod_id, mid_t ue_id); /* Get number of UE transmission antennas */ -int get_ue_transmission_antenna(mid_t mod_id, mid_t ue_id); +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 get_lcg(mid_t ue_id, mid_t lc_id); +int flexran_get_lcg(mid_t ue_id, mid_t lc_id); /* Get direction of logical channel with id lc_id */ -int get_direction(mid_t ue_id, mid_t lc_id); +int flexran_get_direction(mid_t ue_id, mid_t lc_id); /******************* * timer primitves @@ -382,51 +382,51 @@ int get_direction(mid_t ue_id, mid_t lc_id); /* Type of the callback executed when the timer expired */ -typedef Protocol__FlexranMessage *(*enb_agent_timer_callback_t)(void*); +typedef Protocol__FlexranMessage *(*flexran_agent_timer_callback_t)(void*); typedef enum { /* oneshot timer: */ - ENB_AGENT_TIMER_TYPE_ONESHOT = 0x0, + FLEXRAN_AGENT_TIMER_TYPE_ONESHOT = 0x0, /* periodic timer */ - ENB_AGENT_TIMER_TYPE_PERIODIC = 0x1, + FLEXRAN_AGENT_TIMER_TYPE_PERIODIC = 0x1, /* Inactive state: initial state for any timer. */ - ENB_AGENT_TIMER_TYPE_EVENT_DRIVEN = 0x2, + FLEXRAN_AGENT_TIMER_TYPE_EVENT_DRIVEN = 0x2, /* Max number of states available */ - ENB_AGENT_TIMER_TYPE_MAX, -} eNB_agent_timer_type_t; + FLEXRAN_AGENT_TIMER_TYPE_MAX, +} flexran_agent_timer_type_t; typedef enum { /* Inactive state: initial state for any timer. */ - ENB_AGENT_TIMER_STATE_INACTIVE = 0x0, + FLEXRAN_AGENT_TIMER_STATE_INACTIVE = 0x0, /* Inactive state: initial state for any timer. */ - ENB_AGENT_TIMER_STATE_ACTIVE = 0x1, + FLEXRAN_AGENT_TIMER_STATE_ACTIVE = 0x1, /* Inactive state: initial state for any timer. */ - ENB_AGENT_TIMER_STATE_STOPPED = 0x2, + FLEXRAN_AGENT_TIMER_STATE_STOPPED = 0x2, /* Max number of states available */ - ENB_AGENT_TIMER_STATE_MAX, -} eNB_agent_timer_state_t; + FLEXRAN_AGENT_TIMER_STATE_MAX, +} flexran_agent_timer_state_t; -typedef struct enb_agent_timer_args_s{ +typedef struct flexran_agent_timer_args_s{ mid_t mod_id; Protocol__FlexranMessage *msg; -} enb_agent_timer_args_t; +} flexran_agent_timer_args_t; -typedef struct enb_agent_timer_element_s{ - RB_ENTRY(enb_agent_timer_element_s) entry; +typedef struct flexran_agent_timer_element_s{ + RB_ENTRY(flexran_agent_timer_element_s) entry; agent_id_t agent_id; instance_t instance; - eNB_agent_timer_type_t type; - eNB_agent_timer_state_t state; + flexran_agent_timer_type_t type; + flexran_agent_timer_state_t state; uint32_t interval_sec; uint32_t interval_usec; @@ -435,59 +435,59 @@ typedef struct enb_agent_timer_element_s{ xid_t xid; /*The id of the task as received by the controller message*/ - enb_agent_timer_callback_t cb; - enb_agent_timer_args_t *timer_args; + flexran_agent_timer_callback_t cb; + flexran_agent_timer_args_t *timer_args; -} enb_agent_timer_element_t; +} flexran_agent_timer_element_t; -typedef struct enb_agent_timer_instance_s{ - RB_HEAD(enb_agent_map, enb_agent_timer_element_s) enb_agent_head; -}enb_agent_timer_instance_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 enb_agent_init_timer(void); +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 enb_agent_create_timer(uint32_t interval_sec, +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, - enb_agent_timer_callback_t cb, + flexran_agent_timer_callback_t cb, void* timer_args, long *timer_id); /* Destroy all existing timers */ -err_code_t enb_agent_destroy_timers(void); +err_code_t flexran_agent_destroy_timers(void); /* Destroy the timer with the given timer_id */ -err_code_t enb_agent_destroy_timer(long timer_id); +err_code_t flexran_agent_destroy_timer(long timer_id); /* Destroy the timer for task with id xid */ -err_code_t enb_agent_destroy_timer_by_task_id(xid_t xid); +err_code_t flexran_agent_destroy_timer_by_task_id(xid_t xid); /* Stop a timer */ -err_code_t enb_agent_stop_timer(long timer_id); +err_code_t flexran_agent_stop_timer(long timer_id); /* Restart the given timer */ -err_code_t enb_agent_restart_timer(long *timer_id); +err_code_t flexran_agent_restart_timer(long *timer_id); /* Find the timer with the given timer_id */ -struct enb_agent_timer_element_s * get_timer_entry(long 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 * enb_agent_process_timeout(long timer_id, void* timer_args); +Protocol__FlexranMessage * flexran_agent_process_timeout(long timer_id, void* timer_args); /* Comparator function comparing two timers. Decides the ordering of the timers */ -int enb_agent_compare_timer(struct enb_agent_timer_element_s *a, struct enb_agent_timer_element_s *b); +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 enb_agent_sleep_until(struct timespec *ts, int delay); +void flexran_agent_sleep_until(struct timespec *ts, int delay); /* RB_PROTOTYPE is for .h files */ -RB_PROTOTYPE(enb_agent_map, enb_agent_timer_element_s, entry, enb_agent_compare_timer); +RB_PROTOTYPE(flexran_agent_map, flexran_agent_timer_element_s, entry, flexran_agent_compare_timer); #endif diff --git a/openair2/ENB_APP/enb_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c similarity index 98% rename from openair2/ENB_APP/enb_agent_common_internal.c rename to openair2/ENB_APP/flexran_agent_common_internal.c index ca61a96609..f35cd8666f 100644 --- a/openair2/ENB_APP/enb_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -27,7 +27,7 @@ *******************************************************************************/ -/*! \file enb_agent_common_internal.c +/*! \file flexran_agent_common_internal.c * \brief internal functions for common message primitves and utilities * \author Xenofon Foukas * \date 2016 @@ -37,8 +37,8 @@ #include #include -#include "enb_agent_common_internal.h" -#include "enb_agent_mac_internal.h" +#include "flexran_agent_common_internal.h" +#include "flexran_agent_mac_internal.h" int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy_length) { diff --git a/openair2/ENB_APP/enb_agent_common_internal.h b/openair2/ENB_APP/flexran_agent_common_internal.h similarity index 94% rename from openair2/ENB_APP/enb_agent_common_internal.h rename to openair2/ENB_APP/flexran_agent_common_internal.h index 30fd51c5c8..45f4a73ffb 100644 --- a/openair2/ENB_APP/enb_agent_common_internal.h +++ b/openair2/ENB_APP/flexran_agent_common_internal.h @@ -27,19 +27,19 @@ *******************************************************************************/ -/*! \file enb_agent_common_internal.h +/*! \file flexran_agent_common_internal.h * \brief internal agent functions for common message primitves and utilities * \author Xenofon Foukas * \date 2016 * \version 0.1 */ -#ifndef ENB_AGENT_COMMON_INTERNAL_H_ -#define ENB_AGENT_COMMON_INTERNAL_H_ +#ifndef FLEXRAN_AGENT_COMMON_INTERNAL_H_ +#define FLEXRAN_AGENT_COMMON_INTERNAL_H_ #include -#include "enb_agent_defs.h" +#include "flexran_agent_defs.h" int apply_reconfiguration_policy(mid_t mod_id, const char *policy, size_t policy_length); diff --git a/openair2/ENB_APP/enb_agent_defs.h b/openair2/ENB_APP/flexran_agent_defs.h similarity index 70% rename from openair2/ENB_APP/enb_agent_defs.h rename to openair2/ENB_APP/flexran_agent_defs.h index 8d71aa2db3..7da0487120 100644 --- a/openair2/ENB_APP/enb_agent_defs.h +++ b/openair2/ENB_APP/flexran_agent_defs.h @@ -27,14 +27,14 @@ *******************************************************************************/ -/*! \file enb_agent_defs.h - * \brief enb agent common definitions +/*! \file flexran_agent_defs.h + * \brief FlexRAN agent common definitions * \author Navid Nikaein and Xenofon Foukas * \date 2016 * \version 0.1 */ -#ifndef ENB_AGENT_DEFS_H_ -#define ENB_AGENT_DEFS_H_ +#ifndef FLEXRAN_AGENT_DEFS_H_ +#define FLEXRAN_AGENT_DEFS_H_ #include #include @@ -45,54 +45,54 @@ #define NUM_MAX_ENB 2 #define NUM_MAX_UE 2048 -#define DEFAULT_ENB_AGENT_IPv4_ADDRESS "127.0.0.1" -#define DEFAULT_ENB_AGENT_PORT 2210 -#define DEFAULT_ENB_AGENT_CACHE "/mnt/oai_agent_cache" +#define DEFAULT_FLEXRAN_AGENT_IPv4_ADDRESS "127.0.0.1" +#define DEFAULT_FLEXRAN_AGENT_PORT 2210 +#define DEFAULT_FLEXRAN_AGENT_CACHE "/mnt/oai_agent_cache" typedef enum { - ENB_AGENT_DEFAULT=0, + FLEXRAN_AGENT_DEFAULT=0, - ENB_AGENT_PHY=1, - ENB_AGENT_MAC=2, - ENB_AGENT_RLC=3, - ENB_AGENT_PDCP=4, - ENB_AGENT_RRC=5, - ENB_AGENT_S1AP=6, - ENB_AGENT_GTP=7, - ENB_AGENT_X2AP=8, + FLEXRAN_AGENT_PHY=1, + FLEXRAN_AGENT_MAC=2, + FLEXRAN_AGENT_RLC=3, + FLEXRAN_AGENT_PDCP=4, + FLEXRAN_AGENT_RRC=5, + FLEXRAN_AGENT_S1AP=6, + FLEXRAN_AGENT_GTP=7, + FLEXRAN_AGENT_X2AP=8, - ENB_AGENT_MAX=9, + FLEXRAN_AGENT_MAX=9, } agent_id_t; typedef enum { /* no action */ - ENB_AGENT_ACTION_NONE = 0x0, + FLEXRAN_AGENT_ACTION_NONE = 0x0, /* send action */ - ENB_AGENT_ACTION_SEND = 0x1, + FLEXRAN_AGENT_ACTION_SEND = 0x1, /* apply action */ - ENB_AGENT_ACTION_APPLY = 0x2, + FLEXRAN_AGENT_ACTION_APPLY = 0x2, /* clear action */ - ENB_AGENT_ACTION_CLEAR = 0x4, + FLEXRAN_AGENT_ACTION_CLEAR = 0x4, /* write action */ - ENB_AGENT_ACTION_WRITE = 0x8, + FLEXRAN_AGENT_ACTION_WRITE = 0x8, /* filter action */ - ENB_AGENT_ACTION_FILTER = 0x10, + FLEXRAN_AGENT_ACTION_FILTER = 0x10, /* preprocess action */ - ENB_AGENT_ACTION_PREPROCESS = 0x20, + FLEXRAN_AGENT_ACTION_PREPROCESS = 0x20, /* meter action */ - ENB_AGENT_ACTION_METER = 0x40, + FLEXRAN_AGENT_ACTION_METER = 0x40, /* Max number of states available */ - ENB_AGENT_ACTION_MAX = 0x7f, + FLEXRAN_AGENT_ACTION_MAX = 0x7f, } agent_action_t; @@ -122,12 +122,12 @@ typedef struct { uint32_t rx_msg[NUM_MAX_ENB]; uint32_t tx_msg[NUM_MAX_ENB]; -}enb_agent_info_t; +} flexran_agent_info_t; typedef struct { mid_t enb_id; - enb_agent_info_t agent_info; + flexran_agent_info_t agent_info; -}enb_agent_instance_t; +} flexran_agent_instance_t; #endif diff --git a/openair2/ENB_APP/enb_agent_extern.h b/openair2/ENB_APP/flexran_agent_extern.h similarity index 87% rename from openair2/ENB_APP/enb_agent_extern.h rename to openair2/ENB_APP/flexran_agent_extern.h index 58f86dfe15..602b1d6ce3 100644 --- a/openair2/ENB_APP/enb_agent_extern.h +++ b/openair2/ENB_APP/flexran_agent_extern.h @@ -28,21 +28,21 @@ *******************************************************************************/ /*! \file ENB_APP/extern.h - * \brief enb agent - mac interface primitives + * \brief FlexRAN agent - mac interface primitives * \author Xenofon Foukas * \date 2016 * \version 0.1 * \mail x.foukas@sms.ed.ac.uk */ -#ifndef __ENB_AGENT_EXTERN_H__ -#define __ENB_AGENT_EXTERN_H__ +#ifndef __FLEXRAN_AGENT_EXTERN_H__ +#define __FLEXRAN_AGENT_EXTERN_H__ -#include "enb_agent_defs.h" -#include "enb_agent_mac_defs.h" +#include "flexran_agent_defs.h" +#include "flexran_agent_mac_defs.h" -//extern msg_context_t shared_ctxt[NUM_MAX_ENB][ENB_AGENT_MAX]; +//extern msg_context_t shared_ctxt[NUM_MAX_ENB][FLEXRAN_AGENT_MAX]; /* full path of the local cache for storing VSFs */ extern char local_cache[40]; diff --git a/openair2/ENB_APP/enb_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c similarity index 54% rename from openair2/ENB_APP/enb_agent_handler.c rename to openair2/ENB_APP/flexran_agent_handler.c index 46459f98bc..c077827c66 100644 --- a/openair2/ENB_APP/enb_agent_handler.c +++ b/openair2/ENB_APP/flexran_agent_handler.c @@ -27,61 +27,61 @@ *******************************************************************************/ -/*! \file enb_agent_handler.c - * \brief enb agent tx and rx message handler +/*! \file flexran_agent_handler.c + * \brief FlexRAN agent tx and rx message handler * \author Xenofon Foukas and Navid Nikaein * \date 2016 * \version 0.1 */ -#include "enb_agent_common.h" -#include "enb_agent_mac.h" +#include "flexran_agent_common.h" +#include "flexran_agent_mac.h" #include "log.h" #include "assertions.h" -enb_agent_message_decoded_callback agent_messages_callback[][3] = { - {enb_agent_hello, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_HELLO_MSG*/ - {enb_agent_echo_reply, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_ECHO_REQUEST_MSG*/ +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 - {enb_agent_mac_handle_stats, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG*/ + {flexran_agent_mac_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*/ - {enb_agent_enb_config_reply, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG*/ + {flexran_agent_enb_config_reply, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REQUEST_MSG*/ {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_ENB_CONFIG_REPLY_MSG*/ - {enb_agent_ue_config_reply, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_CONFIG_REQUEST_MSG*/ + {flexran_agent_ue_config_reply, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_CONFIG_REQUEST_MSG*/ {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_CONFIG_REPLY_MSG*/ - {enb_agent_lc_config_reply, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_LC_CONFIG_REQUEST_MSG*/ + {flexran_agent_lc_config_reply, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_LC_CONFIG_REQUEST_MSG*/ {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_LC_CONFIG_REPLY_MSG*/ - {enb_agent_mac_handle_dl_mac_config, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG*/ + {flexran_agent_mac_handle_dl_mac_config, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG*/ {0, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG*/ - {enb_agent_control_delegation, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_CONTROL_DELEGATION_MSG*/ - {enb_agent_reconfiguration, 0, 0}, /*PROTOCOL__FLEXRAN_MESSAGE__MSG_AGENT_RECONFIGURATION_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*/ }; -enb_agent_message_destruction_callback message_destruction_callback[] = { - enb_agent_destroy_hello, - enb_agent_destroy_echo_request, - enb_agent_destroy_echo_reply, - enb_agent_mac_destroy_stats_request, - enb_agent_mac_destroy_stats_reply, - enb_agent_mac_destroy_sf_trigger, - enb_agent_mac_destroy_sr_info, - enb_agent_destroy_enb_config_request, - enb_agent_destroy_enb_config_reply, - enb_agent_destroy_ue_config_request, - enb_agent_destroy_ue_config_reply, - enb_agent_destroy_lc_config_request, - enb_agent_destroy_lc_config_reply, - enb_agent_mac_destroy_dl_config, - enb_agent_destroy_ue_state_change, - enb_agent_destroy_control_delegation, - enb_agent_destroy_agent_reconfiguration, +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_mac_destroy_stats_reply, + flexran_agent_mac_destroy_sf_trigger, + flexran_agent_mac_destroy_sr_info, + flexran_agent_destroy_enb_config_request, + flexran_agent_destroy_enb_config_reply, + flexran_agent_destroy_ue_config_request, + flexran_agent_destroy_ue_config_reply, + flexran_agent_destroy_lc_config_request, + flexran_agent_destroy_lc_config_reply, + flexran_agent_mac_destroy_dl_config, + flexran_agent_destroy_ue_state_change, + flexran_agent_destroy_control_delegation, + flexran_agent_destroy_agent_reconfiguration, }; -static const char *enb_agent_direction2String[] = { +static const char *flexran_agent_direction2String[] = { "", /* not_set */ "originating message", /* originating message */ "successfull outcome", /* successfull outcome */ @@ -89,23 +89,23 @@ static const char *enb_agent_direction2String[] = { }; -Protocol__FlexranMessage* enb_agent_handle_message (mid_t mod_id, - uint8_t *data, - uint32_t size){ +Protocol__FlexranMessage* flexran_agent_handle_message (mid_t mod_id, + uint8_t *data, + uint32_t size){ Protocol__FlexranMessage *decoded_message, *reply_message; err_code_t err_code; DevAssert(data != NULL); - if (enb_agent_deserialize_message(data, size, &decoded_message) < 0) { + if (flexran_agent_deserialize_message(data, size, &decoded_message) < 0) { err_code= PROTOCOL__FLEXRAN_ERR__MSG_DECODING; goto error; } - if ((decoded_message->msg_case > sizeof(agent_messages_callback) / (3*sizeof(enb_agent_message_decoded_callback))) || + 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; - goto error; + goto error; } if (agent_messages_callback[decoded_message->msg_case-1][decoded_message->msg_dir-1] == NULL) { @@ -123,20 +123,20 @@ Protocol__FlexranMessage* enb_agent_handle_message (mid_t mod_id, return reply_message; error: - LOG_E(ENB_AGENT,"errno %d occured\n",err_code); + LOG_E(FLEXRAN_AGENT,"errno %d occured\n",err_code); return NULL; } -void * enb_agent_pack_message(Protocol__FlexranMessage *msg, - uint32_t * size){ +void * flexran_agent_pack_message(Protocol__FlexranMessage *msg, + uint32_t * size){ void * buffer; err_code_t err_code = PROTOCOL__FLEXRAN_ERR__NO_ERR; - if (enb_agent_serialize_message(msg, &buffer, size) < 0 ) { + if (flexran_agent_serialize_message(msg, &buffer, size) < 0 ) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENCODING; goto error; } @@ -147,23 +147,23 @@ void * enb_agent_pack_message(Protocol__FlexranMessage *msg, DevAssert(buffer !=NULL); - LOG_D(ENB_AGENT,"Serilized the enb mac stats reply (size %d)\n", *size); + LOG_D(FLEXRAN_AGENT,"Serilized the enb mac stats reply (size %d)\n", *size); return buffer; error : - LOG_E(ENB_AGENT,"errno %d occured\n",err_code); + LOG_E(FLEXRAN_AGENT,"errno %d occured\n",err_code); return NULL; } -Protocol__FlexranMessage *enb_agent_handle_timed_task(void *args) { +Protocol__FlexranMessage *flexran_agent_handle_timed_task(void *args) { err_code_t err_code; - enb_agent_timer_args_t *timer_args = (enb_agent_timer_args_t *) args; + flexran_agent_timer_args_t *timer_args = (flexran_agent_timer_args_t *) args; Protocol__FlexranMessage *timed_task, *reply_message; timed_task = timer_args->msg; - err_code = ((*agent_messages_callback[timed_task->msg_case-1][timed_task->msg_dir-1])(timer_args->mod_id, (void *) timed_task, &reply_message)); + err_code = ((*agent_messages_callback[timed_task->msg_case-1][timed_task->msg_dir-1])(timer_args->mod_id, (void *) timed_task, &reply_message)); if ( err_code < 0 ){ goto error; } @@ -171,27 +171,27 @@ Protocol__FlexranMessage *enb_agent_handle_timed_task(void *args) { return reply_message; error: - LOG_E(ENB_AGENT,"errno %d occured\n",err_code); + LOG_E(FLEXRAN_AGENT,"errno %d occured\n",err_code); return NULL; } -Protocol__FlexranMessage* enb_agent_process_timeout(long timer_id, void* timer_args){ +Protocol__FlexranMessage* flexran_agent_process_timeout(long timer_id, void* timer_args){ - struct enb_agent_timer_element_s *found = get_timer_entry(timer_id); + struct flexran_agent_timer_element_s *found = get_timer_entry(timer_id); if (found == NULL ) goto error; - LOG_I(ENB_AGENT, "Found the entry (%p): timer_id is 0x%lx 0x%lx\n", found, timer_id, found->timer_id); + LOG_I(FLEXRAN_AGENT, "Found the entry (%p): timer_id is 0x%lx 0x%lx\n", found, timer_id, found->timer_id); if (timer_args == NULL) - LOG_W(ENB_AGENT,"null timer args\n"); + LOG_W(FLEXRAN_AGENT,"null timer args\n"); return found->cb(timer_args); error: - LOG_E(ENB_AGENT, "can't get the timer element\n"); + LOG_E(FLEXRAN_AGENT, "can't get the timer element\n"); return TIMER_ELEMENT_NOT_FOUND; } -err_code_t enb_agent_destroy_flexran_message(Protocol__FlexranMessage *msg) { +err_code_t flexran_agent_destroy_flexran_message(Protocol__FlexranMessage *msg) { return ((*message_destruction_callback[msg->msg_case-1])(msg)); } diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/flexran_agent_mac.c similarity index 84% rename from openair2/ENB_APP/enb_agent_mac.c rename to openair2/ENB_APP/flexran_agent_mac.c index 330dafad3a..c85ec6c4eb 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/flexran_agent_mac.c @@ -27,21 +27,21 @@ *******************************************************************************/ -/*! \file enb_agent_mac.c - * \brief enb agent message handler for MAC layer +/*! \file flexran_agent_mac.c + * \brief FlexRAN agent message handler for MAC layer * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein * \date 2016 * \version 0.1 */ -#include "enb_agent_mac.h" -#include "enb_agent_extern.h" -#include "enb_agent_common.h" -#include "enb_agent_mac_internal.h" +#include "flexran_agent_mac.h" +#include "flexran_agent_extern.h" +#include "flexran_agent_common.h" +#include "flexran_agent_mac_internal.h" #include "LAYER2/MAC/proto.h" -#include "LAYER2/MAC/enb_agent_mac_proto.h" -#include "LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h" +#include "LAYER2/MAC/flexran_agent_mac_proto.h" +#include "LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h" #include "liblfds700.h" @@ -61,7 +61,7 @@ struct lfds700_ringbuffer_element *dl_mac_config_array[NUM_MAX_ENB]; struct lfds700_ringbuffer_state ringbuffer_state[NUM_MAX_ENB]; -int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg){ +int flexran_agent_mac_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 @@ -97,8 +97,8 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Flexr 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*/ - enb_agent_disable_cont_mac_stats_update(mod_id); - enb_agent_destroy_timer_by_task_id(xid); + 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 @@ -108,7 +108,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Flexr //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 = get_num_ues(mod_id); //eNB_UE_list->num_UEs + 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 @@ -116,7 +116,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Flexr goto error; } for (i = 0; i < report_config.nr_ue; i++) { - report_config.ue_report_type[i].ue_rnti = 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_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 @@ -153,12 +153,12 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Flexr report_config.ue_report_type[0].ue_report_flags = ue_flags; } request_config.config = &report_config; - enb_agent_mac_stats_request(enb_id, xid, &request_config, &timer_msg); + flexran_agent_mac_stats_request(enb_id, xid, &request_config, &timer_msg); /* Create a timer */ long timer_id = 0; - enb_agent_timer_args_t *timer_args; - timer_args = malloc(sizeof(enb_agent_timer_args_t)); - memset (timer_args, 0, sizeof(enb_agent_timer_args_t)); + 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*/ @@ -169,11 +169,11 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Flexr sec_interval = usec_interval/(1000*1000); usec_interval = usec_interval%(1000*1000); } - enb_agent_create_timer(sec_interval, usec_interval, ENB_AGENT_DEFAULT, enb_id, ENB_AGENT_TIMER_TYPE_PERIODIC, xid, enb_agent_handle_timed_task,(void*) timer_args, &timer_id); + 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*/ - enb_agent_disable_cont_mac_stats_update(mod_id); + 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; @@ -191,7 +191,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Flexr report_config.ue_report_type[0].ue_report_flags = ue_flags; } request_config.config = &report_config; - enb_agent_enable_cont_mac_stats_update(enb_id, xid, &request_config); + flexran_agent_enable_cont_mac_stats_update(enb_id, xid, &request_config); } } break; @@ -236,7 +236,7 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Flexr goto error; } - if (enb_agent_mac_stats_reply(enb_id, xid, &report_config, msg) < 0 ){ + if (flexran_agent_mac_stats_reply(enb_id, xid, &report_config, msg) < 0 ){ err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; goto error; } @@ -247,18 +247,18 @@ int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__Flexr return 0; error : - LOG_E(ENB_AGENT, "errno %d occured\n", err_code); + LOG_E(FLEXRAN_AGENT, "errno %d occured\n", err_code); return err_code; } -int enb_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_stats_request(mid_t mod_id, + xid_t xid, + const stats_request_config_t *report_config, + Protocol__FlexranMessage **msg) { Protocol__FlexHeader *header; int i; - if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REQUEST, &header) != 0) + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REQUEST, &header) != 0) goto error; Protocol__FlexStatsRequest *stats_request_msg; @@ -358,7 +358,7 @@ int enb_agent_mac_stats_request(mid_t mod_id, return -1; } -int enb_agent_mac_destroy_stats_request(Protocol__FlexranMessage *msg) { +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); @@ -377,10 +377,10 @@ int enb_agent_mac_destroy_stats_request(Protocol__FlexranMessage *msg) { return -1; } -int enb_agent_mac_stats_reply(mid_t mod_id, - xid_t xid, - const report_config_t *report_config, - Protocol__FlexranMessage **msg) { +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; int i, j, k; int cc_id = 0; @@ -389,7 +389,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, //UE_list_t *eNB_UE_list= &eNB->UE_list; - if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) goto error; Protocol__FlexStatsReply *stats_reply_msg; @@ -429,14 +429,14 @@ int enb_agent_mac_stats_reply(mid_t mod_id, goto error; for (j = 0; j++; j < ue_report[i]->n_bsr) { // NN: we need to know the cc_id here, consider the first one - elem[j] = get_ue_bsr (enb_id, i, j); + elem[j] = flexran_get_ue_bsr (enb_id, i, j); } ue_report[i]->bsr = elem; } /* 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 = get_ue_phr (enb_id, i); // eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].phr_info; + 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; } @@ -456,7 +456,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, 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 = get_tx_queue_size(enb_id,i,j+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 @@ -480,7 +480,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, /* 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 = (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 + 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 */ @@ -496,10 +496,10 @@ int enb_agent_mac_stats_reply(mid_t mod_id, goto error; protocol__flex_dl_cqi_report__init(dl_report); - dl_report->sfn_sn = get_sfn_sf(enb_id); + 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 = get_active_CC(enb_id,i); + dl_report->n_csi_report = flexran_get_active_CC(enb_id,i); //Create the actual CSI reports. Protocol__FlexDlCsi **csi_reports; @@ -515,7 +515,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, 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 = get_current_RI(enb_id,i,j); + 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 @@ -532,7 +532,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, protocol__flex_csi_p10__init(csi10); //TODO: set the wideband value // NN: this is also depends on cc_id - csi10->wb_cqi = get_ue_wcqi (enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].dl_cqi; + 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; @@ -618,7 +618,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, 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 = get_sfn_sf(enb_id); + 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 @@ -664,8 +664,8 @@ int enb_agent_mac_stats_reply(mid_t mod_id, 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(get_p0_pucch_dbm(enb_id,i, j) != -1){ - full_ul_report->pucch_dbm[j]->p0_pucch_dbm = get_p0_pucch_dbm(enb_id,i,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; } } @@ -704,7 +704,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, goto error; protocol__flex_noise_interference_report__init(ni_report); // Current frame and subframe number - ni_report->sfn_sf = get_sfn_sf(enb_id); + 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; @@ -713,7 +713,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, ni_report->tnp = 0; ni_report->has_tnp = 0; - ni_report->p0_nominal_pucch = get_p0_nominal_pucch(enb_id, 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; } @@ -743,7 +743,7 @@ int enb_agent_mac_stats_reply(mid_t mod_id, return -1; } -int enb_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg) { +int flexran_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg) { //TODO: Need to deallocate memory for the stats reply message if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG) goto error; @@ -860,11 +860,11 @@ int enb_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg) { return -1; } -int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { +int flexran_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { Protocol__FlexHeader *header; int i; const int xid = *((int *)params); - if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UL_SR_INFO, &header) != 0) + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UL_SR_INFO, &header) != 0) goto error; Protocol__FlexUlSrInfo *ul_sr_info_msg; @@ -876,7 +876,7 @@ int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__FlexranMes ul_sr_info_msg->header = header; ul_sr_info_msg->has_sfn_sf = 1; - ul_sr_info_msg->sfn_sf = get_sfn_sf(mod_id); + ul_sr_info_msg->sfn_sf = flexran_get_sfn_sf(mod_id); /*TODO: Set the number of UEs that sent an SR */ ul_sr_info_msg->n_rnti = 1; ul_sr_info_msg->rnti = (uint32_t *) malloc(ul_sr_info_msg->n_rnti * sizeof(uint32_t)); @@ -912,7 +912,7 @@ int enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__FlexranMes return -1; } -int enb_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg) { +int flexran_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_UL_SR_INFO_MSG) goto error; @@ -927,11 +927,11 @@ int enb_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg) { return -1; } -int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { +int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { Protocol__FlexHeader *header; int i,j; const int xid = *((int *)params); - if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_SF_TRIGGER, &header) != 0) + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_SF_TRIGGER, &header) != 0) goto error; Protocol__FlexSfTrigger *sf_trigger_msg; @@ -946,8 +946,8 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Flexran int ahead_of_time = 1; - frame = (frame_t) get_current_system_frame_num(mod_id); - subframe = (sub_frame_t) get_current_subframe(mod_id); + 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); @@ -955,18 +955,18 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Flexran frame = frame + full_frames_ahead; - if (subframe < get_current_subframe(mod_id)) { + if (subframe < flexran_get_current_subframe(mod_id)) { frame++; } sf_trigger_msg->header = header; sf_trigger_msg->has_sfn_sf = 1; - sf_trigger_msg->sfn_sf = get_future_sfn_sf(mod_id, 1); + sf_trigger_msg->sfn_sf = flexran_get_future_sfn_sf(mod_id, 1); /*TODO: Fill in the number of dl HARQ related info, based on the number of currently *transmitting UEs */ - sf_trigger_msg->n_dl_info = get_num_ues(mod_id); + sf_trigger_msg->n_dl_info = flexran_get_num_ues(mod_id); Protocol__FlexDlInfo **dl_info = NULL; @@ -980,12 +980,12 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Flexran if(dl_info[i] == NULL) goto error; protocol__flex_dl_info__init(dl_info[i]); - dl_info[i]->rnti = get_ue_crnti(mod_id, i); + dl_info[i]->rnti = flexran_get_ue_crnti(mod_id, i); dl_info[i]->has_rnti = 1; /*Fill in the right id of this round's HARQ process for this UE*/ int harq_id; int harq_status; - get_harq(mod_id, UE_PCCID(mod_id,i), i, frame, subframe, &harq_id, &harq_status); + flexran_get_harq(mod_id, UE_PCCID(mod_id,i), i, frame, subframe, &harq_id, &harq_status); dl_info[i]->harq_process_id = harq_id; dl_info[i]->has_harq_process_id = 1; /* Fill in the status of the HARQ process (2 TBs)*/ @@ -1009,7 +1009,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Flexran /* Fill in the number of UL reception status related info, based on the number of currently * transmitting UEs */ - sf_trigger_msg->n_ul_info = get_num_ues(mod_id); + sf_trigger_msg->n_ul_info = flexran_get_num_ues(mod_id); Protocol__FlexUlInfo **ul_info = NULL; @@ -1023,15 +1023,15 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Flexran if(ul_info[i] == NULL) goto error; protocol__flex_ul_info__init(ul_info[i]); - ul_info[i]->rnti = get_ue_crnti(mod_id, i); + ul_info[i]->rnti = flexran_get_ue_crnti(mod_id, i); ul_info[i]->has_rnti = 1; /*Fill in the Tx power control command for this UE (if available)*/ - if(get_tpc(mod_id,i) != 1){ - ul_info[i]->tpc = get_tpc(mod_id,i); + if(flexran_get_tpc(mod_id,i) != 1){ + ul_info[i]->tpc = flexran_get_tpc(mod_id,i); ul_info[i]->has_tpc = 1; } else{ - ul_info[i]->tpc = get_tpc(mod_id,i); + ul_info[i]->tpc = flexran_get_tpc(mod_id,i); ul_info[i]->has_tpc = 0; } /*TODO: fill in the amount of data in bytes in the MAC SDU received in this subframe for the @@ -1081,7 +1081,7 @@ int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Flexran return -1; } -int enb_agent_mac_destroy_sf_trigger(Protocol__FlexranMessage *msg) { +int flexran_agent_mac_destroy_sf_trigger(Protocol__FlexranMessage *msg) { int i; if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_SF_TRIGGER_MSG) goto error; @@ -1107,11 +1107,11 @@ int enb_agent_mac_destroy_sf_trigger(Protocol__FlexranMessage *msg) { return -1; } -int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage **msg) { +int flexran_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage **msg) { int xid = 0; Protocol__FlexHeader *header; - if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_DL_MAC_CONFIG, &header) != 0) + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_DL_MAC_CONFIG, &header) != 0) goto error; Protocol__FlexDlMacConfig *dl_mac_config_msg; @@ -1123,7 +1123,7 @@ int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage dl_mac_config_msg->header = header; dl_mac_config_msg->has_sfn_sf = 1; - dl_mac_config_msg->sfn_sf = get_sfn_sf(mod_id); + dl_mac_config_msg->sfn_sf = flexran_get_sfn_sf(mod_id); *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) @@ -1139,7 +1139,7 @@ int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage return -1; } -int enb_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg) { +int flexran_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg) { int i,j, k; if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG) goto error; @@ -1202,7 +1202,7 @@ int enb_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg) { return -1; } -void enb_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__FlexranMessage **msg) { +void flexran_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__FlexranMessage **msg) { struct lfds700_misc_prng_state ls; @@ -1214,7 +1214,7 @@ void enb_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__FlexranMessage } } -int enb_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { +int flexran_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { struct lfds700_misc_prng_state ls; enum lfds700_misc_flag overwrite_occurred_flag; @@ -1233,7 +1233,7 @@ int enb_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protoco if (overwrite_occurred_flag == LFDS700_MISC_FLAG_RAISED) { // Delete unmanaged dl_config - enb_agent_mac_destroy_dl_config(overwritten_dl_config); + flexran_agent_mac_destroy_dl_config(overwritten_dl_config); } *msg = NULL; return 2; @@ -1243,7 +1243,7 @@ int enb_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protoco return -1; } -void enb_agent_init_mac_agent(mid_t mod_id) { +void flexran_agent_init_mac_agent(mid_t mod_id) { lfds700_misc_library_init_valid_on_current_logical_core(); lfds700_misc_prng_init(&ps[mod_id]); int num_elements = RINGBUFFER_SIZE + 1; @@ -1253,10 +1253,10 @@ void enb_agent_init_mac_agent(mid_t mod_id) { } /*********************************************** - * eNB agent - technology mac API implementation + * FlexRAN agent - technology mac API implementation ***********************************************/ -void enb_agent_send_sr_info(mid_t mod_id) { +void flexran_agent_send_sr_info(mid_t mod_id) { int size; Protocol__FlexranMessage *msg; void *data; @@ -1266,27 +1266,27 @@ void enb_agent_send_sr_info(mid_t mod_id) { int xid = 0; /*TODO: Must use a proper xid*/ - err_code = enb_agent_mac_sr_info(mod_id, (void *) &xid, &msg); + err_code = flexran_agent_mac_sr_info(mod_id, (void *) &xid, &msg); if (err_code < 0) { goto error; } if (msg != NULL){ - data=enb_agent_pack_message(msg, &size); + data=flexran_agent_pack_message(msg, &size); /*Send sr info using the MAC channel of the eNB*/ - if (enb_agent_msg_send(mod_id, ENB_AGENT_MAC, data, size, priority)) { + if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_MAC, data, size, priority)) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } - LOG_D(ENB_AGENT,"sent message with size %d\n", size); + LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); return; } error: - LOG_D(ENB_AGENT, "Could not send sr message\n"); + LOG_D(FLEXRAN_AGENT, "Could not send sr message\n"); } -void enb_agent_send_sf_trigger(mid_t mod_id) { +void flexran_agent_send_sf_trigger(mid_t mod_id) { int size; Protocol__FlexranMessage *msg; void *data; @@ -1296,27 +1296,27 @@ void enb_agent_send_sf_trigger(mid_t mod_id) { int xid = 0; /*TODO: Must use a proper xid*/ - err_code = enb_agent_mac_sf_trigger(mod_id, (void *) &xid, &msg); + err_code = flexran_agent_mac_sf_trigger(mod_id, (void *) &xid, &msg); if (err_code < 0) { goto error; } if (msg != NULL){ - data=enb_agent_pack_message(msg, &size); + data=flexran_agent_pack_message(msg, &size); /*Send sr info using the MAC channel of the eNB*/ - if (enb_agent_msg_send(mod_id, ENB_AGENT_MAC, data, size, priority)) { + if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_MAC, data, size, priority)) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } - LOG_D(ENB_AGENT,"sent message with size %d\n", size); + LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); return; } error: - LOG_D(ENB_AGENT, "Could not send sf trigger message\n"); + LOG_D(FLEXRAN_AGENT, "Could not send sf trigger message\n"); } -void enb_agent_send_update_mac_stats(mid_t mod_id) { +void flexran_agent_send_update_mac_stats(mid_t mod_id) { Protocol__FlexranMessage *current_report = NULL, *msg; void *data; @@ -1333,7 +1333,7 @@ void enb_agent_send_update_mac_stats(mid_t mod_id) { if (mac_stats_context[mod_id].cont_update == 1) { /*Create a fresh report with the required flags*/ - err_code = enb_agent_mac_handle_stats(mod_id, (void *) mac_stats_context[mod_id].stats_req, ¤t_report); + 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; } @@ -1343,10 +1343,10 @@ void enb_agent_send_update_mac_stats(mid_t mod_id) { /* *respecting the thresholds. Otherwise send the new report*\/ */ /* if (mac_stats_context[mod_id].prev_stats_reply != NULL) { */ - /* msg = enb_agent_generate_diff_mac_stats_report(current_report, mac_stats_context[mod_id].prev_stats_reply); */ + /* msg = flexran_agent_generate_diff_mac_stats_report(current_report, mac_stats_context[mod_id].prev_stats_reply); */ /* /\*Destroy the old stats*\/ */ - /* enb_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); */ + /* 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; */ @@ -1357,34 +1357,34 @@ void enb_agent_send_update_mac_stats(mid_t mod_id) { } if (current_report != NULL){ - data=enb_agent_pack_message(current_report, &size); + data=flexran_agent_pack_message(current_report, &size); /*Send any stats updates using the MAC channel of the eNB*/ - if (enb_agent_msg_send(mod_id, ENB_AGENT_MAC, data, size, priority)) { + if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_MAC, data, size, priority)) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } - LOG_D(ENB_AGENT,"sent message with size %d\n", size); + LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); return; } error: - LOG_D(ENB_AGENT, "Could not send sf trigger message\n"); + LOG_D(FLEXRAN_AGENT, "Could not send sf trigger message\n"); } -int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { +int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { if (mac_agent_registered[mod_id]) { LOG_E(MAC, "MAC agent for eNB %d is already registered\n", mod_id); return -1; } //xface->agent_ctxt = &shared_ctxt[mod_id]; - xface->enb_agent_send_sr_info = enb_agent_send_sr_info; - xface->enb_agent_send_sf_trigger = enb_agent_send_sf_trigger; - xface->enb_agent_send_update_mac_stats = enb_agent_send_update_mac_stats; - //xface->enb_agent_schedule_ue_spec = schedule_ue_spec_default; - xface->enb_agent_schedule_ue_spec = schedule_ue_spec_remote; - xface->enb_agent_get_pending_dl_mac_config = enb_agent_get_pending_dl_mac_config; - xface->enb_agent_notify_ue_state_change = enb_agent_ue_state_change; + 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_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; @@ -1394,15 +1394,15 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { return 0; } -int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { +int flexran_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { //xface->agent_ctxt = NULL; - xface->enb_agent_send_sr_info = NULL; - xface->enb_agent_send_sf_trigger = NULL; - xface->enb_agent_send_update_mac_stats = NULL; - xface->enb_agent_schedule_ue_spec = NULL; - xface->enb_agent_get_pending_dl_mac_config = NULL; - xface->enb_agent_notify_ue_state_change = 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_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; @@ -1414,10 +1414,10 @@ int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { /****************************************************** - *Implementations of enb_agent_mac_internal.h functions + *Implementations of flexran_agent_mac_internal.h functions ******************************************************/ -err_code_t enb_agent_init_cont_mac_stats_update(mid_t mod_id) { +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*/ @@ -1437,12 +1437,12 @@ err_code_t enb_agent_init_cont_mac_stats_update(mid_t mod_id) { return -1; } -err_code_t enb_agent_destroy_cont_mac_stats_update(mid_t mod_id) { +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; - enb_agent_destroy_flexran_message(mac_stats_context[mod_id].stats_req); - enb_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); + 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] = NULL; @@ -1450,8 +1450,8 @@ err_code_t enb_agent_destroy_cont_mac_stats_update(mid_t mod_id) { } -err_code_t enb_agent_enable_cont_mac_stats_update(mid_t mod_id, - xid_t xid, stats_request_config_t *stats_req) { +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; @@ -1459,7 +1459,7 @@ err_code_t enb_agent_enable_cont_mac_stats_update(mid_t mod_id, Protocol__FlexranMessage *req_msg; - enb_agent_mac_stats_request(mod_id, xid, stats_req, &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; @@ -1472,11 +1472,11 @@ err_code_t enb_agent_enable_cont_mac_stats_update(mid_t mod_id, return 0; error: - LOG_E(ENB_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); + LOG_E(FLEXRAN_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); return -1; } -err_code_t enb_agent_disable_cont_mac_stats_update(mid_t mod_id) { +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; @@ -1484,10 +1484,10 @@ err_code_t enb_agent_disable_cont_mac_stats_update(mid_t mod_id) { mac_stats_context[mod_id].cont_update = 0; mac_stats_context[mod_id].xid = 0; if (mac_stats_context[mod_id].stats_req != NULL) { - enb_agent_destroy_flexran_message(mac_stats_context[mod_id].stats_req); + flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].stats_req); } if (mac_stats_context[mod_id].prev_stats_reply != NULL) { - enb_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); + 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; @@ -1495,7 +1495,7 @@ err_code_t enb_agent_disable_cont_mac_stats_update(mid_t mod_id) { return 0; error: - LOG_E(ENB_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); + LOG_E(FLEXRAN_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); return -1; } diff --git a/openair2/ENB_APP/enb_agent_mac.h b/openair2/ENB_APP/flexran_agent_mac.h similarity index 64% rename from openair2/ENB_APP/enb_agent_mac.h rename to openair2/ENB_APP/flexran_agent_mac.h index 0716b739e5..fbb13ceca9 100644 --- a/openair2/ENB_APP/enb_agent_mac.h +++ b/openair2/ENB_APP/flexran_agent_mac.h @@ -27,23 +27,23 @@ *******************************************************************************/ -/*! \file enb_agent_mac.h - * \brief enb agent message handler APIs for MAC layer +/*! \file flexran_agent_mac.h + * \brief FlexRAN agent message handler APIs for MAC layer * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein * \date 2016 * \version 0.1 */ -#ifndef ENB_AGENT_MAC_H_ -#define ENB_AGENT_MAC_H_ +#ifndef FLEXRAN_AGENT_MAC_H_ +#define FLEXRAN_AGENT_MAC_H_ #include "header.pb-c.h" #include "flexran.pb-c.h" #include "stats_messages.pb-c.h" #include "stats_common.pb-c.h" -#include "enb_agent_common.h" -#include "enb_agent_extern.h" +#include "flexran_agent_common.h" +#include "flexran_agent_extern.h" /* These types will be used to give instructions for the type of stats reports @@ -77,54 +77,54 @@ typedef struct stats_request_config_s{ } stats_request_config_t; /* Initialization function for the agent structures etc */ -void enb_agent_init_mac_agent(mid_t mod_id); +void flexran_agent_init_mac_agent(mid_t mod_id); -int enb_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int flexran_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); /* Statistics request protocol message constructor and destructor */ -int enb_agent_mac_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg); -int enb_agent_mac_destroy_stats_request(Protocol__FlexranMessage *msg); +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 enb_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg); -int enb_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg); +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 enb_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); -int enb_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg); +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); /* Subframe trigger protocol msssage constructor and destructor */ -int enb_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); -int enb_agent_mac_destroy_sf_trigger(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); /* DL MAC scheduling decision protocol message constructor (empty command) and destructor */ -int enb_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage **msg); -int enb_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg); +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); -int enb_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); +int flexran_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg); /********************************** - * eNB agent - technology mac API + * FlexRAN agent - technology mac API **********************************/ /*Inform controller about received scheduling requests during a subframe*/ -void enb_agent_send_sr_info(mid_t mod_id); +void flexran_agent_send_sr_info(mid_t mod_id); /*Inform the controller about the current UL/DL subframe*/ -void enb_agent_send_sf_trigger(mid_t mod_id); +void flexran_agent_send_sf_trigger(mid_t mod_id); /// Send to the controller all the mac stat updates that occured during this subframe /// based on the stats request configuration -void enb_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 enb_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__FlexranMessage **msg); +void flexran_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__FlexranMessage **msg); /*Register technology specific interface callbacks*/ -int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface); +int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface); /*Unregister technology specific callbacks*/ -int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface*xface); +int flexran_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface*xface); #endif diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/flexran_agent_mac_defs.h similarity index 75% rename from openair2/ENB_APP/enb_agent_mac_defs.h rename to openair2/ENB_APP/flexran_agent_mac_defs.h index cf473cae7d..e42847c371 100644 --- a/openair2/ENB_APP/enb_agent_mac_defs.h +++ b/openair2/ENB_APP/flexran_agent_mac_defs.h @@ -27,52 +27,52 @@ *******************************************************************************/ -/*! \file enb_agent_mac_defs.h - * \brief enb agent - mac interface primitives +/*! \file flexran_agent_mac_defs.h + * \brief FlexRAN agent - mac interface primitives * \author Xenofon Foukas * \date 2016 * \version 0.1 * \mail x.foukas@sms.ed.ac.uk */ -#ifndef __ENB_AGENT_MAC_PRIMITIVES_H__ -#define __ENB_AGENT_MAC_PRIMITIVES_H__ +#ifndef __FLEXRAN_AGENT_MAC_PRIMITIVES_H__ +#define __FLEXRAN_AGENT_MAC_PRIMITIVES_H__ -#include "enb_agent_defs.h" +#include "flexran_agent_defs.h" #include "flexran.pb-c.h" #include "header.pb-c.h" #define RINGBUFFER_SIZE 100 -/* ENB AGENT-MAC Interface */ +/* FLEXRAN AGENT-MAC Interface */ typedef struct { //msg_context_t *agent_ctxt; /// Inform the controller about the scheduling requests received during the subframe - void (*enb_agent_send_sr_info)(mid_t mod_id); + void (*flexran_agent_send_sr_info)(mid_t mod_id); /// Inform the controller about the current UL/DL subframe - void (*enb_agent_send_sf_trigger)(mid_t mod_id); + void (*flexran_agent_send_sf_trigger)(mid_t mod_id); /// Send to the controller all the mac stat updates that occured during this subframe /// based on the stats request configuration - void (*enb_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 (*enb_agent_get_pending_dl_mac_config)(mid_t mod_id, - Protocol__FlexranMessage **msg); + void (*flexran_agent_get_pending_dl_mac_config)(mid_t mod_id, + Protocol__FlexranMessage **msg); /// Run the UE DL scheduler and fill the Protocol__FlexranMessage. Assumes that /// dl_info is already initialized as flex_dl_mac_config and fills the /// flex_dl_data part of it - void (*enb_agent_schedule_ue_spec)(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__FlexranMessage **dl_info); - + void (*flexran_agent_schedule_ue_spec)(mid_t mod_id, uint32_t frame, uint32_t subframe, + int *mbsfn_flag, Protocol__FlexranMessage **dl_info); + /// Notify the controller for a state change of a particular UE, by sending the proper /// UE state change message (ACTIVATION, DEACTIVATION, HANDOVER) - void (*enb_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, - uint32_t state_change); + void (*flexran_agent_notify_ue_state_change)(mid_t mod_id, uint32_t rnti, + uint32_t state_change); void *dl_scheduler_loaded_lib; diff --git a/openair2/ENB_APP/enb_agent_mac_internal.c b/openair2/ENB_APP/flexran_agent_mac_internal.c similarity index 98% rename from openair2/ENB_APP/enb_agent_mac_internal.c rename to openair2/ENB_APP/flexran_agent_mac_internal.c index b42b3ac79b..7bfed81b48 100644 --- a/openair2/ENB_APP/enb_agent_mac_internal.c +++ b/openair2/ENB_APP/flexran_agent_mac_internal.c @@ -27,7 +27,7 @@ *******************************************************************************/ -/*! \file enb_agent_mac_internal.c +/*! \file flexran_agent_mac_internal.c * \brief Helper functions for the MAC agent * \author Xenofon Foukas * \date 2016 @@ -37,10 +37,10 @@ #include #include -#include "enb_agent_mac_internal.h" +#include "flexran_agent_mac_internal.h" -Protocol__FlexranMessage * enb_agent_generate_diff_mac_stats_report(Protocol__FlexranMessage *new_message, - Protocol__FlexranMessage *old_message) { +Protocol__FlexranMessage * flexran_agent_generate_diff_mac_stats_report(Protocol__FlexranMessage *new_message, + Protocol__FlexranMessage *old_message) { int i, j; @@ -131,7 +131,7 @@ Protocol__FlexranMessage * enb_agent_generate_diff_mac_stats_report(Protocol__Fl /*Create header*/ int xid = old_report->header->xid; Protocol__FlexHeader *header; - if (flex_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) { + if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) { goto error; } stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply)); @@ -780,7 +780,7 @@ int load_dl_scheduler_function(mid_t mod_id, const char *function_name) { void *loaded_scheduler = dlsym(lib, function_name); if (loaded_scheduler) { if (mac_agent_registered[mod_id]) { - agent_mac_xface[mod_id]->enb_agent_schedule_ue_spec = loaded_scheduler; + agent_mac_xface[mod_id]->flexran_agent_schedule_ue_spec = loaded_scheduler; if (agent_mac_xface[mod_id]->dl_scheduler_loaded_lib != NULL) { dlclose(agent_mac_xface[mod_id]->dl_scheduler_loaded_lib); } diff --git a/openair2/ENB_APP/enb_agent_mac_internal.h b/openair2/ENB_APP/flexran_agent_mac_internal.h similarity index 82% rename from openair2/ENB_APP/enb_agent_mac_internal.h rename to openair2/ENB_APP/flexran_agent_mac_internal.h index 86a021f946..e7a922d503 100644 --- a/openair2/ENB_APP/enb_agent_mac_internal.h +++ b/openair2/ENB_APP/flexran_agent_mac_internal.h @@ -27,23 +27,23 @@ *******************************************************************************/ -/*! \file enb_agent_mac_internal.h - * \brief Implementation specific definitions for the eNB MAC agent +/*! \file flexran_agent_mac_internal.h + * \brief Implementation specific definitions for the FlexRAN MAC agent * \author Xenofon Foukas * \date 2016 * \version 0.1 */ -#ifndef ENB_AGENT_MAC_INTERNAL_H_ -#define ENB_AGENT_MAC_INTERNAL_H_ +#ifndef FLEXRAN_AGENT_MAC_INTERNAL_H_ +#define FLEXRAN_AGENT_MAC_INTERNAL_H_ #include #include -#include "enb_agent_mac.h" -#include "enb_agent_common.h" -#include "enb_agent_defs.h" +#include "flexran_agent_mac.h" +#include "flexran_agent_common.h" +#include "flexran_agent_defs.h" /*This will be used for producing continuous status updates for the MAC *Needs to be thread-safe @@ -64,18 +64,18 @@ mac_stats_updates_context_t mac_stats_context[NUM_MAX_ENB]; /*Functions to initialize and destroy the struct required for the *continuous stats update report*/ -err_code_t enb_agent_init_cont_mac_stats_update(mid_t mod_id); +err_code_t flexran_agent_init_cont_mac_stats_update(mid_t mod_id); -err_code_t enb_agent_destroy_cont_mac_stats_update(mid_t mod_id); +err_code_t flexran_agent_destroy_cont_mac_stats_update(mid_t mod_id); /*Enable/Disable the continuous stats update service for the MAC*/ -err_code_t enb_agent_enable_cont_mac_stats_update(mid_t mod_id, xid_t xid, +err_code_t flexran_agent_enable_cont_mac_stats_update(mid_t mod_id, xid_t xid, stats_request_config_t *stats_req); -err_code_t enb_agent_disable_cont_mac_stats_update(mid_t mod_id); +err_code_t flexran_agent_disable_cont_mac_stats_update(mid_t mod_id); -Protocol__FlexranMessage * enb_agent_generate_diff_mac_stats_report(Protocol__FlexranMessage *new_report, +Protocol__FlexranMessage * flexran_agent_generate_diff_mac_stats_report(Protocol__FlexranMessage *new_report, Protocol__FlexranMessage *old_report); Protocol__FlexUeStatsReport * copy_ue_stats_report(Protocol__FlexUeStatsReport * original); @@ -111,4 +111,4 @@ int parse_dl_scheduler_parameters(mid_t mod_id, yaml_parser_t *parser); int load_dl_scheduler_function(mid_t mod_id, const char *function_name); -#endif /*ENB_AGENT_MAC_INTERNAL_H_*/ +#endif /*FLEXRAN_AGENT_MAC_INTERNAL_H_*/ diff --git a/openair2/ENB_APP/enb_agent_net_comm.c b/openair2/ENB_APP/flexran_agent_net_comm.c similarity index 52% rename from openair2/ENB_APP/enb_agent_net_comm.c rename to openair2/ENB_APP/flexran_agent_net_comm.c index e180d7affd..986c819fb0 100644 --- a/openair2/ENB_APP/enb_agent_net_comm.c +++ b/openair2/ENB_APP/flexran_agent_net_comm.c @@ -27,26 +27,26 @@ *******************************************************************************/ -/*! \file enb_agent_net_comm.c - * \brief enb agent network interface abstraction +/*! \file flexran_agent_net_comm.c + * \brief FlexRAN agent network interface abstraction * \author Xenofon Foukas * \date 2016 * \version 0.1 */ -#include "enb_agent_net_comm.h" +#include "flexran_agent_net_comm.h" #include "log.h" -enb_agent_channel_t *agent_channel[NUM_MAX_ENB][ENB_AGENT_MAX]; -enb_agent_channel_instance_t channel_instance; -int enb_agent_channel_id = 0; +flexran_agent_channel_t *agent_channel[NUM_MAX_ENB][FLEXRAN_AGENT_MAX]; +flexran_agent_channel_instance_t channel_instance; +int flexran_agent_channel_id = 0; -int enb_agent_msg_send(mid_t mod_id, agent_id_t agent_id, void *data, int size, int priority) { +int flexran_agent_msg_send(mid_t mod_id, agent_id_t agent_id, void *data, int size, int priority) { /*Check if agent id is valid*/ - if (agent_id >= ENB_AGENT_MAX || agent_id < 0) { + if (agent_id >= FLEXRAN_AGENT_MAX || agent_id < 0) { goto error; } - enb_agent_channel_t *channel; + flexran_agent_channel_t *channel; channel = agent_channel[mod_id][agent_id]; /*Check if agent has a channel registered*/ @@ -57,16 +57,16 @@ int enb_agent_msg_send(mid_t mod_id, agent_id_t agent_id, void *data, int size, return channel->msg_send(data, size, priority, channel->channel_info); error: - LOG_E(ENB_AGENT, "No channel registered for agent with id %d\n", agent_id); + LOG_E(FLEXRAN_AGENT, "No channel registered for agent with id %d\n", agent_id); return -1; } -int enb_agent_msg_recv(mid_t mod_id, agent_id_t agent_id, void **data, int *size, int *priority) { +int flexran_agent_msg_recv(mid_t mod_id, agent_id_t agent_id, void **data, int *size, int *priority) { /*Check if agent id is valid*/ - if (agent_id >= ENB_AGENT_MAX || agent_id < 0) { + if (agent_id >= FLEXRAN_AGENT_MAX || agent_id < 0) { goto error; } - enb_agent_channel_t *channel; + flexran_agent_channel_t *channel; channel = agent_channel[mod_id][agent_id]; /*Check if agent has a channel registered*/ @@ -77,19 +77,19 @@ int enb_agent_msg_recv(mid_t mod_id, agent_id_t agent_id, void **data, int *size return channel->msg_recv(data, size, priority, channel->channel_info); error: - LOG_E(ENB_AGENT, "No channel registered for agent with id %d\n", agent_id); + LOG_E(FLEXRAN_AGENT, "No channel registered for agent with id %d\n", agent_id); return -1; } -int enb_agent_register_channel(mid_t mod_id, enb_agent_channel_t *channel, agent_id_t agent_id) { +int flexran_agent_register_channel(mid_t mod_id, flexran_agent_channel_t *channel, agent_id_t agent_id) { int i; if (channel == NULL) { return -1; } - if (agent_id == ENB_AGENT_MAX) { - for (i = 0; i < ENB_AGENT_MAX; i++) { + if (agent_id == FLEXRAN_AGENT_MAX) { + for (i = 0; i < FLEXRAN_AGENT_MAX; i++) { agent_channel[mod_id][i] = channel; } } else { @@ -98,11 +98,11 @@ int enb_agent_register_channel(mid_t mod_id, enb_agent_channel_t *channel, agent return 0; } -void enb_agent_unregister_channel(mid_t mod_id, agent_id_t agent_id) { +void flexran_agent_unregister_channel(mid_t mod_id, agent_id_t agent_id) { int i; - if (agent_id == ENB_AGENT_MAX) { - for (i = 0; i < ENB_AGENT_MAX; i++) { + if (agent_id == FLEXRAN_AGENT_MAX) { + for (i = 0; i < FLEXRAN_AGENT_MAX; i++) { agent_channel[mod_id][i] = NULL; } } else { @@ -110,13 +110,13 @@ void enb_agent_unregister_channel(mid_t mod_id, agent_id_t agent_id) { } } -int enb_agent_create_channel(void *channel_info, - int (*msg_send)(void *data, int size, int priority, void *channel_info), - int (*msg_recv)(void **data, int *size, int *priority, void *channel_info), - void (*release)(enb_agent_channel_t *channel)) { +int flexran_agent_create_channel(void *channel_info, + int (*msg_send)(void *data, int size, int priority, void *channel_info), + int (*msg_recv)(void **data, int *size, int *priority, void *channel_info), + void (*release)(flexran_agent_channel_t *channel)) { - int channel_id = ++enb_agent_channel_id; - enb_agent_channel_t *channel = (enb_agent_channel_t *) malloc(sizeof(enb_agent_channel_t)); + int channel_id = ++flexran_agent_channel_id; + flexran_agent_channel_t *channel = (flexran_agent_channel_t *) malloc(sizeof(flexran_agent_channel_t)); channel->channel_id = channel_id; channel->channel_info = channel_info; channel->msg_send = msg_send; @@ -124,22 +124,22 @@ int enb_agent_create_channel(void *channel_info, channel->release = release; /*element should be a real pointer*/ - RB_INSERT(enb_agent_channel_map, &channel_instance.enb_agent_head, channel); + RB_INSERT(flexran_agent_channel_map, &channel_instance.flexran_agent_head, channel); - LOG_I(ENB_AGENT,"Created a new channel with id 0x%lx\n", channel->channel_id); + LOG_I(FLEXRAN_AGENT,"Created a new channel with id 0x%lx\n", channel->channel_id); return channel_id; } -int enb_agent_destroy_channel(int channel_id) { +int flexran_agent_destroy_channel(int channel_id) { int i, j; /*Check to see if channel exists*/ - struct enb_agent_channel_s *e = NULL; - struct enb_agent_channel_s search; - memset(&search, 0, sizeof(struct enb_agent_channel_s)); + struct flexran_agent_channel_s *e = NULL; + struct flexran_agent_channel_s search; + memset(&search, 0, sizeof(struct flexran_agent_channel_s)); - e = RB_FIND(enb_agent_channel_map, &channel_instance.enb_agent_head, &search); + e = RB_FIND(flexran_agent_channel_map, &channel_instance.flexran_agent_head, &search); if (e == NULL) { return -1; @@ -147,7 +147,7 @@ int enb_agent_destroy_channel(int channel_id) { /*Unregister the channel from all agents*/ for (i = 0; i < NUM_MAX_ENB; i++) { - for (j = 0; j < ENB_AGENT_MAX; j++) { + for (j = 0; j < FLEXRAN_AGENT_MAX; j++) { if (agent_channel[i][j] != NULL) { if (agent_channel[i][j]->channel_id == e->channel_id) { agent_channel[i][j] == NULL; @@ -157,21 +157,21 @@ int enb_agent_destroy_channel(int channel_id) { } /*Remove the channel from the tree and free memory*/ - RB_REMOVE(enb_agent_channel_map, &channel_instance.enb_agent_head, e); + RB_REMOVE(flexran_agent_channel_map, &channel_instance.flexran_agent_head, e); e->release(e); free(e); return 0; } -err_code_t enb_agent_init_channel_container(void) { +err_code_t flexran_agent_init_channel_container(void) { int i, j; - LOG_I(ENB_AGENT, "init RB tree for channel container\n"); + LOG_I(FLEXRAN_AGENT, "init RB tree for channel container\n"); - RB_INIT(&channel_instance.enb_agent_head); + RB_INIT(&channel_instance.flexran_agent_head); for (i = 0; i < NUM_MAX_ENB; i++) { - for (j = 0; j < ENB_AGENT_MAX; j++) { + for (j = 0; j < FLEXRAN_AGENT_MAX; j++) { agent_channel[i][j] == NULL; } } @@ -179,9 +179,9 @@ err_code_t enb_agent_init_channel_container(void) { return 0; } -RB_GENERATE(enb_agent_channel_map,enb_agent_channel_s, entry, enb_agent_compare_channel); +RB_GENERATE(flexran_agent_channel_map, flexran_agent_channel_s, entry, flexran_agent_compare_channel); -int enb_agent_compare_channel(struct enb_agent_channel_s *a, struct enb_agent_channel_s *b) { +int flexran_agent_compare_channel(struct flexran_agent_channel_s *a, struct flexran_agent_channel_s *b) { if (a->channel_id < b->channel_id) return -1; if (a->channel_id > b->channel_id) return 1; @@ -189,12 +189,12 @@ int enb_agent_compare_channel(struct enb_agent_channel_s *a, struct enb_agent_ch return 0; } -enb_agent_channel_t * get_channel(int channel_id) { +flexran_agent_channel_t * get_channel(int channel_id) { - struct enb_agent_channel_s search; - memset(&search, 0, sizeof(struct enb_agent_channel_s)); + struct flexran_agent_channel_s search; + memset(&search, 0, sizeof(struct flexran_agent_channel_s)); search.channel_id = channel_id; - return RB_FIND(enb_agent_channel_map, &channel_instance.enb_agent_head, &search); + return RB_FIND(flexran_agent_channel_map, &channel_instance.flexran_agent_head, &search); } diff --git a/openair2/ENB_APP/enb_agent_net_comm.h b/openair2/ENB_APP/flexran_agent_net_comm.h similarity index 54% rename from openair2/ENB_APP/enb_agent_net_comm.h rename to openair2/ENB_APP/flexran_agent_net_comm.h index 2a2268dc80..ca26de7c16 100644 --- a/openair2/ENB_APP/enb_agent_net_comm.h +++ b/openair2/ENB_APP/flexran_agent_net_comm.h @@ -27,63 +27,63 @@ *******************************************************************************/ -/*! \file enb_agent_net_comm.h - * \brief enb agent network interface abstraction +/*! \file flexran_agent_net_comm.h + * \brief FlexRAN agent network interface abstraction * \autho Xenofon Foukas * \date 2016 * \version 0.1 */ -#ifndef ENB_AGENT_NET_COMM_H_ -#define ENB_AGENT_NET_COMM_H_ +#ifndef FLEXRAN_AGENT_NET_COMM_H_ +#define FLEXRAN_AGENT_NET_COMM_H_ -#include "enb_agent_defs.h" +#include "flexran_agent_defs.h" #include "tree.h" /*Channel related information used for Tx/Rx of protocol messages*/ -typedef struct enb_agent_channel_s { - RB_ENTRY(enb_agent_channel_s) entry; +typedef struct flexran_agent_channel_s { + RB_ENTRY(flexran_agent_channel_s) entry; int channel_id; void *channel_info; /*Callbacks for channel message Tx and Rx*/ int (*msg_send)(void *data, int size, int priority, void *channel_info); int (*msg_recv)(void **data, int *size, int *priority, void *channel_info); -void (*release)(struct enb_agent_channel_s *channel); -} enb_agent_channel_t; +void (*release)(struct flexran_agent_channel_s *channel); +} flexran_agent_channel_t; -typedef struct enb_agent_channel_instance_s{ - RB_HEAD(enb_agent_channel_map, enb_agent_channel_s) enb_agent_head; -} enb_agent_channel_instance_t; +typedef struct flexran_agent_channel_instance_s{ + RB_HEAD(flexran_agent_channel_map, flexran_agent_channel_s) flexran_agent_head; +} flexran_agent_channel_instance_t; /*Send and receive messages using the channel registered for a specific agent*/ -int enb_agent_msg_send(mid_t mod_id, agent_id_t agent_id, void *data, int size, int priority); -int enb_agent_msg_recv(mid_t mod_id, agent_id_t agent_id, void **data, int *size, int *priority); +int flexran_agent_msg_send(mid_t mod_id, agent_id_t agent_id, void *data, int size, int priority); +int flexran_agent_msg_recv(mid_t mod_id, agent_id_t agent_id, void **data, int *size, int *priority); -/*Register a channel to an agent. Use ENB_AGENT_MAX to register the +/*Register a channel to an agent. Use FLEXRAN_AGENT_MAX to register the *same channel to all agents*/ -int enb_agent_register_channel(mid_t mod_id, enb_agent_channel_t *channel, agent_id_t agent_id); +int flexran_agent_register_channel(mid_t mod_id, flexran_agent_channel_t *channel, agent_id_t agent_id); -/*Unregister the current channel of an agent. Use ENB_AGENT_MAX to unregister all channels*/ -void enb_agent_unregister_channel(mid_t mod_id, agent_id_t agent_id); +/*Unregister the current channel of an agent. Use FLEXRAN_AGENT_MAX to unregister all channels*/ +void flexran_agent_unregister_channel(mid_t mod_id, agent_id_t agent_id); /*Create a new channel. Returns the id of the new channel or negative number otherwise*/ -int enb_agent_create_channel(void *channel_info, - int (*msg_send)(void *data, int size, int priority, void *channel_info), - int (*msg_recv)(void **data, int *size, int *priority, void *channel_info), - void (*release)(enb_agent_channel_t *channel)); +int flexran_agent_create_channel(void *channel_info, + int (*msg_send)(void *data, int size, int priority, void *channel_info), + int (*msg_recv)(void **data, int *size, int *priority, void *channel_info), + void (*release)(flexran_agent_channel_t *channel)); /*Unregister a channel from all agents and destroy it. Returns 0 in case of success*/ -int enb_agent_destroy_channel(int channel_id); +int flexran_agent_destroy_channel(int channel_id); /*Return an agent communication channel based on its id*/ -enb_agent_channel_t * get_channel(int channel_id); +flexran_agent_channel_t * get_channel(int channel_id); /*Should be called before performing any channel operations*/ -err_code_t enb_agent_init_channel_container(void); +err_code_t flexran_agent_init_channel_container(void); -int enb_agent_compare_channel(struct enb_agent_channel_s *a, struct enb_agent_channel_s *b); +int flexran_agent_compare_channel(struct flexran_agent_channel_s *a, struct flexran_agent_channel_s *b); /* RB_PROTOTYPE is for .h files */ -RB_PROTOTYPE(enb_agent_channel_map, enb_agent_channel_s, entry, enb_agent_compare_channel); +RB_PROTOTYPE(flexran_agent_channel_map, flexran_agent_channel_s, entry, flexran_agent_compare_channel); -#endif /*ENB_AGENT_COMM_H_*/ +#endif /*FLEXRAN_AGENT_COMM_H_*/ diff --git a/openair2/ENB_APP/enb_agent_task_manager.c b/openair2/ENB_APP/flexran_agent_task_manager.c similarity index 74% rename from openair2/ENB_APP/enb_agent_task_manager.c rename to openair2/ENB_APP/flexran_agent_task_manager.c index 9b4be2ff6a..e278386ba4 100644 --- a/openair2/ENB_APP/enb_agent_task_manager.c +++ b/openair2/ENB_APP/flexran_agent_task_manager.c @@ -26,8 +26,8 @@ Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE *******************************************************************************/ -/*! \file enb_agent_task_manager.h - * \brief Implementation of scheduled tasks manager for the enb agent +/*! \file flexran_agent_task_manager.h + * \brief Implementation of scheduled tasks manager for the FlexRAN agent * \author Xenofon Foukas * \date January 2016 * \version 0.1 @@ -39,8 +39,8 @@ #include #include -#include "enb_agent_task_manager.h" -#include "enb_agent_common.c" +#include "flexran_agent_task_manager.h" +#include "flexran_agent_common.c" /* Util macros */ @@ -48,10 +48,10 @@ #define RIGHT(x) (2 * (x) + 2) #define PARENT(x) ((x - 1) / 2) -enb_agent_task_t *enb_agent_task_create(Protocol__FlexranMessage *msg, - uint16_t frame_num, uint8_t subframe_num) { - enb_agent_task_t *task = NULL; - task = malloc(sizeof(enb_agent_task_t)); +flexran_agent_task_t *flexran_agent_task_create(Protocol__FlexranMessage *msg, + uint16_t frame_num, uint8_t subframe_num) { + flexran_agent_task_t *task = NULL; + task = malloc(sizeof(flexran_agent_task_t)); if (task == NULL) goto error; @@ -66,7 +66,7 @@ enb_agent_task_t *enb_agent_task_create(Protocol__FlexranMessage *msg, return NULL; } -void enb_agent_task_destroy(enb_agent_task_t *task) { +void flexran_agent_task_destroy(flexran_agent_task_t *task) { if (task == NULL) return; @@ -75,26 +75,27 @@ void enb_agent_task_destroy(enb_agent_task_t *task) { free(task); } -enb_agent_task_queue_t *enb_agent_task_queue_init(mid_t mod_id, size_t capacity, - int (*cmp)(mid_t mod_id, const enb_agent_task_t *t1, const enb_agent_task_t *t2)) { - enb_agent_task_queue_t *queue = NULL; +flexran_agent_task_queue_t *flexran_agent_task_queue_init(mid_t mod_id, size_t capacity, + int (*cmp)(mid_t mod_id, const flexran_agent_task_t *t1, + const flexran_agent_task_t *t2)) { + flexran_agent_task_queue_t *queue = NULL; - queue = malloc(sizeof(enb_agent_task_queue_t)); + queue = malloc(sizeof(flexran_agent_task_queue_t)); if (queue == NULL) goto error; /* If no comparator was given, use the default one */ if (cmp == NULL) - queue->cmp = _enb_agent_task_queue_cmp; + queue->cmp = _flexran_agent_task_queue_cmp; else queue->cmp = cmp; - + queue->mod_id = mod_id; queue->first_frame = 0; queue->first_subframe = 0; - queue->task = malloc(capacity * sizeof(enb_agent_task_t *)); + queue->task = malloc(capacity * sizeof(flexran_agent_task_t *)); if (queue->task == NULL) goto error; @@ -118,27 +119,27 @@ enb_agent_task_queue_t *enb_agent_task_queue_init(mid_t mod_id, size_t capacity, return NULL; } -enb_agent_task_queue_t *enb_agent_task_queue_default_init(mid_t mod_id) { - return enb_agent_task_queue_init(mod_id, DEFAULT_CAPACITY, NULL); +flexran_agent_task_queue_t *flexran_agent_task_queue_default_init(mid_t mod_id) { + return flexran_agent_task_queue_init(mod_id, DEFAULT_CAPACITY, NULL); } -void enb_agent_task_queue_destroy(enb_agent_task_queue_t *queue) { +void flexran_agent_task_queue_destroy(flexran_agent_task_queue_t *queue) { int i; if (queue == NULL) return; for (i = 0; i < queue->count; i++) { - enb_agent_task_destroy(queue->task[i]); + flexran_agent_task_destroy(queue->task[i]); } free(queue->task); free(queue->mutex); free(queue); } -int enb_agent_task_queue_put(enb_agent_task_queue_t *queue, enb_agent_task_t *task) { +int flexran_agent_task_queue_put(flexran_agent_task_queue_t *queue, flexran_agent_task_t *task) { size_t i; - enb_agent_task_t *tmp = NULL; + flexran_agent_task_t *tmp = NULL; int realloc_status, err_code; if (pthread_mutex_lock(queue->mutex)) { @@ -149,7 +150,7 @@ int enb_agent_task_queue_put(enb_agent_task_queue_t *queue, enb_agent_task_t *ta if (queue->count >= queue->capacity) { /*TODO: need to call realloc heap*/ - realloc_status = _enb_agent_task_queue_realloc_heap(queue); + realloc_status = _flexran_agent_task_queue_realloc_heap(queue); if (realloc_status != HEAP_OK) { err_code = realloc_status; goto error; @@ -179,7 +180,7 @@ int enb_agent_task_queue_put(enb_agent_task_queue_t *queue, enb_agent_task_t *ta } -int enb_agent_task_queue_get_current_task(enb_agent_task_queue_t *queue, enb_agent_task_t **task) { +int flexran_agent_task_queue_get_current_task(flexran_agent_task_queue_t *queue, flexran_agent_task_t **task) { int err_code; if (pthread_mutex_lock(queue->mutex)) { @@ -195,8 +196,8 @@ int enb_agent_task_queue_get_current_task(enb_agent_task_queue_t *queue, enb_age } /* Find current frame and subframe number */ - uint16_t curr_frame=get_current_frame(queue->mod_id); - uint8_t curr_subframe=get_current_subframe(queue->mod_id); + uint16_t curr_frame = flexran_get_current_frame(queue->mod_id); + uint8_t curr_subframe = flexran_get_current_subframe(queue->mod_id); /* If no task is scheduled for the current subframe, return without any task */ if(queue->task[0]->frame_num != curr_frame || queue->task[0]->subframe_num != curr_subframe) { @@ -208,7 +209,7 @@ int enb_agent_task_queue_get_current_task(enb_agent_task_queue_t *queue, enb_age queue->task[0] = queue->task[queue->count-1]; queue->count--; /* Restore heap property */ - _enb_agent_task_queue_heapify(queue, 0); + _flexran_agent_task_queue_heapify(queue, 0); /*If queue has no element*/ if (queue->count < 1) { @@ -231,9 +232,9 @@ int enb_agent_task_queue_get_current_task(enb_agent_task_queue_t *queue, enb_age } /*Warning: Internal function. Should not be called as API function. Not thread safe*/ -void _enb_agent_task_queue_heapify(enb_agent_task_queue_t *queue, size_t idx) { +void _flexran_agent_task_queue_heapify(flexran_agent_task_queue_t *queue, size_t idx) { /* left index, right index, largest */ - enb_agent_task_t *tmp = NULL; + flexran_agent_task_t *tmp = NULL; size_t l_idx, r_idx, lrg_idx; l_idx = LEFT(idx); @@ -258,32 +259,32 @@ void _enb_agent_task_queue_heapify(enb_agent_task_queue_t *queue, size_t idx) { queue->task[lrg_idx] = queue->task[idx]; queue->task[idx] = tmp; /* Heapify again */ - _enb_agent_task_queue_heapify(queue, lrg_idx); + _flexran_agent_task_queue_heapify(queue, lrg_idx); } } /*Warning: Internal function. Should not be called as API function. Not thread safe*/ -int _enb_agent_task_queue_realloc_heap(enb_agent_task_queue_t *queue) { - enb_agent_task_t **resized_task_heap; +int _flexran_agent_task_queue_realloc_heap(flexran_agent_task_queue_t *queue) { + flexran_agent_task_t **resized_task_heap; if (queue->count >= queue->capacity) { - size_t task_size = sizeof(enb_agent_task_t); + size_t task_size = sizeof(flexran_agent_task_t); resized_task_heap = realloc(queue->task, (2*queue->capacity) * task_size); if (resized_task_heap != NULL) { queue->capacity *= 2; - queue->task = (enb_agent_task_t **) resized_task_heap; + queue->task = (flexran_agent_task_t **) resized_task_heap; return HEAP_OK; } else return HEAP_REALLOCERROR; } return HEAP_NOREALLOC; } -int _enb_agent_task_queue_cmp(mid_t mod_id, const enb_agent_task_t *t1, const enb_agent_task_t *t2) { +int _flexran_agent_task_queue_cmp(mid_t mod_id, const flexran_agent_task_t *t1, const flexran_agent_task_t *t2) { if ((t1->frame_num == t2->frame_num) && (t1->subframe_num == t2->subframe_num)) return 0; - uint16_t curr_frame = get_current_frame(mod_id); - uint8_t curr_subframe = get_current_subframe(mod_id); + uint16_t curr_frame = flexran_get_current_frame(mod_id); + uint8_t curr_subframe = flexran_get_current_subframe(mod_id); int f_offset, sf_offset, tmp1, tmp2; diff --git a/openair2/ENB_APP/enb_agent_task_manager.h b/openair2/ENB_APP/flexran_agent_task_manager.h similarity index 68% rename from openair2/ENB_APP/enb_agent_task_manager.h rename to openair2/ENB_APP/flexran_agent_task_manager.h index 0c458061cf..9faa0e3db7 100644 --- a/openair2/ENB_APP/enb_agent_task_manager.h +++ b/openair2/ENB_APP/flexran_agent_task_manager.h @@ -26,8 +26,8 @@ Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE *******************************************************************************/ -/*! \file enb_agent_task_manager.h - * \brief Implementation of scheduled tasks manager for the enb agent +/*! \file flexran_agent_task_manager.h + * \brief Implementation of scheduled tasks manager for the FlexRAN agent * \author Xenofon Foukas * \date January 2016 * \version 0.1 @@ -35,15 +35,15 @@ * @ingroup _mac */ -#ifndef ENB_AGENT_TASK_MANAGER_ -#define ENB_AGENT_TASK_MANAGER_ +#ifndef FLEXRAN_AGENT_TASK_MANAGER_ +#define FLEXRAN_AGENT_TASK_MANAGER_ #include #include #include "flexran.pb-c.h" -#include "enb_agent_common.h" +#include "flexran_agent_common.h" #ifdef __cplusplus extern "C" { @@ -54,19 +54,19 @@ extern "C" { /** * The structure containing the enb agent task to be executed */ -typedef struct enb_agent_task_s { +typedef struct flexran_agent_task_s { /* The frame in which the task needs to be executed */ uint16_t frame_num; /* The subframe in which the task needs to be executed */ uint8_t subframe_num; /* The task to be executed in the form of a Protocol__FlexranMessage */ Protocol__FlexranMessage *task; -} enb_agent_task_t; +} flexran_agent_task_t; /** * Priority Queue Structure for tasks */ -typedef struct enb_agent_task_queue_s { +typedef struct flexran_agent_task_queue_s { mid_t mod_id; /* The amount of allocated memory for agent tasks in the heap*/ volatile size_t capacity; @@ -77,11 +77,11 @@ typedef struct enb_agent_task_queue_s { /* The earliest subframe within the frame that has a pending task */ volatile uint8_t first_subframe; /* An array of prioritized tasks stored in a heap */ - enb_agent_task_t **task; + flexran_agent_task_t **task; /* A pointer to a comparator function, used to prioritize elements */ - int (*cmp)(mid_t mod_id, const enb_agent_task_t *t1, const enb_agent_task_t *t2); + int (*cmp)(mid_t mod_id, const flexran_agent_task_t *t1, const flexran_agent_task_t *t2); pthread_mutex_t *mutex; -} enb_agent_task_queue_t; +} flexran_agent_task_queue_t; typedef enum { HEAP_OK = 0, @@ -95,56 +95,57 @@ typedef enum { /** * Allocate memory for a task in the queue */ -enb_agent_task_t *enb_agent_task_create(Protocol__FlexranMessage *msg, - uint16_t frame_num, uint8_t subframe_num); +flexran_agent_task_t *flexran_agent_task_create(Protocol__FlexranMessage *msg, + uint16_t frame_num, uint8_t subframe_num); /** * Free memory for a task of the queue */ -void enb_agent_task_destroy(enb_agent_task_t *task); +void flexran_agent_task_destroy(flexran_agent_task_t *task); /** * Allocate initial memory for storing the tasks */ - enb_agent_task_queue_t *enb_agent_task_queue_init(mid_t mod_id, size_t capacity, - int (*cmp)(mid_t mod_id, const enb_agent_task_t *t1, const enb_agent_task_t *t2)); + flexran_agent_task_queue_t *flexran_agent_task_queue_init(mid_t mod_id, size_t capacity, + int (*cmp)(mid_t mod_id, const flexran_agent_task_t *t1, + const flexran_agent_task_t *t2)); /** * Allocate initial memory for storing the tasks using default parameters */ -enb_agent_task_queue_t *enb_agent_task_queue_default_init(mid_t mod_id); +flexran_agent_task_queue_t *flexran_agent_task_queue_default_init(mid_t mod_id); /** * De-allocate memory for the tasks queue */ -void enb_agent_task_queue_destroy(enb_agent_task_queue_t *queue); +void flexran_agent_task_queue_destroy(flexran_agent_task_queue_t *queue); /** * Insert task into the queue */ -int enb_agent_task_queue_put(enb_agent_task_queue_t *queue, enb_agent_task_t *task); +int flexran_agent_task_queue_put(flexran_agent_task_queue_t *queue, flexran_agent_task_t *task); /** * Remove the task with the highest priority from the queue * task becomes NULL if there is no task for the current frame and subframe */ -int enb_agent_task_queue_get_current_task(enb_agent_task_queue_t *queue, enb_agent_task_t **task); +int flexran_agent_task_queue_get_current_task(flexran_agent_task_queue_t *queue, flexran_agent_task_t **task); /** * Check if the top priority task is for a specific frame and subframe */ -int enb_agent_task_queue_has_upcoming_task (enb_agent_task_queue_t *queue, - const uint16_t frame, const uint8_t subframe); +int flexran_agent_task_queue_has_upcoming_task (flexran_agent_task_queue_t *queue, + const uint16_t frame, const uint8_t subframe); /** * Restructure heap after modifications */ -void _enb_agent_task_queue_heapify(enb_agent_task_queue_t *queue, size_t idx); +void _flexran_agent_task_queue_heapify(flexran_agent_task_queue_t *queue, size_t idx); /** * Reallocate memory once the heap reaches max size */ -int _enb_agent_task_queue_realloc_heap(enb_agent_task_queue_t *queue); +int _flexran_agent_task_queue_realloc_heap(flexran_agent_task_queue_t *queue); /** * Compare two agent tasks based on frame and subframe @@ -153,10 +154,10 @@ int _enb_agent_task_queue_realloc_heap(enb_agent_task_queue_t *queue); * return positive value if t1 preceeds t2 * Need to give eNB id for the comparisson based on the current frame-subframe */ - int _enb_agent_task_queue_cmp(mid_t mod_id, const enb_agent_task_t *t1, const enb_agent_task_t *t2); + int _flexran_agent_task_queue_cmp(mid_t mod_id, const flexran_agent_task_t *t1, const flexran_agent_task_t *t2); #ifdef __cplusplus } #endif -#endif /*ENB_AGENT_TASK_MANAGER_*/ +#endif /*FLEXRAN_AGENT_TASK_MANAGER_*/ diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index b57f5e965b..d24ac7c5d9 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -53,9 +53,9 @@ #include "pdcp.h" //Agent-related headers -#include "enb_agent_extern.h" -#include "enb_agent_mac.h" -#include "enb_agent_mac_proto.h" +#include "flexran_agent_extern.h" +#include "flexran_agent_mac.h" +#include "flexran_agent_mac_proto.h" #if defined(ENABLE_ITTI) # include "intertask_interface.h" @@ -141,9 +141,9 @@ 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 (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_notify_ue_state_change(module_idP, - rnti, - PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); + agent_mac_xface[module_idP]->flexran_agent_notify_ue_state_change(module_idP, + rnti, + PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); } } else { @@ -330,7 +330,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, /* #ifndef DISABLE_SF_TRIGGER */ /* //Send subframe trigger to the controller */ /* if (mac_agent_registered[module_idP]) { */ -/* agent_mac_xface[module_idP]->enb_agent_send_sf_trigger(module_idP); */ +/* agent_mac_xface[module_idP]->flexran_agent_send_sf_trigger(module_idP); */ /* } */ /* #endif */ @@ -392,19 +392,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif break; @@ -440,19 +440,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif } @@ -470,19 +470,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif } @@ -506,19 +506,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif break; @@ -534,20 +534,20 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); - } + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); + } #endif } @@ -577,19 +577,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif break; @@ -606,19 +606,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif } @@ -642,19 +642,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif } else if ((mac_xface->frame_parms->tdd_config == 0) || // TDD Config 0 @@ -669,19 +669,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif } @@ -721,19 +721,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif break; @@ -745,19 +745,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif break; @@ -772,19 +772,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif } @@ -805,19 +805,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif break; @@ -828,19 +828,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif break; @@ -855,19 +855,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif } @@ -893,19 +893,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif break; @@ -920,19 +920,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif } @@ -952,19 +952,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif break; @@ -977,19 +977,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif break; @@ -1002,19 +1002,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif break; @@ -1027,19 +1027,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif break; @@ -1054,19 +1054,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( - module_idP, - frameP, - subframeP, - mbsfn_status, - &msg); + agent_mac_xface[module_idP]->flexran_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + mbsfn_status, + &msg); - apply_dl_scheduling_decisions(module_idP, - frameP, - subframeP, - mbsfn_status, - msg); - enb_agent_mac_destroy_dl_config(msg); + flexran_apply_dl_scheduling_decisions(module_idP, + frameP, + subframeP, + mbsfn_status, + msg); + flexran_agent_mac_destroy_dl_config(msg); } #endif } @@ -1084,7 +1084,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, #ifndef DISABLE_CONT_STATS //Send subframe trigger to the controller if (mac_agent_registered[module_idP]) { - agent_mac_xface[module_idP]->enb_agent_send_update_mac_stats(module_idP); + agent_mac_xface[module_idP]->flexran_agent_send_update_mac_stats(module_idP); } #endif diff --git a/openair2/LAYER2/MAC/enb_agent_mac_proto.h b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h similarity index 68% rename from openair2/LAYER2/MAC/enb_agent_mac_proto.h rename to openair2/LAYER2/MAC/flexran_agent_mac_proto.h index 3c2d36e678..9e46e0904a 100644 --- a/openair2/LAYER2/MAC/enb_agent_mac_proto.h +++ b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h @@ -27,8 +27,8 @@ *******************************************************************************/ -/*! \file enb_agent_mac_proto.h - * \brief MAC functions for eNB agent +/*! \file flexran_agent_mac_proto.h + * \brief MAC functions for FlexRAN agent * \author Xenofon Foukas * \date 2016 * \email: x.foukas@sms.ed.ac.uk @@ -37,34 +37,34 @@ */ -#ifndef __LAYER2_MAC_ENB_AGENT_MAC_PROTO_H__ -#define __LAYER2_MAC_ENB_AGENT_MAC_PROTO_H__ +#ifndef __LAYER2_MAC_FLEXRAN_AGENT_MAC_PROTO_H__ +#define __LAYER2_MAC_FLEXRAN_AGENT_MAC_PROTO_H__ -#include "enb_agent_defs.h" +#include "flexran_agent_defs.h" #include "header.pb-c.h" #include "flexran.pb-c.h" /* * Default scheduler used by the eNB agent */ -void schedule_ue_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__FlexranMessage **dl_info); +void flexran_schedule_ue_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, + int *mbsfn_flag, Protocol__FlexranMessage **dl_info); /* * Data plane function for applying the DL decisions of the scheduler */ -void apply_dl_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, - const Protocol__FlexranMessage *dl_scheduling_info); +void flexran_apply_dl_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, + const Protocol__FlexranMessage *dl_scheduling_info); /* * Data plane function for applying the UE specific DL decisions of the scheduler */ -void apply_ue_spec_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, - uint32_t n_dl_ue_data, const Protocol__FlexDlData **dl_ue_data); +void flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, + uint32_t n_dl_ue_data, const Protocol__FlexDlData **dl_ue_data); /* * Data plane function for filling the DCI structure */ -void fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, const Protocol__FlexDlDci *dl_dci); +void flexran_fill_oai_dci(mid_t mod_id, uint32_t CC_id, uint32_t rnti, const Protocol__FlexDlDci *dl_dci); #endif diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c similarity index 96% rename from openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c rename to openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c index a4d4d79250..aff196681e 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c @@ -27,7 +27,7 @@ *******************************************************************************/ -/*! \file eNB_agent_scheduler_dataplane.c +/*! \file flexran_agent_scheduler_dataplane.c * \brief data plane procedures related to eNB scheduling * \author Xenofon Foukas * \date 2016 @@ -44,7 +44,7 @@ #include "SCHED/defs.h" #include "SCHED/extern.h" -#include "LAYER2/MAC/enb_agent_mac_proto.h" +#include "LAYER2/MAC/flexran_agent_mac_proto.h" #include "LAYER2/MAC/defs.h" #include "LAYER2/MAC/proto.h" #include "LAYER2/MAC/extern.h" @@ -65,11 +65,11 @@ #include "SIMULATION/TOOLS/defs.h" // for taus -void apply_dl_scheduling_decisions(mid_t mod_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - const Protocol__FlexranMessage *dl_scheduling_info) { +void flexran_apply_dl_scheduling_decisions(mid_t mod_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + const Protocol__FlexranMessage *dl_scheduling_info) { Protocol__FlexDlMacConfig *mac_config = dl_scheduling_info->dl_mac_config_msg; @@ -85,19 +85,19 @@ void apply_dl_scheduling_decisions(mid_t mod_id, // Check if there is anything to schedule for the UEs if (mac_config->n_dl_ue_data > 0) { - apply_ue_spec_scheduling_decisions(mod_id, frame, subframe, mbsfn_flag, - mac_config->n_dl_ue_data, mac_config->dl_ue_data); + flexran_apply_ue_spec_scheduling_decisions(mod_id, frame, subframe, mbsfn_flag, + mac_config->n_dl_ue_data, mac_config->dl_ue_data); } } -void apply_ue_spec_scheduling_decisions(mid_t mod_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - uint32_t n_dl_ue_data, - const Protocol__FlexDlData **dl_ue_data) { +void flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + uint32_t n_dl_ue_data, + const Protocol__FlexDlData **dl_ue_data) { uint8_t CC_id; int UE_id; diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c similarity index 98% rename from openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c rename to openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index 4572e73def..cf033959d3 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -27,7 +27,7 @@ *******************************************************************************/ -/*! \file eNB_agent_scheduler_dlsch_ue.c +/*! \file flexran_agent_scheduler_dlsch_ue.c * \brief procedures related to eNB for the DLSCH transport channel * \author Xenofon Foukas * \date 2016 @@ -44,7 +44,7 @@ #include "SCHED/defs.h" #include "SCHED/extern.h" -#include "LAYER2/MAC/enb_agent_mac_proto.h" +#include "LAYER2/MAC/flexran_agent_mac_proto.h" #include "LAYER2/MAC/defs.h" #include "LAYER2/MAC/proto.h" #include "LAYER2/MAC/extern.h" @@ -57,14 +57,14 @@ #include "RRC/LITE/extern.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" -#include "ENB_APP/enb_agent_defs.h" +#include "ENB_APP/flexran_agent_defs.h" //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" #include "header.pb-c.h" #include "flexran.pb-c.h" -#include "enb_agent_mac.h" +#include "flexran_agent_mac.h" #include "SIMULATION/TOOLS/defs.h" // for taus @@ -76,13 +76,11 @@ //------------------------------------------------------------------------------ void -schedule_ue_spec_default( - mid_t mod_id, - uint32_t frame, - uint32_t subframe, - int *mbsfn_flag, - Protocol__FlexranMessage **dl_info -) +flexran_schedule_ue_spec_default(mid_t mod_id, + uint32_t frame, + uint32_t subframe, + int *mbsfn_flag, + Protocol__FlexranMessage **dl_info) //------------------------------------------------------------------------------ { uint8_t CC_id; @@ -127,7 +125,7 @@ schedule_ue_spec_default( uint8_t ue_has_transmission = 0; uint32_t ndi; - enb_agent_mac_create_empty_dl_config(mod_id, dl_info); + flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); if (UE_list->head==-1) { return; diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c similarity index 86% rename from openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c rename to openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c index b5882c84e3..78b093c27d 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c @@ -27,7 +27,7 @@ *******************************************************************************/ -/*! \file eNB_agent_scheduler_dlsch_ue_remote.c +/*! \file flexran_agent_scheduler_dlsch_ue_remote.c * \brief procedures related to remote scheduling in the DLSCH transport channel * \author Xenofon Foukas * \date 2016 @@ -37,9 +37,9 @@ */ -#include "enb_agent_common_internal.h" +#include "flexran_agent_common_internal.h" -#include "eNB_agent_scheduler_dlsch_ue_remote.h" +#include "flexran_agent_scheduler_dlsch_ue_remote.h" #include "LAYER2/MAC/defs.h" #include "LAYER2/MAC/extern.h" @@ -52,8 +52,8 @@ int queue_initialized = 0; //uint32_t period = 10; //uint32_t sched [] = {1, 2, 3}; -void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, - int *mbsfn_flag, Protocol__FlexranMessage **dl_info) { +void flexran_schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, + int *mbsfn_flag, Protocol__FlexranMessage **dl_info) { //if ((subframe == skip_subframe) && (frame % period == 0)) { @@ -97,19 +97,19 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, } else if (diff < 0) { //previous subframe , delete message and free memory LOG_D(MAC, "Found a decision for a previous subframe in the queue. Let's get rid of it\n"); TAILQ_REMOVE(&queue_head, queue_head.tqh_first, configs); - enb_agent_mac_destroy_dl_config(dl_config_elem->dl_info); + flexran_agent_mac_destroy_dl_config(dl_config_elem->dl_info); free(dl_config_elem); eNB->eNB_stats[mod_id].sched_decisions++; eNB->eNB_stats[mod_id].missed_deadlines++; } else { // next subframe, nothing to do now LOG_D(MAC, "Found a decision for a future subframe in the queue. Nothing to do now\n"); - enb_agent_mac_create_empty_dl_config(mod_id, dl_info); + flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); return; } } //Done with the local cache. Now we need to check if something new arrived - enb_agent_get_pending_dl_mac_config(mod_id, dl_info); + flexran_agent_get_pending_dl_mac_config(mod_id, dl_info); while (*dl_info != NULL) { diff = get_sf_difference(mod_id, (*dl_info)->dl_mac_config_msg->sfn_sf); @@ -119,9 +119,9 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, return; } else if (diff < 0) { LOG_D(MAC, "Found a decision for a previous subframe. Let's get rid of it\n"); - enb_agent_mac_destroy_dl_config(*dl_info); + flexran_agent_mac_destroy_dl_config(*dl_info); *dl_info = NULL; - enb_agent_get_pending_dl_mac_config(mod_id, dl_info); + flexran_agent_get_pending_dl_mac_config(mod_id, dl_info); eNB->eNB_stats[mod_id].sched_decisions++; eNB->eNB_stats[mod_id].missed_deadlines++; } else { // Intended for future subframe. Store it in local cache @@ -129,22 +129,22 @@ void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, dl_mac_config_element_t *e = malloc(sizeof(dl_mac_config_element_t)); e->dl_info = *dl_info; TAILQ_INSERT_TAIL(&queue_head, e, configs); - enb_agent_mac_create_empty_dl_config(mod_id, dl_info); + flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); // No need to look for another. Messages arrive ordered return; } } // We found no pending command, so we will simply pass an empty one - enb_agent_mac_create_empty_dl_config(mod_id, dl_info); + flexran_agent_mac_create_empty_dl_config(mod_id, dl_info); } int get_sf_difference(mid_t mod_id, uint32_t sfn_sf) { int diff_in_subframes; - uint16_t current_frame = get_current_system_frame_num(mod_id); - uint16_t current_subframe = get_current_subframe(mod_id); - uint32_t current_sfn_sf = get_sfn_sf(mod_id); + uint16_t current_frame = flexran_get_current_system_frame_num(mod_id); + uint16_t current_subframe = flexran_get_current_subframe(mod_id); + uint32_t current_sfn_sf = flexran_get_sfn_sf(mod_id); if (sfn_sf == current_sfn_sf) { return 0; diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h similarity index 85% rename from openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h rename to openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h index 9ff750969b..2cfad85771 100644 --- a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue_remote.h +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h @@ -27,7 +27,7 @@ *******************************************************************************/ -/*! \file eNB_agent_scheduler_dlsch_ue_remote.h +/*! \file flexran_agent_scheduler_dlsch_ue_remote.h * \brief Local stub for remote scheduler used by the controller * \author Xenofon Foukas * \date 2016 @@ -37,15 +37,15 @@ */ -#ifndef __LAYER2_MAC_ENB_AGENT_SCHEDULER_DLSCH_UE_REMOTE_H__ -#define __LAYER2_MAC_ENB_AGENT_SCHEDULER_DLSCH_UE_REMOTE_H___ +#ifndef __LAYER2_MAC_FLEXRAN_AGENT_SCHEDULER_DLSCH_UE_REMOTE_H__ +#define __LAYER2_MAC_FLEXRAN_AGENT_SCHEDULER_DLSCH_UE_REMOTE_H___ #include "flexran.pb-c.h" #include "header.pb-c.h" -#include "ENB_APP/enb_agent_defs.h" -#include "enb_agent_mac.h" -#include "LAYER2/MAC/enb_agent_mac_proto.h" +#include "ENB_APP/flexran_agent_defs.h" +#include "flexran_agent_mac.h" +#include "LAYER2/MAC/flexran_agent_mac_proto.h" #include @@ -63,7 +63,7 @@ TAILQ_HEAD(DlMacConfigHead, dl_mac_config_element_s); /* * Default scheduler used by the eNB agent */ -void schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, +void flexran_schedule_ue_spec_remote(mid_t mod_id, uint32_t frame, uint32_t subframe, int *mbsfn_flag, Protocol__FlexranMessage **dl_info); diff --git a/openair2/LAYER2/MAC/flexran_dci_conversions.h b/openair2/LAYER2/MAC/flexran_dci_conversions.h index e9d9494a1a..038290d1b2 100644 --- a/openair2/LAYER2/MAC/flexran_dci_conversions.h +++ b/openair2/LAYER2/MAC/flexran_dci_conversions.h @@ -27,7 +27,7 @@ *******************************************************************************/ -/*! \file dci_conversions.h +/*! \file flexran_dci_conversions.h * \brief Conversion helpers from flexran messages to OAI formats DCI * \author Xenofon Foukas * \date 2016 diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 2b075a7ed3..3f8e7c5f83 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -93,7 +93,7 @@ #include "SIMULATION/TOOLS/defs.h" // for taus -#include "enb_agent_extern.h" +#include "flexran_agent_extern.h" #define XER_PRINT #ifdef PHY_EMUL @@ -4543,7 +4543,7 @@ rrc_eNB_decode_dcch( //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]->enb_agent_notify_ue_state_change(ctxt_pP->module_id, + agent_mac_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); } @@ -4644,7 +4644,7 @@ rrc_eNB_decode_dcch( PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); //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]->enb_agent_notify_ue_state_change(ctxt_pP->module_id, + agent_mac_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/LOG/log.c b/openair2/UTIL/LOG/log.c index 0a5b0a8ccd..49f00325f8 100644 --- a/openair2/UTIL/LOG/log.c +++ b/openair2/UTIL/LOG/log.c @@ -325,13 +325,13 @@ int logInit (void) g_log->log_component[ENB_APP].filelog = 0; g_log->log_component[ENB_APP].filelog_name = ""; - g_log->log_component[ENB_AGENT].name = "ENB_AGENT"; - g_log->log_component[ENB_AGENT].level = LOG_DEBUG; - g_log->log_component[ENB_AGENT].flag = LOG_MED; - g_log->log_component[ENB_AGENT].interval = 1; - g_log->log_component[ENB_AGENT].fd = 0; - g_log->log_component[ENB_AGENT].filelog = 0; - g_log->log_component[ENB_AGENT].filelog_name = ""; + g_log->log_component[FLEXRAN_AGENT].name = "FLEXRAN_AGENT"; + g_log->log_component[FLEXRAN_AGENT].level = LOG_DEBUG; + g_log->log_component[FLEXRAN_AGENT].flag = LOG_MED; + g_log->log_component[FLEXRAN_AGENT].interval = 1; + g_log->log_component[FLEXRAN_AGENT].fd = 0; + g_log->log_component[FLEXRAN_AGENT].filelog = 0; + g_log->log_component[FLEXRAN_AGENT].filelog_name = ""; g_log->log_component[TMR].name = "TMR"; g_log->log_component[TMR].level = LOG_EMERG; diff --git a/openair2/UTIL/LOG/log.h b/openair2/UTIL/LOG/log.h index 442fbd749e..6a6569c1a5 100644 --- a/openair2/UTIL/LOG/log.h +++ b/openair2/UTIL/LOG/log.h @@ -270,7 +270,7 @@ typedef enum { RAL_ENB, RAL_UE, ENB_APP, - ENB_AGENT, + FLEXRAN_AGENT, TMR, USIM, LOCALIZE, diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.flexran.50PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.flexran.50PRB.usrpb210.conf new file mode 100644 index 0000000000..2e39b934e4 --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.flexran.50PRB.usrpb210.conf @@ -0,0 +1,182 @@ +Active_eNBs = ( "eNB_Eurecom_LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB_Eurecom_LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = "1"; + + mobile_country_code = "208"; + + mobile_network_code = "95"; + + ////////// Physical parameters: + + component_carriers = ( + { + node_function = "eNodeB_3GPP"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 5; + downlink_frequency = 879000000L; + uplink_frequency_offset = -45000000; + Nid_cell = 0; + N_RB_DL = 50; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 1; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 115; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = -26; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -90; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -108; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + + ue_TransmissionMode = 1; + } + ); + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.100.101"; + ipv6 = "192:168:100::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.106/24"; + + ENB_INTERFACE_NAME_FOR_S1U = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.106/24"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + NETWORK_CONTROLLER : + { + FLEXRAN_AGENT_INTERFACE_NAME = "eth1"; + FLEXRAN_AGENT_IPV4_ADDRESS = "10.0.2.5/30"; + FLEXRAN_AGENT_PORT = 2210; + FLEXRAN_AGENT_CACHE = "/mnt/oai_agent_cache"; + }; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + } +); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.flexran.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.flexran.usrpb210.conf new file mode 100644 index 0000000000..66e7ef433d --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.flexran.usrpb210.conf @@ -0,0 +1,182 @@ +Active_eNBs = ( "eNB_Eurecom_LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB_Eurecom_LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = "1"; + + mobile_country_code = "208"; + + mobile_network_code = "95"; + + ////////// Physical parameters: + + component_carriers = ( + { + node_function = "eNodeB_3GPP"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 5; + downlink_frequency = 879000000L; + uplink_frequency_offset = -45000000; + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 1; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 115; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = -26; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -90; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -108; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -108; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + + ue_TransmissionMode = 1; + } + ); + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.100.101"; + ipv6 = "192:168:100::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.106/24"; + + ENB_INTERFACE_NAME_FOR_S1U = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.106/24"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + NETWORK_CONTROLLER : + { + FLEXRAN_AGENT_INTERFACE_NAME = "eth1"; + FLEXRAN_AGENT_IPV4_ADDRESS = "10.0.2.5/30"; + FLEXRAN_AGENT_PORT = 2210; + FLEXRAN_AGENT_CACHE = "/mnt/oai_agent_cache"; + }; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + } +); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.50PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.50PRB.usrpb210.conf index f73a78b3b0..7e68b5d84b 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.50PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.50PRB.usrpb210.conf @@ -155,10 +155,10 @@ eNBs = NETWORK_CONTROLLER : { - ENB_AGENT_INTERFACE_NAME = "eth1"; - ENB_AGENT_IPV4_ADDRESS = "10.0.2.5/30"; - ENB_AGENT_PORT = 2210; - ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; + FLEXRAN_AGENT_INTERFACE_NAME = "eth1"; + FLEXRAN_AGENT_IPV4_ADDRESS = "10.0.2.5/30"; + FLEXRAN_AGENT_PORT = 2210; + FLEXRAN_AGENT_CACHE = "/mnt/oai_agent_cache"; }; log_config : diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.usrpb210.conf index e5bd9455e3..4ee429f45e 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.flexran.usrpb210.conf @@ -155,10 +155,10 @@ eNBs = NETWORK_CONTROLLER : { - ENB_AGENT_INTERFACE_NAME = "eth1"; - ENB_AGENT_IPV4_ADDRESS = "10.0.2.5/30"; - ENB_AGENT_PORT = 2210; - ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; + FLEXRAN_AGENT_INTERFACE_NAME = "eth1"; + FLEXRAN_AGENT_IPV4_ADDRESS = "10.0.2.5/30"; + FLEXRAN_AGENT_PORT = 2210; + FLEXRAN_AGENT_CACHE = "/mnt/oai_agent_cache"; }; log_config : diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index 438f1f9efd..9253c2c50d 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -75,8 +75,8 @@ uint8_t config_smbv = 0; char smbv_ip[16]; #endif -#if defined(ENB_AGENT_SB_IF) -# include "enb_agent.h" +#if defined(FLEXRAN_AGENT_SB_IF) +# include "flexran_agent.h" #endif @@ -1301,8 +1301,8 @@ main (int argc, char **argv) smbv_write_config_from_frame_parms(smbv_fname, &PHY_vars_eNB_g[0][0]->frame_parms); #endif - /* #if defined (ENB_AGENT_SB_IF) - enb_agent_start(); + /* #if defined (FLEXRAN_AGENT_SB_IF) + flexran_agent_start(); #endif */ // add events to future event list: Currently not used From 92ef1739b1526c1af72b54198089b468b4ad99b8 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 4 Nov 2016 17:36:45 +0200 Subject: [PATCH 269/413] Restructured FlexRAN agent file hierarchy --- cmake_targets/CMakeLists.txt | 5 +++-- openair1/SCHED/phy_procedures_lte_eNb.c | 2 +- .../ENB_APP/{ => CONTROL_MODULES/MAC}/flexran_agent_mac.c | 0 .../ENB_APP/{ => CONTROL_MODULES/MAC}/flexran_agent_mac.h | 0 .../{ => CONTROL_MODULES/MAC}/flexran_agent_mac_defs.h | 0 .../{ => CONTROL_MODULES/MAC}/flexran_agent_mac_internal.c | 0 .../{ => CONTROL_MODULES/MAC}/flexran_agent_mac_internal.h | 0 7 files changed, 4 insertions(+), 3 deletions(-) rename openair2/ENB_APP/{ => CONTROL_MODULES/MAC}/flexran_agent_mac.c (100%) rename openair2/ENB_APP/{ => CONTROL_MODULES/MAC}/flexran_agent_mac.h (100%) rename openair2/ENB_APP/{ => CONTROL_MODULES/MAC}/flexran_agent_mac_defs.h (100%) rename openair2/ENB_APP/{ => CONTROL_MODULES/MAC}/flexran_agent_mac_internal.c (100%) rename openair2/ENB_APP/{ => CONTROL_MODULES/MAC}/flexran_agent_mac_internal.h (100%) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 8f696ed653..da90efdaee 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -817,6 +817,7 @@ include_directories("${OPENAIR_DIR}/targets/ARCH/COMMON") 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}/UTIL/OSA") include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds6.1.1/liblfds611/inc") include_directories("${OPENAIR2_DIR}/UTIL/LFDS/liblfds7.0.0/liblfds700/inc") @@ -903,12 +904,12 @@ if (FLEXRAN_AGENT_SB_IF) ${OPENAIR2_DIR}/ENB_APP/flexran_agent_handler.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_common.c ${OPENAIR2_DIR}/ENB_APP/flexran_agent_common_internal.c - ${OPENAIR2_DIR}/ENB_APP/flexran_agent_mac.c + ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.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 ${OPENAIR2_DIR}/ENB_APP/flexran_agent_async.c - ${OPENAIR2_DIR}/ENB_APP/flexran_agent_mac_internal.c + ${OPENAIR2_DIR}/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c ) set(FLEXRAN_AGENT_LIB FLEXRAN_AGENT) #include_directories(${OPENAIR2_DIR}/ENB_APP) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index b5fd7efd70..d6f5a40da7 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -64,7 +64,7 @@ //Agent-related headers #include "ENB_APP/flexran_agent_extern.h" -#include "ENB_APP/flexran_agent_mac.h" +#include "ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h" #include "LAYER2/MAC/flexran_agent_mac_proto.h" //#define DIAG_PHY diff --git a/openair2/ENB_APP/flexran_agent_mac.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c similarity index 100% rename from openair2/ENB_APP/flexran_agent_mac.c rename to openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c diff --git a/openair2/ENB_APP/flexran_agent_mac.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h similarity index 100% rename from openair2/ENB_APP/flexran_agent_mac.h rename to openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h diff --git a/openair2/ENB_APP/flexran_agent_mac_defs.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h similarity index 100% rename from openair2/ENB_APP/flexran_agent_mac_defs.h rename to openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_defs.h diff --git a/openair2/ENB_APP/flexran_agent_mac_internal.c b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c similarity index 100% rename from openair2/ENB_APP/flexran_agent_mac_internal.c rename to openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.c diff --git a/openair2/ENB_APP/flexran_agent_mac_internal.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h similarity index 100% rename from openair2/ENB_APP/flexran_agent_mac_internal.h rename to openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h From 5864cc08cdad829039bb80465fe27603ba092626 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Fri, 4 Nov 2016 17:49:39 +0200 Subject: [PATCH 270/413] Integrated scheduler to overall FlexRAN agent functionality --- openair2/LAYER2/MAC/eNB_scheduler.c | 56 ++++++++++++++--------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index d24ac7c5d9..386efec596 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -63,7 +63,7 @@ #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 -#define ENABLE_ENB_AGENT_DL_SCHEDULER +//efine ENABLE_ENB_AGENT_DL_SCHEDULER //#define DISABLE_SF_TRIGGER //#define DISABLE_CONT_STATS @@ -387,7 +387,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, (mac_xface->frame_parms->tdd_config == 6)) { //schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,4);//,calibration_flag); } -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -418,14 +418,14 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 0: case 1: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,7); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #endif break; case 6: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,8); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #endif break; @@ -435,7 +435,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD schedule_ulsch(module_idP,frameP,cooperation_flag,1,5); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -465,7 +465,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // FDD, normal UL/DLSCH if (mac_xface->frame_parms->frame_type == FDD) { //FDD schedule_ulsch(module_idP,frameP,cooperation_flag,2,6); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -501,7 +501,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // no break here! case 5: -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -529,7 +529,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } else { //FDD schedule_ulsch(module_idP,frameP,cooperation_flag,3,7); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -572,7 +572,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // no break here! case 5: -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -601,7 +601,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, if (mac_xface->frame_parms->frame_type == FDD) { //FDD schedule_ulsch(module_idP, frameP, cooperation_flag, 4, 8); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP, frameP, subframeP, mbsfn_status); fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_status); #else @@ -637,7 +637,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, if (mac_xface->frame_parms->frame_type == FDD) { schedule_RA(module_idP,frameP,subframeP,1); schedule_ulsch(module_idP,frameP,cooperation_flag,5,9); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP, frameP, subframeP, mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -660,11 +660,11 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } else if ((mac_xface->frame_parms->tdd_config == 0) || // TDD Config 0 (mac_xface->frame_parms->tdd_config == 6)) { // TDD Config 6 //schedule_ulsch(module_idP,cooperation_flag,subframeP); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #endif } else { -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -701,7 +701,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 1: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,2); // schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #endif break; @@ -709,14 +709,14 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 6: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3); // schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #endif break; case 5: schedule_RA(module_idP,frameP,subframeP,2); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -740,7 +740,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 3: case 4: -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -767,7 +767,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD schedule_ulsch(module_idP,frameP,cooperation_flag,6,0); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -800,7 +800,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 3: case 4: schedule_RA(module_idP,frameP,subframeP,3); // 3 = Msg3 subframeP, not -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -823,7 +823,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; case 5: -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -850,7 +850,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD schedule_ulsch(module_idP,frameP,cooperation_flag,7,1); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -888,7 +888,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // schedule_RA(module_idP,subframeP); schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,2); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -915,7 +915,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD schedule_ulsch(module_idP,frameP,cooperation_flag,8,2); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -947,7 +947,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 1: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3); schedule_RA(module_idP,frameP,subframeP,7); // 7 = Msg3 subframeP, not -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -972,7 +972,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 3: case 4: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -997,7 +997,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 6: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,4); //schedule_RA(module_idP,frameP,subframeP); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -1022,7 +1022,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 2: case 5: //schedule_RA(module_idP,frameP,subframeP); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else @@ -1049,7 +1049,7 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD schedule_ulsch(module_idP,frameP,cooperation_flag,9,3); -#ifndef ENABLE_ENB_AGENT_DL_SCHEDULER +#ifndef FLEXRAN_AGENT_SB_IF schedule_ue_spec(module_idP,frameP,subframeP,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_status); #else From 83929d42f2a38f96d7f2f1af544fd982c410d5e9 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Sat, 5 Nov 2016 14:09:48 +0200 Subject: [PATCH 271/413] Refactored local FlexRAN scheduler to make further use of FlexRAN API --- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 2 +- openair2/ENB_APP/flexran_agent_common.c | 172 ++-- openair2/ENB_APP/flexran_agent_common.h | 15 +- .../MAC/flexran_agent_scheduler_dlsch_ue.c | 765 ++++++++++++++++-- 4 files changed, 819 insertions(+), 135 deletions(-) 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 c85ec6c4eb..34b6ef345f 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -995,7 +995,7 @@ int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__Fle // TODO: This should be different per TB if(harq_status == 0) dl_info[i]->harq_status[j] = PROTOCOL__FLEX_HARQ_STATUS__FLHS_ACK; - else if (harq_status == 1) + else if (harq_status > 0) dl_info[i]->harq_status[j] = PROTOCOL__FLEX_HARQ_STATUS__FLHS_NACK; } /*Fill in the serving cell index for this UE */ diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index 302c792771..00f938f4fb 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -569,46 +569,73 @@ int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t chann return rlc_status.bytes_in_buffer; } -int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id,int CC_id) -{ - 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; - } +int 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]; + int rnti; - int32_t time_advance; - switch (PHY_vars_eNB_g[mod_id][CC_id]->frame_parms.N_RB_DL) { - case 6: - time_advance = eNB_UE_stats->timing_advance_update; - break; + rnti = flexran_get_ue_crnti(mod_id, ue_id); + if (ue_sched_ctl->ta_timer == 0) { - case 15: - time_advance = eNB_UE_stats->timing_advance_update/2; - break; + // 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 + switch (PHY_vars_eNB_g[mod_id][CC_id]->frame_parms.N_RB_DL) { + case 6: + ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update; + break; - case 25: - time_advance = eNB_UE_stats->timing_advance_update/4; - break; + case 15: + ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/2; + break; - case 50: - time_advance = eNB_UE_stats->timing_advance_update/8; - break; + case 25: + ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/4; + break; - case 75: - time_advance = eNB_UE_stats->timing_advance_update/12; - break; + case 50: + ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/8; + break; - case 100: - time_advance = eNB_UE_stats->timing_advance_update/16; - break; - } + case 75: + ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/12; + break; + + case 100: + ue_sched_ctl->ta_update = eNB_UE_stats->timing_advance_update/16; + break; + } + // 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 + } + + return ue_sched_ctl->ta_update = 0; + +} + +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; + UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[ue_id]; + + 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 (ue_sched_ctl->ta_update == 0) { + return 1; + } else { + return 0; + } - if(time_advance > 0) - return 1; - else - return 0; } int flexran_get_active_CC(mid_t mod_id, mid_t ue_id) { @@ -616,12 +643,12 @@ int flexran_get_active_CC(mid_t mod_id, mid_t 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; + LTE_eNB_UE_stats *eNB_UE_stats = NULL; - int pCCid = UE_PCCID(mod_id,ue_id); - rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); + 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,CC_id,rnti); + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti); if (eNB_UE_stats == NULL) { return 0; @@ -631,14 +658,14 @@ int flexran_get_current_RI(mid_t mod_id, mid_t ue_id, int CC_id) { } 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; + 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); + 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); + 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); @@ -651,36 +678,38 @@ int flexran_get_tpc(mid_t mod_id, mid_t ue_id) { } if (normalized_rx_power>(target_rx_power+1)) { - tpc = 0; //-1 + tpc = 0; //-1 } else if (normalized_rx_power<(target_rx_power-1)) { - tpc = 2; //+1 + tpc = 2; //+1 } else { - tpc = 1; //0 + 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, int *id, int *status) { //flag_id_status = 0 then id, else status +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, int *id, int *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 round; + 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,&round,openair_harq_DL); + mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&harq_round,openair_harq_DL); *id = harq_pid; - if (round > 0) { - *status = 1; - } else { - *status = 0; - } + *round = harq_round; + /* if (round > 0) { */ + /* *status = 1; */ + /* } else { */ + /* *status = 0; */ + /* } */ - return 0; + /* return 0; */ + return round; } int flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, int CC_id) { @@ -705,6 +734,24 @@ int flexran_get_p0_nominal_pucch(mid_t mod_id, int 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; +} + /* * ************************************ @@ -861,6 +908,13 @@ int flexran_get_N_RB_UL(mid_t mod_id, int 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; @@ -891,10 +945,10 @@ 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 == 0) - return 1; - else if (frame_parms->frame_type == 1) - return 0; + 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; } diff --git a/openair2/ENB_APP/flexran_agent_common.h b/openair2/ENB_APP/flexran_agent_common.h index 2156d50a0d..caa2eeb900 100644 --- a/openair2/ENB_APP/flexran_agent_common.h +++ b/openair2/ENB_APP/flexran_agent_common.h @@ -193,6 +193,9 @@ 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); +/* Update the timing advance status (find out whether a timing advance command is required) */ +int 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); @@ -245,6 +248,9 @@ 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); @@ -273,13 +279,18 @@ int flexran_get_tpc(mid_t mod_id, mid_t ue_id); 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, int *id, int *status); + const int frame, const uint8_t subframe, int *id, int *round); -/* Reported values for uplink power control */ +/* 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 diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index cf033959d3..73d82507a5 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -29,7 +29,7 @@ /*! \file flexran_agent_scheduler_dlsch_ue.c * \brief procedures related to eNB for the DLSCH transport channel - * \author Xenofon Foukas + * \author Xenofon Foukas, Navid Nikaein and Raymond Knopp * \date 2016 * \email: x.foukas@sms.ed.ac.uk * \version 0.1 @@ -59,7 +59,6 @@ #include "ENB_APP/flexran_agent_defs.h" -//#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" #include "header.pb-c.h" @@ -74,6 +73,7 @@ #define ENABLE_MAC_PAYLOAD_DEBUG + //------------------------------------------------------------------------------ void flexran_schedule_ue_spec_default(mid_t mod_id, @@ -88,22 +88,20 @@ flexran_schedule_ue_spec_default(mid_t mod_id, 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, header_len_dtch=0, header_len_dtch_tmp=0, ta_len=0; - unsigned char header_len = 0, header_len_tmp = 0; + unsigned char header_len = 0, header_len_tmp = 0, ta_len = 0; uint16_t nb_rb, nb_rb_temp, total_nb_available_rb[MAX_NUM_CCs], nb_available_rb; uint16_t TBS, j, rnti, padding=0, post_padding=0; unsigned char round = 0; unsigned char harq_pid = 0; void *DLSCH_dci = NULL; - LTE_eNB_UE_stats *eNB_UE_stats = NULL; uint16_t sdu_length_total = 0; int mcs, mcs_tmp; uint16_t min_rb_unit[MAX_NUM_CCs]; eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; + /* TODO: Must move the helper structs to scheduler implementation */ UE_list_t *UE_list = &eNB->UE_list; - LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; int32_t normalized_rx_power, target_rx_power; - int32_t tpc=1; + int32_t tpc = 1; static int32_t tpc_accumulated=0; UE_sched_ctrl *ue_sched_ctl; @@ -139,14 +137,13 @@ flexran_schedule_ue_spec_default(mid_t mod_id, for (CC_id=0; CC_idget_lte_frame_parms(mod_id, CC_id); // get number of PRBs less those used by common channels - 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] = flexran_get_N_RB_DL(mod_id, CC_id); + for (i=0;i < flexran_get_N_RB_DL(mod_id, CC_id); i++) + if (eNB->common_channels[CC_id].vrb_map[i] != 0) total_nb_available_rb[CC_id]--; - N_RBG[CC_id] = frame_parms[CC_id]->N_RBG; + N_RBG[CC_id] = flexran_get_N_RBG(mod_id, CC_id); // store the global enb stats: eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs; @@ -159,7 +156,7 @@ flexran_schedule_ue_spec_default(mid_t mod_id, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,VCD_FUNCTION_IN); start_meas(&eNB->schedule_dlsch_preprocessor); - dlsch_scheduler_pre_processor(mod_id, + _dlsch_scheduler_pre_processor(mod_id, frame, subframe, N_RBG, @@ -174,25 +171,23 @@ flexran_schedule_ue_spec_default(mid_t mod_id, continue; for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { - rnti = UE_RNTI(mod_id, UE_id); - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + rnti = flexran_get_ue_crnti(mod_id, UE_id); ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; if (rnti==NOT_A_RNTI) { - LOG_D(MAC,"Cannot find rnti for UE_id %d (num_UEs %d)\n",UE_id,UE_list->num_UEs); + LOG_D(MAC,"Cannot find rnti for UE_id %d (num_UEs %d)\n", UE_id,UE_list->num_UEs); // mac_xface->macphy_exit("Cannot find rnti for UE_id"); continue; } - if (eNB_UE_stats==NULL) { - LOG_D(MAC,"[eNB] Cannot find eNB_UE_stats\n"); + if (flexran_get_ue_crnti(mod_id, UE_id) == NOT_A_RNTI) { + LOG_D(MAC,"[eNB] Cannot find UE\n"); // mac_xface->macphy_exit("[MAC][eNB] Cannot find eNB_UE_stats\n"); continue; } if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated - CCE_allocation_infeasible(mod_id, CC_id, 0, subframe, aggregation, rnti) - ) { + CCE_allocation_infeasible(mod_id, CC_id, 0, subframe, aggregation, rnti)) { LOG_D(MAC,"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", mod_id, frame, UE_id, CC_id); //if(mac_xface->get_transmission_mode(module_idP,rnti)==5) @@ -201,14 +196,14 @@ flexran_schedule_ue_spec_default(mid_t mod_id, // break; } - if (frame_parms[CC_id]->frame_type == TDD) { + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { set_ue_dai (subframe, - frame_parms[CC_id]->tdd_config, + flexran_get_subframe_assignment(mod_id, CC_id), UE_id, CC_id, UE_list); - // update UL DAI after DLSCH scheduling - set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe,frame_parms); + //TODO: update UL DAI after DLSCH scheduling + //set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe,frame_parms); } channels_added = 0; @@ -223,38 +218,29 @@ flexran_schedule_ue_spec_default(mid_t mod_id, dl_data[num_ues_added]->serv_cell_index = CC_id; nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; - harq_pid = ue_sched_ctl->harq_pid[CC_id]; - round = ue_sched_ctl->round[CC_id]; - + flexran_get_harq(mod_id, CC_id, UE_id, frame, subframe, &harq_pid, &round); sdu_length_total=0; - - /* - DevCheck(((eNB_UE_stats->DL_cqi[0] < MIN_CQI_VALUE) || (eNB_UE_stats->DL_cqi[0] > MAX_CQI_VALUE)), - eNB_UE_stats->DL_cqi[0], MIN_CQI_VALUE, MAX_CQI_VALUE); - */ - - mcs = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; - // mcs = cmin(mcs, openair_daq_vars.target_ue_dl_mcs); + mcs = cqi_to_mcs[flexran_get_ue_wcqi(mod_id, UE_id)]; #ifdef EXMIMO if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti) == 5) { - mcs = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; + mcs = cqi_to_mcs[flexran_get_ue_wcqi(mod_id, UE_id)]; mcs = cmin(mcs,16); } #endif // initializing the rb allocation indicator for each UE - for(j = 0; j < frame_parms[CC_id]->N_RBG; j++) { + for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0; rballoc_sub[j] = 0; } - 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", - mod_id, frame, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb, - eNB_UE_stats->DL_cqi[0], mcs, - UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); + /* 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", */ + /* mod_id, frame, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb, */ + /* eNB_UE_stats->DL_cqi[0], mcs, */ + /* UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); */ dl_dci = (Protocol__FlexDlDci*) malloc(sizeof(Protocol__FlexDlDci)); protocol__flex_dl_dci__init(dl_dci); @@ -270,7 +256,7 @@ flexran_schedule_ue_spec_default(mid_t mod_id, if (round > 0) { - if (frame_parms[CC_id]->frame_type == TDD) { + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { UE_list->UE_template[CC_id][UE_id].DAI++; update_ul_dci(mod_id, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); LOG_D(MAC,"DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", @@ -282,25 +268,26 @@ flexran_schedule_ue_spec_default(mid_t mod_id, // get freq_allocation nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + /*TODO: Must add this to FlexRAN agent API */ dci_tbs = mac_xface->get_TBS_DL(mcs, nb_rb); if (nb_rb <= nb_available_rb) { if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { - for(j = 0; j < frame_parms[CC_id]->N_RBG; j++) { // for indicating the rballoc for each sub-band + for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { // for indicating the rballoc for each sub-band UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; } } else { nb_rb_temp = nb_rb; j = 0; - while((nb_rb_temp > 0) && (j < frame_parms[CC_id]->N_RBG)) { + while((nb_rb_temp > 0) && (j < flexran_get_N_RBG(mod_id, CC_id))) { if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - if((j == frame_parms[CC_id]->N_RBG-1) && - ((frame_parms[CC_id]->N_RB_DL == 25)|| - (frame_parms[CC_id]->N_RB_DL == 50))) { + if((j == flexran_get_N_RBG(mod_id, CC_id) - 1) && + ((flexran_get_N_RB_DL(mod_id, CC_id) == 25)|| + (flexran_get_N_RB_DL(mod_id, CC_id) == 50))) { nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]+1; } else { nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; @@ -316,7 +303,7 @@ flexran_schedule_ue_spec_default(mid_t mod_id, PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; - for(j=0; jN_RBG; j++) { + for(j=0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; } @@ -360,8 +347,6 @@ flexran_schedule_ue_spec_default(mid_t mod_id, dl_data[num_ues_added]->ce_bitmap[0] = ce_flags; dl_data[num_ues_added]->ce_bitmap[1] = ce_flags; - header_len_dcch = 2; // 2 bytes DCCH SDU subheader - // TODO : Need to prioritize DRBs // Loop through the UE logical channels (DCCH, DCCH1, DTCH for now) for (j = 1; j < NB_RB_MAX; j++) { @@ -467,20 +452,20 @@ flexran_schedule_ue_spec_default(mid_t mod_id, if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { LOG_D(MAC, "[TEST]We had the exact number of rbs. Time to fill the rballoc subband\n"); - for(j = 0; j < frame_parms[CC_id]->N_RBG; j++) { // for indicating the rballoc for each sub-band + for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { // for indicating the rballoc for each sub-band UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; } } else { nb_rb_temp = nb_rb; j = 0; LOG_D(MAC, "[TEST]Will only partially fill the bitmap\n"); - while((nb_rb_temp > 0) && (j < frame_parms[CC_id]->N_RBG)) { + while((nb_rb_temp > 0) && (j < flexran_get_N_RBG(mod_id, CC_id))) { if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; - if ((j == frame_parms[CC_id]->N_RBG-1) && - ((frame_parms[CC_id]->N_RB_DL == 25)|| - (frame_parms[CC_id]->N_RB_DL == 50))) { - nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]+1; + if ((j == flexran_get_N_RBG(mod_id, CC_id) - 1) && + ((flexran_get_N_RB_DL(mod_id, CC_id) == 25)|| + (flexran_get_N_RB_DL(mod_id, CC_id) == 50))) { + nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id] + 1; } else { nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; } @@ -492,7 +477,7 @@ flexran_schedule_ue_spec_default(mid_t mod_id, PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; - for(j = 0; j < frame_parms[CC_id]->N_RBG; j++) { + for(j = 0; j < flexran_get_N_RBG(mod_id, CC_id); j++) { PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; } @@ -518,7 +503,7 @@ flexran_schedule_ue_spec_default(mid_t mod_id, UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; - if (frame_parms[CC_id]->frame_type == TDD) { + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { UE_list->UE_template[CC_id][UE_id].DAI++; // printf("DAI update: subframeP %d: UE %d, DAI %d\n",subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); //#warning only for 5MHz channel @@ -527,9 +512,8 @@ flexran_schedule_ue_spec_default(mid_t mod_id, // do PUCCH power control // this is the normalized RX power - eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); - normalized_rx_power = eNB_UE_stats->Po_PUCCH_dBm; - target_rx_power = mac_xface->get_target_pucch_rx_power(mod_id, CC_id) + 10; + normalized_rx_power = flexran_get_p0_pucch_dbm(mod_id,UE_id, CC_id); //eNB_UE_stats->Po_PUCCH_dBm; + target_rx_power = flexran_get_p0_nominal_pucch(mod_id, CC_id) + 10; //mac_xface->get_target_pucch_rx_power(mod_id, CC_id) + 10; // this assumes accumulated tpc // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out @@ -537,11 +521,11 @@ flexran_schedule_ue_spec_default(mid_t mod_id, if (((framex10psubframe+10)<=(frame*10+subframe)) || //normal case ((framex10psubframe>(frame*10+subframe)) && (((10240-framex10psubframe+frame*10+subframe)>=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=frame; - UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe=subframe; + if (flexran_get_p0_pucch_status(mod_id, UE_id, CC_id) == 1) { + flexran_update_p0_pucch(mod_id, UE_id, CC_id); + + UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame = frame; + UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe = subframe; if (normalized_rx_power>(target_rx_power+1)) { tpc = 0; //-1 tpc_accumulated--; @@ -614,7 +598,7 @@ flexran_schedule_ue_spec_default(mid_t mod_id, dl_dci->n_tbs_size = 1; dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); dl_dci->tbs_size[0] = dci_tbs; - if (frame_parms[CC_id]->frame_type == TDD) { + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; } @@ -648,7 +632,7 @@ flexran_schedule_ue_spec_default(mid_t mod_id, dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); dl_dci->tbs_size[0] = dci_tbs; dl_dci->tbs_size[1] = dci_tbs; - if (frame_parms[CC_id]->frame_type == TDD) { + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; } @@ -682,7 +666,7 @@ flexran_schedule_ue_spec_default(mid_t mod_id, dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); dl_dci->tbs_size[0] = dci_tbs; dl_dci->tbs_size[1] = dci_tbs; - if (frame_parms[CC_id]->frame_type == TDD) { + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; } @@ -712,7 +696,7 @@ flexran_schedule_ue_spec_default(mid_t mod_id, dl_dci->n_tbs_size = 1; dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size); dl_dci->tbs_size[0] = dci_tbs; - if (frame_parms[CC_id]->frame_type == TDD) { + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; } @@ -749,7 +733,7 @@ flexran_schedule_ue_spec_default(mid_t mod_id, dl_dci->n_mcs = 1; dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); dl_dci->mcs[0] = mcs; - if (frame_parms[CC_id]->frame_type == TDD) { + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { dl_dci->has_dai = 1; dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; } @@ -762,8 +746,10 @@ flexran_schedule_ue_spec_default(mid_t mod_id, } } - if (frame_parms[CC_id]->frame_type == TDD) { - set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe, frame_parms); + if (flexran_get_duplex_mode(mod_id, CC_id) == PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD) { + + /* TODO */ + //set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe, frame_parms); } } // UE_id loop } // CC_id loop @@ -778,3 +764,636 @@ flexran_schedule_ue_spec_default(mid_t mod_id, stop_meas(&eNB->schedule_dlsch); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_OUT); } + +// This function stores the downlink buffer for all the logical channels +void _store_dlsch_buffer (module_id_t Mod_id, + frame_t frameP, + sub_frame_t subframeP) +{ + + int UE_id,i; + rnti_t rnti; + mac_rlc_status_resp_t rlc_status; + UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; + UE_TEMPLATE *UE_template; + + for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { + + UE_template = &UE_list->UE_template[UE_PCCID(Mod_id,UE_id)][UE_id]; + + // clear logical channel interface variables + UE_template->dl_buffer_total = 0; + UE_template->dl_pdus_total = 0; + + for(i=0; i< MAX_NUM_LCID; i++) { + UE_template->dl_buffer_info[i]=0; + UE_template->dl_pdus_in_buffer[i]=0; + UE_template->dl_buffer_head_sdu_creation_time[i]=0; + UE_template->dl_buffer_head_sdu_remaining_size_to_send[i]=0; + } + + rnti = UE_RNTI(Mod_id,UE_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 ); + 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 ; + UE_template->dl_buffer_head_sdu_creation_time_max = cmax(UE_template->dl_buffer_head_sdu_creation_time_max, + rlc_status.head_sdu_creation_time ); + UE_template->dl_buffer_head_sdu_remaining_size_to_send[i] = rlc_status.head_sdu_remaining_size_to_send; + UE_template->dl_buffer_head_sdu_is_segmented[i] = rlc_status.head_sdu_is_segmented; + UE_template->dl_buffer_total += UE_template->dl_buffer_info[i];//storing the total dlsch buffer + UE_template->dl_pdus_total += UE_template->dl_pdus_in_buffer[i]; + +#ifdef DEBUG_eNB_SCHEDULER + + /* note for dl_buffer_head_sdu_remaining_size_to_send[i] : + * 0 if head SDU has not been segmented (yet), else remaining size not already segmented and sent + */ + if (UE_template->dl_buffer_info[i]>0) + LOG_D(MAC, + "[eNB %d] Frame %d Subframe %d : RLC status for UE %d in LCID%d: total of %d pdus and size %d, head sdu queuing time %d, remaining size %d, is segmeneted %d \n", + Mod_id, frameP, subframeP, UE_id, + i, UE_template->dl_pdus_in_buffer[i],UE_template->dl_buffer_info[i], + UE_template->dl_buffer_head_sdu_creation_time[i], + UE_template->dl_buffer_head_sdu_remaining_size_to_send[i], + UE_template->dl_buffer_head_sdu_is_segmented[i] + ); + +#endif + + } + + //#ifdef DEBUG_eNB_SCHEDULER + if ( UE_template->dl_buffer_total>0) + LOG_D(MAC,"[eNB %d] Frame %d Subframe %d : RLC status for UE %d : total DL buffer size %d and total number of pdu %d \n", + Mod_id, frameP, subframeP, UE_id, + UE_template->dl_buffer_total, + UE_template->dl_pdus_total + ); + + //#endif + } +} + + +// This function returns the estimated number of RBs required by each UE for downlink scheduling +void _assign_rbs_required (module_id_t Mod_id, + frame_t frameP, + sub_frame_t subframe, + uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], + int min_rb_unit[MAX_NUM_CCs]) +{ + + + rnti_t rnti; + uint16_t TBS = 0; + LTE_eNB_UE_stats *eNB_UE_stats[MAX_NUM_CCs]; + int UE_id,n,i,j,CC_id,pCCid,tmp; + UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; + // UE_TEMPLATE *UE_template; + + // clear rb allocations across all CC_ids + for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { + pCCid = UE_PCCID(Mod_id,UE_id); + rnti = UE_list->UE_template[pCCid][UE_id].rnti; + + //update CQI information across component carriers + for (n=0; nnumactiveCCs[UE_id]; n++) { + CC_id = UE_list->ordered_CCids[n][UE_id]; + eNB_UE_stats[CC_id] = mac_xface->get_eNB_UE_stats(Mod_id,CC_id,rnti); + eNB_UE_stats[CC_id]->dlsch_mcs1=cqi_to_mcs[flexran_get_ue_wcqi(Mod_id, UE_id)]; + } + + // provide the list of CCs sorted according to MCS + for (i=0; inumactiveCCs[UE_id]; i++) { + for (j=i+1; jnumactiveCCs[UE_id]; j++) { + DevAssert( j < MAX_NUM_CCs ); + + if (eNB_UE_stats[UE_list->ordered_CCids[i][UE_id]]->dlsch_mcs1 > + eNB_UE_stats[UE_list->ordered_CCids[j][UE_id]]->dlsch_mcs1) { + tmp = UE_list->ordered_CCids[i][UE_id]; + UE_list->ordered_CCids[i][UE_id] = UE_list->ordered_CCids[j][UE_id]; + UE_list->ordered_CCids[j][UE_id] = tmp; + } + } + } + + /* NN --> RK + * check the index of UE_template" + */ + if (UE_list->UE_template[pCCid][UE_id].dl_buffer_total> 0) { + LOG_D(MAC,"[preprocessor] assign RB for UE %d\n",UE_id); + + for (i=0; inumactiveCCs[UE_id]; i++) { + CC_id = UE_list->ordered_CCids[i][UE_id]; + eNB_UE_stats[CC_id] = mac_xface->get_eNB_UE_stats(Mod_id,CC_id,rnti); + + if (eNB_UE_stats[CC_id]->dlsch_mcs1==0) { + nb_rbs_required[CC_id][UE_id] = 4; // don't let the TBS get too small + } else { + nb_rbs_required[CC_id][UE_id] = min_rb_unit[CC_id]; + } + + TBS = mac_xface->get_TBS_DL(eNB_UE_stats[CC_id]->dlsch_mcs1,nb_rbs_required[CC_id][UE_id]); + + LOG_D(MAC,"[preprocessor] start RB assignement for UE %d CC_id %d dl buffer %d (RB unit %d, MCS %d, TBS %d) \n", + UE_id, CC_id, UE_list->UE_template[pCCid][UE_id].dl_buffer_total, + nb_rbs_required[CC_id][UE_id],eNB_UE_stats[CC_id]->dlsch_mcs1,TBS); + + /* calculating required number of RBs for each UE */ + while (TBS < UE_list->UE_template[pCCid][UE_id].dl_buffer_total) { + nb_rbs_required[CC_id][UE_id] += min_rb_unit[CC_id]; + + if (nb_rbs_required[CC_id][UE_id] > flexran_get_N_RB_DL(Mod_id, CC_id)) { + TBS = mac_xface->get_TBS_DL(eNB_UE_stats[CC_id]->dlsch_mcs1, flexran_get_N_RB_DL(Mod_id, CC_id)); + nb_rbs_required[CC_id][UE_id] = flexran_get_N_RB_DL(Mod_id, CC_id); + break; + } + + TBS = mac_xface->get_TBS_DL(eNB_UE_stats[CC_id]->dlsch_mcs1,nb_rbs_required[CC_id][UE_id]); + } // end of while + + LOG_D(MAC,"[eNB %d] Frame %d: UE %d on CC %d: RB unit %d, nb_required RB %d (TBS %d, mcs %d)\n", + Mod_id, frameP,UE_id, CC_id, min_rb_unit[CC_id], nb_rbs_required[CC_id][UE_id], TBS, eNB_UE_stats[CC_id]->dlsch_mcs1); + } + } + } +} + +// This function scans all CC_ids for a particular UE to find the maximum round index of its HARQ processes +int _maxround(module_id_t Mod_id,uint16_t rnti,int frame,sub_frame_t subframe,uint8_t ul_flag ) +{ + + uint8_t round,round_max=0,UE_id; + int CC_id; + UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; + + for (CC_id=0; CC_idUE_sched_ctrl[UE_id].round[CC_id]; + if (round > round_max) { + round_max = round; + } + } + + return round_max; +} + +// This function scans all CC_ids for a particular UE to find the maximum DL CQI +int _maxcqi(module_id_t Mod_id,int32_t UE_id) +{ + + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; + int CC_id,n; + int CQI = 0; + + for (n=0; nnumactiveCCs[UE_id]; n++) { + CC_id = UE_list->ordered_CCids[n][UE_id]; + eNB_UE_stats = mac_xface->get_eNB_UE_stats(Mod_id,CC_id,UE_RNTI(Mod_id,UE_id)); + + if (eNB_UE_stats==NULL) { + mac_xface->macphy_exit("maxcqi: could not get eNB_UE_stats\n"); + return 0; // not reached + } + + if (eNB_UE_stats->DL_cqi[0] > CQI) { + CQI = eNB_UE_stats->DL_cqi[0]; + } + } + + return(CQI); +} + + +// This fuction sorts the UE in order their dlsch buffer and CQI +void _sort_UEs (module_id_t Mod_idP, + int frameP, + sub_frame_t subframeP) +{ + + + int UE_id1,UE_id2; + int pCC_id1,pCC_id2; + int cqi1,cqi2,round1,round2; + int i=0,ii=0;//,j=0; + rnti_t rnti1,rnti2; + + UE_list_t *UE_list = &eNB_mac_inst[Mod_idP].UE_list; + + for (i=UE_list->head; i>=0; i=UE_list->next[i]) { + + for(ii=UE_list->next[i]; ii>=0; ii=UE_list->next[ii]) { + + UE_id1 = i; + rnti1 = UE_RNTI(Mod_idP,UE_id1); + if(rnti1 == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[UE_id1].ul_out_of_sync == 1) + continue; + pCC_id1 = UE_PCCID(Mod_idP,UE_id1); + cqi1 = _maxcqi(Mod_idP,UE_id1); // + round1 = _maxround(Mod_idP,rnti1,frameP,subframeP,0); + + UE_id2 = ii; + rnti2 = UE_RNTI(Mod_idP,UE_id2); + if(rnti2 == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[UE_id2].ul_out_of_sync == 1) + continue; + cqi2 = _maxcqi(Mod_idP,UE_id2); + round2 = _maxround(Mod_idP,rnti2,frameP,subframeP,0); //mac_xface->get_ue_active_harq_pid(Mod_id,rnti2,subframe,&harq_pid2,&round2,0); + pCC_id2 = UE_PCCID(Mod_idP,UE_id2); + + if(round2 > round1) { // Check first if one of the UEs has an active HARQ process which needs service and swap order + swap_UEs(UE_list,UE_id1,UE_id2,0); + } else if (round2 == round1) { + // RK->NN : I guess this is for fairness in the scheduling. This doesn't make sense unless all UEs have the same configuration of logical channels. This should be done on the sum of all information that has to be sent. And still it wouldn't ensure fairness. It should be based on throughput seen by each UE or maybe using the head_sdu_creation_time, i.e. swap UEs if one is waiting longer for service. + + // first check the buffer status for SRB1 and SRB2 + if ( (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[1] + UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_info[2]) < + (UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[1] + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_info[2]) ) { + swap_UEs(UE_list,UE_id1,UE_id2,0); + } else if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_head_sdu_creation_time_max < + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_head_sdu_creation_time_max ) { + swap_UEs(UE_list,UE_id1,UE_id2,0); + } else if (UE_list->UE_template[pCC_id1][UE_id1].dl_buffer_total < + UE_list->UE_template[pCC_id2][UE_id2].dl_buffer_total ) { + swap_UEs(UE_list,UE_id1,UE_id2,0); + } else if (cqi1 < cqi2) { + swap_UEs(UE_list,UE_id1,UE_id2,0); + } + } + } + } +} + +// This function assigns pre-available RBS to each UE in specified sub-bands before scheduling is done +void _dlsch_scheduler_pre_processor (module_id_t Mod_id, + frame_t frameP, + sub_frame_t subframeP, + int N_RBG[MAX_NUM_CCs], + int *mbsfn_flag) +{ + + unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], harq_pid=0, total_ue_count; + unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]; + int UE_id, i; + unsigned char round = 0; + uint16_t ii,j; + uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + uint16_t nb_rbs_required_remaining_1[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + uint16_t average_rbs_per_user[MAX_NUM_CCs] = {0}; + rnti_t rnti; + int min_rb_unit[MAX_NUM_CCs]; + uint16_t r1=0; + uint8_t CC_id; + UE_list_t *UE_list = &eNB_mac_inst[Mod_id].UE_list; + LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs] = {0}; + + int transmission_mode = 0; + UE_sched_ctrl *ue_sched_ctl; + + for (CC_id=0; CC_id0) // If this CC is allocated for MBSFN skip it here + continue; + + frame_parms[CC_id] = mac_xface->get_lte_frame_parms(Mod_id,CC_id); + + + min_rb_unit[CC_id]=get_min_rb_unit(Mod_id,CC_id); + + for (i=UE_list->head; i>=0; i=UE_list->next[i]) { + UE_id = i; + // Initialize scheduling information for all active UEs + + + _dlsch_scheduler_pre_processor_reset(Mod_id, + UE_id, + CC_id, + frameP, + subframeP, + N_RBG[CC_id], + nb_rbs_required, + nb_rbs_required_remaining, + rballoc_sub, + MIMO_mode_indicator); + + } + } + + // Store the DLSCH buffer for each logical channel + _store_dlsch_buffer (Mod_id,frameP,subframeP); + + // Calculate the number of RBs required by each UE on the basis of logical channel's buffer + _assign_rbs_required (Mod_id,frameP,subframeP,nb_rbs_required,min_rb_unit); + + // Sorts the user on the basis of dlsch logical channel buffer and CQI + _sort_UEs (Mod_id,frameP,subframeP); + + total_ue_count = 0; + + // loop over all active UEs + for (i=UE_list->head; i>=0; i=UE_list->next[i]) { + rnti = flexran_get_ue_crnti(Mod_id, i); + if(rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[i].ul_out_of_sync == 1) + continue; + UE_id = i; + + // if there is no available harq_process, skip the UE + if (UE_list->UE_sched_ctrl[UE_id].harq_pid[CC_id]<0) + continue; + + for (ii=0; ii < UE_num_active_CC(UE_list,UE_id); ii++) { + CC_id = UE_list->ordered_CCids[ii][UE_id]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + flexran_get_harq(Mod_id, CC_id, UE_id, frameP, subframeP, &harq_pid, &round); + + average_rbs_per_user[CC_id]=0; + + frame_parms[CC_id] = mac_xface->get_lte_frame_parms(Mod_id,CC_id); + + // mac_xface->get_ue_active_harq_pid(Mod_id,CC_id,rnti,frameP,subframeP,&harq_pid,&round,0); + + if(round>0) { + nb_rbs_required[CC_id][UE_id] = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + } + + //nb_rbs_required_remaining[UE_id] = nb_rbs_required[UE_id]; + if (nb_rbs_required[CC_id][UE_id] > 0) { + total_ue_count = total_ue_count + 1; + } + + + // hypotetical assignement + /* + * If schedule is enabled and if the priority of the UEs is modified + * The average rbs per logical channel per user will depend on the level of + * priority. Concerning the hypothetical assignement, we should assign more + * rbs to prioritized users. Maybe, we can do a mapping between the + * average rbs per user and the level of priority or multiply the average rbs + * per user by a coefficient which represents the degree of priority. + */ + + if (total_ue_count == 0) { + average_rbs_per_user[CC_id] = 0; + } else if( (min_rb_unit[CC_id] * total_ue_count) <= (frame_parms[CC_id]->N_RB_DL) ) { + average_rbs_per_user[CC_id] = (uint16_t) floor(frame_parms[CC_id]->N_RB_DL/total_ue_count); + } else { + average_rbs_per_user[CC_id] = min_rb_unit[CC_id]; // consider the total number of use that can be scheduled UE + } + } + } + + // note: nb_rbs_required is assigned according to total_buffer_dl + // extend nb_rbs_required to capture per LCID RB required + for(i=UE_list->head; i>=0; i=UE_list->next[i]) { + rnti = UE_RNTI(Mod_id,i); + + for (ii=0; iiordered_CCids[ii][i]; + + // control channel + if (mac_eNB_get_rrc_status(Mod_id,rnti) < RRC_RECONFIGURED) { + nb_rbs_required_remaining_1[CC_id][i] = nb_rbs_required[CC_id][i]; + } else { + nb_rbs_required_remaining_1[CC_id][i] = cmin(average_rbs_per_user[CC_id],nb_rbs_required[CC_id][i]); + + } + } + } + + //Allocation to UEs is done in 2 rounds, + // 1st stage: average number of RBs allocated to each UE + // 2nd stage: remaining RBs are allocated to high priority UEs + for(r1=0; r1<2; r1++) { + + for(i=UE_list->head; i>=0; i=UE_list->next[i]) { + for (ii=0; iiordered_CCids[ii][i]; + + if(r1 == 0) { + nb_rbs_required_remaining[CC_id][i] = nb_rbs_required_remaining_1[CC_id][i]; + } else { // rb required based only on the buffer - rb allloctaed in the 1st round + extra reaming rb form the 1st round + nb_rbs_required_remaining[CC_id][i] = nb_rbs_required[CC_id][i]-nb_rbs_required_remaining_1[CC_id][i]+nb_rbs_required_remaining[CC_id][i]; + } + + if (nb_rbs_required[CC_id][i]> 0 ) + LOG_D(MAC,"round %d : nb_rbs_required_remaining[%d][%d]= %d (remaining_1 %d, required %d, pre_nb_available_rbs %d, N_RBG %d, rb_unit %d)\n", + r1, CC_id, i, + nb_rbs_required_remaining[CC_id][i], + nb_rbs_required_remaining_1[CC_id][i], + nb_rbs_required[CC_id][i], + UE_list->UE_sched_ctrl[i].pre_nb_available_rbs[CC_id], + N_RBG[CC_id], + min_rb_unit[CC_id]); + + } + } + + if (total_ue_count > 0 ) { + for(i=UE_list->head; i>=0; i=UE_list->next[i]) { + UE_id = i; + + for (ii=0; iiordered_CCids[ii][UE_id]; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + flexran_get_harq(Mod_id, CC_id, UE_id, frameP, subframeP, &harq_pid, &round); + rnti = UE_RNTI(Mod_id,UE_id); + + // LOG_D(MAC,"UE %d rnti 0x\n", UE_id, rnti ); + if(rnti == NOT_A_RNTI) + continue; + if (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) + continue; + + transmission_mode = mac_xface->get_transmission_mode(Mod_id,CC_id,rnti); + //rrc_status = mac_eNB_get_rrc_status(Mod_id,rnti); + /* 1st allocate for the retx */ + + // retransmission in data channels + // control channel in the 1st transmission + // data channel for all TM + LOG_T(MAC,"calling dlsch_scheduler_pre_processor_allocate .. \n "); + _dlsch_scheduler_pre_processor_allocate (Mod_id, + UE_id, + CC_id, + N_RBG[CC_id], + transmission_mode, + min_rb_unit[CC_id], + frame_parms[CC_id]->N_RB_DL, + nb_rbs_required, + nb_rbs_required_remaining, + rballoc_sub, + MIMO_mode_indicator); + } + } + } // total_ue_count + } // end of for for r1 and r2 + + for(i=UE_list->head; i>=0; i=UE_list->next[i]) { + UE_id = i; + ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + + for (ii=0; iiordered_CCids[ii][UE_id]; + //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].dl_pow_off = dl_pow_off[UE_id]; + + if (ue_sched_ctl->pre_nb_available_rbs[CC_id] > 0 ) { + LOG_D(MAC,"******************DL Scheduling Information for UE%d ************************\n",UE_id); + LOG_D(MAC,"dl power offset UE%d = %d \n",UE_id,ue_sched_ctl->dl_pow_off[CC_id]); + LOG_D(MAC,"***********RB Alloc for every subband for UE%d ***********\n",UE_id); + + for(j=0; jmu_mimo_mode[UE_id].rballoc_sub[i] = rballoc_sub_UE[CC_id][UE_id][i]; + LOG_D(MAC,"RB Alloc for UE%d and Subband%d = %d\n",UE_id,j,ue_sched_ctl->rballoc_sub_UE[CC_id][j]); + } + + //PHY_vars_eNB_g[Mod_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = pre_nb_available_rbs[CC_id][UE_id]; + LOG_D(MAC,"Total RBs allocated for UE%d = %d\n",UE_id,ue_sched_ctl->pre_nb_available_rbs[CC_id]); + } + } + } +} + +#define SF05_LIMIT 1 + +void _dlsch_scheduler_pre_processor_reset (int module_idP, + int UE_id, + uint8_t CC_id, + int frameP, + int subframeP, + int N_RBG, + uint16_t nb_rbs_required[MAX_NUM_CCs][NUMBER_OF_UE_MAX], + uint16_t nb_rbs_required_remaining[MAX_NUM_CCs][NUMBER_OF_UE_MAX], + unsigned char rballoc_sub[MAX_NUM_CCs][N_RBG_MAX], + unsigned char MIMO_mode_indicator[MAX_NUM_CCs][N_RBG_MAX]) { + int i,j; + UE_list_t *UE_list=&eNB_mac_inst[module_idP].UE_list; + UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; + rnti_t rnti = UE_RNTI(module_idP,UE_id); + uint8_t *vrb_map = eNB_mac_inst[module_idP].common_channels[CC_id].vrb_map; + int RBGsize = PHY_vars_eNB_g[module_idP][CC_id]->frame_parms.N_RB_DL/N_RBG; +#ifdef SF05_LIMIT + //int subframe05_limit=0; + int sf05_upper=-1,sf05_lower=-1; +#endif + LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti); + + flexran_update_TA(module_idP, UE_id, CC_id); + + if (UE_id==0) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_TIMING_ADVANCE,ue_sched_ctl->ta_update); + } + nb_rbs_required[CC_id][UE_id]=0; + ue_sched_ctl->pre_nb_available_rbs[CC_id] = 0; + ue_sched_ctl->dl_pow_off[CC_id] = 2; + nb_rbs_required_remaining[CC_id][UE_id] = 0; + +#ifdef SF05_LIMIT + switch (N_RBG) { + case 6: + sf05_lower=0; + sf05_upper=5; + break; + case 8: + sf05_lower=2; + sf05_upper=5; + break; + case 13: + sf05_lower=4; + sf05_upper=7; + break; + case 17: + sf05_lower=7; + sf05_upper=9; + break; + case 25: + sf05_lower=11; + sf05_upper=13; + break; + } +#endif + // Initialize Subbands according to VRB map + for (i=0; irballoc_sub_UE[CC_id][i] = 0; + rballoc_sub[CC_id][i] = 0; +#ifdef SF05_LIMIT + // for avoiding 6+ PRBs around DC in subframe 0-5 (avoid excessive errors) + + if ((subframeP==0 || subframeP==5) && + (i>=sf05_lower && i<=sf05_upper)) + rballoc_sub[CC_id][i]=1; +#endif + // for SI-RNTI,RA-RNTI and P-RNTI allocations + for (j=0;jUE_sched_ctrl[UE_id]; + + for(i=0; irballoc_sub_UE[CC_id][i] == 0) && + (nb_rbs_required_remaining[CC_id][UE_id]>0) && + (ue_sched_ctl->pre_nb_available_rbs[CC_id] < nb_rbs_required[CC_id][UE_id])) { + + // if this UE is not scheduled for TM5 + if (ue_sched_ctl->dl_pow_off[CC_id] != 0 ) { + + if ((i == N_RBG-1) && ((N_RB_DL == 25) || (N_RB_DL == 50))) { + rballoc_sub[CC_id][i] = 1; + ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; + MIMO_mode_indicator[CC_id][i] = 1; + if (transmission_mode == 5 ) { + ue_sched_ctl->dl_pow_off[CC_id] = 1; + } + nb_rbs_required_remaining[CC_id][UE_id] = nb_rbs_required_remaining[CC_id][UE_id] - min_rb_unit+1; + ue_sched_ctl->pre_nb_available_rbs[CC_id] = ue_sched_ctl->pre_nb_available_rbs[CC_id] + min_rb_unit - 1; + } else { + if (nb_rbs_required_remaining[CC_id][UE_id] >= min_rb_unit){ + rballoc_sub[CC_id][i] = 1; + ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; + MIMO_mode_indicator[CC_id][i] = 1; + if (transmission_mode == 5 ) { + ue_sched_ctl->dl_pow_off[CC_id] = 1; + } + nb_rbs_required_remaining[CC_id][UE_id] = nb_rbs_required_remaining[CC_id][UE_id] - min_rb_unit; + ue_sched_ctl->pre_nb_available_rbs[CC_id] = ue_sched_ctl->pre_nb_available_rbs[CC_id] + min_rb_unit; + } + } + } // dl_pow_off[CC_id][UE_id] ! = 0 + } + } +} From 8750acebbcf3c13de3d35a21f196b2f4e0f89c09 Mon Sep 17 00:00:00 2001 From: GabrirelCouturier Date: Mon, 7 Nov 2016 10:50:05 +0100 Subject: [PATCH 272/413] [OAI-UE] fix for issue#14: segmentation fault in turbo decoder --- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 33 +++++++++++++++++++++ openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c | 12 +++++++- openair1/SCHED/phy_procedures_lte_ue.c | 4 +-- openair1/SCHED/pucch_pc.c | 4 +-- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index aa2daf8ebb..3624d67af1 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -1260,6 +1260,11 @@ int generate_eNB_dlsch_params_from_dci(int frame, dlsch0_harq->TBS = TBStable[get_I_TBS(dlsch0_harq->mcs)][NPRB-1]; } + else + { + LOG_E(PHY,"DL Received HarqReTx round=%d mcs=%d rballoc=%d rv=%d \n", + dlsch0_harq->round,mcs,rballoc,rv); + } dlsch[0]->current_harq_pid = harq_pid; @@ -4143,6 +4148,20 @@ int generate_ue_dlsch_params_from_dci(int frame, dlsch0_harq->DCINdi = ndi; + // this a retransmission + if(dlsch0_harq->round) + { + // compare old TBS to new TBS + if(dlsch0_harq->TBS != TBStable[get_I_TBS(mcs)][NPRB-1]) + { + // this is an eNB issue + // retransmisison but old and new TBS are different !!! + // work around, consider it as a new transmission + LOG_E(PHY,"Format1A Retransmission but TBS are different: consider it as new transmission !!! \n"); + dlsch0_harq->round = 0; + } + } + dlsch0_harq->mcs = mcs; if ((rnti==si_rnti) || (rnti==p_rnti) || (rnti==ra_rnti)) { dlsch0_harq->TBS = TBStable[mcs][NPRB-1]; @@ -4452,6 +4471,20 @@ int generate_ue_dlsch_params_from_dci(int frame, dlsch0_harq->mcs = mcs; + // this a retransmission + if(dlsch0_harq->round) + { + // compare old TBS to new TBS + if(dlsch0_harq->TBS != TBStable[get_I_TBS(mcs)][NPRB-1]) + { + // this is an eNB issue + // retransmisison but old and new TBS are different !!! + // work around, consider it as a new transmission + LOG_E(PHY,"Format1 Retransmission but TBS are different: consider it as new transmission !!! \n"); + dlsch0_harq->round = 0; + } + } + dlsch0_harq->TBS = TBStable[get_I_TBS(mcs)][NPRB-1]; if (mcs <= 28) dlsch0_harq->Qm = get_Qm(mcs); diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c index f4ab4c0924..c7cd5ab52f 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c @@ -249,7 +249,12 @@ uint32_t dlsch_decoding(PHY_VARS_UE *phy_vars_ue, tc = phy_threegpplte_turbo_decoder16; } else - tc = phy_threegpplte_turbo_decoder8; + { + AssertFatal (harq_process->TBS >= 256 , "Mismatch flag nbRB=%d TBS=%d mcs=%d Qm=%d RIV=%d round=%d \n", + harq_process->nb_rb, harq_process->TBS,harq_process->mcs,harq_process->Qm,harq_process->rvidx,harq_process->round); + tc = phy_threegpplte_turbo_decoder8; + } + // nb_rb = dlsch->nb_rb; @@ -448,6 +453,11 @@ uint32_t dlsch_decoding(PHY_VARS_UE *phy_vars_ue, #if 1 if (err_flag == 0) { + if (llr8_flag) { + AssertFatal (Kr >= 256, "turbo algo issue Kr=%d cb_cnt=%d C=%d nbRB=%d TBSInput=%d TBSHarq=%d TBSplus24=%d mcs=%d Qm=%d RIV=%d round=%d\n", + Kr,r,harq_process->C,harq_process->nb_rb,A,harq_process->TBS,harq_process->B,harq_process->mcs,harq_process->Qm,harq_process->rvidx,harq_process->round); + } + start_meas(dlsch_turbo_decoding_stats); ret = tc (&harq_process->d[r][96], diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 756f13f923..55e7686462 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -2579,7 +2579,7 @@ int ue_pdcch_procedures(uint8_t eNB_id,PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint if (generate_ue_dlsch_params_from_dci(frame_rx, subframe_rx, (void *)&dci_alloc_rx[i].dci_pdu, - SI_RNTI, + P_RNTI, dci_alloc_rx[i].format, &ue->dlsch_SI[eNB_id], &ue->frame_parms, @@ -3072,7 +3072,7 @@ void ue_dlsch_procedures(PHY_VARS_UE *ue, subframe_rx, harq_pid, pdsch==PDSCH?1:0, - dlsch0->harq_processes[harq_pid]->nb_rb>10?1:0); + dlsch0->harq_processes[harq_pid]->TBS>256?1:0); stop_meas(&ue->dlsch_decoding_stats); } diff --git a/openair1/SCHED/pucch_pc.c b/openair1/SCHED/pucch_pc.c index 5afd57e6a0..2795fe65a9 100644 --- a/openair1/SCHED/pucch_pc.c +++ b/openair1/SCHED/pucch_pc.c @@ -88,7 +88,7 @@ int8_t pucch_power_cntl(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t subframe,ui } if (pucch_fmt!=pucch_format1) { - LOG_I(PHY,"[UE %d][PDSCH %x] frame %d, subframe %d: Po_PUCCH %d dBm : Po_NOMINAL_PUCCH %d dBm, PL %d dB, g_pucch %d dB\n", + LOG_D(PHY,"[UE %d][PDSCH %x] frame %d, subframe %d: Po_PUCCH %d dBm : Po_NOMINAL_PUCCH %d dBm, PL %d dB, g_pucch %d dB\n", ue->Mod_id, ue->dlsch[eNB_id][0]->rnti,proc->frame_tx,subframe, Po_PUCCH, @@ -96,7 +96,7 @@ int8_t pucch_power_cntl(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t subframe,ui get_PL(ue->Mod_id,ue->CC_id,eNB_id), ue->dlsch[eNB_id][0]->g_pucch); } else { - LOG_I(PHY,"[UE %d][SR %x] frame %d, subframe %d: Po_PUCCH %d dBm : Po_NOMINAL_PUCCH %d dBm, PL %d dB g_pucch %d dB\n", + LOG_D(PHY,"[UE %d][SR %x] frame %d, subframe %d: Po_PUCCH %d dBm : Po_NOMINAL_PUCCH %d dBm, PL %d dB g_pucch %d dB\n", ue->Mod_id, ue->dlsch[eNB_id][0]->rnti,proc->frame_tx,subframe, Po_PUCCH, From 5e94d108a194506e62b5d95bde4b0faf4398be41 Mon Sep 17 00:00:00 2001 From: GabrirelCouturier Date: Mon, 7 Nov 2016 11:01:25 +0100 Subject: [PATCH 273/413] [OAI-UE] fix for issue#18: Cell sync issue --- openair1/PHY/LTE_ESTIMATION/lte_est_freq_offset.c | 15 ++++++++------- openair1/PHY/LTE_TRANSPORT/initial_sync.c | 7 +++++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_est_freq_offset.c b/openair1/PHY/LTE_ESTIMATION/lte_est_freq_offset.c index 6ebd8948cf..d713cc0163 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_est_freq_offset.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_est_freq_offset.c @@ -102,7 +102,7 @@ int lte_est_freq_offset(int **dl_ch_estimates, { int ch_offset, omega, dl_ch_shift; - struct complex16 *omega_cpx; + struct complex16 omega_cpx; double phase_offset; int freq_offset_est; unsigned char aa; @@ -142,9 +142,8 @@ int lte_est_freq_offset(int **dl_ch_estimates, // printf("Computing freq_offset\n"); omega = dot_product(dl_ch,dl_ch_prev,(frame_parms->N_RB_DL/2 - 1)*12,dl_ch_shift); //omega = dot_product(dl_ch,dl_ch_prev,frame_parms->ofdm_symbol_size,15); - omega_cpx = (struct complex16*) ω - - // printf("omega (%d,%d)\n",omega_cpx->r,omega_cpx->i); + omega_cpx.r = ((struct complex16*) &omega)->r; + omega_cpx.i = ((struct complex16*) &omega)->i; dl_ch = (int16_t *)&dl_ch_estimates[aa][(((frame_parms->N_RB_DL/2) + 1)*12) + ch_offset]; @@ -155,10 +154,12 @@ int lte_est_freq_offset(int **dl_ch_estimates, // calculate omega = angle(conj(dl_ch)*dl_ch_prev)) omega = dot_product(dl_ch,dl_ch_prev,((frame_parms->N_RB_DL/2) - 1)*12,dl_ch_shift); - omega_cpx->r += ((struct complex16*) &omega)->r; - omega_cpx->i += ((struct complex16*) &omega)->i; + + omega_cpx.r += ((struct complex16*) &omega)->r; + omega_cpx.i += ((struct complex16*) &omega)->i; + // phase_offset += atan2((double)omega_cpx->i,(double)omega_cpx->r); - phase_offset += atan2((double)omega_cpx->i,(double)omega_cpx->r); + phase_offset += atan2((double)omega_cpx.i,(double)omega_cpx.r); // LOG_I(PHY,"omega (%d,%d) -> %f\n",omega_cpx->r,omega_cpx->i,phase_offset); } diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c index 661fe96be8..91374078c0 100644 --- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c +++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c @@ -462,6 +462,13 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) } } + /* Consider this is a false detection if the offset is > 1000 Hz */ + if( (abs(ue->common_vars.freq_offset) > 1000) && (ret == 0) ) + { + ret=-1; + LOG_E(HW,"Ignore MIB with high freq offset [%d Hz] estimation \n",ue->common_vars.freq_offset); + } + if (ret==0) { // PBCH found so indicate sync to higher layers and configure frame parameters //#ifdef DEBUG_INITIAL_SYNCH From 048b5384dd30aec8246020f0e1c30d5b8dd1970a Mon Sep 17 00:00:00 2001 From: fnabet Date: Mon, 7 Nov 2016 11:22:11 +0100 Subject: [PATCH 274/413] [OAI-UE] revert commit 8236206c and 9672b410 "BSR-stabilization + rebase from oai1B" --- openair2/LAYER2/MAC/config.c | 25 +--- openair2/LAYER2/MAC/defs.h | 14 +-- openair2/LAYER2/MAC/extern.h | 2 - openair2/LAYER2/MAC/proto.h | 6 +- openair2/LAYER2/MAC/ra_procedures.c | 2 +- openair2/LAYER2/MAC/ue_procedures.c | 184 +++++++++------------------- openair2/LAYER2/MAC/vars.h | 9 -- 7 files changed, 66 insertions(+), 176 deletions(-) diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index d46b761bd0..3fbcadafbb 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -69,7 +69,6 @@ void ue_mac_reset(module_id_t module_idP,uint8_t eNB_index) // cancel all pending SRs UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; - UE_mac_inst[module_idP].BSR_reporting_active=0; // stop ongoing RACH procedure @@ -226,34 +225,13 @@ rrc_mac_config_req( if (mac_MainConfig->ext1 && mac_MainConfig->ext1->sr_ProhibitTimer_r9) { UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = (uint16_t) *mac_MainConfig->ext1->sr_ProhibitTimer_r9; } else { - UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = 0; + UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = (uint16_t) 0; } - if (mac_MainConfig->ext2 && mac_MainConfig->ext2->mac_MainConfig_v1020) { - if (mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10) { - UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t) *mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10; - } else { - UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t)0; - } - if (mac_MainConfig->ext2->mac_MainConfig_v1020->extendedPHR_r10) { - UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t) *mac_MainConfig->ext2->mac_MainConfig_v1020->extendedPHR_r10; - } else { - UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t)0; - } - } else { - UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t)0; - UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t)0; - } #endif UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer); UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer); - UE_mac_inst[Mod_idP].BSR_reporting_active = 0; - LOG_D(MAC,"[UE %d]: periodic BSR %d (SF), retx BSR %d (SF)\n", - Mod_idP, - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF, - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF); - UE_mac_inst[Mod_idP].scheduling_info.drx_config = mac_MainConfig->drx_Config; UE_mac_inst[Mod_idP].scheduling_info.phr_config = mac_MainConfig->phr_Config; @@ -274,7 +252,6 @@ rrc_mac_config_req( UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer); UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer); UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[Mod_idP].scheduling_info.PathlossChange); - UE_mac_inst[Mod_idP].PHR_reporting_active = 0; LOG_D(MAC,"[UE %d] config PHR (%d): periodic %d (SF) prohibit %d (SF) pathlosschange %d (db) \n", Mod_idP, (mac_MainConfig->phr_Config)?mac_MainConfig->phr_Config->present:-1, diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index d38ca05362..2235c3e1c4 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -945,12 +945,8 @@ typedef enum { typedef struct { /// buffer status for each lcgid uint8_t BSR[MAX_NUM_LCGID]; // should be more for mesh topology - /// keep the number of bytes in rlc buffer for each lcgid + /// keep the number of bytes in rlc buffer for each lcid uint16_t BSR_bytes[MAX_NUM_LCGID]; -#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 - /// after multiplexing buffer remain for each lcid - uint16_t LCID_buffer_remain[MAX_NUM_LCID]; -#endif /// buffer status for each lcid uint8_t LCID_status[MAX_NUM_LCID]; /// SR pending as defined in 36.321 @@ -991,12 +987,6 @@ typedef struct { int16_t prohibitPHR_SF; ///DL Pathloss Change in db uint16_t PathlossChange_db; - - /// default value is false - uint16_t extendedBSR_Sizes_r10; - /// default value is false - uint16_t extendedPHR_r10; - //Bj bucket usage per lcid int16_t Bj[MAX_NUM_LCID]; // Bucket size per lcid @@ -1084,8 +1074,6 @@ typedef struct { uint8_t PHR_reporting_active; /// power backoff due to power management (as allowed by P-MPRc) for this cell uint8_t power_backoff_db[NUMBER_OF_eNB_MAX]; - /// BSR report falg management - uint8_t BSR_reporting_active; /// MBSFN_Subframe Configuration struct MBSFN_SubframeConfig *mbsfn_SubframeConfig[8]; // FIXME replace 8 by MAX_MBSFN_AREA? /// number of subframe allocation pattern available for MBSFN sync area diff --git a/openair2/LAYER2/MAC/extern.h b/openair2/LAYER2/MAC/extern.h index 4276c342cf..8726cb1349 100644 --- a/openair2/LAYER2/MAC/extern.h +++ b/openair2/LAYER2/MAC/extern.h @@ -46,8 +46,6 @@ extern const uint32_t BSR_TABLE[BSR_TABLE_SIZE]; //extern uint32_t EBSR_Level[63]; -extern const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE]; -//extern uint32_t Extended_BSR_TABLE[63]; ----currently not used extern UE_MAC_INST *UE_mac_inst; extern eNB_MAC_INST *eNB_mac_inst; diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 248f918dc1..59d6c352fe 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -551,7 +551,7 @@ int get_bsr_lcgid (module_id_t module_idP); \param[in] bufflen size of phy transport block \param[out] bsr_len size of bsr control element */ -uint8_t get_bsr_len (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint16_t buflen); +uint8_t get_bsr_len (module_id_t module_idP, uint16_t buflen); /*! \fn BSR_SHORT * get_bsr_short(module_id_t module_idP, uint8_t bsr_len) \brief get short bsr level @@ -577,14 +577,14 @@ BSR_LONG * get_bsr_long(module_id_t module_idP, uint8_t bsr_len); */ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_index, uint8_t lcid, uint8_t lcgid); -/*! \fn locate_BsrIndexByBufferSize (int *table, int size, int value) +/*! \fn locate (int *table, int size, int value) \brief locate the BSR level in the table as defined in 36.321. This function requires that he values in table to be monotonic, either increasing or decreasing. The returned value is not less than 0, nor greater than n-1, where n is the size of table. \param[in] *table Pointer to BSR table \param[in] size Size of the table \param[in] value Value of the buffer \return the index in the BSR_LEVEL table */ -uint8_t locate_BsrIndexByBufferSize (const uint32_t *table, int size, int value); +uint8_t locate (const uint32_t *table, int size, int value); /*! \fn int get_sf_periodicBSRTimer(uint8_t periodicBSR_Timer) diff --git a/openair2/LAYER2/MAC/ra_procedures.c b/openair2/LAYER2/MAC/ra_procedures.c index 3b5734756d..30137fab33 100644 --- a/openair2/LAYER2/MAC/ra_procedures.c +++ b/openair2/LAYER2/MAC/ra_procedures.c @@ -391,7 +391,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP, 1); //post_padding return(&UE_mac_inst[module_idP].RA_prach_resources); - } else if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] > 0) { + } else if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[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, diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index c24702b3b5..d5958f6e5e 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -102,17 +102,13 @@ void ue_init_mac(module_id_t module_idP) UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer_Running=0; UE_mac_inst[module_idP].scheduling_info.maxHARQ_Tx=MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; UE_mac_inst[module_idP].scheduling_info.ttiBundling=0; - UE_mac_inst[module_idP].scheduling_info.extendedBSR_Sizes_r10=0; - UE_mac_inst[module_idP].scheduling_info.extendedPHR_r10=0; UE_mac_inst[module_idP].scheduling_info.drx_config=NULL; UE_mac_inst[module_idP].scheduling_info.phr_config=NULL; UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); - UE_mac_inst[module_idP].BSR_reporting_active = 0; UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer); UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer); UE_mac_inst[module_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[module_idP].scheduling_info.PathlossChange); - UE_mac_inst[module_idP].PHR_reporting_active = 0; for (i=0; i < MAX_NUM_LCID; i++) { LOG_D(MAC,"[UE%d] Applying default logical channel config for LCGID %d\n",module_idP,i); @@ -125,7 +121,7 @@ void ue_init_mac(module_id_t module_idP) UE_mac_inst[module_idP].scheduling_info.LCGID[i]=1; } - UE_mac_inst[module_idP].scheduling_info.LCID_status[i]=LCID_EMPTY; + UE_mac_inst[module_idP].scheduling_info.LCID_status[i]=0; } #ifdef CBA @@ -310,28 +306,18 @@ uint32_t ue_get_SR(module_id_t module_idP,int CC_id,frame_t frameP,uint8_t eNB_i // initiate RA UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; - // release all pucch resource - UE_mac_inst[module_idP].physicalConfigDedicated = NULL; - UE_mac_inst[module_idP].ul_active=0; - UE_mac_inst[module_idP].BSR_reporting_active=0; - - LOG_T(MAC,"[UE %d] Release all SRs \n", module_idP); return(0); } } //------------------------------------------------------------------------------ void -ue_send_sdu( - module_id_t module_idP, - uint8_t CC_id, - frame_t frameP, - uint8_t* sdu, - uint16_t sdu_len, - uint8_t eNB_index -) -//------------------------------------------------------------------------------ -{ +ue_send_sdu(module_id_t module_idP, + uint8_t CC_id, + frame_t frameP, + uint8_t* sdu, + uint16_t sdu_len, + uint8_t eNB_index) { unsigned char rx_ces[MAX_NUM_CE],num_ce,num_sdu,i,*payload_ptr; unsigned char rx_lcids[NB_RB_MAX]; @@ -1258,12 +1244,11 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf BSR_LONG *bsr_l=&bsr_long; POWER_HEADROOM_CMD phr; POWER_HEADROOM_CMD *phr_p=&phr; - unsigned short short_padding=0, post_padding=0, padding_len=0; + unsigned short short_padding=0, post_padding=0; int lcgid; int j; // used for padding // Compute header length - int all_pdu_len; - + if (CC_id>0) { LOG_E(MAC,"Transmission on secondary CCs is not supported yet\n"); mac_xface->macphy_exit("MAC FATAL CC_id>0"); @@ -1297,10 +1282,19 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len=(buflen > 128 ) ? 3 : 2 ; //sizeof(SCH_SUBHEADER_LONG)-1 : sizeof(SCH_SUBHEADER_SHORT); bsr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); phr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); + phr_ce_len = (UE_mac_inst[module_idP].PHR_reporting_active == 1) ? 1 /* sizeof(POWER_HEADROOM_CMD)*/: 0; - bsr_ce_len = get_bsr_len (module_idP, eNB_index, frameP, buflen); - // retxBSR-Timer expires or periodicBSR-Timer expires and Regular BSR trigger - if ((bsr_ce_len > 0 ) && (UE_mac_inst[module_idP].BSR_reporting_active > 0)) { + if (phr_ce_len > 0) { + phr_len = phr_ce_len + phr_header_len; + LOG_D(MAC,"[UE %d] header size info: PHR len %d (ce%d,hdr%d) buff_len %d\n", + module_idP, phr_len, phr_ce_len, phr_header_len, buflen); + } else { + phr_len=0; + } + + bsr_ce_len = get_bsr_len (module_idP, buflen-phr_len); + + if (bsr_ce_len > 0 ) { bsr_len = bsr_ce_len + bsr_header_len; LOG_D(MAC,"[UE %d] header size info: dcch %d, dcch1 %d, dtch %d, bsr (ce%d,hdr%d) buff_len %d\n", module_idP, dcch_header_len,dcch1_header_len,dtch_header_len, bsr_ce_len, bsr_header_len, buflen); @@ -1311,15 +1305,6 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf //bsr_len = bsr_ce_len + bsr_header_len; } - phr_ce_len = (UE_mac_inst[module_idP].PHR_reporting_active == 1) ? 1 /* sizeof(POWER_HEADROOM_CMD)*/: 0; - if (phr_ce_len > 0) { - phr_len = phr_ce_len + phr_header_len; - LOG_D(MAC,"[UE %d] header size info: PHR len %d (ce%d,hdr%d) buff_len %d\n", - module_idP, phr_len, phr_ce_len, phr_header_len, buflen); - } else { - phr_len=0; - } - // check for UL bandwidth requests and add SR control element // check for UL bandwidth requests and add SR control element @@ -1353,12 +1338,8 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf sdu_lcids[0] = DCCH; LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH\n",module_idP,sdu_lengths[0]); num_sdus = 1; - //update_bsr(module_idP, frameP, eNB_index, DCCH, UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]); + update_bsr(module_idP, frameP, eNB_index, DCCH, UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]); //header_len +=2; - UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH] = LCID_EMPTY; -#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 - UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH] = rlc_status.bytes_in_buffer-sdu_lengths[0]; -#endif } else { dcch_header_len=0; num_sdus = 0; @@ -1394,13 +1375,9 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf sdu_length_total += sdu_lengths[num_sdus]; sdu_lcids[num_sdus] = DCCH1; LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH1\n",module_idP,sdu_lengths[num_sdus]); + num_sdus++; //update_bsr(module_idP, frameP, DCCH1); //dcch_header_len +=2; // include dcch1 - UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH1] = LCID_EMPTY; -#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 - UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1] = rlc_status.bytes_in_buffer-sdu_lengths[num_sdus]; -#endif - num_sdus++; } else { dcch1_header_len =0; } @@ -1411,9 +1388,8 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len+=3; dtch_header_len_last=3; - all_pdu_len = bsr_len+phr_len+dcch_header_len+dcch1_header_len+dtch_header_len+sdu_length_total; if ((UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) && - (all_pdu_len <= buflen)) { + ((bsr_len+phr_len+dcch_header_len+dcch1_header_len+dtch_header_len+sdu_length_total) <= buflen)) { // optimize the dtch header lenght //if ((UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DTCH] > 128) && @@ -1431,11 +1407,11 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf ENB_FLAG_NO, MBMS_FLAG_NO, // eNB_index lcid, - buflen-all_pdu_len); + buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total); LOG_D(MAC,"[UE %d] Frame %d : UL-DTCH -> ULSCH%d, %d bytes to send (Transport Block size %d, mac header len %d, BSR byte[%d] %d)\n", module_idP,frameP, lcid, rlc_status.bytes_in_buffer,buflen,dtch_header_len, - lcid, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); + lcid, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcid]); if (rlc_status.bytes_in_buffer > 0) { sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, @@ -1455,20 +1431,16 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len --; dtch_header_len_last --; } -#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 - UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] = rlc_status.bytes_in_buffer-sdu_lengths[num_sdus]; -#endif num_sdus++; - //UE_mac_inst[module_idP].ul_active = update_bsr(module_idP, frameP, eNB_index,lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); + UE_mac_inst[module_idP].ul_active = update_bsr(module_idP, frameP, eNB_index,lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); } else { dtch_header_len -= 3; } - UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_EMPTY; } else { // no rlc pdu : generate the dummy header dtch_header_len -= 3; } } - + lcgid= get_bsr_lcgid(module_idP); if (lcgid < 0 ) { @@ -1480,29 +1452,15 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf bsr_l->Buffer_size1 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]; bsr_l->Buffer_size2 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]; bsr_l->Buffer_size3 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]; - LOG_D(MAC, "[UE %d] Frame %d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP, UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]); - - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID0] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID1] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID2] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID3] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] = 0; } else if (bsr_ce_len == sizeof(BSR_SHORT)) { bsr_l = NULL; bsr_s->LCGID = lcgid; bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]; - - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] = 0; - LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n", module_idP, frameP, UE_mac_inst[module_idP].scheduling_info.BSR[lcgid],lcgid); } else { @@ -1536,14 +1494,12 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len_last-=1; dtch_header_len= (dtch_header_len >0)? dtch_header_len - dtch_header_len_last : dtch_header_len; } - // 1-bit padding or 2-bit padding special padding subheader - padding_len = buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total; - if (padding_len <= 2) { - short_padding = padding_len; - // only add padding header + + if ((buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total) <= 2) { + short_padding = buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total; post_padding = 0; } else { - if (padding_len == buflen) {// nona mac pdu + if ((buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total) == buflen) { *access_mode=CANCELED_ACCESS; } @@ -1588,9 +1544,6 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf module_idP,payload_offset, sdu_length_total); UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; - UE_mac_inst[module_idP].BSR_reporting_active=0; - UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); - UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_OUT); stop_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu); @@ -1752,25 +1705,10 @@ ue_scheduler( // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures // outlined in Sections 5.4.4 an 5.4.5 of 36.321 - // Call BSR procedure as described in Section 5.4.5 in 36.321 - if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF == get_sf_periodicBSRTimer(MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity)) { - UE_mac_inst[module_idP].BSR_reporting_active = 1; - } else if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF <= 0 ){ - // trigger BSR and reset the timer later when the BSR report is sent - UE_mac_inst[module_idP].BSR_reporting_active = 1; - } else if (UE_mac_inst[module_idP].BSR_reporting_active == 0 ) { - UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF--; - } - - if (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF <= 0){ - // trigger BSR and reset the timer later when the BSR report is sent - UE_mac_inst[module_idP].BSR_reporting_active = 1; - } else if (UE_mac_inst[module_idP].BSR_reporting_active == 0 ) { - UE_mac_inst[module_idP].scheduling_info.retxBSR_SF--; - } + // Put this in another function // Get RLC status info and update Bj for all lcids that are active - for (lcid=DCCH; lcid < MAX_NUM_LCID; lcid++ ) { + for (lcid=DCCH; lcid <= DTCH; lcid++ ) { if ((lcid == 0) ||(UE_mac_inst[module_idP].logicalChannelConfig[lcid])) { // meausre the Bj if ((directionP == SF_UL)&& (UE_mac_inst[module_idP].scheduling_info.Bj[lcid] >= 0)) { @@ -1791,8 +1729,6 @@ ue_scheduler( if (update_bsr(module_idP,frameP, eNB_indexP, lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid])) { UE_mac_inst[module_idP].scheduling_info.SR_pending= 1; - // Regular BSR trigger - UE_mac_inst[module_idP].BSR_reporting_active = 1; LOG_D(MAC,"[UE %d][SR] Frame %d subframe %d SR for PUSCH is pending for LCGID %d with BSR level %d (%d bytes in RLC)\n", module_idP, frameP,subframeP,UE_mac_inst[module_idP].scheduling_info.LCGID[lcid], UE_mac_inst[module_idP].scheduling_info.BSR[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], @@ -2034,26 +1970,31 @@ int get_bsr_lcgid (module_id_t module_idP) } } -uint8_t get_bsr_len (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint16_t buflen) +uint8_t get_bsr_len (module_id_t module_idP, uint16_t buflen) { - int lcid; - uint8_t bsr_len=0, num_lcid=0; - int pdu = 0; - mac_rlc_status_resp_t rlc_status; - for (lcid=DCCH; lcid 0 ) { - pdu += rlc_status.bytes_in_buffer + sizeof(SCH_SUBHEADER_SHORT) + bsr_len; - if (rlc_status.bytes_in_buffer > 128 ) { - pdu += 1; //sizeof(SCH_SUBHEADER_LONG) - } + int lcgid=0; + uint8_t bsr_len=0, num_lcgid=0; + int pdu = 0; + + + for (lcgid=0; lcgid < MAX_NUM_LCGID; lcgid++ ) { + if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 0 ) { + pdu += (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] + bsr_len + 2); //2 = sizeof(SCH_SUBHEADER_SHORT) } - if ( (pdu > buflen) && (rlc_status.bytes_in_buffer > 0 ) ) { - num_lcid +=1; - bsr_len = (num_lcid >= 2 ) ? sizeof(BSR_LONG) : sizeof(BSR_SHORT) ; + + if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 128 ) { // long header size: adjust the header size + pdu += 1; } - LOG_D(MAC,"LC buffer Bytes %d for lcid %d bsr len %d num lcid %d\n", rlc_status.bytes_in_buffer, lcid, bsr_len, num_lcid); + + // current phy buff can not transport all sdu for this lcgid -> transmit a bsr for this lcgid + + if ( (pdu > buflen) && (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 0 ) ) { + num_lcgid +=1; + bsr_len = (num_lcgid >= 2 ) ? sizeof(BSR_LONG) : sizeof(BSR_SHORT) ; + } + + LOG_D(MAC,"BSR Bytes %d for lcgid %d bsr len %d num lcgid %d\n", UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid], lcgid, bsr_len, num_lcgid); } if ( bsr_len > 0 ) @@ -2063,6 +2004,7 @@ uint8_t get_bsr_len (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,ui return bsr_len; } + boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_index, uint8_t lcid, uint8_t lcg_id) { @@ -2086,17 +2028,11 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in lcid, 0); - if ((rlc_status.bytes_in_buffer > 0 ) -#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 - && (rlc_status.bytes_in_buffer > UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]) -#endif - ){ - //BSR trigger SR + if (rlc_status.bytes_in_buffer > 0 ) { sr_pending = TRUE; UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_NOT_EMPTY; - // sum lcid buffer which has same lcgid + UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] += locate (BSR_TABLE,BSR_TABLE_SIZE, rlc_status.bytes_in_buffer); UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id] += rlc_status.bytes_in_buffer; - UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); // UE_mac_inst[module_idP].scheduling_info.BSR_short_lcid = lcid; // only applicable to short bsr LOG_D(MAC,"[UE %d] BSR level %d (LCGID %d, rlc buffer %d byte)\n", module_idP, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id],lcg_id, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); @@ -2109,7 +2045,7 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in return sr_pending; } -uint8_t locate_BsrIndexByBufferSize (const uint32_t *table, int size, int value) +uint8_t locate (const uint32_t *table, int size, int value) { uint8_t ju, jm, jl; @@ -2140,7 +2076,7 @@ uint8_t locate_BsrIndexByBufferSize (const uint32_t *table, int size, int value) if (value == table[jl]) { return jl; - } else { + } else { return jl+1; //equally ju } diff --git a/openair2/LAYER2/MAC/vars.h b/openair2/LAYER2/MAC/vars.h index 236439c6e5..83d159f910 100644 --- a/openair2/LAYER2/MAC/vars.h +++ b/openair2/LAYER2/MAC/vars.h @@ -45,15 +45,6 @@ const uint32_t BSR_TABLE[BSR_TABLE_SIZE]= {0,10,12,14,17,19,22,26,31,36,42,49,57 1326,1552,1817,2127,2490,2915,3413,3995,4677,5467,6411,7505,8787,10287,12043,14099, 16507,19325,22624,26487,31009,36304,42502,49759,58255,68201,79846,93479,109439, 128125,150000, 300000 }; -// extended bsr table--currently not used -const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE] = {0,10,13,16,19,23,29,35,43,53,65,80,98,120,147, - 181,223,274,337,414,509,625,769,945,1162,1429, - 1757,2161,2657,3267,4017,4940,6074,7469,9185, - 11294,13888,17077,20999,25822,31752,39045,48012, - 59039,72598,89272,109774,134986,165989,204111, - 250990,308634,379519,466683,573866,705666,867737, - 1067031,1312097,1613447,1984009,2439678,3000000, - 6000000}; //uint32_t EBSR_Level[63]={0,10,13,16,19,23,29,35,43,53,65,80,98,120,147,181}; From d56c651081874c69a42bba2956356514e3f847b2 Mon Sep 17 00:00:00 2001 From: fnabet Date: Mon, 7 Nov 2016 11:57:02 +0100 Subject: [PATCH 275/413] Reapply BSR changes --- openair2/LAYER2/MAC/config.c | 25 +++- openair2/LAYER2/MAC/defs.h | 14 ++- openair2/LAYER2/MAC/extern.h | 2 + openair2/LAYER2/MAC/proto.h | 6 +- openair2/LAYER2/MAC/ra_procedures.c | 2 +- openair2/LAYER2/MAC/ue_procedures.c | 182 +++++++++++++++++++--------- openair2/LAYER2/MAC/vars.h | 9 ++ 7 files changed, 175 insertions(+), 65 deletions(-) diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 3fbcadafbb..d46b761bd0 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -69,6 +69,7 @@ void ue_mac_reset(module_id_t module_idP,uint8_t eNB_index) // cancel all pending SRs UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; + UE_mac_inst[module_idP].BSR_reporting_active=0; // stop ongoing RACH procedure @@ -225,13 +226,34 @@ rrc_mac_config_req( if (mac_MainConfig->ext1 && mac_MainConfig->ext1->sr_ProhibitTimer_r9) { UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = (uint16_t) *mac_MainConfig->ext1->sr_ProhibitTimer_r9; } else { - UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = (uint16_t) 0; + UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = 0; } + if (mac_MainConfig->ext2 && mac_MainConfig->ext2->mac_MainConfig_v1020) { + if (mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10) { + UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t) *mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10; + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t)0; + } + if (mac_MainConfig->ext2->mac_MainConfig_v1020->extendedPHR_r10) { + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t) *mac_MainConfig->ext2->mac_MainConfig_v1020->extendedPHR_r10; + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t)0; + } + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t)0; + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t)0; + } #endif UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer); UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer); + UE_mac_inst[Mod_idP].BSR_reporting_active = 0; + LOG_D(MAC,"[UE %d]: periodic BSR %d (SF), retx BSR %d (SF)\n", + Mod_idP, + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF, + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF); + UE_mac_inst[Mod_idP].scheduling_info.drx_config = mac_MainConfig->drx_Config; UE_mac_inst[Mod_idP].scheduling_info.phr_config = mac_MainConfig->phr_Config; @@ -252,6 +274,7 @@ rrc_mac_config_req( UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer); UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer); UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[Mod_idP].scheduling_info.PathlossChange); + UE_mac_inst[Mod_idP].PHR_reporting_active = 0; LOG_D(MAC,"[UE %d] config PHR (%d): periodic %d (SF) prohibit %d (SF) pathlosschange %d (db) \n", Mod_idP, (mac_MainConfig->phr_Config)?mac_MainConfig->phr_Config->present:-1, diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 2235c3e1c4..d38ca05362 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -945,8 +945,12 @@ typedef enum { typedef struct { /// buffer status for each lcgid uint8_t BSR[MAX_NUM_LCGID]; // should be more for mesh topology - /// keep the number of bytes in rlc buffer for each lcid + /// keep the number of bytes in rlc buffer for each lcgid uint16_t BSR_bytes[MAX_NUM_LCGID]; +#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 + /// after multiplexing buffer remain for each lcid + uint16_t LCID_buffer_remain[MAX_NUM_LCID]; +#endif /// buffer status for each lcid uint8_t LCID_status[MAX_NUM_LCID]; /// SR pending as defined in 36.321 @@ -987,6 +991,12 @@ typedef struct { int16_t prohibitPHR_SF; ///DL Pathloss Change in db uint16_t PathlossChange_db; + + /// default value is false + uint16_t extendedBSR_Sizes_r10; + /// default value is false + uint16_t extendedPHR_r10; + //Bj bucket usage per lcid int16_t Bj[MAX_NUM_LCID]; // Bucket size per lcid @@ -1074,6 +1084,8 @@ typedef struct { uint8_t PHR_reporting_active; /// power backoff due to power management (as allowed by P-MPRc) for this cell uint8_t power_backoff_db[NUMBER_OF_eNB_MAX]; + /// BSR report falg management + uint8_t BSR_reporting_active; /// MBSFN_Subframe Configuration struct MBSFN_SubframeConfig *mbsfn_SubframeConfig[8]; // FIXME replace 8 by MAX_MBSFN_AREA? /// number of subframe allocation pattern available for MBSFN sync area diff --git a/openair2/LAYER2/MAC/extern.h b/openair2/LAYER2/MAC/extern.h index 8726cb1349..4276c342cf 100644 --- a/openair2/LAYER2/MAC/extern.h +++ b/openair2/LAYER2/MAC/extern.h @@ -46,6 +46,8 @@ extern const uint32_t BSR_TABLE[BSR_TABLE_SIZE]; //extern uint32_t EBSR_Level[63]; +extern const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE]; +//extern uint32_t Extended_BSR_TABLE[63]; ----currently not used extern UE_MAC_INST *UE_mac_inst; extern eNB_MAC_INST *eNB_mac_inst; diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 59d6c352fe..248f918dc1 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -551,7 +551,7 @@ int get_bsr_lcgid (module_id_t module_idP); \param[in] bufflen size of phy transport block \param[out] bsr_len size of bsr control element */ -uint8_t get_bsr_len (module_id_t module_idP, uint16_t buflen); +uint8_t get_bsr_len (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint16_t buflen); /*! \fn BSR_SHORT * get_bsr_short(module_id_t module_idP, uint8_t bsr_len) \brief get short bsr level @@ -577,14 +577,14 @@ BSR_LONG * get_bsr_long(module_id_t module_idP, uint8_t bsr_len); */ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_index, uint8_t lcid, uint8_t lcgid); -/*! \fn locate (int *table, int size, int value) +/*! \fn locate_BsrIndexByBufferSize (int *table, int size, int value) \brief locate the BSR level in the table as defined in 36.321. This function requires that he values in table to be monotonic, either increasing or decreasing. The returned value is not less than 0, nor greater than n-1, where n is the size of table. \param[in] *table Pointer to BSR table \param[in] size Size of the table \param[in] value Value of the buffer \return the index in the BSR_LEVEL table */ -uint8_t locate (const uint32_t *table, int size, int value); +uint8_t locate_BsrIndexByBufferSize (const uint32_t *table, int size, int value); /*! \fn int get_sf_periodicBSRTimer(uint8_t periodicBSR_Timer) diff --git a/openair2/LAYER2/MAC/ra_procedures.c b/openair2/LAYER2/MAC/ra_procedures.c index 30137fab33..3b5734756d 100644 --- a/openair2/LAYER2/MAC/ra_procedures.c +++ b/openair2/LAYER2/MAC/ra_procedures.c @@ -391,7 +391,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP, 1); //post_padding return(&UE_mac_inst[module_idP].RA_prach_resources); - } else if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DCCH] > 0) { + } 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, diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index d5958f6e5e..c24702b3b5 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -102,13 +102,17 @@ void ue_init_mac(module_id_t module_idP) UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer_Running=0; UE_mac_inst[module_idP].scheduling_info.maxHARQ_Tx=MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; UE_mac_inst[module_idP].scheduling_info.ttiBundling=0; + UE_mac_inst[module_idP].scheduling_info.extendedBSR_Sizes_r10=0; + UE_mac_inst[module_idP].scheduling_info.extendedPHR_r10=0; UE_mac_inst[module_idP].scheduling_info.drx_config=NULL; UE_mac_inst[module_idP].scheduling_info.phr_config=NULL; UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); + UE_mac_inst[module_idP].BSR_reporting_active = 0; UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer); UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer); UE_mac_inst[module_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[module_idP].scheduling_info.PathlossChange); + UE_mac_inst[module_idP].PHR_reporting_active = 0; for (i=0; i < MAX_NUM_LCID; i++) { LOG_D(MAC,"[UE%d] Applying default logical channel config for LCGID %d\n",module_idP,i); @@ -121,7 +125,7 @@ void ue_init_mac(module_id_t module_idP) UE_mac_inst[module_idP].scheduling_info.LCGID[i]=1; } - UE_mac_inst[module_idP].scheduling_info.LCID_status[i]=0; + UE_mac_inst[module_idP].scheduling_info.LCID_status[i]=LCID_EMPTY; } #ifdef CBA @@ -306,18 +310,28 @@ uint32_t ue_get_SR(module_id_t module_idP,int CC_id,frame_t frameP,uint8_t eNB_i // initiate RA UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; + // release all pucch resource + UE_mac_inst[module_idP].physicalConfigDedicated = NULL; + UE_mac_inst[module_idP].ul_active=0; + UE_mac_inst[module_idP].BSR_reporting_active=0; + + LOG_T(MAC,"[UE %d] Release all SRs \n", module_idP); return(0); } } //------------------------------------------------------------------------------ void -ue_send_sdu(module_id_t module_idP, - uint8_t CC_id, - frame_t frameP, - uint8_t* sdu, - uint16_t sdu_len, - uint8_t eNB_index) { +ue_send_sdu( + module_id_t module_idP, + uint8_t CC_id, + frame_t frameP, + uint8_t* sdu, + uint16_t sdu_len, + uint8_t eNB_index +) +//------------------------------------------------------------------------------ +{ unsigned char rx_ces[MAX_NUM_CE],num_ce,num_sdu,i,*payload_ptr; unsigned char rx_lcids[NB_RB_MAX]; @@ -1244,11 +1258,12 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf BSR_LONG *bsr_l=&bsr_long; POWER_HEADROOM_CMD phr; POWER_HEADROOM_CMD *phr_p=&phr; - unsigned short short_padding=0, post_padding=0; + unsigned short short_padding=0, post_padding=0, padding_len=0; int lcgid; int j; // used for padding // Compute header length - + int all_pdu_len; + if (CC_id>0) { LOG_E(MAC,"Transmission on secondary CCs is not supported yet\n"); mac_xface->macphy_exit("MAC FATAL CC_id>0"); @@ -1282,19 +1297,10 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len=(buflen > 128 ) ? 3 : 2 ; //sizeof(SCH_SUBHEADER_LONG)-1 : sizeof(SCH_SUBHEADER_SHORT); bsr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); phr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); - phr_ce_len = (UE_mac_inst[module_idP].PHR_reporting_active == 1) ? 1 /* sizeof(POWER_HEADROOM_CMD)*/: 0; - if (phr_ce_len > 0) { - phr_len = phr_ce_len + phr_header_len; - LOG_D(MAC,"[UE %d] header size info: PHR len %d (ce%d,hdr%d) buff_len %d\n", - module_idP, phr_len, phr_ce_len, phr_header_len, buflen); - } else { - phr_len=0; - } - - bsr_ce_len = get_bsr_len (module_idP, buflen-phr_len); - - if (bsr_ce_len > 0 ) { + bsr_ce_len = get_bsr_len (module_idP, eNB_index, frameP, buflen); + // retxBSR-Timer expires or periodicBSR-Timer expires and Regular BSR trigger + if ((bsr_ce_len > 0 ) && (UE_mac_inst[module_idP].BSR_reporting_active > 0)) { bsr_len = bsr_ce_len + bsr_header_len; LOG_D(MAC,"[UE %d] header size info: dcch %d, dcch1 %d, dtch %d, bsr (ce%d,hdr%d) buff_len %d\n", module_idP, dcch_header_len,dcch1_header_len,dtch_header_len, bsr_ce_len, bsr_header_len, buflen); @@ -1305,6 +1311,15 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf //bsr_len = bsr_ce_len + bsr_header_len; } + phr_ce_len = (UE_mac_inst[module_idP].PHR_reporting_active == 1) ? 1 /* sizeof(POWER_HEADROOM_CMD)*/: 0; + if (phr_ce_len > 0) { + phr_len = phr_ce_len + phr_header_len; + LOG_D(MAC,"[UE %d] header size info: PHR len %d (ce%d,hdr%d) buff_len %d\n", + module_idP, phr_len, phr_ce_len, phr_header_len, buflen); + } else { + phr_len=0; + } + // check for UL bandwidth requests and add SR control element // check for UL bandwidth requests and add SR control element @@ -1338,8 +1353,12 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf sdu_lcids[0] = DCCH; LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH\n",module_idP,sdu_lengths[0]); num_sdus = 1; - update_bsr(module_idP, frameP, eNB_index, DCCH, UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]); + //update_bsr(module_idP, frameP, eNB_index, DCCH, UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]); //header_len +=2; + UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH] = LCID_EMPTY; +#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH] = rlc_status.bytes_in_buffer-sdu_lengths[0]; +#endif } else { dcch_header_len=0; num_sdus = 0; @@ -1375,9 +1394,13 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf sdu_length_total += sdu_lengths[num_sdus]; sdu_lcids[num_sdus] = DCCH1; LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH1\n",module_idP,sdu_lengths[num_sdus]); - num_sdus++; //update_bsr(module_idP, frameP, DCCH1); //dcch_header_len +=2; // include dcch1 + UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH1] = LCID_EMPTY; +#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1] = rlc_status.bytes_in_buffer-sdu_lengths[num_sdus]; +#endif + num_sdus++; } else { dcch1_header_len =0; } @@ -1388,8 +1411,9 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len+=3; dtch_header_len_last=3; + all_pdu_len = bsr_len+phr_len+dcch_header_len+dcch1_header_len+dtch_header_len+sdu_length_total; if ((UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) && - ((bsr_len+phr_len+dcch_header_len+dcch1_header_len+dtch_header_len+sdu_length_total) <= buflen)) { + (all_pdu_len <= buflen)) { // optimize the dtch header lenght //if ((UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DTCH] > 128) && @@ -1407,11 +1431,11 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf ENB_FLAG_NO, MBMS_FLAG_NO, // eNB_index lcid, - buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total); + buflen-all_pdu_len); LOG_D(MAC,"[UE %d] Frame %d : UL-DTCH -> ULSCH%d, %d bytes to send (Transport Block size %d, mac header len %d, BSR byte[%d] %d)\n", module_idP,frameP, lcid, rlc_status.bytes_in_buffer,buflen,dtch_header_len, - lcid, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcid]); + lcid, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); if (rlc_status.bytes_in_buffer > 0) { sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, @@ -1431,16 +1455,20 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len --; dtch_header_len_last --; } +#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] = rlc_status.bytes_in_buffer-sdu_lengths[num_sdus]; +#endif num_sdus++; - UE_mac_inst[module_idP].ul_active = update_bsr(module_idP, frameP, eNB_index,lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); + //UE_mac_inst[module_idP].ul_active = update_bsr(module_idP, frameP, eNB_index,lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); } else { dtch_header_len -= 3; } + UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_EMPTY; } else { // no rlc pdu : generate the dummy header dtch_header_len -= 3; } } - + lcgid= get_bsr_lcgid(module_idP); if (lcgid < 0 ) { @@ -1452,15 +1480,29 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf bsr_l->Buffer_size1 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]; bsr_l->Buffer_size2 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]; bsr_l->Buffer_size3 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]; + LOG_D(MAC, "[UE %d] Frame %d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP, UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]); + + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID0] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID1] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID2] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID3] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] = 0; } else if (bsr_ce_len == sizeof(BSR_SHORT)) { bsr_l = NULL; bsr_s->LCGID = lcgid; bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]; + + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] = 0; + LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n", module_idP, frameP, UE_mac_inst[module_idP].scheduling_info.BSR[lcgid],lcgid); } else { @@ -1494,12 +1536,14 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len_last-=1; dtch_header_len= (dtch_header_len >0)? dtch_header_len - dtch_header_len_last : dtch_header_len; } - - if ((buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total) <= 2) { - short_padding = buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total; + // 1-bit padding or 2-bit padding special padding subheader + padding_len = buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total; + if (padding_len <= 2) { + short_padding = padding_len; + // only add padding header post_padding = 0; } else { - if ((buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total) == buflen) { + if (padding_len == buflen) {// nona mac pdu *access_mode=CANCELED_ACCESS; } @@ -1544,6 +1588,9 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf module_idP,payload_offset, sdu_length_total); UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; + UE_mac_inst[module_idP].BSR_reporting_active=0; + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_OUT); stop_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu); @@ -1705,10 +1752,25 @@ ue_scheduler( // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures // outlined in Sections 5.4.4 an 5.4.5 of 36.321 - // Put this in another function + // Call BSR procedure as described in Section 5.4.5 in 36.321 + if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF == get_sf_periodicBSRTimer(MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity)) { + UE_mac_inst[module_idP].BSR_reporting_active = 1; + } else if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF <= 0 ){ + // trigger BSR and reset the timer later when the BSR report is sent + UE_mac_inst[module_idP].BSR_reporting_active = 1; + } else if (UE_mac_inst[module_idP].BSR_reporting_active == 0 ) { + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF--; + } + + if (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF <= 0){ + // trigger BSR and reset the timer later when the BSR report is sent + UE_mac_inst[module_idP].BSR_reporting_active = 1; + } else if (UE_mac_inst[module_idP].BSR_reporting_active == 0 ) { + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF--; + } // Get RLC status info and update Bj for all lcids that are active - for (lcid=DCCH; lcid <= DTCH; lcid++ ) { + for (lcid=DCCH; lcid < MAX_NUM_LCID; lcid++ ) { if ((lcid == 0) ||(UE_mac_inst[module_idP].logicalChannelConfig[lcid])) { // meausre the Bj if ((directionP == SF_UL)&& (UE_mac_inst[module_idP].scheduling_info.Bj[lcid] >= 0)) { @@ -1729,6 +1791,8 @@ ue_scheduler( if (update_bsr(module_idP,frameP, eNB_indexP, lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid])) { UE_mac_inst[module_idP].scheduling_info.SR_pending= 1; + // Regular BSR trigger + UE_mac_inst[module_idP].BSR_reporting_active = 1; LOG_D(MAC,"[UE %d][SR] Frame %d subframe %d SR for PUSCH is pending for LCGID %d with BSR level %d (%d bytes in RLC)\n", module_idP, frameP,subframeP,UE_mac_inst[module_idP].scheduling_info.LCGID[lcid], UE_mac_inst[module_idP].scheduling_info.BSR[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], @@ -1970,31 +2034,26 @@ int get_bsr_lcgid (module_id_t module_idP) } } -uint8_t get_bsr_len (module_id_t module_idP, uint16_t buflen) +uint8_t get_bsr_len (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint16_t buflen) { - - int lcgid=0; - uint8_t bsr_len=0, num_lcgid=0; + int lcid; + uint8_t bsr_len=0, num_lcid=0; int pdu = 0; + mac_rlc_status_resp_t rlc_status; - - for (lcgid=0; lcgid < MAX_NUM_LCGID; lcgid++ ) { - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 0 ) { - pdu += (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] + bsr_len + 2); //2 = sizeof(SCH_SUBHEADER_SHORT) + for (lcid=DCCH; lcid 0 ) { + pdu += rlc_status.bytes_in_buffer + sizeof(SCH_SUBHEADER_SHORT) + bsr_len; + if (rlc_status.bytes_in_buffer > 128 ) { + pdu += 1; //sizeof(SCH_SUBHEADER_LONG) + } } - - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 128 ) { // long header size: adjust the header size - pdu += 1; + if ( (pdu > buflen) && (rlc_status.bytes_in_buffer > 0 ) ) { + num_lcid +=1; + bsr_len = (num_lcid >= 2 ) ? sizeof(BSR_LONG) : sizeof(BSR_SHORT) ; } - - // current phy buff can not transport all sdu for this lcgid -> transmit a bsr for this lcgid - - if ( (pdu > buflen) && (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 0 ) ) { - num_lcgid +=1; - bsr_len = (num_lcgid >= 2 ) ? sizeof(BSR_LONG) : sizeof(BSR_SHORT) ; - } - - LOG_D(MAC,"BSR Bytes %d for lcgid %d bsr len %d num lcgid %d\n", UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid], lcgid, bsr_len, num_lcgid); + LOG_D(MAC,"LC buffer Bytes %d for lcid %d bsr len %d num lcid %d\n", rlc_status.bytes_in_buffer, lcid, bsr_len, num_lcid); } if ( bsr_len > 0 ) @@ -2004,7 +2063,6 @@ uint8_t get_bsr_len (module_id_t module_idP, uint16_t buflen) return bsr_len; } - boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_index, uint8_t lcid, uint8_t lcg_id) { @@ -2028,11 +2086,17 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in lcid, 0); - if (rlc_status.bytes_in_buffer > 0 ) { + if ((rlc_status.bytes_in_buffer > 0 ) +#if 0 //calvin for BSR test,current buffer greater then previous one, or buffer from 0 to !0 + && (rlc_status.bytes_in_buffer > UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]) +#endif + ){ + //BSR trigger SR sr_pending = TRUE; UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_NOT_EMPTY; - UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] += locate (BSR_TABLE,BSR_TABLE_SIZE, rlc_status.bytes_in_buffer); + // sum lcid buffer which has same lcgid UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id] += rlc_status.bytes_in_buffer; + UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); // UE_mac_inst[module_idP].scheduling_info.BSR_short_lcid = lcid; // only applicable to short bsr LOG_D(MAC,"[UE %d] BSR level %d (LCGID %d, rlc buffer %d byte)\n", module_idP, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id],lcg_id, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); @@ -2045,7 +2109,7 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in return sr_pending; } -uint8_t locate (const uint32_t *table, int size, int value) +uint8_t locate_BsrIndexByBufferSize (const uint32_t *table, int size, int value) { uint8_t ju, jm, jl; @@ -2076,7 +2140,7 @@ uint8_t locate (const uint32_t *table, int size, int value) if (value == table[jl]) { return jl; - } else { + } else { return jl+1; //equally ju } diff --git a/openair2/LAYER2/MAC/vars.h b/openair2/LAYER2/MAC/vars.h index 83d159f910..236439c6e5 100644 --- a/openair2/LAYER2/MAC/vars.h +++ b/openair2/LAYER2/MAC/vars.h @@ -45,6 +45,15 @@ const uint32_t BSR_TABLE[BSR_TABLE_SIZE]= {0,10,12,14,17,19,22,26,31,36,42,49,57 1326,1552,1817,2127,2490,2915,3413,3995,4677,5467,6411,7505,8787,10287,12043,14099, 16507,19325,22624,26487,31009,36304,42502,49759,58255,68201,79846,93479,109439, 128125,150000, 300000 }; +// extended bsr table--currently not used +const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE] = {0,10,13,16,19,23,29,35,43,53,65,80,98,120,147, + 181,223,274,337,414,509,625,769,945,1162,1429, + 1757,2161,2657,3267,4017,4940,6074,7469,9185, + 11294,13888,17077,20999,25822,31752,39045,48012, + 59039,72598,89272,109774,134986,165989,204111, + 250990,308634,379519,466683,573866,705666,867737, + 1067031,1312097,1613447,1984009,2439678,3000000, + 6000000}; //uint32_t EBSR_Level[63]={0,10,13,16,19,23,29,35,43,53,65,80,98,120,147,181}; From 1a99e785a06bce55cf598a0f4fbcda02f5006086 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Tue, 8 Nov 2016 03:14:01 +0100 Subject: [PATCH 276/413] remove warnings --- openair2/LAYER2/MAC/eNB_scheduler_primitives.c | 2 +- targets/RT/USER/lte-enb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 7946fdf663..5d72f6fc9d 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -1006,7 +1006,7 @@ void dump_CCE_table(int *CCE_table,const int nCCE,const unsigned short rnti,cons for (i=0;i Date: Tue, 8 Nov 2016 14:40:34 +0200 Subject: [PATCH 277/413] Added notification messages for control delegation in dl_scheduler VSF --- .../CONTROL_MODULES/MAC/flexran_agent_mac_internal.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) 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 7bfed81b48..04a90250eb 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 @@ -771,12 +771,15 @@ int load_dl_scheduler_function(mid_t mod_id, const char *function_name) { snprintf(lib_name, sizeof(lib_name), "/%s.so", function_name); strcpy(target, local_cache); strcat(target, lib_name); - + + LOG_I(FLEXRAN_AGENT, "Opening pushed code: %s\n", target); lib = dlopen(target, RTLD_NOW); if (lib == NULL) { + LOG_I(FLEXRAN_AGENT, "Could not load library\n"); goto error; } + LOG_I(FLEXRAN_AGENT, "Loading function: %s\n", function_name); void *loaded_scheduler = dlsym(lib, function_name); if (loaded_scheduler) { if (mac_agent_registered[mod_id]) { @@ -785,8 +788,10 @@ int load_dl_scheduler_function(mid_t mod_id, const char *function_name) { dlclose(agent_mac_xface[mod_id]->dl_scheduler_loaded_lib); } agent_mac_xface[mod_id]->dl_scheduler_loaded_lib = lib; - LOG_D(ENB_APP, "Delegated control for DL UE scheduler succesfully\n"); + LOG_I(FLEXRAN_AGENT, "New DL UE scheduler: %s\n", function_name); } + } else { + LOG_I(FLEXRAN_AGENT, "Scheduler could not be loaded\n"); } return 0; From 2078a9e57cedac81b105afa2814fb401a3dfafb2 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 9 Nov 2016 12:09:02 +0200 Subject: [PATCH 278/413] Added macros for enabling FlexRAN agent operation --- openair1/SCHED/phy_procedures_lte_eNb.c | 4 ++++ openair2/LAYER2/MAC/eNB_scheduler.c | 9 +++++++++ openair2/RRC/LITE/rrc_eNB.c | 7 +++++++ 3 files changed, 20 insertions(+) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index d6f5a40da7..dbc90b34d9 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -62,10 +62,12 @@ #endif +#if defined(FLEXRAN_AGENT_SB_IF) //Agent-related headers #include "ENB_APP/flexran_agent_extern.h" #include "ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h" #include "LAYER2/MAC/flexran_agent_mac_proto.h" +#endif //#define DIAG_PHY @@ -1369,11 +1371,13 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, eNB->dlsch_ra->active = 0; } +#if defined(FLEXRAN_AGENT_SB_IF) #ifndef DISABLE_SF_TRIGGER //Send subframe trigger to the controller if (mac_agent_registered[eNB->Mod_id]) { agent_mac_xface[eNB->Mod_id]->flexran_agent_send_sf_trigger(eNB->Mod_id); } +#endif #endif // Now scan UE specific DLSCH diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 386efec596..c5dc8c88b0 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -52,10 +52,12 @@ //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" +#if defined(FLEXRAN_AGENT_SB_IF) //Agent-related headers #include "flexran_agent_extern.h" #include "flexran_agent_mac.h" #include "flexran_agent_mac_proto.h" +#endif #if defined(ENABLE_ITTI) # include "intertask_interface.h" @@ -103,7 +105,9 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, void *DLSCH_dci=NULL; int size_bits=0,size_bytes=0; +#if defined(FLEXRAN_AGENT_SB_IF) Protocol__FlexranMessage *msg; +#endif LOG_D(MAC,"[eNB %d] Frame %d, Subframe %d, entering MAC scheduler (UE_list->head %d)\n",module_idP, frameP, subframeP,UE_list->head); @@ -137,14 +141,17 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, eNB_mac_inst[module_idP].UE_list.UE_sched_ctrl[i].cqi_req_timer++; + if (mac_xface->get_eNB_UE_stats(module_idP, CC_id, rnti)==NULL) { //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, rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); } +#endif } else { // check uplink failure @@ -1081,11 +1088,13 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, for (CC_id=0;CC_idflexran_agent_send_update_mac_stats(module_idP); } +#endif #endif /* diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 3f8e7c5f83..2ce94ba26c 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -93,7 +93,9 @@ #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 @@ -4541,12 +4543,14 @@ rrc_eNB_decode_dcch( ue_context_p, ul_dcch_msg->message.choice.c1.choice.rrcConnectionReconfigurationComplete.rrc_TransactionIdentifier); +#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, ue_context_p->ue_id_rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_UPDATED); } +#endif } #if defined(ENABLE_ITTI) # if defined(ENABLE_USE_MME) @@ -4642,12 +4646,15 @@ rrc_eNB_decode_dcch( ue_context_p->ue_context.Status = RRC_CONNECTED; LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_CONNECTED \n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); + +#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, ue_context_p->ue_id_rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED); } +#endif } } From bb5b90eab0029cc273720516943cce490eaac376 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 9 Nov 2016 12:09:44 +0200 Subject: [PATCH 279/413] Added compilation options for enabling/disabling FlexRAN agent --- cmake_targets/CMakeLists.txt | 15 +++++++++++++-- cmake_targets/build_oai | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index da90efdaee..b5279de5e2 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -621,7 +621,7 @@ add_boolean_option(MESSAGE_CHART_GENERATOR False "For generating sequenc add_boolean_option(MESSAGE_CHART_GENERATOR_RLC_MAC False "trace RLC-MAC exchanges in sequence diagrams") add_boolean_option(MESSAGE_CHART_GENERATOR_PHY False "trace some PHY exchanges in sequence diagrams") -add_boolean_option(FLEXRAN_AGENT_SB_IF True "enable FlexRAN agent to inteface with a SDN contrller") +add_boolean_option(FLEXRAN_AGENT_SB_IF False "enable FlexRAN agent to inteface with a SDN controller") ######################## # Include order @@ -1185,10 +1185,17 @@ set (MAC_SRC ${MAC_DIR}/eNB_scheduler_RA.c ${MAC_DIR}/pre_processor.c ${MAC_DIR}/config.c + ) + +if (FLEXRAN_AGENT_SB_IF) + +set (MAC_SRC ${MAC_SRC} ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue.c ${MAC_DIR}/flexran_agent_scheduler_dataplane.c ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue_remote.c - ) +) + +endif() set (ENB_APP_SRC ${OPENAIR2_DIR}/ENB_APP/enb_app.c @@ -1201,10 +1208,14 @@ add_library(L2 ${ENB_APP_SRC}) # ${OPENAIR2_DIR}/RRC/L2_INTERFACE/openair_rrc_L2_interface.c) +if (FLEXRAN_AGENT_SB_IF) + #Test for adding a shared library add_library(default_sched SHARED ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue.c) add_library(remote_sched SHARED ${MAC_DIR}/flexran_agent_scheduler_dlsch_ue_remote.c) +endif() + # L3 Libs ########################## diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index b77a9baa56..25e9a1ccc8 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -35,6 +35,7 @@ source $THIS_SCRIPT_PATH/tools/build_helper MSC_GEN="False" XFORMS="True" +FLEXRAN_AGENT_SB_IF="True" PRINT_STATS="False" VCD_TIMING="False" DEADLINE_SCHEDULER_FLAG_USER="False" @@ -83,6 +84,8 @@ Options Makes the UE specific parts (ue_ip, usim, nvram) --RRH Makes the RRH +-a | --agent + Enables agent for software-defined control of the eNB -r | --3gpp-release default is Rel10, Rel8 limits the implementation to 3GPP Release 8 version @@ -169,6 +172,10 @@ function main() { eNB=1 echo_info "Will compile eNB" shift;; + -a | --agent) + FLEXRAN_AGENT=1 + echo_info "Will compile eNB with agent support" + shift;; --UE) UE=1 echo_info "Will compile UE" @@ -439,6 +446,9 @@ function main() { echo "set ( CMAKE_BUILD_TYPE $CMAKE_BUILD_TYPE )" >> $cmake_file echo "set ( CFLAGS_PROCESSOR_USER \"$CFLAGS_PROCESSOR_USER\" )" >> $cmake_file echo "set ( XFORMS $XFORMS )" >> $cmake_file + if [ "$FLEXRAN_AGENT" = "1" ] ; then + echo "set ( FLEXRAN_AGENT_SB_IF $FLEXRAN_AGENT_SB_IF )" >> $cmake_file + fi echo "set ( RRC_ASN1_VERSION \"${REL}\")" >> $cmake_file echo "set ( ENABLE_VCD_FIFO $VCD_TIMING )" >> $cmake_file echo "set ( RF_BOARD \"${HW}\")" >> $cmake_file @@ -581,6 +591,9 @@ function main() { echo "set ( CMAKE_BUILD_TYPE $CMAKE_BUILD_TYPE )" >> $cmake_file echo "set ( CFLAGS_PROCESSOR_USER \"$CFLAGS_PROCESSOR_USER\" )" >> $cmake_file echo "set ( XFORMS $XFORMS )" >> $cmake_file + if [ "$FLEXRAN_AGENT" = "1" ] ; then + echo "set ( FLEXRAN_AGENT_SB_IF $FLEXRAN_AGENT_SB_IF )" >> $cmake_file + fi echo "set ( PRINT_STATS $PRINT_STATS )" >> $cmake_file echo "set ( RRC_ASN1_VERSION \"${REL}\")" >> $cmake_file echo "set ( ENABLE_VCD_FIFO $VCD_TIMING )" >> $cmake_file @@ -649,6 +662,9 @@ function main() { cp $DIR/oaisim_mme_build_oai/CMakeLists.template $cmake_file echo "set ( CMAKE_BUILD_TYPE $CMAKE_BUILD_TYPE )" >> $cmake_file echo "set ( XFORMS $XFORMS )" >> $cmake_file + if [ "$FLEXRAN_AGENT" = "1" ] ; then + echo "set ( FLEXRAN_AGENT_SB_IF $FLEXRAN_AGENT_SB_IF )" >> $cmake_file + fi echo "set ( RRC_ASN1_VERSION \"${REL}\")" >> $cmake_file echo "set ( ENABLE_VCD_FIFO $VCD_TIMING )" >> $cmake_file echo "set ( T_TRACER $T_TRACER )" >> $cmake_file From 985dcdc38cbb7f03ddf12ba801e996355564a8a8 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 9 Nov 2016 12:11:26 +0200 Subject: [PATCH 280/413] Removed deprecated configuration files for FlexRAN agent --- .../CONF/enb.band5.agent.usrpb210.conf | 180 ----------- .../enb.band5.agent.usrpb210.epc.remote.conf | 176 ---------- .../CONF/enb.band7.agent.oaisim.2.enb.conf | 302 ------------------ .../enb.band7.agent.oaisim.local_no_mme.conf | 154 --------- .../enb.band7.agent.usrpb210.epc.remote.conf | 174 ---------- 5 files changed, 986 deletions(-) delete mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.conf delete mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf delete mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.2.enb.conf delete mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf delete mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.usrpb210.epc.remote.conf diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.conf deleted file mode 100644 index caf54b5541..0000000000 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.conf +++ /dev/null @@ -1,180 +0,0 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); -# Asn1_verbosity, choice in: none, info, annoying -Asn1_verbosity = "none"; - -eNBs = -( - { - ////////// Identification parameters: - eNB_ID = 0xe00; - - cell_type = "CELL_MACRO_ENB"; - - eNB_name = "eNB_Eurecom_LTEBox"; - - // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = "1"; - - mobile_country_code = "208"; - - mobile_network_code = "95"; - - ////////// Physical parameters: - - component_carriers = ( - { - frame_type = "FDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 5; - downlink_frequency = 879000000L; - uplink_frequency_offset = -45000000; - Nid_cell = 0; - N_RB_DL = 25; - Nid_cell_mbsfn = 0; - nb_antenna_ports = 1; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - tx_gain = 90; - rx_gain = 125; - prach_root = 0; - prach_config_index = 0; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 1; - prach_freq_offset = 2; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = -29; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 0; - pusch_groupHoppingEnabled = "ENABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 1; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =;*/ - - pusch_p0_Nominal = -90; - pusch_alpha = "AL1"; - pucch_p0_Nominal = -96; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 64; - rach_preamblesGroupAConfig = "DISABLE"; - /* - rach_sizeOfRA_PreamblesGroupA = ; - rach_messageSizeGroupA = ; - rach_messagePowerOffsetGroupB = ; - */ - rach_powerRampingStep = 4; - rach_preambleInitialReceivedTargetPower = -108; - rach_preambleTransMax = 10; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - - ue_TransmissionMode = 1; - } - ); - - srb1_parameters : - { - # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] - timer_poll_retransmit = 80; - - # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] - timer_reordering = 35; - - # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] - timer_status_prohibit = 0; - - # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] - poll_pdu = 4; - - # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] - poll_byte = 99999; - - # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] - max_retx_threshold = 4; - } - - # ------- SCTP definitions - SCTP : - { - # Number of streams to use in input/output - SCTP_INSTREAMS = 2; - SCTP_OUTSTREAMS = 2; - }; - - ////////// MME parameters: - mme_ip_address = ( { ipv4 = "192.168.100.101"; - ipv6 = "192:168:100::17"; - active = "yes"; - preference = "ipv4"; - } - ); - - NETWORK_INTERFACES : - { - ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.106/24"; - - ENB_INTERFACE_NAME_FOR_S1U = "eth0"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.106/24"; - ENB_PORT_FOR_S1U = 2152; # Spec 2152 - }; - - NETWORK_CONTROLLER : - { - ENB_AGENT_INTERFACE_NAME = "eth1"; - ENB_AGENT_IPV4_ADDRESS = "10.0.2.5/30"; - ENB_AGENT_PORT = 2210; - ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; - }; - - - log_config : - { - global_log_level ="info"; - global_log_verbosity ="medium"; - hw_log_level ="info"; - hw_log_verbosity ="medium"; - phy_log_level ="info"; - phy_log_verbosity ="medium"; - mac_log_level ="info"; - mac_log_verbosity ="high"; - rlc_log_level ="info"; - rlc_log_verbosity ="medium"; - pdcp_log_level ="info"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="info"; - rrc_log_verbosity ="medium"; - }; - } -); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf deleted file mode 100644 index e8bb16f2c8..0000000000 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band5.agent.usrpb210.epc.remote.conf +++ /dev/null @@ -1,176 +0,0 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); -# Asn1_verbosity, choice in: none, info, annoying -Asn1_verbosity = "none"; - -eNBs = -( - { - ////////// Identification parameters: - eNB_ID = 0xe00; - - cell_type = "CELL_MACRO_ENB"; - - eNB_name = "eNB_Eurecom_LTEBox"; - - // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = "10"; - - mobile_country_code = "208"; - mobile_network_code = "95"; - - ////////// Physical parameters: - - component_carriers = ( - { - frame_type = "FDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 5; - downlink_frequency = 879000000L; - uplink_frequency_offset = -45000000; - Nid_cell = 0; - N_RB_DL = 25; - Nid_cell_mbsfn = 0; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - tx_gain = 90; - rx_gain = 115; - prach_root = 0; - prach_config_index = 0; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 1; - prach_freq_offset = 2; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = -26; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 0; - pusch_groupHoppingEnabled = "ENABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 1; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =;*/ - - pusch_p0_Nominal = -90; - pusch_alpha = "AL1"; - pucch_p0_Nominal = -108; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 64; - rach_preamblesGroupAConfig = "DISABLE"; -/* - rach_sizeOfRA_PreamblesGroupA = ; - rach_messageSizeGroupA = ; - rach_messagePowerOffsetGroupB = ; -*/ - rach_powerRampingStep = 4; - rach_preambleInitialReceivedTargetPower = -108; - rach_preambleTransMax = 10; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - - } - ); - - - srb1_parameters : - { - # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] - timer_poll_retransmit = 80; - - # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] - timer_reordering = 35; - - # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] - timer_status_prohibit = 0; - - # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] - poll_pdu = 4; - - # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] - poll_byte = 99999; - - # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] - max_retx_threshold = 4; - } - - # ------- SCTP definitions - SCTP : - { - # Number of streams to use in input/output - SCTP_INSTREAMS = 2; - SCTP_OUTSTREAMS = 2; - }; - - ////////// MME parameters: - mme_ip_address = ( {ipv4 = "192.168.100.102"; - ipv6="192:168:30::17"; - active="yes"; - preference="ipv4";}); - - NETWORK_INTERFACES : - { - ENB_INTERFACE_NAME_FOR_S1_MME = "eth2:1"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.103/24"; - - ENB_INTERFACE_NAME_FOR_S1U = "eth2:1"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.103/24"; - ENB_PORT_FOR_S1U = 2152; # Spec 2152 - }; - - NETWORK_CONTROLLER : - { - ENB_AGENT_INTERFACE_NAME = "eth0"; - ENB_AGENT_IPV4_ADDRESS = "10.0.0.5/30"; - ENB_AGENT_PORT = 2210; - ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; - }; - - log_config : - { - global_log_level ="info"; - global_log_verbosity ="medium"; - hw_log_level ="info"; - hw_log_verbosity ="medium"; - phy_log_level ="info"; - phy_log_verbosity ="medium"; - mac_log_level ="debug"; - mac_log_verbosity ="high"; - rlc_log_level ="info"; - rlc_log_verbosity ="medium"; - pdcp_log_level ="info"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="info"; - rrc_log_verbosity ="medium"; - }; - - } -); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.2.enb.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.2.enb.conf deleted file mode 100644 index c792961a18..0000000000 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.2.enb.conf +++ /dev/null @@ -1,302 +0,0 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox1", "eNB_Eurecom_LTEBox"); -# Asn1_verbosity, choice in: none, info, annoying -Asn1_verbosity = "none"; - -eNBs = -( - { - ////////// Identification parameters: - eNB_ID = 0x00; - - cell_type = "CELL_MACRO_ENB"; - - eNB_name = "eNB_Eurecom_LTEBox"; - - // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = "1"; - - mobile_country_code = "208"; - - mobile_network_code = "10"; - - ////////// Physical parameters: - - component_carriers = ( - { - frame_type = "FDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 7; - downlink_frequency = 2680000000L; - uplink_frequency_offset = -120000000; - Nid_cell = 0; - N_RB_DL = 50; - Nid_cell_mbsfn = 0; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - tx_gain = 25; - rx_gain = 20; - prach_root = 0; - prach_config_index = 0; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 1; - prach_freq_offset = 2; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = 0; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 0; - pusch_groupHoppingEnabled = "ENABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 0; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =;*/ - - pusch_p0_Nominal = -108; - pusch_alpha = "AL1"; - pucch_p0_Nominal = -108; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 64; - rach_preamblesGroupAConfig = "DISABLE"; - /* - rach_sizeOfRA_PreamblesGroupA = ; - rach_messageSizeGroupA = ; - rach_messagePowerOffsetGroupB = ; - */ - rach_powerRampingStep = 2; - rach_preambleInitialReceivedTargetPower = -100; - rach_preambleTransMax = 10; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - } - ); - - ////////// MME parameters: - mme_ip_address = ( { ipv4 = "192.168.100.102"; - ipv6 = "0::0"; - active = "yes"; - preference = "ipv4"; - } - ); - - NETWORK_INTERFACES : - { - ENB_INTERFACE_NAME_FOR_S1_MME = "eth2:1"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.103/24"; - - ENB_INTERFACE_NAME_FOR_S1U = "eth2:1"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.103/24"; - ENB_PORT_FOR_S1U = 2153; # Spec 2152 - }; - - NETWORK_CONTROLLER : - { - ENB_AGENT_INTERFACE_NAME = "eth0"; - ENB_AGENT_IPV4_ADDRESS = "10.0.0.5/30"; - ENB_AGENT_PORT = 2210; - ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; - }; - - log_config : - { - global_log_level ="trace"; - global_log_verbosity ="medium"; - hw_log_level ="info"; - hw_log_verbosity ="medium"; - phy_log_level ="trace"; - phy_log_verbosity ="medium"; - mac_log_level ="trace"; - mac_log_verbosity ="medium"; - rlc_log_level ="trace"; - rlc_log_verbosity ="medium"; - pdcp_log_level ="trace"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="trace"; - rrc_log_verbosity ="medium"; - gtpu_log_level ="debug"; - gtpu_log_verbosity ="medium"; - udp_log_level ="debug"; - udp_log_verbosity ="medium"; - osa_log_level ="debug"; - osa_log_verbosity ="low"; - }; - - }, - - { - ////////// Identification parameters: - eNB_ID = 0x01; - - cell_type = "CELL_MACRO_ENB"; - - eNB_name = "eNB_Eurecom_LTEBox1"; - - // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = "1"; - - mobile_country_code = "208"; - - mobile_network_code = "10"; - - ////////// Physical parameters: - - component_carriers = ( - { - frame_type = "FDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 7; - downlink_frequency = 2680000000L; - uplink_frequency_offset = -120000000; - Nid_cell = 10; - N_RB_DL = 25; - Nid_cell_mbsfn = 0; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - tx_gain = 25; - rx_gain = 20; - prach_root = 0; - prach_config_index = 0; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 1; - prach_freq_offset = 2; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = 0; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 0; - pusch_groupHoppingEnabled = "ENABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 0; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =;*/ - - pusch_p0_Nominal = -108; - pusch_alpha = "AL1"; - pucch_p0_Nominal = -108; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 64; - rach_preamblesGroupAConfig = "DISABLE"; - /* - rach_sizeOfRA_PreamblesGroupA = ; - rach_messageSizeGroupA = ; - rach_messagePowerOffsetGroupB = ; - */ - rach_powerRampingStep = 2; - rach_preambleInitialReceivedTargetPower = -100; - rach_preambleTransMax = 10; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - } - ); - - ////////// MME parameters: - mme_ip_address = ( { ipv4 = "192.168.100.102"; - ipv6 = "0::0"; - active = "yes"; - preference = "ipv4"; - } - ); - - NETWORK_INTERFACES : - { - ENB_INTERFACE_NAME_FOR_S1_MME = "eth2:2"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.104/24"; - - ENB_INTERFACE_NAME_FOR_S1U = "eth2:2"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.104/24"; - ENB_PORT_FOR_S1U = 2153; # Spec 2152 - }; - - NETWORK_CONTROLLER : - { - ENB_AGENT_INTERFACE_NAME = "eth0"; - ENB_AGENT_IPV4_ADDRESS = "10.0.0.5/30"; - ENB_AGENT_PORT = 2210; - ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; - }; - - log_config : - { - global_log_level ="trace"; - global_log_verbosity ="medium"; - hw_log_level ="info"; - hw_log_verbosity ="medium"; - phy_log_level ="trace"; - phy_log_verbosity ="medium"; - mac_log_level ="trace"; - mac_log_verbosity ="medium"; - rlc_log_level ="trace"; - rlc_log_verbosity ="medium"; - pdcp_log_level ="trace"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="trace"; - rrc_log_verbosity ="medium"; - gtpu_log_level ="debug"; - gtpu_log_verbosity ="medium"; - udp_log_level ="debug"; - udp_log_verbosity ="medium"; - osa_log_level ="debug"; - osa_log_verbosity ="low"; - }; - - } -); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf deleted file mode 100644 index f95cfd9389..0000000000 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.oaisim.local_no_mme.conf +++ /dev/null @@ -1,154 +0,0 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); -# Asn1_verbosity, choice in: none, info, annoying -Asn1_verbosity = "none"; - -eNBs = -( - { - ////////// Identification parameters: - eNB_ID = 0xe00; - - cell_type = "CELL_MACRO_ENB"; - - eNB_name = "eNB_Eurecom_LTEBox"; - - // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = "1"; - - mobile_country_code = "208"; - - mobile_network_code = "10"; - - ////////// Physical parameters: - - component_carriers = ( - { - frame_type = "FDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 7; - downlink_frequency = 2680000000L; - uplink_frequency_offset = -120000000; - Nid_cell = 0; - N_RB_DL = 25; - Nid_cell_mbsfn = 0; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - tx_gain = 25; - rx_gain = 20; - prach_root = 0; - prach_config_index = 0; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 1; - prach_freq_offset = 2; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = 0; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 0; - pusch_groupHoppingEnabled = "ENABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 0; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =;*/ - - pusch_p0_Nominal = -108; - pusch_alpha = "AL1"; - pucch_p0_Nominal = -108; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 64; - rach_preamblesGroupAConfig = "DISABLE"; - /* - rach_sizeOfRA_PreamblesGroupA = ; - rach_messageSizeGroupA = ; - rach_messagePowerOffsetGroupB = ; - */ - rach_powerRampingStep = 2; - rach_preambleInitialReceivedTargetPower = -100; - rach_preambleTransMax = 10; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - } - ); - - ////////// MME parameters: - mme_ip_address = ( { ipv4 = "0.0.0.0"; - ipv6 = "0::0"; - active = "yes"; - preference = "ipv4"; - } - ); - - NETWORK_INTERFACES : - { - ENB_INTERFACE_NAME_FOR_S1_MME = "none"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "0.0.0.0/24"; - - ENB_INTERFACE_NAME_FOR_S1U = "none"; - ENB_IPV4_ADDRESS_FOR_S1U = "0.0.0.0/24"; - ENB_PORT_FOR_S1U = 2153; # Spec 2152 - }; - - NETWORK_CONTROLLER : - { - ENB_AGENT_INTERFACE_NAME = "eth0"; - ENB_AGENT_IPV4_ADDRESS = "127.0.0.1/24"; - ENB_AGENT_PORT = 2210; - ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; - }; - - log_config : - { - global_log_level ="trace"; - global_log_verbosity ="medium"; - hw_log_level ="info"; - hw_log_verbosity ="medium"; - phy_log_level ="trace"; - phy_log_verbosity ="medium"; - mac_log_level ="trace"; - mac_log_verbosity ="medium"; - rlc_log_level ="trace"; - rlc_log_verbosity ="medium"; - pdcp_log_level ="trace"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="trace"; - rrc_log_verbosity ="medium"; - gtpu_log_level ="debug"; - gtpu_log_verbosity ="medium"; - udp_log_level ="debug"; - udp_log_verbosity ="medium"; - osa_log_level ="debug"; - osa_log_verbosity ="low"; - }; - - } -); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.usrpb210.epc.remote.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.usrpb210.epc.remote.conf deleted file mode 100644 index 939832af45..0000000000 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.agent.usrpb210.epc.remote.conf +++ /dev/null @@ -1,174 +0,0 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); -# Asn1_verbosity, choice in: none, info, annoying -Asn1_verbosity = "none"; - -eNBs = -( - { - ////////// Identification parameters: - eNB_ID = 0xe00; - - cell_type = "CELL_MACRO_ENB"; - - eNB_name = "eNB_Eurecom_LTEBox"; - - // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = "10"; - - mobile_country_code = "208"; - mobile_network_code = "95"; - - ////////// Physical parameters: - - component_carriers = ( - { - frame_type = "FDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 7; - downlink_frequency = 2660000000L; - uplink_frequency_offset = -120000000; - Nid_cell = 0; - N_RB_DL = 50; - Nid_cell_mbsfn = 0; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - tx_gain = 90; - rx_gain = 125; - prach_root = 0; - prach_config_index = 0; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 1; - prach_freq_offset = 2; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = -26; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 0; - pusch_groupHoppingEnabled = "ENABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 1; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =;*/ - - pusch_p0_Nominal = -90; - pusch_alpha = "AL1"; - pucch_p0_Nominal = -108; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 64; - rach_preamblesGroupAConfig = "DISABLE"; - /* - rach_sizeOfRA_PreamblesGroupA = ; - rach_messageSizeGroupA = ; - rach_messagePowerOffsetGroupB = ; - */ - rach_powerRampingStep = 4; - rach_preambleInitialReceivedTargetPower = -108; - rach_preambleTransMax = 10; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - } - ); - - srb1_parameters : - { - # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] - timer_poll_retransmit = 80; - - # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] - timer_reordering = 35; - - # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] - timer_status_prohibit = 0; - - # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] - poll_pdu = 4; - - # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] - poll_byte = 99999; - - # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] - max_retx_threshold = 4; - } - - # ------- SCTP definitions - SCTP : - { - # Number of streams to use in input/output - SCTP_INSTREAMS = 2; - SCTP_OUTSTREAMS = 2; - }; - - ////////// MME parameters: - mme_ip_address = ( {ipv4 = "192.168.100.102"; - ipv6="192:168:30::17"; - active="yes"; - preference="ipv4";}); - - NETWORK_INTERFACES : - { - ENB_INTERFACE_NAME_FOR_S1_MME = "eth2:1"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.100.103/24"; - - ENB_INTERFACE_NAME_FOR_S1U = "eth2:1"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.100.103/24"; - ENB_PORT_FOR_S1U = 2152; # Spec 2152 - }; - - NETWORK_CONTROLLER : - { - ENB_AGENT_INTERFACE_NAME = "eth0"; - ENB_AGENT_IPV4_ADDRESS = "10.0.0.5/30"; - ENB_AGENT_PORT = 2210; - ENB_AGENT_CACHE = "/mnt/oai_agent_cache"; - }; - - log_config : - { - global_log_level ="info"; - global_log_verbosity ="medium"; - hw_log_level ="info"; - hw_log_verbosity ="medium"; - phy_log_level ="info"; - phy_log_verbosity ="medium"; - mac_log_level ="debug"; - mac_log_verbosity ="high"; - rlc_log_level ="info"; - rlc_log_verbosity ="medium"; - pdcp_log_level ="info"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="info"; - rrc_log_verbosity ="medium"; - }; - - } -); From ea4f2948fd87cfe61477b3637e83c5069fd931de Mon Sep 17 00:00:00 2001 From: GabrirelCouturier Date: Wed, 9 Nov 2016 16:58:11 +0100 Subject: [PATCH 281/413] [OAI-UE] fix for issue#19: DCI0 detction with wrong RIV --- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 3624d67af1..fc307655dd 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -6384,8 +6384,10 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, if (rballoc > RIV_max) { - LOG_E(PHY,"frame %d, subframe %d, rnti %x, format %d: FATAL ERROR: generate_ue_ulsch_params_from_dci, rb_alloc > RIV_max\n", - proc->frame_rx, subframe, rnti, dci_format); + LOG_E(PHY,"frame %d, subframe %d, rnti %x, format %d: FATAL ERROR: generate_ue_ulsch_params_from_dci, rb_alloc[%d] > RIV_max[%d]\n", + proc->frame_rx, subframe, rnti, dci_format,rballoc,RIV_max); + LOG_E(PHY,"Wrong DCI0 detection, do not transmit PUSCH for HARQID: %d\n",harq_pid); + ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 0; return(-1); } From 0362cb86446dffc343de3fdb6b6363fffc7948cf Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Thu, 10 Nov 2016 18:09:09 +0100 Subject: [PATCH 282/413] Update rru.band7.tm1.if5.usrpb210.conf --- .../GENERIC-LTE-EPC/CONF/rru.band7.tm1.if5.usrpb210.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.if5.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.if5.usrpb210.conf index 8e1e1441bf..5634279570 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.if5.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.if5.usrpb210.conf @@ -38,6 +38,7 @@ eNBs = Nid_cell_mbsfn = 0; nb_antennas_tx = 1; nb_antennas_rx = 1; + nb_antenna_ports = 1; tx_gain = 90; rx_gain = 125; prach_root = 0; From 58284f60e7ddaa3fe4b0900f04cc339f1907ea89 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Thu, 10 Nov 2016 18:10:21 +0100 Subject: [PATCH 283/413] Update rru.band7.tm1.if5.usrpb210.conf --- .../GENERIC-LTE-EPC/CONF/rru.band7.tm1.if5.usrpb210.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.if5.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.if5.usrpb210.conf index 5634279570..805bb1aba8 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.if5.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.if5.usrpb210.conf @@ -101,6 +101,7 @@ eNBs = ue_TimersAndConstants_t311 = 10000; ue_TimersAndConstants_n310 = 20; ue_TimersAndConstants_n311 = 1; + ue_TransmissionMode = 1; } ); From ad8b86d93a439d467a9f8d9d5181acd4a5bf076a Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Thu, 10 Nov 2016 18:11:19 +0100 Subject: [PATCH 284/413] Update rcc.band7.tm1.if5.usrpb210.conf --- .../GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if5.usrpb210.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if5.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if5.usrpb210.conf index 191071d18c..868e499de6 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if5.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.if5.usrpb210.conf @@ -38,6 +38,7 @@ eNBs = Nid_cell_mbsfn = 0; nb_antennas_tx = 1; nb_antennas_rx = 1; + nb_antenna_ports = 1; tx_gain = 90; rx_gain = 125; prach_root = 0; @@ -100,6 +101,7 @@ eNBs = ue_TimersAndConstants_t311 = 10000; ue_TimersAndConstants_n310 = 20; ue_TimersAndConstants_n311 = 1; + ue_TransmissionMode = 1; } ); From 09f149d86b44ffccf956879ed2988446339ae572 Mon Sep 17 00:00:00 2001 From: calvin wang Date: Fri, 11 Nov 2016 18:01:39 +0800 Subject: [PATCH 285/413] Stabilization UE BSR feature --- openair2/LAYER2/MAC/config.c | 34 ++- openair2/LAYER2/MAC/defs.h | 27 ++- openair2/LAYER2/MAC/extern.h | 2 + openair2/LAYER2/MAC/proto.h | 4 +- openair2/LAYER2/MAC/ra_procedures.c | 2 +- openair2/LAYER2/MAC/ue_procedures.c | 341 +++++++++++++++++++++------- openair2/LAYER2/MAC/vars.h | 9 + 7 files changed, 329 insertions(+), 90 deletions(-) diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 3fbcadafbb..2a6390740c 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -69,7 +69,10 @@ void ue_mac_reset(module_id_t module_idP,uint8_t eNB_index) // cancel all pending SRs UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; - + UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR]=0; + UE_mac_inst[module_idP].BSR_reporting_active[PADDING_BSR]=0; + UE_mac_inst[module_idP].BSR_reporting_active[PERIODIC_BSR]=0; + UE_mac_inst[module_idP].retxBSRTimer_expires_flag = 0; // stop ongoing RACH procedure // discard explicitly signaled ra_PreambleIndex and ra_RACH_MaskIndex, if any @@ -228,10 +231,34 @@ rrc_mac_config_req( UE_mac_inst[Mod_idP].scheduling_info.sr_ProhibitTimer = (uint16_t) 0; } + if (mac_MainConfig->ext2 && mac_MainConfig->ext2->mac_MainConfig_v1020) { + if (mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10) { + UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t) *mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10; + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t)0; + } + if (mac_MainConfig->ext2->mac_MainConfig_v1020->extendedPHR_r10) { + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t) *mac_MainConfig->ext2->mac_MainConfig_v1020->extendedPHR_r10; + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t)0; + } + } else { + UE_mac_inst[Mod_idP].scheduling_info.extendedBSR_Sizes_r10 = (uint16_t)0; + UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t)0; + } #endif - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer); - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer); + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = 0xFFFF; + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = 0xFFFF; + UE_mac_inst[Mod_idP].BSR_reporting_active[REGULAR_BSR]=0; + UE_mac_inst[Mod_idP].BSR_reporting_active[PADDING_BSR]=0; + UE_mac_inst[Mod_idP].BSR_reporting_active[PERIODIC_BSR]=0; + UE_mac_inst[Mod_idP].retxBSRTimer_expires_flag = 0; + LOG_D(MAC,"[UE %d]: periodic BSR %d (SF), retx BSR %d (SF)\n", + Mod_idP, + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF, + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF); + UE_mac_inst[Mod_idP].scheduling_info.drx_config = mac_MainConfig->drx_Config; UE_mac_inst[Mod_idP].scheduling_info.phr_config = mac_MainConfig->phr_Config; @@ -252,6 +279,7 @@ rrc_mac_config_req( UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[Mod_idP].scheduling_info.periodicPHR_Timer); UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[Mod_idP].scheduling_info.prohibitPHR_Timer); UE_mac_inst[Mod_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[Mod_idP].scheduling_info.PathlossChange); + UE_mac_inst[Mod_idP].PHR_reporting_active = 0; LOG_D(MAC,"[UE %d] config PHR (%d): periodic %d (SF) prohibit %d (SF) pathlosschange %d (db) \n", Mod_idP, (mac_MainConfig->phr_Config)?mac_MainConfig->phr_Config->present:-1, diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 2235c3e1c4..bfaaa3ca1d 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -336,6 +336,14 @@ typedef struct { #define SHORT_BSR 29 /*!\brief LCID of long BSR for ULSCH */ #define LONG_BSR 30 +/*!\brief first level bsr type for ULSCH: Regular BSR,Padding BSR,Periodic BSR*/ +#define BSR_TYPE_FIRST_LEVEL 3 +/*!\brief first level bsr type states*/ +typedef enum { + REGULAR_BSR =0, + PADDING_BSR, + PERIODIC_BSR +} UE_FIRST_LEVEL_BSR_TYPE; /*! \brief Downlink SCH PDU Structure */ typedef struct { @@ -945,8 +953,10 @@ typedef enum { typedef struct { /// buffer status for each lcgid uint8_t BSR[MAX_NUM_LCGID]; // should be more for mesh topology - /// keep the number of bytes in rlc buffer for each lcid + /// keep the number of bytes in rlc buffer for each lcgid uint16_t BSR_bytes[MAX_NUM_LCGID]; + /// after multiplexing buffer remain for each lcid + uint16_t LCID_buffer_remain[MAX_NUM_LCID]; /// buffer status for each lcid uint8_t LCID_status[MAX_NUM_LCID]; /// SR pending as defined in 36.321 @@ -958,11 +968,11 @@ typedef struct { /// retxBSR-Timer, default value is sf2560 uint16_t retxBSR_Timer; /// retxBSR_SF, number of subframe before triggering a regular BSR - int16_t retxBSR_SF; + int16_t retxBSR_SF; // if value equal oxFFFF means counters are NOT active /// periodicBSR-Timer, default to infinity uint16_t periodicBSR_Timer; /// periodicBSR_SF, number of subframe before triggering a periodic BSR - int16_t periodicBSR_SF; + int16_t periodicBSR_SF; // if value equal oxFFFF means counters are NOT active /// default value is 0: not configured uint16_t sr_ProhibitTimer; /// sr ProhibitTime running @@ -987,6 +997,12 @@ typedef struct { int16_t prohibitPHR_SF; ///DL Pathloss Change in db uint16_t PathlossChange_db; + + /// default value is false + uint16_t extendedBSR_Sizes_r10; + /// default value is false + uint16_t extendedPHR_r10; + //Bj bucket usage per lcid int16_t Bj[MAX_NUM_LCID]; // Bucket size per lcid @@ -1074,6 +1090,11 @@ typedef struct { uint8_t PHR_reporting_active; /// power backoff due to power management (as allowed by P-MPRc) for this cell uint8_t power_backoff_db[NUMBER_OF_eNB_MAX]; + /// BSR report falg management + uint8_t BSR_reporting_active[BSR_TYPE_FIRST_LEVEL]; + /// retxBSR-Timer expires flag + uint8_t retxBSRTimer_expires_flag; + /// MBSFN_Subframe Configuration struct MBSFN_SubframeConfig *mbsfn_SubframeConfig[8]; // FIXME replace 8 by MAX_MBSFN_AREA? /// number of subframe allocation pattern available for MBSFN sync area diff --git a/openair2/LAYER2/MAC/extern.h b/openair2/LAYER2/MAC/extern.h index 8726cb1349..4276c342cf 100644 --- a/openair2/LAYER2/MAC/extern.h +++ b/openair2/LAYER2/MAC/extern.h @@ -46,6 +46,8 @@ extern const uint32_t BSR_TABLE[BSR_TABLE_SIZE]; //extern uint32_t EBSR_Level[63]; +extern const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE]; +//extern uint32_t Extended_BSR_TABLE[63]; ----currently not used extern UE_MAC_INST *UE_mac_inst; extern eNB_MAC_INST *eNB_mac_inst; diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 59d6c352fe..94f1d3448c 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -545,13 +545,13 @@ int cba_access(module_id_t module_idP,frame_t frameP,sub_frame_t subframe, uint8 */ int get_bsr_lcgid (module_id_t module_idP); -/*! \fn uint8_t get_bsr_len (module_id_t module_idP,uint16_t bufflen); +/*! \fn int get_bsr_type (module_id_t module_idP,uint16_t bufflen); \brief determine whether the bsr is short or long assuming that the MAC pdu is built \param[in] Mod_id instance of the UE \param[in] bufflen size of phy transport block \param[out] bsr_len size of bsr control element */ -uint8_t get_bsr_len (module_id_t module_idP, uint16_t buflen); +int get_bsr_type (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint16_t buflen); /*! \fn BSR_SHORT * get_bsr_short(module_id_t module_idP, uint8_t bsr_len) \brief get short bsr level diff --git a/openair2/LAYER2/MAC/ra_procedures.c b/openair2/LAYER2/MAC/ra_procedures.c index 30137fab33..3b5734756d 100644 --- a/openair2/LAYER2/MAC/ra_procedures.c +++ b/openair2/LAYER2/MAC/ra_procedures.c @@ -391,7 +391,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP, 1); //post_padding return(&UE_mac_inst[module_idP].RA_prach_resources); - } else if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DCCH] > 0) { + } 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, diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index d5958f6e5e..56d4524d7d 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -102,13 +102,22 @@ void ue_init_mac(module_id_t module_idP) UE_mac_inst[module_idP].scheduling_info.sr_ProhibitTimer_Running=0; UE_mac_inst[module_idP].scheduling_info.maxHARQ_Tx=MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; UE_mac_inst[module_idP].scheduling_info.ttiBundling=0; + UE_mac_inst[module_idP].scheduling_info.extendedBSR_Sizes_r10=0; + UE_mac_inst[module_idP].scheduling_info.extendedPHR_r10=0; UE_mac_inst[module_idP].scheduling_info.drx_config=NULL; UE_mac_inst[module_idP].scheduling_info.phr_config=NULL; - UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); - UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); + // set init value 0xFFFF, make sure periodic timer and retx time counters are NOT active, after bsr transmission set the value configured by the NW. + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = 0xFFFF; + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = 0xFFFF; + + UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR]=0; + UE_mac_inst[module_idP].BSR_reporting_active[PADDING_BSR]=0; + UE_mac_inst[module_idP].BSR_reporting_active[PERIODIC_BSR]=0; + UE_mac_inst[module_idP].retxBSRTimer_expires_flag = 0; UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer); UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer); UE_mac_inst[module_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[module_idP].scheduling_info.PathlossChange); + UE_mac_inst[module_idP].PHR_reporting_active = 0; for (i=0; i < MAX_NUM_LCID; i++) { LOG_D(MAC,"[UE%d] Applying default logical channel config for LCGID %d\n",module_idP,i); @@ -121,7 +130,7 @@ void ue_init_mac(module_id_t module_idP) UE_mac_inst[module_idP].scheduling_info.LCGID[i]=1; } - UE_mac_inst[module_idP].scheduling_info.LCID_status[i]=0; + UE_mac_inst[module_idP].scheduling_info.LCID_status[i]=LCID_EMPTY; } #ifdef CBA @@ -306,6 +315,14 @@ uint32_t ue_get_SR(module_id_t module_idP,int CC_id,frame_t frameP,uint8_t eNB_i // initiate RA UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; + // release all pucch resource + UE_mac_inst[module_idP].physicalConfigDedicated = NULL; + UE_mac_inst[module_idP].ul_active=0; + UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR]=0; + UE_mac_inst[module_idP].BSR_reporting_active[PADDING_BSR]=0; + UE_mac_inst[module_idP].BSR_reporting_active[PERIODIC_BSR]=0; + UE_mac_inst[module_idP].retxBSRTimer_expires_flag = 0; + LOG_T(MAC,"[UE %d] Release all SRs \n", module_idP); return(0); } } @@ -1230,7 +1247,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf mac_rlc_status_resp_t rlc_status; uint8_t dcch_header_len=0,dcch1_header_len=0,dtch_header_len=0,dtch_header_len_last=0; uint8_t dcch_header_len_tmp=0, dtch_header_len_tmp=0; - uint8_t bsr_header_len=0, bsr_ce_len=0, bsr_len=0; + uint8_t bsr_len=0; uint8_t phr_header_len=0, phr_ce_len=0,phr_len=0; uint8_t lcid=0; uint16_t sdu_lengths[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -1238,17 +1255,20 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf uint8_t payload_offset=0,num_sdus=0; uint8_t ulsch_buff[MAX_ULSCH_PAYLOAD_BYTES]; uint16_t sdu_length_total=0; - BSR_SHORT bsr_short; + BSR_SHORT bsr_short,bsr_truncated; BSR_LONG bsr_long; BSR_SHORT *bsr_s=&bsr_short; BSR_LONG *bsr_l=&bsr_long; + BSR_SHORT *bsr_t=&bsr_truncated; POWER_HEADROOM_CMD phr; POWER_HEADROOM_CMD *phr_p=&phr; - unsigned short short_padding=0, post_padding=0; + unsigned short short_padding=0, post_padding=0, padding_len=0; int lcgid; int j; // used for padding // Compute header length - + int all_pdu_len; + int bsr_type=0; + if (CC_id>0) { LOG_E(MAC,"Transmission on secondary CCs is not supported yet\n"); mac_xface->macphy_exit("MAC FATAL CC_id>0"); @@ -1280,10 +1300,9 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dcch1_header_len=2;//sizeof(SCH_SUBHEADER_SHORT); // hypo length,in case of long header skip the padding byte dtch_header_len=(buflen > 128 ) ? 3 : 2 ; //sizeof(SCH_SUBHEADER_LONG)-1 : sizeof(SCH_SUBHEADER_SHORT); - bsr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); phr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); - phr_ce_len = (UE_mac_inst[module_idP].PHR_reporting_active == 1) ? 1 /* sizeof(POWER_HEADROOM_CMD)*/: 0; + phr_ce_len = (UE_mac_inst[module_idP].PHR_reporting_active == 1) ? 1 /* sizeof(POWER_HEADROOM_CMD)*/: 0; if (phr_ce_len > 0) { phr_len = phr_ce_len + phr_header_len; LOG_D(MAC,"[UE %d] header size info: PHR len %d (ce%d,hdr%d) buff_len %d\n", @@ -1292,19 +1311,21 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf phr_len=0; } - bsr_ce_len = get_bsr_len (module_idP, buflen-phr_len); - - if (bsr_ce_len > 0 ) { - bsr_len = bsr_ce_len + bsr_header_len; - LOG_D(MAC,"[UE %d] header size info: dcch %d, dcch1 %d, dtch %d, bsr (ce%d,hdr%d) buff_len %d\n", - module_idP, dcch_header_len,dcch1_header_len,dtch_header_len, bsr_ce_len, bsr_header_len, buflen); + bsr_type = get_bsr_type(module_idP, eNB_index, frameP, buflen-phr_len); + if (bsr_type == LONG_BSR) { + bsr_len = sizeof(SCH_SUBHEADER_FIXED)+sizeof(BSR_LONG);; + LOG_D(MAC,"[UE %d] header size info: dcch %d, dcch1 %d, dtch %d, bsr (bsr_type%d) buff_len %d\n", + module_idP, dcch_header_len,dcch1_header_len,dtch_header_len, bsr_type, buflen); + } else if ((bsr_type == SHORT_BSR) || (bsr_type == TRUNCATED_BSR)) { + bsr_len = sizeof(SCH_SUBHEADER_FIXED)+sizeof(BSR_SHORT);; + LOG_D(MAC,"[UE %d] header size info: dcch %d, dcch1 %d, dtch %d, bsr (bsr_type%d) buff_len %d\n", + module_idP, dcch_header_len,dcch1_header_len,dtch_header_len, bsr_type, buflen); } else { bsr_len=0; //LOG_D(MAC,"[UE %d] Empty buffers, send a long BSR to reset the bsr at eNB \n ",Mod_id); // bsr_ce_len = sizeof(BSR_LONG); //bsr_len = bsr_ce_len + bsr_header_len; } - // check for UL bandwidth requests and add SR control element // check for UL bandwidth requests and add SR control element @@ -1338,8 +1359,14 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf sdu_lcids[0] = DCCH; LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH\n",module_idP,sdu_lengths[0]); num_sdus = 1; - update_bsr(module_idP, frameP, eNB_index, DCCH, UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]); + //update_bsr(module_idP, frameP, eNB_index, DCCH, UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]); //header_len +=2; + UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH] = LCID_EMPTY; + if (rlc_status.bytes_in_buffer > sdu_lengths[0]) { + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH] = rlc_status.bytes_in_buffer-sdu_lengths[0]; + } else { + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH] = 0; + } } else { dcch_header_len=0; num_sdus = 0; @@ -1375,9 +1402,16 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf sdu_length_total += sdu_lengths[num_sdus]; sdu_lcids[num_sdus] = DCCH1; LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH1\n",module_idP,sdu_lengths[num_sdus]); - num_sdus++; //update_bsr(module_idP, frameP, DCCH1); //dcch_header_len +=2; // include dcch1 + UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH1] = LCID_EMPTY; + if (rlc_status.bytes_in_buffer > sdu_lengths[num_sdus]) { + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1] = rlc_status.bytes_in_buffer-sdu_lengths[num_sdus]; + } else { + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1] = 0; + } + + num_sdus++; } else { dcch1_header_len =0; } @@ -1388,8 +1422,9 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len+=3; dtch_header_len_last=3; + all_pdu_len = bsr_len+phr_len+dcch_header_len+dcch1_header_len+dtch_header_len+sdu_length_total; if ((UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) && - ((bsr_len+phr_len+dcch_header_len+dcch1_header_len+dtch_header_len+sdu_length_total) <= buflen)) { + (all_pdu_len <= buflen)) { // optimize the dtch header lenght //if ((UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DTCH] > 128) && @@ -1407,65 +1442,99 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf ENB_FLAG_NO, MBMS_FLAG_NO, // eNB_index lcid, - buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total); + buflen-all_pdu_len); LOG_D(MAC,"[UE %d] Frame %d : UL-DTCH -> ULSCH%d, %d bytes to send (Transport Block size %d, mac header len %d, BSR byte[%d] %d)\n", module_idP,frameP, lcid, rlc_status.bytes_in_buffer,buflen,dtch_header_len, - lcid, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcid]); + lcid, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); if (rlc_status.bytes_in_buffer > 0) { - 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, // eNB_index - lcid, - (char *)&ulsch_buff[sdu_length_total]); - - //adjust dtch header - LOG_D(MAC,"[UE %d] TX Got %d bytes for DTCH\n",module_idP,sdu_lengths[num_sdus]); - sdu_lcids[num_sdus] = lcid; - sdu_length_total += sdu_lengths[num_sdus]; - if (sdu_lengths[num_sdus] < 128) { - dtch_header_len --; - dtch_header_len_last --; - } - num_sdus++; - UE_mac_inst[module_idP].ul_active = update_bsr(module_idP, frameP, eNB_index,lcid, 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, // eNB_index + lcid, + (char *)&ulsch_buff[sdu_length_total]); + + //adjust dtch header + LOG_D(MAC,"[UE %d] TX Got %d bytes for DTCH\n",module_idP,sdu_lengths[num_sdus]); + sdu_lcids[num_sdus] = lcid; + sdu_length_total += sdu_lengths[num_sdus]; + if (sdu_lengths[num_sdus] < 128) { + dtch_header_len --; + dtch_header_len_last --; + } + if (rlc_status.bytes_in_buffer > sdu_lengths[num_sdus]) { + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] = rlc_status.bytes_in_buffer-sdu_lengths[num_sdus]; + } else { + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] = 0; + } + + //UE_mac_inst[module_idP].ul_active = update_bsr(module_idP, frameP, eNB_index,lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); + num_sdus++; } else { - dtch_header_len -= 3; + dtch_header_len -= 3; } + UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_EMPTY; } else { // no rlc pdu : generate the dummy header dtch_header_len -= 3; } } - + lcgid= get_bsr_lcgid(module_idP); if (lcgid < 0 ) { bsr_s = NULL; - bsr_l = NULL ; - } else if ((lcgid ==MAX_NUM_LCGID) && (bsr_ce_len == sizeof(BSR_LONG))) { + bsr_l = NULL; + bsr_t = NULL; + } else if ((lcgid ==MAX_NUM_LCGID) && (bsr_type == LONG_BSR)) { bsr_s = NULL; + bsr_t = NULL; bsr_l->Buffer_size0 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]; bsr_l->Buffer_size1 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]; bsr_l->Buffer_size2 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]; bsr_l->Buffer_size3 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]; + LOG_D(MAC, "[UE %d] Frame %d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP, UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]); - } else if (bsr_ce_len == sizeof(BSR_SHORT)) { + + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID0] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID1] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID2] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID3] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] = 0; + } else if (bsr_type == SHORT_BSR) { bsr_l = NULL; + bsr_t = NULL; bsr_s->LCGID = lcgid; bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]; + LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n", module_idP, frameP, UE_mac_inst[module_idP].scheduling_info.BSR[lcgid],lcgid); + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] = 0; + } else if (bsr_type == TRUNCATED_BSR) { + bsr_l = NULL; + bsr_s = NULL; + bsr_t->LCGID = lcgid; + bsr_t->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]; + + LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n", + module_idP, frameP, UE_mac_inst[module_idP].scheduling_info.BSR[lcgid],lcgid); + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] = 0; } else { bsr_s = NULL; bsr_l = NULL; + bsr_t = NULL; } // build PHR and update the timers @@ -1494,12 +1563,14 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len_last-=1; dtch_header_len= (dtch_header_len >0)? dtch_header_len - dtch_header_len_last : dtch_header_len; } - - if ((buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total) <= 2) { - short_padding = buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total; + // 1-bit padding or 2-bit padding special padding subheader + padding_len = buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total; + if (padding_len <= 2) { + short_padding = padding_len; + // only add padding header post_padding = 0; } else { - if ((buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total) == buflen) { + if (padding_len == buflen) {// nona mac pdu *access_mode=CANCELED_ACCESS; } @@ -1524,7 +1595,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf sdu_lcids, // sdu lcid phr_p, // power headroom NULL, // crnti - NULL, // truncated bsr + bsr_t, // truncated bsr bsr_s, // short bsr bsr_l, post_padding); // long_bsr @@ -1544,6 +1615,14 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf module_idP,payload_offset, sdu_length_total); UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; + UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR]=0; + UE_mac_inst[module_idP].BSR_reporting_active[PADDING_BSR]=0; + UE_mac_inst[module_idP].BSR_reporting_active[PERIODIC_BSR]=0; + if (bsr_type > 0) { //if bsr trigger, reset two timer + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); + UE_mac_inst[module_idP].retxBSRTimer_expires_flag = 0; + } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_OUT); stop_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu); @@ -1572,7 +1651,7 @@ ue_scheduler( const int CC_id) //------------------------------------------------------------------------------ { - + int periodicBSR_Timer_infinity_value; int lcid; // lcid index int TTI= 1; int bucketsizeduration = -1; @@ -1705,10 +1784,35 @@ ue_scheduler( // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures // outlined in Sections 5.4.4 an 5.4.5 of 36.321 - // Put this in another function + // Call BSR procedure as described in Section 5.4.5 in 36.321 + periodicBSR_Timer_infinity_value = get_sf_periodicBSRTimer(MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity); + if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF != (int16_t)periodicBSR_Timer_infinity_value) { + if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF <= 0 ) { + /* + periodicBSR-Timer expires, in which case the BSR is referred below to as "Periodic BSR". + */ + UE_mac_inst[module_idP].BSR_reporting_active[PERIODIC_BSR] = 1; + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = periodicBSR_Timer_infinity_value; + } else { + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF--; + } + } + + if (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF != (int16_t)0xFFFF) { + if (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF <= 0){ + /* retxBSR-Timer expires and the UE has data available for transmission for any of the logical channels which belong + to a LCG, in which case the BSR is referred below to as "Regular BSR" + */ + UE_mac_inst[module_idP].retxBSRTimer_expires_flag = 1; + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = (int16_t)0xFFFF; + + } else { + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF--; + } + } // Get RLC status info and update Bj for all lcids that are active - for (lcid=DCCH; lcid <= DTCH; lcid++ ) { + for (lcid=DCCH; lcid < MAX_NUM_LCID; lcid++ ) { if ((lcid == 0) ||(UE_mac_inst[module_idP].logicalChannelConfig[lcid])) { // meausre the Bj if ((directionP == SF_UL)&& (UE_mac_inst[module_idP].scheduling_info.Bj[lcid] >= 0)) { @@ -1727,6 +1831,12 @@ 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]], + UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); + } + if (update_bsr(module_idP,frameP, eNB_indexP, lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid])) { UE_mac_inst[module_idP].scheduling_info.SR_pending= 1; LOG_D(MAC,"[UE %d][SR] Frame %d subframe %d SR for PUSCH is pending for LCGID %d with BSR level %d (%d bytes in RLC)\n", @@ -1970,41 +2080,108 @@ int get_bsr_lcgid (module_id_t module_idP) } } -uint8_t get_bsr_len (module_id_t module_idP, uint16_t buflen) +int get_bsr_type (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint16_t buflen) { - - int lcgid=0; - uint8_t bsr_len=0, num_lcgid=0; + int bsr_type=0; + int lcid,lcgid; int pdu = 0; - - + mac_rlc_status_resp_t rlc_status; + int long_bsr_size=sizeof(SCH_SUBHEADER_FIXED)+sizeof(BSR_LONG); + int short_bsr_size=sizeof(SCH_SUBHEADER_FIXED)+sizeof(BSR_SHORT); + int bsr_group_id[MAX_NUM_LCGID]; + int lcg_report_num=0; + for (lcgid=0; lcgid < MAX_NUM_LCGID; lcgid++ ) { - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 0 ) { - pdu += (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] + bsr_len + 2); //2 = sizeof(SCH_SUBHEADER_SHORT) + bsr_group_id[lcgid] = 0; + } + + for (lcid=DCCH; lcid 0 ) { + /* retxBSR-Timer expires and the UE has data available for transmission for any of the logical channels which belong + to a LCG, in which case the BSR is referred below to as "Regular BSR" + */ + if (UE_mac_inst[module_idP].retxBSRTimer_expires_flag == 1) { + UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR] = 1; + } + pdu += rlc_status.bytes_in_buffer + sizeof(SCH_SUBHEADER_SHORT); + if (rlc_status.bytes_in_buffer > 128 ) { + pdu += 1; //sizeof(SCH_SUBHEADER_LONG) + } + /* UL data, for a logical channel which belongs to a LCG, becomes available for transmission in the RLC entity + either the data belongs to a logical channel with higher priority than the priorities of the logical channels + which belong to any LCG and for which data is already available for transmission + */ + if (rlc_status.bytes_in_buffer > UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]) { + bsr_group_id[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] ++; + UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR] = 1; + } } - - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 128 ) { // long header size: adjust the header size - pdu += 1; + } + + /* or there is no data available for transmission for any of the logical channels which belong to a LCG, + in which case the BSR is referred below to as "Regular BSR" + if (pdu == 0) { + UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR] = 1; + } + */ + + // computed how many LCG has data available for transmission + for (lcgid=0; lcgid < MAX_NUM_LCGID; lcgid++ ) { + if (bsr_group_id[lcgid] > 0) { + lcg_report_num ++; } - - // current phy buff can not transport all sdu for this lcgid -> transmit a bsr for this lcgid - - if ( (pdu > buflen) && (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] > 0 ) ) { - num_lcgid +=1; - bsr_len = (num_lcgid >= 2 ) ? sizeof(BSR_LONG) : sizeof(BSR_SHORT) ; - } - - LOG_D(MAC,"BSR Bytes %d for lcgid %d bsr len %d num lcgid %d\n", UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid], lcgid, bsr_len, num_lcgid); + } + /* + UL resources are allocated and number of padding bits is equal to or larger than the size of the Buffer Status + Report MAC control element plus its subheader, in which case the BSR is referred below to as "Padding BSR" + */ + if ((pdu > 0) && ((pdu+long_bsr_size) <= buflen)) { + UE_mac_inst[module_idP].BSR_reporting_active[PADDING_BSR] = 1; } - if ( bsr_len > 0 ) - LOG_D(MAC,"[UE %d] Prepare a %s (Transport Block Size %d, MAC pdu Size %d) \n", - module_idP, map_int_to_str(BSR_names, bsr_len), buflen, pdu); + /* For Regular and Periodic BSR + - if more than one LCG has data available for transmission in the TTI where the BSR is transmitted: report Long BSR; + - else report Short BSR. + */ + if ((UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR] == 1) + || (UE_mac_inst[module_idP].BSR_reporting_active[PERIODIC_BSR] == 1)) { + if (lcg_report_num > 1) { + bsr_type = LONG_BSR; + } else { + bsr_type = SHORT_BSR; + } + } + /* For Padding BSR: + - if the number of padding bits is equal to or larger than the size of the Short BSR plus its subheader but smaller than the size of the Long BSR plus its subheader: + - if more than one LCG has data available for transmission in the TTI where the BSR is transmitted: report Truncated BSR of the LCG with the highest priority logical channel with data available for transmission; + - else report Short BSR. + - else if the number of padding bits is equal to or larger than the size of the Long BSR plus its subheader, report Long BSR. + */ + if (UE_mac_inst[module_idP].BSR_reporting_active[PADDING_BSR] == 1) { + if (((pdu + short_bsr_size) <= buflen)&&(buflen<(pdu + long_bsr_size))) { + if (lcg_report_num > 1) { + bsr_type = TRUNCATED_BSR; + } else { + bsr_type = SHORT_BSR; + } + } else if ((pdu + long_bsr_size) <= buflen) { + if (lcg_report_num > 1) { + bsr_type = LONG_BSR; + } else { + bsr_type = SHORT_BSR; + } + } + } - return bsr_len; + if ( bsr_type > 0 ) { + LOG_D(MAC, "[UE %d] bsr_type %d (Transport Block Size %d, MAC pdu len %d) lcg_report_num %d\n", + module_idP, bsr_type, buflen, pdu, lcg_report_num); + } + + return bsr_type; } - boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_index, uint8_t lcid, uint8_t lcg_id) { @@ -2029,10 +2206,12 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in 0); if (rlc_status.bytes_in_buffer > 0 ) { + //BSR trigger SR sr_pending = TRUE; UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_NOT_EMPTY; - UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] += locate (BSR_TABLE,BSR_TABLE_SIZE, rlc_status.bytes_in_buffer); + // sum lcid buffer which has same lcgid UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id] += rlc_status.bytes_in_buffer; + UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); // UE_mac_inst[module_idP].scheduling_info.BSR_short_lcid = lcid; // only applicable to short bsr LOG_D(MAC,"[UE %d] BSR level %d (LCGID %d, rlc buffer %d byte)\n", module_idP, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id],lcg_id, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); @@ -2045,7 +2224,7 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in return sr_pending; } -uint8_t locate (const uint32_t *table, int size, int value) +uint8_t locate_BsrIndexByBufferSize (const uint32_t *table, int size, int value) { uint8_t ju, jm, jl; @@ -2144,7 +2323,7 @@ int get_sf_periodicBSRTimer(uint8_t sf_offset) case MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity: default: - return -1; + return 0xFFFF; break; } } diff --git a/openair2/LAYER2/MAC/vars.h b/openair2/LAYER2/MAC/vars.h index 83d159f910..236439c6e5 100644 --- a/openair2/LAYER2/MAC/vars.h +++ b/openair2/LAYER2/MAC/vars.h @@ -45,6 +45,15 @@ const uint32_t BSR_TABLE[BSR_TABLE_SIZE]= {0,10,12,14,17,19,22,26,31,36,42,49,57 1326,1552,1817,2127,2490,2915,3413,3995,4677,5467,6411,7505,8787,10287,12043,14099, 16507,19325,22624,26487,31009,36304,42502,49759,58255,68201,79846,93479,109439, 128125,150000, 300000 }; +// extended bsr table--currently not used +const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE] = {0,10,13,16,19,23,29,35,43,53,65,80,98,120,147, + 181,223,274,337,414,509,625,769,945,1162,1429, + 1757,2161,2657,3267,4017,4940,6074,7469,9185, + 11294,13888,17077,20999,25822,31752,39045,48012, + 59039,72598,89272,109774,134986,165989,204111, + 250990,308634,379519,466683,573866,705666,867737, + 1067031,1312097,1613447,1984009,2439678,3000000, + 6000000}; //uint32_t EBSR_Level[63]={0,10,13,16,19,23,29,35,43,53,65,80,98,120,147,181}; From 6097e0516f44f018b15b412944a9c18c38daa8f4 Mon Sep 17 00:00:00 2001 From: calvin wang Date: Mon, 14 Nov 2016 11:10:33 +0800 Subject: [PATCH 286/413] fix build error --- openair2/LAYER2/MAC/proto.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 94f1d3448c..3733b27336 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -577,14 +577,14 @@ BSR_LONG * get_bsr_long(module_id_t module_idP, uint8_t bsr_len); */ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_index, uint8_t lcid, uint8_t lcgid); -/*! \fn locate (int *table, int size, int value) +/*! \fn locate_BsrIndexByBufferSize (int *table, int size, int value) \brief locate the BSR level in the table as defined in 36.321. This function requires that he values in table to be monotonic, either increasing or decreasing. The returned value is not less than 0, nor greater than n-1, where n is the size of table. \param[in] *table Pointer to BSR table \param[in] size Size of the table \param[in] value Value of the buffer \return the index in the BSR_LEVEL table */ -uint8_t locate (const uint32_t *table, int size, int value); +uint8_t locate_BsrIndexByBufferSize (const uint32_t *table, int size, int value); /*! \fn int get_sf_periodicBSRTimer(uint8_t periodicBSR_Timer) From 54d8b116f9ce2085e763a3398e03d9c9548b9489 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Mon, 14 Nov 2016 18:40:03 +0100 Subject: [PATCH 287/413] updates to E-UTRAN User Guide --- targets/DOCS/E-UTRAN_User_Guide.docx | Bin 1284855 -> 1318181 bytes targets/DOCS/E-UTRAN_User_Guide.pdf | Bin 883242 -> 1563090 bytes 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 targets/DOCS/E-UTRAN_User_Guide.docx mode change 100644 => 100755 targets/DOCS/E-UTRAN_User_Guide.pdf diff --git a/targets/DOCS/E-UTRAN_User_Guide.docx b/targets/DOCS/E-UTRAN_User_Guide.docx old mode 100644 new mode 100755 index 824aa46e9a56b12d33802da83308aa83e7b07922..00e6e6faa9a0dcf5f9f5564cfd7c904aa5527059 GIT binary patch delta 168147 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 delta 134502 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 z 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

faR~ZLB`avm#xR(E>HmxbjZfE) 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 diff --git a/targets/DOCS/E-UTRAN_User_Guide.pdf b/targets/DOCS/E-UTRAN_User_Guide.pdf old mode 100644 new mode 100755 index 5005692944f0940d95d160f1ee734c0ce83cc619..2c1b307ecbd2a2da883f2e89f97bb8f31922b7fe GIT binary patch literal 1563090 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 z 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 z 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%0AvzSowvKv2 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%0A&ILEK%A{Xr=8<^M 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�iEhjiiw*NKMk|&tvGI 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⁢4p?)lc=;R>@fV{nmQN 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%0D1fS_RRB-mv{j|Sz#aJ!->K* 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�s{~h* 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�oVYF^- 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%0ADHaXZ;{ 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 >p{3wEAt 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

Vs3V%c_3 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 zμ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

?R6STpAq#CQx#%s4Qh4< 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

J=v4W_F?_pa7MoP`!(iShvrpL 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%0A@jl)jX>%Rt^w%#Pg!&S(Xq?g|0jC=$A-$0Q{q1n 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 z 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

!}X&ZpE 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 z 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 YQ&?(+scmMx$;D*YXER@)RI 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

5!O7&64R@pI-q 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 From be0b164a52d01fa577a208ce769610fe2ce61f06 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Mon, 14 Nov 2016 18:49:07 +0100 Subject: [PATCH 288/413] minor type updates to E-UTRAN User Guide --- targets/DOCS/E-UTRAN_User_Guide.docx | Bin 1318181 -> 1318302 bytes targets/DOCS/E-UTRAN_User_Guide.pdf | Bin 1563090 -> 1562827 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/targets/DOCS/E-UTRAN_User_Guide.docx b/targets/DOCS/E-UTRAN_User_Guide.docx index 00e6e6faa9a0dcf5f9f5564cfd7c904aa5527059..12a9d17da5f0fed5cd45a06cfc94ae853fb96840 100755 GIT binary patch delta 41246 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 Qfc&KZ(4wgV0Pywy2OIxo-~a#s delta 41155 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 CANofC diff --git a/targets/DOCS/E-UTRAN_User_Guide.pdf b/targets/DOCS/E-UTRAN_User_Guide.pdf index 2c1b307ecbd2a2da883f2e89f97bb8f31922b7fe..3de31b24f2a95476c520378ac29ca6a41e8a2ea7 100755 GIT binary patch delta 93398 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∋0VA(y+@1Mh&q=3w0Np=5Jz?2I{~ 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 delta 93758 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 z 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 Date: Tue, 15 Nov 2016 18:41:46 +0800 Subject: [PATCH 289/413] change bsr trigger --- openair2/LAYER2/MAC/defs.h | 2 ++ openair2/LAYER2/MAC/ue_procedures.c | 39 +++++++++++++++++++---------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index bfaaa3ca1d..c44144d8e7 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -957,6 +957,8 @@ typedef struct { uint16_t BSR_bytes[MAX_NUM_LCGID]; /// after multiplexing buffer remain for each lcid uint16_t LCID_buffer_remain[MAX_NUM_LCID]; + /// sum of all lcid buffer size + uint16_t All_lcid_buffer_size_lastTTI; /// buffer status for each lcid uint8_t LCID_status[MAX_NUM_LCID]; /// SR pending as defined in 36.321 diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 56d4524d7d..d9888b0ba5 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -316,8 +316,6 @@ uint32_t ue_get_SR(module_id_t module_idP,int CC_id,frame_t frameP,uint8_t eNB_i UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; // release all pucch resource - UE_mac_inst[module_idP].physicalConfigDedicated = NULL; - UE_mac_inst[module_idP].ul_active=0; UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR]=0; UE_mac_inst[module_idP].BSR_reporting_active[PADDING_BSR]=0; UE_mac_inst[module_idP].BSR_reporting_active[PERIODIC_BSR]=0; @@ -1313,11 +1311,11 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf bsr_type = get_bsr_type(module_idP, eNB_index, frameP, buflen-phr_len); if (bsr_type == LONG_BSR) { - bsr_len = sizeof(SCH_SUBHEADER_FIXED)+sizeof(BSR_LONG);; + bsr_len = sizeof(SCH_SUBHEADER_FIXED)+sizeof(BSR_LONG); LOG_D(MAC,"[UE %d] header size info: dcch %d, dcch1 %d, dtch %d, bsr (bsr_type%d) buff_len %d\n", module_idP, dcch_header_len,dcch1_header_len,dtch_header_len, bsr_type, buflen); } else if ((bsr_type == SHORT_BSR) || (bsr_type == TRUNCATED_BSR)) { - bsr_len = sizeof(SCH_SUBHEADER_FIXED)+sizeof(BSR_SHORT);; + bsr_len = sizeof(SCH_SUBHEADER_FIXED)+sizeof(BSR_SHORT); LOG_D(MAC,"[UE %d] header size info: dcch %d, dcch1 %d, dtch %d, bsr (bsr_type%d) buff_len %d\n", module_idP, dcch_header_len,dcch1_header_len,dtch_header_len, bsr_type, buflen); } else { @@ -1457,7 +1455,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf MBMS_FLAG_NO, // eNB_index lcid, (char *)&ulsch_buff[sdu_length_total]); - + //adjust dtch header LOG_D(MAC,"[UE %d] TX Got %d bytes for DTCH\n",module_idP,sdu_lengths[num_sdus]); sdu_lcids[num_sdus] = lcid; @@ -1517,8 +1515,8 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf bsr_s->LCGID = lcgid; bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]; - LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n", - module_idP, frameP, UE_mac_inst[module_idP].scheduling_info.BSR[lcgid],lcgid); + LOG_I(MAC,"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%[UE %d] Frame %d SubFrame %d,report SHORT BSR with level %d for LCGID %d\n", + module_idP, frameP, subframe, UE_mac_inst[module_idP].scheduling_info.BSR[lcgid],lcgid); UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] = 0; UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] = 0; } else if (bsr_type == TRUNCATED_BSR) { @@ -2068,6 +2066,7 @@ int get_bsr_lcgid (module_id_t module_idP) if (UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] > 0 ) { lcgid_tmp = lcgid; num_active_lcgid+=1; + printf("////////////////////////////////lcgid %d, BSR %d\n",lcgid,UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]); } } @@ -2090,7 +2089,8 @@ int get_bsr_type (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint1 int short_bsr_size=sizeof(SCH_SUBHEADER_FIXED)+sizeof(BSR_SHORT); int bsr_group_id[MAX_NUM_LCGID]; int lcg_report_num=0; - + int new_data_arrived_flag=0; + for (lcgid=0; lcgid < MAX_NUM_LCGID; lcgid++ ) { bsr_group_id[lcgid] = 0; } @@ -2112,13 +2112,23 @@ int get_bsr_type (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint1 either the data belongs to a logical channel with higher priority than the priorities of the logical channels which belong to any LCG and for which data is already available for transmission */ - if (rlc_status.bytes_in_buffer > UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]) { + if (rlc_status.bytes_in_buffer > UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]) { bsr_group_id[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] ++; + new_data_arrived_flag = 1; UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR] = 1; } } } - + +/* + // one lcid buffer increased and all lcid buffer increased + if ((new_data_arrived_flag == 1) && (pdu > UE_mac_inst[module_idP].scheduling_info.All_lcid_buffer_size_lastTTI)) { + UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR] = 1; + } +*/ + + UE_mac_inst[module_idP].scheduling_info.All_lcid_buffer_size_lastTTI = pdu; + /* or there is no data available for transmission for any of the logical channels which belong to a LCG, in which case the BSR is referred below to as "Regular BSR" if (pdu == 0) { @@ -2130,6 +2140,7 @@ int get_bsr_type (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint1 for (lcgid=0; lcgid < MAX_NUM_LCGID; lcgid++ ) { if (bsr_group_id[lcgid] > 0) { lcg_report_num ++; + printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@lcgid bsr %d > 0\n",lcgid); } } /* @@ -2150,6 +2161,7 @@ int get_bsr_type (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint1 bsr_type = LONG_BSR; } else { bsr_type = SHORT_BSR; + printf("-----------------------------------REGULAR_BSR or PERIODIC_BSR bsr trigger short bsr\n"); } } /* For Padding BSR: @@ -2170,12 +2182,13 @@ int get_bsr_type (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint1 bsr_type = LONG_BSR; } else { bsr_type = SHORT_BSR; + printf("+++++++++++++++++++++++++++++++++++padding bsr trigger short bsr\n"); } } } if ( bsr_type > 0 ) { - LOG_D(MAC, "[UE %d] bsr_type %d (Transport Block Size %d, MAC pdu len %d) lcg_report_num %d\n", + LOG_I(MAC, "[UE %d] bsr_type %d (Transport Block Size %d, MAC pdu len %d) lcg_report_num %d\n", module_idP, bsr_type, buflen, pdu, lcg_report_num); } @@ -2213,8 +2226,8 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id] += rlc_status.bytes_in_buffer; UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); // UE_mac_inst[module_idP].scheduling_info.BSR_short_lcid = lcid; // only applicable to short bsr - LOG_D(MAC,"[UE %d] BSR level %d (LCGID %d, rlc buffer %d byte)\n", - module_idP, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id],lcg_id, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); + LOG_D(MAC,"[UE %d] BSR level %d (LCGID %d,lcid %d rlc buffer %d byte)\n", + module_idP, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id],lcg_id, lcid,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); } else { UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid]=LCID_EMPTY; } From f0f34c029b4718069ea3ed2379df0f309ac7b4a2 Mon Sep 17 00:00:00 2001 From: hbilel Date: Tue, 15 Nov 2016 16:13:24 +0100 Subject: [PATCH 290/413] BSR fixes with CMW500 --- openair2/LAYER2/MAC/config.c | 4 +- openair2/LAYER2/MAC/defs.h | 5 +- openair2/LAYER2/MAC/ue_procedures.c | 219 +++++++++++++++++++++++----- 3 files changed, 191 insertions(+), 37 deletions(-) diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index d46b761bd0..bca0149791 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -245,8 +245,8 @@ rrc_mac_config_req( UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t)0; } #endif - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_Timer); - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer); + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; UE_mac_inst[Mod_idP].BSR_reporting_active = 0; LOG_D(MAC,"[UE %d]: periodic BSR %d (SF), retx BSR %d (SF)\n", diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index d38ca05362..336f3f1039 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -133,6 +133,7 @@ /*!\brief maximum value for channel quality indicator */ #define MAX_CQI_VALUE 15 +#define MAC_UE_BSR_TIMER_NOT_RUNNING (0xFFFF) #define LCID_EMPTY 0 #define LCID_NOT_EMPTY 1 @@ -962,11 +963,11 @@ typedef struct { /// retxBSR-Timer, default value is sf2560 uint16_t retxBSR_Timer; /// retxBSR_SF, number of subframe before triggering a regular BSR - int16_t retxBSR_SF; + uint16_t retxBSR_SF; /// periodicBSR-Timer, default to infinity uint16_t periodicBSR_Timer; /// periodicBSR_SF, number of subframe before triggering a periodic BSR - int16_t periodicBSR_SF; + uint16_t periodicBSR_SF; /// default value is 0: not configured uint16_t sr_ProhibitTimer; /// sr ProhibitTime running diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index c24702b3b5..c2701c5f39 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -91,7 +91,7 @@ void ue_init_mac(module_id_t module_idP) // default values as deined in 36.331 sec 9.2.2 LOG_I(MAC,"[UE%d] Applying default macMainConfig\n",module_idP); //UE_mac_inst[module_idP].scheduling_info.macConfig=NULL; - UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer= MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf2560; + UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer= MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf10240; UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer=MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity; UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer = MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer = MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; @@ -106,8 +106,8 @@ void ue_init_mac(module_id_t module_idP) UE_mac_inst[module_idP].scheduling_info.extendedPHR_r10=0; UE_mac_inst[module_idP].scheduling_info.drx_config=NULL; UE_mac_inst[module_idP].scheduling_info.phr_config=NULL; - UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); - UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; UE_mac_inst[module_idP].BSR_reporting_active = 0; UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer); UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer); @@ -308,14 +308,16 @@ uint32_t ue_get_SR(module_id_t module_idP,int CC_id,frame_t frameP,uint8_t eNB_i // notify RRC to relase PUCCH/SRS // clear any configured dl/ul // initiate RA + if (UE_mac_inst[module_idP].scheduling_info.SR_pending){ + // release all pucch resource + UE_mac_inst[module_idP].physicalConfigDedicated = NULL; + UE_mac_inst[module_idP].ul_active=0; + UE_mac_inst[module_idP].BSR_reporting_active=0; + + LOG_I(MAC,"[UE %d] Release all SRs \n", module_idP); + } UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; - // release all pucch resource - UE_mac_inst[module_idP].physicalConfigDedicated = NULL; - UE_mac_inst[module_idP].ul_active=0; - UE_mac_inst[module_idP].BSR_reporting_active=0; - - LOG_T(MAC,"[UE %d] Release all SRs \n", module_idP); return(0); } } @@ -1259,10 +1261,16 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf POWER_HEADROOM_CMD phr; POWER_HEADROOM_CMD *phr_p=&phr; unsigned short short_padding=0, post_padding=0, padding_len=0; - int lcgid; int j; // used for padding // Compute header length int all_pdu_len; + int lcg_id = 0; + int lcg_id_bsr_short = 0; + int num_lcg_id_with_data = 0; + + LOG_D(MAC,"[UE %d] MAC PROCESS UL TRANSPORT BLOCK at frame%d subframe %d TBS=%d\n", + module_idP, frameP, subframe, buflen); + if (CC_id>0) { LOG_E(MAC,"Transmission on secondary CCs is not supported yet\n"); @@ -1295,10 +1303,83 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dcch1_header_len=2;//sizeof(SCH_SUBHEADER_SHORT); // hypo length,in case of long header skip the padding byte dtch_header_len=(buflen > 128 ) ? 3 : 2 ; //sizeof(SCH_SUBHEADER_LONG)-1 : sizeof(SCH_SUBHEADER_SHORT); - bsr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); + bsr_header_len = 0; phr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); + while (lcg_id < MAX_NUM_LCGID) { + if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]){ + num_lcg_id_with_data ++; + lcg_id_bsr_short = lcg_id; + } + lcg_id ++; + } + + if (num_lcg_id_with_data){ + LOG_I(MAC,"[UE %d] MAC Tx data pending at frame%d subframe %d nb LCG =%d LCG0 bytes=%d BSR Trigger status =%d TBS=%d\n", + module_idP, frameP, subframe, num_lcg_id_with_data, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[0],UE_mac_inst[module_idP].BSR_reporting_active, buflen); + + } + // ReTxBSR-Timer expires, trigger BSR + if ((num_lcg_id_with_data) && (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF == 0)){ + + // If the UE has data to transmit, trigger a BSR + UE_mac_inst[module_idP].BSR_reporting_active = 1; + + LOG_I(MAC,"[UE %d] MAC BSR Triggered ReTxBSR Timer expiry at frame%d subframe %d TBS=%d\n", + module_idP, frameP, subframe, buflen); + + } + // periodicBSR-Timer expires, trigger BSR + if ((UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer != MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity) + && (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF == 0)){ + // Trigger BSR + UE_mac_inst[module_idP].BSR_reporting_active = 1; + + LOG_I(MAC,"[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry at frame%d subframe %d TBS=%d\n", + module_idP, frameP, subframe, buflen); + + } + + //Compute BSR Length + if (UE_mac_inst[module_idP].BSR_reporting_active){ + if (buflen >= 4){ + if (num_lcg_id_with_data <= 1){ + bsr_ce_len = sizeof(BSR_SHORT); //1 byte + } + else{ + bsr_ce_len = sizeof(BSR_LONG); //3 bytes + } + + bsr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); + // Reset Periodic and ReTx BSR Timer + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); + + LOG_I(MAC,"[UE %d] MAC ReTx BSR Timer Reset =%d\n", + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF); + + if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer != MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity){ + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); + + LOG_I(MAC,"[UE %d] MAC Periodic BSR Timer Reset =%d\n", + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF); + + } + + LOG_I(MAC,"[UE %d] MAC BSR Triggered !! bsr (ce%d,hdr%d) buff_len %d\n", + module_idP, bsr_ce_len, bsr_header_len, buflen); + + } + else { + // Cancel Regular and Periodic BSR if Grant is smaller than 4 bytes + UE_mac_inst[module_idP].BSR_reporting_active = 0; + bsr_header_len = 0; + } + } + bsr_len = bsr_ce_len + bsr_header_len; +#if 0 bsr_ce_len = get_bsr_len (module_idP, eNB_index, frameP, buflen); + + // retxBSR-Timer expires or periodicBSR-Timer expires and Regular BSR trigger if ((bsr_ce_len > 0 ) && (UE_mac_inst[module_idP].BSR_reporting_active > 0)) { bsr_len = bsr_ce_len + bsr_header_len; @@ -1310,6 +1391,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf // bsr_ce_len = sizeof(BSR_LONG); //bsr_len = bsr_ce_len + bsr_header_len; } +#endif phr_ce_len = (UE_mac_inst[module_idP].PHR_reporting_active == 1) ? 1 /* sizeof(POWER_HEADROOM_CMD)*/: 0; if (phr_ce_len > 0) { @@ -1336,9 +1418,22 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf MBMS_FLAG_NO, // eNB_index DCCH, (buflen-dcch_header_len-bsr_len-phr_len)); - LOG_D(MAC, "[UE %d] Frame %d : UL-DCCH -> ULSCH, RRC message has %d bytes to " - "send (Transport Block size %d, mac header len %d)\n", - module_idP,frameP, rlc_status.bytes_in_buffer,buflen,dcch_header_len); + LOG_D(MAC, "[UE %d] Frame %d : UL-DCCH -> ULSCH, RLC SRB1 has %d bytes to " + "send (Transport Block size %d BSR size=%d PHR=%d SDU Length Total %d , mac header len %d)\n", + module_idP,frameP, rlc_status.bytes_in_buffer,buflen,bsr_len,phr_len,sdu_length_total,dcch_header_len); + + /* Update BSR : substract transmitted data */ + if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] >= rlc_status.bytes_in_buffer){ + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] -= rlc_status.bytes_in_buffer; + } + else if (rlc_status.bytes_in_buffer){ + LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data to transmit=%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[DCCH]], + UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH], + rlc_status.bytes_in_buffer,DCCH); + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] = 0; + } sdu_lengths[0] += mac_rlc_data_req(module_idP, UE_mac_inst[module_idP].crnti, @@ -1351,7 +1446,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf sdu_length_total += sdu_lengths[0]; sdu_lcids[0] = DCCH; - LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH\n",module_idP,sdu_lengths[0]); + LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU TX Got %d bytes for SRB1\n",module_idP,sdu_lengths[0]); num_sdus = 1; //update_bsr(module_idP, frameP, eNB_index, DCCH, UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]); //header_len +=2; @@ -1379,9 +1474,22 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf DCCH1, (buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-sdu_length_total)); - LOG_D(MAC,"[UE %d] Frame %d : UL-DCCH1 -> ULSCH, RRC message has %d bytes to" - " send (Transport Block size %d, mac header len %d)\n", - module_idP,frameP, rlc_status.bytes_in_buffer,buflen,dcch1_header_len); + LOG_D(MAC,"[UE %d] Frame %d subframe %d: UL-DCCH1 -> ULSCH, RLC SRB2 has %d bytes to" + " send (Transport Block size %d BSR size=%d PHR=%d SRB1 Hdr %d SDU Length Total %d , mac header len %d)\n", + module_idP,frameP, subframe, rlc_status.bytes_in_buffer,buflen,bsr_len,phr_len,dcch_header_len,sdu_length_total,dcch1_header_len); + + /* Update BSR : substract transmitted data */ + if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] >= rlc_status.bytes_in_buffer){ + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] -= rlc_status.bytes_in_buffer; + } + else if (rlc_status.bytes_in_buffer){ + LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data to transmit=%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[DCCH1]], + UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1], + rlc_status.bytes_in_buffer,DCCH1); + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] = 0; + } sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, UE_mac_inst[module_idP].crnti, @@ -1393,7 +1501,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf (char *)&ulsch_buff[sdu_lengths[num_sdus]]); sdu_length_total += sdu_lengths[num_sdus]; sdu_lcids[num_sdus] = DCCH1; - LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH1\n",module_idP,sdu_lengths[num_sdus]); + LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU Got %d bytes for SRB2\n",module_idP,sdu_lengths[num_sdus]); //update_bsr(module_idP, frameP, DCCH1); //dcch_header_len +=2; // include dcch1 UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH1] = LCID_EMPTY; @@ -1438,6 +1546,19 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf lcid, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); if (rlc_status.bytes_in_buffer > 0) { + /* Update BSR : substract transmitted data */ + if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] >= rlc_status.bytes_in_buffer){ + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] -= rlc_status.bytes_in_buffer; + } + else { + LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data to transmit=%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], + rlc_status.bytes_in_buffer,lcid); + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] = 0; + } + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, UE_mac_inst[module_idP].crnti, eNB_index, @@ -1469,12 +1590,18 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf } } - lcgid= get_bsr_lcgid(module_idP); + //lcgid= get_bsr_lcgid(module_idP); - if (lcgid < 0 ) { + // Compute BSR Values + for (lcg_id=0;lcg_idBuffer_size0 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]; bsr_l->Buffer_size1 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]; @@ -1497,14 +1624,14 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] = 0; } else if (bsr_ce_len == sizeof(BSR_SHORT)) { bsr_l = NULL; - bsr_s->LCGID = lcgid; - bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]; + bsr_s->LCGID = lcg_id_bsr_short; + bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_short]; - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id_bsr_short] = 0; + UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_short] = 0; LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n", - module_idP, frameP, UE_mac_inst[module_idP].scheduling_info.BSR[lcgid],lcgid); + module_idP, frameP, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_short],lcg_id_bsr_short); } else { bsr_s = NULL; bsr_l = NULL; @@ -1589,8 +1716,6 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf UE_mac_inst[module_idP].scheduling_info.SR_pending=0; UE_mac_inst[module_idP].scheduling_info.SR_COUNTER=0; UE_mac_inst[module_idP].BSR_reporting_active=0; - UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); - UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_OUT); stop_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu); @@ -1753,6 +1878,23 @@ ue_scheduler( // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures // outlined in Sections 5.4.4 an 5.4.5 of 36.321 // Call BSR procedure as described in Section 5.4.5 in 36.321 + + // TODO : Fix Periodic and ReTx BSR Timers + // First check ReTxBSR Timer because it is always configured +#if 1 + // Decrement ReTxBSR Timer if it is running and not null + if ((UE_mac_inst[module_idP].scheduling_info.retxBSR_SF != MAC_UE_BSR_TIMER_NOT_RUNNING) + && (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF != 0)){ + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF --; + } + + // Decrement Periodic Timer if it is running and not null + if ((UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF != MAC_UE_BSR_TIMER_NOT_RUNNING) + && (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF != 0)){ + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF --; + } + +#else if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF == get_sf_periodicBSRTimer(MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity)) { UE_mac_inst[module_idP].BSR_reporting_active = 1; } else if (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF <= 0 ){ @@ -1768,6 +1910,7 @@ ue_scheduler( } else if (UE_mac_inst[module_idP].BSR_reporting_active == 0 ) { UE_mac_inst[module_idP].scheduling_info.retxBSR_SF--; } +#endif // Get RLC status info and update Bj for all lcids that are active for (lcid=DCCH; lcid < MAX_NUM_LCID; lcid++ ) { @@ -2053,12 +2196,22 @@ uint8_t get_bsr_len (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,ui num_lcid +=1; bsr_len = (num_lcid >= 2 ) ? sizeof(BSR_LONG) : sizeof(BSR_SHORT) ; } + else if (rlc_status.bytes_in_buffer) { + LOG_I(MAC,"pdu smaller than TBS! pdu=%d TBS=%d lcid=%d rlc buffer=%d bsr len=%d num lcid=%d\n",pdu,buflen,lcid,rlc_status.bytes_in_buffer,bsr_len, num_lcid); + } LOG_D(MAC,"LC buffer Bytes %d for lcid %d bsr len %d num lcid %d\n", rlc_status.bytes_in_buffer, lcid, bsr_len, num_lcid); } if ( bsr_len > 0 ) - LOG_D(MAC,"[UE %d] Prepare a %s (Transport Block Size %d, MAC pdu Size %d) \n", - module_idP, map_int_to_str(BSR_names, bsr_len), buflen, pdu); + { + LOG_D(MAC,"[UE %d] Prepare a %s (Transport Block Size %d, MAC pdu Size %d) \n", + module_idP, map_int_to_str(BSR_names, bsr_len), buflen, pdu); + } + else if (rlc_status.bytes_in_buffer){ + LOG_I(MAC,"[UE %d] UL Transport Block size is 0 while RLC has pending data=%d pdu=%d\n", + module_idP, rlc_status.bytes_in_buffer,pdu); + + } return bsr_len; } @@ -2098,8 +2251,8 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, eNB_index_t eNB_in UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id] += rlc_status.bytes_in_buffer; UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); // UE_mac_inst[module_idP].scheduling_info.BSR_short_lcid = lcid; // only applicable to short bsr - LOG_D(MAC,"[UE %d] BSR level %d (LCGID %d, rlc buffer %d byte)\n", - module_idP, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id],lcg_id, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); + LOG_D(MAC,"[UE %d] SR Triggered BSR level %d (LCID %d LCGID %d, rlc buffer=%d byte Total BO=%d)\n", + module_idP, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id],lcid,lcg_id, rlc_status.bytes_in_buffer, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); } else { UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid]=LCID_EMPTY; } From c0ad88e537b457685cbeefab0c8771a27ce8893b Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Wed, 16 Nov 2016 16:12:30 +0200 Subject: [PATCH 291/413] Fixed bug in the creation of MAC PDUs in the local flexran scheduler --- openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index 73d82507a5..bc0187cd56 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -353,7 +353,7 @@ flexran_schedule_ue_spec_default(mid_t mod_id, header_len+=3; // Need to see if we have space for data from this channel - if (dci_tbs - ta_len - header_len > 0) { + if (dci_tbs - ta_len - header_len - sdu_length_total > 0) { LOG_D(MAC, "[TEST]Requested %d bytes from RLC buffer on channel %d during first call\n", dci_tbs-ta_len-header_len); //If we have space, we need to see how much data we can request at most (if any available) rlc_status = mac_rlc_status_ind(mod_id, @@ -396,7 +396,7 @@ flexran_schedule_ue_spec_default(mid_t mod_id, dl_data[num_ues_added]->n_rlc_pdu++; channels_added++; //Set this to the max value that we might request - sdu_length_total = data_to_request; + sdu_length_total += data_to_request; } else { //Take back the assumption of a header for this channel header_len -= 3; From f116a10de3847a4403c4a9bc167ef6579db6fcf3 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 16 Nov 2016 15:20:18 +0100 Subject: [PATCH 292/413] hotfix: turbo decoder should not fail if CRC is 0 The case of a CRC == 0 is legal. After discussion with Raymond, it is also possible to have all bits at 0 (and so a CRC==0) if there is no transmission and thus not much energy. So this hotfix may introduce new problems (false decoding). A future work is to handle this case properly by not calling the turbo decoder if there is not enough energy received. The problem might manifest itself more in the UE part, especially when it tries to decode MIB and/or SIB (if I understood correctly). --- openair1/PHY/CODING/3gpplte_turbo_decoder.c | 2 +- openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c | 2 +- openair1/PHY/CODING/3gpplte_turbo_decoder_sse.c | 2 +- openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c | 2 +- openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder.c b/openair1/PHY/CODING/3gpplte_turbo_decoder.c index 931758c03b..c6976df164 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder.c @@ -1058,7 +1058,7 @@ unsigned char phy_threegpplte_turbo_decoder_scalar(llr_t *y, break; } - if ((crc == oldcrc) && (crc!=0)) { + if (crc == oldcrc) { return(iteration_cnt); } diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c index 49bb9d102c..4efd366bed 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_avx2_16bit.c @@ -1375,7 +1375,7 @@ unsigned char phy_threegpplte_turbo_decoder16avx2(int16_t *y, fprintf(fdavx2b,"oldcrc %x, crc %x, oldcrc_cw2 %x, crc_cw2 %x\n",oldcrc,crc,oldcrc_cw2,crc_cw2); #endif - if ((crc == oldcrc) && (crc!=0) && (crc_cw2 == oldcrc_cw2) && (crc_cw2!=0)) { + if (crc == oldcrc && crc_cw2 == oldcrc_cw2) { return(iteration_cnt); } } diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse.c index abcdc0521b..085dbb723c 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse.c @@ -2556,7 +2556,7 @@ unsigned char phy_threegpplte_turbo_decoder(short *y, stop_meas(intl2_stats); - if ((crc == oldcrc) && (crc!=0)) { + if (crc == oldcrc) { return(iteration_cnt); } } diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c index dc789d0404..a1e408dcda 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c @@ -1612,7 +1612,7 @@ unsigned char phy_threegpplte_turbo_decoder16(short *y, fprintf(fdsse4,"oldcrc %x, crc %x\n",oldcrc,crc); #endif - if ((crc == oldcrc) && (crc!=0)) { + if (crc == oldcrc) { return(iteration_cnt); } } diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c index b56aae4598..4cdfb4f794 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c @@ -1625,7 +1625,7 @@ unsigned char phy_threegpplte_turbo_decoder8(short *y, if (intl2_stats) stop_meas(intl2_stats); - if ((crc == oldcrc) && (crc!=0)) { + if (crc == oldcrc) { return(iteration_cnt); } } From 69ccc900e89ddea4711d86861aec4d7452d9dfbb Mon Sep 17 00:00:00 2001 From: fnabet Date: Wed, 16 Nov 2016 18:24:04 +0100 Subject: [PATCH 293/413] fix BSR long size and fill --- openair2/LAYER2/MAC/defs.h | 9 ++++----- openair2/LAYER2/MAC/ue_procedures.c | 8 +++----- targets/SIMU/USER/oaisim.c | 2 ++ 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 336f3f1039..82907eb40a 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -223,11 +223,10 @@ typedef struct { typedef BSR_SHORT BSR_TRUNCATED; /*!\brief mac control element: long buffer status report for all logical channel group ID*/ typedef struct { - uint32_t Buffer_size3:6; - uint32_t Buffer_size2:6; - uint32_t Buffer_size1:6; - uint32_t Buffer_size0:6; - uint32_t padding:8; + uint8_t Buffer_size3:6; + uint8_t Buffer_size2:6; + uint8_t Buffer_size1:6; + uint8_t Buffer_size0:6; } __attribute__((__packed__))BSR_LONG; #define BSR_LONG_SIZE (sizeof(BSR_LONG)) diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index c2701c5f39..65bb4c09aa 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -1147,8 +1147,6 @@ unsigned char generate_ulsch_header(uint8_t *mac_header, *(ce_ptr) = (long_bsr->Buffer_size0 << 2) | ((long_bsr->Buffer_size1 & 0x30) >> 4); *(ce_ptr + 1) = ((long_bsr->Buffer_size1 & 0x0F) << 4) | ((long_bsr->Buffer_size2 & 0x3C) >> 2); *(ce_ptr + 2) = ((long_bsr->Buffer_size2 & 0x03) << 2) | (long_bsr->Buffer_size3 & 0x3F); - /* Padding */ - *(ce_ptr + 3) = 0; ce_ptr += BSR_LONG_SIZE; // printf("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements); @@ -1347,7 +1345,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf bsr_ce_len = sizeof(BSR_SHORT); //1 byte } else{ - bsr_ce_len = sizeof(BSR_LONG); //3 bytes + bsr_ce_len = BSR_LONG_SIZE; //3 bytes } bsr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); @@ -1601,7 +1599,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf bsr_s = NULL; bsr_l = NULL ; //TO DO : compute padding or truncated BSR - } else if (bsr_ce_len == sizeof(BSR_LONG)) { + } else if (bsr_ce_len == BSR_LONG_SIZE) { bsr_s = NULL; bsr_l->Buffer_size0 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]; bsr_l->Buffer_size1 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1]; @@ -2194,7 +2192,7 @@ uint8_t get_bsr_len (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,ui } if ( (pdu > buflen) && (rlc_status.bytes_in_buffer > 0 ) ) { num_lcid +=1; - bsr_len = (num_lcid >= 2 ) ? sizeof(BSR_LONG) : sizeof(BSR_SHORT) ; + bsr_len = (num_lcid >= 2 ) ? BSR_LONG_SIZE : sizeof(BSR_SHORT) ; } else if (rlc_status.bytes_in_buffer) { LOG_I(MAC,"pdu smaller than TBS! pdu=%d TBS=%d lcid=%d rlc buffer=%d bsr len=%d num lcid=%d\n",pdu,buflen,lcid,rlc_status.bytes_in_buffer,bsr_len, num_lcid); diff --git a/targets/SIMU/USER/oaisim.c b/targets/SIMU/USER/oaisim.c index 79cd2fcc38..f136c605f8 100644 --- a/targets/SIMU/USER/oaisim.c +++ b/targets/SIMU/USER/oaisim.c @@ -122,6 +122,8 @@ char smbv_ip[16]; //#define K 2 /* averaging coefficient */ //#define TARGET_SF_TIME_NS 1000000 /* 1ms = 1000000 ns */ +uint8_t usim_test = 0; + frame_t frame = 0; char stats_buffer[16384]; channel_desc_t *eNB2UE[NUMBER_OF_eNB_MAX][NUMBER_OF_UE_MAX][MAX_NUM_CCs]; From 64615dcc8ef3ada3258c891027fd233a8cb2d8da Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 18 Nov 2016 09:40:14 +0100 Subject: [PATCH 294/413] hotfix: correct PHICH generation The PHICH generation is wrong. HARQ process X is uplink scheduled at TTI n. At TTI n+4 the eNB receives the data. At TTI n+8 the eNB sends ACK/NACK on the PHICH. The problem is that PHICH generation is done after scheduling. And PHICH generation uses "first_rb" and "n_DMRS" to compute "ngroup_PHICH" and "nseq_PHICH". So at TTI n+8 if the eNB has reused the HARQ process X for a new uplink scheduling the values "first_rb" and "n_DMRS" may have changed. We need to use the previous values. One solution would have been to do PHICH generation before scheduling. The problem is that "generate_phich_top" does more than PHICH generation. It has to setup parameters to sort of "emulate" a DCI0 in case of retransmission scheduled without DCI0. So part of it has to be done after scheduling. We would have to split the function. The simple adopted fix is to store old values of "first_rb" and "n_DMRS" and use those values in "generate_phich_top". This fix has only been tested with FDD. TDD may miserably fail. --- openair1/PHY/LTE_TRANSPORT/defs.h | 8 +++++++ openair1/PHY/LTE_TRANSPORT/phich.c | 16 ++++++++----- openair1/SCHED/phy_procedures_lte_eNb.c | 32 +++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/defs.h b/openair1/PHY/LTE_TRANSPORT/defs.h index 83b34971da..01d6cdc449 100644 --- a/openair1/PHY/LTE_TRANSPORT/defs.h +++ b/openair1/PHY/LTE_TRANSPORT/defs.h @@ -360,6 +360,10 @@ typedef struct { uint8_t TPC; /// First Allocated RB uint16_t first_rb; + /// First Allocated RB - previous scheduling + /// This is needed for PHICH generation which + /// is done after a new scheduling + uint16_t previous_first_rb; /// Current Number of RBs uint16_t nb_rb; /// Transport block size @@ -444,6 +448,10 @@ typedef struct { uint8_t Nsymb_initial; /// n_DMRS for cyclic shift of DMRS (36.213 Table 9.1.2-2) uint8_t n_DMRS; + /// n_DMRS for cyclic shift of DMRS (36.213 Table 9.1.2-2) - previous scheduling + /// This is needed for PHICH generation which + /// is done after a new scheduling + uint8_t previous_n_DMRS; /// n_DMRS 2 for cyclic shift of DMRS (36.211 Table 5.5.1.1.-1) uint8_t n_DMRS2; /// Flag to indicate that this ULSCH is for calibration information sent from UE (i.e. no MAC SDU to pass up) diff --git a/openair1/PHY/LTE_TRANSPORT/phich.c b/openair1/PHY/LTE_TRANSPORT/phich.c index 1727ec5324..b0665d89ce 100644 --- a/openair1/PHY/LTE_TRANSPORT/phich.c +++ b/openair1/PHY/LTE_TRANSPORT/phich.c @@ -1453,8 +1453,12 @@ void generate_phich_top(PHY_VARS_eNB *eNB, LOG_D(PHY,"[eNB][PUSCH %d/%x] Frame %d subframe %d (pusch_subframe %d,pusch_frame %d) phich active %d\n", harq_pid,ulsch[UE_id]->rnti,proc->frame_tx,subframe,pusch_subframe,pusch_frame,ulsch[UE_id]->harq_processes[harq_pid]->phich_active); - ngroup_PHICH = (ulsch[UE_id]->harq_processes[harq_pid]->first_rb + - ulsch[UE_id]->harq_processes[harq_pid]->n_DMRS)%Ngroup_PHICH; + /* the HARQ process may have been reused by a new scheduling, so we use + * previous values of first_rb and n_DMRS to compute ngroup_PHICH and nseq_PHICH + */ + + ngroup_PHICH = (ulsch[UE_id]->harq_processes[harq_pid]->previous_first_rb + + ulsch[UE_id]->harq_processes[harq_pid]->previous_n_DMRS)%Ngroup_PHICH; if ((frame_parms->tdd_config == 0) && (frame_parms->frame_type == TDD) ) { @@ -1462,20 +1466,20 @@ void generate_phich_top(PHY_VARS_eNB *eNB, ngroup_PHICH += Ngroup_PHICH; } - nseq_PHICH = ((ulsch[UE_id]->harq_processes[harq_pid]->first_rb/Ngroup_PHICH) + - ulsch[UE_id]->harq_processes[harq_pid]->n_DMRS)%(2*NSF_PHICH); + nseq_PHICH = ((ulsch[UE_id]->harq_processes[harq_pid]->previous_first_rb/Ngroup_PHICH) + + ulsch[UE_id]->harq_processes[harq_pid]->previous_n_DMRS)%(2*NSF_PHICH); LOG_D(PHY,"[eNB %d][PUSCH %d] Frame %d subframe %d Generating PHICH, ngroup_PHICH %d/%d, nseq_PHICH %d : HI %d, first_rb %d dci_alloc %d)\n", eNB->Mod_id,harq_pid,proc->frame_tx, subframe,ngroup_PHICH,Ngroup_PHICH,nseq_PHICH, ulsch[UE_id]->harq_processes[harq_pid]->phich_ACK, - ulsch[UE_id]->harq_processes[harq_pid]->first_rb, + ulsch[UE_id]->harq_processes[harq_pid]->previous_first_rb, ulsch[UE_id]->harq_processes[harq_pid]->dci_alloc); if (ulsch[UE_id]->Msg3_active == 1) { LOG_D(PHY,"[eNB %d][PUSCH %d][RAPROC] Frame %d, subframe %d: Generating Msg3 PHICH for UE %d, ngroup_PHICH %d/%d, nseq_PHICH %d : HI %d, first_rb %d\n", eNB->Mod_id,harq_pid,proc->frame_tx,subframe, UE_id,ngroup_PHICH,Ngroup_PHICH,nseq_PHICH,ulsch[UE_id]->harq_processes[harq_pid]->phich_ACK, - ulsch[UE_id]->harq_processes[harq_pid]->first_rb); + ulsch[UE_id]->harq_processes[harq_pid]->previous_first_rb); } if (eNB->abstraction_flag == 0) { diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 4163b8340c..7ac6e2bf1f 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -1206,6 +1206,38 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, eNB->dlsch[i][0]->subframe_tx[subframe] = 0; } + /* save old HARQ information needed for PHICH generation */ + for (i=0; iulsch[i]) { + /* Store first_rb and n_DMRS for correct PHICH generation below. + * For PHICH generation we need "old" values of last scheduling + * for this HARQ process. 'generate_eNB_dlsch_params' below will + * overwrite first_rb and n_DMRS and 'generate_phich_top', done + * after 'generate_eNB_dlsch_params', would use the "new" values + * instead of the "old" ones. + * + * This has been tested for FDD only, may be wrong for TDD. + * + * TODO: maybe we should restructure the code to be sure it + * is done correctly. The main concern is if the code + * changes and first_rb and n_DMRS are modified before + * we reach here, then the PHICH processing will be wrong, + * using wrong first_rb and n_DMRS values to compute + * ngroup_PHICH and nseq_PHICH. + * + * TODO: check if that works with TDD. + */ + if ((subframe_select(fp,ul_subframe)==SF_UL) || + (fp->frame_type == FDD)) { + harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); + eNB->ulsch[i]->harq_processes[harq_pid]->previous_first_rb = + eNB->ulsch[i]->harq_processes[harq_pid]->first_rb; + eNB->ulsch[i]->harq_processes[harq_pid]->previous_n_DMRS = + eNB->ulsch[i]->harq_processes[harq_pid]->n_DMRS; + } + } + } + num_pdcch_symbols = DCI_pdu->num_pdcch_symbols; LOG_D(PHY,"num_pdcch_symbols %"PRIu8",(dci common %"PRIu8", dci uespec %"PRIu8"\n",num_pdcch_symbols, From 319ae6fbbf7034c96e600dabde81fcd0ef474a51 Mon Sep 17 00:00:00 2001 From: calvin wang Date: Fri, 18 Nov 2016 16:44:18 +0800 Subject: [PATCH 295/413] fix bsr report inaccurate value --- openair2/LAYER2/MAC/config.c | 53 +++++++------ openair2/LAYER2/MAC/defs.h | 8 +- openair2/LAYER2/MAC/proto.h | 6 +- openair2/LAYER2/MAC/ue_procedures.c | 115 +++++++++++++++++----------- 4 files changed, 109 insertions(+), 73 deletions(-) diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 2a6390740c..86062edfa9 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -1,24 +1,31 @@ -/* - * 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 - */ +/******************************************************************************* + 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ /*! \file config.c * \brief UE and eNB configuration performed by RRC or as a consequence of RRC procedures * \author Navid Nikaein and Raymond Knopp @@ -73,6 +80,7 @@ void ue_mac_reset(module_id_t module_idP,uint8_t eNB_index) UE_mac_inst[module_idP].BSR_reporting_active[PADDING_BSR]=0; UE_mac_inst[module_idP].BSR_reporting_active[PERIODIC_BSR]=0; UE_mac_inst[module_idP].retxBSRTimer_expires_flag = 0; + UE_mac_inst[module_idP].periodBSRTimer_expires_flag = 0; // stop ongoing RACH procedure // discard explicitly signaled ra_PreambleIndex and ra_RACH_MaskIndex, if any @@ -247,12 +255,13 @@ rrc_mac_config_req( UE_mac_inst[Mod_idP].scheduling_info.extendedPHR_r10 = (uint16_t)0; } #endif - UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = 0xFFFF; - UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = 0xFFFF; + UE_mac_inst[Mod_idP].scheduling_info.periodicBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; + UE_mac_inst[Mod_idP].scheduling_info.retxBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; UE_mac_inst[Mod_idP].BSR_reporting_active[REGULAR_BSR]=0; UE_mac_inst[Mod_idP].BSR_reporting_active[PADDING_BSR]=0; UE_mac_inst[Mod_idP].BSR_reporting_active[PERIODIC_BSR]=0; UE_mac_inst[Mod_idP].retxBSRTimer_expires_flag = 0; + UE_mac_inst[Mod_idP].periodBSRTimer_expires_flag = 0; LOG_D(MAC,"[UE %d]: periodic BSR %d (SF), retx BSR %d (SF)\n", Mod_idP, diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index c44144d8e7..426ebc610e 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -133,6 +133,8 @@ /*!\brief maximum value for channel quality indicator */ #define MAX_CQI_VALUE 15 +//if value equal oxFFFF means counters are NOT active +#define MAC_UE_BSR_TIMER_NOT_RUNNING (0xFFFF) #define LCID_EMPTY 0 #define LCID_NOT_EMPTY 1 @@ -226,7 +228,6 @@ typedef struct { uint32_t Buffer_size2:6; uint32_t Buffer_size1:6; uint32_t Buffer_size0:6; - uint32_t padding:8; } __attribute__((__packed__))BSR_LONG; #define BSR_LONG_SIZE (sizeof(BSR_LONG)) @@ -345,6 +346,7 @@ typedef enum { PERIODIC_BSR } UE_FIRST_LEVEL_BSR_TYPE; + /*! \brief Downlink SCH PDU Structure */ typedef struct { int8_t payload[8][SCH_PAYLOAD_SIZE_MAX]; @@ -1096,7 +1098,9 @@ typedef struct { uint8_t BSR_reporting_active[BSR_TYPE_FIRST_LEVEL]; /// retxBSR-Timer expires flag uint8_t retxBSRTimer_expires_flag; - + /// periodBSR-Timer expires flag + uint8_t periodBSRTimer_expires_flag; + /// MBSFN_Subframe Configuration struct MBSFN_SubframeConfig *mbsfn_SubframeConfig[8]; // FIXME replace 8 by MAX_MBSFN_AREA? /// number of subframe allocation pattern available for MBSFN sync area diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 3733b27336..69dc7baade 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -538,14 +538,14 @@ UE_L2_STATE_t ue_scheduler( */ int cba_access(module_id_t module_idP,frame_t frameP,sub_frame_t subframe, uint8_t eNB_index,uint16_t buflen); -/*! \fn int get_bsr_lcgid (module_id_t module_idP); +/*! \fn int update_bsr_and_get_bsr_lcgid (module_id_t module_idP); \brief determine the lcgid for the bsr \param[in] Mod_id instance of the UE \param[out] lcgid */ -int get_bsr_lcgid (module_id_t module_idP); +int update_bsr_and_get_bsr_lcgid (module_id_t module_idP); -/*! \fn int get_bsr_type (module_id_t module_idP,uint16_t bufflen); +/*! \fn int get_bsr_type (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint16_t buflen); \brief determine whether the bsr is short or long assuming that the MAC pdu is built \param[in] Mod_id instance of the UE \param[in] bufflen size of phy transport block diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index d9888b0ba5..4d21762924 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -91,7 +91,7 @@ void ue_init_mac(module_id_t module_idP) // default values as deined in 36.331 sec 9.2.2 LOG_I(MAC,"[UE%d] Applying default macMainConfig\n",module_idP); //UE_mac_inst[module_idP].scheduling_info.macConfig=NULL; - UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer= MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf2560; + UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer= MAC_MainConfig__ul_SCH_Config__retxBSR_Timer_sf10240; UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer=MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity; UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer = MAC_MainConfig__phr_Config__setup__periodicPHR_Timer_sf20; UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer = MAC_MainConfig__phr_Config__setup__prohibitPHR_Timer_sf20; @@ -107,13 +107,14 @@ void ue_init_mac(module_id_t module_idP) UE_mac_inst[module_idP].scheduling_info.drx_config=NULL; UE_mac_inst[module_idP].scheduling_info.phr_config=NULL; // set init value 0xFFFF, make sure periodic timer and retx time counters are NOT active, after bsr transmission set the value configured by the NW. - UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = 0xFFFF; - UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = 0xFFFF; + UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = MAC_UE_BSR_TIMER_NOT_RUNNING; UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR]=0; UE_mac_inst[module_idP].BSR_reporting_active[PADDING_BSR]=0; UE_mac_inst[module_idP].BSR_reporting_active[PERIODIC_BSR]=0; UE_mac_inst[module_idP].retxBSRTimer_expires_flag = 0; + UE_mac_inst[module_idP].periodBSRTimer_expires_flag = 0; UE_mac_inst[module_idP].scheduling_info.periodicPHR_SF = get_sf_perioidicPHR_Timer(UE_mac_inst[module_idP].scheduling_info.periodicPHR_Timer); UE_mac_inst[module_idP].scheduling_info.prohibitPHR_SF = get_sf_prohibitPHR_Timer(UE_mac_inst[module_idP].scheduling_info.prohibitPHR_Timer); UE_mac_inst[module_idP].scheduling_info.PathlossChange_db = get_db_dl_PathlossChange(UE_mac_inst[module_idP].scheduling_info.PathlossChange); @@ -320,6 +321,7 @@ uint32_t ue_get_SR(module_id_t module_idP,int CC_id,frame_t frameP,uint8_t eNB_i UE_mac_inst[module_idP].BSR_reporting_active[PADDING_BSR]=0; UE_mac_inst[module_idP].BSR_reporting_active[PERIODIC_BSR]=0; UE_mac_inst[module_idP].retxBSRTimer_expires_flag = 0; + UE_mac_inst[module_idP].periodBSRTimer_expires_flag = 0; LOG_T(MAC,"[UE %d] Release all SRs \n", module_idP); return(0); } @@ -1359,12 +1361,25 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf num_sdus = 1; //update_bsr(module_idP, frameP, eNB_index, DCCH, UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]); //header_len +=2; + // update LCID remain buffer UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH] = LCID_EMPTY; if (rlc_status.bytes_in_buffer > sdu_lengths[0]) { UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH] = rlc_status.bytes_in_buffer-sdu_lengths[0]; } else { UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH] = 0; } + // update LCGID buffer, in order to get right BSR value + if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] > sdu_lengths[0]) { + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] -= sdu_lengths[0]; + } else { + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] = 0; + LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data to transmit=%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[DCCH]], + UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH], + rlc_status.bytes_in_buffer,DCCH); + } + } else { dcch_header_len=0; num_sdus = 0; @@ -1408,7 +1423,11 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf } else { UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1] = 0; } - + if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] > sdu_lengths[num_sdus]) { + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] -= sdu_lengths[num_sdus]; + } else { + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] = 0; + } num_sdus++; } else { dcch1_header_len =0; @@ -1416,7 +1435,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len=0; dtch_header_len_last=0; - for (lcid=NB_RB_MAX-1; lcid>=DTCH ; lcid--){ + for (lcid=MAX_NUM_LCID-1; lcid>=DTCH ; lcid--){ dtch_header_len+=3; dtch_header_len_last=3; @@ -1469,7 +1488,13 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf } else { UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] = 0; } - + 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 { + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] = 0; + } + printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~rlc_status.bytes_in_buffer %d,sdu_lengths[num_sdus] %d buflen %d all_pdu_len %d\n" + ,rlc_status.bytes_in_buffer ,sdu_lengths[num_sdus],buflen, all_pdu_len); //UE_mac_inst[module_idP].ul_active = update_bsr(module_idP, frameP, eNB_index,lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]); num_sdus++; } else { @@ -1481,13 +1506,13 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf } } - lcgid= get_bsr_lcgid(module_idP); + lcgid= update_bsr_and_get_bsr_lcgid(module_idP); if (lcgid < 0 ) { bsr_s = NULL; bsr_l = NULL; bsr_t = NULL; - } else if ((lcgid ==MAX_NUM_LCGID) && (bsr_type == LONG_BSR)) { + } else if (bsr_type == LONG_BSR) { bsr_s = NULL; bsr_t = NULL; bsr_l->Buffer_size0 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0]; @@ -1500,15 +1525,6 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]); - - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID0] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID1] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID2] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[LCGID3] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3] = 0; } else if (bsr_type == SHORT_BSR) { bsr_l = NULL; bsr_t = NULL; @@ -1517,8 +1533,6 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf LOG_I(MAC,"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%[UE %d] Frame %d SubFrame %d,report SHORT BSR with level %d for LCGID %d\n", module_idP, frameP, subframe, UE_mac_inst[module_idP].scheduling_info.BSR[lcgid],lcgid); - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] = 0; } else if (bsr_type == TRUNCATED_BSR) { bsr_l = NULL; bsr_s = NULL; @@ -1527,8 +1541,6 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf LOG_D(MAC,"[UE %d] Frame %d report SHORT BSR with level %d for LCGID %d\n", module_idP, frameP, UE_mac_inst[module_idP].scheduling_info.BSR[lcgid],lcgid); - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid] = 0; - UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] = 0; } else { bsr_s = NULL; bsr_l = NULL; @@ -1620,6 +1632,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); UE_mac_inst[module_idP].retxBSRTimer_expires_flag = 0; + UE_mac_inst[module_idP].periodBSRTimer_expires_flag = 0; } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GET_SDU, VCD_FUNCTION_OUT); stop_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu); @@ -1789,7 +1802,7 @@ ue_scheduler( /* periodicBSR-Timer expires, in which case the BSR is referred below to as "Periodic BSR". */ - UE_mac_inst[module_idP].BSR_reporting_active[PERIODIC_BSR] = 1; + UE_mac_inst[module_idP].periodBSRTimer_expires_flag = 1; UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = periodicBSR_Timer_infinity_value; } else { UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF--; @@ -2057,16 +2070,18 @@ int cba_access(module_id_t module_idP,frame_t frameP,sub_frame_t subframe, uint8 } #endif -int get_bsr_lcgid (module_id_t module_idP) +//AFTER transmission update BSR value, and get witch LCGID have BSR +int update_bsr_and_get_bsr_lcgid (module_id_t module_idP) { int lcgid, lcgid_tmp=-1; int num_active_lcgid = 0; for (lcgid = 0 ; lcgid < MAX_NUM_LCGID; lcgid++) { + // update BSR value, then ue can reprot correct value + UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] = locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcgid]); if (UE_mac_inst[module_idP].scheduling_info.BSR[lcgid] > 0 ) { lcgid_tmp = lcgid; num_active_lcgid+=1; - printf("////////////////////////////////lcgid %d, BSR %d\n",lcgid,UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]); } } @@ -2087,12 +2102,12 @@ int get_bsr_type (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint1 mac_rlc_status_resp_t rlc_status; int long_bsr_size=sizeof(SCH_SUBHEADER_FIXED)+sizeof(BSR_LONG); int short_bsr_size=sizeof(SCH_SUBHEADER_FIXED)+sizeof(BSR_SHORT); - int bsr_group_id[MAX_NUM_LCGID]; - int lcg_report_num=0; + int lcgid_have_bsr_report_flag[MAX_NUM_LCGID]; + int num_lcg_id_with_data=0; int new_data_arrived_flag=0; for (lcgid=0; lcgid < MAX_NUM_LCGID; lcgid++ ) { - bsr_group_id[lcgid] = 0; + lcgid_have_bsr_report_flag[lcgid] = 0; } for (lcid=DCCH; lcid 128 ) { @@ -2113,43 +2133,46 @@ int get_bsr_type (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint1 which belong to any LCG and for which data is already available for transmission */ if (rlc_status.bytes_in_buffer > UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]) { - bsr_group_id[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] ++; + lcgid_have_bsr_report_flag[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] = 1; new_data_arrived_flag = 1; - UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR] = 1; } } } -/* // one lcid buffer increased and all lcid buffer increased if ((new_data_arrived_flag == 1) && (pdu > UE_mac_inst[module_idP].scheduling_info.All_lcid_buffer_size_lastTTI)) { UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR] = 1; } -*/ - UE_mac_inst[module_idP].scheduling_info.All_lcid_buffer_size_lastTTI = pdu; - - /* or there is no data available for transmission for any of the logical channels which belong to a LCG, - in which case the BSR is referred below to as "Regular BSR" - if (pdu == 0) { + /* empty buffer, report 0 bsr reset eNB buffer + */ + if ((pdu == 0) && (UE_mac_inst[module_idP].scheduling_info.All_lcid_buffer_size_lastTTI > 0)) { UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR] = 1; } - */ - // computed how many LCG has data available for transmission + UE_mac_inst[module_idP].scheduling_info.All_lcid_buffer_size_lastTTI = pdu; + + // computed how many LCGID has data available for transmission for (lcgid=0; lcgid < MAX_NUM_LCGID; lcgid++ ) { - if (bsr_group_id[lcgid] > 0) { - lcg_report_num ++; - printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@lcgid bsr %d > 0\n",lcgid); + if (lcgid_have_bsr_report_flag[lcgid] == 1) { + num_lcg_id_with_data ++; + printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@lcgid %d have bsr report\n",lcgid); } } /* UL resources are allocated and number of padding bits is equal to or larger than the size of the Buffer Status Report MAC control element plus its subheader, in which case the BSR is referred below to as "Padding BSR" - */ if ((pdu > 0) && ((pdu+long_bsr_size) <= buflen)) { UE_mac_inst[module_idP].BSR_reporting_active[PADDING_BSR] = 1; } + */ + + if ((pdu+long_bsr_size) <= buflen) { + UE_mac_inst[module_idP].BSR_reporting_active[PADDING_BSR] = 0; + UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR] = 0; + UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR] = 0; + //printf("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&ping test\n"); + } /* For Regular and Periodic BSR - if more than one LCG has data available for transmission in the TTI where the BSR is transmitted: report Long BSR; @@ -2157,7 +2180,7 @@ int get_bsr_type (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint1 */ if ((UE_mac_inst[module_idP].BSR_reporting_active[REGULAR_BSR] == 1) || (UE_mac_inst[module_idP].BSR_reporting_active[PERIODIC_BSR] == 1)) { - if (lcg_report_num > 1) { + if (num_lcg_id_with_data > 1) { bsr_type = LONG_BSR; } else { bsr_type = SHORT_BSR; @@ -2172,13 +2195,13 @@ int get_bsr_type (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint1 */ if (UE_mac_inst[module_idP].BSR_reporting_active[PADDING_BSR] == 1) { if (((pdu + short_bsr_size) <= buflen)&&(buflen<(pdu + long_bsr_size))) { - if (lcg_report_num > 1) { + if (num_lcg_id_with_data > 1) { bsr_type = TRUNCATED_BSR; } else { bsr_type = SHORT_BSR; } } else if ((pdu + long_bsr_size) <= buflen) { - if (lcg_report_num > 1) { + if (num_lcg_id_with_data > 1) { bsr_type = LONG_BSR; } else { bsr_type = SHORT_BSR; @@ -2189,7 +2212,7 @@ int get_bsr_type (module_id_t module_idP, uint8_t eNB_index,frame_t frameP,uint1 if ( bsr_type > 0 ) { LOG_I(MAC, "[UE %d] bsr_type %d (Transport Block Size %d, MAC pdu len %d) lcg_report_num %d\n", - module_idP, bsr_type, buflen, pdu, lcg_report_num); + module_idP, bsr_type, buflen, pdu, num_lcg_id_with_data); } return bsr_type; From c03f13c07b1cb4af8bf222ca0cb256dcaba0da5b Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 18 Nov 2016 10:29:48 +0100 Subject: [PATCH 296/413] T: add a trace for PHICH --- common/utils/T/T_messages.txt | 4 ++++ openair1/PHY/LTE_TRANSPORT/phich.c | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index 321225a597..6e5e0ad7aa 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -61,6 +61,10 @@ ID = ENB_PHY_PUCCH_1_ENERGY DESC = eNodeB PUCCH 1 energy and threshold GROUP = ALL:PHY:GRAPHIC:HEAVY:ENB FORMAT = int,eNB_ID : int,UE_ID : int,frame : int,subframe : int,energy : int,threshold +ID = ENB_PHY_PHICH + DESC = eNodeB PHICH + GROUP = ALL:PHY:ENB + FORMAT = int,eNB_ID : int,frame : int,subframe : int,UE_id : int,rnti : int,harq_pid : int,NGROUP : int,NSF : int,ngroup : int,nseq : int,ACK : int,first_rb : int,n_DMRS #MAC logs ID = ENB_MAC_UE_DL_SDU diff --git a/openair1/PHY/LTE_TRANSPORT/phich.c b/openair1/PHY/LTE_TRANSPORT/phich.c index b0665d89ce..6b66ee0282 100644 --- a/openair1/PHY/LTE_TRANSPORT/phich.c +++ b/openair1/PHY/LTE_TRANSPORT/phich.c @@ -1475,6 +1475,14 @@ void generate_phich_top(PHY_VARS_eNB *eNB, ulsch[UE_id]->harq_processes[harq_pid]->previous_first_rb, ulsch[UE_id]->harq_processes[harq_pid]->dci_alloc); + T(T_ENB_PHY_PHICH, T_INT(eNB->Mod_id), T_INT(proc->frame_tx), T_INT(subframe), + T_INT(UE_id), T_INT(ulsch[UE_id]->rnti), T_INT(harq_pid), + T_INT(Ngroup_PHICH), T_INT(NSF_PHICH), + T_INT(ngroup_PHICH), T_INT(nseq_PHICH), + T_INT(ulsch[UE_id]->harq_processes[harq_pid]->phich_ACK), + T_INT(ulsch[UE_id]->harq_processes[harq_pid]->previous_first_rb), + T_INT(ulsch[UE_id]->harq_processes[harq_pid]->previous_n_DMRS)); + if (ulsch[UE_id]->Msg3_active == 1) { LOG_D(PHY,"[eNB %d][PUSCH %d][RAPROC] Frame %d, subframe %d: Generating Msg3 PHICH for UE %d, ngroup_PHICH %d/%d, nseq_PHICH %d : HI %d, first_rb %d\n", eNB->Mod_id,harq_pid,proc->frame_tx,subframe, From 7f74065484a6f30e82116fc65e0931698b0cfb38 Mon Sep 17 00:00:00 2001 From: GabrirelCouturier Date: Fri, 18 Nov 2016 15:22:11 +0100 Subject: [PATCH 297/413] BSR fixes for ping --- openair2/LAYER2/MAC/ue_procedures.c | 162 +++++++++++++++++----------- 1 file changed, 102 insertions(+), 60 deletions(-) diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 65bb4c09aa..cad41c86a5 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -1313,20 +1313,23 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf } if (num_lcg_id_with_data){ - LOG_I(MAC,"[UE %d] MAC Tx data pending at frame%d subframe %d nb LCG =%d LCG0 bytes=%d BSR Trigger status =%d TBS=%d\n", - module_idP, frameP, subframe, num_lcg_id_with_data, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[0],UE_mac_inst[module_idP].BSR_reporting_active, buflen); + LOG_D(MAC,"[UE %d] MAC Tx data pending at frame%d subframe %d nb LCG =%d Bytes for LCG0=%d LCG1=%d LCG2=%d LCG3=%d BSR Trigger status =%d TBS=%d\n", + module_idP, + frameP, + subframe, + num_lcg_id_with_data, + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[0], + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[1], + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[2], + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[3], + UE_mac_inst[module_idP].BSR_reporting_active, buflen); } - // ReTxBSR-Timer expires, trigger BSR - if ((num_lcg_id_with_data) && (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF == 0)){ - - // If the UE has data to transmit, trigger a BSR - UE_mac_inst[module_idP].BSR_reporting_active = 1; - - LOG_I(MAC,"[UE %d] MAC BSR Triggered ReTxBSR Timer expiry at frame%d subframe %d TBS=%d\n", - module_idP, frameP, subframe, buflen); - + //Restart ReTxBSR Timer at new grant indication (36.321) + if (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF != MAC_UE_BSR_TIMER_NOT_RUNNING){ + UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); } + // periodicBSR-Timer expires, trigger BSR if ((UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer != MAC_MainConfig__ul_SCH_Config__periodicBSR_Timer_infinity) && (UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF == 0)){ @@ -1342,6 +1345,17 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf if (UE_mac_inst[module_idP].BSR_reporting_active){ if (buflen >= 4){ if (num_lcg_id_with_data <= 1){ + + // If there are no data to transmit Set LCGID short to the group of the first DTCH configured else it will be SRB + if (num_lcg_id_with_data == 0) { + for (lcid=DTCH; lcid < MAX_NUM_LCID; lcid++) { + if (UE_mac_inst[module_idP].logicalChannelConfig[lcid] != NULL) { + lcg_id_bsr_short = UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]; + break; + } + } + } + bsr_ce_len = sizeof(BSR_SHORT); //1 byte } else{ @@ -1417,31 +1431,33 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf DCCH, (buflen-dcch_header_len-bsr_len-phr_len)); LOG_D(MAC, "[UE %d] Frame %d : UL-DCCH -> ULSCH, RLC SRB1 has %d bytes to " - "send (Transport Block size %d BSR size=%d PHR=%d SDU Length Total %d , mac header len %d)\n", - module_idP,frameP, rlc_status.bytes_in_buffer,buflen,bsr_len,phr_len,sdu_length_total,dcch_header_len); + "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, rlc_status.bytes_in_buffer,buflen,bsr_len,phr_len,sdu_length_total,dcch_header_len,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]]); - /* Update BSR : substract transmitted data */ - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] >= rlc_status.bytes_in_buffer){ - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] -= rlc_status.bytes_in_buffer; - } - else if (rlc_status.bytes_in_buffer){ - LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data to transmit=%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[DCCH]], - UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH], - rlc_status.bytes_in_buffer,DCCH); - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] = 0; - } - sdu_lengths[0] += mac_rlc_data_req(module_idP, + sdu_lengths[0] += mac_rlc_data_req(module_idP, UE_mac_inst[module_idP].crnti, eNB_index, frameP, - ENB_FLAG_NO, + ENB_FLAG_NO, MBMS_FLAG_NO, DCCH, (char *)&ulsch_buff[sdu_lengths[0]]); + /* Update BSR : substract transmitted data */ + if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] >= sdu_lengths[0]){ + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] -= sdu_lengths[0]; + } + 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[DCCH]], + UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH], + sdu_lengths[0],DCCH); + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] = 0; + } + + sdu_length_total += sdu_lengths[0]; sdu_lcids[0] = DCCH; LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU TX Got %d bytes for SRB1\n",module_idP,sdu_lengths[0]); @@ -1473,23 +1489,10 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf (buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-sdu_length_total)); LOG_D(MAC,"[UE %d] Frame %d subframe %d: UL-DCCH1 -> ULSCH, RLC SRB2 has %d bytes to" - " send (Transport Block size %d BSR size=%d PHR=%d SRB1 Hdr %d SDU Length Total %d , mac header len %d)\n", - module_idP,frameP, subframe, rlc_status.bytes_in_buffer,buflen,bsr_len,phr_len,dcch_header_len,sdu_length_total,dcch1_header_len); + " send (Transport Block size %d BSR size=%d PHR=%d SRB1 Hdr %d SDU Length Total %d , mac header len %d BSR byte before Tx=%d)\n", + module_idP,frameP, subframe, rlc_status.bytes_in_buffer,buflen,bsr_len,phr_len,dcch_header_len,sdu_length_total,dcch1_header_len,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]]); - /* Update BSR : substract transmitted data */ - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] >= rlc_status.bytes_in_buffer){ - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] -= rlc_status.bytes_in_buffer; - } - else if (rlc_status.bytes_in_buffer){ - LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data to transmit=%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[DCCH1]], - UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1], - rlc_status.bytes_in_buffer,DCCH1); - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] = 0; - } - - sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, UE_mac_inst[module_idP].crnti, eNB_index, frameP, @@ -1497,6 +1500,20 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf MBMS_FLAG_NO, DCCH1, (char *)&ulsch_buff[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[DCCH1]] >= sdu_lengths[num_sdus]){ + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] -= 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[DCCH1]], + UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1], + sdu_lengths[num_sdus],DCCH1); + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] = 0; + } + sdu_length_total += sdu_lengths[num_sdus]; sdu_lcids[num_sdus] = DCCH1; LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU Got %d bytes for SRB2\n",module_idP,sdu_lengths[num_sdus]); @@ -1513,7 +1530,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf dtch_header_len=0; dtch_header_len_last=0; - for (lcid=NB_RB_MAX-1; lcid>=DTCH ; lcid--){ + for (lcid=MAX_NUM_LCID-1; lcid>=DTCH ; lcid--){ dtch_header_len+=3; dtch_header_len_last=3; @@ -1521,6 +1538,8 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf if ((UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) && (all_pdu_len <= buflen)) { + AssertFatal (UE_mac_inst[module_idP].logicalChannelConfig[lcid] != NULL, "LCID (%d) is not active!\n", lcid); + // optimize the dtch header lenght //if ((UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DTCH] > 128) && /* if (((UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DTCH] >= 128) && @@ -1539,23 +1558,10 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf lcid, buflen-all_pdu_len); - LOG_D(MAC,"[UE %d] Frame %d : UL-DTCH -> ULSCH%d, %d bytes to send (Transport Block size %d, mac header len %d, BSR byte[%d] %d)\n", - module_idP,frameP, lcid, rlc_status.bytes_in_buffer,buflen,dtch_header_len, - lcid, 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 subframe %d: UL-DTCH -> ULSCH%d, %d bytes to send (Transport Block size %d, mac header len %d, BSR byte before Tx=%d)\n", + module_idP,frameP, subframe,lcid, rlc_status.bytes_in_buffer,buflen,dtch_header_len, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); if (rlc_status.bytes_in_buffer > 0) { - /* Update BSR : substract transmitted data */ - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] >= rlc_status.bytes_in_buffer){ - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] -= rlc_status.bytes_in_buffer; - } - else { - LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data to transmit=%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], - rlc_status.bytes_in_buffer,lcid); - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] = 0; - } sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, UE_mac_inst[module_idP].crnti, @@ -1566,8 +1572,21 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf lcid, (char *)&ulsch_buff[sdu_length_total]); + /* 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; + } + //adjust dtch header - LOG_D(MAC,"[UE %d] TX Got %d bytes for DTCH\n",module_idP,sdu_lengths[num_sdus]); + LOG_D(MAC,"[UE %d] Frame %d Subframe %d TX Got %d bytes for DTCH%d New BSR bytes=%d\n",module_idP,frameP,subframe,sdu_lengths[num_sdus],lcid,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); sdu_lcids[num_sdus] = lcid; sdu_length_total += sdu_lengths[num_sdus]; if (sdu_lengths[num_sdus] < 128) { @@ -1595,6 +1614,15 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id] = locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[lcg_id]); } + if (bsr_ce_len) { + //Print updated BSR when sent + LOG_D(MAC,"[UE %d] Frame %d Subframe %d TX BSR size=%d BSR0=%d BSR1=%d BSR2=%d BSR3=%d\n",module_idP,frameP,subframe,bsr_ce_len, + UE_mac_inst[module_idP].scheduling_info.BSR[0], + UE_mac_inst[module_idP].scheduling_info.BSR[1], + UE_mac_inst[module_idP].scheduling_info.BSR[2], + UE_mac_inst[module_idP].scheduling_info.BSR[3]); + } + if (bsr_ce_len == 0 ) { bsr_s = NULL; bsr_l = NULL ; @@ -1751,6 +1779,8 @@ ue_scheduler( // int8_t lcg_id; struct RACH_ConfigCommon *rach_ConfigCommon = (struct RACH_ConfigCommon *)NULL; protocol_ctxt_t ctxt; + int num_lcid_with_data = 0; + #if defined(ENABLE_ITTI) MessageDef *msg_p; const char *msg_name; @@ -1931,6 +1961,8 @@ ue_scheduler( } if (update_bsr(module_idP,frameP, eNB_indexP, lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid])) { + // TO DO: implement first BSR trigger criteria based on new data become available + num_lcid_with_data ++; UE_mac_inst[module_idP].scheduling_info.SR_pending= 1; // Regular BSR trigger UE_mac_inst[module_idP].BSR_reporting_active = 1; @@ -1942,6 +1974,16 @@ ue_scheduler( } } + // Trigger Regular BSR if ReTxBSR Timer has expired and UE has data for transmission + if ((num_lcid_with_data) && (UE_mac_inst[module_idP].scheduling_info.retxBSR_SF == 0)) { + + UE_mac_inst[module_idP].BSR_reporting_active = 1; + + LOG_D(MAC,"[UE %d] PDCCH Tick : MAC BSR Triggered ReTxBSR Timer expiry at frame %d subframe %d\n", + module_idP, frameP, subframeP); + + } + // UE has no valid phy config dedicated || no valid/released SR if ((UE_mac_inst[module_idP].physicalConfigDedicated == NULL)) { // cancel all pending SRs From 12f1cb9c7ceb53c9b4f2a9c50427a9d2a66b7a04 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Fri, 18 Nov 2016 16:23:01 +0100 Subject: [PATCH 298/413] fixing original dlsim from develop --- cmake_targets/CMakeLists.txt | 3 ++- openair1/PHY/MODULATION/defs.h | 2 +- openair1/PHY/MODULATION/ofdm_mod.c | 2 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 32 ++++++++++++++++--------- openair1/SIMULATION/LTE_PHY/dlsim_tm7.c | 4 ++-- targets/RT/USER/lte-enb.c | 4 ++-- 6 files changed, 29 insertions(+), 18 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 0619d4af7f..3f3b4f2fbe 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1840,7 +1840,7 @@ target_link_libraries (oaisim_nos1 ${T_LIB}) # Unitary tests for each piece of L1: example, mbmssim is MBMS L1 simulator ##################################### -foreach(myExe dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim) +foreach(myExe dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim) add_executable(${myExe} ${OPENAIR_BIN_DIR}/messages_xml.h ${OPENAIR1_DIR}/SIMULATION/LTE_PHY/${myExe}.c @@ -1920,6 +1920,7 @@ if (${T_TRACER}) add_dependencies(rrh_gw generate_T) add_dependencies(oaisim generate_T) add_dependencies(oaisim_nos1 generate_T) + add_dependencies(dlsim generate_T) add_dependencies(dlsim_tm7 generate_T) add_dependencies(ulsim generate_T) add_dependencies(pbchsim generate_T) diff --git a/openair1/PHY/MODULATION/defs.h b/openair1/PHY/MODULATION/defs.h index ce73d0461d..289b1edd43 100644 --- a/openair1/PHY/MODULATION/defs.h +++ b/openair1/PHY/MODULATION/defs.h @@ -82,7 +82,7 @@ void normal_prefix_mod(int32_t *txdataF,int32_t *txdata,uint8_t nsymb,LTE_DL_FRA void do_OFDM_mod(int32_t **txdataF, int32_t **txdata, uint32_t frame,uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms); -void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms); +void do_OFDM_mod_symbol(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms); void remove_7_5_kHz(PHY_VARS_eNB *phy_vars_eNB,uint8_t subframe); diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 6a4e72180b..2fd7fd88a3 100644 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -285,7 +285,7 @@ void do_OFDM_mod(int32_t **txdataF, int32_t **txdata, uint32_t frame,uint16_t ne } // OFDM modulation for each symbol -void do_OFDM_mod_l(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms) +void do_OFDM_mod_symbol(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms) { int aa, l, slot_offset; diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 40faf1049f..2e9a04def3 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -403,7 +403,8 @@ void fill_DCI(PHY_VARS_eNB *eNB, SI_RNTI, 0, P_RNTI, - eNB->UE_stats[0].DL_pmi_single); + eNB->UE_stats[0].DL_pmi_single, + transmission_mode>=7?transmission_mode:0); *num_dci = *num_dci+1; *num_ue_spec_dci = *num_ue_spec_dci+1; @@ -543,7 +544,8 @@ void fill_DCI(PHY_VARS_eNB *eNB, SI_RNTI, 0, P_RNTI, - eNB->UE_stats[0].DL_pmi_single); + eNB->UE_stats[0].DL_pmi_single, + transmission_mode>=7?transmission_mode:0); *num_common_dci=*num_common_dci+1; *num_dci = *num_dci + 1; @@ -710,7 +712,8 @@ void fill_DCI(PHY_VARS_eNB *eNB, SI_RNTI, 0, P_RNTI, - eNB->UE_stats[0].DL_pmi_single); + eNB->UE_stats[0].DL_pmi_single, + transmission_mode>=7?transmission_mode:0); *num_dci = *num_dci + 1; *num_ue_spec_dci = *num_ue_spec_dci + 1; @@ -850,7 +853,8 @@ void fill_DCI(PHY_VARS_eNB *eNB, SI_RNTI, 0, P_RNTI, - eNB->UE_stats[0].DL_pmi_single); + eNB->UE_stats[0].DL_pmi_single, + transmission_mode>=7?transmission_mode:0); *num_common_dci = *num_common_dci + 1; *num_dci = *num_dci + 1; @@ -1018,7 +1022,8 @@ void fill_DCI(PHY_VARS_eNB *eNB, SI_RNTI, 0, P_RNTI, - eNB->UE_stats[0].DL_pmi_single); + eNB->UE_stats[0].DL_pmi_single, + transmission_mode>=7?transmission_mode:0); *num_dci = *num_dci + 1; *num_ue_spec_dci = *num_ue_spec_dci + 1; @@ -1158,7 +1163,8 @@ void fill_DCI(PHY_VARS_eNB *eNB, SI_RNTI, 0, P_RNTI, - eNB->UE_stats[0].DL_pmi_single); + eNB->UE_stats[0].DL_pmi_single, + transmission_mode>=7?transmission_mode:0); *num_common_dci = *num_common_dci + 1; *num_dci = *num_dci + 1; @@ -1187,7 +1193,8 @@ void fill_DCI(PHY_VARS_eNB *eNB, SI_RNTI, 0, P_RNTI, - eNB->UE_stats[k].DL_pmi_single); + eNB->UE_stats[k].DL_pmi_single, + transmission_mode>=7?transmission_mode:0); dump_dci(&eNB->frame_parms,&dci_alloc[*num_dci]); *num_ue_spec_dci = *num_ue_spec_dci + 1; @@ -1762,7 +1769,8 @@ int main(int argc, char **argv) printf("dual_stream_UE=%d\n", dual_stream_UE); } - lte_param_init(n_tx, + lte_param_init(transmission_mode==1?1:2, + n_tx, n_rx, transmission_mode, extended_prefix_flag, @@ -2042,7 +2050,7 @@ int main(int argc, char **argv) for (k=0; kdlsch[k][i] = new_eNB_dlsch(Kmimo,8,Nsoft,N_RB_DL,0); + eNB->dlsch[k][i] = new_eNB_dlsch(Kmimo,8,Nsoft,N_RB_DL,0,&eNB->frame_parms); if (!eNB->dlsch[k][i]) { printf("Can't get eNB dlsch structures\n"); @@ -2065,7 +2073,7 @@ int main(int argc, char **argv) } // structure for SIC at UE - UE->dlsch_eNB[0] = new_eNB_dlsch(Kmimo,8,Nsoft,N_RB_DL,0); + UE->dlsch_eNB[0] = new_eNB_dlsch(Kmimo,8,Nsoft,N_RB_DL,0,&eNB->frame_parms); if (DLSCH_alloc_pdu2_1E[0].tpmi == 5) { @@ -2159,7 +2167,9 @@ int main(int argc, char **argv) get_Qm(eNB->dlsch[0][0]->harq_processes[0]->mcs), eNB->dlsch[0][0]->harq_processes[0]->Nl, num_pdcch_symbols, - 0,subframe); + 0, + subframe, + transmission_mode>=7?transmission_mode:0); uncoded_ber_bit = (short*) malloc(sizeof(short)*coded_bits_per_codeword); printf("uncoded_ber_bit=%p\n",uncoded_ber_bit); diff --git a/openair1/SIMULATION/LTE_PHY/dlsim_tm7.c b/openair1/SIMULATION/LTE_PHY/dlsim_tm7.c index 691287171f..0d5dcd63ce 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim_tm7.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim_tm7.c @@ -2830,12 +2830,12 @@ PMI_FEEDBACK: } */ - do_OFDM_mod_l(&eNB->common_vars, + do_OFDM_mod_symbol(&eNB->common_vars, eNB_id, (subframe*2), &eNB->frame_parms); - do_OFDM_mod_l(&eNB->common_vars, + do_OFDM_mod_symbol(&eNB->common_vars, eNB_id, (subframe*2)+1, &eNB->frame_parms); diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 7d50da5ddc..af06979efd 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -295,14 +295,14 @@ void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_OFDM_MODULATION,1); - do_OFDM_mod_l(&phy_vars_eNB->lte_eNB_common_vars, + do_OFDM_mod_symbol(&phy_vars_eNB->lte_eNB_common_vars, 0, subframe<<1, &phy_vars_eNB->lte_frame_parms); // if S-subframe generate first slot only if (subframe_select(&phy_vars_eNB->lte_frame_parms,subframe) == SF_DL) { - do_OFDM_mod_l(&phy_vars_eNB->lte_eNB_common_vars, + do_OFDM_mod_symbol(&phy_vars_eNB->lte_eNB_common_vars, 0, 1+(subframe<<1), &phy_vars_eNB->lte_frame_parms); From 0b1050c14934a6a2fda7d95f2549ff1f44c951fb Mon Sep 17 00:00:00 2001 From: ROBERT Benoit Date: Fri, 18 Nov 2016 18:31:57 +0100 Subject: [PATCH 299/413] Add following functionnalities to OAI UE autotest framework - add progess bar report - reduce ssh max_tries to 10 - cleanOldPrograms -> change kill cmd line to be able to run autotest on same machine than lte-softmodem (thanks Rohit & Gabriel) - Cleanning output prints - add --skip-machine-preparation on cmd line - add --skip-sanity-check on cmd line - add HTML REPORT (no-S1 only) - add XML detailled report (no-S1 only) --- cmake_targets/CMakeLists.txt | 1 + cmake_targets/autotests/openair.py | 10 +- .../3gpplte_turbo_decoder_sse_8bit.patch | 25 - .../autotest_ue_cell_synch_event.patch | 16 +- .../patches/phy_test__target_dl_mcs.patch | 17 - .../autotests/run_exec_lte-softmodem_tests.py | 925 ++++-- .../autotests/run_lte-softmodem-nos1_tests.py | 754 ++--- cmake_targets/autotests/testsuite_ue_noS1.xml | 2898 +++++++++++++++++ .../autotests/tools/autotest_analyser.py | 125 +- .../autotests/tools/lib_autotest_analyser.py | 164 +- cmake_targets/build_oai | 8 + .../CODING/3gpplte_turbo_decoder_sse_8bit.c | 7 +- openair1/PHY/LTE_TRANSPORT/initial_sync.c | 9 + openair1/SCHED/phy_procedures_lte_ue.c | 7 + targets/RT/USER/lte-softmodem.c | 5 + 15 files changed, 4082 insertions(+), 889 deletions(-) delete mode 100644 cmake_targets/autotests/patches/3gpplte_turbo_decoder_sse_8bit.patch delete mode 100644 cmake_targets/autotests/patches/phy_test__target_dl_mcs.patch create mode 100644 cmake_targets/autotests/testsuite_ue_noS1.xml diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 3169c6cc98..eaf541713f 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -235,6 +235,7 @@ add_boolean_option(DEBUG_OMG False "???") add_boolean_option(XFORMS False "This adds the possibility to see the signal oscilloscope") add_boolean_option(PRINT_STATS False "This adds the possibility to see the status") add_boolean_option(T_TRACER False "Activate the T tracer, a debugging/monitoring framework" ) +add_boolean_option(UE_AUTOTEST_TRACE False "Activate UE autotest specific logs") add_boolean_option(DEBUG_CONSOLE False "makes debugging easier, disables stdout/stderr buffering") diff --git a/cmake_targets/autotests/openair.py b/cmake_targets/autotests/openair.py index 5cea3aa121..7ad118ef1b 100644 --- a/cmake_targets/autotests/openair.py +++ b/cmake_targets/autotests/openair.py @@ -75,7 +75,7 @@ class openair(core): return (stdout, stderr) def connect(self, username, password, prompt='PEXPECT_OAI'): - max_retries=100 + max_retries=10 i=0 while i <= max_retries: self.prompt1 = prompt @@ -97,9 +97,9 @@ class openair(core): # need to look for twice the string of the prompt self.oai.prompt() self.oai.prompt() - self.oai.sendline('uptime') - self.oai.prompt() - print self.oai.before +# self.oai.sendline('uptime') +# self.oai.prompt() +# print self.oai.before break except Exception, e: error='' @@ -171,7 +171,7 @@ class openair(core): sys.exit(1) def disconnect(self): - print 'disconnecting the ssh connection to ' + self.address + '\n' +# print 'disconnecting the ssh connection to ' + self.address + '\n' self.oai.send('exit') # self.cancel() diff --git a/cmake_targets/autotests/patches/3gpplte_turbo_decoder_sse_8bit.patch b/cmake_targets/autotests/patches/3gpplte_turbo_decoder_sse_8bit.patch deleted file mode 100644 index 957778f332..0000000000 --- a/cmake_targets/autotests/patches/3gpplte_turbo_decoder_sse_8bit.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c -index d2c7ac6..0853373 100644 ---- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c -+++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c -@@ -493,7 +493,7 @@ void compute_beta8(llr_t* alpha,llr_t* beta,llr_t *m_11,llr_t* m_10,unsigned sho - - #endif - -- if (frame_length > 6143) { -+ if (frame_length > 6144) { - LOG_E(PHY,"compute_beta: frame_length %d\n",frame_length); - return; - } -@@ -979,6 +979,11 @@ unsigned char phy_threegpplte_turbo_decoder8(short *y, - } else - n2 = n; - -+ if(n2<256) -+ { -+ printf("phy_threegpplte_turbo_decoder8 : frame length < 256\n"); -+ return 255; -+ } - - for (iind=0; iind < 188 && f1f2mat[iind].nb_bits != n; iind++); - diff --git a/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch b/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch index 8c80d55871..33f5ac339f 100644 --- a/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch +++ b/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch @@ -1,17 +1,19 @@ diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c -index 71372d9..763397b 100644 +index 661fe96..782305d 100644 --- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c +++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c -@@ -477,6 +477,13 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) +@@ -469,6 +469,15 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) //#endif if (ue->UE_scan_carrier == 0) { + -+ /* SYRTEM */ -+ printf("AUTOTEST Cell Sync : frame = %d, rx_offset %d, freq_offset %d \n", -+ ue->proc.proc_rxtx[0].frame_rx, -+ ue->rx_offset, -+ ue->common_vars.freq_offset ); ++ #if UE_AUTOTEST_TRACE ++ LOG_I(PHY,"[UE %d] AUTOTEST Cell Sync : frame = %d, rx_offset %d, freq_offset %d \n", ++ ue->Mod_id, ++ ue->proc.proc_rxtx[0].frame_rx, ++ ue->rx_offset, ++ ue->common_vars.freq_offset ); ++ #endif + if (ue->mac_enabled==1) { LOG_I(PHY,"[UE%d] Sending synch status to higher layers\n",ue->Mod_id); diff --git a/cmake_targets/autotests/patches/phy_test__target_dl_mcs.patch b/cmake_targets/autotests/patches/phy_test__target_dl_mcs.patch deleted file mode 100644 index ec8c43cb72..0000000000 --- a/cmake_targets/autotests/patches/phy_test__target_dl_mcs.patch +++ /dev/null @@ -1,17 +0,0 @@ - -diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c -index 96645f8..a7f1dfb 100644 ---- a/targets/RT/USER/lte-softmodem.c -+++ b/targets/RT/USER/lte-softmodem.c -@@ -1602,6 +1602,11 @@ int main( int argc, char **argv ) - PHY_vars_eNB_g[0][CC_id] = init_lte_eNB(frame_parms[CC_id],0,frame_parms[CC_id]->Nid_cell,abstraction_flag); - PHY_vars_eNB_g[0][CC_id]->CC_id = CC_id; - -+ PHY_vars_eNB_g[0][CC_id]->ue_dl_rb_alloc=0x1fff; -+ PHY_vars_eNB_g[0][CC_id]->target_ue_dl_mcs=target_dl_mcs; -+ PHY_vars_eNB_g[0][CC_id]->ue_ul_nb_rb=6; -+ PHY_vars_eNB_g[0][CC_id]->target_ue_ul_mcs=target_ul_mcs; -+ - if (phy_test==1) PHY_vars_eNB_g[0][CC_id]->mac_enabled = 0; - else PHY_vars_eNB_g[0][CC_id]->mac_enabled = 1; - diff --git a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py index 796235a77f..69a3eab7c5 100755 --- a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py +++ b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py @@ -20,10 +20,14 @@ # * contact@openairinterface.org # */ -# \author Rohit Gupta +# \author Rohit Gupta - Benoit ROBERT (benoit.robert@syrtem.com) # \version 0.1 # @ingroup _test +# \Changelog +# 2016-11-18 : +# - Add progess bar during test execution update_progress() + import tempfile import threading import sys @@ -37,6 +41,8 @@ import math #from time import clock import xml.etree.ElementTree as ET import re +#from dict2xml import dict2xml as xmlify + from colorama import Fore, Back, Style import numpy as np @@ -57,6 +63,36 @@ import ssh from ssh import SSHSession import argparse + +# update_progress() : Displays or updates a console progress bar +## Accepts a float between 0 and 1. Any int will be converted to a float. +## A value under 0 represents a 'halt'. +## A value at 1 or bigger represents 100% +def update_progress(progress, prefix_string): + barLength = 20 # Modify this to change the length of the progress bar + status = "" + #print "progress = "+ str(progress) + if isinstance(progress, int): + progress = float(progress) + if not isinstance(progress, float): + progress = 0 + status = "error: progress var must be float\r\n" + if progress < 0: + progress = 0 + status = "Halt...\r\n" + if progress >= 1: + progress = 1 + status = "Done...\r\n" + block = int(round(barLength*progress)) + text = "\r"+prefix_string+" [{0}] {1}% {2}".format( "="*block + " "*(barLength-block), progress*100, status) + sys.stdout.write(text) + sys.stdout.flush() + + +def exit_prog(exit_val): + print(Style.RESET_ALL), + sys.exit(exit_val) + # \brief write a string to a file # \param filename name of file # \param string string to write @@ -271,7 +307,7 @@ def update_config_file(oai, config_string, logdirRepo, python_script): # \param logdir_local_base local directory # \param operation operation to perform (get_all, put_all) transfers recursively for directories def SSHSessionWrapper(machine, username, key_file, password, logdir_remote, logdir_local_base, operation): - max_tries = 100 + max_tries = 10 i=0 while i <= max_tries: i = i +1 @@ -306,30 +342,50 @@ def SSHSessionWrapper(machine, username, key_file, password, logdir_remote, logd # \param CleanUpAluLteBox program to terminate AlU Bell Labs LTE Box # \param ExmimoRfStop String to stop EXMIMO card (specified in test_case_list.xml) def cleanOldPrograms(oai, programList, CleanUpAluLteBox, ExmimoRfStop, logdir, logdirOAI5GRepo): - cmd = 'sudo -E killall -s INT -q -r ' + programList + ' ; sleep 5 ; sudo -E killall -9 -q -r ' + programList + cmd = 'killall -9 ' + programList result = oai.send(cmd, True) - print "Killing old programs..." + result +# print "\t\t > "+cmd +# print "\t\t < "+result + +# print "Killing old programs on ..." + result programArray = programList.split() programListJoin = '|'.join(programArray) cmd = " ( date ;echo \"Starting cleaning old programs.. \" ; dmesg|tail ; echo \"Current disk space.. \" ; df -h )>& " + logdir + "/oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync" result=oai.send_recv(cmd) +# print "\t\t > "+cmd +# print "\t\t < "+result + cmd = cleanupOldProgramsScript + ' ' + '\''+programListJoin+'\'' #result = oai.send_recv(cmd) #print result result = oai.send_expect_false(cmd, 'Match found', False) - print "Looking for old programs..." + result +# print "\t\t > "+cmd +# print "\t\t < "+result + +# print "Looking for old programs..." + result res=oai.send_recv(CleanUpAluLteBox, True) +# print "\t\t > "+CleanUpAluLteBox +# print "\t\t < "+res cmd= " echo \"Starting EXmimoRF Stop... \" >> " + logdir + "/oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync "; - oai.send_recv(cmd) + result = oai.send_recv(cmd) +# print "\t\t > "+cmd +# print "\t\t < "+result cmd = "( " + "cd " + logdirOAI5GRepo + " ; source oaienv ; " + ExmimoRfStop + " ) >> " + logdir + "/oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync " - print "cleanoldprograms cmd = " + cmd +# print "cleanoldprograms cmd = " + cmd res=oai.send_recv(cmd, False, timeout=600) +# print "\t\t > "+cmd +# print "\t\t < "+res + cmd= " echo \"Stopping EXmimoRF Stop... \" >> " + logdir + "/oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync "; - oai.send_recv(cmd) + result = oai.send_recv(cmd) +# print "\t\t > "+cmd +# print "\t\t < "+result #res = oai.send_recv(ExmimoRfStop, False) cmd = " ( date ;echo \"Finished cleaning old programs.. \" ; dmesg | tail)>> $HOME/.oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync" res=oai.send_recv(cmd) +# print "\t\t > "+cmd +# print "\t\t < "+res # \brief Class thread to launch a generic command on remote machine # \param threadID number of thread (for book keeping) @@ -355,10 +411,10 @@ class oaiThread (threading.Thread): try: oai = openair('localdomain',self.machine) oai.connect(self.username, self.password) - print "Starting " + self.threadname + " on machine " + self.machine + # print "Starting " + self.threadname + " on machine " + self.machine result = oai.send_recv(self.cmd, self.sudo, self.timeout) - print "result = " + result - print "Exiting " + self.threadname + #print "result = " + result + #print "Exiting " + self.threadname oai.disconnect() except Exception, e: error='' @@ -1262,6 +1318,8 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe if testcase_verdict != 'PASS': # if something went wrong to not run test cases max_ntries=0 + indent="\t\t" + runs_results = [] nb_runs = 0 nb_run_pass = 0 @@ -1281,9 +1339,11 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe # # RUN initialization # ---------------------------------------------------- - print (Fore.WHITE + indent + "> RUN_"+str(run).zfill(2)+" : " ), - - sys.stdout.flush() + + prefix_string = Fore.WHITE + indent + "> RUN_"+str(run).zfill(2)+" :" + +# print (Fore.WHITE + indent + "> RUN_"+str(run).zfill(2)+" : " ), +# sys.stdout.flush() run_start_time=datetime.datetime.now() @@ -1399,8 +1459,34 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe threads.append(thread_UE) thread_eNB.start() thread_UE.start() + + run_work_inprogress_flag = True + progress_step = timeout_thread/20 + progress_count = 0 + + while (run_work_inprogress_flag): + + + update_progress(float(progress_count)/float(timeout_thread),prefix_string) + + time.sleep(progress_step) + + progress_count += progress_step + +# sys.stdout.write ('#') +# sys.stdout.flush() + + run_work_inprogress_flag = False + for t in threads: + if t.isAlive(): + run_work_inprogress_flag = True + + + update_progress(1,prefix_string) + for t in threads: - t.join() + t.join() + # # @@ -1415,10 +1501,12 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe fname = logdir_local_run+ '/UE_exec' + '_' + str(run) + '_.log' cell_synch_status = analyser.check_cell_synchro(fname) + print (Fore.WHITE + indent + "> Check Cell synchro :"), + if cell_synch_status == 'CELL_SYNCH': - print '!!!!!!!!!!!!!! Cell synchronized !!!!!!!!!!!' + print ( Fore.GREEN + cell_synch_status) else : - print '!!!!!!!!!!!!!! Cell NOT NOT synchronized !!!!!!!!!!!' + print ( Fore.RED + cell_synch_status) metric_checks_flag = 0 ue_seg_fault_status = analyser.check_exec_seg_fault(fname) @@ -1437,6 +1525,9 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe # UE side metrics metricList=testcase.findall('UE_metric') for metric in metricList: + + metric_verdict = 'PASS' + metric_def = {} metric_def['id'] = metric.get('id') metric_def['description'] = metric.get('description') @@ -1457,15 +1548,19 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe metric_extracted = analyser.do_extract_metrics(args) - print "\t > Metric "+metric_def['id']+" :" - print "\t\t> min = "+ str( metric_extracted['metric_min'] ) - print "\t\t> min_index = "+ str( metric_extracted['metric_min_index'] ) - print "\t\t> max = "+ str( metric_extracted['metric_max'] ) - print "\t\t> max_index = "+ str( metric_extracted['metric_max_index'] ) - print "\t\t> mean = "+ str( metric_extracted['metric_mean'] ) - print "\t\t> median = "+ str( metric_extracted['metric_median'] ) + print (Fore.WHITE + indent + "> Metric : "+metric_def['id']), + print ("(min="+str( metric_extracted['metric_min'])+", max="+str( metric_extracted['metric_max'])+", mean="+str( metric_extracted['metric_mean'])+", median="+str( metric_extracted['metric_median'])+")") - verdict = analyser.do_check_verdict(metric_def, metric_extracted) +# print "\t > Metric "+metric_def['id']+" :" +# print "\t\t> min = "+ str( metric_extracted['metric_min'] ) +# print "\t\t> min_index = "+ str( metric_extracted['metric_min_index'] ) +# print "\t\t> max = "+ str( metric_extracted['metric_max'] ) +# print "\t\t> max_index = "+ str( metric_extracted['metric_max_index'] ) +# print "\t\t> mean = "+ str( metric_extracted['metric_mean'] ) +# print "\t\t> median = "+ str( metric_extracted['metric_median'] ) + + if metric_def['pass_fail_stat'] : + metric_verdict = analyser.do_check_verdict(metric_def, metric_extracted) metric_fig = logdir_local_run+ '/UE_metric_'+ metric_def['id']+'_' + str(run) + '_.png' analyser.do_img_metrics(metric_def, metric_extracted, metric_fig) @@ -1493,6 +1588,13 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe runs_metrics.append(run_metrics) + if metric_verdict != 'PASS': + verdict = metric_verdict + + # End Metrics LOOP + # --------------------- + + # Traffic analysis if UE_traffic_exec != "": @@ -1546,9 +1648,9 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe run_stop_time=datetime.datetime.now() run_duration = run_stop_time-run_start_time # print (Fore.WHITE + ("duration=" :"), - print (Fore.WHITE + indent + "> RUN duration : "+ str(run_duration) +"s" ) + print (Fore.WHITE + indent + "> RUN duration : "+ str(run_duration) +"s" ) - print (Fore.WHITE + indent + "> RUN verdict :"), + print (Fore.WHITE + indent + "> RUN verdict :"), if verdict == 'PASS': nb_run_pass += 1 @@ -1578,6 +1680,8 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe # END RUN LOOP #---------------------------------------------------- + indent="\t" + # Test case duration # ---------------------------------- testcase_time_stop = datetime.datetime.now() @@ -1617,11 +1721,9 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe else: print (Fore.YELLOW+'INCONCLUSIVE') - duration= testcase_time_stop - testcase_time_start - xmlFile = logdir_local_testcase + '/test.' + testcasename + '.xml' - xml="\n \n" - write_file(xmlFile, xml, mode="w") + print(Style.RESET_ALL) + duration= testcase_time_stop - testcase_time_start test_result = dict(testcase_name=testcasename, testcaseclass=testcaseclass, @@ -1640,7 +1742,17 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe testcase_eNBMachine =eNBMachine, testcase_UEMachine =UEMachine, runs_results = runs_results) - #test_results.append(test_result) + test_results.append(test_result) + + xmlFile = logdir_local_testcase + '/test.' + testcasename + '.xml' + xml="\n \n" + write_file(xmlFile, xml, mode="w") + +# xmlFile_ng = logdir_local_testcase + '/test.' + testcasename + '_ng.xml' +# xml_ng = xmlify(test_result, wrap=testcasename, indent=" ") +# write_file(xmlFile_ng, xml_ng, mode="w") + + return testcase_verdict @@ -1659,12 +1771,12 @@ def search_test_case_group(testcasename, testcasegroup, test_case_exclude): if entry.find('+') >=0: match = re.search(entry, testcasename) if match: - print "\nSkipping test case as it is found in black list: " + testcasename + #print "\nSkipping test case as it is found in black list: " + testcasename return False else: match = entry.find(testcasename) if match >=0: - print "\nSkipping test case as it is found in black list: " + testcasename + #print "\nSkipping test case as it is found in black list: " + testcasename return False if testcasegroup == '': return True @@ -1752,6 +1864,7 @@ if openairdir_local is None: print "Environment variable OPENAIR_DIR not set correctly" sys.exit() locallogdir = openairdir_local + '/cmake_targets/autotests/log' +reportdir = openairdir_local + '/cmake_targets/autotests/report' MachineList = '' MachineListGeneric='' MachineDescDic={} @@ -1760,12 +1873,19 @@ flag_start_testcase=False nruns_lte_softmodem='' flag_skip_git_head_check=False flag_skip_oai_install=False +flag_skip_machine_preparation=False +flag_skip_sanity_check=False +flag_generate_html_report = False Timeout_cmd='' xmlInputFile='' -print "Number of arguments argc = " + str(len(sys.argv)) + +#print "Number of arguments argc = " + str(len(sys.argv)) #for index in range(1,len(sys.argv) ): # print "argv_" + str(index) + " : " + sys.argv[index] +oai_list = [] + + i=1 while i < len (sys.argv): arg=sys.argv[i] @@ -1825,9 +1945,15 @@ while i < len (sys.argv): i = i +1 elif arg == '--skip-oai-install': flag_skip_oai_install=True + elif arg == '--skip-machine-preparation': + flag_skip_machine_preparation=True + elif arg == '--skip-sanity-check': + flag_skip_sanity_check=True elif arg == '--test-suite' : xmlInputFile = sys.argv[i+1] i = i +1 + elif arg == '--generate-html-report': + flag_generate_html_report=True elif arg == '-h' : print "-s: This flag *MUST* be set to start the test cases" print "-r: Remove the log directory in autotests" @@ -1845,90 +1971,65 @@ while i < len (sys.argv): print "--skip-git-head-check: skip checking of GitHead remote/local branch (only for debugging)" print "--timeout_cmd: Override the default parameter (timeout_cmd) in test_case_list.xml. This parameter is in seconds and should be > 120" print "--skip-oai-install: Skips the openairinterface5g installer" + print "--skip-machine-preparation: skipp the whole system preparation -> direct to test cases" + print "--skip-sanity-check: skipp the machine sanity checks" print "--test-suite: Select a XML test-suite file" + print "--generate-html-report: Generate an HTML report of the test campaign (supported only for noS1 testsuite !!)" sys.exit() else : print "Unrecongnized Option: <" + arg + ">. Use -h to see valid options" sys.exit() i= i + 1 -try: - os.environ["OPENAIR1_DIR"] -except KeyError: - print "Please set the environment variable OPENAIR1_DIR in the .bashrc" - sys.exit(1) - -try: - os.environ["OPENAIR2_DIR"] -except KeyError: - print "Please set the environment variable OPENAIR2_DIR in the .bashrc" - sys.exit(1) - -try: - os.environ["OPENAIR_TARGETS"] -except KeyError: - print "Please set the environment variable OPENAIR_TARGETS in the .bashrc" - sys.exit(1) - -print "Killing zombie ssh sessions from earlier sessions..." -cmd='ps aux |grep \"/usr/bin/ssh -q -l guptar\"| awk \'{print $2}\' | sudo xargs kill -9 ' - -os.system(cmd) - -try: - analyser = __import__("lib_autotest_analyser") -except ImportError as err: - print('Import error: ' + str(err)) - exit(0) - - -if flag_start_testcase == False: - print "You need to start the testcase by passing option -s. Use -h to see all options. Aborting now..." - sys.exit(1) - -# get the oai object -host = os.uname()[1] -#oai = openair('localdomain','calisson') -oai_list = [] - -#start_time = time.time() # datetime.datetime.now() -if user=='': - user = getpass.getuser() -if pw=='': - pw = getpass.getpass() - -print "Killing zombie ssh sessions from earlier sessions..." -cmd='ps aux |grep \"/usr/bin/ssh -q -l guptar\"|tr -s \" \" :|cut -f 2 -d :|xargs kill -9 ' -cmd = cmd + '; ps aux |grep \"/usr/bin/ssh -q -l ' + user + '\"|tr -s \" \" :|cut -f 2 -d :|xargs kill -9 ' -os.system(cmd) - -print "host = " + host -print "user = " + user -if xmlInputFile == '': - xmlInputFile=os.environ.get('OPENAIR_DIR')+"/cmake_targets/autotests/test_case_list.xml" -NFSResultsDir = '/mnt/sradio' -cleanupOldProgramsScript = '$OPENAIR_DIR/cmake_targets/autotests/tools/remove_old_programs.bash' logdir = '/tmp/' + 'OAITestFrameWork-' + user + '/' logdirOAI5GRepo = logdir + 'openairinterface5g/' logdirOpenaircnRepo = logdir + 'openair-cn/' patchdir = logdirOAI5GRepo + 'cmake_targets/autotests/patches/' - -if flag_remove_logdir == True: - print "Removing directory: " + locallogdir - os.system(' rm -fr ' + locallogdir + '; mkdir -p ' + locallogdir ) -else: - os.system('mkdir -p ' + locallogdir) - -paramiko_logfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/log/paramiko.log') -res=os.system(' echo > ' + paramiko_logfile) -paramiko.util.log_to_file(paramiko_logfile) - -#pw=getpass.getpass() +NFSResultsDir = '/mnt/sradio' +cleanupOldProgramsScript = '$OPENAIR_DIR/cmake_targets/autotests/tools/remove_old_programs.bash' #Now we parse the xml file for basic configuration +if xmlInputFile == '': + xmlInputFile=os.environ.get('OPENAIR_DIR')+"/cmake_targets/autotests/test_case_list.xml" xmlTree = ET.parse(xmlInputFile) xmlRoot = xmlTree.getroot() +# +# Read test session configuration +# --------------------------------------------------------------------------------- +print (Fore.YELLOW + '\nStep 0.1 - Read test session configuration') +print (Fore.YELLOW + '-------------------------------------------------') + +test_session_start_time = datetime.datetime.now() +print (Fore.WHITE + ' - start time : '+ str(test_session_start_time)) + +host = os.uname()[1] +print (Fore.WHITE + ' - MTC host : '+host) + + +if user=='': + user = getpass.getuser() +print (Fore.WHITE + ' - user : '+user) + +if pw=='': + pw = getpass.getpass() +print (Fore.WHITE + ' - password : '+pw) + +print (Fore.WHITE + ' - cmd line flags : ') +print (Fore.WHITE + ' + -s : '+str(flag_start_testcase)) +print (Fore.WHITE + ' + -r : '+str(flag_remove_logdir)) +print (Fore.WHITE + ' + -c : '+str(cleanUpRemoteMachines)) +print (Fore.WHITE + ' + --skip-git-head-check : '+str(flag_skip_git_head_check)) +print (Fore.WHITE + ' + --skip-oai-install : '+str(flag_skip_oai_install)) +print (Fore.WHITE + ' + --skip-machine-preparation : '+str(flag_skip_machine_preparation)) +print (Fore.WHITE + ' + --skip-sanity-check : '+str(flag_skip_sanity_check)) + + +print (Fore.WHITE + ' - Test setup basic config : (* -> overwrite by cmd line parameter)') +print (Fore.WHITE + ' + test setup config file : '+str(xmlInputFile)) +print (Fore.WHITE + ' + remote setup dir : '+str(logdir)) +print (Fore.WHITE + ' + remote OAI5G repo : '+str(logdirOAI5GRepo)) +print (Fore.WHITE + ' + remote OpenAirCN repo : '+str(logdirOpenaircnRepo)) if MachineList =='': @@ -1941,6 +2042,8 @@ if GitOAI5GRepo == '': if GitOAI5GRepoBranch == '': GitOAI5GRepoBranch = xmlRoot.findtext('GitOAI5GRepoBranch',default='') +if GitOAI5GHeadVersion == '': + GitOAI5GHeadVersion = xmlRoot.findtext('GitOAI5GHeadVersion',default='') GitOpenaircnRepoBranch = xmlRoot.findtext('GitOpenair-cnRepoBranch',default='') CleanUpOldProgs = xmlRoot.findtext('CleanUpOldProgs',default='') @@ -1953,25 +2056,27 @@ ExmimoRfStop = xmlRoot.findtext('ExmimoRfStop',default='') if nruns_lte_softmodem == '': nruns_lte_softmodem = xmlRoot.findtext('nruns_lte-softmodem',default='') -OAI5GpatchFileList=xmlRoot.findall('OAI5GPatchFile') +print (Fore.WHITE + ' + MachineList : '+ MachineList) +print (Fore.WHITE + ' + GitOpenair-cnRepo : '+ GitOpenaircnRepo) +print (Fore.WHITE + ' + GitOAI5GRepo : '+ GitOAI5GRepo) +print (Fore.WHITE + ' + GitOAI5GBranch : '+ GitOAI5GRepoBranch) +print (Fore.WHITE + ' + GitOpenaircnRepoBranch : '+ GitOpenaircnRepoBranch) +print (Fore.WHITE + ' + NFSResultsShare : '+ NFSResultsShare) +print (Fore.WHITE + ' + nruns_lte_softmodem : '+ nruns_lte_softmodem) +print (Fore.WHITE + ' + Timeout_cmd : '+ Timeout_cmd) -print "MachineList = " + MachineList -print "GitOpenair-cnRepo = " + GitOpenaircnRepo -print "GitOAI5GRepo = " + GitOAI5GRepo -print "GitOAI5GBranch = " + GitOAI5GRepoBranch -print "GitOpenaircnRepoBranch = " + GitOpenaircnRepoBranch -print "NFSResultsShare = " + NFSResultsShare -print "nruns_lte_softmodem = " + nruns_lte_softmodem -print "Timeout_cmd = " + Timeout_cmd if GitOAI5GHeadVersion == '': - cmd = "git show-ref --heads -s "+ GitOAI5GRepoBranch + cmd = "git log --pretty=format:\'%H\' -n 1" # origin/"+ GitOAI5GRepoBranch +# cmd = "git show-ref --heads -s "+ GitOAI5GRepoBranch GitOAI5GHeadVersion = subprocess.check_output ([cmd], shell=True) GitOAI5GHeadVersion=GitOAI5GHeadVersion.replace("\n","") -print "GitOAI5GHeadVersion = " + GitOAI5GHeadVersion -print "CleanUpOldProgs = " + CleanUpOldProgs -print "Timeout_execution = " + str(Timeout_execution) + # Print commiter and date : git log -1 --pretty=format:"%an %ad" + +print (Fore.WHITE + ' + GitOAI5GHeadVersion : '+ GitOAI5GHeadVersion) +#print "CleanUpOldProgs = " + CleanUpOldProgs +print (Fore.WHITE + ' + Timeout_execution (s) : '+ str(Timeout_execution)) if GitOAI5GHeadVersion == '': print "Error getting the OAI5GBranch Head version...Exiting" @@ -1979,214 +2084,401 @@ if GitOAI5GHeadVersion == '': NFSTestsResultsDir = NFSResultsShare + '/'+ GitOAI5GRepoBranch + '/' + GitOAI5GHeadVersion -print "NFSTestsResultsDir = " + NFSTestsResultsDir +#print "NFSTestsResultsDir = " + NFSTestsResultsDir + +OAI5GpatchFileList=xmlRoot.findall('OAI5GPatchFile') + + MachineList = MachineList.split() MachineListGeneric = MachineListGeneric.split() -#index=0 + +MachineDescDic + + +# +# 'Check Mater Test Controller sanity (MTC)' +# --------------------------------------------------------------------------------- +print (Fore.YELLOW + '\nStep 0.2 - Check Mater Test Controller sanity (MTC)') +print (Fore.YELLOW + '-------------------------------------------------') + +try: + print (Fore.WHITE + ' - check OpenAirInterface environment variable OPENAIR1_DIR... '), + os.environ["OPENAIR1_DIR"] +except KeyError: + print (Fore.RED + 'FAILED') + print "Please set the environment variable OPENAIR1_DIR in the .bashrc or run 'source oaienv' " + exit_prog(1) +print (Fore.GREEN + 'OK') + +try: + print (Fore.WHITE + ' - check OpenAirInterface environment variable OPENAIR2_DIR... '), + os.environ["OPENAIR2_DIR"] +except KeyError: + print (Fore.RED + 'FAILED') + print "Please set the environment variable OPENAIR2_DIR in the .bashrc or run 'source oaienv' " + exit_prog(1) +print (Fore.GREEN + 'OK') + +try: + os.environ["OPENAIR_TARGETS"] +except KeyError: + print "Please set the environment variable OPENAIR_TARGETS in the .bashrc or run 'source oaienv' " + sexit_prog(1) + +print (Fore.WHITE + ' - kill zombie ssh sessions from earlier sessions... '), +cmd='ps aux |grep \"/usr/bin/ssh -q -l ' + user + '\"| tr -s \" \" :| cut -f 2 -d :| xargs kill -9 ' +os.system(cmd) +print (Fore.GREEN + 'DONE') + +if flag_start_testcase == False: + print "You need to start the testcase by passing option -s. Use -h to see all options. Aborting now..." + exit_prog(1) + + +#print "Killing zombie ssh sessions from earlier sessions..." +#cmd='ps aux |grep \"/usr/bin/ssh -q -l guptar\"|tr -s \" \" :|cut -f 2 -d :|xargs kill -9 ' +#cmd = cmd + '; ps aux |grep \"/usr/bin/ssh -q -l ' + user + '\"| tr -s \" \" :| cut -f 2 -d :| xargs kill -9 ' +#os.system(cmd) +#print cmd + +try: + analyser = __import__("lib_autotest_analyser") +except ImportError as err: + print('Import error: ' + str(err)) + exit(0) + +if flag_remove_logdir == True: + print "Removing directory: " + locallogdir + os.system(' rm -fr ' + locallogdir + '; mkdir -p ' + locallogdir ) + +if not os.path.exists(locallogdir): + os.system('mkdir -p ' + locallogdir ) + + +paramiko_logfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/log/paramiko.log') +res=os.system(' echo > ' + paramiko_logfile) +paramiko.util.log_to_file(paramiko_logfile) + + +# +# 'REMOTE MACHINE SANITY CHEKS' +# --------------------------------------------------------------------------------- +print (Fore.YELLOW + '\nStep 0.3 - REMOTE MACHINE SANITY CHEKS') +print (Fore.YELLOW + '-------------------------------------------------') + + for machine in MachineList: oai_list.append( openair('localdomain',machine)) MachineDescDic[machine]={} - #index = index + 1 -print "\nTesting the sanity of machines used for testing..." -if localshell == 0: +if not flag_skip_sanity_check: + + if localshell == 0: try: - index=0 - for machine in MachineList: - print '\n******* Note that the user <'+user+'> should be a sudoer *******\n' - print '******* Connecting to the machine <'+machine+'> to perform the test *******\n' - if not pw : - print "username: " + user - #pw = getpass.getpass() - #print "password: " + pw - else : - print "username: " + user - #print "password: " + pw - # issues in ubuntu 12.04 - oai_list[index].connect(user,pw) - print '\nChecking for sudo permissions on machine <'+machine+'>...' - result = oai_list[index].send_expect_false('sudo -S -v','may not run sudo',True) - print "Sudo permissions..." + result - - print '\nCleaning Older running programs : ' + CleanUpOldProgs - cleanOldPrograms(oai_list[index], CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop, '$HOME', '/tmp') + index=0 + for machine in MachineList: + print (Fore.WHITE + " - Check sanity for remote machine "+machine) - #result = oai_list[index].send('mount ' + NFSResultsDir, True) - #print "Mounting NFS Share " + NFSResultsDir + "..." + result + oai_list[index].connect(user,pw) + print (Fore.WHITE + " > Checking for sudo permissions for user "+user+ " : "), + result = oai_list[index].send_expect_false('sudo -S -v','may not run sudo',True) + if (result == 'OK'): + print (Fore.GREEN + result ) + else: + print (Fore.RED + result ) + + print (Fore.WHITE + " > Cleaning Older running programs : "), + cleanOldPrograms(oai_list[index], CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop, '$HOME', '/tmp') + print (Fore.WHITE + " Done") - # Check if NFS share is mounted correctly. - #print 'Checking if NFS Share<' + NFSResultsDir + '> is mounted correctly...' - #cmd = 'if grep -qs '+NFSResultsDir+ ' /proc/mounts; then echo \'' + NFSResultsDir + ' is mounted\' ; fi' - #search_expr = NFSResultsDir + ' is mounted' - #print "cmd = " + cmd - #print "search_expr = " + search_expr - #result = oai_list[index].send_expect(cmd, search_expr) - #print "Mount NFS_Results_Dir..." + result - index = index + 1 - - #oai.connect2(user,pw) - #oai.get_shell() + #result = oai_list[index].send('mount ' + NFSResultsDir, True) + #print "Mounting NFS Share " + NFSResultsDir + "..." + result + + # Check if NFS share is mounted correctly. + #print 'Checking if NFS Share<' + NFSResultsDir + '> is mounted correctly...' + #cmd = 'if grep -qs '+NFSResultsDir+ ' /proc/mounts; then echo \'' + NFSResultsDir + ' is mounted\' ; fi' + #search_expr = NFSResultsDir + ' is mounted' + #print "cmd = " + cmd + #print "search_expr = " + search_expr + #result = oai_list[index].send_expect(cmd, search_expr) + #print "Mount NFS_Results_Dir..." + result + index = index + 1 + + #oai.connect2(user,pw) + #oai.get_shell() except : print 'Fail to connect to the machine: '+ machine sys.exit(1) + else: + pw = '' + oai_list[0].connect_localshell() else: - pw = '' - oai_list[0].connect_localshell() + print (Fore.RED + " Skipping Machine sanity check...") -#We now prepare the machines for testing -index=0 -threads_init_setup=[] -for oai in oai_list: - try: - print "setting up machine: " + MachineList[index] - #print oai_list[oai].send_recv('echo \''+pw+'\' |sudo -S -v') - #print oai_list[oai].send_recv('sudo su') - #print oai_list[oai].send_recv('who am i') - #cleanUpPrograms(oai_list[oai] - cmd = 'sudo -S -E rm -fr ' + logdir + ' ; mkdir -p ' + logdir - result = oai.send_recv(cmd) +# +# 'REMOTE MACHINE TEST SETUP CONFIGURATION' +# --------------------------------------------------------------------------------- +print (Fore.YELLOW + '\nStep 0.4 - REMOTE MACHINE PREPARATION') +print (Fore.YELLOW + '-------------------------------------------------') + +if not flag_skip_machine_preparation: + index=0 + threads_init_setup=[] + for oai in oai_list: + try: + print "setting up machine: " + MachineList[index] + #print oai_list[oai].send_recv('echo \''+pw+'\' |sudo -S -v') + #print oai_list[oai].send_recv('sudo su') + #print oai_list[oai].send_recv('who am i') + #cleanUpPrograms(oai_list[oai] + cmd = 'sudo -S -E rm -fr ' + logdir + ' ; mkdir -p ' + logdir + result = oai.send_recv(cmd) + print cmd + + setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' + setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' + + #Sometimes git fails so the script below retries in that case + localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/tools/git-retry.sh') + remotefile = logdir + '/git-retry.sh' + paramList=[] + port=22 + paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) + sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') + sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) + + cmd = ' ( \n' + #cmd = cmd + 'rm -fR ' + logdir + '\n' + #cmd = cmd + 'mkdir -p ' + logdir + '\n' + cmd = cmd + 'cd '+ logdir + '\n' + cmd = cmd + 'sudo apt-get install -y git \n' + cmd = cmd + 'chmod 700 ' + logdir + '/git-retry.sh \n' + cmd = cmd + logdir + '/git-retry.sh clone '+ GitOAI5GRepo +' \n' + cmd = cmd + logdir + '/git-retry.sh clone '+ GitOpenaircnRepo + ' \n' + cmd = cmd + 'cd ' + logdirOAI5GRepo + '\n' + cmd = cmd + 'git checkout ' + GitOAI5GRepoBranch + '\n' + if GitOAI5GHeadVersion : + cmd = cmd + 'git checkout ' + GitOAI5GHeadVersion + '\n' + cmd = cmd + 'git_head=`git ls-remote |grep \'' + GitOAI5GRepoBranch + '\'` \n' + cmd = cmd + 'git_head=($git_head) \n' + cmd = cmd + 'git_head=${git_head[0]} \n' + cmd = cmd + 'echo \"GitOAI5GHeadVersion_remote = $git_head\" \n' + cmd = cmd + 'echo \"GitOAI5GHeadVersion_local = ' + GitOAI5GHeadVersion + '\" \n' + if flag_skip_git_head_check==True: + cmd = cmd + 'echo \"skipping GitHead check...\" \n ' + else: + cmd = cmd + 'if [ \"$git_head\" != \"'+ GitOAI5GHeadVersion + '\" ]; then echo \"error: Git openairinterface5g head version does not match\" ; fi \n' + cmd = cmd + 'source oaienv' + '\n' + if flag_skip_oai_install == False: + cmd = cmd + 'source $OPENAIR_DIR/cmake_targets/tools/build_helper \n' + cmd = cmd + 'echo \"Installing core OAI dependencies...Start\" \n' + cmd = cmd + '$OPENAIR_DIR/cmake_targets/build_oai -I --install-optional-packages \n' + cmd = cmd + 'echo \"Installing core OAI dependencies...Finished\" \n' + #cmd = cmd + 'echo \"Installing BLADERF OAI dependencies...Start\" \n' + #cmd = cmd + 'check_install_bladerf_driver \n' + #cmd = cmd + 'echo \"Installing BLADERF OAI dependencies...Finished\" \n' + #cmd = cmd + 'echo \"Installing USRP OAI dependencies...Start\" \n' + #cmd = cmd + 'check_install_usrp_uhd_driver \n' + #cmd = cmd + 'echo \"Installing USRP OAI dependencies...Finished\" \n' + cmd = cmd + 'cd ' + logdirOpenaircnRepo + '\n' + cmd = cmd + 'git checkout ' + GitOpenaircnRepoBranch + '\n' + cmd = cmd + 'env |grep OPENAIR' + '\n' + cmd = cmd + ' cd ' + logdir + '\n' + cmd = cmd + 'mkdir -p ' + patchdir + '\n' + cmd = cmd + ' ) > ' + setuplogfile + ' 2>&1 \n' + #cmd = cmd + 'echo \' ' + cmd + '\' > ' + setup_script + ' 2>&1 \n ' + #result = oai_list[index].send_recv(cmd, False, 300 ) + write_file(setup_script, cmd, mode="w") + tempThread = oaiThread(index, 'thread_setup_'+str(index)+'_' + MachineList[index] , MachineList[index] , user, pw, cmd, False, 3000) + threads_init_setup.append(tempThread ) + tempThread.start() + index = index + 1 + except Exception, e: + print 'There is error in one of the commands to setup the machine '+ MachineList[index] + error='' + error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) + error = error + traceback.format_exc() + print error + sys.exit(1) + + #Now we wait for all the threads to complete + index = 0 + for t in threads_init_setup: + t.join() + + port = 22 + paramList=[] + sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') + + #Now we copy patch files and apply them + print( Fore.WHITE + " - Installating patch files on machine " + MachineList[index]) + for patchFile in OAI5GpatchFileList: + localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/patches/')+patchFile.get('name') + remotefile = logdirOAI5GRepo + '/cmake_targets/autotests/patches/'+patchFile.get('name') + if patchFile.get('machine') == MachineList[index] or patchFile.get('machine') == None: + if os.path.isfile(localfile): + print( Fore.WHITE + "\t> PATCH FILE :"+localfile) + paramList=[] + paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) + sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) + cmd = ' cd ' + logdirOAI5GRepo + ' ;git apply cmake_targets/autotests/patches/'+patchFile.get('name') + res = oai_list[index].send_recv(cmd) + #print res - setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' - setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' + paramList=[] - #Sometimes git fails so the script below retries in that case - localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/tools/git-retry.sh') - remotefile = logdir + '/git-retry.sh' - paramList=[] - port=22 - paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) - sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') - sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) + setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' + setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' + localfile = locallogdir + '/setup_log_' + MachineList[index] + '_.txt' + remotefile = logdir + '/setup_log_' + MachineList[index] + '_.txt' + sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') + paramList.append ( {"operation":'get', "localfile":localfile, "remotefile":remotefile} ) + #sftp_module (user, pw, MachineList[index], port, localfile, remotefile, sftp_log, "get") + + #Now we copy test_case_list.xml on the remote machines + localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/test_case_list.xml') + remotefile = logdirOAI5GRepo + '/cmake_targets/autotests/test_case_list.xml' + # paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) + # sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) + + sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) - cmd = ' ( \n' - #cmd = cmd + 'rm -fR ' + logdir + '\n' - #cmd = cmd + 'mkdir -p ' + logdir + '\n' - cmd = cmd + 'cd '+ logdir + '\n' - cmd = cmd + 'sudo apt-get install -y git \n' - cmd = cmd + 'chmod 700 ' + logdir + '/git-retry.sh \n' - cmd = cmd + logdir + '/git-retry.sh clone '+ GitOAI5GRepo +' \n' - cmd = cmd + logdir + '/git-retry.sh clone '+ GitOpenaircnRepo + ' \n' - cmd = cmd + 'cd ' + logdirOAI5GRepo + '\n' - cmd = cmd + 'git checkout ' + GitOAI5GRepoBranch + '\n' - #cmd = cmd + 'git checkout ' + GitOAI5GHeadVersion + '\n' - cmd = cmd + 'git_head=`git ls-remote |grep \'' + GitOAI5GRepoBranch + '\'` \n' - cmd = cmd + 'git_head=($git_head) \n' - cmd = cmd + 'git_head=${git_head[0]} \n' - cmd = cmd + 'echo \"GitOAI5GHeadVersion_remote = $git_head\" \n' - cmd = cmd + 'echo \"GitOAI5GHeadVersion_local = ' + GitOAI5GHeadVersion + '\" \n' - if flag_skip_git_head_check==True: - cmd = cmd + 'echo \"skipping GitHead check...\" \n ' - else: - cmd = cmd + 'if [ \"$git_head\" != \"'+ GitOAI5GHeadVersion + '\" ]; then echo \"error: Git openairinterface5g head version does not match\" ; fi \n' - cmd = cmd + 'source oaienv' + '\n' - if flag_skip_oai_install == False: - cmd = cmd + 'source $OPENAIR_DIR/cmake_targets/tools/build_helper \n' - cmd = cmd + 'echo \"Installing core OAI dependencies...Start\" \n' - cmd = cmd + '$OPENAIR_DIR/cmake_targets/build_oai -I --install-optional-packages \n' - cmd = cmd + 'echo \"Installing core OAI dependencies...Finished\" \n' - #cmd = cmd + 'echo \"Installing BLADERF OAI dependencies...Start\" \n' - #cmd = cmd + 'check_install_bladerf_driver \n' - #cmd = cmd + 'echo \"Installing BLADERF OAI dependencies...Finished\" \n' - #cmd = cmd + 'echo \"Installing USRP OAI dependencies...Start\" \n' - #cmd = cmd + 'check_install_usrp_uhd_driver \n' - #cmd = cmd + 'echo \"Installing USRP OAI dependencies...Finished\" \n' - cmd = cmd + 'cd ' + logdirOpenaircnRepo + '\n' - cmd = cmd + 'git checkout ' + GitOpenaircnRepoBranch + '\n' - cmd = cmd + 'env |grep OPENAIR' + '\n' - cmd = cmd + ' cd ' + logdir + '\n' - cmd = cmd + 'mkdir -p ' + patchdir + '\n' - cmd = cmd + ' ) > ' + setuplogfile + ' 2>&1 \n' - #cmd = cmd + 'echo \' ' + cmd + '\' > ' + setup_script + ' 2>&1 \n ' - #result = oai_list[index].send_recv(cmd, False, 300 ) - write_file(setup_script, cmd, mode="w") - tempThread = oaiThread(index, 'thread_setup_'+str(index)+'_' + MachineList[index] , MachineList[index] , user, pw, cmd, False, 3000) - threads_init_setup.append(tempThread ) - tempThread.start() - index = index + 1 - except Exception, e: - print 'There is error in one of the commands to setup the machine '+ MachineList[index] - error='' - error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) - error = error + traceback.format_exc() - print error - sys.exit(1) - -#Now we wait for all the threads to complete -index = 0 -for t in threads_init_setup: - t.join() - setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' - setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' - localfile = locallogdir + '/setup_log_' + MachineList[index] + '_.txt' - remotefile = logdir + '/setup_log_' + MachineList[index] + '_.txt' - port = 22 - - #Now we copy patch files and apply them - print "Installating patch files on machine " + MachineList[index] - for patchFile in OAI5GpatchFileList: - localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/patches/')+patchFile.get('name') - remotefile = logdirOAI5GRepo + '/cmake_targets/autotests/patches/'+patchFile.get('name') - if patchFile.get('machine') == MachineList[index] or patchFile.get('machine') == None: - if os.path.isfile(localfile): - print "\t> PATCH FILE :"+localfile - paramList=[] - paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) - sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) - cmd = ' cd ' + logdirOAI5GRepo + ' ;git apply cmake_targets/autotests/patches/'+patchFile.get('name') - res = oai_list[index].send_recv(cmd) - - paramList=[] - - setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' - setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' - localfile = locallogdir + '/setup_log_' + MachineList[index] + '_.txt' - remotefile = logdir + '/setup_log_' + MachineList[index] + '_.txt' - sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') - paramList.append ( {"operation":'get', "localfile":localfile, "remotefile":remotefile} ) - #sftp_module (user, pw, MachineList[index], port, localfile, remotefile, sftp_log, "get") - - #Now we copy test_case_list.xml on the remote machines - localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/test_case_list.xml') - remotefile = logdirOAI5GRepo + '/cmake_targets/autotests/test_case_list.xml' - paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) - sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') - sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) - - cmd = ' cd ' + logdirOAI5GRepo + ' ; source oaienv ; env|grep OPENAIR \n' - res = oai_list[index].send_recv(cmd) - index = index +1 - if os.path.exists(localfile) == 0: + cmd = ' cd ' + logdirOAI5GRepo + ' ; source oaienv ; env|grep OPENAIR \n' + res = oai_list[index].send_recv(cmd) + index = index +1 + if os.path.exists(localfile) == 0: print "Setup log file <" + localfile + "> missing for machine <" + MachineList[index] + ">. Please check the setup log files. Exiting now" sys.exit(1) -#Now we process all the test cases -#Now we check if there was error in setup files + #Now we process all the test cases + #Now we check if there was error in setup files -status, out = commands.getstatusoutput('grep ' + ' -il \'error\' ' + locallogdir + '/setup_log*') -if (out != '') : - print "There is error in setup of machines" - print "status = " + str(status) + "\n Check files for error = " + out - print "Exiting now..." - sys.exit(1) + status, out = commands.getstatusoutput('grep ' + ' -il \'error\' ' + locallogdir + '/setup_log*') + if (out != '') : + print "There is error in setup of machines" + print "status = " + str(status) + "\n Check files for error = " + out + print "Exiting now..." + sys.exit(1) -cleanOldProgramsAllMachines(oai_list, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop, '$HOME' , logdirOAI5GRepo) -if cleanUpRemoteMachines == True: - sys.exit(0) + cleanOldProgramsAllMachines(oai_list, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop, '$HOME' , logdirOAI5GRepo) + if cleanUpRemoteMachines == True: + print "Error while cleaning Remote machines" + print "Exiting now..." + sys.exit(0) + + +else: + print (Fore.RED + " Skipping Machine preparation...") + +# ************************************************************************** +# ************************************************************************** +# STEP 2 - TEST SELECTION AND PARAMETRIZATION +# ************************************************************************** +# ************************************************************************** + +print (Fore.YELLOW + '\nStep 2 - TEST SELECTION') +print (Fore.YELLOW + '-------------------------------------------------') + +print (Fore.WHITE + " Parsing test case list for test selection...") +print (Fore.WHITE + " - TestCaseExclusionList : "+TestCaseExclusionList) +print (Fore.WHITE + " - testcasegroup : "+testcasegroup) + + +testcaseList=xmlRoot.findall('testCase') + +nb_total_testcases = 0 +nb_total_testcases_softmodem = 0 +nb_total_testcases_softmodem_noS1 = 0 +nb_total_testcases_compilation = 0 +nb_total_testcases_execution = 0 + +nb_run_testcases = 0 +nb_run_testcases_softmodem = 0 +nb_run_testcases_softmodem_noS1 = 0 +nb_run_testcases_compilation = 0 +nb_run_testcases_execution = 0 + + +for testcase in testcaseList: + try: + testcasename = testcase.get('id') + testcaseclass = testcase.findtext('class',default='') + desc = testcase.findtext('desc',default='') + nb_total_testcases+=1 + + run_flag = search_test_case_group(testcasename, testcasegroup, TestCaseExclusionList) + if (run_flag): + nb_run_testcases+=1 + + if testcaseclass == 'lte-softmodem' : + nb_total_testcases_softmodem+=1 + if (run_flag): nb_run_testcases_softmodem+=1 + elif testcaseclass == 'lte-softmodem-noS1': + nb_total_testcases_softmodem_noS1+=1 + if (run_flag): nb_run_testcases_softmodem_noS1+=1 + elif testcaseclass == 'compilation': + nb_total_testcases_compilation+=1 + if (run_flag): nb_run_testcases_compilation+=1 + elif testcaseclass == 'execution': + nb_total_testcases_execution+=1 + if (run_flag): nb_run_testcases_execution+=1 + else : + print "Unknown test case class: " + testcaseclass + sys.exit() + + except Exception, e: + error='' + error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) + error = error + '\n testcasename = ' + testcasename + '\n testcaseclass = ' + testcaseclass + '\n desc = ' + 'desc' + '\n' + error = error + traceback.format_exc() + print error + print "Continuing to next test case..." + +print (Fore.WHITE + " Parsing done...") + +print (Fore.WHITE + " - Total number of test cases : "+str(nb_total_testcases)) +print (Fore.WHITE + " - Total number class softmodem : "+str(nb_total_testcases_softmodem)) +print (Fore.WHITE + " - Total number class softmodem-noS1 : "+str(nb_total_testcases_softmodem_noS1)) +print (Fore.WHITE + " - Total number class compilation : "+str(nb_total_testcases_compilation)) +print (Fore.WHITE + " - Total number class execution : "+str(nb_total_testcases_execution)) +print +print (Fore.WHITE + " - Selected number of test cases : "+str(nb_run_testcases)) +print (Fore.WHITE + " - Selected class softmodem : "+str(nb_run_testcases_softmodem)) +print (Fore.WHITE + " - Selected class softmodem_noS1 : "+str(nb_run_testcases_softmodem_noS1)) +print (Fore.WHITE + " - Selected class compilation : "+str(nb_run_testcases_compilation)) +print (Fore.WHITE + " - Selected class execution : "+str(nb_run_testcases_execution)) + + +# ************************************************************************** +# ************************************************************************** +# STEP 3 - TEST CAMPAIGNS +# ************************************************************************** +# ************************************************************************** + +test_results = [] + + +print (Fore.YELLOW + '\nStep 3 - TEST CAMPAIGNS') +print (Fore.YELLOW + '-------------------------------------------------') + +print (Fore.WHITE + " Start test campaign...") threadListGlobal=[] -testcaseList=xmlRoot.findall('testCase') -#print testcaseList +run_count = 0 for testcase in testcaseList: try: testcasename = testcase.get('id') testcaseclass = testcase.findtext('class',default='') desc = testcase.findtext('desc',default='') #print "Machine list top level = " + ','.join(MachineList) + if search_test_case_group(testcasename, testcasegroup, TestCaseExclusionList) == True: + run_count+=1 + print (Fore.WHITE + " ("+str(run_count).zfill(3)+"/"+str(nb_run_testcases).zfill(3)+") - test case "+testcasename+" : "), if testcaseclass == 'lte-softmodem' : eNBMachine = testcase.findtext('eNB',default='') UEMachine = testcase.findtext('UE',default='') @@ -2258,6 +2550,22 @@ for param in threadListGlobal: thread_id = param["thread_id"] thread_id.join() + +# ************************************************************************** +# ************************************************************************** +# STEP 4 - TEST REPORT PRODUCTION +# ************************************************************************** +# ************************************************************************** + + + +test_session_stop_time = datetime.datetime.now() + +print (Fore.YELLOW + '\nStep 4 - TEST REPORT PRODUCTION') +print (Fore.YELLOW + '-------------------------------------------------') + +# XML test report +# -------------------------------------------------------------------- print "Creating xml file for overall results..." cmd = "cat $OPENAIR_DIR/cmake_targets/autotests/log/*/*.xml > $OPENAIR_DIR/cmake_targets/autotests/log/results_autotests.xml " res=os.system(cmd) @@ -2276,4 +2584,43 @@ res = oai_localhost.send_recv(cmd) oai_localhost.disconnect() + +# HTML test report +# -------------------------------------------------------------------- +if flag_generate_html_report: + + print "Creating html test report..." + + report_dir = reportdir + '/'+ test_session_start_time.strftime("%Y-%m-%d_%H-%M")+"_"+host + + cmd = 'mkdir -p ' + report_dir + result = os.system(cmd) + + cmd = 'cp -r '+locallogdir+' '+report_dir + result = os.system(cmd) + + context = { + 'report_path' : report_dir, + 'test_session_start_time' : test_session_start_time, + 'test_session_stop_time' : test_session_stop_time, + 'test_session_duration' : test_session_stop_time-test_session_start_time, + 'mtc_host' : host, + 'user' : user, + 'password' : pw, + 'test_results' : test_results, + } + + for test_result in test_results: + cmd = 'mkdir -p ' + report_dir + '/'+ test_result['testcase_name'] + result = os.system(cmd) + + report_file = report_dir + '/'+ test_result['testcase_name'] + '/'+ test_result['testcase_name']+ '_report.html' + + analyser.create_test_report_detailed_html(test_result, report_file ) + + # print test_result + + analyser.create_report_html(context) + + sys.exit() diff --git a/cmake_targets/autotests/run_lte-softmodem-nos1_tests.py b/cmake_targets/autotests/run_lte-softmodem-nos1_tests.py index 19939f0d5c..2ece62ae16 100755 --- a/cmake_targets/autotests/run_lte-softmodem-nos1_tests.py +++ b/cmake_targets/autotests/run_lte-softmodem-nos1_tests.py @@ -1,70 +1,32 @@ #! /usr/bin/python -#****************************************************************************** +#/* +# * 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 +# */ -# 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -# *******************************************************************************/ -# \author Rohit Gupta +# \author Rohit Gupta - Benoit ROBERT (benoit.robert@syrtem.com) # \version 0.1 # @ingroup _test - -#****************************************************************************** -# -# \file run_lte-softmodem-nos1_tests.py -# -# \par Informations -# - \b Project : UED Autotest Framework -# - \b Software : -# -# \date 16 september 2016 -# -# \version 0.1 -# -# \brief master test script to run test class 'handle_testcaseclass_softmodem_noS1' -# This script is largely inspired by 'run_exec_lte-softmodem_tests.py', and -# reused parts of it. -# -# \author Benoit ROBERT (benoit.robert@syrtem.com) -# -# \par Statement of Ownership -# COPYRIGHT (c) 2016 BY SYRTEM S.A.R.L -# This software is furnished under license and may be used and copied -# only in accordance with the terms of such license and with the inclusion -# of the above COPYRIGHT notice. This SOFTWARE or any other copies thereof -# may not be provided or otherwise made available to any other person. -# No title to and ownership of the SOFTWARE is hereby transferred. -# -# The information in this SOFTWARE is subject to change without notice -# and should not be constructed as a commitment by SYRTEM. -# SYRTEM assumes no responsibility for the use or reliability of its -# SOFTWARE on equipment or platform not explicitly validated by SYRTEM. -# -# ******************************************************************************* +# \Changelog +# 2016-11-18 : +# - Add progess bar during test execution update_progress() import tempfile import threading @@ -79,6 +41,8 @@ import math #from time import clock import xml.etree.ElementTree as ET import re +#from dict2xml import dict2xml as xmlify + from colorama import Fore, Back, Style import numpy as np @@ -100,6 +64,31 @@ from ssh import SSHSession import argparse +# update_progress() : Displays or updates a console progress bar +## Accepts a float between 0 and 1. Any int will be converted to a float. +## A value under 0 represents a 'halt'. +## A value at 1 or bigger represents 100% +def update_progress(progress, prefix_string): + barLength = 20 # Modify this to change the length of the progress bar + status = "" + #print "progress = "+ str(progress) + if isinstance(progress, int): + progress = float(progress) + if not isinstance(progress, float): + progress = 0 + status = "error: progress var must be float\r\n" + if progress < 0: + progress = 0 + status = "Halt...\r\n" + if progress >= 1: + progress = 1 + status = "Done...\r\n" + block = int(round(barLength*progress)) + text = "\r"+prefix_string+" [{0}] {1}% {2}".format( "="*block + " "*(barLength-block), progress*100, status) + sys.stdout.write(text) + sys.stdout.flush() + + def exit_prog(exit_val): print(Style.RESET_ALL), sys.exit(exit_val) @@ -318,7 +307,7 @@ def update_config_file(oai, config_string, logdirRepo, python_script): # \param logdir_local_base local directory # \param operation operation to perform (get_all, put_all) transfers recursively for directories def SSHSessionWrapper(machine, username, key_file, password, logdir_remote, logdir_local_base, operation): - max_tries = 100 + max_tries = 10 i=0 while i <= max_tries: i = i +1 @@ -648,7 +637,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , RRH_pre_exec_args = testcase.findtext('RRH_pre_exec_args',default='') RRH_main_exec = testcase.findtext('RRH_main_exec',default='') RRH_main_exec_args = testcase.findtext('RRH_main_exec_args',default='') - RRH_terminate_missing_procs = testcase.findtext('RRH_terminate_missing_procs',default='True') + RRH_terminate_missing_procs = testcase.findtext('RRH_terminate_missing_procs',default='False') eNBMachine = testcase.findtext('eNB',default='') @@ -661,7 +650,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , eNB_main_exec_args = testcase.findtext('eNB_main_exec_args',default='') eNB_traffic_exec = testcase.findtext('eNB_traffic_exec',default='') eNB_traffic_exec_args = testcase.findtext('eNB_traffic_exec_args',default='') - eNB_terminate_missing_procs = testcase.findtext('eNB_terminate_missing_procs',default='True') + eNB_terminate_missing_procs = testcase.findtext('eNB_terminate_missing_procs',default='False') eNB_search_expr_true = testcase.findtext('eNB_search_expr_true','') if re.compile('\w+').match(eNB_search_expr_true) != None: eNB_search_expr_true = eNB_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' @@ -676,7 +665,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , UE_main_exec_args = testcase.findtext('UE_main_exec_args',default='') UE_traffic_exec = testcase.findtext('UE_traffic_exec',default='') UE_traffic_exec_args = testcase.findtext('UE_traffic_exec_args',default='') - UE_terminate_missing_procs = testcase.findtext('UE_terminate_missing_procs',default='True') + UE_terminate_missing_procs = testcase.findtext('UE_terminate_missing_procs',default='False') UE_search_expr_true = testcase.findtext('UE_search_expr_true','') UE_stop_script = testcase.findtext('UE_stop_script','') if re.compile('\w+').match(UE_search_expr_true) != None: @@ -697,25 +686,23 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , HSS_main_exec_args = testcase.findtext('HSS_main_exec_args',default='') EPC_traffic_exec = testcase.findtext('EPC_traffic_exec',default='') EPC_traffic_exec_args = testcase.findtext('EPC_traffic_exec_args',default='') - EPC_terminate_missing_procs = testcase.findtext('EPC_terminate_missing_procs',default='True') + EPC_terminate_missing_procs = testcase.findtext('EPC_terminate_missing_procs',default='False') EPC_search_expr_true = testcase.findtext('EPC_search_expr_true','') if re.compile('\w+').match(EPC_search_expr_true) != None: EPC_search_expr_true = EPC_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' index_eNBMachine = MachineList.index(eNBMachine) index_UEMachine = MachineList.index(UEMachine) -# index_EPCMachine = MachineList.index(EPCMachine) + index_EPCMachine = MachineList.index(EPCMachine) cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep OPENAIR' oai_eNB = openair('localdomain', eNBMachine) oai_eNB.connect(user, password) res= oai_eNB.send_recv(cmd) oai_UE = openair('localdomain', UEMachine) oai_UE.connect(user, password) -# print cmd - res = oai_UE.send_recv(cmd) -# print res -# oai_EPC = openair('localdomain', EPCMfachine) -# oai_EPC.connect(user, password) + res = oai_eNB.send_recv(cmd) + oai_EPC = openair('localdomain', EPCMachine) + oai_EPC.connect(user, password) res = oai_eNB.send_recv(cmd) if RRHMachine != '': cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep OPENAIR' @@ -735,9 +722,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , #cmd = 'mkdir -p ' + logdir_eNB #result = oai_eNB.send_recv(cmd) #cmd = 'mkdir -p ' + logdir_UE - #print cmd #result = oai_UE.send_recv(cmd) - #print result #cmd = 'mkdir -p ' + logdir_EPC #result = oai_EPC.send_recv(cmd) @@ -764,11 +749,9 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , cmd = 'rm -fr ' + logdir_eNB + ' ; mkdir -p ' + logdir_eNB result = oai_eNB.send_recv(cmd) cmd = 'rm -fr ' + logdir_UE + ' ; mkdir -p ' + logdir_UE -# print cmd result = oai_UE.send_recv(cmd) - # print result cmd = 'rm -fr ' + logdir_EPC + '; mkdir -p ' + logdir_EPC -# result = oai_EPC.send_recv(cmd) + result = oai_EPC.send_recv(cmd) cmd = ' rm -fr ' + logdir_local_testcase + ' ; mkdir -p ' + logdir_local_testcase result = os.system(cmd) @@ -919,17 +902,17 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , logfile_task_EPC_compile = logdir_local_testcase + '/EPC_task_compile' + '_' + str(run) + '_.log' logfile_local_traffic_EPC_out = logdir_local_testcase + '/EPC_traffic' + '_' + str(run) + '_.log' -# task_EPC_compile = ' ( uname -a ; date \n' -# task_EPC_compile = task_EPC_compile + 'array_exec_pid=()' + '\n' -# task_EPC_compile = task_EPC_compile + 'cd ' + logdirOpenaircnRepo + ' ; source oaienv \n' -# task_EPC_compile = task_EPC_compile + update_config_file(oai_EPC, EPC_config_file, logdirOpenaircnRepo, logdirOpenaircnRepo+'/TEST/autotests/tools/search_repl.py') + '\n' -# task_EPC_compile = task_EPC_compile + 'source BUILD/TOOLS/build_helper \n' -# if EPC_compile_prog != "": -# task_EPC_compile = task_EPC_compile + '(' + EPC_compile_prog + ' ' + EPC_compile_prog_args + ' ) > ' + logfile_compile_EPC + ' 2>&1 \n' -# if HSS_compile_prog != "": -# task_EPC_compile = task_EPC_compile + '(' + HSS_compile_prog + ' ' + HSS_compile_prog_args + ' ) > ' + logfile_compile_HSS + ' 2>&1 \n' -# task_EPC_compile = task_EPC_compile + ' ) > ' + logfile_task_EPC_compile_out + ' 2>&1 ' -# write_file(logfile_task_EPC_compile, task_EPC_compile, mode="w") + task_EPC_compile = ' ( uname -a ; date \n' + task_EPC_compile = task_EPC_compile + 'array_exec_pid=()' + '\n' + task_EPC_compile = task_EPC_compile + 'cd ' + logdirOpenaircnRepo + ' ; source oaienv \n' + task_EPC_compile = task_EPC_compile + update_config_file(oai_EPC, EPC_config_file, logdirOpenaircnRepo, logdirOpenaircnRepo+'/TEST/autotests/tools/search_repl.py') + '\n' + task_EPC_compile = task_EPC_compile + 'source BUILD/TOOLS/build_helper \n' + if EPC_compile_prog != "": + task_EPC_compile = task_EPC_compile + '(' + EPC_compile_prog + ' ' + EPC_compile_prog_args + ' ) > ' + logfile_compile_EPC + ' 2>&1 \n' + if HSS_compile_prog != "": + task_EPC_compile = task_EPC_compile + '(' + HSS_compile_prog + ' ' + HSS_compile_prog_args + ' ) > ' + logfile_compile_HSS + ' 2>&1 \n' + task_EPC_compile = task_EPC_compile + ' ) > ' + logfile_task_EPC_compile_out + ' 2>&1 ' + write_file(logfile_task_EPC_compile, task_EPC_compile, mode="w") task_EPC = ' ( uname -a ; date \n' task_EPC = task_EPC + ' export OPENAIRCN_TESTDIR=' + logdir_EPC + '\n' @@ -960,30 +943,31 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , task_EPC = task_EPC + ' ) > ' + logfile_task_EPC_out + ' 2>&1 ' write_file(logfile_task_EPC, task_EPC, mode="w") - #first we compile all the programs -# thread_EPC = oaiThread(1, "EPC_thread", EPCMachine, user, password , task_EPC_compile, False, timeout_thread) - thread_eNB = oaiThread(2, "eNB_thread", eNBMachine, user, password , task_eNB_compile, False, timeout_thread) - thread_UE = oaiThread(3, "UE_thread", UEMachine, user, password , task_UE_compile, False, timeout_thread) - if RRHMachine != '': - thread_RRH = oaiThread(4, "RRH_thread", RRHMachine, user, password , task_RRH_compile, False, timeout_thread) - threads=[] - threads.append(thread_eNB) - threads.append(thread_UE) -# threads.append(thread_EPC) - if RRHMachine != '': - threads.append(thread_RRH) - # Start new Threads - thread_eNB.start() - thread_UE.start() -# thread_EPC.start() - if RRHMachine != '': - thread_RRH.start() - #Wait for all the compile threads to complete - for t in threads: - t.join() + #first we compile all the programs but only for run_0 + if run == 0: + thread_EPC = oaiThread(1, "EPC_thread", EPCMachine, user, password , task_EPC_compile, False, timeout_thread) + thread_eNB = oaiThread(2, "eNB_thread", eNBMachine, user, password , task_eNB_compile, False, timeout_thread) + thread_UE = oaiThread(3, "UE_thread", UEMachine, user, password , task_UE_compile, False, timeout_thread) + if RRHMachine != '': + thread_RRH = oaiThread(4, "RRH_thread", RRHMachine, user, password , task_RRH_compile, False, timeout_thread) + threads=[] + threads.append(thread_eNB) + threads.append(thread_UE) + threads.append(thread_EPC) + if RRHMachine != '': + threads.append(thread_RRH) + # Start new Threads + thread_eNB.start() + thread_UE.start() + thread_EPC.start() + if RRHMachine != '': + thread_RRH.start() + #Wait for all the compile threads to complete + for t in threads: + t.join() #Now we execute all the threads -# thread_EPC = oaiThread(1, "EPC_thread", EPCMachine, user, password , task_EPC, False, timeout_thread) + thread_EPC = oaiThread(1, "EPC_thread", EPCMachine, user, password , task_EPC, False, timeout_thread) thread_eNB = oaiThread(2, "eNB_thread", eNBMachine, user, password , task_eNB, False, timeout_thread) thread_UE = oaiThread(3, "UE_thread", UEMachine, user, password , task_UE, False, timeout_thread) if RRHMachine != '': @@ -991,14 +975,14 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , threads=[] threads.append(thread_eNB) threads.append(thread_UE) -# threads.append(thread_EPC) + threads.append(thread_EPC) if RRHMachine != '': threads.append(thread_RRH) # Start new Threads thread_eNB.start() thread_UE.start() -# thread_EPC.start() + thread_EPC.start() if RRHMachine != '': thread_RRH.start() #Wait for all the compile threads to complete @@ -1008,8 +992,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , if RRHMachine != '': cleanOldProgramsAllMachines([oai_eNB, oai_UE, oai_EPC, oai_RRH] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB, logdir_UE, logdir_EPC, logdir_RRH], logdirOAI5GRepo) else: - cleanOldProgramsAllMachines([oai_eNB, oai_UE] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB, logdir_UE, logdir_EPC], logdirOAI5GRepo) -# cleanOldProgramsAllMachines([oai_eNB, oai_UE, oai_EPC] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB, logdir_UE, logdir_EPC], logdirOAI5GRepo) + cleanOldProgramsAllMachines([oai_eNB, oai_UE, oai_EPC] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB, logdir_UE, logdir_EPC], logdirOAI5GRepo) logfile_UE_stop_script_out = logdir_UE + '/UE_stop_script_out' + '_' + str(run) + '_.log' logfile_UE_stop_script = logdir_local_testcase + '/UE_stop_script' + '_' + str(run) + '_.log' @@ -1020,32 +1003,30 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , cmd = cmd + UE_stop_script + '\n' cmd = cmd + ') > ' + logfile_UE_stop_script_out + ' 2>&1 ' write_file(logfile_UE_stop_script , cmd, mode="w") -# thread_UE = oaiThread(4, "UE_thread", UEMachine, user, password , cmd, False, timeout_thread) -# thread_UE.start() -# thread_UE.join() + thread_UE = oaiThread(4, "UE_thread", UEMachine, user, password , cmd, False, timeout_thread) + thread_UE.start() + thread_UE.join() #Now we change the permissions of the logfiles to avoid some of them being with root permissions cmd = 'sudo -E chown -R ' + user + ' ' + logdir_eNB res= oai_eNB.send_recv(cmd) -# print "Changing permissions of logdir <" + logdir_eNB + "> in eNB machine..." + res + print "Changing permissions of logdir <" + logdir_eNB + "> in eNB machine..." + res cmd = 'sudo -E chown -R ' + user + ' ' + logdir_UE -# print cmd res= oai_UE.send_recv(cmd) -# print res -# print "Changing permissions of logdir <" + logdir_UE + "> in UE machine..." + res + print "Changing permissions of logdir <" + logdir_UE + "> in UE machine..." + res cmd = 'sudo -E chown -R ' + user + ' ' + logdir_EPC -# res= oai_EPC.send_recv(cmd) -# print "Changing permissions of logdir <" + logdir_EPC + "> in EPC machine..." + res + res= oai_EPC.send_recv(cmd) + print "Changing permissions of logdir <" + logdir_EPC + "> in EPC machine..." + res if RRHMachine != '': cmd = 'sudo -E chown -R ' + user + ' ' + logdir_RRH res= oai_RRH.send_recv(cmd) -# print "Changing permissions of logdir <" + logdir_RRH + "> in RRH machine..." + res + print "Changing permissions of logdir <" + logdir_RRH + "> in RRH machine..." + res print "Copying files from EPCMachine : " + EPCMachine + "logdir_EPC = " + logdir_EPC -# SSHSessionWrapper(EPCMachine, user, None, password, logdir_EPC, logdir_local + '/cmake_targets/autotests/log/'+ testcasename, "get_all") + SSHSessionWrapper(EPCMachine, user, None, password, logdir_EPC, logdir_local + '/cmake_targets/autotests/log/'+ testcasename, "get_all") print "Copying files from eNBMachine " + eNBMachine + "logdir_eNB = " + logdir_eNB SSHSessionWrapper(eNBMachine, user, None, password, logdir_eNB, logdir_local + '/cmake_targets/autotests/log/'+ testcasename, "get_all") @@ -1089,6 +1070,13 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , run_result=0 run_result_string = ' RUN_'+str(run) + ' = FAIL(Thread_Busy)' + #If there is Segmentation fault, we mark the test case as failure as most likely eNB crashed + cmd = "grep -ilr \"segmentation fault\" " + logdir_local_testcase + " | cat " + cmd_out = subprocess.check_output ([cmd], shell=True) + if len(cmd_out) !=0: + run_result=0 + run_result_string = ' RUN_'+str(run) + ' = FAIL(SEGFAULT)' + run_result_string = run_result_string + tput_run_string test_result=test_result & run_result @@ -1096,7 +1084,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , oai_eNB.disconnect() oai_UE.disconnect() -# oai_EPC.disconnect() + oai_EPC.disconnect() #We need to close the new ssh session that was created #if index_eNBMachine == index_EPCMachine: # oai_EPC.disconnect() @@ -1113,6 +1101,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , + # \brief handler for executing test cases (lte-softmodem-noS1) # \param testcase name of testcase # \param oldprogramList list of programs which must be terminated before running a test case @@ -1329,6 +1318,8 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe if testcase_verdict != 'PASS': # if something went wrong to not run test cases max_ntries=0 + indent="\t\t" + runs_results = [] nb_runs = 0 nb_run_pass = 0 @@ -1348,9 +1339,11 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe # # RUN initialization # ---------------------------------------------------- - print (Fore.WHITE + indent + "> RUN_"+str(run).zfill(2)+" : " ), - - sys.stdout.flush() + + prefix_string = Fore.WHITE + indent + "> RUN_"+str(run).zfill(2)+" :" + +# print (Fore.WHITE + indent + "> RUN_"+str(run).zfill(2)+" : " ), +# sys.stdout.flush() run_start_time=datetime.datetime.now() @@ -1466,8 +1459,34 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe threads.append(thread_UE) thread_eNB.start() thread_UE.start() + + run_work_inprogress_flag = True + progress_step = timeout_thread/20 + progress_count = 0 + + while (run_work_inprogress_flag): + + + update_progress(float(progress_count)/float(timeout_thread),prefix_string) + + time.sleep(progress_step) + + progress_count += progress_step + +# sys.stdout.write ('#') +# sys.stdout.flush() + + run_work_inprogress_flag = False + for t in threads: + if t.isAlive(): + run_work_inprogress_flag = True + + + update_progress(1,prefix_string) + for t in threads: - t.join() + t.join() + # # @@ -1482,10 +1501,12 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe fname = logdir_local_run+ '/UE_exec' + '_' + str(run) + '_.log' cell_synch_status = analyser.check_cell_synchro(fname) + print (Fore.WHITE + indent + "> Check Cell synchro :"), + if cell_synch_status == 'CELL_SYNCH': - print '!!!!!!!!!!!!!! Cell synchronized !!!!!!!!!!!' + print ( Fore.GREEN + cell_synch_status) else : - print '!!!!!!!!!!!!!! Cell NOT NOT synchronized !!!!!!!!!!!' + print ( Fore.RED + cell_synch_status) metric_checks_flag = 0 ue_seg_fault_status = analyser.check_exec_seg_fault(fname) @@ -1504,6 +1525,9 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe # UE side metrics metricList=testcase.findall('UE_metric') for metric in metricList: + + metric_verdict = 'PASS' + metric_def = {} metric_def['id'] = metric.get('id') metric_def['description'] = metric.get('description') @@ -1524,15 +1548,19 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe metric_extracted = analyser.do_extract_metrics(args) - print "\t > Metric "+metric_def['id']+" :" - print "\t\t> min = "+ str( metric_extracted['metric_min'] ) - print "\t\t> min_index = "+ str( metric_extracted['metric_min_index'] ) - print "\t\t> max = "+ str( metric_extracted['metric_max'] ) - print "\t\t> max_index = "+ str( metric_extracted['metric_max_index'] ) - print "\t\t> mean = "+ str( metric_extracted['metric_mean'] ) - print "\t\t> median = "+ str( metric_extracted['metric_median'] ) + print (Fore.WHITE + indent + "> Metric : "+metric_def['id']), + print ("(min="+str( metric_extracted['metric_min'])+", max="+str( metric_extracted['metric_max'])+", mean="+str( metric_extracted['metric_mean'])+", median="+str( metric_extracted['metric_median'])+")") - verdict = analyser.do_check_verdict(metric_def, metric_extracted) +# print "\t > Metric "+metric_def['id']+" :" +# print "\t\t> min = "+ str( metric_extracted['metric_min'] ) +# print "\t\t> min_index = "+ str( metric_extracted['metric_min_index'] ) +# print "\t\t> max = "+ str( metric_extracted['metric_max'] ) +# print "\t\t> max_index = "+ str( metric_extracted['metric_max_index'] ) +# print "\t\t> mean = "+ str( metric_extracted['metric_mean'] ) +# print "\t\t> median = "+ str( metric_extracted['metric_median'] ) + + if metric_def['pass_fail_stat'] : + metric_verdict = analyser.do_check_verdict(metric_def, metric_extracted) metric_fig = logdir_local_run+ '/UE_metric_'+ metric_def['id']+'_' + str(run) + '_.png' analyser.do_img_metrics(metric_def, metric_extracted, metric_fig) @@ -1560,6 +1588,13 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe runs_metrics.append(run_metrics) + if metric_verdict != 'PASS': + verdict = metric_verdict + + # End Metrics LOOP + # --------------------- + + # Traffic analysis if UE_traffic_exec != "": @@ -1613,9 +1648,9 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe run_stop_time=datetime.datetime.now() run_duration = run_stop_time-run_start_time # print (Fore.WHITE + ("duration=" :"), - print (Fore.WHITE + indent + "> RUN duration : "+ str(run_duration) +"s" ) + print (Fore.WHITE + indent + "> RUN duration : "+ str(run_duration) +"s" ) - print (Fore.WHITE + indent + "> RUN verdict :"), + print (Fore.WHITE + indent + "> RUN verdict :"), if verdict == 'PASS': nb_run_pass += 1 @@ -1645,6 +1680,8 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe # END RUN LOOP #---------------------------------------------------- + indent="\t" + # Test case duration # ---------------------------------- testcase_time_stop = datetime.datetime.now() @@ -1684,11 +1721,9 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe else: print (Fore.YELLOW+'INCONCLUSIVE') - duration= testcase_time_stop - testcase_time_start - xmlFile = logdir_local_testcase + '/test.' + testcasename + '.xml' - xml="\n \n" - write_file(xmlFile, xml, mode="w") + print(Style.RESET_ALL) + duration= testcase_time_stop - testcase_time_start test_result = dict(testcase_name=testcasename, testcaseclass=testcaseclass, @@ -1709,161 +1744,20 @@ def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRe runs_results = runs_results) test_results.append(test_result) + xmlFile = logdir_local_testcase + '/test.' + testcasename + '.xml' + xml="\n \n" + write_file(xmlFile, xml, mode="w") + + xmlFile_ng = logdir_local_testcase + '/test.' + testcasename + '_ng.xml' + xml_ng = xmlify(test_result, wrap=testcasename, indent=" ") + write_file(xmlFile_ng, xml_ng, mode="w") + + + return testcase_verdict -# mypassword='' -# #addsudo = 'echo \'' + mypassword + '\' | sudo -S -E ' -# addpass = 'echo \'' + mypassword + '\' | ' -# #user = getpass.getuser() - - - - - - - -# eNB_traffic_exec = testcase.findtext('eNB_traffic_exec',default='') -# eNB_traffic_exec_args = testcase.findtext('eNB_traffic_exec_args',default='') -# eNB_terminate_missing_procs = testcase.findtext('eNB_terminate_missing_procs',default='True') -# eNB_search_expr_true = testcase.findtext('eNB_search_expr_true','') -# if re.compile('\w+').match(eNB_search_expr_true) != None: -# eNB_search_expr_true = eNB_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' - - - -# UE_traffic_exec = testcase.findtext('UE_traffic_exec',default='') -# UE_traffic_exec_args = testcase.findtext('UE_traffic_exec_args',default='') -# -# UE_search_expr_true = testcase.findtext('UE_search_expr_true','') -# UE_stop_script = testcase.findtext('UE_stop_script','') -# if re.compile('\w+').match(UE_search_expr_true) != None: -# UE_search_expr_true = UE_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' - - - -# #cleanOldPrograms(oai_eNB, oldprogramList, CleanUpAluLteBox, ExmimoRfStop) -# #cleanOldPrograms(oai_UE, oldprogramList, CleanUpAluLteBox, ExmimoRfStop) -# #cleanOldPrograms(oai_EPC, oldprogramList, CleanUpAluLteBox, ExmimoRfStop) -# logdir_local = os.environ.get('OPENAIR_DIR') -# if logdir_local is None: -# print "Environment variable OPENAIR_DIR not set correctly" -# sys.exit() - - -# print "Updating the config files for ENB/UE/EPC..." -# #updating the eNB/UE/EPC configuration file from the test case -# #update_config_file(oai_eNB, eNB_config_file, logdirOAI5GRepo) -# #update_config_file(oai_UE, UE_config_file, logdirOAI5GRepo) -# #update_config_file(oai_EPC, EPC_config_file, logdirOpenaircnRepo) - -# test_result=1 -# test_result_string='' -# start_time=time.time() - -# for run in range(0,nruns): -# run_result=1 -# run_result_string='' -# logdir_eNB = logdirOAI5GRepo+'/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) -# logdir_UE = logdirOAI5GRepo+'/cmake_targets/autotests/log/'+ testcasename + - - - - -# logfile_traffic_eNB = logdir_eNB + '/eNB_traffic' + '_' + str(run) + '_.log' - - -# logfile_local_traffic_eNB_out = logdir_local_testcase + '/eNB_traffic' + '_' + str(run) + '_.log' -# logfile_tshark_eNB = logdir_eNB + '/eNB_tshark' + '_' + str(run) + '_.log' -# logfile_pcap_eNB = logdir_eNB + '/eNB_tshark' + '_' + str(run) + '_.pcap' -# logfile_pcap_zip_eNB = logdir_eNB + '/eNB_tshark' + '_' + str(run) + '_.pcap.zip' -# logfile_pcap_tmp_eNB = '/tmp/' + '/eNB_tshark' + '_' + str(run) + '_.pcap' - -# task_eNB_compile = ' ( uname -a ; date \n' -# task_eNB_compile = task_eNB_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' -# task_eNB_compile = task_eNB_compile + 'env |grep OPENAIR \n' -# task_eNB_compile = task_eNB_compile + update_config_file(oai_eNB, eNB_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' -# if eNB_compile_prog != "": -# task_eNB_compile = task_eNB_compile + ' ( ' + eNB_compile_prog + ' '+ eNB_compile_prog_args + ' ) > ' + logfile_compile_eNB + ' 2>&1 \n' -# task_eNB_compile = task_eNB_compile + ' date ) > ' + logfile_task_eNB_compile_out + ' 2>&1 ' -# write_file(logfile_task_eNB_compile, task_eNB_compile, mode="w") - - - -# #task_eNB = 'echo \" ' + task_eNB + '\" > ' + logfile_script_eNB + ' 2>&1 ; ' + task_eNB -# logfile_compile_UE = logdir_UE + '/UE_compile' + '_' + str(run) + '_.log' -# logfile_exec_UE = logdir_UE + '/UE_exec' + '_' + str(run) + '_.log' - - - - -# #Now we execute all the threads - - -# #Now we get the log files from remote machines on the local machine -# cleanOldProgramsAllMachines([oai_eNB, oai_UE] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB, logdir_UE, logdir_EPC], logdirOAI5GRepo) - -# logfile_UE_stop_script_out = logdir_UE + '/UE_stop_script_out' + '_' + str(run) + '_.log' -# logfile_UE_stop_script = logdir_local_testcase + '/UE_stop_script' + '_' + str(run) + '_.log' - -# if UE_stop_script != "": -# cmd = ' ( uname -a ; date \n' -# cmd = cmd + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' -# cmd = cmd + 'env |grep OPENAIR \n' + 'array_exec_pid=() \n' -# cmd = cmd + UE_stop_script + '\n' -# cmd = cmd + ') > ' + logfile_UE_stop_script_out + ' 2>&1 ' -# write_file(logfile_UE_stop_script , cmd, mode="w") -# # thread_UE = oaiThread(4, "UE_thread", UEMachine, user, password , cmd, False, timeout_thread) -# # thread_UE.start() -# # thread_UE.join() - - - - -# #Currently we only perform throughput tests -# tput_run_string='' -# result, tput_string = tput_test_search_expr(eNB_search_expr_true, logfile_local_traffic_eNB_out) -# tput_run_string = tput_run_string + tput_string -# run_result=run_result&result -# result, tput_string = tput_test_search_expr(EPC_search_expr_true, logfile_local_traffic_EPC_out) -# run_result=run_result&result -# tput_run_string = tput_run_string + tput_string -# result, tput_string = tput_test_search_expr(UE_search_expr_true, logfile_local_traffic_UE_out) -# run_result=run_result&result -# tput_run_string = tput_run_string + tput_string - -# if run_result == 1: -# run_result_string = ' RUN_'+str(run) + ' = PASS' -# else: -# run_result_string = ' RUN_'+str(run) + ' = FAIL' - -# #If there is assertion, we mark the test case as failure as most likely eNB crashed -# cmd = "grep -ilr \"assertion\" " + logdir_local_testcase + " | cat " -# cmd_out = subprocess.check_output ([cmd], shell=True) -# if len(cmd_out) !=0 : -# run_result=0 -# run_result_string = ' RUN_'+str(run) + ' = FAIL(Assert)' - -# #If there is thread busy error, we mark the test case as failure as most likely eNB crashed -# cmd = "grep -ilr \"thread busy\" " + logdir_local_testcase + " | cat " -# cmd_out = subprocess.check_output ([cmd], shell=True) -# if len(cmd_out) !=0: -# run_result=0 -# run_result_string = ' RUN_'+str(run) + ' = FAIL(Thread_Busy)' - -# run_result_string = run_result_string + tput_run_string - -# test_result=test_result & run_result -# test_result_string=test_result_string + run_result_string - - - - - - - - # \brief This function searches if test case is present in list of test cases that need to be executed by user # \param testcasename the test case to search for @@ -1982,7 +1876,7 @@ flag_skip_oai_install=False flag_skip_machine_preparation=False flag_skip_sanity_check=False Timeout_cmd='' -xmlInputFile=os.environ.get('OPENAIR_DIR')+"/cmake_targets/autotests/testsuite_ue_noS1.xml" +xmlInputFile='' #print "Number of arguments argc = " + str(len(sys.argv)) #for index in range(1,len(sys.argv) ): @@ -2054,6 +1948,9 @@ while i < len (sys.argv): flag_skip_machine_preparation=True elif arg == '--skip-sanity-check': flag_skip_sanity_check=True + elif arg == '--test-suite' : + xmlInputFile = sys.argv[i+1] + i = i +1 elif arg == '-h' : print "-s: This flag *MUST* be set to start the test cases" print "-r: Remove the log directory in autotests" @@ -2073,6 +1970,7 @@ while i < len (sys.argv): print "--skip-oai-install: Skips the openairinterface5g installer" print "--skip-machine-preparation: skipp the whole system preparation -> direct to test cases" print "--skip-sanity-check: skipp the machine sanity checks" + print "--test-suite: Select a XML test-suite file" sys.exit() else : print "Unrecongnized Option: <" + arg + ">. Use -h to see valid options" @@ -2163,7 +2061,7 @@ print (Fore.WHITE + ' + Timeout_cmd : '+ Timeout_cmd) if GitOAI5GHeadVersion == '': - cmd = "git log --pretty=format:\'%H\' -n 1 origin/"+ GitOAI5GRepoBranch + cmd = "git log --pretty=format:\'%H\' -n 1" # origin/"+ GitOAI5GRepoBranch # cmd = "git show-ref --heads -s "+ GitOAI5GRepoBranch GitOAI5GHeadVersion = subprocess.check_output ([cmd], shell=True) GitOAI5GHeadVersion=GitOAI5GHeadVersion.replace("\n","") @@ -2337,13 +2235,24 @@ if not flag_skip_machine_preparation: setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' + + #Sometimes git fails so the script below retries in that case + localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/tools/git-retry.sh') + remotefile = logdir + '/git-retry.sh' + paramList=[] + port=22 + paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) + sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') + sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) + cmd = ' ( \n' #cmd = cmd + 'rm -fR ' + logdir + '\n' #cmd = cmd + 'mkdir -p ' + logdir + '\n' cmd = cmd + 'cd '+ logdir + '\n' - cmd = cmd + 'git config --global http.sslVerify false \n' - cmd = cmd + 'git clone '+ GitOAI5GRepo +' \n' - cmd = cmd + 'git clone '+ GitOpenaircnRepo + ' \n' + cmd = cmd + 'sudo apt-get install -y git \n' + cmd = cmd + 'chmod 700 ' + logdir + '/git-retry.sh \n' + cmd = cmd + logdir + '/git-retry.sh clone '+ GitOAI5GRepo +' \n' + cmd = cmd + logdir + '/git-retry.sh clone '+ GitOpenaircnRepo + ' \n' cmd = cmd + 'cd ' + logdirOAI5GRepo + '\n' cmd = cmd + 'git checkout ' + GitOAI5GRepoBranch + '\n' if GitOAI5GHeadVersion : @@ -2399,9 +2308,8 @@ if not flag_skip_machine_preparation: paramList=[] sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') - #Now we copy patch files for u + #Now we copy patch files and apply them print( Fore.WHITE + " - Installating patch files on machine " + MachineList[index]) - #Now we copy patch files for u for patchFile in OAI5GpatchFileList: localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/patches/')+patchFile.get('name') remotefile = logdirOAI5GRepo + '/cmake_targets/autotests/patches/'+patchFile.get('name') @@ -2417,19 +2325,20 @@ if not flag_skip_machine_preparation: paramList=[] + setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' + setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' + localfile = locallogdir + '/setup_log_' + MachineList[index] + '_.txt' + remotefile = logdir + '/setup_log_' + MachineList[index] + '_.txt' + sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') + paramList.append ( {"operation":'get', "localfile":localfile, "remotefile":remotefile} ) + #sftp_module (user, pw, MachineList[index], port, localfile, remotefile, sftp_log, "get") + #Now we copy test_case_list.xml on the remote machines localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/test_case_list.xml') remotefile = logdirOAI5GRepo + '/cmake_targets/autotests/test_case_list.xml' # paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) # sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) - setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' - setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' - localfile = locallogdir + '/setup_log_' + MachineList[index] + '_.txt' - remotefile = logdir + '/setup_log_' + MachineList[index] + '_.txt' - - sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') - paramList.append ( {"operation":'get', "localfile":localfile, "remotefile":remotefile} ) sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) @@ -2456,6 +2365,7 @@ if not flag_skip_machine_preparation: print "Exiting now..." sys.exit(0) + else: print (Fore.RED + " Skipping Machine preparation...") @@ -2558,21 +2468,65 @@ for testcase in testcaseList: try: testcasename = testcase.get('id') testcaseclass = testcase.findtext('class',default='') + desc = testcase.findtext('desc',default='') + #print "Machine list top level = " + ','.join(MachineList) - if (search_test_case_group(testcasename, testcasegroup, TestCaseExclusionList)): + if search_test_case_group(testcasename, testcasegroup, TestCaseExclusionList) == True: run_count+=1 print (Fore.WHITE + " ("+str(run_count).zfill(3)+"/"+str(nb_run_testcases).zfill(3)+") - test case "+testcasename+" : "), if testcaseclass == 'lte-softmodem' : - print (Fore.RED + "skipped - lte-softmodem class not supported") - elif testcaseclass == 'lte-softmodem-noS1': - print + eNBMachine = testcase.findtext('eNB',default='') + UEMachine = testcase.findtext('UE',default='') + EPCMachine = testcase.findtext('EPC',default='') + #index_eNBMachine = MachineList.index(eNBMachine) + #index_UEMachine = MachineList.index(UEMachine) + #index_EPCMachine = MachineList.index(EPCMachine) + if (eNBMachine not in MachineList)|(UEMachine not in MachineList)|(UEMachine not in MachineList): + print "One of the machines is not in the machine list" + print "eNBMachine : " + eNBMachine + "UEMachine : " + UEMachine + "EPCMachine : " + EPCMachine + "MachineList : " + ','.join(MachineList) + print "testcasename = " + testcasename + " class = " + testcaseclass + threadListGlobal = wait_testcaseclass_generic_threads(threadListGlobal, Timeout_execution) + #cleanOldProgramsAllMachines(oai_list, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop) + handle_testcaseclass_softmodem (testcase, CleanUpOldProgs, logdirOAI5GRepo, logdirOpenaircnRepo, MachineList, user, pw, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, Timeout_cmd ) + + #The lines below are copied from below to trace the failure of some of the machines in test setup. These lines below need to be removed in long term + print "Creating xml file for overall results..." + cmd = "cat $OPENAIR_DIR/cmake_targets/autotests/log/*/*.xml > $OPENAIR_DIR/cmake_targets/autotests/log/results_autotests.xml " + res=os.system(cmd) + os.system('sync') + print "Now copying files to NFS Share" + oai_localhost = openair('localdomain','localhost') + oai_localhost.connect(user,pw) + cmd = ' mkdir -p ' + NFSTestsResultsDir + res = oai_localhost.send_recv(cmd) + + print "Copying files from GilabCI Runner Machine : " + host + " .locallogdir = " + locallogdir + ", NFSTestsResultsDir = " + NFSTestsResultsDir + SSHSessionWrapper('localhost', user, None, pw , NFSTestsResultsDir , locallogdir, "put_all") + oai_localhost.disconnect() + + elif testcaseclass == 'lte-softmodem-noS1' : + eNBMachine = testcase.findtext('eNB',default='') + UEMachine = testcase.findtext('UE',default='') + if (eNBMachine not in MachineList)|(UEMachine not in MachineList): + print "One of the machines is not in the machine list" + print "eNBMachine : " + eNBMachine + "UEMachine : " + UEMachine + "MachineList : " + ','.join(MachineList) + print "testcasename = " + testcasename + " class = " + testcaseclass + threadListGlobal = wait_testcaseclass_generic_threads(threadListGlobal, Timeout_execution) + handle_testcaseclass_softmodem_noS1 (testcase, CleanUpOldProgs, logdirOAI5GRepo, logdirOpenaircnRepo, MachineList, user, pw, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, Timeout_cmd ) - elif testcaseclass == 'compilation': - print (Fore.RED + "skipped - compilation class not supported") - elif testcaseclass == 'execution': - print (Fore.RED + "skipped - execution class not supported") + + #The lines below are copied from below to trace the failure of some of the machines in test setup. These lines below need to be removed in long term + print "Creating xml file for overall results..." + cmd = "cat $OPENAIR_DIR/cmake_targets/autotests/log/*/*.xml > $OPENAIR_DIR/cmake_targets/autotests/log/results_autotests.xml " + res=os.system(cmd) + os.system('sync') + + elif (testcaseclass == 'compilation'): + threadListGlobal = handle_testcaseclass_generic (testcasename, threadListGlobal, CleanUpOldProgs, logdirOAI5GRepo, MachineListGeneric, user, pw, CleanUpAluLteBox,Timeout_execution, ExmimoRfStop) + elif (testcaseclass == 'execution'): + threadListGlobal = handle_testcaseclass_generic (testcasename, threadListGlobal, CleanUpOldProgs, logdirOAI5GRepo, MachineListGeneric, user, pw, CleanUpAluLteBox, Timeout_execution, ExmimoRfStop) else : - print (Fore.RED + "Unknown test case class: " + testcaseclass) + print "Unknown test case class: " + testcaseclass sys.exit() except Exception, e: @@ -2582,8 +2536,14 @@ for testcase in testcaseList: error = error + traceback.format_exc() print error print "Continuing to next test case..." + #sys.exit(1) -threadListGlobal=[] + +print "Exiting the test cases execution now. Waiting for existing threads to complete..." + +for param in threadListGlobal: + thread_id = param["thread_id"] + thread_id.join() # ************************************************************************** @@ -2633,153 +2593,3 @@ analyser.create_report_html(context) exit_prog(0) -#print testcaseList -for testcase in testcaseList: - try: - testcasename = testcase.get('id') - testcaseclass = testcase.findtext('class',default='') - desc = testcase.findtext('desc',default='') - #print "Machine list top level = " + ','.join(MachineList) - if search_test_case_group(testcasename, testcasegroup, TestCaseExclusionList) == True: - if testcaseclass == 'lte-softmodem' : - eNBMachine = testcase.findtext('eNB',default='') - UEMachine = testcase.findtext('UE',default='') - EPCMachine = testcase.findtext('EPC',default='') - #index_eNBMachine = MachineList.index(eNBMachine) - #index_UEMachine = MachineList.index(UEMachine) - #index_EPCMachine = MachineList.index(EPCMachine) - if (eNBMachine not in MachineList)|(UEMachine not in MachineList)|(UEMachine not in MachineList): - print "One of the machines is not in the machine list" - print "eNBMachine : " + eNBMachine + "UEMachine : " + UEMachine + "EPCMachine : " + EPCMachine + "MachineList : " + ','.join(MachineList) - print "testcasename = " + testcasename + " class = " + testcaseclass - threadListGlobal = wait_testcaseclass_generic_threads(threadListGlobal, Timeout_execution) - #cleanOldProgramsAllMachines(oai_list, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop) - #handle_testcaseclass_softmodem (testcase, CleanUpOldProgs, logdirOAI5GRepo, logdirOpenaircnRepo, MachineList, user, pw, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, Timeout_cmd ) - - #The lines below are copied from below to trace the failure of some of the machines in test setup. These lines below need to be removed in long term -# print "Creating xml file for overall results..." -# cmd = "cat $OPENAIR_DIR/cmake_targets/autotests/log/*/*.xml > $OPENAIR_DIR/cmake_targets/autotests/log/results_autotests.xml " -# res=os.system(cmd) -# os.system('sync') -# print "Now copying files to NFS Share" -# oai_localhost = openair('localdomain','localhost') -# oai_localhost.connect(user,pw) -# cmd = ' mkdir -p ' + NFSTestsResultsDir -# print cmd -# res = oai_localhost.send_recv(cmd) -# print res - - # print "Copying files from GilabCI Runner Machine : " + host + " .locallogdir = " + locallogdir + ", NFSTestsResultsDir = " + NFSTestsResultsDir - # SSHSessionWrapper('localhost', user, None, pw , NFSTestsResultsDir , locallogdir, "put_all") - # oai_localhost.disconnect() - - elif (testcaseclass == 'compilation'): - threadListGlobal = handle_testcaseclass_generic (testcasename, threadListGlobal, CleanUpOldProgs, logdirOAI5GRepo, MachineListGeneric, user, pw, CleanUpAluLteBox,Timeout_execution, ExmimoRfStop) - elif (testcaseclass == 'execution'): - threadListGlobal = handle_testcaseclass_generic (testcasename, threadListGlobal, CleanUpOldProgs, logdirOAI5GRepo, MachineListGeneric, user, pw, CleanUpAluLteBox, Timeout_execution, ExmimoRfStop) - else : - print "Unknown test case class: " + testcaseclass - sys.exit() - - except Exception, e: - error='' - error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) - error = error + '\n testcasename = ' + testcasename + '\n testcaseclass = ' + testcaseclass + '\n desc = ' + 'desc' + '\n' - error = error + traceback.format_exc() - print error - print "Continuing to next test case..." - #sys.exit(1) - - -print "Exiting the test cases execution now. Waiting for existing threads to complete..." - -for param in threadListGlobal: - thread_id = param["thread_id"] - thread_id.join() - -print "Creating xml file for overall results..." -cmd = "cat $OPENAIR_DIR/cmake_targets/autotests/log/*/*.xml > $OPENAIR_DIR/cmake_targets/autotests/log/results_autotests.xml " -res=os.system(cmd) - -print "Now copying files to NFS Share" -oai_localhost = openair('localdomain','localhost') -oai_localhost.connect(user,pw) -cmd = 'mkdir -p ' + NFSTestsResultsDir -print cmd -res = oai_localhost.send_recv(cmd) -print res - -print "Copying files from GilabCI Runner Machine : " + host + " .locallogdir = " + locallogdir + ", NFSTestsResultsDir = " + NFSTestsResultsDir -SSHSessionWrapper('localhost', user, None, pw , NFSTestsResultsDir , locallogdir, "put_all") - -cmd = "cat " + NFSTestsResultsDir + "/log/*/*.xml > " + NFSTestsResultsDir + "/log/results_autotests.xml" -res = oai_localhost.send_recv(cmd) - -oai_localhost.disconnect() - -sys.exit() - - - - - - - -run_count = 0 -for testcase in testcaseList: - try: - testcasename = testcase.get('id') - testcaseclass = testcase.findtext('class',default='') - - if (search_test_case_group(testcasename, testcasegroup, TestCaseExclusionList)): - run_count+=1 - print (Fore.WHITE + " ("+str(run_count).zfill(3)+"/"+str(nb_run_testcases).zfill(3)+") - test case "+testcasename+" : "), - if testcaseclass == 'lte-softmodem' : - print (Fore.RED + "skipped - lte-softmodem class not supported") - elif testcaseclass == 'lte-softmodem-noS1': - print - - testcase_verdict = 'PASS' - testcase_time_start = datetime.datetime.now() - testcase_name = testcase.get('id') - testcase_desc = testcase.findtext('desc',default='') - timeout_cmd = testcase.findtext('TimeOut_cmd',default='') - timeout_cmd = int(float(timeout_cmd)) - timeout_thread = timeout_cmd + 300 #Timeout_thread is more than that of cmd to have room for compilation time, etc - if nruns_lte_softmodem == '': - nruns = testcase.findtext('nruns',default='') - else: - nruns = nruns_lte_softmodem - nruns = int(float(nruns)) - tags = testcase.findtext('tags',default='') - testcase_time_stop = datetime.datetime.now() - - test_result = dict(testcase_name=testcase_name, - testcaseclass=testcaseclass, - testcase_verdict = testcase_verdict, - testcase_time_start=testcase_time_start, - testcase_time_stop=testcase_time_stop, - tags=tags, - nruns=nruns, - testcase_timeout=timeout_cmd, - testcase_duration = testcase_time_stop-testcase_time_start, - testcase_eNBMachine ="TOTO", - testcase_UEMachine ="TITI") - test_results.append(test_result) - - - elif testcaseclass == 'compilation': - print (Fore.RED + "skipped - compilation class not supported") - elif testcaseclass == 'execution': - print (Fore.RED + "skipped - execution class not supported") - else : - print (Fore.RED + "Unknown test case class: " + testcaseclass) - sys.exit() - - except Exception, e: - error='' - error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) - error = error + '\n testcasename = ' + testcasename + '\n testcaseclass = ' + testcaseclass + '\n desc = ' + 'desc' + '\n' - error = error + traceback.format_exc() - print error - print "Continuing to next test case..." diff --git a/cmake_targets/autotests/testsuite_ue_noS1.xml b/cmake_targets/autotests/testsuite_ue_noS1.xml new file mode 100644 index 0000000000..c2f87b881f --- /dev/null +++ b/cmake_targets/autotests/testsuite_ue_noS1.xml @@ -0,0 +1,2898 @@ + + +imb182-desktop yanbo-M4HM87P-00 + /mnt/sradio/TEST_RESULTS/ + https://gitlab.eurecom.fr/oai1B/openairinterface5g.git + + + https://gitlab.eurecom.fr/oai/openair-cn.git --> + develop1B + + + + + + + + develop + oaisim oaisim_nos1 lte-softmodem lte-softmodem-nos1 mme_gw run_epc auth_request run_hss oai_hss mme spgw hss hss_sim configure_cots* wvdial iperf iperf_script iperf_script_phone ping tshark rrh_gw iperf3 iperf3_script iperf3_script_phone pppd + sudo -S -E /opt/ltebox/tools/stop_ltebox +$OPENAIR_DIR/cmake_targets/build_oai -w EXMIMO -c; sudo -S -E $OPENAIR_DIR/cmake_targets/tools/stop_exmimo2; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_huaweiE398_ue.py --reset-ue; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue; uname -a; sudo -E dmesg + 36000 + + + yanbo-M4HM87P-00 + + + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS00 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS00 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 1 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS01 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 1 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS01 + 36 + + + + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS09 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS09 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS16 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS16 + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS10 + + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS10 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS17 + + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS17 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 18 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS18 + + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 18 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS18 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS19 + + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS19 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 20 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS20 + + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 20 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS20 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 21 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS21 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 21 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS21 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 22 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS22 + + 36 + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 22 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS22 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 23 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS23 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 23 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS23 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 24 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS24 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 24 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS24 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 25 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS25 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 25 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS25 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 26 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS26 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 26 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS26 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS27 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS27 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS28 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS28 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 3600 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_STAB.BAND7.5MHZ.MCS27 + 16 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_STAB.BAND7.5MHZ.MCS27 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf -W -m 27 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r50 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.10MHZ.MCS27 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf -W -m 27 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r50 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.10MHZ.MCS27 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf -W -m 28 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r50 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + UE_USRP.NOS1.PHYTEST_PERF.BAND7.10MHZ.MCS28 + 36 + + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf -W -m 19 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r50 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test + + + + + + False + UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.10MHZ.MCS19 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 512K + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS00 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf -W -m 28 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 6M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r50 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.10MHZ.MCS28 + 36 + + + + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 512K + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS00 + 36 + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS09 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS09 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS10 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS10 + 36 + + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS16 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS16 + 36 + + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS17 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS17 + 36 + + + + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS19 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 10M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS19 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 + sleep 30;iperf -c 10.0.1.9 -i 1 -u -b 10M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 5; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS27 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 3600 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 2800 + + False + UE_USRP.NOS1.DATA_IPERF_STAB.BAND7.5MHZ.MCS27 + 16 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + ued-PRM-130 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w EXMIMO --noS1 --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2660000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 + + iperf -s -i 1 -u + + 200 + + False + UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS27 + 36 + + + + + + + diff --git a/cmake_targets/autotests/tools/autotest_analyser.py b/cmake_targets/autotests/tools/autotest_analyser.py index a75727ad65..61759a1545 100755 --- a/cmake_targets/autotests/tools/autotest_analyser.py +++ b/cmake_targets/autotests/tools/autotest_analyser.py @@ -35,12 +35,15 @@ import getopt import sys from subprocess import call +import encoder + +sys.path.append(os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/tools/')) #test_cases = ('030001', '030901', '031001', '031601', '031701', '031801', '031901', '032001', '032101', '032201', '032301', '032501', '032601', '032801') -test_cases = ('030030' , '030030' ) +test_cases = ('032800' , '032730' ) -nb_run = 3 +nb_run = 2 def error_opt(msg): print("Option error: " + msg) @@ -58,14 +61,27 @@ def main(args): + # metric = {} + # metric['id'] = 'UE_DLSCH_BITRATE' + # metric['description'] = 'UE downlink physical throughput' + # metric['regex'] = '(UE_DLSCH_BITRATE) =\s+(\d+\.\d+) kbps.+frame = (\d+)\)' + # metric['unit_of_meas'] = 'kbps' + # metric['min_limit'] = 14668.8 + + +#AUTOTEST Metric : RRC Measurments RSRP[0]=-97.60 dBm/RE, RSSI=-72.83 dBm, RSRQ[0] 9.03 dB, N0 -125 dBm/RE, NF 7.2 dB (frame = 4490) + metric = {} - metric['id'] = 'UE_DLSCH_BITRATE' - metric['description'] = 'UE downlink physical throughput' - metric['regex'] = '(UE_DLSCH_BITRATE) =\s+(\d+\.\d+) kbps.+frame = (\d+)\)' + metric['id'] = 'UE_DL_RRC_MEAS' + metric['description'] = 'UE downlink RRC Measurments' + metric['nb_metric'] = 5 +# metric['regex'] = 'AUTOTEST Metric : RRC Measurments (RSRP\[0\])=(-?\d+\.?\d*)\s+(.+),\s+(RSRQ\[0\])=(-?\d+\.?\d*)\s+(.+),,\s+(N0)=(-?\d+\.?\d*)\s+(.+),,\s+(NF)=(-?\d+\.?\d*)\s+(.+)\s+\(frame = (\d+)\) ' + metric['regex'] = 'AUTOTEST Metric : RRC Measurments (RSRP\[0\])=(-?\d+\.?\d*)\s+(.+)\,\s+(RSSI)=(-?\d+\.?\d*)\s+(.+)\,\s+(RSRQ\[0\])=(-?\d+\.?\d*)\s+(.+)\,\s+(N0)=(-?\d+\.?\d*)\s+(.+)\,\s+(NF)=(-?\d+\.?\d*)\s+(.+)\s+\(frame = (\d+)\)' metric['unit_of_meas'] = 'kbps' metric['min_limit'] = 14668.8 + #report_path = log_path+'/report/' #os.system(' mkdir -p ' + report_path) @@ -74,58 +90,44 @@ def main(args): #return(0) + test_results = [] + for test_case in test_cases: -# print test_case - if test_case == '030001': - metric['min_limit'] = 500.0 - if test_case == '030901': - metric['min_limit'] = 640.0 - if test_case == '031001': - metric['min_limit'] = 3200.0 - if test_case == '031601': - metric['min_limit'] = 5920.0 - if test_case == '031701': - metric['min_limit'] = 6000.0 - if test_case == '031801': - metric['min_limit'] = 6200.0 - if test_case == '031901': - metric['min_limit'] = 7000.0 - if test_case == '032001': - metric['min_limit'] = 7800.0 - if test_case == '032101': - metric['min_limit'] = 8000.0 - if test_case == '032201': - metric['min_limit'] = 9000.0 - if test_case == '032301': - metric['min_limit'] = 10000.0 - if test_case == '032501': - metric['min_limit'] = 11000.0 - if test_case == '032601': - metric['min_limit'] = 12000.0 - if test_case == '032801': - metric['min_limit'] = 12500.0 - - if test_case == '035201': - metric['min_limit'] = 14668.8 - if test_case == '036001': - metric['min_limit'] = 25363.2 - - - for i in range(0, nb_run): - fname = 'log//'+test_case+'/run_'+str(i)+'/UE_exec_'+str(i)+'_.log' + fname = '..//log//'+test_case+'/run_'+str(i)+'/UE_exec_'+str(i)+'_.log' args = {'metric' : metric, 'file' : fname } - cell_synch_status = analyser.check_cell_synchro(fname) - if cell_synch_status == 'CELL_SYNCH': - print '!!!!!!!!!!!!!! Cell synchronized !!!!!!!!!!!' - metric_checks_flag = 0 - else : - print '!!!!!!!!!!!!!! Cell NOT NOT synchronized !!!!!!!!!!!' + # cell_synch_status = analyser.check_cell_synchro(fname) + # if cell_synch_status == 'CELL_SYNCH': + # print '!!!!!!!!!!!!!! Cell synchronized !!!!!!!!!!!' + # metric_checks_flag = 0 + # else : + # print '!!!!!!!!!!!!!! Cell NOT NOT synchronized !!!!!!!!!!!' -# metric_extracted = analyser.do_extract_metrics(args) +# metrics_extracted = analyser.do_extract_metrics_new(args) + + + # de-xmlfy test report + xml_file = '..//log//'+test_case+'/test.'+test_case+'_ng.xml' + print xml_file + + # test_result = + + + # test_results.append(test_result) + + # xmlFile = logdir_local_testcase + '/test.' + testcasename + '.xml' + # xml="\n \n" + # write_file(xmlFile, xml, mode="w") + + # xmlFile_ng = logdir_local_testcase + '/test.' + testcasename + '_ng.xml' + # xml_ng = xmlify(test_result, wrap=testcasename, indent=" ") + # write_file(xmlFile_ng, xml_ng, mode="w") + + + # print "min = "+ str( metric_extracted['metric_min'] ) # print "min_index = "+ str( metric_extracted['metric_min_index'] ) @@ -143,16 +145,27 @@ def main(args): # print fname # analyser.do_img_metrics(metric, metric_extracted, fname) -# fname = 'log//'+test_case+'/run_'+str(i)+'/UE_traffic_'+str(i)+'_.log' + # fname = 'log//'+test_case+'/run_'+str(i)+'/UE_traffic_'+str(i)+'_.log' -# args = {'file' : fname } + # args = {'file' : fname } -# traffic_metrics = analyser.do_extract_traffic_metrics(args) + # traffic_metrics = analyser.do_extract_traffic_metrics(args) -# fname= 'report/iperf_'+test_case+'_'+str(i)+'.png' + # fname= 'report/iperf_'+test_case+'_'+str(i)+'.png' -# print fname -# analyser.do_img_traffic(traffic_metrics, fname) + # print fname + # analyser.do_img_traffic(traffic_metrics, fname) + + + for test_result in test_results: + cmd = 'mkdir -p ' + report_dir + '/'+ test_result['testcase_name'] + result = os.system(cmd) + + report_file = report_dir + '/'+ test_result['testcase_name'] + '/'+ test_result['testcase_name']+ '_report.html' + + analyser.create_test_report_detailed_html(test_result, report_file ) + + print test_result diff --git a/cmake_targets/autotests/tools/lib_autotest_analyser.py b/cmake_targets/autotests/tools/lib_autotest_analyser.py index 92dcc31e48..333bbd656e 100644 --- a/cmake_targets/autotests/tools/lib_autotest_analyser.py +++ b/cmake_targets/autotests/tools/lib_autotest_analyser.py @@ -41,7 +41,7 @@ from jinja2 import Environment, FileSystemLoader PATH = os.path.dirname(os.path.abspath(__file__)) TEMPLATE_ENVIRONMENT = Environment( autoescape=False, - loader=FileSystemLoader(os.path.join(PATH, 'templates')), + loader=FileSystemLoader(os.path.join(PATH, '../templates')), trim_blocks=False) @@ -103,6 +103,129 @@ def do_extract_metrics(args): } return(ret) + +def do_extract_metrics_new(args): + +# print "" +# print "do_extract_metrics ... " + + fname = args['file'] + metric = args['metric'] + print(fname) + print 'metric id = ' + metric['id'] + print 'metric regex = ' + metric['regex'] + + + + count = 0 + mmin = 0 + mmin_index = 0 + mmax = 0 + mmax_index = 0 + mean = 0 + median = 0 + + toto = [('id', 'S20'), ('metric', np.float), ('frame', np.int)] + print toto + + + np_format = [] + + for x in range(0, metric['nb_metric']): + np_format.append( ('id'+str(x), 'S20') ) + np_format.append( ('metric'+str(x), np.float) ) + np_format.append( ('uom'+str(x), 'S20') ) + np_format.append( ('frame', np.int)) + + print np_format + + output = np.fromregex(fname,metric['regex'], np_format) + print output + count = output['frame'].size + print count + if count > 0: + + + fontP = FontProperties() + fontP.set_size('small') + + fig = plt.figure(1) + plt.figure(figsize=(10,10)) + + plot_xmax = np.amax(output['frame'])+np.amin(output['frame']) + + for x in range(0, metric['nb_metric']): + + metric_name = output['id'+str(x)][0] + metric_uom = output['uom'+str(x)][0] + + mmin = np.amin(output['metric'+str(x)]) + mmax = np.amax(output['metric'+str(x)]) + mmean = np.mean(output['metric'+str(x)]) + mmedian = np.median(output['metric'+str(x)]) + + plot_loc = 100*metric['nb_metric']+10+x+1 + + sbplt = plt.subplot(plot_loc) + sbplt.plot(output['frame'], output['metric'+str(x)], color='b' ) + sbplt.set_title( metric_name+' ('+metric_uom+')') + if mmin < 0: + sbplot_ymin=mmin+mmin/10 + else: + sbplot_ymin=0 + sbplt.set_ylim(ymin=sbplot_ymin) + if mmax > 0: + sbplot_ymax=mmax+mmax/10 + else: + sbplot_ymax=0 + sbplt.set_ylim(ymax=sbplot_ymax) + + sbplt.set_xlim(xmax=plot_xmax) + sbplt.set_xlim(xmin=0) + text='min: '+str(mmin)+'\nmax: '+str(mmax)+'\nmean: '+str(mmean)+'\nmedian: '+str(mmedian) + sbplt.text( plot_xmax+10,sbplot_ymin,text) + sbplt.set_xlabel('frame') + sbplt.set_ylabel(metric_name) + + plt.tight_layout() + + fname = "toto.png" + +# lgd = plt.legend(prop=fontP, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) + mng = plt.get_current_fig_manager() + plt.savefig(fname, bbox_inches='tight') + plt.close() + + + + + + + + + + mmin = np.amin(output['metric']); + mmin_index = np.argmin(output['metric']); + mmax = np.amax(output['metric']); + mmax_index = np.argmax(output['metric']); + mean = np.mean(output['metric']); + median = np.median(output['metric']); + +# print ( ( (metric['min_limit'] > output['metric']).sum() / float(output['metric'].size) ) * 100 ) + + ret = { 'metric_count' : count, + 'metric_buf' : output, + + + 'metric_min' : mmin, + 'metric_min_index' : mmin_index, + 'metric_max' : mmax, + 'metric_max_index' : mmax_index, + 'metric_mean' : mean, + 'metric_median' : median, + } + return(ret) + # # # @@ -182,24 +305,30 @@ def do_img_metrics(metric_def, metric_data, fname): # print output['metric'].size plt.scatter(output['frame'], output['metric'], color='b', alpha=0.33, s = 1 , label=metric_def['id']) - plt.plot([0, output['frame'][metric_data['metric_count']-1]],[ metric_def['min_limit'],metric_def['min_limit']], 'r-', lw=2, label='min limit') # Red straight line + + if 'min_limit' in metric_def: + plt.plot([0, output['frame'][metric_data['metric_count']-1]],[ metric_def['min_limit'],metric_def['min_limit']], 'r-', lw=2, label='min limit') # Red straight line - plt.title('Physical throughput ('+metric_def['unit_of_meas']+')') + plt.title(metric_def['id'] +' ('+metric_def['unit_of_meas']+')') plt.xlabel('frame') plt.ylabel(metric_def['id']) # Set graphic minimum Y axis # ------------------------- - if metric_data['metric_min'] == 0 : - plt.ylim(ymin=-metric_def['min_limit']/10) + if metric_data['metric_min'] < 0: + plt.ylim(ymin=metric_data['metric_min']+metric_data['metric_min']/10) else : plt.ylim(ymin=0) y_axis_max = 0 - if metric_data['metric_max'] > metric_def['min_limit']: - y_axis_max =metric_data['metric_max']+metric_data['metric_max']/10 + if 'min_limit' in metric_def: + if metric_data['metric_max'] > metric_def['min_limit']: + y_axis_max =metric_data['metric_max']+metric_data['metric_max']/10 + else: + y_axis_max =metric_def['min_limit']+metric_def['min_limit']/10 else: - y_axis_max =metric_def['min_limit']+metric_def['min_limit']/10 + y_axis_max =metric_data['metric_max']+metric_data['metric_max']/10 + plt.ylim(ymax=y_axis_max) @@ -219,9 +348,6 @@ def do_img_metrics(metric_def, metric_data, fname): def do_extract_traffic_metrics(args): - print "" - print "do_extract_traffic_metrics ... " - fname = args['file'] # print(fname) @@ -325,7 +451,8 @@ def do_img_traffic(traffic_data, fname): ax1.set_xlim(xmax=np.amax(output['interval_stop'])) text='min: '+str(traffic_data['bw_min'])+'\nmax: '+str(traffic_data['bw_max'])+'\nmean: '+str(traffic_data['bw_mean'])+'\nmedian: '+str(traffic_data['bw_median']) ax1.text( np.amax(output['interval_stop'])+10,0,text) - + ax1.set_xlabel('time (s)') + ax1.set_ylabel(' ') ax2=plt.subplot(312) plt.plot(output['interval_stop'], output['jitter'], color='b' ) @@ -334,6 +461,8 @@ def do_img_traffic(traffic_data, fname): ax2.set_ylim(ymin=-1) text='min: '+str(traffic_data['jitter_min'])+'\nmax: '+str(traffic_data['jitter_max'])+'\nmean: '+str(traffic_data['jitter_mean'])+'\nmedian: '+str(traffic_data['jitter_median']) ax2.text( np.amax(output['interval_stop'])+10,0,text) + ax2.set_xlabel('time (s)') + ax2.set_ylabel(' ') ax3=plt.subplot(313) plt.plot(output['interval_stop'], output['rate_lost'], color='b') @@ -342,10 +471,11 @@ def do_img_traffic(traffic_data, fname): ax3.set_ylim(ymin=-1) text='min: '+str(traffic_data['rl_min'])+'\nmax: '+str(traffic_data['rl_max'])+'\nmean: '+str(traffic_data['rl_mean'])+'\nmedian: '+str(traffic_data['rl_median']) ax3.text( np.amax(output['interval_stop'])+10,0,text) - + ax3.set_xlabel('time (s)') + ax3.set_ylabel(' ') # plt.title('Physical throughput ('+metric_def['unit_of_meas']+')') - plt.xlabel('time (s)') +# plt.xlabel('time (s)') # plt.ylabel(metric_def['id']) # Set graphic minimum Y axis @@ -365,7 +495,7 @@ def do_img_traffic(traffic_data, fname): plt.tight_layout() - lgd = plt.legend(prop=fontP, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) +# lgd = plt.legend(prop=fontP, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) mng = plt.get_current_fig_manager() plt.savefig(fname, bbox_inches='tight') plt.close() @@ -395,7 +525,7 @@ def check_cell_synchro(fname): m = re.search('AUTOTEST Cell Sync \:', line) if m : - print line + #print line return 'CELL_SYNCH' return 'CELL_NOT_SYNCH' @@ -407,7 +537,7 @@ def check_exec_seg_fault(fname): for line in f: m = re.search('Segmentation fault', line) if m : - print line + #print line return 'SEG_FAULT' return 'NO_SEG_FAULT' diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index b77a9baa56..8e3021d0b0 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -53,6 +53,7 @@ BUILD_DOXYGEN=0 T_TRACER="False" DISABLE_HARDWARE_DEPENDENCY="False" CMAKE_BUILD_TYPE="" +UE_AUTOTEST_TRACE="False" trap handle_ctrl_c INT function print_help() { @@ -127,6 +128,8 @@ Options Enables the T tracer. --disable-hardware-dependency Disable HW dependency during installation +--ue-autotest-trace + Enable specific traces for UE autotest framework 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 @@ -278,6 +281,10 @@ function main() { echo_info "Disabling hardware dependency for compiling software" DISABLE_HARDWARE_DEPENDENCY="True" shift 1;; + --ue-autotest-trace) + UE_AUTOTEST_TRACE="True" + echo_info "Enabling autotest specific trace for UE" + shift 1;; -h | --help) print_help exit 1;; @@ -447,6 +454,7 @@ function main() { echo "set (DEADLINE_SCHEDULER \"${DEADLINE_SCHEDULER_FLAG_USER}\" )" >>$cmake_file echo "set (CPU_AFFINITY \"${CPU_AFFINITY_FLAG_USER}\" )" >>$cmake_file echo "set ( T_TRACER $T_TRACER )" >> $cmake_file + echo "set (UE_AUTOTEST_TRACE $UE_AUTOTEST_TRACE)" >> $cmake_file echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file cd $DIR/$lte_build_dir/build cmake .. diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c index 4cdfb4f794..5ae2ec2ecd 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c @@ -486,7 +486,7 @@ void compute_beta8(llr_t* alpha,llr_t* beta,llr_t *m_11,llr_t* m_10,unsigned sho #endif - if (frame_length > 6143) { + if (frame_length > 6144) { LOG_E(PHY,"compute_beta: frame_length %d\n",frame_length); return; } @@ -972,6 +972,11 @@ unsigned char phy_threegpplte_turbo_decoder8(short *y, } else n2 = n; + if(n2<256) + { + printf("phy_threegpplte_turbo_decoder8 : frame length < 256\n"); + return 255; + } for (iind=0; iind < 188 && f1f2mat[iind].nb_bits != n; iind++); diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c index 661fe96be8..782305d2fd 100644 --- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c +++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c @@ -469,6 +469,15 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) //#endif if (ue->UE_scan_carrier == 0) { + + #if UE_AUTOTEST_TRACE + LOG_I(PHY,"[UE %d] AUTOTEST Cell Sync : frame = %d, rx_offset %d, freq_offset %d \n", + ue->Mod_id, + ue->proc.proc_rxtx[0].frame_rx, + ue->rx_offset, + ue->common_vars.freq_offset ); + #endif + if (ue->mac_enabled==1) { LOG_I(PHY,"[UE%d] Sending synch status to higher layers\n",ue->Mod_id); //mac_resynch(); diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 3ed4c79ea3..6023886315 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -2944,6 +2944,13 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin LOG_D(PHY,"[UE %d] Calculating bitrate Frame %d: total_TBS = %d, total_TBS_last = %d, bitrate %f kbits\n", ue->Mod_id,frame_rx,ue->total_TBS[eNB_id], ue->total_TBS_last[eNB_id],(float) ue->bitrate[eNB_id]/1000.0); + + #if UE_AUTOTEST_TRACE + if ((frame_rx % 100 == 0)) { + LOG_I(PHY,"[UE %d] AUTOTEST Metric : UE_DLSCH_BITRATE = %5.2f kbps (frame = %d) \n", ue->Mod_id, (float) ue->bitrate[eNB_id]/1000.0, frame_rx); + } + #endif + } diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 40b9255936..de5be6913c 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1601,6 +1601,11 @@ int main( int argc, char **argv ) PHY_vars_eNB_g[0][CC_id] = init_lte_eNB(frame_parms[CC_id],0,frame_parms[CC_id]->Nid_cell,abstraction_flag); PHY_vars_eNB_g[0][CC_id]->CC_id = CC_id; + PHY_vars_eNB_g[0][CC_id]->ue_dl_rb_alloc=0x1fff; + PHY_vars_eNB_g[0][CC_id]->target_ue_dl_mcs=target_dl_mcs; + PHY_vars_eNB_g[0][CC_id]->ue_ul_nb_rb=6; + PHY_vars_eNB_g[0][CC_id]->target_ue_ul_mcs=target_ul_mcs; + if (phy_test==1) PHY_vars_eNB_g[0][CC_id]->mac_enabled = 0; else PHY_vars_eNB_g[0][CC_id]->mac_enabled = 1; From 85361335e5098fa06044b486251d8d06e382a1f6 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Fri, 18 Nov 2016 13:33:13 -0800 Subject: [PATCH 300/413] frame_length check in compute_beta for LLR8 turbo-decoder --- openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c index 4cdfb4f794..ff7e02a239 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c @@ -486,7 +486,7 @@ void compute_beta8(llr_t* alpha,llr_t* beta,llr_t *m_11,llr_t* m_10,unsigned sho #endif - if (frame_length > 6143) { + if (frame_length > 6144) { LOG_E(PHY,"compute_beta: frame_length %d\n",frame_length); return; } From 9c4cee34f0778222c8fffc75e19f6bccfc9b7150 Mon Sep 17 00:00:00 2001 From: GabrirelCouturier Date: Mon, 21 Nov 2016 11:30:24 +0100 Subject: [PATCH 301/413] [OAI-UE] several fixes in OAI-UE 1- implement max harq retrans 2- bug in harqId > 1 for dci format 1A 3- wrong G computation 4- bug in harq UL for scheduling flag 5- initial sync, limit freq offset to 150Hz --- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 74 ++++++++++++++++--- openair1/PHY/LTE_TRANSPORT/defs.h | 7 +- openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c | 11 ++- openair1/PHY/LTE_TRANSPORT/initial_sync.c | 2 +- openair1/PHY/LTE_TRANSPORT/phich.c | 42 +++++++++-- openair1/PHY/LTE_TRANSPORT/ulsch_coding.c | 15 ++++ openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c | 8 +- openair1/SCHED/phy_procedures_lte_ue.c | 20 ++++- openair2/UTIL/LOG/vcd_signal_dumper.c | 4 + openair2/UTIL/LOG/vcd_signal_dumper.h | 4 + 10 files changed, 161 insertions(+), 26 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index da678088fd..c55290adf8 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -36,7 +36,10 @@ #include "PHY/vars.h" #endif #include "assertions.h" - + +#include "LAYER2/MAC/extern.h" +#include "LAYER2/MAC/defs.h" + //#define DEBUG_DCI uint32_t localRIV2alloc_LUT6[32]; @@ -3922,10 +3925,10 @@ int generate_ue_dlsch_params_from_dci(int frame, dlsch0_harq = dlsch[0]->harq_processes[harq_pid]; } else { - if (harq_pid>1) { - LOG_E(PHY,"Format 1A: harq_pid > 1\n"); - return(-1); - } + //if (harq_pid>1) { + // LOG_E(PHY,"Format 1A: harq_pid > 1\n"); + // return(-1); + //} dlsch0_harq = dlsch[0]->harq_processes[harq_pid]; NPRB = RIV2nb_rb_LUT25[rballoc]; @@ -5552,7 +5555,8 @@ int generate_ue_dlsch_params_from_dci(int frame, #ifdef DEBUG_DCI - if (dlsch[0]) { + if (dlsch[0] && (dlsch[0]->rnti != 0xffff)) { + printf("dci_format:%d \n",dci_format); printf("PDSCH dlsch0 UE: rnti %x\n",dlsch[0]->rnti); printf("PDSCH dlsch0 UE: NBRB %d\n",dlsch0_harq->nb_rb); printf("PDSCH dlsch0 UE: rballoc %x\n",dlsch0_harq->rb_alloc_even[0]); @@ -6396,7 +6400,11 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, if ((rnti >= cba_rnti) && (rnti < p_rnti)) ulsch->harq_processes[harq_pid]->subframe_cba_scheduling_flag = 1; //+=1 this indicates the number of dci / cba group: not supported in the data struct else - ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 1; + { + ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 1; + //LOG_I(PHY,"[HARQ-UL harqId: %d] DCI0 ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag, ulsch->harq_processes[harq_pid]->round); + + } ulsch->harq_processes[harq_pid]->TPC = TPC; @@ -6426,7 +6434,41 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, ulsch->harq_processes[harq_pid]->round = 0; } else { // ulsch->harq_processes[harq_pid]->Ndi = 0; - // ulsch->harq_processes[harq_pid]->round++; // This is done in phich RX + //ulsch->harq_processes[harq_pid]->round++; // This is done in phich RX + + //#ifdef DEBUG_PHICH + //LOG_I(PHY,"[UE %d][PUSCH %d] Frame %d subframe %d Adaptative Retrans, NDI not toggled => Nack. maxHARQ_Tx %d \n", + // ue->Mod_id,harq_pid, + // proc->frame_rx, + // subframe, + // UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx); + //#endif + + + ulsch->harq_processes[harq_pid] = ulsch->harq_processes[8]; + ulsch->harq_processes[harq_pid]->round++; + //LOG_I(PHY," Adaptative retransmission - copy temporary harq Process to current harq process. [harqId %d round %d] \n",harq_pid, ulsch->harq_processes[8]->round); + + + if (ulsch->harq_processes[harq_pid]->round >= UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx) + { + ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 0; + ulsch->harq_processes[harq_pid]->round = 0; + ulsch->harq_processes[harq_pid]->status = IDLE; + //LOG_I(PHY," PUSCH MAX Retransmission acheived ==> flush harq buff (%d) \n",harq_pid); + //LOG_I(PHY," [HARQ-UL harqId: %d] Adaptative retransmission NACK MAX RETRANS(%d) ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag, ulsch->harq_processes[harq_pid]->round); + } + else + { + // ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 1; + uint8_t rv_table[4] = {0, 2, 3, 1}; + ulsch->harq_processes[harq_pid]->rvidx = rv_table[ulsch->harq_processes[harq_pid]->round&3]; + ulsch->O_RI = 0; + ulsch->O = 0; + ulsch->uci_format = HLC_subband_cqi_nopmi; + //LOG_I(PHY," [HARQ-UL harqId: %d] Adaptative retransmission NACK ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag,ulsch->harq_processes[harq_pid]->round); + } + } } @@ -6476,7 +6518,16 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, if (cqi_req == 1) { - ulsch->O_RI = 1; //we only support 2 antenna ports, so this is always 1 according to 3GPP 36.213 Table + + if( (AntennaInfoDedicated__transmissionMode_tm3 == transmission_mode) || (AntennaInfoDedicated__transmissionMode_tm4 == transmission_mode) ) + { + ulsch->O_RI = 1; + } + else + { + ulsch->O_RI = 0; + } + //ulsch->O_RI = 0; //we only support 2 antenna ports, so this is always 1 according to 3GPP 36.213 Table switch(transmission_mode) { // The aperiodic CQI reporting mode is fixed for every transmission mode instead of being configured by higher layer signaling @@ -7039,12 +7090,15 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, #ifdef DEBUG_DCI printf("Format 0 DCI : ulsch (ue): NBRB %d\n",ulsch->harq_processes[harq_pid]->nb_rb); printf("Format 0 DCI :ulsch (ue): first_rb %d\n",ulsch->harq_processes[harq_pid]->first_rb); + printf("Format 0 DCI :ulsch (ue): rballoc %d\n",rballoc); printf("Format 0 DCI :ulsch (ue): harq_pid %d\n",harq_pid); + printf("Format 0 DCI :ulsch (ue): first_tx %d\n",ulsch->harq_processes[harq_pid]->first_tx); + printf("Format 0 DCI :ulsch (ue): DCINdi %d\n",ulsch->harq_processes[harq_pid]->DCINdi); printf("Format 0 DCI :ulsch (ue): round %d\n",ulsch->harq_processes[harq_pid]->round); printf("Format 0 DCI :ulsch (ue): TBS %d\n",ulsch->harq_processes[harq_pid]->TBS); printf("Format 0 DCI :ulsch (ue): mcs %d\n",ulsch->harq_processes[harq_pid]->mcs); printf("Format 0 DCI :ulsch (ue): O %d\n",ulsch->O); - + printf("Format 0 DCI :ulsch (ue): cqiReq %d\n",cqi_req); if (frame_parms->frame_type == TDD) printf("Format 0 DCI :ulsch (ue): O_ACK/DAI %d/%d\n",ulsch->harq_processes[harq_pid]->O_ACK,dai); else diff --git a/openair1/PHY/LTE_TRANSPORT/defs.h b/openair1/PHY/LTE_TRANSPORT/defs.h index 026ba40340..f8d36d3bd4 100644 --- a/openair1/PHY/LTE_TRANSPORT/defs.h +++ b/openair1/PHY/LTE_TRANSPORT/defs.h @@ -227,6 +227,11 @@ typedef struct { uint8_t control_only; /// Flag to indicate that this is a calibration ULSCH (i.e. no MAC SDU and filled with TDD calibration information) // int calibration_flag; + /// Number of soft channel bits + uint32_t G; + + // decode phich + uint8_t decode_phich; } LTE_UL_UE_HARQ_t; typedef struct { @@ -278,7 +283,7 @@ typedef struct { /// SRS active flag uint8_t srs_active; /// Pointers to 8 HARQ processes for the ULSCH - LTE_UL_UE_HARQ_t *harq_processes[8]; + LTE_UL_UE_HARQ_t *harq_processes[9]; /// Pointer to CQI data uint8_t o[MAX_CQI_BYTES]; /// Length of CQI data (bits) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c index c7cd5ab52f..4a80110b22 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_decoding.c @@ -619,7 +619,11 @@ uint32_t dlsch_decoding(PHY_VARS_UE *phy_vars_ue, harq_process->errors[harq_process->round]++; harq_process->round++; - // LOG_D(PHY,"[UE %d] DLSCH: Setting NACK for subframe %d (pid %d, round %d)\n",phy_vars_ue->Mod_id,subframe,harq_pid,harq_process->round); + + if(is_crnti) + { + LOG_D(PHY,"[UE %d] DLSCH: Setting NACK for subframe %d (pid %d, round %d, TBS %d)\n",phy_vars_ue->Mod_id,subframe,harq_pid,harq_process->round,harq_process->TBS); + } // printf("Rate: [UE %d] DLSCH: Setting NACK for subframe %d (pid %d, round %d)\n",phy_vars_ue->Mod_id,subframe,harq_pid,harq_process->round); if (harq_process->round >= dlsch->Mdlharq) { harq_process->status = SCH_IDLE; @@ -632,7 +636,10 @@ uint32_t dlsch_decoding(PHY_VARS_UE *phy_vars_ue, dlsch->harq_ack[subframe].ack = 1; dlsch->harq_ack[subframe].harq_id = harq_pid; dlsch->harq_ack[subframe].send_harq_status = 1; - LOG_D(PHY,"[UE %d] DLSCH: Setting ACK for subframe %d (pid %d, round %d)\n",phy_vars_ue->Mod_id,subframe,harq_pid,harq_process->round); + if(is_crnti) + { + LOG_D(PHY,"[UE %d] DLSCH: Setting ACK for subframe %d (pid %d, round %d, TBS %d)\n",phy_vars_ue->Mod_id,subframe,harq_pid,harq_process->round,harq_process->TBS); + } } diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c index 91374078c0..663978e92c 100644 --- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c +++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c @@ -463,7 +463,7 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) } /* Consider this is a false detection if the offset is > 1000 Hz */ - if( (abs(ue->common_vars.freq_offset) > 1000) && (ret == 0) ) + if( (abs(ue->common_vars.freq_offset) > 150) && (ret == 0) ) { ret=-1; LOG_E(HW,"Ignore MIB with high freq offset [%d Hz] estimation \n",ue->common_vars.freq_offset); diff --git a/openair1/PHY/LTE_TRANSPORT/phich.c b/openair1/PHY/LTE_TRANSPORT/phich.c index 6b66ee0282..dc46f0505c 100644 --- a/openair1/PHY/LTE_TRANSPORT/phich.c +++ b/openair1/PHY/LTE_TRANSPORT/phich.c @@ -34,6 +34,10 @@ #include "PHY/extern.h" #include "SCHED/defs.h" #include "defs.h" + +#include "LAYER2/MAC/extern.h" +#include "LAYER2/MAC/defs.h" + #ifndef USER_MODE #include "ARCH/CBMIMO1/DEVICE_DRIVER/extern.h" #endif @@ -1375,15 +1379,30 @@ void rx_phich(PHY_VARS_UE *ue, subframe, HI16, nseq_PHICH, - ngroup_PHICH); + ngroup_PHICH, + UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx); //#endif - ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 1; + // ulsch->harq_processes[harq_pid]->Ndi = 0; ulsch->harq_processes[harq_pid]->round++; - ulsch->harq_processes[harq_pid]->rvidx = rv_table[ulsch->harq_processes[harq_pid]->round&3]; - ulsch->O_RI = 0; - ulsch->O = 0; - ulsch->uci_format = HLC_subband_cqi_nopmi; + + if (ulsch->harq_processes[harq_pid]->round >= UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx) + { + ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 0; + ulsch->harq_processes[harq_pid]->round = 0; + ulsch->harq_processes[harq_pid]->status = IDLE; + //LOG_I(PHY,"PUSCH MAX Retransmission acheived ==> flush harq buff (%d) \n",harq_pid); + //LOG_I(PHY,"[HARQ-UL harqId: %d] PHICH NACK MAX RETRANS(%d) ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag, ulsch->harq_processes[harq_pid]->round); + } + else + { + // ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 1; + ulsch->harq_processes[harq_pid]->rvidx = rv_table[ulsch->harq_processes[harq_pid]->round&3]; + ulsch->O_RI = 0; + ulsch->O = 0; + ulsch->uci_format = HLC_subband_cqi_nopmi; + //LOG_I(PHY,"[HARQ-UL harqId: %d] PHICH NACK ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag,ulsch->harq_processes[harq_pid]->round); + } } @@ -1405,11 +1424,22 @@ void rx_phich(PHY_VARS_UE *ue, //#endif } + // LOG_I(PHY,"[HARQ-UL harqId: %d] subframe_scheduling_flag = %d \n",harq_pid, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag); + + // Incase of adaptive retransmission, PHICH is always decoded as ACK (at least with OAI-eNB) + // Workaround: + // rely only on DCI0 decoding and check if NDI has toggled + // save current harq_processes content in temporary struct + // harqId-8 corresponds to the temporary struct. In total we have 8 harq process(0 ..7) + 1 temporary harq process() + ulsch->harq_processes[8] = ulsch->harq_processes[harq_pid]; + ulsch->harq_processes[harq_pid]->subframe_scheduling_flag =0; ulsch->harq_processes[harq_pid]->status = IDLE; ulsch->harq_processes[harq_pid]->round = 0; // inform MAC? ue->ulsch_Msg3_active[eNB_id] = 0; + + //LOG_I(PHY,"[HARQ-UL harqId: %d] PHICH ACK ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag, ulsch->harq_processes[harq_pid]->round); } } diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c index 53eaa849fd..48048bf5de 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c @@ -498,6 +498,21 @@ uint32_t ulsch_encoding(uint8_t *a, G = G - Q_RI - Q_CQI; + ulsch->harq_processes[harq_pid]->G = G; + +/* + LOG_I(PHY,"ULSCH Encoding G %d, Q_RI %d (O_RI%d, Msc_initial %d, Nsymb_initial%d, beta_offset_ri_times8 %d), Q_CQI %d \n",G,Q_RI,ulsch->O_RI,ulsch->harq_processes[harq_pid]->Msc_initial,ulsch->harq_processes[harq_pid]->Nsymb_initial,ulsch->beta_offset_ri_times8,Q_CQI); + + LOG_I(PHY,"ulsch_decoding (Nid_cell %d, rnti %x): harq_pid %d round %d, RV %d, mcs %d, O_RI %d, O_ACK %d, G %d\n", + frame_parms->Nid_cell,ulsch->rnti, + harq_pid, + ulsch->harq_processes[harq_pid]->round, + ulsch->harq_processes[harq_pid]->rvidx, + ulsch->harq_processes[harq_pid]->mcs, + ulsch->O_RI, + ulsch->harq_processes[harq_pid]->O_ACK, + G); +*/ if ((int)G < 0) { LOG_E(PHY,"FATAL: ulsch_coding.c G < 0 (%d) : Q_RI %d, Q_CQI %d, O %d, betaCQI_times8 %d)\n",G,Q_RI,Q_CQI,ulsch->O,ulsch->beta_offset_cqi_times8); diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c index 80168dd3c5..02323d6ccd 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c @@ -424,15 +424,17 @@ void ulsch_modulation(int32_t **txdataF, Q_m = get_Qm_ul(ulsch->harq_processes[harq_pid]->mcs); - G = (int)ulsch->harq_processes[harq_pid]->nb_rb * (12 * Q_m) * (ulsch->Nsymb_pusch); + //G = (int)ulsch->harq_processes[harq_pid]->nb_rb * (12 * Q_m) * (ulsch->Nsymb_pusch); + + G = ulsch->harq_processes[harq_pid]->G; // Mapping nsymb = (frame_parms->Ncp==0) ? 14:12; Msc_PUSCH = ulsch->harq_processes[harq_pid]->nb_rb*12; #ifdef DEBUG_ULSCH_MODULATION - printf("ulsch_modulation.c: Doing modulation (rnti %x,x2 %x) for G=%d bits, harq_pid %d , nb_rb %d, Q_m %d, Nsymb_pusch %d (nsymb %d), subframe %d\n", - ulsch->rnti,x2,G,harq_pid,ulsch->harq_processes[harq_pid]->nb_rb,Q_m, ulsch->Nsymb_pusch,nsymb,subframe); + LOG_D(PHY,"ulsch_modulation.c: Doing modulation (rnti %x,x2 %x) for G=%d bits, harq_pid %d , nb_rb %d, Q_m %d, Nsymb_pusch %d (nsymb %d), subframe %d\n", + ulsch->rnti,x2,G,harq_pid,ulsch->harq_processes[harq_pid]->nb_rb,Q_m, ulsch->Nsymb_pusch,nsymb,subframe); #endif // scrambling (Note the placeholding bits are handled in ulsch_coding.c directly!) diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 55e7686462..92eee4a99d 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -1213,7 +1213,7 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB ue->generate_ul_signal[eNB_id] = 1; // deactivate service request - ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 0; + // ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 0; ack_status = get_ack(&ue->frame_parms, ue->dlsch[eNB_id][0]->harq_ack, @@ -3089,22 +3089,27 @@ void ue_dlsch_procedures(PHY_VARS_UE *ue, if (ret == (1+dlsch0->max_turbo_iterations)) { *dlsch_errors=*dlsch_errors+1; - + if(dlsch0->rnti != 0xffff) + { LOG_D(PHY,"[UE %d][PDSCH %x/%d] Frame %d subframe %d DLSCH in error (rv %d,mcs %d,TBS %d)\n", ue->Mod_id,dlsch0->rnti, harq_pid,frame_rx,subframe_rx, dlsch0->harq_processes[harq_pid]->rvidx, dlsch0->harq_processes[harq_pid]->mcs, dlsch0->harq_processes[harq_pid]->TBS); + } } else { + if(dlsch0->rnti != 0xffff) + { LOG_D(PHY,"[UE %d][PDSCH %x/%d] Frame %d subframe %d: Received DLSCH (rv %d,mcs %d,TBS %d)\n", ue->Mod_id,dlsch0->rnti, harq_pid,frame_rx,subframe_rx, dlsch0->harq_processes[harq_pid]->rvidx, dlsch0->harq_processes[harq_pid]->mcs, dlsch0->harq_processes[harq_pid]->TBS); + } #ifdef DEBUG_DLSCH int j; @@ -3293,6 +3298,7 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin // do procedures for C-RNTI if (ue->dlsch[eNB_id][0]->active == 1) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN); ue_pdsch_procedures(ue, proc, eNB_id, @@ -3302,9 +3308,11 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin ue->pdcch_vars[eNB_id]->num_pdcch_symbols, ue->frame_parms.symbols_per_tti>>1, abstraction_flag); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_OUT); } // do procedures for SI-RNTI if ((ue->dlsch_SI[eNB_id]) && (ue->dlsch_SI[eNB_id]->active == 1)) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_SI, VCD_FUNCTION_IN); ue_pdsch_procedures(ue, proc, eNB_id, @@ -3314,10 +3322,12 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin ue->pdcch_vars[eNB_id]->num_pdcch_symbols, ue->frame_parms.symbols_per_tti>>1, abstraction_flag); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_SI, VCD_FUNCTION_OUT); } // do procedures for SI-RNTI if ((ue->dlsch_p[eNB_id]) && (ue->dlsch_p[eNB_id]->active == 1)) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_P, VCD_FUNCTION_IN); ue_pdsch_procedures(ue, proc, eNB_id, @@ -3327,10 +3337,12 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin ue->pdcch_vars[eNB_id]->num_pdcch_symbols, ue->frame_parms.symbols_per_tti>>1, abstraction_flag); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_P, VCD_FUNCTION_OUT); } // do procedures for RA-RNTI if ((ue->dlsch_ra[eNB_id]) && (ue->dlsch_ra[eNB_id]->active == 1)) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_RA, VCD_FUNCTION_IN); ue_pdsch_procedures(ue, proc, eNB_id, @@ -3340,6 +3352,7 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin ue->pdcch_vars[eNB_id]->num_pdcch_symbols, ue->frame_parms.symbols_per_tti>>1, abstraction_flag); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_RA, VCD_FUNCTION_OUT); } if (subframe_select(&ue->frame_parms,subframe_rx) != SF_S) { // do front-end processing for second slot, and first symbol of next subframe @@ -3375,6 +3388,7 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin // do procedures for C-RNTI if (ue->dlsch[eNB_id][0]->active == 1) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN); ue_pdsch_procedures(ue, proc, eNB_id, @@ -3393,7 +3407,7 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin &ue->dlsch_errors[eNB_id], mode, abstraction_flag); - + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_OUT); } else { diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.c b/openair2/UTIL/LOG/vcd_signal_dumper.c index 226f8f0754..d367ec7766 100644 --- a/openair2/UTIL/LOG/vcd_signal_dumper.c +++ b/openair2/UTIL/LOG/vcd_signal_dumper.c @@ -240,6 +240,10 @@ const char* eurecomFunctionsNames[] = { "rx_pdcch", "dci_decoding", "rx_phich", + "pdsch_procedures", + "pdsch_procedures_si", + "pdsch_procedures_p", + "pdsch_procedures_ra", "phy_ue_config_sib2", "macxface_phy_config_sib1_eNB", "macxface_phy_config_sib2_eNB", diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.h b/openair2/UTIL/LOG/vcd_signal_dumper.h index 81a5fb083d..1e03e95002 100644 --- a/openair2/UTIL/LOG/vcd_signal_dumper.h +++ b/openair2/UTIL/LOG/vcd_signal_dumper.h @@ -214,6 +214,10 @@ typedef enum { VCD_SIGNAL_DUMPER_FUNCTIONS_RX_PDCCH, VCD_SIGNAL_DUMPER_FUNCTIONS_DCI_DECODING, VCD_SIGNAL_DUMPER_FUNCTIONS_RX_PHICH, + VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, + VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_SI, + VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_P, + VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_RA, VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_CONFIG_SIB2, VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_CONFIG_SIB1_ENB, VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_CONFIG_SIB2_ENB, From e86b3e31c79bcc489b67f55e3cbadd035e706fbf Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Mon, 26 Sep 2016 14:51:52 +0200 Subject: [PATCH 302/413] changing some config files --- .../CONF/enb.band4.exmimo2.conf | 147 ++++++++++++++++++ .../CONF/enb.band7.usrpb210.conf | 2 +- 2 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band4.exmimo2.conf diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band4.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band4.exmimo2.conf new file mode 100644 index 0000000000..bf7861f66d --- /dev/null +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band4.exmimo2.conf @@ -0,0 +1,147 @@ +Active_eNBs = ( "eNB_Eurecom_LTEBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +eNBs = +( + { + # real_time choice in {hard, rt-preempt, no} + real_time = "no"; + ////////// Identification parameters: + eNB_ID = 0xe00; + + cell_type = "CELL_MACRO_ENB"; + + eNB_name = "eNB_Eurecom_LTEBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = "1"; + + mobile_country_code = "208"; + + mobile_network_code = "94"; + + ////////// Physical parameters: + + component_carriers = ( + { + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 4; + downlink_frequency = 2112500000L; + uplink_frequency_offset = -400000000; + + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + nb_antenna_ports = 1; + tx_gain = 20; + rx_gain = 20; + prach_root = 22; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = -25; + pdsch_p_b = 0; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 1; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 0; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ + + pusch_p0_Nominal = -85; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -96; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; + + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; +/* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; +*/ + rach_powerRampingStep = 2; + rach_preambleInitialReceivedTargetPower = -100; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; + + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 20000; //10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + + ue_TransmissionMode = 1; + + } + ); + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.12.70"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.212/24"; + + ENB_INTERFACE_NAME_FOR_S1U = "eth0"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.212/24"; + ENB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="high"; + hw_log_level ="info"; + hw_log_verbosity ="high"; + phy_log_level ="info"; + phy_log_verbosity ="high"; + mac_log_level ="debug"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="high"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="high"; + rrc_log_level ="info"; + rrc_log_verbosity ="high"; + }; + + } +); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.usrpb210.conf index 7941441d1d..1fe3beae0e 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.usrpb210.conf @@ -135,7 +135,7 @@ eNBs = }; ////////// MME parameters: - mme_ip_address = ( { ipv4 = "192.168.12.171"; + mme_ip_address = ( { ipv4 = "192.168.12.70"; ipv6 = "192:168:30::17"; active = "yes"; preference = "ipv4"; From 5c5c336300924ed66beb6b4946117314ee8a4b64 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Mon, 21 Nov 2016 11:55:36 +0100 Subject: [PATCH 303/413] fixes to make lte-softmodem compile again --- targets/ARCH/EXMIMO/DEFS/openair_device.h | 6 +- .../ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c | 8 +- targets/RT/USER/lte-enb.c | 98 +++++++++---------- targets/RT/USER/lte-softmodem.c | 8 +- 4 files changed, 59 insertions(+), 61 deletions(-) diff --git a/targets/ARCH/EXMIMO/DEFS/openair_device.h b/targets/ARCH/EXMIMO/DEFS/openair_device.h index 6c1c8708db..b4916490e2 100644 --- a/targets/ARCH/EXMIMO/DEFS/openair_device.h +++ b/targets/ARCH/EXMIMO/DEFS/openair_device.h @@ -24,9 +24,9 @@ // Maximum number of concurrently supported cards -// -#define MAX_CARDS 16 -#define INIT_ZEROS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +// defined in openair_common_lib.h +//#define MAX_CARDS 16 +//#define INIT_ZEROS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /** PCIe subsystem configuration Space diff --git a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c index 2d0146b3f1..4db108b3c8 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c +++ b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c @@ -63,7 +63,7 @@ exmimo_pci_interface_bot_virtual_t openair0_exmimo_pci[MAX_CARDS]; // contains userspace pointers for each card -char *bigshm_top[MAX_CARDS] = INIT_ZEROS; +char *bigshm_top[MAX_CARDS]; int openair0_fd; int openair0_num_antennas[MAX_CARDS]; @@ -126,7 +126,8 @@ int openair0_open(void) //printf("bigshm_top_kvirtptr (MAX_CARDS %d): %p %p %p %p\n", MAX_CARDS,bigshm_top_kvirtptr[0], bigshm_top_kvirtptr[1], bigshm_top_kvirtptr[2], bigshm_top_kvirtptr[3]); - + for( card=0; card < MAX_CARDS; card++) + bigshm_top[card] = NULL; for( card=0; card < openair0_num_detected_cards; card++) { bigshm_top[card] = (char *)mmap( NULL, @@ -530,6 +531,7 @@ int trx_exmimo_read(openair0_device *device, openair0_timestamp *ptimestamp, voi return(0); } + ret = pthread_mutex_lock(&exm->watchdog_mutex); switch (ret) { case EINVAL: @@ -558,8 +560,6 @@ int trx_exmimo_read(openair0_device *device, openair0_timestamp *ptimestamp, voi break; } - ret = pthread_mutex_lock(&exm->watchdog_mutex); - ts = exm->ts; if (exm->wait_first_read==1) { exm->wait_first_read=0; diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index af06979efd..965894cac0 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -277,75 +277,73 @@ static inline void wait_sync(char *thread_name) { void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB) { - unsigned int aa,slot_offset, slot_offset_F; - int dummy_tx_b[7680*4] __attribute__((aligned(32))); + unsigned int aa,slot_offset; + //int dummy_tx_b[7680*4] __attribute__((aligned(32))); int i, tx_offset; - int slot_sizeF = (phy_vars_eNB->lte_frame_parms.ofdm_symbol_size)* - ((phy_vars_eNB->lte_frame_parms.Ncp==1) ? 6 : 7); + //int slot_sizeF = (phy_vars_eNB->frame_parms.ofdm_symbol_size)* ((phy_vars_eNB->frame_parms.Ncp==1) ? 6 : 7); int len; + //int slot_offset_F = (subframe<<1)*slot_sizeF; - slot_offset_F = (subframe<<1)*slot_sizeF; - - slot_offset = subframe*phy_vars_eNB->lte_frame_parms.samples_per_tti; + slot_offset = subframe*phy_vars_eNB->frame_parms.samples_per_tti; - if ((subframe_select(&phy_vars_eNB->lte_frame_parms,subframe)==SF_DL)|| - ((subframe_select(&phy_vars_eNB->lte_frame_parms,subframe)==SF_S))) { + if ((subframe_select(&phy_vars_eNB->frame_parms,subframe)==SF_DL)|| + ((subframe_select(&phy_vars_eNB->frame_parms,subframe)==SF_S))) { // LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_OFDM_MODULATION,1); - do_OFDM_mod_symbol(&phy_vars_eNB->lte_eNB_common_vars, + do_OFDM_mod_symbol(&phy_vars_eNB->common_vars, 0, subframe<<1, - &phy_vars_eNB->lte_frame_parms); + &phy_vars_eNB->frame_parms); // if S-subframe generate first slot only - if (subframe_select(&phy_vars_eNB->lte_frame_parms,subframe) == SF_DL) { - do_OFDM_mod_symbol(&phy_vars_eNB->lte_eNB_common_vars, + if (subframe_select(&phy_vars_eNB->frame_parms,subframe) == SF_DL) { + do_OFDM_mod_symbol(&phy_vars_eNB->common_vars, 0, 1+(subframe<<1), - &phy_vars_eNB->lte_frame_parms); + &phy_vars_eNB->frame_parms); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_OFDM_MODULATION,0); /* - for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { - if (phy_vars_eNB->lte_frame_parms.Ncp == EXTENDED) { - PHY_ofdm_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F], + for (aa=0; aaframe_parms.nb_antennas_tx; aa++) { + if (phy_vars_eNB->frame_parms.Ncp == EXTENDED) { + PHY_ofdm_mod(&phy_vars_eNB->common_vars.txdataF[0][aa][slot_offset_F], dummy_tx_b, - phy_vars_eNB->lte_frame_parms.ofdm_symbol_size, + phy_vars_eNB->frame_parms.ofdm_symbol_size, 6, - phy_vars_eNB->lte_frame_parms.nb_prefix_samples, + phy_vars_eNB->frame_parms.nb_prefix_samples, CYCLIC_PREFIX); - PHY_ofdm_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F+slot_sizeF], - dummy_tx_b+(phy_vars_eNB->lte_frame_parms.samples_per_tti>>1), - phy_vars_eNB->lte_frame_parms.ofdm_symbol_size, + PHY_ofdm_mod(&phy_vars_eNB->common_vars.txdataF[0][aa][slot_offset_F+slot_sizeF], + dummy_tx_b+(phy_vars_eNB->frame_parms.samples_per_tti>>1), + phy_vars_eNB->frame_parms.ofdm_symbol_size, 6, - phy_vars_eNB->lte_frame_parms.nb_prefix_samples, + phy_vars_eNB->frame_parms.nb_prefix_samples, CYCLIC_PREFIX); } else { - normal_prefix_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F], + normal_prefix_mod(&phy_vars_eNB->common_vars.txdataF[0][aa][slot_offset_F], dummy_tx_b, 7, - &(phy_vars_eNB->lte_frame_parms)); + &(phy_vars_eNB->frame_parms)); // if S-subframe generate first slot only - if (subframe_select(&phy_vars_eNB->lte_frame_parms,subframe) == SF_DL) - normal_prefix_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F+slot_sizeF], - dummy_tx_b+(phy_vars_eNB->lte_frame_parms.samples_per_tti>>1), + if (subframe_select(&phy_vars_eNB->frame_parms,subframe) == SF_DL) + normal_prefix_mod(&phy_vars_eNB->common_vars.txdataF[0][aa][slot_offset_F+slot_sizeF], + dummy_tx_b+(phy_vars_eNB->frame_parms.samples_per_tti>>1), 7, - &(phy_vars_eNB->lte_frame_parms)); + &(phy_vars_eNB->frame_parms)); } } */ - for (aa=0; aalte_frame_parms.nb_antennas_tx; aa++) { + for (aa=0; aaframe_parms.nb_antennas_tx; aa++) { // if S-subframe generate first slot only - if (subframe_select(&phy_vars_eNB->lte_frame_parms,subframe) == SF_S) - len = phy_vars_eNB->lte_frame_parms.samples_per_tti>>1; + if (subframe_select(&phy_vars_eNB->frame_parms,subframe) == SF_S) + len = phy_vars_eNB->frame_parms.samples_per_tti>>1; else - len = phy_vars_eNB->lte_frame_parms.samples_per_tti; + len = phy_vars_eNB->frame_parms.samples_per_tti; /* for (i=0;ilte_frame_parms.samples_per_tti; + tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti; - if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti)) - tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti; + if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti)) + tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti; -/* ((short*)&phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset])[0] = ((short*)dummy_tx_b)[2*i]<common_vars.txdata[0][aa][tx_offset])[0] = ((short*)dummy_tx_b)[2*i]<lte_eNB_common_vars.txdata[0][aa][tx_offset])[1] = ((short*)dummy_tx_b)[2*i+1]<common_vars.txdata[0][aa][tx_offset])[1] = ((short*)dummy_tx_b)[2*i+1]<lte_eNB_common_vars.txdata[0][aa][tx_offset])[0] = ((short*)&phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset])[0]<common_vars.txdata[0][aa][tx_offset])[0] = ((short*)&phy_vars_eNB->common_vars.txdata[0][aa][tx_offset])[0]<lte_eNB_common_vars.txdata[0][aa][tx_offset])[1] = ((short*)&phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset])[1]<common_vars.txdata[0][aa][tx_offset])[1] = ((short*)&phy_vars_eNB->common_vars.txdata[0][aa][tx_offset])[1]<lte_frame_parms,subframe) == SF_S) { + if (subframe_select(&phy_vars_eNB->frame_parms,subframe) == SF_S) { for (i=0; ilte_eNB_common_vars.txdata[0][aa][tx_offset++] = 0x00010001; + phy_vars_eNB->common_vars.txdata[0][aa][tx_offset++] = 0x00010001; } } - if ((((phy_vars_eNB->lte_frame_parms.tdd_config==0) || - (phy_vars_eNB->lte_frame_parms.tdd_config==1) || - (phy_vars_eNB->lte_frame_parms.tdd_config==2) || - (phy_vars_eNB->lte_frame_parms.tdd_config==6)) && + if ((((phy_vars_eNB->frame_parms.tdd_config==0) || + (phy_vars_eNB->frame_parms.tdd_config==1) || + (phy_vars_eNB->frame_parms.tdd_config==2) || + (phy_vars_eNB->frame_parms.tdd_config==6)) && (subframe==0)) || (subframe==5)) { // turn on tx switch N_TA_offset before //LOG_D(HW,"subframe %d, time to switch to tx (N_TA_offset %d, slot_offset %d) \n",subframe,phy_vars_eNB->N_TA_offset,slot_offset); for (i=0; iN_TA_offset; i++) { tx_offset = (int)slot_offset+time_offset[aa]+i-phy_vars_eNB->N_TA_offset/2; if (tx_offset<0) - tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti; + tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti; - if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti)) - tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti; + if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti)) + tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti; - phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset] = 0x00000000; + phy_vars_eNB->common_vars.txdata[0][aa][tx_offset] = 0x00000000; } } } diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 40b9255936..0cca7b6379 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1121,13 +1121,13 @@ static void get_options (int argc, char **argv) frame_parms[CC_id]->N_RB_DL = enb_properties->properties[i]->N_RB_DL[CC_id]; frame_parms[CC_id]->N_RB_UL = enb_properties->properties[i]->N_RB_DL[CC_id]; frame_parms[CC_id]->nb_antennas_tx = enb_properties->properties[i]->nb_antennas_tx[CC_id]; - frame_parms[CC_id]->nb_antennas_tx_eNB = enb_properties->properties[i]->nb_antenna_ports[CC_id]; + frame_parms[CC_id]->nb_antenna_ports_eNB = enb_properties->properties[i]->nb_antenna_ports[CC_id]; frame_parms[CC_id]->nb_antennas_rx = enb_properties->properties[i]->nb_antennas_rx[CC_id]; frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex = enb_properties->properties[i]->prach_config_index[CC_id]; frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset = enb_properties->properties[i]->prach_freq_offset[CC_id]; - frame_parms[CC_id]->mode1_flag = (frame_parms[CC_id]->nb_antennas_tx_eNB == 1) ? 1 : 0; + frame_parms[CC_id]->mode1_flag = (frame_parms[CC_id]->nb_antenna_ports_eNB == 1) ? 1 : 0; frame_parms[CC_id]->threequarter_fs = threequarter_fs; //} // j @@ -1225,7 +1225,7 @@ void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { frame_parms[CC_id]->Ncp_UL = NORMAL; frame_parms[CC_id]->Nid_cell = 0; frame_parms[CC_id]->num_MBSFN_config = 0; - frame_parms[CC_id]->nb_antennas_tx_eNB = 1; + frame_parms[CC_id]->nb_antenna_ports_eNB = 1; frame_parms[CC_id]->nb_antennas_tx = 1; frame_parms[CC_id]->nb_antennas_rx = 1; @@ -1524,7 +1524,7 @@ int main( int argc, char **argv ) if (UE_flag==1) { frame_parms[CC_id]->nb_antennas_tx = 1; frame_parms[CC_id]->nb_antennas_rx = 1; - frame_parms[CC_id]->nb_antennas_tx_eNB = 1; //initial value overwritten by initial sync later + frame_parms[CC_id]->nb_antenna_ports_eNB = 1; //initial value overwritten by initial sync later } init_ul_hopping(frame_parms[CC_id]); From 040afd4800c4e0e401ab9743a1c5612c65c5bf46 Mon Sep 17 00:00:00 2001 From: ROBERT Benoit Date: Mon, 21 Nov 2016 16:02:00 +0100 Subject: [PATCH 304/413] Add missing template files for HTML report generation --- cmake_targets/autotests/templates/index.html | 87 +++++++++++ .../autotests/templates/testcase_report.html | 142 ++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 cmake_targets/autotests/templates/index.html create mode 100644 cmake_targets/autotests/templates/testcase_report.html diff --git a/cmake_targets/autotests/templates/index.html b/cmake_targets/autotests/templates/index.html new file mode 100644 index 0000000000..10a15fb53d --- /dev/null +++ b/cmake_targets/autotests/templates/index.html @@ -0,0 +1,87 @@ + + + + + OAI5G UE Autotest Report + + + + +

+

OAI5G UE Autotest Report

+
+ +

+ + + + + + + + +
Test session configuration
Start time{{test_session_start_time}}
Stop time{{test_session_stop_time}}
Duration{{test_session_duration}}
MTC host{{mtc_host}}
User{{user}}
Password{{password}}
+

+ + +

Test Setup

+To be complete + +

+

UE phy-test performances tests results

+

Objectives

+

Checks that OAI UE can achieve at least 75 percent of the theoretical throughput.

+

Tests are done for all MCS (0 to 28) for 5MHz and 10MHz bandwidth.

+

Results

+ + + +{% for result in test_results|sort(attribute='testcase_name') %} + + + + {% if result.testcase_verdict == "PASS" %} + + {% elif result.testcase_verdict == "FAIL" %} + + {% else %} + + {% endif %} + + + + + + + + + + + + +{% endfor %} +
IDTAGVERDICTNB RUNSPASSFAILEDINCONSKIPPEDSEG FAULTTC TimeoutStartStopDurationDetails
{{result.testcase_name}}{{result.tags}}{{result.testcase_verdict}}{{result.testcase_verdict}}{{result.testcase_verdict}}{{result.nruns}}{{result.nb_run_pass}}{{result.nb_run_failed}}{{result.nb_run_inc}}{{result.nb_run_skip}}{{result.nb_seg_fault}}{{result.testcase_timeout}}{{result.testcase_time_start.strftime('%Y-%m-%d %H:%M:%S')}}{{result.testcase_time_stop.strftime('%Y-%m-%d %H:%M:%S')}}{{result.testcase_duration}}{{ result.testcase_name }}_report.html
+ + +

+

UE phy-test stability tests results

+

Objectives

+

To be complete

+

Results

+To be complete + + + + + diff --git a/cmake_targets/autotests/templates/testcase_report.html b/cmake_targets/autotests/templates/testcase_report.html new file mode 100644 index 0000000000..007ab56909 --- /dev/null +++ b/cmake_targets/autotests/templates/testcase_report.html @@ -0,0 +1,142 @@ + + + + + OAI5G UE test case report + + + + +
+

OAI5G UE test case report details

+
+ +

Test Case description

+

+ + + + + + + + + + + +
ID{{testcase_name}}
TAG{{tags}}
class{{testcaseclass}}
description
timeout{{testcase_timeout}}
number of runs{{nruns}}
eNB machine{{testcase_eNBMachine}}
UE machine{{testcase_UEMachine}}
+

+ + +

Test Case execution

+

+ + + + + + + + + + + + {% if testcase_verdict == "PASS" %} + + {% elif testcase_verdict == "FAIL" %} + + {% else %} + + {% endif %} + + + +
testcase_time_start{{testcase_time_start}}
testcase_time_stop{{testcase_time_stop}}
testcase_duration{{testcase_duration}}
Nb runs{{nruns}}
Nb PASS{{nb_run_pass}}
Nb FAILED{{nb_run_failed}}
Nb INCONCLUSIVE{{nb_run_inc}}
testcase_verdict{{testcase_verdict}}{{testcase_verdict}}{{testcase_verdict}}
Nb Seg Fault{{nb_seg_fault}}
+

+ + + +

Test Case runs results

+ +{% for run_results in runs_results|sort(attribute='run_id') %} +

RUN {{run_results.run_id}}

+ + + + + + + {% if run_results.run_verdict == "PASS" %} + + {% elif run_results.run_verdict == "FAIL" %} + + {% else %} + + {% endif %} + + + {% if run_results.ue_seg_fault_status == "NO_SEG_FAULT" %} + + {% elif run_results.ue_seg_fault_status == "SEG_FAULT" %} + + {% else %} + + {% endif %} + +
run_start_time {{run_results.run_start_time}}
run_stop_time{{run_results.run_stop_time}}
run_duration{{run_results.run_duration}}
run_verdict{{run_results.run_verdict}}{{run_results.run_verdict}}{{run_results.run_verdict}}
Seg Fault Satus{{run_results.ue_seg_fault_status}}{{run_results.ue_seg_fault_status}}unknown
+ + {% for run_metrics in run_results.runs_metrics %} +

+ + + + + + + + + + {% if run_metrics.pass_fail_stat is defined %} + + {% endif %} + {% if run_metrics.pass_fail_min_limit is defined %} + + {% endif %} + {% if run_metrics.pass_fail_max_limit is defined %} + + {% endif %} + + +
metric_id{{run_metrics.metric_id}}
Description{{run_metrics.metric_desc}}
Unit of measure{{run_metrics.metric_uom}}
metric_min{{run_metrics.metric_min}}
metric_max{{run_metrics.metric_max}}
metric_mean{{run_metrics.metric_mean}}
metric_median{{run_metrics.metric_median}}
Pass/fail stat{{run_metrics.pass_fail_stat}}
Pass/fail min limit{{run_metrics.pass_fail_min_limit}}
Pass/fail max limit{{run_metrics.pass_fail_max_limit}}
metric_fig
+ + {% endfor %} + + {% if run_results.run_traffic.traffic_count != 0 %} +

+ + + + + + + + + +
Iperf metricminmaxmeanmedian
Bandwidth {{run_results.run_traffic.bw_min}}{{run_results.run_traffic.bw_max}}{{run_results.run_traffic.bw_mean}}{{run_results.run_traffic.bw_median}}
Jitter{{run_results.run_traffic.jitter_min}}{{run_results.run_traffic.jitter_max}}{{run_results.run_traffic.jitter_mean}}{{run_results.run_traffic.jitter_median}}
Loss rate{{run_results.run_traffic.rl_min}}{{run_results.run_traffic.rl_max}}{{run_results.run_traffic.rl_mean}}{{run_results.run_traffic.rl_median}}
Iperf duration{{run_results.run_traffic.iperf_duration}}Pass/Fail criteria (min duration){{run_results.run_traffic.dur_pass_fail_crit}}
traffic_fig
+ {% endif %} + +{% endfor %} + + + From 43df2913749e32f14b3bf89c1eb5579db5131a6c Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 22 Nov 2016 10:14:51 +0100 Subject: [PATCH 305/413] T: add some traces - Msg3 allocation - initiation of Random Access procedure --- common/utils/T/T_messages.txt | 8 ++++++++ openair1/SCHED/phy_procedures_lte_eNb.c | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index 6e5e0ad7aa..cd123970c3 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -65,6 +65,14 @@ ID = ENB_PHY_PHICH DESC = eNodeB PHICH GROUP = ALL:PHY:ENB FORMAT = int,eNB_ID : int,frame : int,subframe : int,UE_id : int,rnti : int,harq_pid : int,NGROUP : int,NSF : int,ngroup : int,nseq : int,ACK : int,first_rb : int,n_DMRS +ID = ENB_PHY_MSG3_ALLOCATION + DESC = eNodeB Msg3 allocation/reallocation + GROUP = ALL:PHY:ENB + FORMAT = int,eNB_ID : int,frame : int,subframe : int,UE_id : int,rnti : int,first_transmission : int,Msg3_frame : int,Msg3_subframe +ID = ENB_PHY_INITIATE_RA_PROCEDURE + DESC = eNodeB initiates a random access procedure after detecting enough energy for one of the preambles + GROUP = ALL:PHY:ENB + FORMAT = int,eNB_ID : int,frame : int,subframe : int,UE_id : int,preamble : int,energy : int,delay #MAC logs ID = ENB_MAC_UE_DL_SDU diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 7ac6e2bf1f..5d84853930 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -968,6 +968,10 @@ void pdsch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,LTE_eNB_DLSCH_t *d UE_id, eNB->ulsch[(uint32_t)UE_id]->Msg3_frame, eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe); + + T(T_ENB_PHY_MSG3_ALLOCATION, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), + T_INT(UE_id), T_INT((uint16_t)crnti), T_INT(1 /* 1 is for initial transmission*/), + T_INT(eNB->ulsch[UE_id]->Msg3_frame), T_INT(eNB->ulsch[UE_id]->Msg3_subframe)); } if (ue_stats) ue_stats->total_TBS_MAC += dlsch_harq->TBS; } @@ -1959,6 +1963,9 @@ void prach_procedures(PHY_VARS_eNB *eNB) { preamble_energy_max%10, preamble_delay_list[preamble_max]); + T(T_ENB_PHY_INITIATE_RA_PROCEDURE, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(UE_id), + T_INT(preamble_max), T_INT(preamble_energy_max), T_INT(preamble_delay_list[preamble_max])); + if (eNB->mac_enabled==1) { uint8_t update_TA=4; @@ -3059,6 +3066,10 @@ void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,const frame, &eNB->ulsch[i]->Msg3_frame, &eNB->ulsch[i]->Msg3_subframe); + + T(T_ENB_PHY_MSG3_ALLOCATION, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), + T_INT(i), T_INT(eNB->ulsch[i]->rnti), T_INT(0 /* 0 is for retransmission*/), + T_INT(eNB->ulsch[i]->Msg3_frame), T_INT(eNB->ulsch[i]->Msg3_subframe)); } LOG_D(PHY,"[eNB] Frame %d, Subframe %d: Msg3 in error, i = %d \n", frame,subframe,i); } // This is Msg3 error From 6bb69e1964d28b700eff9ff72530b2aa417ae8ac Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 22 Nov 2016 10:38:18 +0100 Subject: [PATCH 306/413] hotfix: correct Msg3 ressource blocks reservation The Msg3 ressource blocks used by random access procedure were not correctly handled. The MAC scheduler could wrongly allocate a ressource block for both random access Msg3 and a regular UE. This hotfix hopefully fixes the problem. A new function "set_msg3_subframe" has been added in the interface between PHY and MAC. --- openair1/SCHED/phy_procedures_lte_eNb.c | 6 +++++ openair2/LAYER2/MAC/eNB_scheduler_RA.c | 3 ++- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 28 ++++++++++++++++++++++- openair2/LAYER2/MAC/main.c | 1 + openair2/LAYER2/MAC/proto.h | 19 +++++++++++++++ openair2/PHY_INTERFACE/defs.h | 10 ++++++++ 6 files changed, 65 insertions(+), 2 deletions(-) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 5d84853930..82e6b0dc1f 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -969,6 +969,9 @@ void pdsch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,LTE_eNB_DLSCH_t *d eNB->ulsch[(uint32_t)UE_id]->Msg3_frame, eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe); + mac_xface->set_msg3_subframe(eNB->Mod_id, eNB->CC_id, frame, subframe, (uint16_t)crnti, + eNB->ulsch[UE_id]->Msg3_frame, eNB->ulsch[UE_id]->Msg3_subframe); + T(T_ENB_PHY_MSG3_ALLOCATION, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(UE_id), T_INT((uint16_t)crnti), T_INT(1 /* 1 is for initial transmission*/), T_INT(eNB->ulsch[UE_id]->Msg3_frame), T_INT(eNB->ulsch[UE_id]->Msg3_subframe)); @@ -3067,6 +3070,9 @@ void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,const &eNB->ulsch[i]->Msg3_frame, &eNB->ulsch[i]->Msg3_subframe); + mac_xface->set_msg3_subframe(eNB->Mod_id, eNB->CC_id, frame, subframe, eNB->ulsch[i]->rnti, + eNB->ulsch[i]->Msg3_frame, eNB->ulsch[i]->Msg3_subframe); + T(T_ENB_PHY_MSG3_ALLOCATION, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(i), T_INT(eNB->ulsch[i]->rnti), T_INT(0 /* 0 is for retransmission*/), T_INT(eNB->ulsch[i]->Msg3_frame), T_INT(eNB->ulsch[i]->Msg3_subframe)); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c index 0da90652c0..23ba001d4c 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c @@ -259,7 +259,8 @@ void schedule_RA(module_id_t module_idP,frame_t frameP, sub_frame_t subframeP,un RA_template->RA_dci_fmt1, 1); - RA_template->Msg3_subframe=Msg3_subframe; + /* this will be updated when PHY calls set_msg3_subframe */ + RA_template->Msg3_subframe = -1; } } else if (RA_template->generate_Msg4 == 1) { diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index a65ec917de..77eb36c4d8 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -601,6 +601,29 @@ unsigned char *parse_ulsch_header(unsigned char *mac_header, return(mac_header_ptr); } +/* This function is called by PHY layer when it schedules some + * uplink for a random access message 3. + * The MAC scheduler has to skip the RBs used by this message 3 + * (done below in schedule_ulsch). + */ +void set_msg3_subframe(module_id_t Mod_id, + int CC_id, + int frame, + int subframe, + int rnti, + int Msg3_frame, + int Msg3_subframe) +{ + eNB_MAC_INST *eNB=&eNB_mac_inst[Mod_id]; + int i; + for (i=0; icommon_channels[CC_id].RA_template[i].RA_active == TRUE && + eNB->common_channels[CC_id].RA_template[i].rnti == rnti) { + eNB->common_channels[CC_id].RA_template[i].Msg3_subframe = Msg3_subframe; + break; + } + } +} void schedule_ulsch(module_id_t module_idP, frame_t frameP, @@ -619,6 +642,7 @@ void schedule_ulsch(module_id_t module_idP, for (CC_id=0; CC_idcommon_channels[CC_id].RA_template[i].RA_active == TRUE) && (eNB->common_channels[CC_id].RA_template[i].generate_rar == 0) && + (eNB->common_channels[CC_id].RA_template[i].generate_Msg4 == 0) && + (eNB->common_channels[CC_id].RA_template[i].wait_ack_Msg4 == 0) && (eNB->common_channels[CC_id].RA_template[i].Msg3_subframe == sched_subframe)) { - //leave out first RB for PUCCH first_rb[CC_id]++; + eNB->common_channels[CC_id].RA_template[i].Msg3_subframe = -1; break; } } diff --git a/openair2/LAYER2/MAC/main.c b/openair2/LAYER2/MAC/main.c index 4fee906f74..0fe9d63b6f 100644 --- a/openair2/LAYER2/MAC/main.c +++ b/openair2/LAYER2/MAC/main.c @@ -454,6 +454,7 @@ int l2_init(LTE_DL_FRAME_PARMS *frame_parms,int eMBMS_active, char *uecap_xer,ui mac_xface->fill_rar = fill_rar; mac_xface->initiate_ra_proc = initiate_ra_proc; mac_xface->cancel_ra_proc = cancel_ra_proc; + mac_xface->set_msg3_subframe = set_msg3_subframe; mac_xface->SR_indication = SR_indication; mac_xface->UL_failure_indication = UL_failure_indication; mac_xface->rx_sdu = rx_sdu; diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 59d6c352fe..4df0c6fa45 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -246,6 +246,25 @@ unsigned short fill_rar( */ void cancel_ra_proc(module_id_t module_idP,int CC_id,frame_t frameP, uint16_t preamble_index); +/* \brief Function used by PHY to inform MAC that an uplink is scheduled + for Msg3 in given subframe. This is used so that the MAC + scheduler marks as busy the RBs used by the Msg3. +@param Mod_id Instance ID of eNB +@param CC_id CC ID of eNB +@param frame current frame +@param subframe current subframe +@param rnti UE rnti concerned +@param Msg3_frame frame where scheduling takes place +@param Msg3_subframe subframe where scheduling takes place +*/ +void set_msg3_subframe(module_id_t Mod_id, + int CC_id, + int frame, + int subframe, + int rnti, + int Msg3_frame, + int Msg3_subframe); + /* \brief Function to indicate a received SDU on ULSCH. @param Mod_id Instance ID of eNB @param rnti RNTI of UE transmitting the SR diff --git a/openair2/PHY_INTERFACE/defs.h b/openair2/PHY_INTERFACE/defs.h index 0892b4d0b1..8c711e971d 100644 --- a/openair2/PHY_INTERFACE/defs.h +++ b/openair2/PHY_INTERFACE/defs.h @@ -72,6 +72,16 @@ typedef struct { /// cancel an ongoing RA procedure void (*cancel_ra_proc)(module_id_t Mod_id,int CC_id,frame_t frameP,uint16_t preamble); + /// Inform MAC layer that an uplink is scheduled for Msg3 in given subframe. + /// This is used so that the MAC scheduler marks as busy the RBs used by the Msg3. + void (*set_msg3_subframe)(module_id_t Mod_id, + int CC_id, + int frame, + int subframe, + int rnti, + int Msg3_frame, + int Msg3_subframe); + /// Get DCI for current subframe from MAC DCI_PDU* (*get_dci_sdu)(module_id_t Mod_id,int CC_id,frame_t frameP,sub_frame_t subframe); From b55b63c5ab20f0e752b12e3c9fa019da5ec00a7c Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 22 Nov 2016 10:46:04 +0100 Subject: [PATCH 307/413] hotfix: hack to improve PHICH generation The eNodeB may sometimes wrongly generate PHICH because somewhere 'phich_active' is not reset to 0, due to an unidentified reason. When adding this hack the problem seems to disappear completely. This is not the end of the story. The real underlying problem has to be understood and fixed correctly. --- openair1/SCHED/phy_procedures_lte_eNb.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 82e6b0dc1f..11fb37dcdf 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -969,6 +969,15 @@ void pdsch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,LTE_eNB_DLSCH_t *d eNB->ulsch[(uint32_t)UE_id]->Msg3_frame, eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe); + /* TODO: get rid of this hack. The problem is that the eNodeB may + * sometimes wrongly generate PHICH because somewhere 'phich_active' was + * not reset to 0, due to an unidentified reason. When adding this + * resetting here the problem seems to disappear completely. + */ + LOG_D(PHY, "hack: set phich_active to 0 for UE %d fsf %d %d all HARQs\n", UE_id, frame, subframe); + for (i = 0; i < 8; i++) + eNB->ulsch[(uint32_t)UE_id]->harq_processes[i]->phich_active = 0; + mac_xface->set_msg3_subframe(eNB->Mod_id, eNB->CC_id, frame, subframe, (uint16_t)crnti, eNB->ulsch[UE_id]->Msg3_frame, eNB->ulsch[UE_id]->Msg3_subframe); From 1a8069b9243f90b02031933a2e0e5de1b7fd614e Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 22 Nov 2016 11:19:23 +0100 Subject: [PATCH 308/413] bug fixed for DEBUG_PHY in lte_init.c --- openair1/PHY/INIT/lte_init.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 0009dbfefe..7e6cc39ac7 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1226,23 +1226,23 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, common_vars->txdataF_BF[eNB_id] = (int32_t **)malloc16(fp->nb_antennas_tx*sizeof(int32_t*)); for (i=0; i<14; i++) { - common_vars->txdataF[eNB_id][i] = (int32_t*)malloc16_clear( fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t) ); + common_vars->txdataF[eNB_id][i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t) ); #ifdef DEBUG_PHY msg("[openair][LTE_PHY][INIT] lte_common_vars->txdataF[%d][%d] = %p (%d bytes)\n", eNB_id,i,common_vars->txdataF[eNB_id][i], - FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(int32_t)); + fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t)); #endif } for (i=0; inb_antennas_tx; i++) { - common_vars->txdataF_BF[eNB_id][i] = (int32_t*)malloc16_clear( fp->ofdm_symbol_size*sizeof(int32_t) ); + common_vars->txdataF_BF[eNB_id][i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*sizeof(int32_t) ); if (eNB->node_function != NGFI_RCC_IF4p5) - common_vars->txdata[eNB_id][i] = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) ); + common_vars->txdata[eNB_id][i] = (int32_t*)malloc16_clear(fp->samples_per_tti*10*sizeof(int32_t) ); #ifdef DEBUG_PHY msg("[openair][LTE_PHY][INIT] lte_common_vars->txdataF_BF[%d][%d][%d] = %p (%d bytes)\n", eNB_id,i,j,common_vars->txdataF_BF[eNB_id][i][j], - OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); + fp->ofdm_symbol_size*sizeof(int32_t)); msg("[openair][LTE_PHY][INIT] lte_common_vars->txdata[%d][%d] = %p\n",eNB_id,i,common_vars->txdata[eNB_id][i]); #endif } @@ -1256,7 +1256,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, #ifdef DEBUG_PUY msg("[openair][LTE_PHY][INIT] lte_common_vars->beam_weights[%d][%d][%d] = %p (%d bytes)\n", eNB_id,i,j,common_vars->beam_weights[eNB_id][i][j], - OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); + fp->ofdm_symbol_size*sizeof(int32_t)); #endif } } From 3ae5f956539f88855ddd44c03cd7c673378313d8 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 12 Aug 2016 14:24:24 +0200 Subject: [PATCH 309/413] T: fix small typo --- common/utils/T/tracer/macpdu2wireshark.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/utils/T/tracer/macpdu2wireshark.c b/common/utils/T/tracer/macpdu2wireshark.c index 886638f5ef..be0bbd3821 100644 --- a/common/utils/T/tracer/macpdu2wireshark.c +++ b/common/utils/T/tracer/macpdu2wireshark.c @@ -177,7 +177,7 @@ void usage(void) printf( "options:\n" " -d this option is mandatory\n" -" -in read events from this dump file\n" +" -i read events from this dump file\n" " -ip send packets to this IP address (default %s)\n" " -p send packets to this port (default %d)\n", DEFAULT_IP, @@ -205,7 +205,7 @@ int main(int n, char **v) if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage(); if (!strcmp(v[i], "-d")) { if (i > n-2) usage(); database_filename = v[++i]; continue; } - if (!strcmp(v[i], "-in")) + if (!strcmp(v[i], "-i")) { if (i > n-2) usage(); input_filename = v[++i]; continue; } if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; } if (!strcmp(v[i], "-p")) {if(i>n-2)usage(); port=atoi(v[++i]); continue; } From b526ef7b476608795413b495a4d7ae454b93b4c5 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 22 Nov 2016 12:02:10 +0100 Subject: [PATCH 310/413] T: update a trace add ndi to trace ENB_MAC_UE_DL_SDU --- common/utils/T/T_messages.txt | 2 +- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index cd123970c3..3e3ba082dd 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -82,7 +82,7 @@ ID = ENB_MAC_UE_DL_SDU ID = ENB_MAC_UE_UL_SCHEDULE DESC = MAC uplink UE scheduling decision GROUP = ALL:MAC:ENB - FORMAT = int,eNB_ID : int,CC_id : int,rnti : int,frame : int,subframe : int,harq_pid : int,mcs : int,first_rb : int,nb_rb : int,TBS + FORMAT = int,eNB_ID : int,CC_id : int,rnti : int,frame : int,subframe : int,harq_pid : int,mcs : int,first_rb : int,nb_rb : int,TBS : int,ndi ID = ENB_MAC_UE_UL_SCHEDULE_RETRANSMISSION DESC = MAC uplink UE scheduling retransmission decision GROUP = ALL:MAC:ENB diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 77eb36c4d8..671e95aec5 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -880,7 +880,7 @@ void schedule_ulsch_rnti(module_id_t module_idP, T(T_ENB_MAC_UE_UL_SCHEDULE, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(mcs), T_INT(first_rb[CC_id]), T_INT(rb_table[rb_table_index]), - T_INT(TBS)); + T_INT(TBS), T_INT(ndi)); // bad indices : 20 (40 PRB), 21 (45 PRB), 22 (48 PRB) // increment for next UE allocation From 60a1f34a5aa8831363edbd8e98a00a3dfeee620d Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 22 Nov 2016 12:29:18 +0100 Subject: [PATCH 311/413] cosmetic changes --- openair1/PHY/INIT/lte_init.c | 6 +++--- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 7e6cc39ac7..44d9e65dc8 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -29,7 +29,7 @@ #include "LAYER2/MAC/extern.h" #include "MBSFN-SubframeConfigList.h" #include "UTIL/LOG/vcd_signal_dumper.h" -//#define DEBUG_PHY +#define DEBUG_PHY #include "assertions.h" #include @@ -1240,8 +1240,8 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, common_vars->txdata[eNB_id][i] = (int32_t*)malloc16_clear(fp->samples_per_tti*10*sizeof(int32_t) ); #ifdef DEBUG_PHY - msg("[openair][LTE_PHY][INIT] lte_common_vars->txdataF_BF[%d][%d][%d] = %p (%d bytes)\n", - eNB_id,i,j,common_vars->txdataF_BF[eNB_id][i][j], + msg("[openair][LTE_PHY][INIT] lte_common_vars->txdataF_BF[%d][%d] = %p (%d bytes)\n", + eNB_id,i,common_vars->txdataF_BF[eNB_id][i], fp->ofdm_symbol_size*sizeof(int32_t)); msg("[openair][LTE_PHY][INIT] lte_common_vars->txdata[%d][%d] = %p\n",eNB_id,i,common_vars->txdata[eNB_id][i]); #endif diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 9bf01400e3..7914437a53 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -2039,8 +2039,8 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB, P1_SHIFT, P2_SHIFT); - if ((mimo_mode == TM7) && (lprime>=0)) - mprime +=3+frame_parms->Ncp; + if ((mimo_mode == TM7) && (lprime>=0)) + mprime +=3+frame_parms->Ncp; } else { From ce8c81af0ab09c11d572df384a356858bc94c52f Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 22 Nov 2016 14:01:41 +0100 Subject: [PATCH 312/413] hotfix: cqi_crc_status was not properly set/reset --- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 80dfb69877..805c5302c3 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -1533,6 +1533,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, // CQI // printf("before cqi c[%d] = %p\n",0,ulsch_harq->c[0]); + ulsch_harq->cqi_crc_status = 0; if (Q_CQI>0) { memset((void *)&dummy_w_cc[0],0,3*(ulsch_harq->Or1+8+32)); @@ -1555,9 +1556,6 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, if (extract_cqi_crc(o_flip,ulsch_harq->Or1) == (crc8(o_flip,ulsch_harq->Or1)>>24)) ulsch_harq->cqi_crc_status = 1; - else - ulsch_harq->cqi_crc_status = 0; - if (ulsch->harq_processes[harq_pid]->Or1<=32) { ulsch_harq->o[3] = o_flip[0] ; From 5a3b3ed0b57fb6c69609bef634508fc9f62229f8 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 22 Nov 2016 14:02:52 +0100 Subject: [PATCH 313/413] minor: remove compilation warnings --- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 805c5302c3..0ce810a52c 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -449,7 +449,7 @@ int ulsch_decoding_data_2thread(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr int16_t dummy_w[MAX_NUM_ULSCH_SEGMENTS][3*(6144+64)]; LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; - int Q_m = get_Qm_ul(ulsch_harq->mcs); + //int Q_m = get_Qm_ul(ulsch_harq->mcs); int G = ulsch_harq->G; unsigned int E; int Cby2; @@ -657,7 +657,7 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB,int UE_id,int harq_pid,int llr8_flag) int16_t dummy_w[MAX_NUM_ULSCH_SEGMENTS][3*(6144+64)]; LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[UE_id]; LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid]; - int Q_m = get_Qm_ul(ulsch_harq->mcs); + //int Q_m = get_Qm_ul(ulsch_harq->mcs); int G = ulsch_harq->G; unsigned int E; From eab744f6f990c417e2f5041dccdaeeb524267a69 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 22 Nov 2016 14:57:11 +0100 Subject: [PATCH 314/413] add in allocate_REs_in_RB the TM7 case --- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 116 +++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 7914437a53..84e4bddec2 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -619,10 +619,21 @@ int allocate_REs_in_RB(PHY_VARS_eNB* phy_vars_eNB, int32_t tmp_sample1,tmp_sample2; int16_t tmp_amp=amp; int s=1; + int mprime2 = mprime,ind,ind_dword,ind_qpsk_symb; gain_lin_QPSK = (int16_t)((amp*ONE_OVER_SQRT2_Q15)>>15); // if (mimo_mode == LARGE_CDD) gain_lin_QPSK>>=1; + int32_t qpsk[4]; + ((int16_t *)&qpsk[0])[0] = gain_lin_QPSK; + ((int16_t *)&qpsk[0])[1] = gain_lin_QPSK; + ((int16_t *)&qpsk[1])[0] = -gain_lin_QPSK; + ((int16_t *)&qpsk[1])[1] = gain_lin_QPSK;; + ((int16_t *)&qpsk[2])[0] = gain_lin_QPSK;; + ((int16_t *)&qpsk[2])[1] = -gain_lin_QPSK;; + ((int16_t *)&qpsk[3])[0] = -gain_lin_QPSK;; + ((int16_t *)&qpsk[3])[1] = -gain_lin_QPSK; + if (dlsch1_harq) { x1 = dlsch1_harq->e; // Fill these in later for TM8-10 @@ -1285,8 +1296,111 @@ x0[1+*jj]); *re_allocated = *re_allocated + 1; } } + + if (mimo_mode == TM7) { + *re_allocated = *re_allocated + 1; - if (mimo_mode >= TM8) { //TM8,TM9,TM10 + if (is_not_UEspecRS(lprime,re,frame_parms->Nid_cell%3,frame_parms->Ncp,7)) { + + switch (mod_order0){ + case 2: //QPSK + + ((int16_t*)&txdataF[5][tti_offset])[0] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + *jj = *jj + 1; + ((int16_t*)&txdataF[5][tti_offset])[1] = (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; + *jj = *jj + 1; + + //printf("%d(%d) : %d,%d => + //",tti_offset,*jj,((int16_t*)&tmp_sample1)[0],((int16_t*)&tmp_sample1)[1]); + break; + + case 4: //16QAM + + qam16_table_offset_re = 0; + qam16_table_offset_im = 0; + + if (x0[*jj] == 1) + qam16_table_offset_re+=2; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam16_table_offset_im+=2; + + *jj=*jj+1; + + + if (x0[*jj] == 1) + qam16_table_offset_re+=1; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam16_table_offset_im+=1; + + *jj=*jj+1; + + ((int16_t*)&txdataF[5][tti_offset])[0] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); + ((int16_t*)&txdataF[5][tti_offset])[1] = (int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); + + break; + + case 6: //64QAM + + + qam64_table_offset_re = 0; + qam64_table_offset_im = 0; + + if (x0[*jj] == 1) + qam64_table_offset_re+=4; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam64_table_offset_im+=4; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam64_table_offset_re+=2; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam64_table_offset_im+=2; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam64_table_offset_re+=1; + + *jj=*jj+1; + + if (x0[*jj] == 1) + qam64_table_offset_im+=1; + + *jj=*jj+1; + + ((int16_t*)&txdataF[5][tti_offset])[0] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); + ((int16_t*)&txdataF[5][tti_offset])[1] = (int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); + + break; + + } + } else { + //precoding UE spec RS + //printf("precoding UE spec RS\n"); + + ind = 3*lprime*dlsch0_harq->nb_rb+mprime2; + ind_dword = ind>>4; + ind_qpsk_symb = ind&0xf; + + txdataF[5][tti_offset] = qpsk[(phy_vars_eNB->lte_gold_uespec_port5_table[0][Ns][ind_dword]>>(2*ind_qpsk_symb))&3]; + mprime2++; + + } + + } else if (mimo_mode >= TM8) { //TM8,TM9,TM10 //uint8_t is_not_UEspecRS(int8_t lprime, uint8_t re, uint8_t nushift, uint8_t Ncp, uint8_t beamforming_mode) if (is_not_UEspecRS(lprime,re,frame_parms->nushift,frame_parms->Ncp,8)) { From c3c3f2748742f79793754c38e5ccbd149504a1d9 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Tue, 22 Nov 2016 18:15:57 +0100 Subject: [PATCH 315/413] fixes for phy-test option at eNB --- openair1/SCHED/phy_mac_stub.c | 2 ++ targets/RT/USER/lte-softmodem.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/openair1/SCHED/phy_mac_stub.c b/openair1/SCHED/phy_mac_stub.c index 939023b2c8..0ac194d051 100644 --- a/openair1/SCHED/phy_mac_stub.c +++ b/openair1/SCHED/phy_mac_stub.c @@ -70,6 +70,7 @@ void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) case 5: DCI_pdu->Num_common_dci = 1; DCI_pdu->dci_alloc[0].L = 2; + DCI_pdu->dci_alloc[0].firstCCE = 0; DCI_pdu->dci_alloc[0].rnti = SI_RNTI; DCI_pdu->dci_alloc[0].format = format1A; DCI_pdu->dci_alloc[0].ra_flag = 0; @@ -212,6 +213,7 @@ void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) case 7: DCI_pdu->Num_ue_spec_dci = 1; DCI_pdu->dci_alloc[0].L = 2; + DCI_pdu->dci_alloc[0].firstCCE = 0; DCI_pdu->dci_alloc[0].rnti = 0x1235; DCI_pdu->dci_alloc[0].format = format1; DCI_pdu->dci_alloc[0].ra_flag = 0; diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 40b9255936..de5be6913c 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1601,6 +1601,11 @@ int main( int argc, char **argv ) PHY_vars_eNB_g[0][CC_id] = init_lte_eNB(frame_parms[CC_id],0,frame_parms[CC_id]->Nid_cell,abstraction_flag); PHY_vars_eNB_g[0][CC_id]->CC_id = CC_id; + PHY_vars_eNB_g[0][CC_id]->ue_dl_rb_alloc=0x1fff; + PHY_vars_eNB_g[0][CC_id]->target_ue_dl_mcs=target_dl_mcs; + PHY_vars_eNB_g[0][CC_id]->ue_ul_nb_rb=6; + PHY_vars_eNB_g[0][CC_id]->target_ue_ul_mcs=target_ul_mcs; + if (phy_test==1) PHY_vars_eNB_g[0][CC_id]->mac_enabled = 0; else PHY_vars_eNB_g[0][CC_id]->mac_enabled = 1; From 7dbc59c830ae9521ff1bad8ff0ae479e7cdd2b3b Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Tue, 22 Nov 2016 18:34:57 +0100 Subject: [PATCH 316/413] adapt dlsim to TM7 --- openair1/SIMULATION/LTE_PHY/dlsim.c | 95 ++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 22 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 2e9a04def3..1ba2196eb6 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -275,6 +275,8 @@ void fill_DCI(PHY_VARS_eNB *eNB, case 1: case 2: + + case 7: if (common_flag == 0) { if (eNB->frame_parms.frame_type == TDD) { @@ -1259,6 +1261,7 @@ int main(int argc, char **argv) int c; int k,i,aa; + int re; int s,Kr,Kr_bytes; @@ -1275,9 +1278,12 @@ int main(int argc, char **argv) double forgetting_factor=0.0; //in [0,1] 0 means a new channel every time, 1 means keep the same channel - uint8_t extended_prefix_flag=0,transmission_mode=1,n_tx=1,n_rx=2; + uint8_t extended_prefix_flag=0,transmission_mode=1,n_tx_port=1,n_tx_phy=1,n_rx=2; uint16_t Nid_cell=0; + int32_t **cell_spec_bf_weights; + int32_t *ue_spec_bf_weights; + int eNB_id = 0; unsigned char mcs1=0,mcs2=0,mcs_i=0,dual_stream_UE = 0,awgn_flag=0,round; unsigned char i_mod = 2; @@ -1416,7 +1422,7 @@ int main(int argc, char **argv) // num_layers = 1; perfect_ce = 0; - while ((c = getopt (argc, argv, "ahdpZDe:Em:n:o:s:f:t:c:g:r:F:x:y:z:AM:N:I:i:O:R:S:C:T:b:u:v:w:B:Pl:WXY")) != -1) { + while ((c = getopt (argc, argv, "ahdpZDe:Em:n:o:s:f:t:c:g:r:F:x:q:y:z:AM:N:I:i:O:R:S:C:T:b:u:v:w:B:Pl:WXY")) != -1) { switch (c) { case 'a': awgn_flag = 1; @@ -1617,7 +1623,7 @@ int main(int argc, char **argv) dual_stream_UE=1; UE->use_ia_receiver = 1; - if ((n_tx!=2) || (transmission_mode!=5)) { + if ((n_tx_port!=2) || (transmission_mode!=5)) { msg("IA receiver only supported for TM5!"); exit(-1); } @@ -1638,6 +1644,17 @@ int main(int argc, char **argv) print_perf=1; break; + case 'q': + n_tx_port=atoi(optarg); + + if ((n_tx_port==0) || ((n_tx_port>2))) { + msg("Unsupported number of cell specific antennas ports %d\n",n_tx_port); + exit(-1); + } + + break; + + case 'x': transmission_mode=atoi(optarg); @@ -1646,25 +1663,37 @@ int main(int argc, char **argv) (transmission_mode!=3) && (transmission_mode!=4) && (transmission_mode!=5) && - (transmission_mode!=6)) { + (transmission_mode!=6) && + (transmission_mode!=7)) { msg("Unsupported transmission mode %d\n",transmission_mode); exit(-1); } - if (transmission_mode>1) { - n_tx = 2; + if (transmission_mode>1 && transmission_mode<7) { + n_tx_port = 2; } break; case 'y': - n_tx=atoi(optarg); + n_tx_phy=atoi(optarg); - if ((n_tx==0) || (n_tx>2)) { - msg("Unsupported number of tx antennas %d\n",n_tx); + if (n_tx_phy < n_tx_port) { + msg("n_tx_phy mush not be smaller than n_tx_port"); exit(-1); } + if ((transmission_mode>1 && transmission_mode<7) && n_tx_port<2) { + msg("n_tx_port must be >1 for transmission_mode %d\n",transmission_mode); + exit(-1); + } + + if (transmission_mode==7 && (n_tx_phy!=1 && n_tx_phy!=2 && n_tx_phy!=4 && n_tx_phy!=8 && n_tx_phy!=16 && n_tx_phy!=64 && n_tx_phy!=128)) { + msg("Physical number of antennas not supported for TM7.\n"); + exit(-1); + } + + break; break; case 'X': @@ -1693,7 +1722,7 @@ int main(int argc, char **argv) case 'h': default: - printf("%s -h(elp) -a(wgn on) -d(ci decoding on) -p(extended prefix on) -m mcs1 -M mcs2 -n n_frames -s snr0 -x transmission mode (1,2,5,6) -y TXant -z RXant -I trch_file\n",argv[0]); + printf("%s -h(elp) -a(wgn on) -d(ci decoding on) -p(extended prefix on) -m mcs1 -M mcs2 -n n_frames -s snr0 -x transmission mode (1,2,5,6,7) -y TXant -z RXant -I trch_file\n",argv[0]); printf("-h This message\n"); printf("-a Use AWGN channel and not multipath\n"); printf("-c Number of PDCCH symbols\n"); @@ -1708,7 +1737,8 @@ int main(int argc, char **argv) printf("-r ressource block allocation (see section 7.1.6.3 in 36.213\n"); printf("-g [A:M] Use 3GPP 25.814 SCM-A/B/C/D('A','B','C','D') or 36-101 EPA('E'), EVA ('F'),ETU('G') models (ignores delay spread and Ricean factor), Rayghleigh8 ('H'), Rayleigh1('I'), Rayleigh1_corr('J'), Rayleigh1_anticorr ('K'), Rice8('L'), Rice1('M')\n"); printf("-F forgetting factor (0 new channel every trial, 1 channel constant\n"); - printf("-x Transmission mode (1,2,6 for the moment)\n"); + printf("-x Transmission mode (1,2,6,7 for the moment)\n"); + printf("-q Number of TX antennas ports used in eNB\n"); printf("-y Number of TX antennas used in eNB\n"); printf("-z Number of RX antennas used in UE\n"); printf("-t MCS of interfering UE\n"); @@ -1747,9 +1777,6 @@ int main(int argc, char **argv) } else NB_RB = 4; - if ((transmission_mode > 1) && (n_tx != 2)) - printf("n_tx must be >1 for transmission_mode %d\n",transmission_mode); - if (xforms==1) { fl_initialize (&argc, argv, NULL, 0, 0); form_ue = create_lte_phy_scope_ue(); @@ -1769,8 +1796,8 @@ int main(int argc, char **argv) printf("dual_stream_UE=%d\n", dual_stream_UE); } - lte_param_init(transmission_mode==1?1:2, - n_tx, + lte_param_init(n_tx_port, + n_tx_phy, n_rx, transmission_mode, extended_prefix_flag, @@ -1782,6 +1809,26 @@ int main(int argc, char **argv) osf, perfect_ce); + /* Check if really needed */ + /*cell_spec_bf_weights = eNB->common_vars.beam_weights[0][0]; + for(aa=0;aaofdm_symbol_size;re++) { + if (n_tx_phy==1 || n_tx_phy==2) + cell_spec_bf_weights[aa][re] = 0x00007fff; + else if (n_tx_phy==4 || n_tx_phy==8) + cell_spec_bf_weights[aa][re] = 0x00007fff>>1; + else if (n_tx_phy==16) + cell_spec_bf_weights[aa][re] = 0x00007fff>>2; + else if (n_tx_phy==64) + cell_spec_bf_weights[aa][re] = 0x00007fff>>4; + } + } + + if (transmission_mode==7) { + lte_gold_ue_spec_port5(eNB->lte_gold_uespec_port5_table[0],Nid_cell,n_rnti); + lte_gold_ue_spec_port5(UE->lte_gold_uespec_port5_table,Nid_cell,n_rnti); + }*/ + eNB->mac_enabled=1; if (two_thread_flag == 0) { eNB->te = dlsch_encoding; @@ -1803,7 +1850,7 @@ int main(int argc, char **argv) printf("Setting mcs2 = %d\n",mcs2); printf("NPRB = %d\n",NB_RB); printf("n_frames = %d\n",n_frames); - printf("Transmission mode %d with %dx%d antenna configuration, Extended Prefix %d\n",transmission_mode,n_tx,n_rx,extended_prefix_flag); + printf("Transmission mode %d with %dx%d antenna configuration, Extended Prefix %d\n",transmission_mode,n_tx_phy,n_rx,extended_prefix_flag); snr1 = snr0+snr_int; printf("SNR0 %f, SNR1 %f\n",snr0,snr1); @@ -1838,7 +1885,7 @@ int main(int argc, char **argv) //char dirname[FILENAME_MAX]; //sprintf(dirname, "%s/SIMU/USER/pre-ci-logs-%s", getenv("OPENAIR_TARGETS"),hostname ); sprintf(time_meas_fname,"time_meas_prb%d_mcs%d_anttx%d_antrx%d_pdcch%d_channel%s_tx%d.csv", - N_RB_DL,mcs1,n_tx,n_rx,num_pdcch_symbols,channel_model_input,transmission_mode); + N_RB_DL,mcs1,n_tx_phy,n_rx,num_pdcch_symbols,channel_model_input,transmission_mode); //mkdir(dirname,0777); time_meas_fd = fopen(time_meas_fname,"w"); if (time_meas_fd==NULL) { @@ -2403,11 +2450,15 @@ int main(int argc, char **argv) if (n_frames==1) { printf("tx_lev = %d (%d dB)\n",tx_lev,tx_lev_dB); - write_output("txsig0.m","txs0", &eNB->common_vars.txdata[eNB_id][0][subframe* eNB->frame_parms.samples_per_tti], - eNB->frame_parms.samples_per_tti,1,1); - write_output("txsigF0.m","txsF0", &eNB->common_vars.txdataF[eNB_id][0][subframe*nsymb*eNB->frame_parms.ofdm_symbol_size], - nsymb*eNB->frame_parms.ofdm_symbol_size,1,1); + write_output("txsig0.m","txs0", &eNB->common_vars.txdata[eNB_id][0][subframe* eNB->frame_parms.samples_per_tti], eNB->frame_parms.samples_per_tti,1,1); + + if (transmission_mode<7) { + write_output("txsigF0.m","txsF0", &eNB->common_vars.txdataF[eNB_id][0][subframe*nsymb*eNB->frame_parms.ofdm_symbol_size],nsymb*eNB->frame_parms.ofdm_symbol_size,1,1); + } else if (transmission_mode == 7) { + write_output("txsigF0.m","txsF0", &eNB->common_vars.txdataF[eNB_id][5][subframe*nsymb*eNB->frame_parms.ofdm_symbol_size],nsymb*eNB->frame_parms.ofdm_symbol_size,1,1); + write_output("txsigF0_BF.m","txsF0_BF", &eNB->common_vars.txdataF_BF[eNB_id][0][0],eNB->frame_parms.ofdm_symbol_size,1,1); + } } } From 263254408df04af4babd86cbdc10f0e8f21fa172 Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Wed, 23 Nov 2016 10:41:00 +0100 Subject: [PATCH 317/413] use symbol based OFDM modulation in dlsim --- openair1/SIMULATION/LTE_PHY/dlsim.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 1ba2196eb6..b94b757adf 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -1282,7 +1282,6 @@ int main(int argc, char **argv) uint16_t Nid_cell=0; int32_t **cell_spec_bf_weights; - int32_t *ue_spec_bf_weights; int eNB_id = 0; unsigned char mcs1=0,mcs2=0,mcs_i=0,dual_stream_UE = 0,awgn_flag=0,round; @@ -2411,6 +2410,7 @@ int main(int argc, char **argv) start_meas(&eNB->ofdm_mod_stats); + /* do_OFDM_mod_l(eNB->common_vars.txdataF[eNB_id], eNB->common_vars.txdata[eNB_id], (subframe*2), @@ -2420,7 +2420,19 @@ int main(int argc, char **argv) eNB->common_vars.txdata[eNB_id], (subframe*2)+1, &eNB->frame_parms); - + */ + + do_OFDM_mod_symbol(&eNB->common_vars, + eNB_id, + (subframe*2), + &eNB->frame_parms); + + do_OFDM_mod_symbol(&eNB->common_vars, + eNB_id, + (subframe*2)+1, + &eNB->frame_parms); + + stop_meas(&eNB->ofdm_mod_stats); // generate next subframe for channel estimation From b4a6e0305349f8c4b08ee18b4acefa406f1fa2ec Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Wed, 23 Nov 2016 11:48:18 +0100 Subject: [PATCH 318/413] error message disply fixed in dl bf ch est --- .../LTE_ESTIMATION/lte_dl_bf_channel_estimation.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c index 7f4a14f197..0b220c2c39 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c @@ -205,7 +205,7 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, } //estimation and interpolation - if ((frame_parms->N_RB_DL&1) == 0) // even number of RBs + if ((frame_parms->N_RB_DL&1) == 0) { // even number of RBs for (rb=0; rbN_RB_DL; rb++) { if (rb < 32) @@ -240,14 +240,13 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, ch[0] = (short)(((int)pil[0]*rxF[16] - (int)pil[1]*rxF[17])>>15); ch[1] = (short)(((int)pil[0]*rxF[17] + (int)pil[1]*rxF[16])>>15); multadd_real_vector_complex_scalar(fr,ch,dl_bf_ch,16); + } else { + msg("lte_dl_bf_channel_estimation(lte_dl_bf_channel_estimation.c):TM7 beamgforming channel estimation not supported for extented CP\n"); + exit(-1); } } else { - msg("lte_dl_bf_channel_estimation(lte_dl_bf_channel_estimation.c):TM7 beamgforming channel estimation not supported for extented CP\n"); - exit(-1); + msg("lte_dl_bf_channel_estimation(lte_dl_bf_channel_estimation.c): transmission mode not supported.\n"); } - - } else { - msg("lte_dl_bf_channel_estimation(lte_dl_bf_channel_estimation.c): transmission mode not supported.\n"); } nb_rb++; } @@ -255,7 +254,7 @@ int lte_dl_bf_channel_estimation(PHY_VARS_UE *phy_vars_ue, rxF+=24; dl_bf_ch+=24; } - else { // Odd number of RBs + } else { // Odd number of RBs for (rb=0; rbN_RB_DL>>1; rb++) { skip_half=0; From 2716aaa7115a35afabe705570d23822c350ba200 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 23 Nov 2016 15:00:36 +0100 Subject: [PATCH 319/413] T: activate all info/warning/error legacy traces by default in enb.c --- common/utils/T/tracer/enb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/utils/T/tracer/enb.c b/common/utils/T/tracer/enb.c index 3b8e2bf14e..f041f21871 100644 --- a/common/utils/T/tracer/enb.c +++ b/common/utils/T/tracer/enb.c @@ -525,9 +525,9 @@ int main(int n, char **v) on_off(database, "ENB_PHY_PUCCH_1_ENERGY", is_on, 1); on_off(database, "ENB_PHY_PUCCH_1AB_IQ", is_on, 1); - on_off(database, "LEGACY_RRC_INFO", is_on, 1); - on_off(database, "LEGACY_RRC_ERROR", is_on, 1); - on_off(database, "LEGACY_RRC_WARNING", is_on, 1); + on_off(database, "LEGACY_GROUP_INFO", is_on, 1); + on_off(database, "LEGACY_GROUP_ERROR", is_on, 1); + on_off(database, "LEGACY_GROUP_WARNING", is_on, 1); view_add_log(eg.phyview, "ENB_PHY_DLSCH_UE_DCI", h, database, is_on); view_add_log(eg.phyview, "ENB_PHY_DLSCH_UE_ACK", h, database, is_on); From 441b062e3affb72d78f75dd02d70ceb22f401121 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Wed, 23 Nov 2016 15:15:56 +0100 Subject: [PATCH 320/413] changing config files --- .../CONF/enb.band7.tm1.usrpb210.conf | 14 +- .../CONF/enb.band7.usrpb210.conf | 232 +++++++++--------- 2 files changed, 123 insertions(+), 123 deletions(-) diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf index 01cd014afc..5ef5a4f50b 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -68,9 +68,9 @@ eNBs = srs_ackNackST =; srs_MaxUpPts =;*/ - pusch_p0_Nominal = -96; + pusch_p0_Nominal = -90; pusch_alpha = "AL1"; - pucch_p0_Nominal = -103; + pucch_p0_Nominal = -96; msg3_delta_Preamble = 6; pucch_deltaF_Format1 = "deltaF2"; pucch_deltaF_Format1b = "deltaF3"; @@ -137,7 +137,7 @@ eNBs = ////////// MME parameters: - mme_ip_address = ( { ipv4 = "127.0.0.3"; + mme_ip_address = ( { ipv4 = "192.168.12.70"; ipv6 = "192:168:30::17"; active = "yes"; preference = "ipv4"; @@ -147,10 +147,10 @@ eNBs = NETWORK_INTERFACES : { - ENB_INTERFACE_NAME_FOR_S1_MME = "lo"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "127.0.0.2/24"; - ENB_INTERFACE_NAME_FOR_S1U = "lo"; - ENB_IPV4_ADDRESS_FOR_S1U = "127.0.0.4/24"; + ENB_INTERFACE_NAME_FOR_S1_MME = "eth1"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.147/24"; + ENB_INTERFACE_NAME_FOR_S1U = "eth1"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.147/24"; ENB_PORT_FOR_S1U = 2152; # Spec 2152 }; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.usrpb210.conf index 1fe3beae0e..540edcd5b9 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.usrpb210.conf @@ -7,125 +7,126 @@ eNBs = { ////////// Identification parameters: eNB_ID = 0xe00; - + cell_type = "CELL_MACRO_ENB"; - + eNB_name = "eNB_Eurecom_LTEBox"; - + // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = "1"; - + mobile_country_code = "208"; - + mobile_network_code = "94"; - + ////////// Physical parameters: - + component_carriers = ( - { - frame_type = "FDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 7; - downlink_frequency = 2680000000L; - uplink_frequency_offset = -120000000; - Nid_cell = 0; - N_RB_DL = 25; - Nid_cell_mbsfn = 0; - nb_antenna_ports = 2; - nb_antennas_tx = 2; - nb_antennas_rx = 2; - tx_gain = 90; - rx_gain = 125; - prach_root = 0; - prach_config_index = 0; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 1; - prach_freq_offset = 2; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = -26; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 0; - pusch_groupHoppingEnabled = "ENABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 1; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =;*/ + { + node_function = "eNodeB_3GPP"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "FDD"; + tdd_config = 3; + tdd_config_s = 0; + prefix_type = "NORMAL"; + eutra_band = 7; + downlink_frequency = 2660000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 0; + N_RB_DL = 25; + Nid_cell_mbsfn = 0; + nb_antenna_ports = 2; + nb_antennas_tx = 2; + nb_antennas_rx = 2; + tx_gain = 90; + rx_gain = 125; + prach_root = 0; + prach_config_index = 0; + prach_high_speed = "DISABLE"; + prach_zero_correlation = 1; + prach_freq_offset = 2; + pucch_delta_shift = 1; + pucch_nRB_CQI = 1; + pucch_nCS_AN = 0; + pucch_n1_AN = 32; + pdsch_referenceSignalPower = -24; + pdsch_p_b = 1; + pusch_n_SB = 1; + pusch_enable64QAM = "DISABLE"; + pusch_hoppingMode = "interSubFrame"; + pusch_hoppingOffset = 0; + pusch_groupHoppingEnabled = "ENABLE"; + pusch_groupAssignment = 0; + pusch_sequenceHoppingEnabled = "DISABLE"; + pusch_nDMRS1 = 1; + phich_duration = "NORMAL"; + phich_resource = "ONESIXTH"; + srs_enable = "DISABLE"; + /* srs_BandwidthConfig =; + srs_SubframeConfig =; + srs_ackNackST =; + srs_MaxUpPts =;*/ - pusch_p0_Nominal = -90; - pusch_alpha = "AL1"; - pucch_p0_Nominal = -96; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 64; - rach_preamblesGroupAConfig = "DISABLE"; -/* - rach_sizeOfRA_PreamblesGroupA = ; - rach_messageSizeGroupA = ; - rach_messagePowerOffsetGroupB = ; -*/ - rach_powerRampingStep = 4; - rach_preambleInitialReceivedTargetPower = -108; - rach_preambleTransMax = 10; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; + pusch_p0_Nominal = -90; + pusch_alpha = "AL1"; + pucch_p0_Nominal = -96; + msg3_delta_Preamble = 6; + pucch_deltaF_Format1 = "deltaF2"; + pucch_deltaF_Format1b = "deltaF3"; + pucch_deltaF_Format2 = "deltaF0"; + pucch_deltaF_Format2a = "deltaF0"; + pucch_deltaF_Format2b = "deltaF0"; - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; + rach_numberOfRA_Preambles = 64; + rach_preamblesGroupAConfig = "DISABLE"; + /* + rach_sizeOfRA_PreamblesGroupA = ; + rach_messageSizeGroupA = ; + rach_messagePowerOffsetGroupB = ; + */ + rach_powerRampingStep = 4; + rach_preambleInitialReceivedTargetPower = -104; + rach_preambleTransMax = 10; + rach_raResponseWindowSize = 10; + rach_macContentionResolutionTimer = 48; + rach_maxHARQ_Msg3Tx = 4; - ue_TransmissionMode = 2; - - } - ); + pcch_default_PagingCycle = 128; + pcch_nB = "oneT"; + bcch_modificationPeriodCoeff = 2; + ue_TimersAndConstants_t300 = 1000; + ue_TimersAndConstants_t301 = 1000; + ue_TimersAndConstants_t310 = 1000; + ue_TimersAndConstants_t311 = 10000; + ue_TimersAndConstants_n310 = 20; + ue_TimersAndConstants_n311 = 1; + ue_TransmissionMode = 2; + } + ); srb1_parameters : { - # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] timer_poll_retransmit = 80; - + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] timer_reordering = 35; - + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] timer_status_prohibit = 0; - + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] poll_pdu = 4; - + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] poll_byte = 99999; - + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] max_retx_threshold = 4; } - + # ------- SCTP definitions SCTP : { @@ -133,7 +134,7 @@ eNBs = SCTP_INSTREAMS = 2; SCTP_OUTSTREAMS = 2; }; - + ////////// MME parameters: mme_ip_address = ( { ipv4 = "192.168.12.70"; ipv6 = "192:168:30::17"; @@ -142,33 +143,32 @@ eNBs = } ); - NETWORK_INTERFACES : + NETWORK_INTERFACES : { - ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.150/24"; - ENB_INTERFACE_NAME_FOR_S1U = "eth0"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.150/24"; + ENB_INTERFACE_NAME_FOR_S1_MME = "eth1"; + ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.147/24"; + ENB_INTERFACE_NAME_FOR_S1U = "eth1"; + ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.147/24"; ENB_PORT_FOR_S1U = 2152; # Spec 2152 }; - - log_config : + + log_config : { - global_log_level ="info"; - global_log_verbosity ="medium"; - hw_log_level ="info"; - hw_log_verbosity ="medium"; - phy_log_level ="info"; - phy_log_verbosity ="medium"; - mac_log_level ="info"; - mac_log_verbosity ="high"; - rlc_log_level ="info"; - rlc_log_verbosity ="medium"; - pdcp_log_level ="info"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="info"; - rrc_log_verbosity ="medium"; - }; - + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="debug"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; } ); From 7133633997f39d048121d4104794e53158c3f813 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Wed, 23 Nov 2016 15:17:01 +0100 Subject: [PATCH 321/413] bugfixes in precoder --- openair1/PHY/INIT/lte_init.c | 13 +++++++------ openair1/PHY/MODULATION/beamforming.c | 14 ++++++++------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 0009dbfefe..1c0ed16e0f 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1251,12 +1251,13 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, common_vars->beam_weights[eNB_id][i] = (int32_t **)malloc16_clear(fp->nb_antennas_tx*sizeof(int32_t*)); for (j=0; jnb_antennas_tx; j++) { common_vars->beam_weights[eNB_id][i][j] = (int32_t *)malloc16_clear(fp->ofdm_symbol_size*sizeof(int32_t)); - for (re=0; reofdm_symbol_size; re++) - common_vars->beam_weights[eNB_id][i][j][re] = 0x00007fff; -#ifdef DEBUG_PUY - msg("[openair][LTE_PHY][INIT] lte_common_vars->beam_weights[%d][%d][%d] = %p (%d bytes)\n", - eNB_id,i,j,common_vars->beam_weights[eNB_id][i][j], - OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); + if (i==j) + for (re=0; reofdm_symbol_size; re++) + common_vars->beam_weights[eNB_id][i][j][re] = 0x00007fff; +#ifdef DEBUG_PHY + msg("[openair][LTE_PHY][INIT] lte_common_vars->beam_weights[%d][%d][%d] = %p (%d bytes)\n", + eNB_id,i,j,common_vars->beam_weights[eNB_id][i][j], + OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); #endif } } diff --git a/openair1/PHY/MODULATION/beamforming.c b/openair1/PHY/MODULATION/beamforming.c index 3aa7810aec..5e4660f034 100644 --- a/openair1/PHY/MODULATION/beamforming.c +++ b/openair1/PHY/MODULATION/beamforming.c @@ -61,18 +61,19 @@ int beam_precoding(int32_t **txdataF, // clear txdata_BF[aa][re] for each call of ue_spec_beamforming for(aa=0;aanb_antennas_tx;aa++) - memset(txdataF_BF[aa],0,4*(frame_parms->ofdm_symbol_size)); + memset(txdataF_BF[aa],0,sizeof(int32_t)*(frame_parms->ofdm_symbol_size)); for (re=0;reofdm_symbol_size;re++) { for (p=0; p<2; p++) { if (txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { for (aa=0;aanb_antennas_tx;aa++) { - ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); + ((int16_t*)&txdataF_BF[aa][re])[0] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[0][aa][re])[0])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); - /*printf("beamforming.c:txdata[%d][%d]=%d+j%d, beam_weights[%d][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", + /* + printf("beamforming.c:txdataF[%d][%d]=%d+j%d, beam_weights[%d][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", p,slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re, ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0], ((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1], @@ -80,7 +81,8 @@ int beam_precoding(int32_t **txdataF, ((int16_t*)&beam_weights[p][aa][re])[0],((int16_t*)&beam_weights[p][aa][re])[1], aa,re, ((int16_t*)&txdataF_BF[aa][re])[0], - ((int16_t*)&txdataF_BF[aa][re])[1]); */ + ((int16_t*)&txdataF_BF[aa][re])[1]); + */ } } From f216bacb1142dccda5a6df7b1340958c6895ca6c Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Wed, 23 Nov 2016 17:01:22 +0100 Subject: [PATCH 322/413] fix the dlsim for TM7 --- openair1/PHY/INIT/lte_init.c | 2 +- openair1/SCHED/phy_procedures_lte_ue.c | 2 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 20 -------------------- openair1/SIMULATION/LTE_PHY/dlsim_tm7.c | 3 ++- 4 files changed, 4 insertions(+), 23 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 0a212db27b..16a608f4e9 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1251,7 +1251,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, common_vars->beam_weights[eNB_id][i] = (int32_t **)malloc16_clear(fp->nb_antennas_tx*sizeof(int32_t*)); for (j=0; jnb_antennas_tx; j++) { common_vars->beam_weights[eNB_id][i][j] = (int32_t *)malloc16_clear(fp->ofdm_symbol_size*sizeof(int32_t)); - if (i==j) + if (((i<=4) && (i==j)) || (i>=5)) for (re=0; reofdm_symbol_size; re++) common_vars->beam_weights[eNB_id][i][j][re] = 0x00007fff; #ifdef DEBUG_PHY diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 6dfdc7297d..bcf6507e20 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -2354,7 +2354,7 @@ void ue_pdsch_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, int eNB_id, PDSC //TM7 UE specific channel estimation here!!! if (ue->transmission_mode[eNB_id]==7) { if (ue->frame_parms.Ncp==0) { - if ((m==3) || (m==6) || (m==8) || (m==11)) + if ((m==3) || (m==6) || (m==9) || (m==12)) //LOG_D(PHY,"[UE %d] dlsch->active in subframe %d => %d, l=%d\n",phy_vars_ue->Mod_id,subframe_rx,phy_vars_ue->dlsch_ue[eNB_id][0]->active, l); lte_dl_bf_channel_estimation(ue,eNB_id,0,subframe_rx*2+(m>6?1:0),5,m); } else { diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index b94b757adf..c657069e46 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -1808,26 +1808,6 @@ int main(int argc, char **argv) osf, perfect_ce); - /* Check if really needed */ - /*cell_spec_bf_weights = eNB->common_vars.beam_weights[0][0]; - for(aa=0;aaofdm_symbol_size;re++) { - if (n_tx_phy==1 || n_tx_phy==2) - cell_spec_bf_weights[aa][re] = 0x00007fff; - else if (n_tx_phy==4 || n_tx_phy==8) - cell_spec_bf_weights[aa][re] = 0x00007fff>>1; - else if (n_tx_phy==16) - cell_spec_bf_weights[aa][re] = 0x00007fff>>2; - else if (n_tx_phy==64) - cell_spec_bf_weights[aa][re] = 0x00007fff>>4; - } - } - - if (transmission_mode==7) { - lte_gold_ue_spec_port5(eNB->lte_gold_uespec_port5_table[0],Nid_cell,n_rnti); - lte_gold_ue_spec_port5(UE->lte_gold_uespec_port5_table,Nid_cell,n_rnti); - }*/ - eNB->mac_enabled=1; if (two_thread_flag == 0) { eNB->te = dlsch_encoding; diff --git a/openair1/SIMULATION/LTE_PHY/dlsim_tm7.c b/openair1/SIMULATION/LTE_PHY/dlsim_tm7.c index 0d5dcd63ce..66dea185de 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim_tm7.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim_tm7.c @@ -636,6 +636,7 @@ int main(int argc, char **argv) frame_parms = &eNB->frame_parms; + /* cell_spec_bf_weights = eNB->common_vars.beam_weights[0][0]; for(aa=0;aaofdm_symbol_size;re++) { @@ -653,7 +654,7 @@ int main(int argc, char **argv) if (transmission_mode==7){ lte_gold_ue_spec_port5(eNB->lte_gold_uespec_port5_table[0],Nid_cell,n_rnti); lte_gold_ue_spec_port5(UE->lte_gold_uespec_port5_table,Nid_cell,n_rnti); - } + }*/ eNB_id_i = UE->n_connected_eNB; From 953de398a31f0ee1b57b80b51541c5263dcf441b Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 24 Nov 2016 10:46:20 +0100 Subject: [PATCH 323/413] adapt the tm7 configuration file --- .../GENERIC-LTE-EPC/CONF/enb.band7.tm7.exmimo2.conf | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm7.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm7.exmimo2.conf index d26ebbe735..52a8d8ee50 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm7.exmimo2.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm7.exmimo2.conf @@ -23,6 +23,9 @@ eNBs = component_carriers = ( { + node_function = "eNodeB_3GPP"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; frame_type = "FDD"; tdd_config = 3; tdd_config_s = 0; @@ -34,8 +37,8 @@ eNBs = N_RB_DL = 25; Nid_cell_mbsfn = 0; nb_antenna_ports = 1; - nb_antennas_tx = 2; - nb_antennas_rx = 2; + nb_antennas_tx = 1; + nb_antennas_rx = 1; tx_gain = 25; rx_gain = 20; prach_root = 0; From 33e89e3e9f41c8fa1e83c5f7591b3d66a8e0b085 Mon Sep 17 00:00:00 2001 From: GabrirelCouturier Date: Thu, 24 Nov 2016 10:54:37 +0100 Subject: [PATCH 324/413] [OAI-UE] fix for issue#32 1- timing Advance fix 2- harq UL fix --- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 49 ++++++++++--------- openair1/PHY/LTE_TRANSPORT/phich.c | 15 ++++-- openair1/PHY/LTE_TRANSPORT/ulsch_coding.c | 2 +- openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c | 3 +- openair1/SCHED/phy_procedures_lte_ue.c | 22 +++++++-- 5 files changed, 59 insertions(+), 32 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index c55290adf8..107fa042a6 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -6444,29 +6444,30 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, // UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx); //#endif - - ulsch->harq_processes[harq_pid] = ulsch->harq_processes[8]; - ulsch->harq_processes[harq_pid]->round++; - //LOG_I(PHY," Adaptative retransmission - copy temporary harq Process to current harq process. [harqId %d round %d] \n",harq_pid, ulsch->harq_processes[8]->round); - - - if (ulsch->harq_processes[harq_pid]->round >= UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx) + if (ulsch->harq_processes[harq_pid]->round > 0) // NACK detected on phich { - ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 0; - ulsch->harq_processes[harq_pid]->round = 0; - ulsch->harq_processes[harq_pid]->status = IDLE; - //LOG_I(PHY," PUSCH MAX Retransmission acheived ==> flush harq buff (%d) \n",harq_pid); - //LOG_I(PHY," [HARQ-UL harqId: %d] Adaptative retransmission NACK MAX RETRANS(%d) ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag, ulsch->harq_processes[harq_pid]->round); - } - else - { - // ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 1; - uint8_t rv_table[4] = {0, 2, 3, 1}; - ulsch->harq_processes[harq_pid]->rvidx = rv_table[ulsch->harq_processes[harq_pid]->round&3]; - ulsch->O_RI = 0; - ulsch->O = 0; - ulsch->uci_format = HLC_subband_cqi_nopmi; - //LOG_I(PHY," [HARQ-UL harqId: %d] Adaptative retransmission NACK ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag,ulsch->harq_processes[harq_pid]->round); + // ulsch->harq_processes[harq_pid]->round++; already done on phich_rx + ulsch->harq_processes[harq_pid] = ulsch->harq_processes[8]; + // LOG_I(PHY," Adaptative retransmission - copy temporary harq Process to current harq process. [harqId %d round %d] \n",harq_pid, ulsch->harq_processes[8]->round); + + if (ulsch->harq_processes[harq_pid]->round >= UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx) + { + ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 0; + ulsch->harq_processes[harq_pid]->round = 0; + ulsch->harq_processes[harq_pid]->status = IDLE; + //LOG_I(PHY," PUSCH MAX Retransmission acheived ==> flush harq buff (%d) \n",harq_pid); + //LOG_I(PHY," [HARQ-UL harqId: %d] Adaptative retransmission NACK MAX RETRANS(%d) ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag, ulsch->harq_processes[harq_pid]->round); + } + else + { + // ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 1; + uint8_t rv_table[4] = {0, 2, 3, 1}; + ulsch->harq_processes[harq_pid]->rvidx = rv_table[ulsch->harq_processes[harq_pid]->round&3]; + ulsch->O_RI = 0; + ulsch->O = 0; + ulsch->uci_format = HLC_subband_cqi_nopmi; + //LOG_I(PHY," [HARQ-UL harqId: %d] Adaptative retransmission NACK ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag,ulsch->harq_processes[harq_pid]->round); + } } } @@ -7087,7 +7088,8 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, // ulsch->n_DMRS2 = ((DCI0_5MHz_TDD_1_6_t *)dci_pdu)->cshift; -#ifdef DEBUG_DCI + #ifdef DEBUG_DCI + printf("Format 0 DCI : ulsch (ue): AbsSubframe %d.%d\n",proc->frame_rx,subframe); printf("Format 0 DCI : ulsch (ue): NBRB %d\n",ulsch->harq_processes[harq_pid]->nb_rb); printf("Format 0 DCI :ulsch (ue): first_rb %d\n",ulsch->harq_processes[harq_pid]->first_rb); printf("Format 0 DCI :ulsch (ue): rballoc %d\n",rballoc); @@ -7106,6 +7108,7 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, printf("Format 0 DCI :ulsch (ue): Nsymb_pusch %d\n",ulsch->Nsymb_pusch); printf("Format 0 DCI :ulsch (ue): cshift %d\n",ulsch->harq_processes[harq_pid]->n_DMRS2); + printf("Format 0 DCI :ulsch (ue): phich status %d\n",ulsch->harq_processes[harq_pid]->status); #else UNUSED_VARIABLE(dai); #endif diff --git a/openair1/PHY/LTE_TRANSPORT/phich.c b/openair1/PHY/LTE_TRANSPORT/phich.c index dc46f0505c..2d07ba948a 100644 --- a/openair1/PHY/LTE_TRANSPORT/phich.c +++ b/openair1/PHY/LTE_TRANSPORT/phich.c @@ -1386,11 +1386,20 @@ void rx_phich(PHY_VARS_UE *ue, // ulsch->harq_processes[harq_pid]->Ndi = 0; ulsch->harq_processes[harq_pid]->round++; - if (ulsch->harq_processes[harq_pid]->round >= UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx) + if ( ulsch->harq_processes[harq_pid]->round >= (UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx - 1) ) { - ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 0; - ulsch->harq_processes[harq_pid]->round = 0; + // this is last push re transmission + ulsch->harq_processes[harq_pid]->rvidx = rv_table[ulsch->harq_processes[harq_pid]->round&3]; + ulsch->O_RI = 0; + ulsch->O = 0; + ulsch->uci_format = HLC_subband_cqi_nopmi; + + // disable phich decoding since it is the last retransmission ulsch->harq_processes[harq_pid]->status = IDLE; + + //ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 0; + //ulsch->harq_processes[harq_pid]->round = 0; + //LOG_I(PHY,"PUSCH MAX Retransmission acheived ==> flush harq buff (%d) \n",harq_pid); //LOG_I(PHY,"[HARQ-UL harqId: %d] PHICH NACK MAX RETRANS(%d) ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag, ulsch->harq_processes[harq_pid]->round); } diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c index 48048bf5de..6d2d6232cb 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c @@ -503,7 +503,7 @@ uint32_t ulsch_encoding(uint8_t *a, /* LOG_I(PHY,"ULSCH Encoding G %d, Q_RI %d (O_RI%d, Msc_initial %d, Nsymb_initial%d, beta_offset_ri_times8 %d), Q_CQI %d \n",G,Q_RI,ulsch->O_RI,ulsch->harq_processes[harq_pid]->Msc_initial,ulsch->harq_processes[harq_pid]->Nsymb_initial,ulsch->beta_offset_ri_times8,Q_CQI); - LOG_I(PHY,"ulsch_decoding (Nid_cell %d, rnti %x): harq_pid %d round %d, RV %d, mcs %d, O_RI %d, O_ACK %d, G %d\n", + LOG_I(PHY,"ULSCH Encoding (Nid_cell %d, rnti %x): harq_pid %d round %d, RV %d, mcs %d, O_RI %d, O_ACK %d, G %d\n", frame_parms->Nid_cell,ulsch->rnti, harq_pid, ulsch->harq_processes[harq_pid]->round, diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c index 02323d6ccd..ee9bfc53cd 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_modulation.c @@ -424,9 +424,8 @@ void ulsch_modulation(int32_t **txdataF, Q_m = get_Qm_ul(ulsch->harq_processes[harq_pid]->mcs); - //G = (int)ulsch->harq_processes[harq_pid]->nb_rb * (12 * Q_m) * (ulsch->Nsymb_pusch); + G = (int)ulsch->harq_processes[harq_pid]->nb_rb * (12 * Q_m) * (ulsch->Nsymb_pusch); - G = ulsch->harq_processes[harq_pid]->G; // Mapping nsymb = (frame_parms->Ncp==0) ? 14:12; diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 92eee4a99d..6e7354f883 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -944,9 +944,18 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc) { #if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)//this is the EXPRESS MIMO case ulsch_start = (ue->rx_offset+subframe_tx*frame_parms->samples_per_tti- - ue->hw_timing_advance- - ue->timing_advance- - ue->N_TA_offset+5)%(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti); + ue->hw_timing_advance- + ue->timing_advance- + ue->N_TA_offset+5); + //LOG_E(PHY,"ul-signal [subframe: %d, ulsch_start %d]\n",subframe_tx, ulsch_start); + + if(ulsch_start < 0) + ulsch_start = ulsch_start + (LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti); + + if (ulsch_start > (LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti)) + ulsch_start = ulsch_start % (LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti); + + //LOG_E(PHY,"ul-signal [subframe: %d, ulsch_start %d]\n",subframe_tx, ulsch_start); #else //this is the normal case ulsch_start = (frame_parms->samples_per_tti*subframe_tx)-ue->N_TA_offset; //-ue->timing_advance; #endif //else EXMIMO @@ -1214,6 +1223,13 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB // deactivate service request // ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 0; + LOG_D(PHY,"Generating PUSCH (Abssubframe: %d.%d): harq-Id: %d, round: %d, MaxReTrans: %d \n",frame_tx,subframe_tx,harq_pid,ue->ulsch[eNB_id]->harq_processes[harq_pid]->round,UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx); + if (ue->ulsch[eNB_id]->harq_processes[harq_pid]->round >= (UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx - 1)) + { + LOG_D(PHY,"PUSCH MAX Retransmission acheived ==> send last pusch (%d) \n"); + ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 0; + ue->ulsch[eNB_id]->harq_processes[harq_pid]->round = 0; + } ack_status = get_ack(&ue->frame_parms, ue->dlsch[eNB_id][0]->harq_ack, From 7715900222394b7c98f772913748e0346bd1a793 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Thu, 24 Nov 2016 14:42:06 +0100 Subject: [PATCH 325/413] some more bugfixes (old and introcuded by merge) plus ability too use phy-test for tm7 --- openair1/PHY/INIT/lte_init.c | 10 +++++- openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c | 34 +++++++------------ openair1/PHY/MODULATION/beamforming.c | 9 +++-- openair1/SCHED/phy_mac_stub.c | 2 ++ .../CONF/enb.band7.tm1.usrpb210.conf | 4 +-- targets/RT/USER/lte-enb.c | 15 ++++++-- targets/RT/USER/lte-softmodem.c | 20 +++++++++-- 7 files changed, 61 insertions(+), 33 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 16a608f4e9..5dd747de92 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -1251,9 +1251,17 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, common_vars->beam_weights[eNB_id][i] = (int32_t **)malloc16_clear(fp->nb_antennas_tx*sizeof(int32_t*)); for (j=0; jnb_antennas_tx; j++) { common_vars->beam_weights[eNB_id][i][j] = (int32_t *)malloc16_clear(fp->ofdm_symbol_size*sizeof(int32_t)); - if (((i<=4) && (i==j)) || (i>=5)) + // antenna ports 0-3 are mapped on antennas 0-3 + // antenna port 4 is mapped on antenna 0 + // antenna ports 5-14 are mapped on all antennas + if (((i<4) && (i==j)) || ((i==4) && (j==0))) { for (re=0; reofdm_symbol_size; re++) common_vars->beam_weights[eNB_id][i][j][re] = 0x00007fff; + } + else if (i>4) { + for (re=0; reofdm_symbol_size; re++) + common_vars->beam_weights[eNB_id][i][j][re] = 0x00007fff/fp->nb_antennas_tx; + } #ifdef DEBUG_PHY msg("[openair][LTE_PHY][INIT] lte_common_vars->beam_weights[%d][%d][%d] = %p (%d bytes)\n", eNB_id,i,j,common_vars->beam_weights[eNB_id][i][j], diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c index 84e4bddec2..d6e680344b 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c @@ -678,15 +678,11 @@ x0[1+*jj]); case 2: //QPSK // printf("re %d %d(%d) : %d,%d => ",re,tti_offset,*jj,((int16_t*)&txdataF[0][tti_offset])[0],((int16_t*)&txdataF[0][tti_offset])[1]); - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t*)&txdataF[aa][tti_offset])[0] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i - } + ((int16_t*)&txdataF[0][tti_offset])[0] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //I //b_i *jj = *jj + 1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t*)&txdataF[aa][tti_offset])[1] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} - } + ((int16_t*)&txdataF[0][tti_offset])[1] += (x0[*jj]==1) ? (-gain_lin_QPSK) : gain_lin_QPSK; //Q //b_{i+1} *jj = *jj + 1; @@ -719,12 +715,10 @@ x0[1+*jj]); *jj=*jj+1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s0[qam16_table_offset_re]; - ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s0[qam16_table_offset_im]; - // ((int16_t *)&txdataF[aa][tti_offset])[0]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); - // ((int16_t *)&txdataF[aa][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); - } + ((int16_t *)&txdataF[0][tti_offset])[0]+=qam_table_s0[qam16_table_offset_re]; + ((int16_t *)&txdataF[0][tti_offset])[1]+=qam_table_s0[qam16_table_offset_im]; + // ((int16_t *)&txdataF[aa][tti_offset])[0]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); + // ((int16_t *)&txdataF[aa][tti_offset])[1]+=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); break; @@ -764,10 +758,8 @@ x0[1+*jj]); *jj=*jj+1; - for (aa=0; aanb_antennas_tx; aa++) { - ((int16_t *)&txdataF[aa][tti_offset])[0]+=qam_table_s0[qam64_table_offset_re]; - ((int16_t *)&txdataF[aa][tti_offset])[1]+=qam_table_s0[qam64_table_offset_im]; - } + ((int16_t *)&txdataF[0][tti_offset])[0]+=qam_table_s0[qam64_table_offset_re]; + ((int16_t *)&txdataF[0][tti_offset])[1]+=qam_table_s0[qam64_table_offset_im]; break; @@ -970,7 +962,7 @@ x0[1+*jj]); *re_allocated = *re_allocated + 1; - if (frame_parms->nb_antennas_tx == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { switch (mod_order0) { default: LOG_E(PHY,"Unknown mod_order0 %d\n",mod_order0); @@ -1186,7 +1178,7 @@ x0[1+*jj]); ((int16_t*)&txdataF[0][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample1)[0]*ONE_OVER_SQRT2_Q15)>>15); ((int16_t*)&txdataF[0][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample1)[1]*ONE_OVER_SQRT2_Q15)>>15); - if (frame_parms->nb_antennas_tx == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { layer1prec2A(&tmp_sample1,&tmp_sample2,precoder_index); ((int16_t*)&txdataF[1][tti_offset])[0] += (int16_t)((((int16_t*)&tmp_sample2)[0]*ONE_OVER_SQRT2_Q15)>>15); ((int16_t*)&txdataF[1][tti_offset])[1] += (int16_t)((((int16_t*)&tmp_sample2)[1]*ONE_OVER_SQRT2_Q15)>>15); @@ -1226,7 +1218,7 @@ x0[1+*jj]); ((int16_t *)&txdataF[0][tti_offset])[0] += ((int16_t*)&tmp_sample1)[0]; ((int16_t *)&txdataF[0][tti_offset])[1] += ((int16_t*)&tmp_sample1)[1]; - if (frame_parms->nb_antennas_tx == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { layer1prec2A(&tmp_sample1,&tmp_sample2,precoder_index); ((int16_t*)&txdataF[1][tti_offset])[0] += ((int16_t*)&tmp_sample2)[0]; ((int16_t*)&txdataF[1][tti_offset])[1] += ((int16_t*)&tmp_sample2)[1]; @@ -1276,7 +1268,7 @@ x0[1+*jj]); ((int16_t *)&txdataF[0][tti_offset])[0] += ((int16_t*)&tmp_sample1)[0]; ((int16_t *)&txdataF[0][tti_offset])[1] += ((int16_t*)&tmp_sample1)[1]; - if (frame_parms->nb_antennas_tx == 2) { + if (frame_parms->nb_antenna_ports_eNB == 2) { layer1prec2A(&tmp_sample1,&tmp_sample2,precoder_index); ((int16_t*)&txdataF[1][tti_offset])[0] += ((int16_t*)&tmp_sample2)[0]; ((int16_t*)&txdataF[1][tti_offset])[1] += ((int16_t*)&tmp_sample2)[1]; @@ -1284,7 +1276,7 @@ x0[1+*jj]); break; - } + } } if (mimo_mode == ALAMOUTI) { diff --git a/openair1/PHY/MODULATION/beamforming.c b/openair1/PHY/MODULATION/beamforming.c index 5e4660f034..75321daee0 100644 --- a/openair1/PHY/MODULATION/beamforming.c +++ b/openair1/PHY/MODULATION/beamforming.c @@ -84,14 +84,13 @@ int beam_precoding(int32_t **txdataF, ((int16_t*)&txdataF_BF[aa][re])[1]); */ } - } } if (txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually using TM7 for (aa=0;aanb_antennas_tx;aa++) { - ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[5][aa][re])[0])>>15); + ((int16_t*)&txdataF_BF[aa][re])[0] += (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[5][aa][re])[0])>>15); ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[5][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[5][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[5][aa][re])[1])>>15); ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[5][aa][re])[0])>>15); /* printf("beamforming.c:txdata[5][%d]=%d+j%d, beam_weights[5][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", @@ -112,9 +111,9 @@ int beam_precoding(int32_t **txdataF, for (p=7;p<15;p++) { if (txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually allocated for (aa=0;aanb_antennas_tx;aa++) { - ((int16_t*)&txdataF_BF[aa][re])[0] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); + ((int16_t*)&txdataF_BF[aa][re])[0] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] = (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); } } diff --git a/openair1/SCHED/phy_mac_stub.c b/openair1/SCHED/phy_mac_stub.c index cae8b8c82e..9051127dbf 100644 --- a/openair1/SCHED/phy_mac_stub.c +++ b/openair1/SCHED/phy_mac_stub.c @@ -63,6 +63,8 @@ void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) uint32_t bcch_pdu; uint64_t dlsch_pdu; + LOG_I(PHY,"frame %d, subframe %d, transmission_mode %d\n",proc->frame_tx,proc->subframe_tx,transmission_mode); + DCI_pdu->Num_common_dci = 0; DCI_pdu->Num_ue_spec_dci=0; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf index 5ef5a4f50b..2942832d94 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -37,8 +37,8 @@ eNBs = N_RB_DL = 25; Nid_cell_mbsfn = 0; nb_antenna_ports = 1; - nb_antennas_tx = 1; - nb_antennas_rx = 1; + nb_antennas_tx = 2; + nb_antennas_rx = 2; tx_gain = 90; rx_gain = 125; prach_root = 0; diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 965894cac0..3eef00ef29 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -128,6 +128,8 @@ extern pthread_cond_t sync_cond; extern pthread_mutex_t sync_mutex; extern int sync_var; +extern transmission_mode; + //pthread_t main_eNB_thread; time_stats_t softmodem_stats_mt; // main thread @@ -467,8 +469,17 @@ void proc_tx_full(PHY_VARS_eNB *eNB, // if TX fronthaul go ahead if (eNB->tx_fh) eNB->tx_fh(eNB,proc); - - + /* + if (proc->frame_tx>1000) { + write_output("/tmp/txsig0.m","txs0", &eNB->common_vars.txdata[eNB->Mod_id][0][0], eNB->frame_parms.samples_per_tti*10,1,1); + write_output("/tmp/txsigF0.m","txsF0", &eNB->common_vars.txdataF[eNB->Mod_id][0][0],eNB->frame_parms.symbols_per_tti*eNB->frame_parms.ofdm_symbol_size*10,1,1); + write_output("/tmp/txsig1.m","txs1", &eNB->common_vars.txdata[eNB->Mod_id][1][0], eNB->frame_parms.samples_per_tti*10,1,1); + write_output("/tmp/txsigF1.m","txsF1", &eNB->common_vars.txdataF[eNB->Mod_id][1][0],eNB->frame_parms.symbols_per_tti*eNB->frame_parms.ofdm_symbol_size*10,1,1); + if (transmission_mode == 7) + write_output("/tmp/txsigF5.m","txsF5", &eNB->common_vars.txdataF[eNB->Mod_id][5][0],eNB->frame_parms.symbols_per_tti*eNB->frame_parms.ofdm_symbol_size*10,1,1); + exit_fun(""); + } + */ } void proc_tx_rru_if4p5(PHY_VARS_eNB *eNB, diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index d2362081de..3cb01c876a 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -234,7 +234,7 @@ uint64_t num_missed_slots=0; // counter for the number of missed slots extern void reset_opp_meas(void); extern void print_opp_meas(void); -//int transmission_mode=1; +int transmission_mode=1; int16_t glog_level = LOG_INFO; int16_t glog_verbosity = LOG_MED; @@ -1189,8 +1189,13 @@ static void get_options (int argc, char **argv) printf("Downlink frequency/ uplink offset of CC_id %d set to %ju/%d\n", CC_id, enb_properties->properties[i]->downlink_frequency[CC_id], enb_properties->properties[i]->uplink_frequency_offset[CC_id]); + } // CC_id }// i + + //this is needed for phy-test option + transmission_mode = enb_properties->properties[0]->ue_TransmissionMode[0]+1; + } else if (UE_flag == 1) { if (conf_config_file_name != NULL) { @@ -1363,7 +1368,7 @@ void init_openair0() { int main( int argc, char **argv ) { - int i,aa; + int i,j,k,aa,re; #if defined (XFORMS) void *status; #endif @@ -1606,6 +1611,17 @@ int main( int argc, char **argv ) PHY_vars_eNB_g[0][CC_id]->ue_ul_nb_rb=6; PHY_vars_eNB_g[0][CC_id]->target_ue_ul_mcs=target_ul_mcs; + // initialization for phy-test + for (k=0;ktransmission_mode[k] = transmission_mode; + if (transmission_mode==7) + lte_gold_ue_spec_port5(PHY_vars_eNB_g[0][CC_id]->lte_gold_uespec_port5_table[k],frame_parms[CC_id]->Nid_cell,0x1235+k); + } + if ((transmission_mode==1) || (transmission_mode==7)) { + for (j=0; jnb_antennas_tx; j++) + for (re=0; reofdm_symbol_size; re++) + PHY_vars_eNB_g[0][CC_id]->common_vars.beam_weights[0][0][j][re] = 0x00007fff/frame_parms[CC_id]->nb_antennas_tx; + } if (phy_test==1) PHY_vars_eNB_g[0][CC_id]->mac_enabled = 0; else PHY_vars_eNB_g[0][CC_id]->mac_enabled = 1; From 0c52c76df62b838cc3c6dfc44038ddfbc2be8de0 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Thu, 24 Nov 2016 14:58:51 +0100 Subject: [PATCH 326/413] add RRH test cases --- cmake_targets/autotests/README.txt | 6 +- .../autotests/run_exec_lte-softmodem_tests.py | 2 + cmake_targets/autotests/test_case_list.xml | 946 ++++++++++-------- 3 files changed, 554 insertions(+), 400 deletions(-) diff --git a/cmake_targets/autotests/README.txt b/cmake_targets/autotests/README.txt index 2a1b57c0b2..cf0e972b08 100644 --- a/cmake_targets/autotests/README.txt +++ b/cmake_targets/autotests/README.txt @@ -218,7 +218,7 @@ Obj.# Case# Test# Description 01 70 05 Band 7 FDD 20MHz DL Throughput for 300 sec for 1TX/1RX -01 75 00 lte-softmodem + RRH tests with B210 RF as eNB and ALU EPC w/ Bandrich COTS UE for TX/1RX +01 75 00 lte-softmodem + RRU (NGFI IF4P5, RAW) tests with B210 RF as eNB and ALU EPC w/ Bandrich COTS UE for TX/1RX 01 75 00 Band 7 FDD 5MHz UL Throughput for 300 sec for 1TX/1RX 01 75 01 Band 7 FDD 10MHz UL Throughput for 300 sec for 1TX/1RX 01 75 02 Band 7 FDD 20MHz UL Throughput for 300 sec for 1TX/1RX @@ -226,7 +226,7 @@ Obj.# Case# Test# Description 01 75 04 Band 7 FDD 10MHz DL Throughput for 300 sec for 1TX/1RX 01 75 05 Band 7 FDD 20MHz DL Throughput for 300 sec for 1TX/1RX -01 80 00 lte-softmodem + RRH tests with BladeRF RF as eNB and ALU EPC w/ Bandrich COTS UE for TX/1RX +01 80 00 lte-softmodem + RRU (NGFI) tests with BladeRF RF as eNB and ALU EPC w/ Bandrich COTS UE for TX/1RX 01 80 00 Band 7 FDD 5MHz UL Throughput for 300 sec for 1TX/1RX 01 80 01 Band 7 FDD 10MHz UL Throughput for 300 sec for 1TX/1RX 01 80 02 Band 7 FDD 20MHz UL Throughput for 300 sec for 1TX/1RX @@ -234,7 +234,7 @@ Obj.# Case# Test# Description 01 80 04 Band 7 FDD 10MHz DL Throughput for 300 sec for 1TX/1RX 01 80 05 Band 7 FDD 20MHz DL Throughput for 300 sec for 1TX/1RX -01 85 00 lte-softmodem + RRH tests with USRP X310 RF as eNB and ALU EPC w/ Bandrich COTS UE for TX/1RX +01 85 00 lte-softmodem + RRU (NGFI) tests with USRP X310 RF as eNB and ALU EPC w/ Bandrich COTS UE for TX/1RX 01 85 00 Band 7 FDD 5MHz UL Throughput for 300 sec for 1TX/1RX 01 85 01 Band 7 FDD 10MHz UL Throughput for 300 sec for 1TX/1RX 01 85 02 Band 7 FDD 20MHz UL Throughput for 300 sec for 1TX/1RX diff --git a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py index 796235a77f..ba54fa38b3 100755 --- a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py +++ b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py @@ -575,6 +575,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , tags = testcase.findtext('tags',default='') RRHMachine = testcase.findtext('RRH',default='') + RRH_config_file = testcase.findtext('RRH_config_file',default='') RRH_compile_prog = testcase.findtext('RRH_compile_prog',default='') RRH_compile_prog_args = testcase.findtext('RRH_compile_prog_args',default='') RRH_pre_exec = testcase.findtext('RRH_pre_exec',default='') @@ -710,6 +711,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , task_RRH_compile = ' ( uname -a ; date \n' task_RRH_compile = task_RRH_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' task_RRH_compile = task_RRH_compile + 'env |grep OPENAIR \n' + task_RRH_compile = task_RRH_compile + update_config_file(oai_RRH, RRH_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' if RRH_compile_prog != "": task_RRH_compile = task_RRH_compile + ' ( ' + RRH_compile_prog + ' '+ RRH_compile_prog_args + ' ) > ' + logfile_compile_RRH + ' 2>&1 \n' task_RRH_compile = task_RRH_compile + ' date ) > ' + logfile_task_RRH_compile_out + ' 2>&1 ' diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index f882ea7ee8..3d9e7f19e6 100644 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -1,7 +1,7 @@ -mozart hutch starsky stevens amerique calisson nano +amerique mozart hutch starsky stevens calisson nano superserver /mnt/sradio/TEST_RESULTS/ https://gitlab.eurecom.fr/oai/openairinterface5g.git https://gitlab.eurecom.fr/oai/openair-cn.git @@ -11,9 +11,9 @@ sudo -S -E /opt/ltebox/tools/stop_ltebox exmimo_pci=`lspci -m | grep Xilinx`; if [ -n "$exmimo_pci" ] ; then $OPENAIR_DIR/cmake_targets/build_oai -w EXMIMO -c; sudo -S -E $OPENAIR_DIR/cmake_targets/tools/stop_exmimo2; fi; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_huaweiE398_ue.py --reset-ue; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue; uname -a; sudo -E dmesg 36000 - 010141 0102+ 010301 010303 010304 010305 0104+ 015508 015511 015520 015523 015518 015519 015520 015521 015522 015523 015602 015605 015702 015705 015818 015819 015820 015821 015822 015823 016102 016105 016502 016505 017002 017005 017502 017505 018002 018005 018502 018505 025514 025517 025520 025523 025518 025519 025520 025521 025522 025523 + 010141 0102+ 010301 010303 010304 010305 0104+ 015508 015511 015520 015523 015518 015519 015520 015521 015522 015523 015602 015605 015702 015705 015818 015819 015820 015821 015822 015823 016102 016105 016502 016505 017002 017005 018002 018005 018502 018505 025514 025517 025520 025523 025518 025519 025520 025521 025522 025523 3 - mozart hutch starsky stevens amerique calisson + amerique mozart hutch starsky stevens calisson superserver compilation Build oaisim.Rel8 @@ -1025,7 +1025,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -1040,7 +1040,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s @@ -1100,7 +1100,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -1115,7 +1115,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s @@ -1175,7 +1175,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -1190,7 +1190,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14M -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14M @@ -1249,7 +1249,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -1322,7 +1322,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -1396,7 +1396,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -1473,7 +1473,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -1550,7 +1550,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -1626,7 +1626,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread -E + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf -E @@ -1702,7 +1702,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -1778,7 +1778,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -1855,7 +1855,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread -E + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf -E @@ -1929,7 +1929,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -2004,7 +2004,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -2079,7 +2079,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -2153,7 +2153,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -2226,7 +2226,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -2300,7 +2300,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -2379,7 +2379,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -2456,7 +2456,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -2532,7 +2532,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread -E + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf -E @@ -2608,7 +2608,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -2684,7 +2684,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -2761,7 +2761,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread -E + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf -E @@ -2854,7 +2854,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s @@ -2938,7 +2938,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s @@ -3022,7 +3022,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -3106,7 +3106,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m throughput_test min=00.0Mbits/sec max=10.5Mbits/sec average=11.0Mbits/sec @@ -3190,7 +3190,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m throughput_test min=0.0Mbits/sec max=21.0Mbits/sec average=22.0Mbits/sec @@ -3274,7 +3274,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m throughput_test min=0.0Mbits/sec max=42.0Mbits/sec average=44.0Mbits/sec @@ -3358,7 +3358,7 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s @@ -3452,7 +3452,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s @@ -3546,7 +3546,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -3640,7 +3640,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf3_script 1 ppp0 -c 192.172.0.1 -i 1 -u -f m -B 192.172.0.2 -b 10M -R + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf3_script 1 ppp0 -c 192.172.0.1 -i 1 -u -f m -b 10M -R throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec @@ -3734,7 +3734,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf3_script 1 ppp0 -c 192.172.0.1 -i 1 -u -f m -B 192.172.0.2 -b 10M -R + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf3_script 1 ppp0 -c 192.172.0.1 -i 1 -u -f m -b 10M -R throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec @@ -3827,7 +3827,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf3_script 1 ppp0 -c 192.172.0.1 -i 1 -u -f m -B 192.172.0.2 -b 9M -R + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf3_script 1 ppp0 -c 192.172.0.1 -i 1 -u -f m -b 9M -R throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec @@ -3904,7 +3904,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf @@ -3918,7 +3918,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s @@ -3976,7 +3976,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf @@ -3990,7 +3990,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s @@ -4048,7 +4048,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf @@ -4063,7 +4063,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 17Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 17Mbits/s @@ -4120,7 +4120,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf @@ -4191,7 +4191,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf @@ -4263,7 +4263,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf @@ -4334,7 +4334,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf @@ -4348,7 +4348,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -c 192.172.0.1 -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -c 192.172.0.1 @@ -4406,7 +4406,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf @@ -4420,7 +4420,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -c 192.172.0.1 -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -c 192.172.0.1 @@ -4478,7 +4478,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf @@ -4493,7 +4493,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -c 192.172.0.1 -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -c 192.172.0.1 @@ -4550,7 +4550,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf @@ -4621,7 +4621,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf @@ -4693,7 +4693,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpx310.conf @@ -4766,7 +4766,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf @@ -4780,7 +4780,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s @@ -4840,7 +4840,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf @@ -4854,7 +4854,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s @@ -4914,7 +4914,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf @@ -4929,7 +4929,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 28Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 28Mbits/s @@ -4988,7 +4988,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf @@ -5061,7 +5061,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf @@ -5135,7 +5135,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf @@ -5208,7 +5208,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf @@ -5222,7 +5222,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -c 192.172.0.1 -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -c 192.172.0.1 @@ -5282,7 +5282,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf @@ -5296,7 +5296,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -c 192.172.0.1 -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -c 192.172.0.1 @@ -5356,7 +5356,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf @@ -5371,7 +5371,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -c 192.172.0.1 -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -c 192.172.0.1 @@ -5430,7 +5430,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf @@ -5503,7 +5503,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf @@ -5577,7 +5577,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_usrpb210.py --stop-usrpb210 ; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S /usr/local/bin/niusrprio_pcie start ; dmesg|tail $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpx310.conf @@ -5665,7 +5665,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -5748,7 +5748,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -5911,7 +5911,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m throughput_test min=00.0Mbits/sec max=10.5Mbits/sec average=11.0Mbits/sec @@ -5992,7 +5992,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m throughput_test min=0.0Mbits/sec max=21.0Mbits/sec average=22.0Mbits/sec @@ -6074,7 +6074,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m throughput_test min=0.0Mbits/sec max=21.0Mbits/sec average=22.0Mbits/sec @@ -6140,7 +6140,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S $OPENAIR_DIR/cmake_targets/tools/stop_exmimo2; dmesg|tail $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf @@ -6154,7 +6154,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s @@ -6212,7 +6212,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S $OPENAIR_DIR/cmake_targets/tools/stop_exmimo2 ; dmesg|tail $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf @@ -6227,7 +6227,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s @@ -6300,7 +6300,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -6357,7 +6357,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S $OPENAIR_DIR/cmake_targets/tools/stop_exmimo2 ; dmesg|tail $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf @@ -6428,7 +6428,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S $OPENAIR_DIR/cmake_targets/tools/stop_exmimo2 ; dmesg|tail $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf @@ -6499,7 +6499,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E -S $OPENAIR_DIR/cmake_targets/tools/stop_exmimo2 ; dmesg|tail $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.conf @@ -6588,7 +6588,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -6671,7 +6671,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -6752,7 +6752,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -6833,7 +6833,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m throughput_test min=00.0Mbits/sec max=10.5Mbits/sec average=11.0Mbits/sec @@ -6914,7 +6914,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m throughput_test min=0.0Mbits/sec max=21.0Mbits/sec average=22.0Mbits/sec @@ -6995,7 +6995,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m throughput_test min=0.0Mbits/sec max=21.0Mbits/sec average=22.0Mbits/sec @@ -7080,7 +7080,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -7156,7 +7156,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -7231,7 +7231,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -7306,7 +7306,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m False sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue @@ -7379,7 +7379,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m throughput_test min=0.0Mbits/sec max=9.0Mbits/sec average=8.5Mbits/sec @@ -7454,7 +7454,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m throughput_test min=0.0Mbits/sec max=15.0Mbits/sec average=15.0Mbits/sec @@ -7529,7 +7529,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -7605,7 +7605,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -7680,7 +7680,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s @@ -7755,7 +7755,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m False sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue @@ -7828,7 +7828,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m throughput_test min=0.0Mbits/sec max=9.0Mbits/sec average=8.5Mbits/sec @@ -7903,7 +7903,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m throughput_test min=0.0Mbits/sec max=15.0Mbits/sec average=15.0Mbits/sec @@ -7935,67 +7935,90 @@ c lte-softmodem - calisson + superserver stevens amerique - mozart + hutch 390 /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mobile_network_code \"92\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf downlink_frequency 2660000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf pdsch_referenceSignalPower -26 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth6\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.111/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth6\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.111/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_PORT_FOR_S1U 2152 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf rrh_gw_config "local_if_name=\"eth0\";remote_address=\"10:60:4b:75:80:83\";local_address=\"98:90:96:df:66:07\";local_port=50000;remote_port=50000;tr_preference=\"raw\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=70;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_function \"NGFI_RCC_IF4p5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_timing \"synch_to_ext_device\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_synch_ref 0 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -24 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antenna_ports 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ue_TransmissionMode 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth6\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf rrh_gw_config "local_if_name=\"em2\";remote_address=\"00:25:90:f0:f1:2f\";local_address=\"0c:c4:7a:82:95:95\";local_port=50000;remote_port=50000;tr_preference=\"raw_if4p5\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=80;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" + $OPENAIR_DIR/cmake_targets/build_oai - --eNB -w None -t ETHERNET -x -c --disable-deadline + --eNB -w None -t ETHERNET -x -c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - sleep 5; sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf + sleep 30; sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf False + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_function \"NGFI_RRU_IF4p5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_timing \"synch_to_ext_device\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_synch_ref 0 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -24 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antenna_ports 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf ue_TransmissionMode 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf rrh_gw_config "local_if_name=\"eth3\";remote_address=\"0c:c4:7a:82:95:95\";local_address=\"00:25:90:f0:f1:2f\";local_port=50000;remote_port=50000;tr_preference=\"raw_if4p5\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=80;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" $OPENAIR_DIR/cmake_targets/build_oai - --RRH -w USRP -t ETHERNET -c --disable-deadline + --eNB -w USRP -t ETHERNET -c -x $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/rrh_gw/build/rrh_gw - -n1 -x -m1 -i eth1 + sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf False - - /tmp $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 7Mbits/s False - sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue /tmp @@ -8012,10 +8035,10 @@ c $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 5 lo -s -i 1 -u -f m - throughput_test min=0.0Mbits/sec max=1.0Mbits/sec average=1.0Mbits/sec + throughput_test min=0.0Mbits/sec max=5.0Mbits/sec average=5.0Mbits/sec False - USRPb210.RRH.ALU_EPC.Bandrich.5MHz.FDD.Band_7.UL.1TX.1RX + USRPb210.RRH.IF4P5.ALU_EPC.SonyExperiaM4.5MHz.FDD.UDP.Band_7.UL.1TX.1RX 10 @@ -8023,65 +8046,91 @@ c lte-softmodem - calisson - mozart + superserver stevens amerique + hutch 390 /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mobile_network_code \"92\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf N_RB_DL 50 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf downlink_frequency 2660000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf pdsch_referenceSignalPower -29 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth6\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.111/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth6\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.111/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_PORT_FOR_S1U 2152 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf rrh_gw_config "local_if_name=\"eth0\";remote_address=\"10:60:4b:75:80:83\";local_address=\"98:90:96:df:66:07\";local_port=50000;remote_port=50000;tr_preference=\"raw\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=113;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_function \"NGFI_RCC_IF4p5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_timing \"synch_to_ext_device\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_synch_ref 0 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf N_RB_DL 50 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -27 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antenna_ports 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ue_TransmissionMode 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth6\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf rrh_gw_config "local_if_name=\"em2\";remote_address=\"00:25:90:f0:f1:2f\";local_address=\"0c:c4:7a:82:95:95\";local_port=50000;remote_port=50000;tr_preference=\"raw_if4p5\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=80;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" + $OPENAIR_DIR/cmake_targets/build_oai - --eNB -w None -t ETHERNET -x -c --disable-deadline + --eNB -w None -t ETHERNET -x -c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - sleep 5; sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf + sleep 30; sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf False + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_function \"NGFI_RRU_IF4p5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_timing \"synch_to_ext_device\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_synch_ref 0 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf N_RB_DL 50 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -27 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antenna_ports 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf ue_TransmissionMode 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf rrh_gw_config "local_if_name=\"eth3\";remote_address=\"0c:c4:7a:82:95:95\";local_address=\"00:25:90:f0:f1:2f\";local_port=50000;remote_port=50000;tr_preference=\"raw_if4p5\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=80;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" $OPENAIR_DIR/cmake_targets/build_oai - --RRH -w USRP -t ETHERNET -c --disable-deadline + --eNB -w USRP -t ETHERNET -c -x $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/rrh_gw/build/rrh_gw - -n1 -x -m1 -i eth1 + sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf False + /tmp $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 14Mbits/s False - sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue /tmp @@ -8098,59 +8147,84 @@ c $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 5 lo -s -i 1 -u -f m - throughput_test min=0.0Mbits/sec max=1.0Mbits/sec average=1.0Mbits/sec + throughput_test min=0.0Mbits/sec max=10.0Mbits/sec average=10.0Mbits/sec False - USRPb210.RRH.ALU_EPC.Bandrich.10MHz.FDD.Band_7.UL.1TX.1RX + USRPb210.RRH.IF4P5.ALU_EPC.SonyExperiaM4.10MHz.FDD.UDP.Band_7.UL.1TX.1RX 10 lte-softmodem - calisson - mozart + superserver stevens amerique + hutch 390 /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mobile_network_code \"92\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf N_RB_DL 100 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf downlink_frequency 2660000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf pdsch_referenceSignalPower -32 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth6\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.111/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth6\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.111/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_PORT_FOR_S1U 2152 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf rrh_gw_config "local_if_name=\"eth0\";remote_address=\"10:60:4b:75:80:83\";local_address=\"98:90:96:df:66:07\";local_port=50000;remote_port=50000;tr_preference=\"raw\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=115;tx_scheduling_advance=11;rrh_gw_active=\"yes\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_function \"NGFI_RCC_IF4p5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_timing \"synch_to_ext_device\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_synch_ref 0 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf N_RB_DL 100 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -30 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antenna_ports 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ue_TransmissionMode 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth6\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf rrh_gw_config "local_if_name=\"em2\";remote_address=\"00:25:90:f0:f1:2f\";local_address=\"0c:c4:7a:82:95:95\";local_port=50000;remote_port=50000;tr_preference=\"raw_if4p5\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=80;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" + $OPENAIR_DIR/cmake_targets/build_oai - --eNB -w None -t ETHERNET -x -c --disable-deadline + --eNB -w None -t ETHERNET -x -c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - sleep 5; sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf + sleep 30; sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf False + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_function \"NGFI_RRU_IF4p5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_timing \"synch_to_ext_device\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_synch_ref 0 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf N_RB_DL 100 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -30 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antenna_ports 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf ue_TransmissionMode 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf rrh_gw_config "local_if_name=\"eth3\";remote_address=\"0c:c4:7a:82:95:95\";local_address=\"00:25:90:f0:f1:2f\";local_port=50000;remote_port=50000;tr_preference=\"raw_if4p5\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=80;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" $OPENAIR_DIR/cmake_targets/build_oai - --RRH -w USRP -t ETHERNET -c --disable-deadline + --eNB -w USRP -t ETHERNET -c -x $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/rrh_gw/build/rrh_gw - -n1 -x -m1 -i eth1 + sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf False /tmp @@ -8159,14 +8233,14 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 28Mbits/s False - sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue /tmp @@ -8183,76 +8257,103 @@ c $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 5 lo -s -i 1 -u -f m - throughput_test min=0.0Mbits/sec max=1.0Mbits/sec average=1.0Mbits/sec + throughput_test min=0.0Mbits/sec max=5.0Mbits/sec average=5.0Mbits/sec False - USRPb210.RRH.ALU_EPC.Bandrich.20MHz.FDD.Band_7.UL.1TX.1RX + USRPb210.RRH.IF4P5.ALU_EPC.SonyExperiaM4.10MHz.FDD.UDP.Band_7.UL.1TX.1RX 10 lte-softmodem - calisson - mozart + superserver stevens amerique + hutch 390 /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mobile_network_code \"92\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf downlink_frequency 2660000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf pdsch_referenceSignalPower -26 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth6\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.111/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth6\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.111/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_PORT_FOR_S1U 2152 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf rrh_gw_config "local_if_name=\"eth0\";remote_address=\"10:60:4b:75:80:83\";local_address=\"98:90:96:df:66:07\";local_port=50000;remote_port=50000;tr_preference=\"raw\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=70;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_function \"NGFI_RCC_IF4p5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_timing \"synch_to_ext_device\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_synch_ref 0 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -24 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antenna_ports 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ue_TransmissionMode 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth6\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf rrh_gw_config "local_if_name=\"em2\";remote_address=\"00:25:90:f0:f1:2f\";local_address=\"0c:c4:7a:82:95:95\";local_port=50000;remote_port=50000;tr_preference=\"raw_if4p5\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=80;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" + $OPENAIR_DIR/cmake_targets/build_oai - --eNB -w None -t ETHERNET -x -c --disable-deadline + --eNB -w None -t ETHERNET -x -c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - sleep 5; sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf + sleep 30; sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf False + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_function \"NGFI_RRU_IF4p5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_timing \"synch_to_ext_device\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_synch_ref 0 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -24 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antenna_ports 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf ue_TransmissionMode 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf rrh_gw_config "local_if_name=\"eth3\";remote_address=\"0c:c4:7a:82:95:95\";local_address=\"00:25:90:f0:f1:2f\";local_port=50000;remote_port=50000;tr_preference=\"raw_if4p5\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=80;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" $OPENAIR_DIR/cmake_targets/build_oai - --RRH -w USRP -t ETHERNET -c --disable-deadline + --eNB -w USRP -t ETHERNET -c -x $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/rrh_gw/build/rrh_gw - -n1 -x -m1 -i eth1 + sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf False + /tmp $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -s -i 1 -u -f m - False - sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue - throughput_test min=0.0Mbits/sec max=5.0Mbits/sec average=4.0Mbits/sec + throughput_test min=0.0Mbits/sec max=5.0Mbits/sec average=4.0Mbits/sec - + False + sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue + + /tmp @@ -8266,144 +8367,85 @@ c /opt/hss_sim0609/starthss >> /dev/null ; sleep 3000 - $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 60 lo -u -c 192.172.0.2 -b 10Mbits/s + $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 10 192.172.0.2 -c 192.172.0.2 -b 16Mbits/s -i 1 -f m -u False - USRPb210.RRH.ALU_EPC.Bandrich.5MHz.FDD.Band_7.DL.1TX.1RX + USRPb210.RRH.IF4P5.ALU_EPC.SonyExperiaM4.5MHz.FDD.UDP.Band_7.DL.1TX.1RX 10 lte-softmodem - calisson - mozart + superserver stevens amerique + hutch 390 /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mobile_network_code \"92\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf N_RB_DL 50 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf downlink_frequency 2660000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf pdsch_referenceSignalPower -29 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth6\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.111/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth6\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.111/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_PORT_FOR_S1U 2152 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf rrh_gw_config "local_if_name=\"eth0\";remote_address=\"10:60:4b:75:80:83\";local_address=\"98:90:96:df:66:07\";local_port=50000;remote_port=50000;tr_preference=\"raw\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=113;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_function \"NGFI_RCC_IF4p5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_timing \"synch_to_ext_device\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_synch_ref 0 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf N_RB_DL 50 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -27 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antenna_ports 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ue_TransmissionMode 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth6\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf rrh_gw_config "local_if_name=\"em2\";remote_address=\"00:25:90:f0:f1:2f\";local_address=\"0c:c4:7a:82:95:95\";local_port=50000;remote_port=50000;tr_preference=\"raw_if4p5\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=80;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" + $OPENAIR_DIR/cmake_targets/build_oai - --eNB -w None -t ETHERNET -x -c --disable-deadline + --eNB -w None -t ETHERNET -x -c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - sleep 5; sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf + sleep 30; sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf False + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_function \"NGFI_RRU_IF4p5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_timing \"synch_to_ext_device\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_synch_ref 0 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf N_RB_DL 50 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -27 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antenna_ports 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf ue_TransmissionMode 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf rrh_gw_config "local_if_name=\"eth3\";remote_address=\"0c:c4:7a:82:95:95\";local_address=\"00:25:90:f0:f1:2f\";local_port=50000;remote_port=50000;tr_preference=\"raw_if4p5\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=80;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" $OPENAIR_DIR/cmake_targets/build_oai - --RRH -w USRP -t ETHERNET -c --disable-deadline + --eNB -w USRP -t ETHERNET -c -x $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/rrh_gw/build/rrh_gw - -n1 -x -m1 -i eth1 - False - - /tmp - - - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 - - throughput_test min=0.0Mbits/sec max=9.0Mbits/sec average=8.5Mbits/sec - - False - sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue - - - /tmp - - - - - - - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - - /opt/ltebox/tools/stop_ltebox ; /opt/ltebox/tools/start_ltebox ; sleep 3000 - - /opt/hss_sim0609/starthss >> /dev/null ; sleep 3000 - - $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 60 lo -u -c 192.172.0.2 -b 10Mbits/s - - - False - USRPb210.RRH.ALU_EPC.Bandrich.10MHz.FDD.Band_7.DL.1TX.1RX - 10 - - - - lte-softmodem - - calisson - mozart - stevens - amerique - 390 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mobile_network_code \"92\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf N_RB_DL 100 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf downlink_frequency 2660000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf pdsch_referenceSignalPower -32 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth6\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.111/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth6\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.111/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf ENB_PORT_FOR_S1U 2152 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf rrh_gw_config "local_if_name=\"eth0\";remote_address=\"10:60:4b:75:80:83\";local_address=\"98:90:96:df:66:07\";local_port=50000;remote_port=50000;tr_preference=\"raw\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=115;tx_scheduling_advance=11;rrh_gw_active=\"yes\";" - $OPENAIR_DIR/cmake_targets/build_oai - --eNB -w None -t ETHERNET -x -c --disable-deadline - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - - sleep 5; $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.rrh.usrpb210.conf - - - - - False - - $OPENAIR_DIR/cmake_targets/build_oai - --RRH -w USRP -t ETHERNET -c --disable-deadline - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - - sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/rrh_gw/build/rrh_gw - -n1 -x -m1 -i eth1 + sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf False /tmp @@ -8412,16 +8454,16 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -s -i 1 -u -f m -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -s -i 1 -u -f m - throughput_test min=00.0Mbits/sec max=10.0Mbits/sec average=10.0Mbits/sec + throughput_test min=0.0Mbits/sec max=5.0Mbits/sec average=4.0Mbits/sec False - sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue - - + sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue + + /tmp @@ -8435,11 +8477,121 @@ c /opt/hss_sim0609/starthss >> /dev/null ; sleep 3000 - $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 60 lo -u -c 192.172.0.2 -b 15Mbits/s + $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 10 192.172.0.2 -c 192.172.0.2 -b 32Mbits/s -i 1 -f m -u False - USRPb210.RRH.ALU_EPC.Bandrich.20MHz.FDD.Band_7.DL.1TX.1RX + USRPb210.RRH.IF4P5.ALU_EPC.SonyExperiaM4.5MHz.FDD.UDP.Band_7.DL.1TX.1RX + 10 + + + + lte-softmodem + + superserver + stevens + amerique + hutch + 390 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_function \"NGFI_RCC_IF4p5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_timing \"synch_to_ext_device\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf node_synch_ref 0 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf N_RB_DL 100 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -30 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf nb_antenna_ports 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ue_TransmissionMode 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth6\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf rrh_gw_config "local_if_name=\"em2\";remote_address=\"00:25:90:f0:f1:2f\";local_address=\"0c:c4:7a:82:95:95\";local_port=50000;remote_port=50000;tr_preference=\"raw_if4p5\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=80;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" + + $OPENAIR_DIR/cmake_targets/build_oai + --eNB -w None -t ETHERNET -x -c + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + + sleep 30; sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.usrpb210.conf + + + + + False + + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_function \"NGFI_RRU_IF4p5\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_timing \"synch_to_ext_device\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf node_synch_ref 0 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf N_RB_DL 100 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -30 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf nb_antenna_ports 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf ue_TransmissionMode 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf rrh_gw_config "local_if_name=\"eth3\";remote_address=\"0c:c4:7a:82:95:95\";local_address=\"00:25:90:f0:f1:2f\";local_port=50000;remote_port=50000;tr_preference=\"raw_if4p5\";rf_preference=\"usrp_b200\";iq_txshift=4;tx_sample_advance=80;tx_scheduling_advance=9;rrh_gw_active=\"yes\";" + $OPENAIR_DIR/cmake_targets/build_oai + --eNB -w USRP -t ETHERNET -c -x + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + + sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rru.band7.tm1.usrpb210.conf + False + + /tmp + + + + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + + sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue + + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -s -i 1 -u -f m + + throughput_test min=0.0Mbits/sec max=5.0Mbits/sec average=4.0Mbits/sec + + False + sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue + + + /tmp + + + + + + + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + + /opt/ltebox/tools/stop_ltebox ; /opt/ltebox/tools/start_ltebox ; sleep 3000 + + /opt/hss_sim0609/starthss >> /dev/null ; sleep 3000 + + $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 10 192.172.0.2 -c 192.172.0.2 -b 60Mbits/s -i 1 -f m -u + + + False + USRPb210.RRH.IF4P5.ALU_EPC.SonyExperiaM4.5MHz.FDD.UDP.Band_7.DL.1TX.1RX 10 @@ -8474,7 +8626,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -8489,7 +8641,7 @@ c sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 7Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 7Mbits/s @@ -8549,7 +8701,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -8564,7 +8716,7 @@ c sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 14Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 14Mbits/s @@ -8624,7 +8776,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -8639,7 +8791,7 @@ c sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 10Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 28Mbits/s @@ -8698,7 +8850,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -8772,7 +8924,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -8847,7 +8999,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -8921,7 +9073,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -8936,7 +9088,7 @@ c sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -c 192.172.0.1 -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -c 192.172.0.1 @@ -8996,7 +9148,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -9011,7 +9163,7 @@ c sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -c 192.172.0.1 -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -c 192.172.0.1 @@ -9071,7 +9223,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -9086,7 +9238,7 @@ c sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -c 192.172.0.1 -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -c 192.172.0.1 @@ -9145,7 +9297,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -9219,7 +9371,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -E -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -E -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -9294,7 +9446,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -9371,7 +9523,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -9386,7 +9538,7 @@ c sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 7Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 7Mbits/s @@ -9448,7 +9600,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -9463,7 +9615,7 @@ c sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 14Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 14Mbits/s @@ -9525,7 +9677,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread -E + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf -E @@ -9540,7 +9692,7 @@ c sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 14Mbits/s -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -u -c 192.172.0.1 -b 14Mbits/s @@ -9601,7 +9753,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -9677,7 +9829,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -9754,7 +9906,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread -E + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf -E @@ -9830,7 +9982,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -9845,7 +9997,7 @@ c sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -c 192.172.0.1 -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -c 192.172.0.1 @@ -9907,7 +10059,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -9922,7 +10074,7 @@ c sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -c 192.172.0.1 -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -c 192.172.0.1 @@ -9984,7 +10136,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread -E + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf -E @@ -9999,7 +10151,7 @@ c sleep 50; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -c 192.172.0.1 -B 192.172.0.2 + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script_phone 1 YT9115PX1E -c 192.172.0.1 @@ -10060,7 +10212,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -10136,7 +10288,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf @@ -10213,7 +10365,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/autotests/tools/run_gdb $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf --single-thread -E + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm2.usrpb210.conf -E From af2ad0682f84256841de6a3d614d33528a6dfaed Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Thu, 24 Nov 2016 14:59:42 +0100 Subject: [PATCH 327/413] removing -L option from dlsim testcases --- cmake_targets/autotests/test_case_list.xml | 20 ++++++++++---------- openair1/SIMULATION/LTE_PHY/dlsim.c | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index 3d9e7f19e6..c73a5257e9 100644 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -952,17 +952,17 @@ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash $OPENAIR_DIR/cmake_targets/lte-simulators/build/dlsim - -m5 -gF -s-1 -w1.0 -f.2 -n500 -B50 -c2 -z2 -O70 -L + -m5 -gF -s-1 -w1.0 -f.2 -n500 -B50 -c2 -z2 -O70 -m4 -gF -s0 -w1.0 -f.2 -n500 -B6 -c4 -z2 -O70 - -m15 -gF -s6.7 -w1.0 -f.2 -n500 -B50 -c2 -z2 -O70 -L - -m14 -gF -s6.7 -w1.0 -f.2 -n500 -B25 -c3 -z2 -O70 -L - -m15 -gG -s6.7 -w1.0 -f.2 -n500 -B50 -c2 -z2 -O30 -L - -m14 -gG -s1.4 -w1.0 -f.2 -n500 -B25 -c3 -z2 -O30 -L - -m25 -gF -s17.4 -w1.0 -f.2 -n500 -B25 -c3 -z2 -O70 -L - -m25 -gF -s17.5 -w1.0 -f.2 -n500 -B25 -c3 -z2 -r1022 -O70 -L - -m26 -gF -s17.7 -w1.0 -f.2 -n500 -B50 -c2 -z2 -O70 -L - -m14 -gF -s6.8 -w1.0 -f.2 -n500 -B50 -c2 -x2 -y2 -z2 -O70 -L - -m13 -gF -s5.9 -w1.0 -f.2 -n500 -B25 -c3 -x2 -y2 -z2 -O70 -L + -m15 -gF -s6.7 -w1.0 -f.2 -n500 -B50 -c2 -z2 -O70 + -m14 -gF -s6.7 -w1.0 -f.2 -n500 -B25 -c3 -z2 -O70 + -m15 -gG -s6.7 -w1.0 -f.2 -n500 -B50 -c2 -z2 -O30 + -m14 -gG -s1.4 -w1.0 -f.2 -n500 -B25 -c3 -z2 -O30 + -m25 -gF -s17.4 -w1.0 -f.2 -n500 -B25 -c3 -z2 -O70 + -m25 -gF -s17.5 -w1.0 -f.2 -n500 -B25 -c3 -z2 -r1022 -O70 + -m26 -gF -s17.7 -w1.0 -f.2 -n500 -B50 -c2 -z2 -O70 + -m14 -gF -s6.8 -w1.0 -f.2 -n500 -B50 -c2 -x2 -y2 -z2 -O70 + -m13 -gF -s5.9 -w1.0 -f.2 -n500 -B25 -c3 -x2 -y2 -z2 -O70 dlsim.test1 dlsim.test5 dlsim.test6 dlsim.test6b dlsim.test7 dlsim.test7b dlsim.test10 dlsim.test10b dlsim.test11 dlsim.TM2_test1 dlsim.TM2_test1b "passed" segmentation fault|assertion|exiting|fatal diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 40faf1049f..96c533bde5 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -2420,7 +2420,7 @@ int main(int argc, char **argv) phy_procedures_UE_RX(UE,proc,0,0,normal_txrx,no_relay,NULL); if (UE->dlsch[0][0]->active == 0) { - printf("DCI not received\n"); + //printf("DCI not received\n"); /* 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); From 03231dd163e673651ada2555e564f7157faad616 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 24 Nov 2016 16:44:15 +0100 Subject: [PATCH 328/413] hotfix: fix pucch_procedures Something went wrong somewhere in the commit history, the function was not correct. The most obvious symptom was that way too much SR (scheduling requests) were given to the UE whenever it had some PUCCH to send. The case for TDD has not been tested. --- openair1/SCHED/phy_procedures_lte_eNb.c | 599 ++++++++++++------------ 1 file changed, 288 insertions(+), 311 deletions(-) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 11fb37dcdf..6d0bc53ac8 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -2016,11 +2016,11 @@ void prach_procedures(PHY_VARS_eNB *eNB) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0); } -void pucch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,int UE_id,int harq_pid) { - +void pucch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,int UE_id,int harq_pid) +{ LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; uint8_t SR_payload = 0,*pucch_payload=NULL,pucch_payload0[2]= {0,0},pucch_payload1[2]= {0,0}; - int16_t n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3; + int16_t n1_pucch0 = -1, n1_pucch1 = -1, n1_pucch2 = -1, n1_pucch3 = -1; uint8_t do_SR = 0; uint8_t pucch_sel = 0; int32_t metric0=0,metric1=0,metric0_SR=0; @@ -2031,352 +2031,329 @@ void pucch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,int UE_id,int harq if ((eNB->dlsch[UE_id][0]) && (eNB->dlsch[UE_id][0]->rnti>0) && - (eNB->ulsch[UE_id]->harq_processes[harq_pid]->subframe_scheduling_flag==0)) { + (eNB->ulsch[UE_id]->harq_processes[harq_pid]->subframe_scheduling_flag==0)) { // check SR availability do_SR = is_SR_subframe(eNB,proc,UE_id); // do_SR = 0; - + // Now ACK/NAK // First check subframe_tx flag for earlier subframes get_n1_pucch_eNB(eNB, - proc, - UE_id, - &n1_pucch0, - &n1_pucch1, - &n1_pucch2, - &n1_pucch3); - + proc, + UE_id, + &n1_pucch0, + &n1_pucch1, + &n1_pucch2, + &n1_pucch3); + LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d, subframe %d Checking for PUCCH (%d,%d,%d,%d) SR %d\n", - eNB->Mod_id,eNB->dlsch[UE_id][0]->rnti, - frame,subframe, - n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3,do_SR); - + eNB->Mod_id,eNB->dlsch[UE_id][0]->rnti, + frame,subframe, + n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3,do_SR); + if ((n1_pucch0==-1) && (n1_pucch1==-1) && (do_SR==0)) { // no TX PDSCH that have to be checked and no SR for this UE_id } else { // otherwise we have some PUCCH detection to do - + // Null out PUCCH PRBs for noise measurement switch(fp->N_RB_UL) { case 6: - eNB->rb_mask_ul[0] |= (0x1 | (1<<5)); //position 5 - break; + eNB->rb_mask_ul[0] |= (0x1 | (1<<5)); //position 5 + break; case 15: - eNB->rb_mask_ul[0] |= (0x1 | (1<<14)); // position 14 - break; + eNB->rb_mask_ul[0] |= (0x1 | (1<<14)); // position 14 + break; case 25: - eNB->rb_mask_ul[0] |= (0x1 | (1<<24)); // position 24 - break; + eNB->rb_mask_ul[0] |= (0x1 | (1<<24)); // position 24 + break; case 50: - eNB->rb_mask_ul[0] |= 0x1; - eNB->rb_mask_ul[1] |= (1<<17); // position 49 (49-32) - break; + eNB->rb_mask_ul[0] |= 0x1; + eNB->rb_mask_ul[1] |= (1<<17); // position 49 (49-32) + break; case 75: - eNB->rb_mask_ul[0] |= 0x1; - eNB->rb_mask_ul[2] |= (1<<10); // position 74 (74-64) - break; + eNB->rb_mask_ul[0] |= 0x1; + eNB->rb_mask_ul[2] |= (1<<10); // position 74 (74-64) + break; case 100: - eNB->rb_mask_ul[0] |= 0x1; - eNB->rb_mask_ul[3] |= (1<<3); // position 99 (99-96) - break; + eNB->rb_mask_ul[0] |= 0x1; + eNB->rb_mask_ul[3] |= (1<<3); // position 99 (99-96) + break; default: - LOG_E(PHY,"Unknown number for N_RB_UL %d\n",fp->N_RB_UL); - break; + LOG_E(PHY,"Unknown number for N_RB_UL %d\n",fp->N_RB_UL); + break; } - + if (do_SR == 1) { - eNB->UE_stats[UE_id].sr_total++; + eNB->UE_stats[UE_id].sr_total++; - if (eNB->abstraction_flag == 0) - metric0_SR = rx_pucch(eNB, - pucch_format1, - UE_id, - eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex, - 0, // n2_pucch - 0, // shortened format, should be use_srs flag, later - &SR_payload, - frame, - subframe, - PUCCH1_THRES); - + if (eNB->abstraction_flag == 0) { + metric0_SR = rx_pucch(eNB, + pucch_format1, + UE_id, + eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex, + 0, // n2_pucch + 0, // shortened format, should be use_srs flag, later + &SR_payload, + frame, + subframe, + PUCCH1_THRES); + LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Checking SR is %d (SR n1pucch is %d)\n", + eNB->Mod_id, + eNB->ulsch[UE_id]->rnti, + frame, + subframe, + SR_payload, + eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex); + } #ifdef PHY_ABSTRACTION - else { - metric0_SR = rx_pucch_emul(eNB, - proc, - UE_id, - pucch_format1, - 0, - &SR_payload); - LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Checking SR (UE SR %d/%d)\n",eNB->Mod_id, - eNB->ulsch[UE_id]->rnti,frame,subframe,SR_payload,eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex); - } - + else { + metric0_SR = rx_pucch_emul(eNB, + proc, + UE_id, + pucch_format1, + 0, + &SR_payload); + LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Checking SR (UE SR %d/%d)\n",eNB->Mod_id, + eNB->ulsch[UE_id]->rnti,frame,subframe,SR_payload,eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex); + } #endif - - if (SR_payload == 1) { - LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Got SR for PUSCH, transmitting to MAC\n",eNB->Mod_id, - eNB->ulsch[UE_id]->rnti,frame,subframe); - eNB->UE_stats[UE_id].sr_received++; - - if (eNB->first_sr[UE_id] == 1) { // this is the first request for uplink after Connection Setup, so clear HARQ process 0 use for Msg4 - eNB->first_sr[UE_id] = 0; - eNB->dlsch[UE_id][0]->harq_processes[0]->round=0; - eNB->dlsch[UE_id][0]->harq_processes[0]->status=SCH_IDLE; - LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d First SR\n", - eNB->Mod_id, - eNB->ulsch[UE_id]->rnti,frame,subframe); - } - - if (eNB->mac_enabled==1) { - mac_xface->SR_indication(eNB->Mod_id, - eNB->CC_id, - frame, - eNB->dlsch[UE_id][0]->rnti,subframe); - } - } }// do_SR==1 - + if ((n1_pucch0==-1) && (n1_pucch1==-1)) { // just check for SR - } else if (eNB->frame_parms.frame_type==FDD) { // FDD - // if SR was detected, use the n1_pucch from SR, else use n1_pucch0 - // n1_pucch0 = (SR_payload==1) ? eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex:n1_pucch0; - - LOG_D(PHY,"Demodulating PUCCH for ACK/NAK: n1_pucch0 %d (%d), SR_payload %d\n",n1_pucch0,eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex,SR_payload); - - if (eNB->abstraction_flag == 0) { - - - - metric0 = rx_pucch(eNB, - pucch_format1a, - UE_id, - (uint16_t)n1_pucch0, - 0, //n2_pucch - 0, // shortened format - pucch_payload0, - frame, - subframe, - PUCCH1a_THRES); - - if (metric0 < metric0_SR) - metric0=rx_pucch(eNB, - pucch_format1a, - UE_id, - eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex, - 0, //n2_pucch - 0, // shortened format - pucch_payload0, - frame, - subframe, - PUCCH1a_THRES); - - } - - if (eNB->mac_enabled==1) { - mac_xface->SR_indication(eNB->Mod_id, - eNB->CC_id, - frame, - eNB->dlsch[UE_id][0]->rnti,subframe); - } - } - }// do_SR==1 - - if ((n1_pucch0==-1) && (n1_pucch1==-1)) { // just check for SR - } else if (fp->frame_type==FDD) { // FDD - // if SR was detected, use the n1_pucch from SR, else use n1_pucch0 - // n1_pucch0 = (SR_payload==1) ? eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex:n1_pucch0; - - LOG_D(PHY,"Demodulating PUCCH for ACK/NAK: n1_pucch0 %d (%d), SR_payload %d\n",n1_pucch0,eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex,SR_payload); - - if (eNB->abstraction_flag == 0) { - - - - metric0 = rx_pucch(eNB, - pucch_format1a, - UE_id, - (uint16_t)n1_pucch0, - 0, //n2_pucch - 0, // shortened format - pucch_payload0, - frame, - subframe, - PUCCH1a_THRES); - - if (metric0 < metric0_SR) - metric0=rx_pucch(eNB, - pucch_format1a, - UE_id, - eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex, - 0, //n2_pucch - 0, // shortened format - pucch_payload0, - frame, - subframe, - PUCCH1a_THRES); - } - else { + } else if (fp->frame_type==FDD) { // FDD + // if SR was detected, use the n1_pucch from SR, else use n1_pucch0 + // n1_pucch0 = (SR_payload==1) ? eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex:n1_pucch0; + + LOG_D(PHY,"Demodulating PUCCH for ACK/NAK: n1_pucch0 %d (%d), SR_payload %d\n",n1_pucch0,eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex,SR_payload); + + if (eNB->abstraction_flag == 0) { + metric0 = rx_pucch(eNB, + pucch_format1a, + UE_id, + (uint16_t)n1_pucch0, + 0, //n2_pucch + 0, // shortened format + pucch_payload0, + frame, + subframe, + PUCCH1a_THRES); + } #ifdef PHY_ABSTRACTION - metric0 = rx_pucch_emul(eNB, - proc, - UE_id, - pucch_format1a, - 0, - pucch_payload0); -#endif - } - -#ifdef DEBUG_PHY_PROC - LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d pucch1a (FDD) payload %d (metric %d)\n", - eNB->Mod_id, - eNB->dlsch[UE_id][0]->rnti, - frame,subframe, - pucch_payload0[0],metric0); -#endif - - process_HARQ_feedback(UE_id,eNB,proc, - 0,// pusch_flag - pucch_payload0, - 2, - SR_payload); - - } // FDD - else { //TDD - - bundling_flag = eNB->pucch_config_dedicated[UE_id].tdd_AckNackFeedbackMode; - - // fix later for 2 TB case and format1b - - if ((fp->frame_type==FDD) || - (bundling_flag==bundling) || - ((fp->frame_type==TDD)&&(fp->tdd_config==1)&&((subframe!=2)||(subframe!=7)))) { - format = pucch_format1a; - } else { - format = pucch_format1b; - } - - // if SR was detected, use the n1_pucch from SR - if (SR_payload==1) { -#ifdef DEBUG_PHY_PROC - LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d Checking ACK/NAK (%d,%d,%d,%d) format %d with SR\n",eNB->Mod_id, - eNB->dlsch[UE_id][0]->rnti, - frame,subframe, - n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3,format); + else { + metric0 = rx_pucch_emul(eNB, + proc, + UE_id, + pucch_format1a, + 0, + pucch_payload0); + } #endif - if (eNB->abstraction_flag == 0) - metric0_SR = rx_pucch(eNB, - format, - UE_id, - eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex, - 0, //n2_pucch - 0, // shortened format - pucch_payload0, - frame, - subframe, - PUCCH1a_THRES); - else { + /* cancel SR detection if reception on n1_pucch0 is better than on SR PUCCH resource index */ + if (do_SR && metric0 > metric0_SR) SR_payload = 0; + + if (do_SR && metric0 <= metric0_SR) { + /* when transmitting ACK/NACK on SR PUCCH resource index, SR payload is always 1 */ + SR_payload = 1; + + if (eNB->abstraction_flag == 0) { + metric0=rx_pucch(eNB, + pucch_format1a, + UE_id, + eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex, + 0, //n2_pucch + 0, // shortened format + pucch_payload0, + frame, + subframe, + PUCCH1a_THRES); + } #ifdef PHY_ABSTRACTION - metric0 = rx_pucch_emul(eNB,proc, - UE_id, - format, - 0, - pucch_payload0); + else { + metric0 = rx_pucch_emul(eNB, + proc, + UE_id, + pucch_format1a, + 0, + pucch_payload0); + } #endif - } - } else { //using n1_pucch0/n1_pucch1 resources -#ifdef DEBUG_PHY_PROC - LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d Checking ACK/NAK (%d,%d,%d,%d) format %d\n",eNB->Mod_id, - eNB->dlsch[UE_id][0]->rnti, - frame,subframe, - n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3,format); -#endif - metric0=0; - metric1=0; - - // Check n1_pucch0 metric - if (n1_pucch0 != -1) { - if (eNB->abstraction_flag == 0) - metric0 = rx_pucch(eNB, - format, - UE_id, - (uint16_t)n1_pucch0, - 0, // n2_pucch - 0, // shortened format - pucch_payload0, - frame, - subframe, - PUCCH1a_THRES); - else { -#ifdef PHY_ABSTRACTION - metric0 = rx_pucch_emul(eNB, - proc, - UE_id, - format, - 0, - pucch_payload0); -#endif - } - } - - // Check n1_pucch1 metric - if (n1_pucch1 != -1) { - if (eNB->abstraction_flag == 0) - metric1 = rx_pucch(eNB, - format, - UE_id, - (uint16_t)n1_pucch1, - 0, //n2_pucch - 0, // shortened format - pucch_payload1, - frame, - subframe, - PUCCH1a_THRES); - else { -#ifdef PHY_ABSTRACTION - metric1 = rx_pucch_emul(eNB, - proc, - UE_id, - format, - 1, - pucch_payload1); -#endif - } - } - } - - if (SR_payload == 1) { - pucch_payload = pucch_payload0; - - if (bundling_flag == bundling) - pucch_sel = 2; - } else if (bundling_flag == multiplexing) { // multiplexing + no SR - pucch_payload = (metric1>metric0) ? pucch_payload1 : pucch_payload0; - pucch_sel = (metric1>metric0) ? 1 : 0; - } else { // bundling + no SR - if (n1_pucch1 != -1) - pucch_payload = pucch_payload1; - else if (n1_pucch0 != -1) - pucch_payload = pucch_payload0; - - pucch_sel = 2; // indicate that this is a bundled ACK/NAK - } + } #ifdef DEBUG_PHY_PROC - LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d ACK/NAK metric 0 %d, metric 1 %d, sel %d, (%d,%d)\n",eNB->Mod_id, - eNB->dlsch[UE_id][0]->rnti, - frame,subframe, - metric0,metric1,pucch_sel,pucch_payload[0],pucch_payload[1]); + LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d pucch1a (FDD) payload %d (metric %d)\n", + eNB->Mod_id, + eNB->dlsch[UE_id][0]->rnti, + frame,subframe, + pucch_payload0[0],metric0); #endif - process_HARQ_feedback(UE_id,eNB,proc, - 0,// pusch_flag - pucch_payload, - pucch_sel, - SR_payload); + + process_HARQ_feedback(UE_id,eNB,proc, + 0,// pusch_flag + pucch_payload0, + 2, + SR_payload); + } // FDD + else { //TDD + + bundling_flag = eNB->pucch_config_dedicated[UE_id].tdd_AckNackFeedbackMode; + + // fix later for 2 TB case and format1b + + if ((fp->frame_type==FDD) || + (bundling_flag==bundling) || + ((fp->frame_type==TDD)&&(fp->tdd_config==1)&&((subframe!=2)||(subframe!=7)))) { + format = pucch_format1a; + } else { + format = pucch_format1b; + } + + // if SR was detected, use the n1_pucch from SR + if (SR_payload==1) { +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d Checking ACK/NAK (%d,%d,%d,%d) format %d with SR\n",eNB->Mod_id, + eNB->dlsch[UE_id][0]->rnti, + frame,subframe, + n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3,format); +#endif + + if (eNB->abstraction_flag == 0) + metric0 = rx_pucch(eNB, + format, + UE_id, + eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex, + 0, //n2_pucch + 0, // shortened format + pucch_payload0, + frame, + subframe, + PUCCH1a_THRES); + else { +#ifdef PHY_ABSTRACTION + metric0 = rx_pucch_emul(eNB,proc, + UE_id, + format, + 0, + pucch_payload0); +#endif + } + } else { //using n1_pucch0/n1_pucch1 resources +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d Checking ACK/NAK (%d,%d,%d,%d) format %d\n",eNB->Mod_id, + eNB->dlsch[UE_id][0]->rnti, + frame,subframe, + n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3,format); +#endif + metric0=0; + metric1=0; + + // Check n1_pucch0 metric + if (n1_pucch0 != -1) { + if (eNB->abstraction_flag == 0) + metric0 = rx_pucch(eNB, + format, + UE_id, + (uint16_t)n1_pucch0, + 0, // n2_pucch + 0, // shortened format + pucch_payload0, + frame, + subframe, + PUCCH1a_THRES); + else { +#ifdef PHY_ABSTRACTION + metric0 = rx_pucch_emul(eNB, + proc, + UE_id, + format, + 0, + pucch_payload0); +#endif + } + } + + // Check n1_pucch1 metric + if (n1_pucch1 != -1) { + if (eNB->abstraction_flag == 0) + metric1 = rx_pucch(eNB, + format, + UE_id, + (uint16_t)n1_pucch1, + 0, //n2_pucch + 0, // shortened format + pucch_payload1, + frame, + subframe, + PUCCH1a_THRES); + else { +#ifdef PHY_ABSTRACTION + metric1 = rx_pucch_emul(eNB, + proc, + UE_id, + format, + 1, + pucch_payload1); +#endif + } + } + } + + if (SR_payload == 1) { + pucch_payload = pucch_payload0; + + if (bundling_flag == bundling) + pucch_sel = 2; + } else if (bundling_flag == multiplexing) { // multiplexing + no SR + pucch_payload = (metric1>metric0) ? pucch_payload1 : pucch_payload0; + pucch_sel = (metric1>metric0) ? 1 : 0; + } else { // bundling + no SR + if (n1_pucch1 != -1) + pucch_payload = pucch_payload1; + else if (n1_pucch0 != -1) + pucch_payload = pucch_payload0; + + pucch_sel = 2; // indicate that this is a bundled ACK/NAK + } + +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d ACK/NAK metric 0 %d, metric 1 %d, sel %d, (%d,%d)\n",eNB->Mod_id, + eNB->dlsch[UE_id][0]->rnti, + frame,subframe, + metric0,metric1,pucch_sel,pucch_payload[0],pucch_payload[1]); +#endif + process_HARQ_feedback(UE_id,eNB,proc, + 0,// pusch_flag + pucch_payload, + pucch_sel, + SR_payload); + } // TDD } - } + + if (SR_payload == 1) { + LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Got SR for PUSCH, transmitting to MAC\n",eNB->Mod_id, + eNB->ulsch[UE_id]->rnti,frame,subframe); + eNB->UE_stats[UE_id].sr_received++; + + if (eNB->first_sr[UE_id] == 1) { // this is the first request for uplink after Connection Setup, so clear HARQ process 0 use for Msg4 + eNB->first_sr[UE_id] = 0; + eNB->dlsch[UE_id][0]->harq_processes[0]->round=0; + eNB->dlsch[UE_id][0]->harq_processes[0]->status=SCH_IDLE; + LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d First SR\n", + eNB->Mod_id, + eNB->ulsch[UE_id]->rnti,frame,subframe); + } + + if (eNB->mac_enabled==1) { + mac_xface->SR_indication(eNB->Mod_id, + eNB->CC_id, + frame, + eNB->dlsch[UE_id][0]->rnti,subframe); + } + } + } } From f15426d75c0a1a96b09dc03e66efa0772548fcfb Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Thu, 24 Nov 2016 16:56:30 +0100 Subject: [PATCH 329/413] fixing config file --- .../PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm1.exmimo2.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm1.exmimo2.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm1.exmimo2.conf index 9444a6f95e..157a31154e 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm1.exmimo2.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band38.tm1.exmimo2.conf @@ -35,6 +35,7 @@ eNBs = Nid_cell_mbsfn = 0; nb_antennas_tx = 1; nb_antennas_rx = 1; + nb_antenna_ports = 1; tx_gain = 10; //25; rx_gain = 10; //20; prach_root = 0; @@ -97,6 +98,8 @@ eNBs = ue_TimersAndConstants_t311 = 10000; ue_TimersAndConstants_n310 = 20; ue_TimersAndConstants_n311 = 1; + + ue_TransmissionMode = 1; } ); From 933dc966c0437ef555f5926233172c4aa3311892 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Thu, 24 Nov 2016 17:14:50 +0100 Subject: [PATCH 330/413] fix for EXMIMO --- targets/RT/USER/lte-enb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 0741d88c42..8f636d20d6 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -1775,7 +1775,7 @@ void init_eNB(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst } } - if (setup_eNB_buffers(PHY_vars_eNB_g[inst],&openair0_cfg[CC_id])!=0) { + if (setup_eNB_buffers(PHY_vars_eNB_g[inst],&openair0_cfg[0])!=0) { printf("Exiting, cannot initialize eNodeB Buffers\n"); exit(-1); } From 41fd001b3181a8ddaf362bb6ab4901b9123f386e Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Thu, 24 Nov 2016 17:57:52 +0100 Subject: [PATCH 331/413] delete redundant code in beamforming.c --- openair1/PHY/MODULATION/beamforming.c | 63 ++++++--------------------- openair1/PHY/MODULATION/defs.h | 6 ++- openair1/PHY/MODULATION/ofdm_mod.c | 11 +++-- openair1/SIMULATION/LTE_PHY/dlsim.c | 8 +++- 4 files changed, 29 insertions(+), 59 deletions(-) diff --git a/openair1/PHY/MODULATION/beamforming.c b/openair1/PHY/MODULATION/beamforming.c index 75321daee0..6557a47ee7 100644 --- a/openair1/PHY/MODULATION/beamforming.c +++ b/openair1/PHY/MODULATION/beamforming.c @@ -51,26 +51,27 @@ int beam_precoding(int32_t **txdataF, LTE_DL_FRAME_PARMS *frame_parms, int32_t ***beam_weights, int slot, - int symbol) + int symbol, + int aa) { - uint8_t p,aa; + uint8_t p; uint16_t re=0; int slot_offset_F; slot_offset_F = slot*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==1) ? 6 : 7); // clear txdata_BF[aa][re] for each call of ue_spec_beamforming - for(aa=0;aanb_antennas_tx;aa++) - memset(txdataF_BF[aa],0,sizeof(int32_t)*(frame_parms->ofdm_symbol_size)); + memset(txdataF_BF[aa],0,sizeof(int32_t)*(frame_parms->ofdm_symbol_size)); - for (re=0;reofdm_symbol_size;re++) { - for (p=0; p<2; p++) { - if (txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { - for (aa=0;aanb_antennas_tx;aa++) { - ((int16_t*)&txdataF_BF[aa][re])[0] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); - ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); + for (p=0; p<14; p++) { + //if (p==0 || p==1 || p==5 || p>7) + // mult_cpx_conj_vector((int16_t*)txdataF[p], (int16_t*)beam_weights[p][aa], (int16_t*)txdataF_BF[aa], frame_parms->ofdm_symbol_size, 15); + for (re=0;reofdm_symbol_size;re++) { + if ((p==0 || p==1 || p==5 || p>=7) && txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { + ((int16_t*)&txdataF_BF[aa][re])[0] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); + ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); + ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); /* printf("beamforming.c:txdataF[%d][%d]=%d+j%d, beam_weights[%d][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", @@ -83,44 +84,8 @@ int beam_precoding(int32_t **txdataF, ((int16_t*)&txdataF_BF[aa][re])[0], ((int16_t*)&txdataF_BF[aa][re])[1]); */ - } } } - if (txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually using TM7 - for (aa=0;aanb_antennas_tx;aa++) { - ((int16_t*)&txdataF_BF[aa][re])[0] += (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[5][aa][re])[0])>>15); - ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[5][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[5][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[5][aa][re])[0])>>15); - - /* printf("beamforming.c:txdata[5][%d]=%d+j%d, beam_weights[5][%d][%d]=%d+j%d,txdata_BF[%d][%d]=%d+j%d\n", - slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re, - ((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0], - ((int16_t*)&txdataF[5][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1], - aa,re, - ((int16_t*)&beam_weights[5][aa][re])[0], - ((int16_t*)&beam_weights[5][aa][re])[1], - aa,re, - ((int16_t*)&txdataF_BF[aa][re])[0], - ((int16_t*)&txdataF_BF[aa][re])[1]); */ - - } - } - - if (txdataF[7][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually using TM8-10 - for (p=7;p<15;p++) { - if (txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re]!=0) { //that means this RE is actually allocated - for (aa=0;aanb_antennas_tx;aa++) { - ((int16_t*)&txdataF_BF[aa][re])[0] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); - ((int16_t*)&txdataF_BF[aa][re])[0] -= (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[0]*((int16_t*)&beam_weights[p][aa][re])[1])>>15); - ((int16_t*)&txdataF_BF[aa][re])[1] += (int16_t)((((int16_t*)&txdataF[p][slot_offset_F+symbol*frame_parms->ofdm_symbol_size+re])[1]*((int16_t*)&beam_weights[p][aa][re])[0])>>15); - } - } - } - } } - -return 0; - + return 0; } diff --git a/openair1/PHY/MODULATION/defs.h b/openair1/PHY/MODULATION/defs.h index 289b1edd43..6937db6d9b 100644 --- a/openair1/PHY/MODULATION/defs.h +++ b/openair1/PHY/MODULATION/defs.h @@ -103,13 +103,15 @@ after beamforming @param beam_weights Beamforming weights applied on each antenna element and each carrier @param slot Slot number - @param symbol Symbol index on which to act*/ + @param symbol Symbol index on which to act + @param aa physical antenna index*/ int beam_precoding(int32_t **txdataF, int32_t **txdataF_BF, LTE_DL_FRAME_PARMS *frame_parms, int32_t ***beam_weights, int slot, - int symbol); + int symbol, + int aa); int f_read(char *calibF_fname, int nb_ant, int nb_freq, int32_t **tdd_calib_coeffs); diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 2fd7fd88a3..74037b4a6e 100644 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -298,14 +298,13 @@ void do_OFDM_mod_symbol(LTE_eNB_COMMON *eNB_common_vars, int eNB_id, uint16_t ne //printf("Thread %d starting ... aa %d (%llu)\n",omp_get_thread_num(),aa,rdtsc()); for (l=0; lsymbols_per_tti>>1; l++) { - //printf("do_OFDM_mod_l, slot=%d, l=%d, NUMBER_OF_OFDM_CARRIERS=%d,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES=%d\n",next_slot, l,NUMBER_OF_OFDM_CARRIERS,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES); - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_BEAM_PRECODING,1); - beam_precoding(txdataF,txdataF_BF,frame_parms,eNB_common_vars->beam_weights[eNB_id],next_slot,l); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_BEAM_PRECODING,0); - for (aa=0; aanb_antennas_tx; aa++) { + //printf("do_OFDM_mod_l, slot=%d, l=%d, NUMBER_OF_OFDM_CARRIERS=%d,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES=%d\n",next_slot, l,NUMBER_OF_OFDM_CARRIERS,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_BEAM_PRECODING,1); + beam_precoding(txdataF,txdataF_BF,frame_parms,eNB_common_vars->beam_weights[eNB_id],next_slot,l,aa); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_BEAM_PRECODING,0); + //PMCH case not implemented... if (frame_parms->Ncp == 1) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index c657069e46..f3804f0f70 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -1281,8 +1281,6 @@ int main(int argc, char **argv) uint8_t extended_prefix_flag=0,transmission_mode=1,n_tx_port=1,n_tx_phy=1,n_rx=2; uint16_t Nid_cell=0; - int32_t **cell_spec_bf_weights; - int eNB_id = 0; unsigned char mcs1=0,mcs2=0,mcs_i=0,dual_stream_UE = 0,awgn_flag=0,round; unsigned char i_mod = 2; @@ -1808,6 +1806,12 @@ int main(int argc, char **argv) osf, perfect_ce); + if ((transmission_mode==1) || (transmission_mode==7)) { + for (aa=0; aaframe_parms.nb_antennas_tx; aa++) + for (re=0; reframe_parms.ofdm_symbol_size; re++) + eNB->common_vars.beam_weights[0][0][aa][re] = 0x00007fff/eNB->frame_parms.nb_antennas_tx; + } + eNB->mac_enabled=1; if (two_thread_flag == 0) { eNB->te = dlsch_encoding; From b0b472e035c9eb5a95b29f1917777c1c750f7505 Mon Sep 17 00:00:00 2001 From: hbilel Date: Thu, 24 Nov 2016 18:17:21 +0100 Subject: [PATCH 332/413] BSR fixes on CMW500 --- openair2/LAYER2/MAC/config.c | 1 + openair2/LAYER2/MAC/ue_procedures.c | 33 +++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 46ded848b1..2ec37a423e 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -188,6 +188,7 @@ rrc_mac_config_req( else { UE_mac_inst[Mod_idP].scheduling_info.LCGID[logicalChannelIdentity] = MAX_NUM_LCGID; } + UE_mac_inst[Mod_idP].scheduling_info.LCID_buffer_remain[logicalChannelIdentity] = 0; } else { LOG_E(MAC,"[CONFIG][UE %d] LCID %d NULL ul_SpecificParameters\n",Mod_idP,logicalChannelIdentity); mac_xface->macphy_exit("NULL ul_SpecificParameters"); diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index b25aab9442..a4c77c2cda 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -128,6 +128,7 @@ void ue_init_mac(module_id_t module_idP) } UE_mac_inst[module_idP].scheduling_info.LCID_status[i]=LCID_EMPTY; + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[i] = 0; } #ifdef CBA @@ -1504,6 +1505,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU Got %d bytes for SRB2\n",module_idP,sdu_lengths[num_sdus]); //dcch_header_len +=2; // include dcch1 UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH1] = LCID_EMPTY; + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1] -= 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[DCCH1]] >= sdu_lengths[num_sdus]){ UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] -= sdu_lengths[num_sdus]; @@ -1653,7 +1655,18 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf if (bsr_ce_len) { //Print updated BSR when sent - LOG_D(MAC,"[UE %d] Frame %d Subframe %d TX BSR size=%d BSR0=%d BSR1=%d BSR2=%d BSR3=%d\n",module_idP,frameP,subframe,bsr_ce_len, + LOG_D(MAC,"[UE %d] Remaining Buffer after Tx frame%d subframe %d nb LCG =%d Bytes for LCG0=%d LCG1=%d LCG2=%d LCG3=%d BSR Trigger status =%d TBS=%d\n", + module_idP, + frameP, + subframe, + num_lcg_id_with_data, + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[0], + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[1], + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[2], + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[3], + UE_mac_inst[module_idP].BSR_reporting_active, buflen); + + LOG_D(MAC,"[UE %d] Frame %d Subframe %d TX BSR Regular or Periodic size=%d BSR0=%d BSR1=%d BSR2=%d BSR3=%d\n",module_idP,frameP,subframe,bsr_ce_len, UE_mac_inst[module_idP].scheduling_info.BSR[0], UE_mac_inst[module_idP].scheduling_info.BSR[1], UE_mac_inst[module_idP].scheduling_info.BSR[2], @@ -2309,6 +2322,7 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subfra uint8_t array_index = 0; // Reset All BSR Infos + lcid_bytes_in_buffer[0] = 0; for (lcid=DCCH; lcid < MAX_NUM_LCID; lcid++) { // Reset transmission status @@ -2316,7 +2330,7 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subfra UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid]=LCID_EMPTY; } - for (lcgid=0; lcid < MAX_NUM_LCGID; lcgid++) + for (lcgid=0; lcgid < MAX_NUM_LCGID; lcgid++) { // Reset Buffer Info UE_mac_inst[module_idP].scheduling_info.BSR[lcgid]=0; @@ -2344,6 +2358,8 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subfra if (rlc_status.bytes_in_buffer > 0) { + LOG_D(MAC,"[UE %d] PDCCH Tick : LCID%d LCGID%d has data to transmit =%d bytes at frame %d subframe %d\n", + module_idP, lcid,lcgid,rlc_status.bytes_in_buffer,frameP,subframeP); UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_NOT_EMPTY; //Update BSR_bytes and position in lcid_reordered_array only if Group is defined @@ -2381,6 +2397,9 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subfra // Check whether a regular BSR can be triggered according to the first cases in 36.321 if (num_lcid_with_data) { + LOG_D(MAC,"[UE %d] PDCCH Tick at frame %d subframe %d: NumLCID with data=%d Reordered LCID0=%d LCID1=%d LCID2=%d\n", + module_idP, frameP, subframeP,num_lcid_with_data,lcid_reordered_array[0],lcid_reordered_array[1],lcid_reordered_array[2]); + for (array_index=0; array_index < num_lcid_with_data; array_index++) { lcid = lcid_reordered_array[array_index]; @@ -2395,8 +2414,8 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subfra { bsr_regular_triggered = TRUE; - LOG_D(MAC,"[UE %d] PDCCH Tick : MAC BSR Triggered LCID%d data become available at frame %d subframe %d\n", - module_idP, lcid,frameP, subframeP); + LOG_D(MAC,"[UE %d] PDCCH Tick : MAC BSR Triggered LCID%d LCGID%d data become available at frame %d subframe %d\n", + module_idP, lcid,UE_mac_inst[module_idP].scheduling_info.LCGID[lcid],frameP, subframeP); break; } @@ -2407,8 +2426,10 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subfra { bsr_regular_triggered = TRUE; - LOG_D(MAC,"[UE %d] PDCCH Tick : MAC BSR Triggered ReTxBSR Timer expiry at frame %d subframe %d\n", - module_idP, frameP, subframeP); + if ((UE_mac_inst[module_idP].BSR_reporting_active & BSR_TRIGGER_REGULAR) == 0) { + LOG_I(MAC,"[UE %d] PDCCH Tick : MAC BSR Triggered ReTxBSR Timer expiry at frame %d subframe %d\n", + module_idP, frameP, subframeP); + } } } From eb711645d0a5530c19fbb33126f4d2881ff97843 Mon Sep 17 00:00:00 2001 From: hbilel Date: Thu, 24 Nov 2016 18:26:23 +0100 Subject: [PATCH 333/413] fix issue#33 : RLC AM BO --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 427d7c8a02..85104b940c 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -53,6 +53,7 @@ rlc_am_get_buffer_occupancy_in_bytes ( 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 TRACE_RLC_AM_BO @@ -64,7 +65,7 @@ rlc_am_get_buffer_occupancy_in_bytes ( } #endif - return ((15 + rlc_pP->num_nack_sn*(10+1) + rlc_pP->num_nack_so*(15+15+1) + 7) >> 3); + rlc_pP->status_buffer_occupancy = ((15 + rlc_pP->num_nack_sn*(10+1) + rlc_pP->num_nack_so*(15+15+1) + 7) >> 3); } } From 62ed687ef52f2e0b6c9dc3834116f06879917566 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Fri, 25 Nov 2016 10:05:56 +0100 Subject: [PATCH 334/413] [Gitlab CI] minor fix to logging --- cmake_targets/autotests/run_exec_lte-softmodem_tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py index ba54fa38b3..ab507578af 100755 --- a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py +++ b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py @@ -2190,6 +2190,8 @@ for testcase in testcaseList: #print "Machine list top level = " + ','.join(MachineList) if search_test_case_group(testcasename, testcasegroup, TestCaseExclusionList) == True: if testcaseclass == 'lte-softmodem' : + #First we wait for all the test cases in generic test case class to finish as they are running in parallel + threadListGlobal = wait_testcaseclass_generic_threads(threadListGlobal, Timeout_execution) eNBMachine = testcase.findtext('eNB',default='') UEMachine = testcase.findtext('UE',default='') EPCMachine = testcase.findtext('EPC',default='') @@ -2200,7 +2202,6 @@ for testcase in testcaseList: print "One of the machines is not in the machine list" print "eNBMachine : " + eNBMachine + "UEMachine : " + UEMachine + "EPCMachine : " + EPCMachine + "MachineList : " + ','.join(MachineList) print "testcasename = " + testcasename + " class = " + testcaseclass - threadListGlobal = wait_testcaseclass_generic_threads(threadListGlobal, Timeout_execution) #cleanOldProgramsAllMachines(oai_list, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop) handle_testcaseclass_softmodem (testcase, CleanUpOldProgs, logdirOAI5GRepo, logdirOpenaircnRepo, MachineList, user, pw, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, Timeout_cmd ) From 7f1bef9b650aa99ac6780d7c226c6b68f700a1b3 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Fri, 25 Nov 2016 10:53:26 +0100 Subject: [PATCH 335/413] minor fix to Google Protobuf logging in installation --- cmake_targets/tools/build_helper | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 7cde2811c8..448d54f334 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -164,6 +164,9 @@ compilations() { ############################################ install_protobuf_from_source(){ + protobuf_install_log=$OPENAIR_DIR/cmake_targets/log/protobuf_install_log.txt + echo_info "\nInstalling Google Protobuf from sources. The log file for Protobuf installation is here: $protobuf_install_log " + ( cd /tmp echo "Downloading protobuf" rm -rf /tmp/protobuf-2.6.1.tar.gz* /tmp/protobuf-2.6.1 @@ -174,11 +177,14 @@ install_protobuf_from_source(){ echo "Compiling protobuf" make -j`nproc` $SUDO make install - rm -rf /tmp/protobuf-2.6.1.tar.gz /tmp/protobuf-2.6.1 $SUDO ldconfig + ) >& $protobuf_install_log } install_protobuf_c_from_source(){ + protobuf_c_install_log=$OPENAIR_DIR/cmake_targets/log/protobuf_c_install_log.txt + echo_info "\nInstalling Google Protobuf_C from sources. The log file for Protobuf_C installation is here: $protobuf_c_install_log " + ( cd /tmp echo "Downloading protobuf-c" rm -rf /tmp/protobuf-c @@ -189,8 +195,8 @@ install_protobuf_c_from_source(){ echo "Compiling protobuf-c" make -j`nproc` $SUDO make install - rm -rf /tmp/protobuf-c $SUDO ldconfig + ) >& $protobuf_c_install_log } check_install_usrp_uhd_driver(){ @@ -396,6 +402,7 @@ remove_nettle_from_source() { cd nettle-2.5/ ./configure --disable-openssl --enable-shared --prefix=/usr $SUDO make uninstall || true + $SUDO ldconfig ) >& $nettle_uninstall_log } @@ -419,6 +426,7 @@ remove_gnutls_from_source(){ cd gnutls-3.1.23/ ./configure --prefix=/usr $SUDO make uninstall || true + $SUDO ldconfig )>& $gnutls_uninstall_log } @@ -433,6 +441,7 @@ install_asn1c_from_source(){ make -j`nproc` $SUDO make install cd - + $SUDO ldconfig ) > $asn1_install_log 2>&1 } From 0579d471546a4d9667b989492bedfb3262d01893 Mon Sep 17 00:00:00 2001 From: ROBERT Benoit Date: Fri, 25 Nov 2016 14:43:28 +0100 Subject: [PATCH 336/413] Complete autotest patch files set for OAI1B autotest setup --- .../autotests/patches/CmakeLists.patch | 12 ++++++ .../autotest_ue_dlsch_bitrate_metric.patch | 11 +++-- .../patches/autotest_ue_offsets_metric.patch | 31 ++++++++++++++ .../autotests/patches/build_oai.patch | 40 +++++++++++++++++++ cmake_targets/autotests/testsuite_ue_noS1.xml | 6 +-- 5 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 cmake_targets/autotests/patches/CmakeLists.patch create mode 100644 cmake_targets/autotests/patches/autotest_ue_offsets_metric.patch create mode 100644 cmake_targets/autotests/patches/build_oai.patch diff --git a/cmake_targets/autotests/patches/CmakeLists.patch b/cmake_targets/autotests/patches/CmakeLists.patch new file mode 100644 index 0000000000..9f2731ca73 --- /dev/null +++ b/cmake_targets/autotests/patches/CmakeLists.patch @@ -0,0 +1,12 @@ +diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt +index 3169c6c..eaf5417 100644 +--- a/cmake_targets/CMakeLists.txt ++++ b/cmake_targets/CMakeLists.txt +@@ -235,6 +235,7 @@ add_boolean_option(DEBUG_OMG False "???") + add_boolean_option(XFORMS False "This adds the possibility to see the signal oscilloscope") + add_boolean_option(PRINT_STATS False "This adds the possibility to see the status") + add_boolean_option(T_TRACER False "Activate the T tracer, a debugging/monitoring framework" ) ++add_boolean_option(UE_AUTOTEST_TRACE False "Activate UE autotest specific logs") + + add_boolean_option(DEBUG_CONSOLE False "makes debugging easier, disables stdout/stderr buffering") + diff --git a/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch b/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch index e8213960e1..b7a7dbfa02 100644 --- a/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch +++ b/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch @@ -1,18 +1,17 @@ diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c -index 3ed4c79..da88000 100644 +index 3ed4c79..6023886 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c -@@ -2944,6 +2944,14 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin +@@ -2944,6 +2944,13 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin LOG_D(PHY,"[UE %d] Calculating bitrate Frame %d: total_TBS = %d, total_TBS_last = %d, bitrate %f kbits\n", ue->Mod_id,frame_rx,ue->total_TBS[eNB_id], ue->total_TBS_last[eNB_id],(float) ue->bitrate[eNB_id]/1000.0); + -+ /* SYRTEM */ ++ #if UE_AUTOTEST_TRACE + if ((frame_rx % 100 == 0)) { -+ printf("AUTOTEST Metric : UE_DLSCH_BITRATE = %5.2f kbps (frame = %d) \n", (float) ue->bitrate[eNB_id]/1000.0, frame_rx); -+ /* End of SYRTEM */ ++ LOG_I(PHY,"[UE %d] AUTOTEST Metric : UE_DLSCH_BITRATE = %5.2f kbps (frame = %d) \n", ue->Mod_id, (float) ue->bitrate[eNB_id]/1000.0, frame_rx); + } -+ ++ #endif + } diff --git a/cmake_targets/autotests/patches/autotest_ue_offsets_metric.patch b/cmake_targets/autotests/patches/autotest_ue_offsets_metric.patch new file mode 100644 index 0000000000..3fca1a70fd --- /dev/null +++ b/cmake_targets/autotests/patches/autotest_ue_offsets_metric.patch @@ -0,0 +1,31 @@ +diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c +index 3ed4c79..7185e5a 100644 +--- a/openair1/SCHED/phy_procedures_lte_ue.c ++++ b/openair1/SCHED/phy_procedures_lte_ue.c +@@ -2748,7 +2748,25 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin + 0); + + // first slot has been processed (FFTs + Channel Estimation, PCFICH/PHICH/PDCCH) +- ++ ++ /* SYRTEM */ ++ if ( (frame_rx % 10 == 0) && (subframe_rx == 0)) { ++ printf("AUTOTEST Metric : UE_FREQ_OFFSET = %d Hz (frame = %d) \n", ue->common_vars.freq_offset, frame_rx); ++ printf("AUTOTEST Metric : UE_RX_OFFSET = %d (frame = %d) \n", ue->rx_offset, frame_rx); ++ ++ printf("AUTOTEST Metric : RRC Measurments RSRP[0] %.2f dBm/RE, RSSI %.2f dBm, RSRQ[0] %.2f dB, N0 %d dBm/RE, NF %.1f dB (frame = %d)\n", ++ 10*log10(ue->measurements.rsrp[0])-ue->rx_total_gain_dB, ++ 10*log10(ue->measurements.rssi)-ue->rx_total_gain_dB, ++ 10*log10(ue->measurements.rsrq[0]), ++ ue->measurements.n0_power_tot_dBm, ++ (double)ue->measurements.n0_power_tot_dBm+132.24, ++ frame_rx); ++ } ++ ++ ++ ++ ++ + // do procedures for C-RNTI + if (ue->dlsch[eNB_id][0]->active == 1) { + ue_pdsch_procedures(ue, diff --git a/cmake_targets/autotests/patches/build_oai.patch b/cmake_targets/autotests/patches/build_oai.patch new file mode 100644 index 0000000000..d6cecda6e5 --- /dev/null +++ b/cmake_targets/autotests/patches/build_oai.patch @@ -0,0 +1,40 @@ +diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai +index b77a9ba..8e3021d 100755 +--- a/cmake_targets/build_oai ++++ b/cmake_targets/build_oai +@@ -53,6 +53,7 @@ BUILD_DOXYGEN=0 + T_TRACER="False" + DISABLE_HARDWARE_DEPENDENCY="False" + CMAKE_BUILD_TYPE="" ++UE_AUTOTEST_TRACE="False" + trap handle_ctrl_c INT + + function print_help() { +@@ -127,6 +128,8 @@ Options + Enables the T tracer. + --disable-hardware-dependency + Disable HW dependency during installation ++--ue-autotest-trace ++ Enable specific traces for UE autotest framework + 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 +@@ -278,6 +281,10 @@ function main() { + echo_info "Disabling hardware dependency for compiling software" + DISABLE_HARDWARE_DEPENDENCY="True" + shift 1;; ++ --ue-autotest-trace) ++ UE_AUTOTEST_TRACE="True" ++ echo_info "Enabling autotest specific trace for UE" ++ shift 1;; + -h | --help) + print_help + exit 1;; +@@ -447,6 +454,7 @@ function main() { + echo "set (DEADLINE_SCHEDULER \"${DEADLINE_SCHEDULER_FLAG_USER}\" )" >>$cmake_file + echo "set (CPU_AFFINITY \"${CPU_AFFINITY_FLAG_USER}\" )" >>$cmake_file + echo "set ( T_TRACER $T_TRACER )" >> $cmake_file ++ echo "set (UE_AUTOTEST_TRACE $UE_AUTOTEST_TRACE)" >> $cmake_file + echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file + cd $DIR/$lte_build_dir/build + cmake .. diff --git a/cmake_targets/autotests/testsuite_ue_noS1.xml b/cmake_targets/autotests/testsuite_ue_noS1.xml index c2f87b881f..19b945dc28 100644 --- a/cmake_targets/autotests/testsuite_ue_noS1.xml +++ b/cmake_targets/autotests/testsuite_ue_noS1.xml @@ -2,11 +2,11 @@ imb182-desktop yanbo-M4HM87P-00 /mnt/sradio/TEST_RESULTS/ - https://gitlab.eurecom.fr/oai1B/openairinterface5g.git - + + https://gitlab.eurecom.fr/oai/openairinterface5g.git --> https://gitlab.eurecom.fr/oai/openair-cn.git --> - develop1B + Enhancement-142-OAI_UE_autotest_framework From 426e6cd74bd4de38095cc26ebeed42fbebbdab68 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Fri, 25 Nov 2016 16:55:35 +0100 Subject: [PATCH 337/413] bugfix for TDD: special subframe was not transmitted. --- openair1/SCHED/phy_procedures_lte_eNb.c | 2 +- targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c | 5 ++--- targets/RT/USER/lte-softmodem.c | 14 +++++--------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 6d0bc53ac8..c868a1a733 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -1119,7 +1119,7 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, #endif - if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_DL)) return; + if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)==SF_UL)) return; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX+offset,1); if (do_meas==1) start_meas(&eNB->phy_proc_tx); diff --git a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c index f25c09acb1..75aa4d2622 100644 --- a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c +++ b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c @@ -876,11 +876,8 @@ int openair0_config(openair0_config_t *openair0_cfg, int UE_flag) if (openair0_cfg[card].rx_freq[ant]>0) { p_exmimo_config->rf.rf_mode[ant] += (RXEN + DMAMODE_RX + RXLPFNORM + RXLPFEN + rx_filter); - p_exmimo_config->rf.rf_freq_rx[ant] = (unsigned int)openair0_cfg[card].rx_freq[ant]; - printf("openair0 : programming card %d RX antenna %d (freq %u, gain %d)\n",card,ant,p_exmimo_config->rf.rf_freq_rx[ant],p_exmimo_config->rf.rx_gain[ant][0]); - switch (openair0_cfg[card].rxg_mode[ant]) { default: case max_gain: @@ -916,6 +913,8 @@ int openair0_config(openair0_config_t *openair0_cfg, int UE_flag) } break; } + printf("openair0 : programming card %d RX antenna %d (freq %u, gain %d)\n",card,ant,p_exmimo_config->rf.rf_freq_rx[ant],p_exmimo_config->rf.rx_gain[ant][0]); + } else { p_exmimo_config->rf.rf_mode[ant] = 0; p_exmimo_config->rf.do_autocal[ant] = 0; diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index de5be6913c..6272fdb4eb 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1339,12 +1339,6 @@ void init_openair0() { else openair0_cfg[card].rx_freq[i]=0.0; - printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n", - card,i, openair0_cfg[card].tx_gain[i], - openair0_cfg[card].rx_gain[i], - openair0_cfg[card].tx_freq[i], - openair0_cfg[card].rx_freq[i]); - openair0_cfg[card].autocal[i] = 1; openair0_cfg[card].tx_gain[i] = tx_gain[0][i]; if (UE_flag == 0) { @@ -1354,10 +1348,12 @@ void init_openair0() { openair0_cfg[card].rx_gain[i] = PHY_vars_UE_g[0][0]->rx_total_gain_dB - rx_gain_off; } - + printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n", + card,i, openair0_cfg[card].tx_gain[i], + openair0_cfg[card].rx_gain[i], + openair0_cfg[card].tx_freq[i], + openair0_cfg[card].rx_freq[i]); } - - } } From 956135f9a3cbc63c3a3830bad877fe1aabad7537 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 25 Nov 2016 17:14:40 +0100 Subject: [PATCH 338/413] T: add mechanisms to free filters --- common/utils/T/tracer/filter/filter.c | 31 ++++++++++++++++++++++++++- common/utils/T/tracer/filter/filter.h | 2 ++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/common/utils/T/tracer/filter/filter.c b/common/utils/T/tracer/filter/filter.c index b09b01259d..d26dc25000 100644 --- a/common/utils/T/tracer/filter/filter.c +++ b/common/utils/T/tracer/filter/filter.c @@ -13,6 +13,7 @@ struct filter { } v; int (*eval)(struct filter *this, event e); + void (*free)(struct filter *this); }; /****************************************************************************/ @@ -52,7 +53,23 @@ int eval_evarg(struct filter *f, event e) } /****************************************************************************/ -/* filter construction functions */ +/* free memory functions */ +/****************************************************************************/ + +void free_op2(struct filter *f) +{ + free_filter(f->v.op2.a); + free_filter(f->v.op2.b); + free(f); +} + +void free_noop(struct filter *f) +{ + free(f); +} + +/****************************************************************************/ +/* filter construction/destruction functions */ /****************************************************************************/ filter *filter_and(filter *a, filter *b) @@ -60,6 +77,7 @@ filter *filter_and(filter *a, filter *b) struct filter *ret = calloc(1, sizeof(struct filter)); if (ret == NULL) abort(); ret->eval = eval_and; + ret->free = free_op2; ret->v.op2.a = a; ret->v.op2.b = b; return ret; @@ -70,6 +88,7 @@ filter *filter_eq(filter *a, filter *b) struct filter *ret = calloc(1, sizeof(struct filter)); if (ret == NULL) abort(); ret->eval = eval_eq; + ret->free = free_op2; ret->v.op2.a = a; ret->v.op2.b = b; return ret; @@ -80,6 +99,7 @@ filter *filter_int(int v) struct filter *ret = calloc(1, sizeof(struct filter)); if (ret == NULL) abort(); ret->eval = eval_int; + ret->free = free_noop; ret->v.v = v; return ret; } @@ -97,6 +117,7 @@ filter *filter_evarg(void *database, char *event_name, char *varname) f = get_format(database, event_id); ret->eval = eval_evarg; + ret->free = free_noop; ret->v.evarg.event_type = event_id; ret->v.evarg.arg_index = -1; @@ -114,6 +135,14 @@ filter *filter_evarg(void *database, char *event_name, char *varname) return ret; } +void free_filter(filter *_f) +{ + struct filter *f; + if (_f == NULL) return; + f = _f; + f->free(f); +} + /****************************************************************************/ /* eval function */ /****************************************************************************/ diff --git a/common/utils/T/tracer/filter/filter.h b/common/utils/T/tracer/filter/filter.h index eba02d7fb7..d45e0bdd86 100644 --- a/common/utils/T/tracer/filter/filter.h +++ b/common/utils/T/tracer/filter/filter.h @@ -12,4 +12,6 @@ filter *filter_evarg(void *database, char *event_name, char *varname); int filter_eval(filter *f, event e); +void free_filter(filter *f); + #endif /* _FILTER_H_ */ From 0bb875d9c2b98c01484653335c2cca9d59726a16 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 25 Nov 2016 17:15:25 +0100 Subject: [PATCH 339/413] T: free previous filter in logger_set_filter --- common/utils/T/tracer/logger/logger.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/utils/T/tracer/logger/logger.c b/common/utils/T/tracer/logger/logger.c index ab6fb8bc62..ffba2d25c0 100644 --- a/common/utils/T/tracer/logger/logger.c +++ b/common/utils/T/tracer/logger/logger.c @@ -1,5 +1,6 @@ #include "logger.h" #include "logger_defs.h" +#include "filter/filter.h" #include void logger_add_view(logger *_l, view *v) @@ -13,5 +14,6 @@ void logger_add_view(logger *_l, view *v) void logger_set_filter(logger *_l, void *filter) { struct logger *l = _l; + free_filter(l->filter); l->filter = filter; } From 8eeebdaf982dce42cbf27e27576aab5a9a6d5eb2 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 25 Nov 2016 17:17:16 +0100 Subject: [PATCH 340/413] T: add function label_set_text --- common/utils/T/tracer/gui/gui.h | 1 + common/utils/T/tracer/gui/gui_defs.h | 2 +- common/utils/T/tracer/gui/label.c | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/common/utils/T/tracer/gui/gui.h b/common/utils/T/tracer/gui/gui.h index 27e6603042..0eebae91ba 100644 --- a/common/utils/T/tracer/gui/gui.h +++ b/common/utils/T/tracer/gui/gui.h @@ -39,6 +39,7 @@ widget *new_space(gui *gui, int width, int height); widget *new_image(gui *gui, unsigned char *data, int length); void label_set_clickable(gui *gui, widget *label, int clickable); +void label_set_text(gui *gui, widget *label, char *text); void container_set_child_growable(gui *_gui, widget *_this, widget *child, int growable); diff --git a/common/utils/T/tracer/gui/gui_defs.h b/common/utils/T/tracer/gui/gui_defs.h index ec72bb0e2b..938641178c 100644 --- a/common/utils/T/tracer/gui/gui_defs.h +++ b/common/utils/T/tracer/gui/gui_defs.h @@ -141,7 +141,7 @@ struct button_widget { struct label_widget { struct widget common; - const char *t; + char *t; int color; int width; /* as given by the graphic's backend */ int height; /* as given by the graphic's backend */ diff --git a/common/utils/T/tracer/gui/label.c b/common/utils/T/tracer/gui/label.c index f649fa5201..02efabfaf3 100644 --- a/common/utils/T/tracer/gui/label.c +++ b/common/utils/T/tracer/gui/label.c @@ -81,3 +81,21 @@ void label_set_clickable(gui *_g, widget *_this, int clickable) gunlock(g); } + +void label_set_text(gui *_g, widget *_this, char *text) +{ + struct gui *g = _g; + struct label_widget *this = _this; + + glock(g); + + free(this->t); + this->t = strdup(text); if (this->t == NULL) OOM; + + x_text_get_dimensions(g->x, DEFAULT_FONT, text, + &this->width, &this->height, &this->baseline); + + send_event(g, REPACK, this->common.id); + + gunlock(g); +} From 484cad24311b324d1dffe2c883e84b47638ac21b Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 25 Nov 2016 17:17:39 +0100 Subject: [PATCH 341/413] T: add function xy_plot_set_title --- common/utils/T/tracer/gui/gui.h | 1 + common/utils/T/tracer/gui/xy_plot.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/common/utils/T/tracer/gui/gui.h b/common/utils/T/tracer/gui/gui.h index 0eebae91ba..c61c2dc6c0 100644 --- a/common/utils/T/tracer/gui/gui.h +++ b/common/utils/T/tracer/gui/gui.h @@ -50,6 +50,7 @@ void xy_plot_set_range(gui *gui, widget *this, void xy_plot_set_points(gui *gui, widget *this, int plot, int npoints, float *x, float *y); void xy_plot_get_dimensions(gui *gui, widget *this, int *width, int *height); +void xy_plot_set_title(gui *gui, widget *this, char *label); void textlist_add(gui *gui, widget *this, const char *text, int position, int color); diff --git a/common/utils/T/tracer/gui/xy_plot.c b/common/utils/T/tracer/gui/xy_plot.c index 7d20a027a1..9342a5a464 100644 --- a/common/utils/T/tracer/gui/xy_plot.c +++ b/common/utils/T/tracer/gui/xy_plot.c @@ -290,3 +290,22 @@ void xy_plot_get_dimensions(gui *_gui, widget *_this, int *width, int *height) gunlock(g); } + +void xy_plot_set_title(gui *_gui, widget *_this, char *label) +{ + struct gui *g = _gui; + struct xy_plot_widget *this = _this; + + glock(g); + + free(this->label); + this->label = strdup(label); if (this->label == NULL) OOM; + /* TODO: be sure calling X there is valid wrt "global model" (we are + * not in the "gui thread") */ + x_text_get_dimensions(g->x, DEFAULT_FONT, label, + &this->label_width, &this->label_height, &this->label_baseline); + + send_event(g, REPACK, this->common.id); + + gunlock(g); +} From ee934102b6c98acfe4fd2cdf3fa29c1f1bdbd9c8 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 25 Nov 2016 17:19:33 +0100 Subject: [PATCH 342/413] T: switch UE in enb tracer Just below the logo you see the current UE, eg. [UE 0], and near that you have two "buttons" [prev UE] and [next UE]. You click with left button of mouse on those and the various plots that depend on the UE are now done for the new UE (say UE 1 instead of UE 0 if you click on [next UE]). The plots are not cleared when you switch. Let's say it's a feature. --- common/utils/T/tracer/enb.c | 214 +++++++++++++++++++++++++++--------- 1 file changed, 160 insertions(+), 54 deletions(-) diff --git a/common/utils/T/tracer/enb.c b/common/utils/T/tracer/enb.c index f041f21871..5d785782ea 100644 --- a/common/utils/T/tracer/enb.c +++ b/common/utils/T/tracer/enb.c @@ -24,6 +24,26 @@ typedef struct { view *pdcpview; view *rrcview; view *legacy; + widget *current_ue_label; + widget *prev_ue_button; + widget *next_ue_button; + widget *pusch_iq_ue_xy_plot; + widget *ul_estimate_ue_xy_plot; + widget *pucch1_energy_ue_xy_plot; + widget *pucch_iq_ue_xy_plot; + widget *dl_ul_harq_ue_label; + logger *pusch_iq_ue_logger; + logger *ul_estimate_ue_logger; + logger *pucch1_energy_ue_threshold_logger; + logger *pucch1_energy_ue_energy_logger; + logger *pucch_iq_ue_logger; + logger *dl_dci_logger[8]; + logger *dl_ack_logger[8]; + logger *dl_nack_logger[8]; + logger *ul_dci_logger[8]; + logger *ul_dci_retransmission_logger[8]; + logger *ul_ack_logger[8]; + logger *ul_nack_logger[8]; } enb_gui; typedef struct { @@ -31,6 +51,9 @@ typedef struct { int *is_on; int nevents; pthread_mutex_t lock; + enb_gui *e; + int ue; /* what UE is displayed in the UE specific views */ + void *database; } enb_data; void is_on_changed(void *_d) @@ -86,18 +109,93 @@ static void *gui_thread(void *_g) return NULL; } -static filter *ticktime_filter(void *database, char *event, int i) +static filter *ticktime_filter(void *database, char *event, int i, int ue) { /* filter is "harq_pid == i && UE_id == 0 && eNB_id == 0" */ return filter_and( filter_eq(filter_evarg(database, event, "harq_pid"), filter_int(i)), filter_and( - filter_eq(filter_evarg(database, event, "UE_id"), filter_int(0)), + filter_eq(filter_evarg(database, event, "UE_id"), filter_int(ue)), filter_eq(filter_evarg(database, event, "eNB_ID"), filter_int(0)))); } -static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database) +static void set_current_ue(gui *g, enb_data *e, int ue) +{ + int i; + char s[256]; + + sprintf(s, "[UE %d] ", ue); + label_set_text(g, e->e->current_ue_label, s); + sprintf(s, "PUSCH IQ [UE %d]", ue); + xy_plot_set_title(g, e->e->pusch_iq_ue_xy_plot, s); + sprintf(s, "UL estimated channel [UE %d]", ue); + xy_plot_set_title(g, e->e->ul_estimate_ue_xy_plot, s); + sprintf(s, "PUCCH1 energy (SR) [UE %d]", ue); + xy_plot_set_title(g, e->e->pucch1_energy_ue_xy_plot, s); + sprintf(s, "PUCCH IQ [UE %d]", ue); + xy_plot_set_title(g, e->e->pucch_iq_ue_xy_plot, s); + sprintf(s, "DL/UL HARQ (x8) [UE %d]", ue); + label_set_text(g, e->e->dl_ul_harq_ue_label, s); + + logger_set_filter(e->e->pusch_iq_ue_logger, + filter_eq( + filter_evarg(e->database, "ENB_PHY_PUSCH_IQ", "UE_ID"), + filter_int(ue))); + logger_set_filter(e->e->ul_estimate_ue_logger, + filter_eq( + filter_evarg(e->database, "ENB_PHY_UL_CHANNEL_ESTIMATE", "UE_ID"), + filter_int(ue))); + logger_set_filter(e->e->pucch1_energy_ue_threshold_logger, + filter_eq( + filter_evarg(e->database, "ENB_PHY_PUCCH_1_ENERGY", "UE_ID"), + filter_int(ue))); + logger_set_filter(e->e->pucch1_energy_ue_energy_logger, + filter_eq( + filter_evarg(e->database, "ENB_PHY_PUCCH_1_ENERGY", "UE_ID"), + filter_int(ue))); + logger_set_filter(e->e->pucch_iq_ue_logger, + filter_eq( + filter_evarg(e->database, "ENB_PHY_PUCCH_1AB_IQ", "UE_ID"), + filter_int(ue))); + for (i = 0; i < 8; i++) { + logger_set_filter(e->e->dl_dci_logger[i], + ticktime_filter(e->database, "ENB_PHY_DLSCH_UE_DCI", i, ue)); + logger_set_filter(e->e->dl_ack_logger[i], + ticktime_filter(e->database, "ENB_PHY_DLSCH_UE_ACK", i, ue)); + logger_set_filter(e->e->dl_nack_logger[i], + ticktime_filter(e->database, "ENB_PHY_DLSCH_UE_NACK", i, ue)); + logger_set_filter(e->e->ul_dci_logger[i], + ticktime_filter(e->database, "ENB_PHY_ULSCH_UE_DCI", i, ue)); + logger_set_filter(e->e->ul_dci_retransmission_logger[i], + ticktime_filter(e->database, + "ENB_PHY_ULSCH_UE_NO_DCI_RETRANSMISSION", i, ue)); + logger_set_filter(e->e->ul_ack_logger[i], + ticktime_filter(e->database, "ENB_PHY_ULSCH_UE_ACK", i, ue)); + logger_set_filter(e->e->ul_nack_logger[i], + ticktime_filter(e->database, "ENB_PHY_ULSCH_UE_NACK", i, ue)); + } +} + +static void click(void *private, gui *g, + char *notification, widget *w, void *notification_data) +{ + int *d = notification_data; + int button = d[0]; + enb_data *ed = private; + enb_gui *e = ed->e; + int ue = ed->ue; + + if (button != 1) return; + if (w == e->prev_ue_button) { ue--; if (ue < 0) ue = 0; } + if (w == e->next_ue_button) ue++; + + if (ue != ed->ue) set_current_ue(g, ed, ue); + ed->ue = ue; +} + +static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database, + enb_data *ed) { widget *main_window; widget *top_container; @@ -113,7 +211,7 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database) widget *text; view *textview; int i; - widget *w; + widget *w, *w2; view *v; logger *l; @@ -124,7 +222,26 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database) line = new_container(g, HORIZONTAL); widget_add_child(g, top_container, line, -1); logo = new_image(g, openair_logo_png, openair_logo_png_len); - widget_add_child(g, line, logo, -1); + + /* logo + prev/next UE buttons */ + col = new_container(g, VERTICAL); + widget_add_child(g, col, logo, -1); + w = new_container(g, HORIZONTAL); + widget_add_child(g, col, w, -1); + w2 = new_label(g, ""); + widget_add_child(g, w, w2, -1); + e->current_ue_label = w2; + /* TODO: use button widget, not label widget */ + w2 = new_label(g, " [prev UE] "); + widget_add_child(g, w, w2, -1); + label_set_clickable(g, w2, 1); + e->prev_ue_button = w2; + w2 = new_label(g, " [next UE] "); + widget_add_child(g, w, w2, -1); + label_set_clickable(g, w2, 1); + e->next_ue_button = w2; + widget_add_child(g, line, col, -1); + input_signal_plot = new_xy_plot(g, 256, 55, "input signal", 20); widget_add_child(g, line, input_signal_plot, -1); xy_plot_set_range(g, input_signal_plot, 0, 7680*10, 20, 70); @@ -138,21 +255,20 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database) g, input_signal_plot, new_color(g, "#0c0c72"), XY_LOOP_MODE); logger_add_view(input_signal_log, input_signal_view); - /* UE 0 PUSCH IQ data */ - w = new_xy_plot(g, 55, 55, "PUSCH IQ [UE 0]", 50); + /* UE x PUSCH IQ data */ + w = new_xy_plot(g, 55, 55, "", 50); + e->pusch_iq_ue_xy_plot = w; widget_add_child(g, line, w, -1); xy_plot_set_range(g, w, -1000, 1000, -1000, 1000); l = new_iqlog(h, database, "ENB_PHY_PUSCH_IQ", "nb_rb", "N_RB_UL", "symbols_per_tti", "pusch_comp"); v = new_view_xy(100*12*14,10,g,w,new_color(g,"#000"),XY_FORCED_MODE); logger_add_view(l, v); - logger_set_filter(l, - filter_eq( - filter_evarg(database, "ENB_PHY_PUSCH_IQ", "UE_ID"), - filter_int(0))); + e->pusch_iq_ue_logger = l; - /* UE 0 estimated UL channel */ - w = new_xy_plot(g, 280, 55, "UL estimated channel [UE 0]", 50); + /* UE x estimated UL channel */ + w = new_xy_plot(g, 280, 55, "", 50); + e->ul_estimate_ue_xy_plot = w; widget_add_child(g, line, w, -1); xy_plot_set_range(g, w, 0, 512*10, -10, 80); l = new_framelog(h, database, @@ -161,43 +277,33 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database) framelog_set_update_only_at_sf9(l, 0); v = new_view_xy(512*10, 10, g, w, new_color(g, "#0c0c72"), XY_LOOP_MODE); logger_add_view(l, v); - logger_set_filter(l, - filter_eq( - filter_evarg(database, "ENB_PHY_UL_CHANNEL_ESTIMATE", "UE_ID"), - filter_int(0))); + e->ul_estimate_ue_logger = l; - /* UE 0 PUCCH energy */ - w = new_xy_plot(g, 128, 55, "PUCCH1 energy (SR) [UE 0]", 50); + /* UE x PUCCH energy */ + w = new_xy_plot(g, 128, 55, "", 50); + e->pucch1_energy_ue_xy_plot = w; widget_add_child(g, line, w, -1); xy_plot_set_range(g, w, 0, 1024*10, -10, 80); l = new_ttilog(h, database, "ENB_PHY_PUCCH_1_ENERGY", "frame", "subframe", "threshold", 0); v = new_view_tti(10, g, w, new_color(g, "#ff0000")); logger_add_view(l, v); - logger_set_filter(l, - filter_eq( - filter_evarg(database, "ENB_PHY_PUCCH_1_ENERGY", "UE_ID"), - filter_int(0))); + e->pucch1_energy_ue_threshold_logger = l; l = new_ttilog(h, database, "ENB_PHY_PUCCH_1_ENERGY", "frame", "subframe", "energy", 1); v = new_view_tti(10, g, w, new_color(g, "#0c0c72")); logger_add_view(l, v); - logger_set_filter(l, - filter_eq( - filter_evarg(database, "ENB_PHY_PUCCH_1_ENERGY", "UE_ID"), - filter_int(0))); + e->pucch1_energy_ue_energy_logger = l; - /* UE 0 PUCCH IQ data */ - w = new_xy_plot(g, 55, 55, "PUCCH IQ [UE 0]", 50); + /* UE x PUCCH IQ data */ + w = new_xy_plot(g, 55, 55, "", 50); + e->pucch_iq_ue_xy_plot = w; widget_add_child(g, line, w, -1); - xy_plot_set_range(g, w, -100, 100, -100, 100); + xy_plot_set_range(g, w, -2000, 2000, -2000, 2000); l = new_iqdotlog(h, database, "ENB_PHY_PUCCH_1AB_IQ", "I", "Q"); v = new_view_xy(500, 10, g, w, new_color(g,"#000"), XY_LOOP_MODE); logger_add_view(l, v); - logger_set_filter(l, - filter_eq( - filter_evarg(database, "ENB_PHY_PUCCH_1AB_IQ", "UE_ID"), - filter_int(0))); + e->pucch_iq_ue_logger = l; /* downlink/uplink UE DCIs */ widget_add_child(g, top_container, @@ -250,8 +356,8 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database) logger_add_view(timelog, subview); /* harq processes' ticktime view */ - widget_add_child(g, top_container, - new_label(g,"DL/UL HARQ (x8) [UE 0]"), -1); + e->dl_ul_harq_ue_label = new_label(g, ""); + widget_add_child(g, top_container, e->dl_ul_harq_ue_label, -1); line = new_container(g, HORIZONTAL); widget_add_child(g, top_container, line, -1); timeline_plot = new_timeline(g, 512, 2*8+2, 3); @@ -271,15 +377,14 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database) /* tick on UL view */ subview = new_subview_ticktime(timeview, 9, new_color(g,"#bbb"), 3600*1000); logger_add_view(timelog, subview); - /* DL harq pids */ + /* DL DCI */ for (i = 0; i < 8; i++) { timelog = new_ticklog(h, database, "ENB_PHY_DLSCH_UE_DCI", "frame", "subframe"); subview = new_subview_ticktime(timeview, i+1, new_color(g,"#55f"), 3600*1000); logger_add_view(timelog, subview); - logger_set_filter(timelog, - ticktime_filter(database, "ENB_PHY_DLSCH_UE_DCI", i)); + e->dl_dci_logger[i] = timelog; } /* DL ACK */ for (i = 0; i < 8; i++) { @@ -288,8 +393,7 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database) subview = new_subview_ticktime(timeview, i+1, new_color(g,"#282"), 3600*1000); logger_add_view(timelog, subview); - logger_set_filter(timelog, - ticktime_filter(database, "ENB_PHY_DLSCH_UE_ACK", i)); + e->dl_ack_logger[i] = timelog; } /* DL NACK */ for (i = 0; i < 8; i++) { @@ -298,10 +402,9 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database) subview = new_subview_ticktime(timeview, i+1, new_color(g,"#f22"), 3600*1000); logger_add_view(timelog, subview); - logger_set_filter(timelog, - ticktime_filter(database, "ENB_PHY_DLSCH_UE_NACK", i)); + e->dl_nack_logger[i] = timelog; } - /* UL harq pids */ + /* UL DCI/retransmission without DCI */ for (i = 0; i < 8; i++) { /* first transmission */ timelog = new_ticklog(h, database, "ENB_PHY_ULSCH_UE_DCI", @@ -309,17 +412,14 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database) subview = new_subview_ticktime(timeview, i+9+1, new_color(g,"#55f"), 3600*1000); logger_add_view(timelog, subview); - logger_set_filter(timelog, - ticktime_filter(database, "ENB_PHY_ULSCH_UE_DCI", i)); + e->ul_dci_logger[i] = timelog; /* retransmission */ timelog = new_ticklog(h, database, "ENB_PHY_ULSCH_UE_NO_DCI_RETRANSMISSION", "frame", "subframe"); subview = new_subview_ticktime(timeview, i+9+1, new_color(g,"#99f"), 3600*1000); logger_add_view(timelog, subview); - logger_set_filter(timelog, - ticktime_filter(database, - "ENB_PHY_ULSCH_UE_NO_DCI_RETRANSMISSION", i)); + e->ul_dci_retransmission_logger[i] = timelog; } /* UL ACK */ for (i = 0; i < 8; i++) { @@ -328,8 +428,7 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database) subview = new_subview_ticktime(timeview, i+9+1, new_color(g,"#282"), 3600*1000); logger_add_view(timelog, subview); - logger_set_filter(timelog, - ticktime_filter(database, "ENB_PHY_ULSCH_UE_ACK", i)); + e->ul_ack_logger[i] = timelog; } /* UL NACK */ for (i = 0; i < 8; i++) { @@ -338,8 +437,7 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database) subview = new_subview_ticktime(timeview, i+9+1, new_color(g,"#f22"), 3600*1000); logger_add_view(timelog, subview); - logger_set_filter(timelog, - ticktime_filter(database, "ENB_PHY_ULSCH_UE_NACK", i)); + e->ul_nack_logger[i] = timelog; } /* phy/mac/rlc/pdcp/rrc textlog */ @@ -416,6 +514,10 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database) widget_add_child(g, top_container, text, -1); container_set_child_growable(g, top_container, text, 1); e->legacy = new_view_textlist(10000, 10, g, text); + + set_current_ue(g, ed, 0); + register_notifier(g, "click", e->prev_ue_button, click, ed); + register_notifier(g, "click", e->next_ue_button, click, ed); } void view_add_log(view *v, char *log, event_handler *h, void *database, @@ -495,7 +597,11 @@ int main(int n, char **v) g = gui_init(); new_thread(gui_thread, g); - enb_main_gui(&eg, g, h, database); + enb_data.ue = 0; + enb_data.e = ⪚ + enb_data.database = database; + + enb_main_gui(&eg, g, h, database, &enb_data); for (i = 0; i < number_of_events; i++) { logger *textlog; From 6e21152facb0eb5b6498ec59d9af1aa69b5bb7a4 Mon Sep 17 00:00:00 2001 From: GabrirelCouturier Date: Mon, 28 Nov 2016 10:21:01 +0100 Subject: [PATCH 343/413] [OAI-UE] fixes for issue#35 issue#36 issue#37 1-issue#35: miss dci detection 2-issue#36: ack/nack on pusch are badly encoded 3-issue#37: ack/nack are sent on pucch instead of pusch --- openair1/PHY/CODING/lte_segmentation.c | 2 +- openair1/PHY/LTE_TRANSPORT/dci.c | 8 ++-- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 14 +++++- openair1/PHY/LTE_TRANSPORT/phich.c | 5 ++- openair1/PHY/LTE_TRANSPORT/ulsch_coding.c | 2 +- openair1/SCHED/phy_procedures_lte_ue.c | 53 +++++++++++++++++++---- 6 files changed, 65 insertions(+), 19 deletions(-) diff --git a/openair1/PHY/CODING/lte_segmentation.c b/openair1/PHY/CODING/lte_segmentation.c index 746344a6ac..04056c4c9e 100644 --- a/openair1/PHY/CODING/lte_segmentation.c +++ b/openair1/PHY/CODING/lte_segmentation.c @@ -60,7 +60,7 @@ int lte_segmentation(unsigned char *input_buffer, } if ((*C)>MAX_NUM_DLSCH_SEGMENTS) { - msg("lte_segmentation.c: too many segments %d\n",*C); + LOG_E(PHY,"lte_segmentation.c: too many segments %d, B %d, L %d, Bprime %d\n",*C,B,L,Bprime); return(-1); } diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index bd2f162312..38cfc2c8c9 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -3248,7 +3248,7 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *ue, SI_RNTI, ra_rnti, P_RNTI, - 3, + 0, format1A, format1A, format1A, @@ -3277,7 +3277,7 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *ue, SI_RNTI, ra_rnti, P_RNTI, - 2, + 1, format1A, format1A, format1A, @@ -3310,7 +3310,7 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *ue, SI_RNTI, ra_rnti, P_RNTI, - 1, + 2, format1A, format1A, format1A, @@ -3339,7 +3339,7 @@ uint16_t dci_decoding_procedure(PHY_VARS_UE *ue, SI_RNTI, ra_rnti, P_RNTI, - 0, + 3, format1A, format1A, format1A, diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 107fa042a6..92836ebcf9 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -4456,6 +4456,7 @@ int generate_ue_dlsch_params_from_dci(int frame, dlsch0_harq->status = ACTIVE; dlsch0_harq->DCINdi = ndi; + dlsch[0]->harq_ack[subframe].send_harq_status = 1; if (dlsch0_harq->first_tx==1) { LOG_D(PHY,"[PDSCH %x/%d] Format 1 DCI First TX: Clearing flag\n"); dlsch0_harq->first_tx = 0; @@ -5556,7 +5557,7 @@ int generate_ue_dlsch_params_from_dci(int frame, #ifdef DEBUG_DCI if (dlsch[0] && (dlsch[0]->rnti != 0xffff)) { - printf("dci_format:%d \n",dci_format); + printf("dci_format:%d Abssubframe: %d.%d \n",dci_format,frame,subframe); printf("PDSCH dlsch0 UE: rnti %x\n",dlsch[0]->rnti); printf("PDSCH dlsch0 UE: NBRB %d\n",dlsch0_harq->nb_rb); printf("PDSCH dlsch0 UE: rballoc %x\n",dlsch0_harq->rb_alloc_even[0]); @@ -6231,13 +6232,22 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, uint8_t harq_pid; uint8_t transmission_mode = ue->transmission_mode[eNB_id]; - ANFBmode_t AckNackFBMode = ue->pucch_config_dedicated[eNB_id].tdd_AckNackFeedbackMode; + ANFBmode_t AckNackFBMode; LTE_UE_ULSCH_t *ulsch = ue->ulsch[eNB_id]; // LTE_UE_DLSCH_t **dlsch = ue->dlsch[0]; PHY_MEASUREMENTS *meas = &ue->measurements; LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; // uint32_t current_dlsch_cqi = ue->current_dlsch_cqi[eNB_id]; + if(frame_parms->frame_type == TDD) + { + AckNackFBMode = ue->pucch_config_dedicated[eNB_id].tdd_AckNackFeedbackMode; + } + else + { + AckNackFBMode = 1; // 1: multiplexing for FDD + } + uint32_t cqi_req; uint32_t dai=0; uint32_t cshift; diff --git a/openair1/PHY/LTE_TRANSPORT/phich.c b/openair1/PHY/LTE_TRANSPORT/phich.c index 2d07ba948a..9a32876602 100644 --- a/openair1/PHY/LTE_TRANSPORT/phich.c +++ b/openair1/PHY/LTE_TRANSPORT/phich.c @@ -1050,7 +1050,6 @@ void generate_phich(LTE_DL_FRAME_PARMS *frame_parms, // This routine demodulates the PHICH and updates PUSCH/ULSCH parameters - void rx_phich(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t subframe, @@ -1085,8 +1084,10 @@ void rx_phich(PHY_VARS_UE *ue, if (!ulsch) return; + LOG_D(PHY,"[UE %d][PUSCH %d] Frame %d subframe %d PHICH RX Status: %d \n",ue->Mod_id,harq_pid,proc->frame_rx,subframe, ulsch->harq_processes[harq_pid]->status); + if (ulsch->harq_processes[harq_pid]->status == ACTIVE) { - LOG_D(PHY,"[UE %d][PUSCH %d] Frame %d subframe %d PHICH RX ACTIVE\n",ue->Mod_id,harq_pid,proc->frame_rx,subframe); + LOG_D(PHY,"[UE %d][PUSCH %d] Frame %d subframe %d PHICH RX ACTIVE\n",ue->Mod_id,harq_pid,proc->frame_rx,subframe); Ngroup_PHICH = (frame_parms->phich_config_common.phich_resource*frame_parms->N_RB_DL)/48; if (((frame_parms->phich_config_common.phich_resource*frame_parms->N_RB_DL)%48) > 0) diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c index 6d2d6232cb..fe4e05747a 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c @@ -501,7 +501,7 @@ uint32_t ulsch_encoding(uint8_t *a, ulsch->harq_processes[harq_pid]->G = G; /* - LOG_I(PHY,"ULSCH Encoding G %d, Q_RI %d (O_RI%d, Msc_initial %d, Nsymb_initial%d, beta_offset_ri_times8 %d), Q_CQI %d \n",G,Q_RI,ulsch->O_RI,ulsch->harq_processes[harq_pid]->Msc_initial,ulsch->harq_processes[harq_pid]->Nsymb_initial,ulsch->beta_offset_ri_times8,Q_CQI); + LOG_I(PHY,"ULSCH Encoding G %d, Q_RI %d (O_RI%d, Msc_initial %d, Nsymb_initial%d, beta_offset_ri_times8 %d), Q_CQI %d, Q_ACK %d \n",G,Q_RI,ulsch->O_RI,ulsch->harq_processes[harq_pid]->Msc_initial,ulsch->harq_processes[harq_pid]->Nsymb_initial,ulsch->beta_offset_ri_times8,Q_CQI,Q_ACK); LOG_I(PHY,"ULSCH Encoding (Nid_cell %d, rnti %x): harq_pid %d round %d, RV %d, mcs %d, O_RI %d, O_ACK %d, G %d\n", frame_parms->Nid_cell,ulsch->rnti, diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 6e7354f883..5dc629b90b 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -61,6 +61,9 @@ fifo_dump_emos_UE emos_dump_UE; # include "intertask_interface.h" #endif +#include "PHY/defs.h" + +#include "PHY/CODING/extern.h" #define DLSCH_RB_ALLOC 0x1fbf // skip DC RB (total 23/25 RBs) #define DLSCH_RB_ALLOC_12 0x0aaa // skip DC RB (total 23/25 RBs) @@ -1026,6 +1029,15 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc) { } #endif #endif + /* + only for debug + LOG_I(PHY,"ul-signal [subframe: %d, ulsch_start %d, TA: %d, rxOffset: %d, timing_advance: %d, hw_timing_advance: %d]\n",subframe_tx, ulsch_start, ue->N_TA_offset, ue->rx_offset, ue->timing_advance, ue->hw_timing_advance); + if( (crash == 1) && (subframe_tx == 0) ) + { + LOG_E(PHY,"***** DUMP TX Signal [ulsch_start %d] *****\n",ulsch_start); + write_output("txBuff.m","txSignal",&ue->common_vars.txdata[aa][ulsch_start],frame_parms->samples_per_tti,1,1); + } + */ } //nb_antennas_tx @@ -1242,6 +1254,27 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB + + if (ack_status > 0) { + + // check if we received a PDSCH at subframe_tx - 4 + // ==> send ACK/NACK on PUSCH + if( (ue->dlsch[eNB_id][0]->harq_ack[proc->subframe_rx].send_harq_status) == 1) + { + ue->ulsch[eNB_id]->harq_processes[harq_pid]->O_ACK = 1; + } + else + { + ue->ulsch[eNB_id]->harq_processes[harq_pid]->O_ACK = 0; + } + LOG_D(PHY,"[UE %d][PDSCH %x] Frame %d subframe %d Generating ACK (%d,%d) for %d bits on PUSCH\n", + Mod_id, + ue->ulsch[eNB_id]->rnti, + frame_tx,subframe_tx, + ue->ulsch[eNB_id]->o_ACK[0],ue->ulsch[eNB_id]->o_ACK[1], + ue->ulsch[eNB_id]->harq_processes[harq_pid]->O_ACK); + } + #ifdef DEBUG_PHY_PROC LOG_D(PHY, "[UE %d][PUSCH %d] Frame %d subframe %d Generating PUSCH : first_rb %d, nb_rb %d, round %d, mcs %d, rv %d, cyclic_shift %d (cyclic_shift_common %d,n_DMRS2 %d,n_PRS %d), ACK (%d,%d), O_ACK %d\n", @@ -1260,15 +1293,6 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB ue->ulsch[eNB_id]->harq_processes[harq_pid]->O_ACK); #endif - if (ack_status > 0) { - LOG_D(PHY,"[UE %d][PDSCH %x] Frame %d subframe %d Generating ACK (%d,%d) for %d bits on PUSCH\n", - Mod_id, - ue->ulsch[eNB_id]->rnti, - frame_tx,subframe_tx, - ue->ulsch[eNB_id]->o_ACK[0],ue->ulsch[eNB_id]->o_ACK[1], - ue->ulsch[eNB_id]->harq_processes[harq_pid]->O_ACK); - } - @@ -1535,6 +1559,17 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin ACK/NACK and SR using the shortened PUCCH format. This shortened PUCCH format shall be used in a cell specific SRS subframe even if the UE does not transmit SRS in that subframe */ + + int harq_pid = subframe2harq_pid(&ue->frame_parms, + frame_tx, + subframe_tx); + + if(ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag) + { + LOG_D(PHY,"PUSCH is programmed on this subframe [pid %d] AbsSuframe %d.%d ==> Skip PUCCH transmission \n",harq_pid,frame_tx,subframe_tx); + return; + } + uint8_t isShortenPucch = (pSoundingrs_ul_config_dedicated->srsCellSubframe && frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission); bundling_flag = ue->pucch_config_dedicated[eNB_id].tdd_AckNackFeedbackMode; From ca2aeaccb87894f36d51a59ac5fb0da90f160d02 Mon Sep 17 00:00:00 2001 From: hbilel Date: Mon, 28 Nov 2016 10:36:46 +0100 Subject: [PATCH 344/413] BSR and MAC multiplexing fixes --- openair2/LAYER2/MAC/defs.h | 8 +- openair2/LAYER2/MAC/ue_procedures.c | 524 ++++++++++++------------- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 1 + 3 files changed, 261 insertions(+), 272 deletions(-) diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index de9071525d..cb1b2e4917 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -133,12 +133,18 @@ /*!\brief maximum value for channel quality indicator */ #define MAX_CQI_VALUE 15 -//if value equal oxFFFF means counters are NOT active +/*!\brief value for indicating BSR Timer is not running */ #define MAC_UE_BSR_TIMER_NOT_RUNNING (0xFFFF) #define LCID_EMPTY 0 #define LCID_NOT_EMPTY 1 +/*!\brief minimum RLC PDU size to be transmitted = min RLC Status PDU or RLC UM PDU SN 5 bits */ +#define MIN_RLC_PDU_SIZE (2) + +/*!\brief minimum MAC data needed for transmitting 1 min RLC PDU size + 1 byte MAC subHeader */ +#define MIN_MAC_HDR_RLC_SIZE (1 + MIN_RLC_PDU_SIZE) + /* * eNB part */ diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index a4c77c2cda..c90dd5857c 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -1245,13 +1245,12 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf { mac_rlc_status_resp_t rlc_status; - uint8_t dcch_header_len=0,dcch1_header_len=0,dtch_header_len=0,dtch_header_len_last=0; - uint8_t dcch_header_len_tmp=0, dtch_header_len_tmp=0; - //TO DO -// uint8_t total_rlc_pdu_header_len=0, rlc_pdu_header_len_last=0 ; + 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; + boolean_t is_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; @@ -1267,7 +1266,6 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf unsigned short short_padding=0, post_padding=0, padding_len=0; int j; // used for padding // Compute header length - int all_pdu_len; int lcg_id = 0; int lcg_id_bsr_trunc = 0; int highest_priority = 16; @@ -1304,10 +1302,6 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf } #endif - dcch_header_len=2;//sizeof(SCH_SUBHEADER_SHORT); - dcch1_header_len=2;//sizeof(SCH_SUBHEADER_SHORT); - // hypo length,in case of long header skip the padding byte - dtch_header_len=(buflen > 128 ) ? 3 : 2 ; //sizeof(SCH_SUBHEADER_LONG)-1 : sizeof(SCH_SUBHEADER_SHORT); bsr_header_len = 0; phr_header_len = 1;//sizeof(SCH_SUBHEADER_FIXED); @@ -1385,258 +1379,233 @@ 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++) { + if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) { - if (UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH] == LCID_NOT_EMPTY) { + is_lcid_processed = FALSE; - //It is not necessary to get RLC status again, it was done in ue_scheduler and stored - //for sanity keep it and check, to be removed if OK - 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 - DCCH, - (buflen-dcch_header_len-bsr_len-phr_len)); + //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 + rlc_pdu_header_len_last + sdu_length_total + MIN_MAC_HDR_RLC_SIZE <= buflen)) { - AssertFatal ( UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH] >= rlc_status.bytes_in_buffer, "Inconsistent BO! for LCID=%d MAC=%d RLC=%d\n", - DCCH,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH],rlc_status.bytes_in_buffer); + buflen_remain = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + rlc_pdu_header_len_last + sdu_length_total + 1); - LOG_D(MAC, "[UE %d] Frame %d : UL-DCCH -> ULSCH, RLC SRB1 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, UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH],buflen,bsr_len,phr_len,sdu_length_total,dcch_header_len,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]]); + 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); + + 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\n", + lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],rlc_status.bytes_in_buffer); + + if (rlc_status.bytes_in_buffer > 0) { - sdu_lengths[0] += mac_rlc_data_req(module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, - DCCH, - (char *)&ulsch_buff[sdu_lengths[0]]); + 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]]); - AssertFatal (UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH] >= sdu_lengths[0], "LCID=%d RLC has segmented %d bytes but MAC has max=%d\n", - DCCH,sdu_lengths[0],UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH]); + + 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 (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[0]; - sdu_lcids[0] = DCCH; - LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU TX Got %d bytes for SRB1\n",module_idP,sdu_lengths[0]); - num_sdus = 1; - //header_len +=2; - // update LCID remain buffer - UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH] -= sdu_lengths[0]; - /* Update BSR : substract transmitted data */ - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] >= sdu_lengths[0]){ - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] -= sdu_lengths[0] ; - } - 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[DCCH]], - UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH], - sdu_lengths[0],DCCH); - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] = 0; - } + 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 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[DCCH]] == 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 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[DCCH] = LCID_EMPTY; + //Update total MAC Header size for RLC PDUs and save last one + total_rlc_pdu_header_len += rlc_pdu_header_len_last; + + 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 ++; + } + + + } //end if (rlc_status.bytes_in_buffer > 0) + else { + // Switch to next LCID or exit the whole loop + is_lcid_processed = TRUE; + } } - else { - dcch_header_len=0; - num_sdus = 0; - } + + 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; + + //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 + rlc_pdu_header_len_last + sdu_length_total + MIN_MAC_HDR_RLC_SIZE <= buflen)) { + + buflen_remain = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + rlc_pdu_header_len_last + 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); + + 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\n", + lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],rlc_status.bytes_in_buffer); + + 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 (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 the RLC AM is used, then RLC will only provide 2 bytes for ACK - // in this case, we sould add bsr + 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; + } - // DCCH1 - if (UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH1] == LCID_NOT_EMPTY) { + //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; + } - //It is not necessary to get RLC status again, it was done in ue_scheduler and stored - //for sanity keep it and check, to be removed if OK - 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 - DCCH1, - (buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-sdu_length_total)); + } - AssertFatal ( UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1] >= rlc_status.bytes_in_buffer, "Inconsistent BO! for LCID=%d MAC=%d RLC=%d\n", - DCCH1,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1],rlc_status.bytes_in_buffer); + //Update total MAC Header size for RLC PDUs and save last one + total_rlc_pdu_header_len += rlc_pdu_header_len_last; - LOG_D(MAC,"[UE %d] Frame %d subframe %d: UL-DCCH1 -> ULSCH, RLC SRB2 has %d bytes to" - " send (Transport Block size %d BSR size=%d PHR=%d SRB1 Hdr %d SDU Length Total %d , mac header len %d BSR byte before Tx=%d)\n", - module_idP,frameP, subframe, UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1],buflen,bsr_len,phr_len,dcch_header_len,sdu_length_total,dcch1_header_len,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]]); + 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 ; - 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, - DCCH1, - (char *)&ulsch_buff[sdu_lengths[num_sdus]]); + //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; + } - AssertFatal (UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1] >= sdu_lengths[num_sdus], "LCID=%d RLC has segmented %d bytes but MAC has max=%d\n", - DCCH1,sdu_lengths[num_sdus],UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1]); + //Update number of SDU + num_sdus ++; + } - sdu_length_total += sdu_lengths[num_sdus]; - sdu_lcids[num_sdus] = DCCH1; - LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU Got %d bytes for SRB2\n",module_idP,sdu_lengths[num_sdus]); - //dcch_header_len +=2; // include dcch1 - UE_mac_inst[module_idP].scheduling_info.LCID_status[DCCH1] = LCID_EMPTY; - UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[DCCH1] -= 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[DCCH1]] >= sdu_lengths[num_sdus]){ - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] -= 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[DCCH1]], - UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1], - sdu_lengths[num_sdus],DCCH1); - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH1]] = 0; - } + } //end if (rlc_status.bytes_in_buffer > 0) + else { + // Switch to next LCID or exit the whole loop + is_lcid_processed = TRUE; + } + } - //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[DCCH1]] == 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; - } - } - - num_sdus++; - - } else { - dcch1_header_len =0; - } - - - dtch_header_len=0; - dtch_header_len_last=0; - for (lcid=DTCH; lcid < MAX_NUM_LCID ; lcid++){ - dtch_header_len+=3; - dtch_header_len_last=3; - - all_pdu_len = bsr_len+phr_len+dcch_header_len+dcch1_header_len+dtch_header_len+sdu_length_total; - if ((UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) && - (all_pdu_len <= buflen)) { - - AssertFatal (UE_mac_inst[module_idP].logicalChannelConfig[lcid] != NULL, "LCID (%d) is not active!\n", lcid); - - // optimize the dtch header lenght - //if ((UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DTCH] > 128) && - /* if (((UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DTCH] >= 128) && - ((UE_mac_inst[module_idP].scheduling_info.BSR_bytes[DTCH]+bsr_len+phr_len+dcch_header_len+dcch1_header_len+dtch_header_len) > buflen)&& - buflen >=128 )) - dtch_header_len = 3;//sizeof(SCH_SUBHEADER_LONG); - else - dtch_header_len = 2;//sizeof(SCH_SUBHEADER_SHORT); - */ - //It is not necessary to get RLC status again, it was done in ue_scheduler and stored - //for sanity keep it and check, to be removed if OK - 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-all_pdu_len); - - 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\n", - lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],rlc_status.bytes_in_buffer); - - LOG_D(MAC,"[UE %d] Frame %d subframe %d: UL-DTCH -> ULSCH%d, %d bytes to send (Transport Block size %d, mac header len %d, BSR byte before Tx=%d)\n", - module_idP,frameP, subframe,lcid, rlc_status.bytes_in_buffer,buflen,dtch_header_len, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); - - if (rlc_status.bytes_in_buffer > 0) { - - 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, // eNB_index - lcid, - (char *)&ulsch_buff[sdu_length_total]); - - 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]); - - - //adjust dtch header - LOG_D(MAC,"[UE %d] Frame %d Subframe %d TX Got %d bytes for DTCH%d New BSR bytes=%d\n",module_idP,frameP,subframe,sdu_lengths[num_sdus],lcid,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); - sdu_lcids[num_sdus] = lcid; - sdu_length_total += sdu_lengths[num_sdus]; - if (sdu_lengths[num_sdus] < 128) { - dtch_header_len --; - dtch_header_len_last --; - } - - /* Update BSR : substract transmitted data */ - UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] -= sdu_lengths[num_sdus]; - 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; - } - } - - - num_sdus++; - - } else { - dtch_header_len -= 3; - } - UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_EMPTY; - } else { // no rlc pdu : generate the dummy header - dtch_header_len -= 3; - } - } + UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_EMPTY; + } +} //lcgid= get_bsr_lcgid(module_idP); @@ -1687,28 +1656,22 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf LOG_T(MAC,"[UE %d] Frame %d: bsr s %p bsr_l %p, phr_p %p\n", module_idP,frameP,bsr_s, bsr_l, phr_p); - if (dtch_header_len == 0 ) - dtch_header_len_last =0; - - // adjust the header length - dcch_header_len_tmp = dcch_header_len; - dtch_header_len_tmp = dtch_header_len; - - if (dtch_header_len==0) { - dcch_header_len = (dcch_header_len>0)? 1: dcch_header_len; - } else { - dtch_header_len_last-=1; - dtch_header_len= (dtch_header_len >0)? dtch_header_len - dtch_header_len_last : dtch_header_len; - } // Check BSR padding: it is done after PHR according to Logical Channel Prioritization order + // Check for max padding size, ie MAC Hdr for last RLC PDU = 1 /* For Padding BSR: - if the number of padding bits is equal to or larger than the size of the Short BSR plus its subheader but smaller than the size of the Long BSR plus its subheader: - if more than one LCG has data available for transmission in the TTI where the BSR is transmitted: report Truncated BSR of the LCG with the highest priority logical channel with data available for transmission; - else report Short BSR. - else if the number of padding bits is equal to or larger than the size of the Long BSR plus its subheader, report Long BSR. */ - padding_len = buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total; + if (sdu_length_total) { + padding_len = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); + } + else { + padding_len = buflen - (bsr_len + phr_len); + } + if ((padding_len) && (bsr_len == 0)) { @@ -1766,7 +1729,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf bsr_l->Buffer_size2 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]; bsr_l->Buffer_size3 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]; - LOG_D(MAC, "[UE %d] Frame %d BSR Trig=%d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP, + LOG_I(MAC, "[UE %d] Frame %d BSR Trig=%d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP, UE_mac_inst[module_idP].BSR_reporting_active, UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], @@ -1781,7 +1744,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf bsr_t->LCGID = lcg_id_bsr_trunc; bsr_t->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc]; - LOG_D(MAC,"[UE %d] Frame %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", + LOG_I(MAC,"[UE %d] Frame %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", module_idP, frameP, UE_mac_inst[module_idP].BSR_reporting_active, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc],lcg_id_bsr_trunc); } @@ -1791,31 +1754,49 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf bsr_s->LCGID = lcg_id_bsr_trunc; bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc]; - LOG_D(MAC,"[UE %d] Frame %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", + LOG_I(MAC,"[UE %d] Frame %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", module_idP, frameP, UE_mac_inst[module_idP].BSR_reporting_active, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc],lcg_id_bsr_trunc); } } - // 1-bit padding or 2-bit padding special padding subheader - padding_len = buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total; +// 1-bit padding or 2-bit padding special padding subheader +// Check for max padding size, ie MAC Hdr for last RLC PDU = 1 + if (sdu_length_total) { + padding_len = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); + } + else { + padding_len = buflen - (bsr_len + phr_len); + } + if (padding_len <= 2) { short_padding = padding_len; // only add padding header post_padding = 0; - } else { + //update total MAC Hdr size for RLC data + if (sdu_length_total) { + rlc_pdu_header_len_last = 1; + total_rlc_pdu_header_len ++; + } + } + else if (sdu_length_total) { + total_rlc_pdu_header_len += rlc_pdu_header_len_last; + post_padding = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); + // If by adding MAC Hdr for last RLC PDU the padding is 0 then set MAC Hdr for last RLC PDU = 1 and compute 1 or 2 byte padding + if (post_padding == 0) { + total_rlc_pdu_header_len -= rlc_pdu_header_len_last; + padding_len = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); + short_padding = padding_len; + total_rlc_pdu_header_len ++; + } + } + else { if (padding_len == buflen) {// nona mac pdu *access_mode=CANCELED_ACCESS; } short_padding = 0; - if (dtch_header_len==0) { - dcch_header_len = dcch_header_len_tmp; - } else { - dtch_header_len= dtch_header_len_tmp; - } - - post_padding = buflen-bsr_len-phr_len-dcch_header_len-dcch1_header_len-dtch_header_len-sdu_length_total -1 ; + post_padding = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); } // Generate header @@ -1834,11 +1815,13 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf post_padding); // long_bsr LOG_D(MAC, - "[UE %d] Generate header :bufflen %d sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d, dcch_header_len %d, dtch_header_len %d, padding %d,post_padding %d, bsr len %d, phr len %d, reminder %d \n", - module_idP,buflen, sdu_length_total,num_sdus,sdu_lengths[0],sdu_lcids[0],payload_offset, dcch_header_len, dtch_header_len, + "[UE %d] Generate header :bufflen %d sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d, total_rlc_pdu_header_len %d, padding %d,post_padding %d, bsr len %d, phr len %d, reminder %d \n", + module_idP,buflen, sdu_length_total,num_sdus,sdu_lengths[0],sdu_lcids[0],payload_offset, total_rlc_pdu_header_len, short_padding,post_padding, bsr_len, phr_len,buflen-sdu_length_total-payload_offset); // cycle through SDUs and place in ulsch_buffer - memcpy(&ulsch_buffer[payload_offset],ulsch_buff,sdu_length_total); + if (sdu_length_total) { + memcpy(&ulsch_buffer[payload_offset],ulsch_buff,sdu_length_total); + } // fill remainder of DLSCH with random data for (j=0; j<(buflen-sdu_length_total-payload_offset); j++) { @@ -1852,10 +1835,13 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf /* Actions when a BSR is sent */ if (bsr_ce_len) { + LOG_D(MAC,"[UE %d] MAC BSR Sent !! bsr (ce%d,hdr%d) buff_len %d\n", + module_idP, bsr_ce_len, bsr_header_len, buflen); + // Reset ReTx BSR Timer UE_mac_inst[module_idP].scheduling_info.retxBSR_SF = get_sf_retxBSRTimer(UE_mac_inst[module_idP].scheduling_info.retxBSR_Timer); - LOG_I(MAC,"[UE %d] MAC ReTx BSR Timer Reset =%d\n", + LOG_D(MAC,"[UE %d] MAC ReTx BSR Timer Reset =%d\n", UE_mac_inst[module_idP].scheduling_info.retxBSR_SF); // Reset Periodic Timer except when BSR is truncated @@ -1863,15 +1849,11 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf { UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF = get_sf_periodicBSRTimer(UE_mac_inst[module_idP].scheduling_info.periodicBSR_Timer); - LOG_I(MAC,"[UE %d] MAC Periodic BSR Timer Reset =%d\n", + LOG_D(MAC,"[UE %d] MAC Periodic BSR Timer Reset =%d\n", UE_mac_inst[module_idP].scheduling_info.periodicBSR_SF); } - LOG_I(MAC,"[UE %d] MAC BSR Triggered !! bsr (ce%d,hdr%d) buff_len %d\n", - module_idP, bsr_ce_len, bsr_header_len, buflen); - - // Reset BSR Trigger flags UE_mac_inst[module_idP].BSR_reporting_active = BSR_TRIGGER_NONE; } 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 85104b940c..ded7dc0783 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -341,6 +341,7 @@ rlc_am_get_pdus ( if (pdu) { list_add_tail_eurecom (pdu, &rlc_pP->pdus_to_mac_layer); rlc_pP->status_requested = 0; + rlc_pP->status_buffer_occupancy = 0; rlc_am_start_timer_status_prohibit(ctxt_pP, rlc_pP); return; } From 710a246596aee5063facd0106a6935a64edaea12 Mon Sep 17 00:00:00 2001 From: hbilel Date: Mon, 28 Nov 2016 10:55:00 +0100 Subject: [PATCH 345/413] enhance BSR log --- openair2/LAYER2/MAC/ue_procedures.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index c90dd5857c..1ba0fa092d 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -1729,7 +1729,7 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) bsr_l->Buffer_size2 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]; bsr_l->Buffer_size3 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]; - LOG_I(MAC, "[UE %d] Frame %d BSR Trig=%d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP, + LOG_I(MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP,subframe, UE_mac_inst[module_idP].BSR_reporting_active, UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], @@ -1744,8 +1744,8 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) bsr_t->LCGID = lcg_id_bsr_trunc; bsr_t->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc]; - LOG_I(MAC,"[UE %d] Frame %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", - module_idP, frameP, UE_mac_inst[module_idP].BSR_reporting_active, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc],lcg_id_bsr_trunc); + LOG_I(MAC,"[UE %d] Frame %d subframe %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", + module_idP, frameP, subframe, UE_mac_inst[module_idP].BSR_reporting_active, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc],lcg_id_bsr_trunc); } else @@ -1754,8 +1754,8 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) bsr_s->LCGID = lcg_id_bsr_trunc; bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc]; - LOG_I(MAC,"[UE %d] Frame %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", - module_idP, frameP, UE_mac_inst[module_idP].BSR_reporting_active, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc],lcg_id_bsr_trunc); + LOG_I(MAC,"[UE %d] Frame %d subframe %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", + module_idP, frameP, subframe, UE_mac_inst[module_idP].BSR_reporting_active, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc],lcg_id_bsr_trunc); } } From 28923dc8e27d15839cde227786f896a3ec94bd82 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Mon, 28 Nov 2016 13:58:41 +0100 Subject: [PATCH 346/413] fixing bug introduced in 5c5c336300924ed66beb6b4946117314ee8a4b64 --- targets/ARCH/COMMON/common_lib.h | 3 ++- targets/ARCH/EXMIMO/DEFS/openair_device.h | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h index a6c8e43483..a366b54023 100644 --- a/targets/ARCH/COMMON/common_lib.h +++ b/targets/ARCH/COMMON/common_lib.h @@ -44,8 +44,9 @@ #define BBU_LOCAL_RADIO_HEAD 0 #define BBU_REMOTE_RADIO_HEAD 1 +#ifndef MAX_CARDS #define MAX_CARDS 8 - +#endif typedef int64_t openair0_timestamp; typedef volatile int64_t openair0_vtimestamp; diff --git a/targets/ARCH/EXMIMO/DEFS/openair_device.h b/targets/ARCH/EXMIMO/DEFS/openair_device.h index b4916490e2..b22cf1879b 100644 --- a/targets/ARCH/EXMIMO/DEFS/openair_device.h +++ b/targets/ARCH/EXMIMO/DEFS/openair_device.h @@ -24,9 +24,8 @@ // Maximum number of concurrently supported cards -// defined in openair_common_lib.h -//#define MAX_CARDS 16 -//#define INIT_ZEROS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +#define MAX_CARDS 16 +#define INIT_ZEROS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /** PCIe subsystem configuration Space From 860394244b13260f70417c673b3eaae545113af7 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 28 Nov 2016 18:28:10 +0100 Subject: [PATCH 347/413] T: bugfix: lock required When the user clicks on "next UE" or "prev UE" we change the filters of loggers. At the same time, the main thread of enb.c processes events received from the soft-modem and uses the filters, some of them maybe in the process of being changed. Changing the filters is not atomic and has to be protected. --- common/utils/T/tracer/enb.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/common/utils/T/tracer/enb.c b/common/utils/T/tracer/enb.c index 5d785782ea..07768763a5 100644 --- a/common/utils/T/tracer/enb.c +++ b/common/utils/T/tracer/enb.c @@ -190,8 +190,12 @@ static void click(void *private, gui *g, if (w == e->prev_ue_button) { ue--; if (ue < 0) ue = 0; } if (w == e->next_ue_button) ue++; - if (ue != ed->ue) set_current_ue(g, ed, ue); - ed->ue = ue; + if (pthread_mutex_lock(&ed->lock)) abort(); + if (ue != ed->ue) { + set_current_ue(g, ed, ue); + ed->ue = ue; + } + if (pthread_mutex_unlock(&ed->lock)) abort(); } static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database, @@ -745,7 +749,9 @@ restart: event e; e = get_event(enb_data.socket, v, database); if (e.type == -1) goto restart; + if (pthread_mutex_lock(&enb_data.lock)) abort(); handle_event(h, e); + if (pthread_mutex_unlock(&enb_data.lock)) abort(); } return 0; From b80ce3510e205423e8f2cb4508c74f9f997609c7 Mon Sep 17 00:00:00 2001 From: GabrirelCouturier Date: Mon, 28 Nov 2016 19:27:25 +0100 Subject: [PATCH 348/413] BSR and MAC UL encoding fixes --- openair2/LAYER2/MAC/defs.h | 4 +- openair2/LAYER2/MAC/ue_procedures.c | 166 ++++++++++++++++------------ 2 files changed, 97 insertions(+), 73 deletions(-) diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index cb1b2e4917..86fc367f51 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -959,9 +959,9 @@ typedef struct { /// buffer status for each lcgid uint8_t BSR[MAX_NUM_LCGID]; // should be more for mesh topology /// keep the number of bytes in rlc buffer for each lcgid - uint16_t BSR_bytes[MAX_NUM_LCGID]; + int32_t BSR_bytes[MAX_NUM_LCGID]; /// after multiplexing buffer remain for each lcid - uint16_t LCID_buffer_remain[MAX_NUM_LCID]; + int32_t LCID_buffer_remain[MAX_NUM_LCID]; /// sum of all lcid buffer size uint16_t All_lcid_buffer_size_lastTTI; /// buffer status for each lcid diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 1ba0fa092d..0413cfe524 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -1162,50 +1162,67 @@ unsigned char generate_ulsch_header(uint8_t *mac_header, LOG_T(MAC,"[UE] sdu subheader %d (lcid %d, %d bytes)\n",i,sdu_lcids[i],sdu_lengths[i]); #endif - if ((first_element>0)) { - mac_header_ptr->E = 1; -#ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, - ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); -#endif - mac_header_ptr+=last_size; - // printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); - } else { - first_element=1; - + if ((i == (num_sdus - 1)) && ((short_padding) || (post_padding == 0))) { + if (first_element>0) { + mac_header_ptr->E = 1; + #ifdef DEBUG_HEADER_PARSING + LOG_D(MAC,"[UE] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); + #endif + mac_header_ptr+=last_size; + } + mac_header_ptr->R = 0; + mac_header_ptr->E = 0; + mac_header_ptr->LCID = sdu_lcids[i]; } + else { + if ((first_element>0)) { + mac_header_ptr->E = 1; + #ifdef DEBUG_HEADER_PARSING + LOG_D(MAC,"[UE] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, + ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); + #endif + mac_header_ptr+=last_size; + // printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); + } else { + first_element=1; - if (sdu_lengths[i] < 128) { - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R = 0; // 3 - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E = 0; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F = 0; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID = sdu_lcids[i]; - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L = (unsigned char)sdu_lengths[i]; - last_size=2; -#ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] short sdu\n"); - LOG_T(MAC,"[UE] last subheader : %x (R%d,E%d,LCID%d,F%d,L%d)\n", - ((uint16_t*)mac_header_ptr)[0], - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R, - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E, - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID, - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F, - ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L); -#endif - } else { - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->R = 0; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->E = 0; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->F = 1; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->LCID = sdu_lcids[i]; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB = ((unsigned short) sdu_lengths[i]>>8)&0x7f; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB = (unsigned short) sdu_lengths[i]&0xff; - ((SCH_SUBHEADER_LONG *)mac_header_ptr)->padding = 0x00; - last_size=3; -#ifdef DEBUG_HEADER_PARSING - LOG_D(MAC,"[UE] long sdu\n"); -#endif + } + + if (sdu_lengths[i] < 128) { + ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R = 0; // 3 + ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E = 0; + ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F = 0; + ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID = sdu_lcids[i]; + ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L = (unsigned char)sdu_lengths[i]; + last_size=2; + #ifdef DEBUG_HEADER_PARSING + LOG_D(MAC,"[UE] short sdu\n"); + LOG_T(MAC,"[UE] last subheader : %x (R%d,E%d,LCID%d,F%d,L%d)\n", + ((uint16_t*)mac_header_ptr)[0], + ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R, + ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E, + ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID, + ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F, + ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L); + #endif + } else { + ((SCH_SUBHEADER_LONG *)mac_header_ptr)->R = 0; + ((SCH_SUBHEADER_LONG *)mac_header_ptr)->E = 0; + ((SCH_SUBHEADER_LONG *)mac_header_ptr)->F = 1; + ((SCH_SUBHEADER_LONG *)mac_header_ptr)->LCID = sdu_lcids[i]; + ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB = ((unsigned short) sdu_lengths[i]>>8)&0x7f; + ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB = (unsigned short) sdu_lengths[i]&0xff; + ((SCH_SUBHEADER_LONG *)mac_header_ptr)->padding = 0x00; + last_size=3; + #ifdef DEBUG_HEADER_PARSING + LOG_D(MAC,"[UE] long sdu\n"); + #endif + } } } @@ -1223,6 +1240,7 @@ unsigned char generate_ulsch_header(uint8_t *mac_header, //mac_header_ptr=last_size; // FIXME: should be ++ } + if ((ce_ptr-mac_header_control_elements) > 0) { memcpy((void*)mac_header_ptr,mac_header_control_elements,ce_ptr-mac_header_control_elements); mac_header_ptr+=(unsigned char)(ce_ptr-mac_header_control_elements); @@ -1249,7 +1267,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf 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; + uint8_t lcid=0,lcid_rlc_pdu_count=0; boolean_t is_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 }; @@ -1384,12 +1402,13 @@ for (lcid=DCCH; lcid < DTCH ; 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 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 + rlc_pdu_header_len_last + sdu_length_total + MIN_MAC_HDR_RLC_SIZE <= buflen)) { + 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 + rlc_pdu_header_len_last + sdu_length_total + 1); + 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, @@ -1400,8 +1419,8 @@ for (lcid=DCCH; lcid < DTCH ; lcid++) { lcid, buflen_remain); - 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\n", - lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],rlc_status.bytes_in_buffer); + 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) { @@ -1458,9 +1477,6 @@ for (lcid=DCCH; lcid < DTCH ; lcid++) { } - //Update total MAC Header size for RLC PDUs and save last one - total_rlc_pdu_header_len += rlc_pdu_header_len_last; - 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 @@ -1475,17 +1491,20 @@ for (lcid=DCCH; lcid < DTCH ; lcid++) { rlc_pdu_header_len_last = 1; is_lcid_processed = TRUE; } - - //Update number of SDU - num_sdus ++; } + //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; @@ -1499,12 +1518,13 @@ 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 + rlc_pdu_header_len_last + sdu_length_total + MIN_MAC_HDR_RLC_SIZE <= buflen)) { + 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 + rlc_pdu_header_len_last + sdu_length_total + 1); + 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, @@ -1515,8 +1535,8 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) lcid, buflen_remain); - 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\n", - lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],rlc_status.bytes_in_buffer); + 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) { @@ -1535,6 +1555,9 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) 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]); @@ -1573,9 +1596,6 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) } - //Update total MAC Header size for RLC PDUs and save last one - total_rlc_pdu_header_len += rlc_pdu_header_len_last; - 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 @@ -1590,17 +1610,20 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) rlc_pdu_header_len_last = 1; is_lcid_processed = TRUE; } - - //Update number of SDU - num_sdus ++; } + //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; @@ -1666,7 +1689,7 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) - else if the number of padding bits is equal to or larger than the size of the Long BSR plus its subheader, report Long BSR. */ if (sdu_length_total) { - padding_len = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); + padding_len = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len - rlc_pdu_header_len_last + sdu_length_total + 1); } else { padding_len = buflen - (bsr_len + phr_len); @@ -1762,7 +1785,7 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) // 1-bit padding or 2-bit padding special padding subheader // Check for max padding size, ie MAC Hdr for last RLC PDU = 1 if (sdu_length_total) { - padding_len = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); + padding_len = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len - rlc_pdu_header_len_last + sdu_length_total + 1); } else { padding_len = buflen - (bsr_len + phr_len); @@ -1774,12 +1797,11 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) post_padding = 0; //update total MAC Hdr size for RLC data if (sdu_length_total) { + total_rlc_pdu_header_len = total_rlc_pdu_header_len - rlc_pdu_header_len_last + 1; rlc_pdu_header_len_last = 1; - total_rlc_pdu_header_len ++; - } + } } else if (sdu_length_total) { - total_rlc_pdu_header_len += rlc_pdu_header_len_last; post_padding = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); // If by adding MAC Hdr for last RLC PDU the padding is 0 then set MAC Hdr for last RLC PDU = 1 and compute 1 or 2 byte padding if (post_padding == 0) { @@ -1824,8 +1846,10 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) } // fill remainder of DLSCH with random data - for (j=0; j<(buflen-sdu_length_total-payload_offset); j++) { - ulsch_buffer[payload_offset+sdu_length_total+j] = (char)(taus()&0xff); + if (post_padding) { + for (j=0; j<(buflen-sdu_length_total-payload_offset); j++) { + ulsch_buffer[payload_offset+sdu_length_total+j] = (char)(taus()&0xff); + } } LOG_D(MAC,"[UE %d][SR] Gave SDU to PHY, clearing any scheduling request\n", module_idP,payload_offset, sdu_length_total); @@ -2295,7 +2319,7 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subfra uint8_t lcgid; uint8_t num_lcid_with_data = 0; // for LCID with data only if LCGID is defined uint16_t lcgid_buffer_remain[MAX_NUM_LCGID] = {0,0,0,0}; - uint16_t lcid_bytes_in_buffer[MAX_NUM_LCID]; + int32_t lcid_bytes_in_buffer[MAX_NUM_LCID]; /* Array for ordering LCID with data per decreasing priority order */ uint8_t lcid_reordered_array[MAX_NUM_LCID]= {MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID,MAX_NUM_LCID}; From ea7c0e1b36656de02bf1185ab9cd77786e0cd143 Mon Sep 17 00:00:00 2001 From: hbilel Date: Tue, 29 Nov 2016 15:26:57 +0100 Subject: [PATCH 349/413] reduce BSR logging --- openair2/LAYER2/MAC/ue_procedures.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 0413cfe524..28520802c7 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -1752,7 +1752,7 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) bsr_l->Buffer_size2 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID2]; bsr_l->Buffer_size3 = UE_mac_inst[module_idP].scheduling_info.BSR[LCGID3]; - LOG_I(MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP,subframe, + LOG_D(MAC, "[UE %d] Frame %d subframe %d BSR Trig=%d report long BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 %d)\n", module_idP,frameP,subframe, UE_mac_inst[module_idP].BSR_reporting_active, UE_mac_inst[module_idP].scheduling_info.BSR[LCGID0], UE_mac_inst[module_idP].scheduling_info.BSR[LCGID1], @@ -1767,7 +1767,7 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) bsr_t->LCGID = lcg_id_bsr_trunc; bsr_t->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc]; - LOG_I(MAC,"[UE %d] Frame %d subframe %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", + LOG_D(MAC,"[UE %d] Frame %d subframe %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n", module_idP, frameP, subframe, UE_mac_inst[module_idP].BSR_reporting_active, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc],lcg_id_bsr_trunc); } @@ -1777,7 +1777,7 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) bsr_s->LCGID = lcg_id_bsr_trunc; bsr_s->Buffer_size = UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc]; - LOG_I(MAC,"[UE %d] Frame %d subframe %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", + LOG_D(MAC,"[UE %d] Frame %d subframe %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n", module_idP, frameP, subframe, UE_mac_inst[module_idP].BSR_reporting_active, UE_mac_inst[module_idP].scheduling_info.BSR[lcg_id_bsr_trunc],lcg_id_bsr_trunc); } } From 31541601ce3efcfe37fb50c72140e5492e64dcd8 Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Tue, 29 Nov 2016 17:19:14 +0100 Subject: [PATCH 350/413] fixes for tdd (N_TA_offset was not initialized) + some other code cleanup tested with both EXMIMO and USRP. performance better than in master branch. --- targets/RT/USER/lte-enb.c | 51 +++++++++++++++++++-------------- targets/RT/USER/lte-softmodem.c | 26 +++++++++++++++-- targets/RT/USER/lte-ue.c | 24 ++++++++-------- 3 files changed, 65 insertions(+), 36 deletions(-) diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 8f636d20d6..bdc281c8ea 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -134,8 +134,8 @@ time_stats_t softmodem_stats_mt; // main thread time_stats_t softmodem_stats_hw; // hw acquisition time_stats_t softmodem_stats_rxtx_sf; // total tx time time_stats_t softmodem_stats_rx_sf; // total rx time -int32_t **rxdata; -int32_t **txdata; +//int32_t **rxdata; +//int32_t **txdata; uint8_t seqno; //sequence number @@ -302,12 +302,13 @@ void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB) { 6, phy_vars_eNB->frame_parms.nb_prefix_samples, CYCLIC_PREFIX); - PHY_ofdm_mod(&phy_vars_eNB->common_vars.txdataF[0][aa][slot_offset_F+slot_sizeF], - dummy_tx_b+(phy_vars_eNB->frame_parms.samples_per_tti>>1), - phy_vars_eNB->frame_parms.ofdm_symbol_size, - 6, - phy_vars_eNB->frame_parms.nb_prefix_samples, - CYCLIC_PREFIX); + if (subframe_select(&phy_vars_eNB->frame_parms,subframe) == SF_DL) + PHY_ofdm_mod(&phy_vars_eNB->common_vars.txdataF[0][aa][slot_offset_F+slot_sizeF], + dummy_tx_b+(phy_vars_eNB->frame_parms.samples_per_tti>>1), + phy_vars_eNB->frame_parms.ofdm_symbol_size, + 6, + phy_vars_eNB->frame_parms.nb_prefix_samples, + CYCLIC_PREFIX); } else { normal_prefix_mod(&phy_vars_eNB->common_vars.txdataF[0][aa][slot_offset_F], dummy_tx_b, @@ -385,7 +386,7 @@ void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB) { // turn on tx switch N_TA_offset before //LOG_D(HW,"subframe %d, time to switch to tx (N_TA_offset %d, slot_offset %d) \n",subframe,phy_vars_eNB->N_TA_offset,slot_offset); for (i=0; iN_TA_offset; i++) { - tx_offset = (int)slot_offset+time_offset[aa]+i-phy_vars_eNB->N_TA_offset/2; + tx_offset = (int)slot_offset+time_offset[aa]+i-phy_vars_eNB->N_TA_offset; if (tx_offset<0) tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti; @@ -468,8 +469,16 @@ void proc_tx_full(PHY_VARS_eNB *eNB, // if TX fronthaul go ahead if (eNB->tx_fh) eNB->tx_fh(eNB,proc); - - + /* + if (proc->frame_tx>1000) { + write_output("/tmp/txsig0.m","txs0", &eNB->common_vars.txdata[eNB->Mod_id][0][0], eNB->frame_parms.samples_per_tti*10,1,1); + write_output("/tmp/txsigF0.m","txsF0", &eNB->common_vars.txdataF[eNB->Mod_id][0][0],eNB->frame_parms.symbols_per_tti*eNB->frame_parms.ofdm_symbol_size*10,1,1); + write_output("/tmp/txsig1.m","txs1", &eNB->common_vars.txdata[eNB->Mod_id][1][0], eNB->frame_parms.samples_per_tti*10,1,1); + write_output("/tmp/txsigF1.m","txsF1", &eNB->common_vars.txdataF[eNB->Mod_id][1][0],eNB->frame_parms.symbols_per_tti*eNB->frame_parms.ofdm_symbol_size*10,1,1); + //if (transmission_mode == 7) write_output("/tmp/txsigF5.m","txsF5", &eNB->common_vars.txdataF[eNB->Mod_id][5][0],eNB->frame_parms.symbols_per_tti*eNB->frame_parms.ofdm_symbol_size*10,1,1); + exit_fun(""); + } + */ } void proc_tx_rru_if4p5(PHY_VARS_eNB *eNB, @@ -539,7 +548,8 @@ int wait_CCs(eNB_rxtx_proc_t *proc) { static inline int rxtx(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, char *thread_name) { start_meas(&softmodem_stats_rxtx_sf); - // **************************************** + +// **************************************** // Common RX procedures subframe n phy_procedures_eNB_common_RX(eNB); @@ -1477,7 +1487,7 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c int i, CC_id; int j; - uint16_t N_TA_offset = 0; + //uint16_t N_TA_offset = 0; LTE_DL_FRAME_PARMS *frame_parms; @@ -1490,6 +1500,7 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c return(-1); } + /* if (frame_parms->frame_type == TDD) { if (frame_parms->N_RB_DL == 100) N_TA_offset = 624; @@ -1498,7 +1509,7 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c else if (frame_parms->N_RB_DL == 25) N_TA_offset = 624/4; } - + */ if (openair0_cfg[CC_id].mmapped_dma == 1) { @@ -1508,11 +1519,8 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c printf("Mapping eNB CC_id %d, rx_ant %d\n",CC_id,i); free(phy_vars_eNB[CC_id]->common_vars.rxdata[0][i]); phy_vars_eNB[CC_id]->common_vars.rxdata[0][i] = openair0_cfg[CC_id].rxbase[i]; - - - + printf("rxdata[%d] @ %p\n",i,phy_vars_eNB[CC_id]->common_vars.rxdata[0][i]); - for (j=0; j<16; j++) { printf("rxbuffer %d: %x\n",j,phy_vars_eNB[CC_id]->common_vars.rxdata[0][i][j]); phy_vars_eNB[CC_id]->common_vars.rxdata[0][i][j] = 16-j; @@ -1533,15 +1541,15 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c } } else { // not memory-mapped DMA - - + //nothing to do, everything already allocated in lte_init + /* rxdata = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*)); txdata = (int32_t**)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*)); for (i=0; inb_antennas_rx; i++) { free(phy_vars_eNB[CC_id]->common_vars.rxdata[0][i]); rxdata[i] = (int32_t*)(32 + malloc16(32+frame_parms->samples_per_tti*10*sizeof(int32_t))); // FIXME broken memory allocation - phy_vars_eNB[CC_id]->common_vars.rxdata[0][i] = rxdata[i]-N_TA_offset; // N_TA offset for TDD FIXME! N_TA_offset > 16 => access of unallocated memory + phy_vars_eNB[CC_id]->common_vars.rxdata[0][i] = rxdata[i]; //-N_TA_offset; // N_TA offset for TDD FIXME! N_TA_offset > 16 => access of unallocated memory memset(rxdata[i], 0, frame_parms->samples_per_tti*10*sizeof(int32_t)); printf("rxdata[%d] @ %p (%p) (N_TA_OFFSET %d)\n", i, phy_vars_eNB[CC_id]->common_vars.rxdata[0][i],rxdata[i],N_TA_offset); } @@ -1553,6 +1561,7 @@ int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_c memset(txdata[i],0, frame_parms->samples_per_tti*10*sizeof(int32_t)); printf("txdata[%d] @ %p\n", i, phy_vars_eNB[CC_id]->common_vars.txdata[0][i]); } + */ } } diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 6272fdb4eb..c73bc8d01b 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1583,7 +1583,18 @@ int main( int argc, char **argv ) UE[CC_id]->rx_total_gain_dB = (int)rx_gain[CC_id][0] + rx_gain_off; UE[CC_id]->tx_power_max_dBm = tx_max_power[CC_id]; - UE[CC_id]->N_TA_offset = 0; + + if (frame_parms[CC_id]->frame_type==FDD) { + UE[CC_id]->N_TA_offset = 0; + } + else { + if (frame_parms[CC_id]->N_RB_DL == 100) + UE[CC_id]->N_TA_offset = 624; + else if (frame_parms[CC_id]->N_RB_DL == 50) + UE[CC_id]->N_TA_offset = 624/2; + else if (frame_parms[CC_id]->N_RB_DL == 25) + UE[CC_id]->N_TA_offset = 624/4; + } } @@ -1623,8 +1634,17 @@ int main( int argc, char **argv ) PHY_vars_eNB_g[0][CC_id]->rx_total_gain_dB = (int)rx_gain[CC_id][0]; - PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 0; - + if (frame_parms[CC_id]->frame_type==FDD) { + PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 0; + } + else { + if (frame_parms[CC_id]->N_RB_DL == 100) + PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624; + else if (frame_parms[CC_id]->N_RB_DL == 50) + PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624/2; + else if (frame_parms[CC_id]->N_RB_DL == 25) + PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624/4; + } } diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 22cc46388d..f4b8e0ab3a 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -98,8 +98,8 @@ extern uint32_t downlink_frequency[MAX_NUM_CCs][4]; extern int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; extern int oai_exit; -extern int32_t **rxdata; -extern int32_t **txdata; +int32_t **rxdata; +int32_t **txdata; //extern unsigned int tx_forward_nsamps; //extern int tx_delay; @@ -1628,14 +1628,14 @@ int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg) } /* - if (frame_parms->frame_type == TDD) { + if (frame_parms->frame_type == TDD) { if (frame_parms->N_RB_DL == 100) - N_TA_offset = 624; - else if (frame_parms->N_RB_DL == 50) - N_TA_offset = 624/2; - else if (frame_parms->N_RB_DL == 25) - N_TA_offset = 624/4; - } + N_TA_offset = 624; + else if (frame_parms->N_RB_DL == 50) + N_TA_offset = 624/2; + else if (frame_parms->N_RB_DL == 25) + N_TA_offset = 624/4; + } */ // replace RX signal buffers with mmaped HW versions @@ -1645,9 +1645,9 @@ int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg) for (i=0; inb_antennas_rx; i++) { printf( "Mapping UE CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n", CC_id, i, downlink_frequency[CC_id][i], rf_map->card, rf_map->chain+i ); free( phy_vars_ue[CC_id]->common_vars.rxdata[i] ); - rxdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) ); - phy_vars_ue[CC_id]->common_vars.rxdata[i] = rxdata[i]; // what about the "-N_TA_offset" ? // N_TA offset for TDD - printf("rxdata[%d] : %p\n",i,rxdata[i]); + rxdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) ); + phy_vars_ue[CC_id]->common_vars.rxdata[i] = rxdata[i]; // what about the "-N_TA_offset" ? // N_TA offset for TDD + printf("rxdata[%d] : %p\n",i,rxdata[i]); } for (i=0; inb_antennas_tx; i++) { From 7adc4703be5954fb9c869962195c15aaa96caf9d Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 30 Nov 2016 16:29:14 +0100 Subject: [PATCH 351/413] T: update traces - add mcs to ENB_PHY_DLSCH_UE_DCI - add mcs, round, first_rb, nb_rb, TBS to ENB_PHY_ULSCH_UE_DCI --- common/utils/T/T_messages.txt | 4 ++-- openair1/SCHED/phy_procedures_lte_eNb.c | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index 3e3ba082dd..d6aa753892 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -16,7 +16,7 @@ ID = ENB_PHY_DL_TICK ID = ENB_PHY_DLSCH_UE_DCI DESC = eNodeB downlink UE specific DCI as sent by the PHY layer GROUP = ALL:PHY:GRAPHIC:ENB - FORMAT = int,eNB_ID : int,frame : int,subframe : int,UE_id : int,rnti : int,dci_format : int,harq_pid + FORMAT = int,eNB_ID : int,frame : int,subframe : int,UE_id : int,rnti : int,dci_format : int,harq_pid : int,mcs ID = ENB_PHY_DLSCH_UE_ACK DESC = eNodeB downlink UE ACK as seen by the PHY layer in process_HARQ_feedback GROUP = ALL:PHY:GRAPHIC:ENB @@ -28,7 +28,7 @@ ID = ENB_PHY_DLSCH_UE_NACK ID = ENB_PHY_ULSCH_UE_DCI DESC = eNodeB uplink UE specific DCI as sent by the PHY layer GROUP = ALL:PHY:GRAPHIC:ENB - FORMAT = int,eNB_ID : int,frame : int,subframe : int,UE_id : int,rnti : int,harq_pid + FORMAT = int,eNB_ID : int,frame : int,subframe : int,UE_id : int,rnti : int,harq_pid : int,mcs : int,round : int,first_rb : int,nb_rb : int,TBS ID = ENB_PHY_ULSCH_UE_NO_DCI_RETRANSMISSION DESC = eNodeB uplink UE retransmission due to PHICH NACK (see generate_phich_top) GROUP = ALL:PHY:GRAPHIC:ENB diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index c868a1a733..160153317d 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -760,7 +760,8 @@ void generate_eNB_dlsch_params(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC T(T_ENB_PHY_DLSCH_UE_DCI, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(UE_id), T_INT(dci_alloc->rnti), T_INT(dci_alloc->format), - T_INT(eNB->dlsch[(int)UE_id][0]->current_harq_pid)); + T_INT(eNB->dlsch[(int)UE_id][0]->current_harq_pid), + T_INT(eNB->dlsch[(int)UE_id][0]->harq_processes[eNB->dlsch[(int)UE_id][0]->current_harq_pid]->mcs)); eNB->dlsch[(uint8_t)UE_id][0]->nCCE[subframe] = dci_alloc->firstCCE; @@ -854,8 +855,12 @@ void generate_eNB_ulsch_params(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 1; T(T_ENB_PHY_ULSCH_UE_DCI, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(UE_id), - T_INT(dci_alloc->rnti), T_INT(harq_pid)); - + T_INT(dci_alloc->rnti), T_INT(harq_pid), + T_INT(eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->mcs), + T_INT(eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->round), + T_INT(eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->first_rb), + T_INT(eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->nb_rb), + T_INT(eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->TBS)); } void pdsch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,LTE_eNB_DLSCH_t *dlsch, LTE_eNB_DLSCH_t *dlsch1,LTE_eNB_UE_stats *ue_stats,int ra_flag,int num_pdcch_symbols) { From a016cb75897ef7fc7bc015d2631ac8a0ee165837 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 30 Nov 2016 16:32:29 +0100 Subject: [PATCH 352/413] T: new logger ticked_ttilog A new logger is there: the "ticked TTI logger". Similar to TTI logger (used by the PUCCH1 energy plot) but takes another input, the "tick" (think subframe) and a default value for when no event is triggered between two ticks. This is used for the UL and DL MCS plots in enb.c (next commit). --- common/utils/T/tracer/logger/Makefile | 2 +- common/utils/T/tracer/logger/logger.h | 5 + common/utils/T/tracer/logger/ticked_ttilog.c | 196 +++++++++++++++++++ 3 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 common/utils/T/tracer/logger/ticked_ttilog.c diff --git a/common/utils/T/tracer/logger/Makefile b/common/utils/T/tracer/logger/Makefile index 92431739db..897c36e66f 100644 --- a/common/utils/T/tracer/logger/Makefile +++ b/common/utils/T/tracer/logger/Makefile @@ -2,7 +2,7 @@ CC=gcc CFLAGS=-Wall -g -pthread -I.. OBJS=logger.o textlog.o framelog.o ttilog.o timelog.o ticklog.o iqlog.o \ - iqdotlog.o + iqdotlog.o ticked_ttilog.o logger.a: $(OBJS) ar cr logger.a $(OBJS) diff --git a/common/utils/T/tracer/logger/logger.h b/common/utils/T/tracer/logger/logger.h index b2ab4f8cbc..4ade141742 100644 --- a/common/utils/T/tracer/logger/logger.h +++ b/common/utils/T/tracer/logger/logger.h @@ -10,6 +10,10 @@ logger *new_textlog(void *event_handler, void *database, logger *new_ttilog(void *event_handler, void *database, char *event_name, char *frame_varname, char *subframe_varname, char *data_varname, int convert_to_dB); +logger *new_ticked_ttilog(void *event_handler, void *database, + char *tick_event_name, + char *event_name, char *frame_varname, char *subframe_varname, + char *data_varname, int convert_to_dB, float empty_value); logger *new_timelog(void *event_handler, void *database, char *event_name); logger *new_ticklog(void *event_handler, void *database, char *event_name, char *frame_name, char *subframe_name); @@ -28,5 +32,6 @@ void textlog_dump_buffer(logger *_this, int dump_buffer); void logger_add_view(logger *l, view *v); void logger_set_filter(logger *l, void *filter); +void ticked_ttilog_set_tick_filter(logger *l, void *filter); #endif /* _LOGGER_H_ */ diff --git a/common/utils/T/tracer/logger/ticked_ttilog.c b/common/utils/T/tracer/logger/ticked_ttilog.c new file mode 100644 index 0000000000..96ad20a931 --- /dev/null +++ b/common/utils/T/tracer/logger/ticked_ttilog.c @@ -0,0 +1,196 @@ +#include "logger.h" +#include "logger_defs.h" +#include "event.h" +#include "database.h" +#include "handler.h" +#include "filter/filter.h" +#include +#include +#include +#include + +struct ticked_ttilog { + struct logger common; + void *database; + int tick_frame_arg; + int tick_subframe_arg; + int data_frame_arg; + int data_subframe_arg; + int data_arg; + int convert_to_dB; + int last_tick_frame; + int last_tick_subframe; + float last_value; + float empty_value; + char *tick_event_name; + unsigned long tick_handler_id; + /* tick filter - NULL is no filter set */ + void *tick_filter; +}; + +static void _event(void *p, event e) +{ + struct ticked_ttilog *l = p; + int frame; + int subframe; + float value; + + if (l->common.filter != NULL && filter_eval(l->common.filter, e) == 0) + return; + + frame = e.e[l->data_frame_arg].i; + subframe = e.e[l->data_subframe_arg].i; + + if (frame != l->last_tick_frame || subframe != l->last_tick_subframe) { + printf("WARNING: %s:%d: data comes without previous tick!\n", + __FILE__, __LINE__); + return; + } + + switch (e.e[l->data_arg].type) { + case EVENT_INT: value = e.e[l->data_arg].i; break; + case EVENT_ULONG: value = e.e[l->data_arg].ul; break; + default: printf("%s:%d: unsupported type\n", __FILE__, __LINE__); abort(); + } + + if (l->convert_to_dB) value = 10 * log10(value); + + l->last_value = value; +} + +static void _tick_event(void *p, event e) +{ + struct ticked_ttilog *l = p; + int i; + int frame; + int subframe; + + if (l->tick_filter != NULL && filter_eval(l->tick_filter, e) == 0) + return; + + frame = e.e[l->tick_frame_arg].i; + subframe = e.e[l->tick_subframe_arg].i; + + for (i = 0; i < l->common.vsize; i++) + l->common.v[i]->append(l->common.v[i], frame, subframe, l->last_value); + + l->last_value = l->empty_value; + l->last_tick_frame = frame; + l->last_tick_subframe = subframe; +} + +logger *new_ticked_ttilog(event_handler *h, void *database, + char *tick_event_name, char *frame_varname, char *subframe_varname, + char *event_name, char *data_varname, + int convert_to_dB, float empty_value) +{ + struct ticked_ttilog *ret; + int event_id; + database_event_format f; + int i; + + ret = calloc(1, sizeof(struct ticked_ttilog)); if (ret == NULL) abort(); + + ret->common.event_name = strdup(event_name); + if (ret->common.event_name == NULL) abort(); + ret->database = database; + ret->convert_to_dB = convert_to_dB; + + ret->tick_event_name = strdup(tick_event_name); + if (ret->tick_event_name == NULL) abort(); + ret->empty_value = empty_value; + ret->last_value = empty_value; + + /* tick event */ + event_id = event_id_from_name(database, tick_event_name); + + ret->tick_handler_id=register_handler_function(h,event_id,_tick_event,ret); + + f = get_format(database, event_id); + + /* look for frame, subframe and data args */ + ret->tick_frame_arg = -1; + ret->tick_subframe_arg = -1; + for (i = 0; i < f.count; i++) { + if (!strcmp(f.name[i], frame_varname)) ret->tick_frame_arg = i; + if (!strcmp(f.name[i], subframe_varname)) ret->tick_subframe_arg = i; + } + if (ret->tick_frame_arg == -1) { + printf("%s:%d: frame argument '%s' not found in event '%s'\n", + __FILE__, __LINE__, frame_varname, event_name); + abort(); + } + if (ret->tick_subframe_arg == -1) { + printf("%s:%d: subframe argument '%s' not found in event '%s'\n", + __FILE__, __LINE__, subframe_varname, event_name); + abort(); + } + if (strcmp(f.type[ret->tick_frame_arg], "int") != 0) { + printf("%s:%d: argument '%s' has wrong type (should be 'int')\n", + __FILE__, __LINE__, frame_varname); + abort(); + } + if (strcmp(f.type[ret->tick_subframe_arg], "int") != 0) { + printf("%s:%d: argument '%s' has wrong type (should be 'int')\n", + __FILE__, __LINE__, subframe_varname); + abort(); + } + + /* data event */ + event_id = event_id_from_name(database, event_name); + + ret->common.handler_id = register_handler_function(h,event_id,_event,ret); + + f = get_format(database, event_id); + + /* look for frame and subframe */ + ret->data_frame_arg = -1; + ret->data_subframe_arg = -1; + ret->data_arg = -1; + for (i = 0; i < f.count; i++) { + if (!strcmp(f.name[i], frame_varname)) ret->data_frame_arg = i; + if (!strcmp(f.name[i], subframe_varname)) ret->data_subframe_arg = i; + if (!strcmp(f.name[i], data_varname)) ret->data_arg = i; + } + if (ret->data_frame_arg == -1) { + printf("%s:%d: frame argument '%s' not found in event '%s'\n", + __FILE__, __LINE__, frame_varname, event_name); + abort(); + } + if (ret->data_subframe_arg == -1) { + printf("%s:%d: subframe argument '%s' not found in event '%s'\n", + __FILE__, __LINE__, subframe_varname, event_name); + abort(); + } + if (ret->data_arg == -1) { + printf("%s:%d: data argument '%s' not found in event '%s'\n", + __FILE__, __LINE__, data_varname, event_name); + abort(); + } + if (strcmp(f.type[ret->data_frame_arg], "int") != 0) { + printf("%s:%d: argument '%s' has wrong type (should be 'int')\n", + __FILE__, __LINE__, frame_varname); + abort(); + } + if (strcmp(f.type[ret->data_subframe_arg], "int") != 0) { + printf("%s:%d: argument '%s' has wrong type (should be 'int')\n", + __FILE__, __LINE__, subframe_varname); + abort(); + } + if (strcmp(f.type[ret->data_arg], "int") != 0 && + strcmp(f.type[ret->data_arg], "float") != 0) { + printf("%s:%d: argument '%s' has wrong type" + " (should be 'int' or 'float')\n", + __FILE__, __LINE__, data_varname); + abort(); + } + + return ret; +} + +void ticked_ttilog_set_tick_filter(logger *_l, void *filter) +{ + struct ticked_ttilog *l = (struct ticked_ttilog *)_l; + free(l->tick_filter); + l->tick_filter = filter; +} From 1e485b4b5e09aeb17210763f1b9f743900a631e7 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 30 Nov 2016 16:39:49 +0100 Subject: [PATCH 353/413] T: add DL and UL MCS plots in enb.c Helps visualize MCS usage over time. --- common/utils/T/tracer/enb.c | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/common/utils/T/tracer/enb.c b/common/utils/T/tracer/enb.c index 07768763a5..c6f3bba5ff 100644 --- a/common/utils/T/tracer/enb.c +++ b/common/utils/T/tracer/enb.c @@ -32,6 +32,8 @@ typedef struct { widget *pucch1_energy_ue_xy_plot; widget *pucch_iq_ue_xy_plot; widget *dl_ul_harq_ue_label; + widget *dl_mcs_xy_plot; + widget *ul_mcs_xy_plot; logger *pusch_iq_ue_logger; logger *ul_estimate_ue_logger; logger *pucch1_energy_ue_threshold_logger; @@ -44,6 +46,8 @@ typedef struct { logger *ul_dci_retransmission_logger[8]; logger *ul_ack_logger[8]; logger *ul_nack_logger[8]; + logger *dl_mcs_logger; + logger *ul_mcs_logger; } enb_gui; typedef struct { @@ -137,6 +141,10 @@ static void set_current_ue(gui *g, enb_data *e, int ue) xy_plot_set_title(g, e->e->pucch_iq_ue_xy_plot, s); sprintf(s, "DL/UL HARQ (x8) [UE %d]", ue); label_set_text(g, e->e->dl_ul_harq_ue_label, s); + sprintf(s, "DL MCS [UE %d]", ue); + xy_plot_set_title(g, e->e->dl_mcs_xy_plot, s); + sprintf(s, "UL MCS [UE %d]", ue); + xy_plot_set_title(g, e->e->ul_mcs_xy_plot, s); logger_set_filter(e->e->pusch_iq_ue_logger, filter_eq( @@ -175,6 +183,14 @@ static void set_current_ue(gui *g, enb_data *e, int ue) logger_set_filter(e->e->ul_nack_logger[i], ticktime_filter(e->database, "ENB_PHY_ULSCH_UE_NACK", i, ue)); } + logger_set_filter(e->e->dl_mcs_logger, + filter_eq( + filter_evarg(e->database, "ENB_PHY_DLSCH_UE_DCI", "UE_id"), + filter_int(ue))); + logger_set_filter(e->e->ul_mcs_logger, + filter_eq( + filter_evarg(e->database, "ENB_PHY_ULSCH_UE_DCI", "UE_id"), + filter_int(ue))); } static void click(void *private, gui *g, @@ -309,6 +325,30 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database, logger_add_view(l, v); e->pucch_iq_ue_logger = l; + /* UE x DL mcs */ + line = new_container(g, HORIZONTAL); + widget_add_child(g, top_container, line, -1); + w = new_xy_plot(g, 128, 55, "", 20); + xy_plot_set_range(g, w, 0, 1024*10, -1, 29); + e->dl_mcs_xy_plot = w; + widget_add_child(g, line, w, -1); + l = new_ticked_ttilog(h, database, "ENB_PHY_DL_TICK", "frame", "subframe", + "ENB_PHY_DLSCH_UE_DCI", "mcs", 0, -1); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72")); + logger_add_view(l, v); + e->dl_mcs_logger = l; + + /* UE x UL mcs */ + w = new_xy_plot(g, 128, 55, "", 20); + xy_plot_set_range(g, w, 0, 1024*10, -1, 29); + e->ul_mcs_xy_plot = w; + widget_add_child(g, line, w, -1); + l = new_ticked_ttilog(h, database, "ENB_PHY_DL_TICK", "frame", "subframe", + "ENB_PHY_ULSCH_UE_DCI", "mcs", 0, -1); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72")); + logger_add_view(l, v); + e->ul_mcs_logger = l; + /* downlink/uplink UE DCIs */ widget_add_child(g, top_container, new_label(g,"DL/UL TICK/DCI/ACK/NACK [all UEs]"), -1); From cbc2164e50ff1cfb012cf79806184a24e923f747 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 30 Nov 2016 18:01:17 +0100 Subject: [PATCH 354/413] T: bugfix: vertical tick was off by 1 pixel The problem was visible when DL MCS was set to 20 (do a ping -c 192.172.0.1 -i0.2 to get it). The dots were not plotted at the exact line of the tick mark. Not sure the fix is always correct. No big deal anyway. --- common/utils/T/tracer/gui/xy_plot.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common/utils/T/tracer/gui/xy_plot.c b/common/utils/T/tracer/gui/xy_plot.c index 9342a5a464..af88bb7149 100644 --- a/common/utils/T/tracer/gui/xy_plot.c +++ b/common/utils/T/tracer/gui/xy_plot.c @@ -70,9 +70,9 @@ static void paint(gui *_gui, widget *_this) */ char v[64]; int vwidth, dummy; - float x = (k * ticstep - allocated_xmin) / - (allocated_xmax - allocated_xmin) * - (allocated_plot_width - 1); + int x = (k * ticstep - allocated_xmin) / + (allocated_xmax - allocated_xmin) * + (allocated_plot_width - 1); x_draw_line(g->x, g->xwin, FOREGROUND_COLOR, this->common.x + this->vrule_width + x, this->common.y + this->common.height - this->label_height * 2, @@ -112,9 +112,9 @@ static void paint(gui *_gui, widget *_this) for (k = kmin; k <= kmax; k++) { char v[64]; int vwidth, dummy; - float y = (k * ticstep - allocated_ymin) / - (allocated_ymax - allocated_ymin) * - (allocated_plot_height - 1); + int y = (k * ticstep - allocated_ymin) / + (allocated_ymax - allocated_ymin) * + (allocated_plot_height - 1); sprintf(v, "%g", k * ticstep); x_text_get_dimensions(g->x, DEFAULT_FONT, v, &vwidth, &dummy, &dummy); x_draw_line(g->x, g->xwin, FOREGROUND_COLOR, From f89c70dfc34898199861fb93f7c31bbe0ebd6431 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 30 Nov 2016 18:03:49 +0100 Subject: [PATCH 355/413] T: change range of DL/UL MCS plots [-1 29] was not very pleasant for MCS 28 or no DCI (value is -1 in this case). [-2 30] looks better. --- common/utils/T/tracer/enb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/utils/T/tracer/enb.c b/common/utils/T/tracer/enb.c index c6f3bba5ff..14e1da35c0 100644 --- a/common/utils/T/tracer/enb.c +++ b/common/utils/T/tracer/enb.c @@ -329,7 +329,7 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database, line = new_container(g, HORIZONTAL); widget_add_child(g, top_container, line, -1); w = new_xy_plot(g, 128, 55, "", 20); - xy_plot_set_range(g, w, 0, 1024*10, -1, 29); + xy_plot_set_range(g, w, 0, 1024*10, -2, 30); e->dl_mcs_xy_plot = w; widget_add_child(g, line, w, -1); l = new_ticked_ttilog(h, database, "ENB_PHY_DL_TICK", "frame", "subframe", @@ -340,7 +340,7 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database, /* UE x UL mcs */ w = new_xy_plot(g, 128, 55, "", 20); - xy_plot_set_range(g, w, 0, 1024*10, -1, 29); + xy_plot_set_range(g, w, 0, 1024*10, -2, 30); e->ul_mcs_xy_plot = w; widget_add_child(g, line, w, -1); l = new_ticked_ttilog(h, database, "ENB_PHY_DL_TICK", "frame", "subframe", From cae34e0f4d5cf63e7cb031a1b33f3f08f93db808 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 1 Dec 2016 11:08:13 +0100 Subject: [PATCH 356/413] T: minor fix - wrong comments --- common/utils/T/tracer/logger/ticked_ttilog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/utils/T/tracer/logger/ticked_ttilog.c b/common/utils/T/tracer/logger/ticked_ttilog.c index 96ad20a931..53bbad7681 100644 --- a/common/utils/T/tracer/logger/ticked_ttilog.c +++ b/common/utils/T/tracer/logger/ticked_ttilog.c @@ -108,7 +108,7 @@ logger *new_ticked_ttilog(event_handler *h, void *database, f = get_format(database, event_id); - /* look for frame, subframe and data args */ + /* look for frame and subframe */ ret->tick_frame_arg = -1; ret->tick_subframe_arg = -1; for (i = 0; i < f.count; i++) { @@ -143,7 +143,7 @@ logger *new_ticked_ttilog(event_handler *h, void *database, f = get_format(database, event_id); - /* look for frame and subframe */ + /* look for frame, subframe and data args */ ret->data_frame_arg = -1; ret->data_subframe_arg = -1; ret->data_arg = -1; From 53ccc0e7adcf85b1a0c81cfd2c1ff438b2e8c3ca Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 1 Dec 2016 13:15:34 +0100 Subject: [PATCH 357/413] T: minor bugfix - bad argument type in log --- common/utils/T/tracer/gui/xy_plot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/utils/T/tracer/gui/xy_plot.c b/common/utils/T/tracer/gui/xy_plot.c index af88bb7149..3baac92c04 100644 --- a/common/utils/T/tracer/gui/xy_plot.c +++ b/common/utils/T/tracer/gui/xy_plot.c @@ -85,7 +85,7 @@ static void paint(gui *_gui, widget *_this) this->common.y + this->common.height - this->label_height * 2 + this->label_baseline, v); - LOGD("tic k %d val %g x %g\n", k, k * ticstep, x); + LOGD("tic k %d val %g x %d\n", k, k * ticstep, x); } /* vertical tics */ From ce1e9cb15ac7f6ce06e6447528151f1f58fee9de Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 1 Dec 2016 13:16:49 +0100 Subject: [PATCH 358/413] T: bugfix: bad order of parameters in function declaration --- common/utils/T/tracer/logger/logger.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/utils/T/tracer/logger/logger.h b/common/utils/T/tracer/logger/logger.h index 4ade141742..70fe7cab1f 100644 --- a/common/utils/T/tracer/logger/logger.h +++ b/common/utils/T/tracer/logger/logger.h @@ -11,9 +11,9 @@ logger *new_ttilog(void *event_handler, void *database, char *event_name, char *frame_varname, char *subframe_varname, char *data_varname, int convert_to_dB); logger *new_ticked_ttilog(void *event_handler, void *database, - char *tick_event_name, - char *event_name, char *frame_varname, char *subframe_varname, - char *data_varname, int convert_to_dB, float empty_value); + char *tick_event_name, char *frame_varname, char *subframe_varname, + char *event_name, char *data_varname, + int convert_to_dB, float empty_value); logger *new_timelog(void *event_handler, void *database, char *event_name); logger *new_ticklog(void *event_handler, void *database, char *event_name, char *frame_name, char *subframe_name); From f22e56ee6d5c2b2b6ee641dfa4c2bd0057ab5439 Mon Sep 17 00:00:00 2001 From: ROBERT Benoit Date: Thu, 1 Dec 2016 16:31:05 +0100 Subject: [PATCH 359/413] - Problem in DCI NDI : the implementation use 5 HARQ processes, but process 0 NDI never toggled because it was reused on subframe 5 that is not carrying format 1 DCI. Fix -> use 8 harq processes instead of 5. - SI scheduled on every subframe 5 (even and odd frames) instead of only on even frames - Add DLSCH scheduling on subframe 5 for odd frames - change default rballoc from 0x7FFF to 0x1FFFF to support maximum 10MHz throughput --- openair1/SCHED/phy_mac_stub.c | 79 ++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/openair1/SCHED/phy_mac_stub.c b/openair1/SCHED/phy_mac_stub.c index 0ac194d051..7753e9c2e3 100644 --- a/openair1/SCHED/phy_mac_stub.c +++ b/openair1/SCHED/phy_mac_stub.c @@ -40,14 +40,21 @@ #include "SCHED/phy_procedures_emos.h" #endif +/* SYRTEM */ +uint8_t dci_ndi_toggle_even[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint8_t dci_ndi_toggle_odd[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { - +/* SYRTEM */ + uint8_t *dci_ndi_toggle_tmp = NULL; + uint8_t harq_pid_value = 0; +/* End of SYRTEM */ //uint8_t cooperation_flag = eNB->cooperation_flag; uint8_t transmission_mode = eNB->transmission_mode[0]; - uint32_t rballoc = 0x7FFF; + uint32_t rballoc = 0x1FFFF; //uint32_t rballoc2 = 0x000F; int subframe = proc->subframe_tx; @@ -68,12 +75,14 @@ void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) switch (subframe) { case 5: - DCI_pdu->Num_common_dci = 1; - DCI_pdu->dci_alloc[0].L = 2; - DCI_pdu->dci_alloc[0].firstCCE = 0; - DCI_pdu->dci_alloc[0].rnti = SI_RNTI; - DCI_pdu->dci_alloc[0].format = format1A; - DCI_pdu->dci_alloc[0].ra_flag = 0; + if ( !(proc->frame_tx&1) ) // SI message on even frame only (SFN mod 2 == 0) + { + DCI_pdu->Num_common_dci = 1; + DCI_pdu->dci_alloc[0].L = 2; + DCI_pdu->dci_alloc[0].firstCCE = 0; + DCI_pdu->dci_alloc[0].rnti = SI_RNTI; + DCI_pdu->dci_alloc[0].format = format1A; + DCI_pdu->dci_alloc[0].ra_flag = 0; switch (eNB->frame_parms.N_RB_DL) { case 6: @@ -187,6 +196,12 @@ void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) } break; //subframe switch + } // if ( !(proc->frame_tx&1) ) + else // No SI message on odd frame (SFN mod 2 == 1) + { + /* warning: work around to send dlsch on subframe 5 odd frame !!! */ + /* todo: clean up, espacially if subframe cases are added next !!! */ + } /* case 6: DCI_pdu->Num_ue_spec_dci = 1; @@ -225,15 +240,23 @@ void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) if (eNB->frame_parms.frame_type == FDD) { DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_5MHz_FDD_t; + harq_pid_value = ( ((proc->frame_tx * 10) + subframe) % 8 ); + + if (!(subframe&1)) // even subframe + dci_ndi_toggle_tmp = &(dci_ndi_toggle_even[harq_pid_value]); + else // odd subframe + dci_ndi_toggle_tmp = &(dci_ndi_toggle_odd[harq_pid_value]); + ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(25,10,3); ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->TPC = 0; - ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->harq_pid = subframe % 5; + ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->harq_pid = harq_pid_value; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = eNB->target_ue_dl_mcs; - //((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((eNB->frame%1024)%28); - ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = subframe / 5; + ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = (*dci_ndi_toggle_tmp); ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rv = 0; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rah = 0; + (*dci_ndi_toggle_tmp) = ((*dci_ndi_toggle_tmp) + 1) & 1; + memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_5MHz_FDD_t)); /* @@ -296,36 +319,24 @@ void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) if (eNB->frame_parms.frame_type == FDD) { DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_10MHz_FDD_t; + harq_pid_value = ( ((proc->frame_tx * 10) + subframe) % 8 ); + + if (!(subframe&1)) // even subframe + dci_ndi_toggle_tmp = &(dci_ndi_toggle_even[harq_pid_value]); + else // odd subframe + dci_ndi_toggle_tmp = &(dci_ndi_toggle_odd[harq_pid_value]); + ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(50,10,3); ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->TPC = 0; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->harq_pid = subframe % 5; + ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->harq_pid = harq_pid_value; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = eNB->target_ue_dl_mcs; - //((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((eNB->frame%1024)%28); - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = subframe / 5; + ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = (*dci_ndi_toggle_tmp); ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rv = 0; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rah = 0; + (*dci_ndi_toggle_tmp) = ((*dci_ndi_toggle_tmp) + 1) & 1; + memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_10MHz_FDD_t)); - - /* - //user2 - DCI_pdu->dci_alloc[1].dci_length = sizeof_DCI1_10MHz_TDD_t; - DCI_pdu->dci_alloc[1].L = 2; - DCI_pdu->dci_alloc[1].rnti = 0x1236; - DCI_pdu->dci_alloc[1].format = format1; - DCI_pdu->dci_alloc[1].ra_flag = 0; - - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc2; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->TPC = 0; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->dai = 0; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->harq_pid = 1; - //((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((eNB->proc[subframe].frame%1024)%28); - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = eNB->target_ue_dl_mcs; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = 1; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rv = 0; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rah = 0; - memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&((DCI1_10MHz_FDD_t *)&dlsch_pdu)->,sizeof(DCI1_10MHz_TDD_t)); - */ } else { DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_10MHz_TDD_t; From f4b93cdc120d3db72ee7f13b7c852157bd864708 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Thu, 1 Dec 2016 19:37:48 +0100 Subject: [PATCH 360/413] [Gitlab CI] Add OAI UE to autotests --- cmake_targets/autotests/README.txt | 9 + .../autotests/run_exec_lte-softmodem_tests.py | 23 +- cmake_targets/autotests/test_case_list.xml | 795 ++++++++++++++++-- 3 files changed, 738 insertions(+), 89 deletions(-) diff --git a/cmake_targets/autotests/README.txt b/cmake_targets/autotests/README.txt index cf0e972b08..5841ed6dc2 100644 --- a/cmake_targets/autotests/README.txt +++ b/cmake_targets/autotests/README.txt @@ -268,6 +268,15 @@ Obj.# Case# Test# Description 02 55 22 Band 7 FDD 10MHz DL Throughput (TCP) for 300 sec for 2TX/2RX (TM2) 02 55 23 Band 7 FDD 20MHz DL Throughput (TCP) for 300 sec for 2TX/2RX (TM2) +02 57 lte-softmodem tests with USRP B210 RF as eNB and OAI EPC (eNB and EPC are on different machines) w/ OAI UE +02 57 00 Band 7 FDD 5MHz UL Throughput for 300 sec for 1TX/1RX +02 57 01 Band 7 FDD 10MHz UL Throughput for 300 sec for 1TX/1RX +02 57 02 Band 7 FDD 20MHz UL Throughput for 300 sec for 1TX/1RX +02 57 03 Band 7 FDD 5MHz DL Throughput for 300 sec for 1TX/1RX +02 57 04 Band 7 FDD 10MHz DL Throughput for 300 sec for 1TX/1RX +02 57 05 Band 7 FDD 20MHz DL Throughput for 300 sec for 1TX/1RX + + 01 64 lte-softmodem-noS1 tests 02 Functional test case diff --git a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py index ab507578af..ada0cf0932 100755 --- a/cmake_targets/autotests/run_exec_lte-softmodem_tests.py +++ b/cmake_targets/autotests/run_exec_lte-softmodem_tests.py @@ -552,7 +552,7 @@ def wait_testcaseclass_generic_threads(threadListGeneric, timeout = 1): # \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) # \param ExmimoRfStop command to stop EXMIMO Card # \param nruns_lte-softmodem global parameter to override number of runs (nruns) within the test case -def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , logdirOpenaircnRepo, MachineList, user, password, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, timeout_cmd): +def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , logdirOpenaircnRepo, MachineList, user, password, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, GitOAI5GRepoBranch, GitOpenaircnRepoBranch,timeout_cmd): #We ignore the password sent to this function for secuirity reasons for password present in log files #It is recommended to add a line in /etc/sudoers that looks something like below. The line below will run sudo without password prompt # your_user_name ALL=(ALL:ALL) NOPASSWD: ALL @@ -583,7 +583,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , RRH_main_exec = testcase.findtext('RRH_main_exec',default='') RRH_main_exec_args = testcase.findtext('RRH_main_exec_args',default='') RRH_terminate_missing_procs = testcase.findtext('RRH_terminate_missing_procs',default='False') - + RRH_branch = testcase.findtext('RRH_branch',default=GitOAI5GRepoBranch) eNBMachine = testcase.findtext('eNB',default='') eNB_config_file = testcase.findtext('eNB_config_file',default='') @@ -599,6 +599,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , eNB_search_expr_true = testcase.findtext('eNB_search_expr_true','') if re.compile('\w+').match(eNB_search_expr_true) != None: eNB_search_expr_true = eNB_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' + eNB_branch = testcase.findtext('eNB_branch',default=GitOAI5GRepoBranch) UEMachine = testcase.findtext('UE',default='') UE_config_file = testcase.findtext('UE_config_file',default='') @@ -615,6 +616,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , UE_stop_script = testcase.findtext('UE_stop_script','') if re.compile('\w+').match(UE_search_expr_true) != None: UE_search_expr_true = UE_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' + UE_branch = testcase.findtext('UE_branch',default=GitOAI5GRepoBranch) EPCMachine = testcase.findtext('EPC',default='') EPC_config_file = testcase.findtext('EPC_config_file',default='') @@ -633,6 +635,8 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , EPC_traffic_exec_args = testcase.findtext('EPC_traffic_exec_args',default='') EPC_terminate_missing_procs = testcase.findtext('EPC_terminate_missing_procs',default='False') EPC_search_expr_true = testcase.findtext('EPC_search_expr_true','') + EPC_branch = testcase.findtext('EPC_branch',default=GitOpenaircnRepoBranch) + if re.compile('\w+').match(EPC_search_expr_true) != None: EPC_search_expr_true = EPC_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' @@ -689,7 +693,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , logdir_local_testcase = logdir_local + '/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) #Make the log directory of test case if RRHMachine != '': - cmd = 'rm -fr ' + logdir_RRH + ' ; mkdir -p ' + logdir_RRH + cmd = 'rm -fr ' + logdir_RRH + ' ; mkdir -p ' + logdir_RRH result = oai_RRH.send_recv(cmd) cmd = 'rm -fr ' + logdir_eNB + ' ; mkdir -p ' + logdir_eNB result = oai_eNB.send_recv(cmd) @@ -709,7 +713,8 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , logfile_task_RRH_out = logdir_RRH + '/RRH_task_out' + '_' + str(run) + '_.log' logfile_task_RRH = logdir_local_testcase + '/RRH_task' + '_' + str(run) + '_.log' task_RRH_compile = ' ( uname -a ; date \n' - task_RRH_compile = task_RRH_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_RRH_compile = task_RRH_compile + 'cd ' + logdirOAI5GRepo + '; git reset --hard HEAD ; git checkout ' + RRH_branch + ' ; source oaienv \n' + task_RRH_compile = task_RRH_compile + ' source cmake_targets/tools/build_helper \n' task_RRH_compile = task_RRH_compile + 'env |grep OPENAIR \n' task_RRH_compile = task_RRH_compile + update_config_file(oai_RRH, RRH_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' if RRH_compile_prog != "": @@ -749,7 +754,8 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , logfile_pcap_tmp_eNB = '/tmp/' + '/eNB_tshark' + '_' + str(run) + '_.pcap' task_eNB_compile = ' ( uname -a ; date \n' - task_eNB_compile = task_eNB_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' + task_eNB_compile = task_eNB_compile + 'cd ' + logdirOAI5GRepo + '; git reset --hard HEAD ; git checkout ' + eNB_branch + ' ; source oaienv \n' + task_eNB_compile = task_eNB_compile + ' source cmake_targets/tools/build_helper \n' task_eNB_compile = task_eNB_compile + 'env |grep OPENAIR \n' task_eNB_compile = task_eNB_compile + update_config_file(oai_eNB, eNB_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' if eNB_compile_prog != "": @@ -799,8 +805,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , task_UE_compile = ' ( uname -a ; date \n' task_UE_compile = task_UE_compile + 'array_exec_pid=()' + '\n' - task_UE_compile = task_UE_compile + 'cd ' + logdirOAI5GRepo + '\n' - task_UE_compile = task_UE_compile + 'source oaienv \n' + task_UE_compile = task_UE_compile + 'cd ' + logdirOAI5GRepo + '; git reset --hard HEAD ; git checkout ' + UE_branch + ' ; source oaienv \n' task_UE_compile = task_UE_compile + 'source cmake_targets/tools/build_helper \n' task_UE_compile = task_UE_compile + 'env |grep OPENAIR \n' task_UE_compile = task_UE_compile + update_config_file(oai_UE, UE_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' @@ -850,7 +855,7 @@ def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , task_EPC_compile = ' ( uname -a ; date \n' task_EPC_compile = task_EPC_compile + 'array_exec_pid=()' + '\n' - task_EPC_compile = task_EPC_compile + 'cd ' + logdirOpenaircnRepo + ' ; source oaienv \n' + task_EPC_compile = task_EPC_compile + 'cd ' + logdirOpenaircnRepo + '; git reset --hard HEAD ; git checkout ' + EPC_branch + ' ; source oaienv \n' task_EPC_compile = task_EPC_compile + update_config_file(oai_EPC, EPC_config_file, logdirOpenaircnRepo, logdirOpenaircnRepo+'/TEST/autotests/tools/search_repl.py') + '\n' task_EPC_compile = task_EPC_compile + 'source BUILD/TOOLS/build_helper \n' if EPC_compile_prog != "": @@ -2203,7 +2208,7 @@ for testcase in testcaseList: print "eNBMachine : " + eNBMachine + "UEMachine : " + UEMachine + "EPCMachine : " + EPCMachine + "MachineList : " + ','.join(MachineList) print "testcasename = " + testcasename + " class = " + testcaseclass #cleanOldProgramsAllMachines(oai_list, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop) - handle_testcaseclass_softmodem (testcase, CleanUpOldProgs, logdirOAI5GRepo, logdirOpenaircnRepo, MachineList, user, pw, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, Timeout_cmd ) + handle_testcaseclass_softmodem (testcase, CleanUpOldProgs, logdirOAI5GRepo, logdirOpenaircnRepo, MachineList, user, pw, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, GitOAI5GRepoBranch, GitOpenaircnRepoBranch, Timeout_cmd ) #The lines below are copied from below to trace the failure of some of the machines in test setup. These lines below need to be removed in long term print "Creating xml file for overall results..." diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index c73a5257e9..061569bd96 100644 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -3315,7 +3315,7 @@ lte-softmodem - calisson + hutch stevens nano 390 @@ -3333,10 +3333,10 @@ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 $OPENAIR_DIR/cmake_targets/build_oai --eNB -w USRP -c @@ -3353,6 +3353,7 @@ /tmp + develop $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash @@ -3368,27 +3369,32 @@ /tmp ETC/hss.conf MYSQL_user \"root\" ETC/hss.conf MYSQL_pass \"linux\" + ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" - ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth0\" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S11_MME \"127.0.11.1/8\" ETC/mme.conf MME_PORT_FOR_S11_MME 2123 ETC/mme.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" ETC/mme.conf OUTPUT \"CONSOLE\" - ETC/mme.conf HSS_HOSTNAME \"hss\" + ETC/mme.conf HSS_HOSTNAME \"nano\" ETC/mme_fd.conf Identity \"nano.openair4G.eur\" - ETC/hss_fd.conf Identity \"hss.openair4G.eur\" + ETC/mme_fd.conf ConnectPeer nano.openair4G.eur + ETC/hss_fd.conf Identity \"nano.openair4G.eur\" ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S11 \"lo\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"192.168.12.62/24\" - ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\",\"192.172.1.0/24\" - sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai -vf; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c + ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" + ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" + ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/acl.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai ; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c - sudo mkdir -p /usr/local/etc/oai/freeDiamter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ hss.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 @@ -3409,7 +3415,7 @@ c lte-softmodem - calisson + hutch stevens nano 390 @@ -3427,10 +3433,10 @@ c targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 $OPENAIR_DIR/cmake_targets/build_oai --eNB -w USRP -c @@ -3462,27 +3468,32 @@ c /tmp ETC/hss.conf MYSQL_user \"root\" ETC/hss.conf MYSQL_pass \"linux\" + ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" - ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth0\" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S11_MME \"127.0.11.1/8\" ETC/mme.conf MME_PORT_FOR_S11_MME 2123 ETC/mme.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" ETC/mme.conf OUTPUT \"CONSOLE\" - ETC/mme.conf HSS_HOSTNAME \"hss\" + ETC/mme.conf HSS_HOSTNAME \"nano\" ETC/mme_fd.conf Identity \"nano.openair4G.eur\" - ETC/hss_fd.conf Identity \"hss.openair4G.eur\" + ETC/mme_fd.conf ConnectPeer nano.openair4G.eur + ETC/hss_fd.conf Identity \"nano.openair4G.eur\" ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S11 \"lo\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"192.168.12.62/24\" - ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\",\"192.172.1.0/24\" - sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai -vf; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c + ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" + ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" + ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/acl.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai ; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c - sudo mkdir -p /usr/local/etc/oai/freeDiamter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ hss.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 @@ -3503,7 +3514,7 @@ c lte-softmodem - calisson + hutch stevens nano 390 @@ -3512,7 +3523,7 @@ c targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"92\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 100 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -29 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -32 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.62\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2660000000L targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 @@ -3521,10 +3532,10 @@ c targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 $OPENAIR_DIR/cmake_targets/build_oai --eNB -w USRP -c @@ -3556,27 +3567,32 @@ c /tmp ETC/hss.conf MYSQL_user \"root\" ETC/hss.conf MYSQL_pass \"linux\" + ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" - ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth0\" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S11_MME \"127.0.11.1/8\" ETC/mme.conf MME_PORT_FOR_S11_MME 2123 ETC/mme.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" ETC/mme.conf OUTPUT \"CONSOLE\" - ETC/mme.conf HSS_HOSTNAME \"hss\" + ETC/mme.conf HSS_HOSTNAME \"nano\" ETC/mme_fd.conf Identity \"nano.openair4G.eur\" - ETC/hss_fd.conf Identity \"hss.openair4G.eur\" + ETC/mme_fd.conf ConnectPeer nano.openair4G.eur + ETC/hss_fd.conf Identity \"nano.openair4G.eur\" ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S11 \"lo\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"192.168.12.62/24\" - ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\",\"192.172.1.0/24\" - sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai -vf; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c + ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" + ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" + ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/acl.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai ; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c - sudo mkdir -p /usr/local/etc/oai/freeDiamter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ hss.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 @@ -3597,7 +3613,7 @@ c lte-softmodem - calisson + hutch stevens nano 390 @@ -3615,10 +3631,10 @@ c targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 $OPENAIR_DIR/cmake_targets/build_oai --eNB -w USRP -c @@ -3640,7 +3656,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf3_script 1 ppp0 -c 192.172.0.1 -i 1 -u -f m -b 10M -R + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec @@ -3650,27 +3666,32 @@ c /tmp ETC/hss.conf MYSQL_user \"root\" ETC/hss.conf MYSQL_pass \"linux\" + ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" - ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth0\" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S11_MME \"127.0.11.1/8\" ETC/mme.conf MME_PORT_FOR_S11_MME 2123 ETC/mme.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" ETC/mme.conf OUTPUT \"CONSOLE\" - ETC/mme.conf HSS_HOSTNAME \"hss\" + ETC/mme.conf HSS_HOSTNAME \"nano\" ETC/mme_fd.conf Identity \"nano.openair4G.eur\" - ETC/hss_fd.conf Identity \"hss.openair4G.eur\" + ETC/mme_fd.conf ConnectPeer nano.openair4G.eur + ETC/hss_fd.conf Identity \"nano.openair4G.eur\" ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S11 \"lo\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"192.168.12.62/24\" - ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\",\"192.172.1.0/24\" - sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai -vf; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c + ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" + ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" + ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/acl.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai ; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c - sudo mkdir -p /usr/local/etc/oai/freeDiamter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ hss.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 @@ -3679,7 +3700,7 @@ c cp -vf $OPENAIRCN_DIR/ETC/*.conf $OPENAIRCN_TESTDIR/; $OPENAIRCN_DIR/SCRIPTS/run_hss --export-db $OPENAIRCN_TESTDIR/hss_export.db - $OPENAIRCN_DIR/TEST/autotests/tools/iperf3_script 5 lo -s -i 1 -f m + $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 10 192.172.0.2 -c 192.172.0.2 -b 16M -i 1 -f m -u @@ -3691,7 +3712,7 @@ c lte-softmodem - calisson + hutch stevens nano 390 @@ -3709,10 +3730,10 @@ c targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 $OPENAIR_DIR/cmake_targets/build_oai --eNB -w USRP -c @@ -3734,7 +3755,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf3_script 1 ppp0 -c 192.172.0.1 -i 1 -u -f m -b 10M -R + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec @@ -3744,35 +3765,42 @@ c /tmp ETC/hss.conf MYSQL_user \"root\" ETC/hss.conf MYSQL_pass \"linux\" + ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" - ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth0\" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S11_MME \"127.0.11.1/8\" ETC/mme.conf MME_PORT_FOR_S11_MME 2123 ETC/mme.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" ETC/mme.conf OUTPUT \"CONSOLE\" - ETC/mme.conf HSS_HOSTNAME \"hss\" + ETC/mme.conf HSS_HOSTNAME \"nano\" ETC/mme_fd.conf Identity \"nano.openair4G.eur\" - ETC/hss_fd.conf Identity \"hss.openair4G.eur\" + ETC/mme_fd.conf ConnectPeer nano.openair4G.eur + ETC/hss_fd.conf Identity \"nano.openair4G.eur\" ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S11 \"lo\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"192.168.12.62/24\" - ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\",\"192.172.1.0/24\" - sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai -vf; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c + ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" + ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" + ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/acl.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai ; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c - sudo mkdir -p /usr/local/etc/oai/freeDiamter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ hss.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c + + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc cp -vf $OPENAIRCN_DIR/ETC/*.conf $OPENAIRCN_TESTDIR/; $OPENAIRCN_DIR/SCRIPTS/run_hss --export-db $OPENAIRCN_TESTDIR/hss_export.db - $OPENAIRCN_DIR/TEST/autotests/tools/iperf3_script 5 lo -s -i 1 -f m + $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 10 192.172.0.2 -c 192.172.0.2 -b33M -i 1 -f m -u @@ -3784,7 +3812,7 @@ c lte-softmodem - calisson + hutch stevens nano 390 @@ -3793,7 +3821,7 @@ c targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"92\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 100 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -29 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -32 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.62\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2660000000L targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 @@ -3802,10 +3830,10 @@ c targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 $OPENAIR_DIR/cmake_targets/build_oai --eNB -w USRP -c @@ -3827,7 +3855,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf3_script 1 ppp0 -c 192.172.0.1 -i 1 -u -f m -b 9M -R + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec @@ -3837,27 +3865,32 @@ c /tmp ETC/hss.conf MYSQL_user \"root\" ETC/hss.conf MYSQL_pass \"linux\" + ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" - ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth0\" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S11_MME \"127.0.11.1/8\" ETC/mme.conf MME_PORT_FOR_S11_MME 2123 ETC/mme.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" ETC/mme.conf OUTPUT \"CONSOLE\" - ETC/mme.conf HSS_HOSTNAME \"hss\" + ETC/mme.conf HSS_HOSTNAME \"nano\" ETC/mme_fd.conf Identity \"nano.openair4G.eur\" - ETC/hss_fd.conf Identity \"hss.openair4G.eur\" + ETC/mme_fd.conf ConnectPeer nano.openair4G.eur + ETC/hss_fd.conf Identity \"nano.openair4G.eur\" ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S11 \"lo\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"192.168.12.62/24\" - ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\",\"192.172.1.0/24\" - sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai -vf; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c + ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" + ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" + ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/acl.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai ; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c - sudo mkdir -p /usr/local/etc/oai/freeDiamter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ hss.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 @@ -3866,7 +3899,7 @@ c cp -vf $OPENAIRCN_DIR/ETC/*.conf $OPENAIRCN_TESTDIR/; $OPENAIRCN_DIR/SCRIPTS/run_hss --export-db $OPENAIRCN_TESTDIR/hss_export.db - $OPENAIRCN_DIR/TEST/autotests/tools/iperf3_script 5 lo -s -i 1 -f m + $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 10 192.172.0.2 -c 192.172.0.2 -b55M -i 1 -f m -u @@ -10410,5 +10443,607 @@ c + + lte-softmodem + + hutch + starsky + nano + 390 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"93\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -26 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.62\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + --eNB -w USRP -c + sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf + + $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai --eNB --UE -w USRP -c -x + develop1B + + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + + cd $OPENAIR_DIR/cmake_targets/lte_build_oai/build ; sudo -E $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 --ue-rxgain 125 + + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s + + + + False + sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + + /tmp + ETC/hss.conf MYSQL_user \"root\" + ETC/hss.conf MYSQL_pass \"linux\" + ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" + ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"93\";MME_GID=\"4\";MME_CODE=\"1\";}" + ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"93\";TAC=\"1\";}" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" + ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" + ETC/mme.conf MME_IPV4_ADDRESS_FOR_S11_MME \"127.0.11.1/8\" + ETC/mme.conf MME_PORT_FOR_S11_MME 2123 + ETC/mme.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/mme.conf OUTPUT \"CONSOLE\" + ETC/mme.conf HSS_HOSTNAME \"nano\" + ETC/mme_fd.conf Identity \"nano.openair4G.eur\" + ETC/mme_fd.conf ConnectPeer nano.openair4G.eur + ETC/hss_fd.conf Identity \"nano.openair4G.eur\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S11 \"lo\" + ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" + ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" + ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 + ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" + ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" + ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/acl.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai ; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c + + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c + +c + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 + + sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc + + cp -vf $OPENAIRCN_DIR/ETC/*.conf $OPENAIRCN_TESTDIR/; $OPENAIRCN_DIR/SCRIPTS/run_hss --export-db $OPENAIRCN_TESTDIR/hss_export.db + + $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 5 lo -s -i 1 -u -f m + + throughput_test min=0.0Mbits/sec max=1.0Mbits/sec average=1.0Mbits/sec + + False + USRPb210.OAI_EPC_remote.OAI_UE.5MHz.FDD.Band_7.UL.1TX.1RX + 10 + + + + lte-softmodem + + hutch + starsky + nano + 390 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 50 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -29 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.62\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + --eNB -w USRP -c + sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf + + $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf + + + + + False + + /tmp + + + + develop1B + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + + $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s + + + + False + sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + + /tmp + ETC/hss.conf MYSQL_user \"root\" + ETC/hss.conf MYSQL_pass \"linux\" + ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" + ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" + ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" + ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" + ETC/mme.conf MME_IPV4_ADDRESS_FOR_S11_MME \"127.0.11.1/8\" + ETC/mme.conf MME_PORT_FOR_S11_MME 2123 + ETC/mme.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/mme.conf OUTPUT \"CONSOLE\" + ETC/mme.conf HSS_HOSTNAME \"nano\" + ETC/mme_fd.conf Identity \"nano.openair4G.eur\" + ETC/mme_fd.conf ConnectPeer nano.openair4G.eur + ETC/hss_fd.conf Identity \"nano.openair4G.eur\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S11 \"lo\" + ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" + ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" + ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 + ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" + ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" + ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/acl.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai ; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c + + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c + +c + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 + + sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc + + cp -vf $OPENAIRCN_DIR/ETC/*.conf $OPENAIRCN_TESTDIR/; $OPENAIRCN_DIR/SCRIPTS/run_hss --export-db $OPENAIRCN_TESTDIR/hss_export.db + + $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 5 lo -s -i 1 -u -f m + + throughput_test min=0.0Mbits/sec max=1.0Mbits/sec average=1.0Mbits/sec + + False + USRPb210.OAI_EPC_remote.OAI_UE.10MHz.FDD.Band_7.UL.1TX.1RX + 10 + + + + lte-softmodem + + hutch + starsky + nano + 390 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 100 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -32 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.62\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + --eNB -w USRP -c + sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ;sudo -E ifconfig eth0:3 192.170.0.2 up ; sudo -E ifconfig eth0:4 192.170.1.2 up; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf + + $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf + + + + + False + + /tmp + + + + develop1B + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + + $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s + + + + False + sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + + /tmp + ETC/hss.conf MYSQL_user \"root\" + ETC/hss.conf MYSQL_pass \"linux\" + ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" + ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" + ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" + ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" + ETC/mme.conf MME_IPV4_ADDRESS_FOR_S11_MME \"127.0.11.1/8\" + ETC/mme.conf MME_PORT_FOR_S11_MME 2123 + ETC/mme.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/mme.conf OUTPUT \"CONSOLE\" + ETC/mme.conf HSS_HOSTNAME \"nano\" + ETC/mme_fd.conf Identity \"nano.openair4G.eur\" + ETC/mme_fd.conf ConnectPeer nano.openair4G.eur + ETC/hss_fd.conf Identity \"nano.openair4G.eur\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S11 \"lo\" + ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" + ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" + ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 + ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" + ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" + ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/acl.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai ; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c + + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c + +c + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 + + sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc + + cp -vf $OPENAIRCN_DIR/ETC/*.conf $OPENAIRCN_TESTDIR/; $OPENAIRCN_DIR/SCRIPTS/run_hss --export-db $OPENAIRCN_TESTDIR/hss_export.db + + $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 5 lo -s -i 1 -u -f m + + throughput_test min=0.0Mbits/sec max=1.0Mbits/sec average=1.0Mbits/sec + + False + USRPb210.OAI_EPC_remote.OAI_UE.20MHz.FDD.Band_7.UL.1TX.1RX + 10 + + + + lte-softmodem + + hutch + starsky + nano + 390 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -26 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.62\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + --eNB -w USRP -c + sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf + + $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf + + + + + False + + /tmp + + + + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + + develop1B + $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u + + throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec + + False + sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + + /tmp + ETC/hss.conf MYSQL_user \"root\" + ETC/hss.conf MYSQL_pass \"linux\" + ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" + ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" + ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" + ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" + ETC/mme.conf MME_IPV4_ADDRESS_FOR_S11_MME \"127.0.11.1/8\" + ETC/mme.conf MME_PORT_FOR_S11_MME 2123 + ETC/mme.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/mme.conf OUTPUT \"CONSOLE\" + ETC/mme.conf HSS_HOSTNAME \"nano\" + ETC/mme_fd.conf Identity \"nano.openair4G.eur\" + ETC/mme_fd.conf ConnectPeer nano.openair4G.eur + ETC/hss_fd.conf Identity \"nano.openair4G.eur\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S11 \"lo\" + ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" + ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" + ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 + ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" + ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" + ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/acl.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai ; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c + + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c + +c + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 + + sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc + + cp -vf $OPENAIRCN_DIR/ETC/*.conf $OPENAIRCN_TESTDIR/; $OPENAIRCN_DIR/SCRIPTS/run_hss --export-db $OPENAIRCN_TESTDIR/hss_export.db + + $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 10 192.172.0.2 -c 192.172.0.2 -b 16M -i 1 -f m -u + + + + False + USRPb210.OAI_EPC_remote.OAI_UE.5MHz.FDD.Band_7.DL.1TX.1RX + 10 + + + + lte-softmodem + + hutch + starsky + nano + 390 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 50 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -29 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.62\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + --eNB -w USRP -c + sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf + + $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf + + + + + False + + /tmp + + + + develop1B + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + + $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u + + throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec + + False + sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + + /tmp + ETC/hss.conf MYSQL_user \"root\" + ETC/hss.conf MYSQL_pass \"linux\" + ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" + ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" + ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" + ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" + ETC/mme.conf MME_IPV4_ADDRESS_FOR_S11_MME \"127.0.11.1/8\" + ETC/mme.conf MME_PORT_FOR_S11_MME 2123 + ETC/mme.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/mme.conf OUTPUT \"CONSOLE\" + ETC/mme.conf HSS_HOSTNAME \"nano\" + ETC/mme_fd.conf Identity \"nano.openair4G.eur\" + ETC/mme_fd.conf ConnectPeer nano.openair4G.eur + ETC/hss_fd.conf Identity \"nano.openair4G.eur\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S11 \"lo\" + ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" + ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" + ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 + ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" + ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" + ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/acl.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai ; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c + + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c + + + + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 + + sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc + + cp -vf $OPENAIRCN_DIR/ETC/*.conf $OPENAIRCN_TESTDIR/; $OPENAIRCN_DIR/SCRIPTS/run_hss --export-db $OPENAIRCN_TESTDIR/hss_export.db + + $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 10 192.172.0.2 -c 192.172.0.2 -b33M -i 1 -f m -u + + + + False + USRPb210.OAI_EPC_remote.OAI_UE.10MHz.FDD.Band_7.DL.1TX.1RX + 10 + + + + lte-softmodem + + hutch + starsky + nano + 390 + /tmp + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 100 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -32 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.62\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2660000000L + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.19/24\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 + $OPENAIR_DIR/cmake_targets/build_oai + --eNB -w USRP -c + sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf + + develop1B + $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf + + + + + False + + /tmp + + + + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + + $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u + + throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec + + False + sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + + /tmp + ETC/hss.conf MYSQL_user \"root\" + ETC/hss.conf MYSQL_pass \"linux\" + ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" + ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" + ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" + ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" + ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" + ETC/mme.conf MME_IPV4_ADDRESS_FOR_S11_MME \"127.0.11.1/8\" + ETC/mme.conf MME_PORT_FOR_S11_MME 2123 + ETC/mme.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/mme.conf OUTPUT \"CONSOLE\" + ETC/mme.conf HSS_HOSTNAME \"nano\" + ETC/mme_fd.conf Identity \"nano.openair4G.eur\" + ETC/mme_fd.conf ConnectPeer nano.openair4G.eur + ETC/hss_fd.conf Identity \"nano.openair4G.eur\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S11 \"lo\" + ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S11 \"127.0.11.2/8\" + ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" + ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" + ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 + ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" + ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" + ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/acl.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/mme.conf /usr/local/etc/oai/ ; sudo cp -vf $OPENAIRCN_DIR/ETC/mme_fd.conf /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/spgw.conf /usr/local/etc/oai ; $OPENAIRCN_DIR/SCRIPTS/./check_mme_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur ; $OPENAIRCN_DIR/SCRIPTS/build_mme -c ; $OPENAIRCN_DIR/SCRIPTS/build_spgw -c + + sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c + +c + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 + + sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc + + cp -vf $OPENAIRCN_DIR/ETC/*.conf $OPENAIRCN_TESTDIR/; $OPENAIRCN_DIR/SCRIPTS/run_hss --export-db $OPENAIRCN_TESTDIR/hss_export.db + + $OPENAIRCN_DIR/TEST/autotests/tools/iperf_script 10 192.172.0.2 -c 192.172.0.2 -b55M -i 1 -f m -u + + + + False + USRPb210.OAI_EPC_remote.OAI_UE.20MHz.FDD.Band_7.DL.1TX.1RX + 10 + + + From 7c9a3311e7fb27e04cd7de69e71a99796ffb2f8b Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Thu, 1 Dec 2016 22:24:04 +0100 Subject: [PATCH 361/413] minor fixes to OAI UE/OAI EPC test cases --- cmake_targets/autotests/test_case_list.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index 061569bd96..8fb4dc1c39 100644 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -3353,11 +3353,10 @@ /tmp - develop $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s @@ -10488,7 +10487,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - cd $OPENAIR_DIR/cmake_targets/lte_build_oai/build ; sudo -E $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 --ue-rxgain 125 + sleep 50; cd $OPENAIR_DIR/cmake_targets/lte_build_oai/build ; sudo -E $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 --ue-rxgain 125 $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s From 05c635311d1dec5a82d03e6c988da2dd44d83caa Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Fri, 2 Dec 2016 07:20:43 +0100 Subject: [PATCH 362/413] fix for 0157 test cases --- cmake_targets/autotests/test_case_list.xml | 53 +++++++++++----------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index 8fb4dc1c39..60d7043338 100644 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -11,7 +11,7 @@ sudo -S -E /opt/ltebox/tools/stop_ltebox exmimo_pci=`lspci -m | grep Xilinx`; if [ -n "$exmimo_pci" ] ; then $OPENAIR_DIR/cmake_targets/build_oai -w EXMIMO -c; sudo -S -E $OPENAIR_DIR/cmake_targets/tools/stop_exmimo2; fi; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_huaweiE398_ue.py --reset-ue; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue; uname -a; sudo -E dmesg 36000 - 010141 0102+ 010301 010303 010304 010305 0104+ 015508 015511 015520 015523 015518 015519 015520 015521 015522 015523 015602 015605 015702 015705 015818 015819 015820 015821 015822 015823 016102 016105 016502 016505 017002 017005 018002 018005 018502 018505 025514 025517 025520 025523 025518 025519 025520 025521 025522 025523 + 010141 0102+ 010301 010303 010304 010305 0104+ 015508 015511 015520 015523 015518 015519 015520 015521 015522 015523 015602 015605 015818 015819 015820 015821 015822 015823 016102 016105 016502 016505 017002 017005 018002 018005 018502 018505 025514 025517 025520 025523 025518 025519 025520 025521 025522 025523 3 amerique mozart hutch starsky stevens calisson superserver @@ -3387,7 +3387,7 @@ ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_INTERFACE_NAME_FOR_SGI \"eth1\" ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" @@ -3396,7 +3396,7 @@ sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c c - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc @@ -3455,7 +3455,7 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s @@ -3486,7 +3486,7 @@ c ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_INTERFACE_NAME_FOR_SGI \"eth1\" ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" @@ -3554,9 +3554,9 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 28Mbits/s @@ -3585,7 +3585,7 @@ c ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_INTERFACE_NAME_FOR_SGI \"eth1\" ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" @@ -3653,14 +3653,14 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u - throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec - False sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + throughput_test min=0.0Mbits/sec max=5.0Mbits/sec average=4.0Mbits/sec + /tmp ETC/hss.conf MYSQL_user \"root\" @@ -3684,7 +3684,7 @@ c ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_INTERFACE_NAME_FOR_SGI \"eth1\" ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" @@ -3752,14 +3752,14 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u - throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec - False sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + throughput_test min=0.0Mbits/sec max=9.0Mbits/sec average=9.0Mbits/sec + /tmp ETC/hss.conf MYSQL_user \"root\" @@ -3783,7 +3783,7 @@ c ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_INTERFACE_NAME_FOR_SGI \"eth1\" ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" @@ -3852,14 +3852,15 @@ c $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; sleep 10; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u - throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec - False sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + throughput_test min=0.0Mbits/sec max=9.0Mbits/sec average=9.0Mbits/sec + + /tmp ETC/hss.conf MYSQL_user \"root\" @@ -3883,7 +3884,7 @@ c ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_INTERFACE_NAME_FOR_SGI \"eth1\" ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" @@ -10518,7 +10519,7 @@ c ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_INTERFACE_NAME_FOR_SGI \"eth1\" ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" @@ -10618,7 +10619,7 @@ c ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_INTERFACE_NAME_FOR_SGI \"eth1\" ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" @@ -10718,7 +10719,7 @@ c ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_INTERFACE_NAME_FOR_SGI \"eth1\" ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" @@ -10818,7 +10819,7 @@ c ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_INTERFACE_NAME_FOR_SGI \"eth1\" ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" @@ -10918,7 +10919,7 @@ c ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_INTERFACE_NAME_FOR_SGI \"eth1\" ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" @@ -11019,7 +11020,7 @@ c ETC/spgw.conf SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP \"eth1\" ETC/spgw.conf SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP \"192.168.12.62/24\" ETC/spgw.conf SGW_IPV4_PORT_FOR_S1U_S12_S4_UP 2152 - ETC/spgw.conf PGW_IPV4_ADDRESS_FOR_SGI \"eth1\" + ETC/spgw.conf PGW_INTERFACE_NAME_FOR_SGI \"eth1\" ETC/spgw.conf PGW_MASQUERADE_SGI \"yes\" ETC/spgw.conf DEFAULT_DNS_IPV4_ADDRESS \"192.168.12.100\" ETC/spgw.conf IPV4_LIST \"192.172.0.0/24\" From 06409595609f2b2f48d9c04ad4be11f2faee8a66 Mon Sep 17 00:00:00 2001 From: Rohit gupta Date: Fri, 2 Dec 2016 07:54:02 +0100 Subject: [PATCH 363/413] minor fixes for 0257* test cases --- cmake_targets/autotests/test_case_list.xml | 118 +++++++++++---------- 1 file changed, 61 insertions(+), 57 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index 60d7043338..c96c906fc3 100644 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -10486,16 +10486,16 @@ c $OPENAIR_DIR/cmake_targets/build_oai --eNB --UE -w USRP -c -x develop1B - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo rmmod nasmesh ; sudo rmmod ue_ip; sudo rmmod oai_nw_drv sleep 50; cd $OPENAIR_DIR/cmake_targets/lte_build_oai/build ; sudo -E $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 --ue-rxgain 125 - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 7Mbits/s + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 oai0 -u -c 192.172.0.1 -b 7Mbits/s False - sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + /tmp ETC/hss.conf MYSQL_user \"root\" @@ -10528,7 +10528,7 @@ c sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c c - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc @@ -10553,7 +10553,7 @@ c /tmp targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"93\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 50 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -29 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.62\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" @@ -10571,7 +10571,7 @@ c targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 $OPENAIR_DIR/cmake_targets/build_oai --eNB -w USRP -c - sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf + sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -10583,26 +10583,26 @@ c /tmp - - + $OPENAIR_DIR/cmake_targets/build_oai --eNB --UE -w USRP -c -x develop1B - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo rmmod nasmesh ; sudo rmmod ue_ip; sudo rmmod oai_nw_drv - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + sleep 50; cd $OPENAIR_DIR/cmake_targets/lte_build_oai/build ; sudo -E $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -U -C2660000000 -r50 --ue-scan-carrier --ue-txgain 90 --ue-rxgain 125 - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 14Mbits/s + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 oai0 -u -c 192.172.0.1 -b 14Mbits/s False - sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + /tmp ETC/hss.conf MYSQL_user \"root\" ETC/hss.conf MYSQL_pass \"linux\" ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" - ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" - ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" + ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"93\";MME_GID=\"4\";MME_CODE=\"1\";}" + ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"93\";TAC=\"1\";}" ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" @@ -10628,7 +10628,7 @@ c sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c c - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc @@ -10653,7 +10653,7 @@ c /tmp targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"93\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 100 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -32 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.62\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" @@ -10671,7 +10671,7 @@ c targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 $OPENAIR_DIR/cmake_targets/build_oai --eNB -w USRP -c - sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ;sudo -E ifconfig eth0:3 192.170.0.2 up ; sudo -E ifconfig eth0:4 192.170.1.2 up; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf + sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -10683,26 +10683,26 @@ c /tmp - - + $OPENAIR_DIR/cmake_targets/build_oai --eNB --UE -w USRP -c -x develop1B - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo rmmod nasmesh ; sudo rmmod ue_ip; sudo rmmod oai_nw_drv - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + sleep 50; cd $OPENAIR_DIR/cmake_targets/lte_build_oai/build ; sudo -E $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -U -C2660000000 -r100 --ue-scan-carrier --ue-txgain 90 --ue-rxgain 125 - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 ppp0 -u -c 192.172.0.1 -b 10Mbits/s + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 oai0 -u -c 192.172.0.1 -b 28Mbits/s False - sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + /tmp ETC/hss.conf MYSQL_user \"root\" ETC/hss.conf MYSQL_pass \"linux\" ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" - ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" - ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" + ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"93\";MME_GID=\"4\";MME_CODE=\"1\";}" + ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"93\";TAC=\"1\";}" ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" @@ -10728,7 +10728,7 @@ c sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c c - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc @@ -10781,28 +10781,29 @@ c False + /tmp - - - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - + $OPENAIR_DIR/cmake_targets/build_oai --eNB --UE -w USRP -c -x develop1B - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo rmmod nasmesh ; sudo rmmod ue_ip; sudo rmmod oai_nw_drv + + sleep 50; cd $OPENAIR_DIR/cmake_targets/lte_build_oai/build ; sudo -E $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 --ue-rxgain 125 - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u - throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec + throughput_test min=0.0Mbits/sec max=1Mbits/sec average=1Mbits/sec False - sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + /tmp ETC/hss.conf MYSQL_user \"root\" ETC/hss.conf MYSQL_pass \"linux\" ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" - ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" - ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" + ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"93\";MME_GID=\"4\";MME_CODE=\"1\";}" + ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"93\";TAC=\"1\";}" ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" @@ -10828,7 +10829,7 @@ c sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c c - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc @@ -10883,26 +10884,27 @@ c /tmp - - + $OPENAIR_DIR/cmake_targets/build_oai --eNB --UE -w USRP -c -x develop1B - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo rmmod nasmesh ; sudo rmmod ue_ip; sudo rmmod oai_nw_drv - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + sleep 50; cd $OPENAIR_DIR/cmake_targets/lte_build_oai/build ; sudo -E $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -U -C2660000000 -r50 --ue-scan-carrier --ue-txgain 90 --ue-rxgain 125 - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u - throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec + throughput_test min=0.0Mbits/sec max=1Mbits/sec average=1Mbits/sec False - sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + /tmp + ETC/hss.conf MYSQL_user \"root\" ETC/hss.conf MYSQL_pass \"linux\" ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" - ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" - ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" + ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"93\";MME_GID=\"4\";MME_CODE=\"1\";}" + ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"93\";TAC=\"1\";}" ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" @@ -10927,9 +10929,9 @@ c sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c +c + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash - - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc @@ -10985,25 +10987,26 @@ c /tmp - + $OPENAIR_DIR/cmake_targets/build_oai --eNB --UE -w USRP -c -x + develop1B - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo rmmod nasmesh ; sudo rmmod ue_ip; sudo rmmod oai_nw_drv - $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --stop-ue ; $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --start-ue + sleep 50; cd $OPENAIR_DIR/cmake_targets/lte_build_oai/build ; sudo -E $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -U -C2660000000 -r100 --ue-scan-carrier --ue-txgain 90 --ue-rxgain 125 - $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u + $OPENAIR_DIR/cmake_targets/autotests/tools/iperf_script 1 lo -s -i 1 -f m -u - throughput_test min=0.0Mbits/sec max=9Mbits/sec average=9Mbits/sec + throughput_test min=0.0Mbits/sec max=1Mbits/sec average=1Mbits/sec False - sudo -S -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue + /tmp ETC/hss.conf MYSQL_user \"root\" ETC/hss.conf MYSQL_pass \"linux\" ETC/hss.conf OPERATOR_key \"1006020f0a478bf6b699f15c062e42b3\" - ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"92\";MME_GID=\"4\";MME_CODE=\"1\";}" - ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"92\";TAC=\"1\";}" + ETC/mme.conf GUMMEI_LIST "{MCC=\"208\";MNC=\"93\";MME_GID=\"4\";MME_CODE=\"1\";}" + ETC/mme.conf TAI_LIST "{MCC=\"208\";MNC=\"93\";TAC=\"1\";}" ETC/mme.conf MME_INTERFACE_NAME_FOR_S1_MME \"eth1\" ETC/mme.conf MME_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.62/24\" ETC/mme.conf MME_INTERFACE_NAME_FOR_S11_MME \"lo\" @@ -11029,7 +11032,8 @@ c sudo mkdir -p /usr/local/etc/oai/freeDiameter; sudo cp -vf $OPENAIRCN_DIR/ETC/hss.conf /usr/local/etc/oai ; sudo cp -vf $OPENAIRCN_DIR/ETC/hss_fd.conf /usr/local/etc/oai/freeDiameter ; $OPENAIRCN_DIR/SCRIPTS/check_hss_s6a_certificate /usr/local/etc/oai/freeDiameter/ nano.openair4G.eur; $OPENAIRCN_DIR/SCRIPTS/build_hss -c c - $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; sudo -E ifconfig eth0 add 192.172.0.1 + $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash + sleep 10;$OPENAIRCN_DIR/TEST/autotests/tools/run_epc From a78ef7c9322b375f31b88d416404d9c6f9f13a3e Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Fri, 2 Dec 2016 14:56:21 +0100 Subject: [PATCH 364/413] minor fixes for 0257+ test cases --- cmake_targets/autotests/test_case_list.xml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index c96c906fc3..bf2a1ed36c 100644 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -10753,9 +10753,9 @@ c /tmp targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"93\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -26 + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -24 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.62\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2660000000L targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 @@ -10771,7 +10771,7 @@ c targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 $OPENAIR_DIR/cmake_targets/build_oai --eNB -w USRP -c - sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf + sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -10854,7 +10854,7 @@ c /tmp targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"93\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 50 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -29 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.62\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" @@ -10872,7 +10872,7 @@ c targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 $OPENAIR_DIR/cmake_targets/build_oai --eNB -w USRP -c - sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf + sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -10956,7 +10956,7 @@ c /tmp targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"92\" + targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"93\" targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 100 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf pdsch_referenceSignalPower -32 targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.62\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" @@ -10974,9 +10974,8 @@ c targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 $OPENAIR_DIR/cmake_targets/build_oai --eNB -w USRP -c - sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash ; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf + sleep 15; $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash; ifconfig ; cp $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf $OPENAIR_TESTDIR/enb.conf - develop1B $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf From d7831c1f5763c25686942ad953ec283399cfb628 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 5 Dec 2016 14:52:12 +0100 Subject: [PATCH 365/413] T: add TBS to ENB_PHY_DLSCH_UE_DCI --- common/utils/T/T_messages.txt | 2 +- openair1/SCHED/phy_procedures_lte_eNb.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index d6aa753892..2d2ee3c489 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -16,7 +16,7 @@ ID = ENB_PHY_DL_TICK ID = ENB_PHY_DLSCH_UE_DCI DESC = eNodeB downlink UE specific DCI as sent by the PHY layer GROUP = ALL:PHY:GRAPHIC:ENB - FORMAT = int,eNB_ID : int,frame : int,subframe : int,UE_id : int,rnti : int,dci_format : int,harq_pid : int,mcs + FORMAT = int,eNB_ID : int,frame : int,subframe : int,UE_id : int,rnti : int,dci_format : int,harq_pid : int,mcs : int,TBS ID = ENB_PHY_DLSCH_UE_ACK DESC = eNodeB downlink UE ACK as seen by the PHY layer in process_HARQ_feedback GROUP = ALL:PHY:GRAPHIC:ENB diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 160153317d..7286154c65 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -761,7 +761,8 @@ void generate_eNB_dlsch_params(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC T(T_ENB_PHY_DLSCH_UE_DCI, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(UE_id), T_INT(dci_alloc->rnti), T_INT(dci_alloc->format), T_INT(eNB->dlsch[(int)UE_id][0]->current_harq_pid), - T_INT(eNB->dlsch[(int)UE_id][0]->harq_processes[eNB->dlsch[(int)UE_id][0]->current_harq_pid]->mcs)); + T_INT(eNB->dlsch[(int)UE_id][0]->harq_processes[eNB->dlsch[(int)UE_id][0]->current_harq_pid]->mcs), + T_INT(eNB->dlsch[(int)UE_id][0]->harq_processes[eNB->dlsch[(int)UE_id][0]->current_harq_pid]->TBS)); eNB->dlsch[(uint8_t)UE_id][0]->nCCE[subframe] = dci_alloc->firstCCE; From 031a72de7dc0a4394f0bc6305c79631174cc272d Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 5 Dec 2016 15:08:27 +0100 Subject: [PATCH 366/413] T: new function 'bps' This function is used to print rates (say '1kb/s' or '16Mb/s'). --- common/utils/T/tracer/utils.c | 11 +++++++++++ common/utils/T/tracer/utils.h | 1 + 2 files changed, 12 insertions(+) diff --git a/common/utils/T/tracer/utils.c b/common/utils/T/tracer/utils.c index a22e0a0565..5071546735 100644 --- a/common/utils/T/tracer/utils.c +++ b/common/utils/T/tracer/utils.c @@ -7,6 +7,7 @@ #include #include #include +#include void new_thread(void *(*f)(void *), void *data) { @@ -36,6 +37,16 @@ void sleepms(int ms) if (nanosleep(&t, NULL)) abort(); } +void bps(char *out, float v, char *suffix) +{ + static char *bps_unit[4] = { "", "k", "M", "G" }; + int flog; + if (v < 1000) flog = 0; else flog = floor(floor(log10(v)) / 3); + if (flog > 3) flog = 3; + v /= pow(10, flog*3); + sprintf(out, "%g%s%s", round(v*100)/100, bps_unit[flog], suffix); +} + /****************************************************************************/ /* list */ /****************************************************************************/ diff --git a/common/utils/T/tracer/utils.h b/common/utils/T/tracer/utils.h index 086e92b5dc..3be6cfe1a7 100644 --- a/common/utils/T/tracer/utils.h +++ b/common/utils/T/tracer/utils.h @@ -3,6 +3,7 @@ void new_thread(void *(*f)(void *), void *data); void sleepms(int ms); +void bps(char *out, float v, char *suffix); /****************************************************************************/ /* list */ From f52a2c958360179e57b59d2c4fabd0ae4fb601a4 Mon Sep 17 00:00:00 2001 From: ROBERT Benoit Date: Mon, 5 Dec 2016 15:41:47 +0100 Subject: [PATCH 367/413] correct issue 147 : --phy-test mode : error msg " DL Received HarqReTx round=1 mcs=28 rballoc=8191 rv=0 " --- openair1/SCHED/phy_procedures_lte_eNb.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 7286154c65..3069afa763 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -1105,7 +1105,7 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, int frame=proc->frame_tx; int subframe=proc->subframe_tx; // uint16_t input_buffer_length; - uint32_t i,aa; + uint32_t i,j,aa; uint8_t harq_pid; DCI_PDU *DCI_pdu; DCI_PDU DCI_pdu_tmp; @@ -1203,6 +1203,14 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, fill_dci_emos(DCI_pdu,eNB); #else fill_dci(DCI_pdu,eNB,proc); + // clear previous allocation information for all UEs + for (i=0; idlsch[i][0]){ + for (j=0; j<8; j++) + eNB->dlsch[i][0]->harq_processes[j]->round = 0; + } + } + #endif } From bc032392c9e7c9fc2e97d4f4905d00e9bb7f19d0 Mon Sep 17 00:00:00 2001 From: fnabet Date: Mon, 5 Dec 2016 16:51:27 +0100 Subject: [PATCH 368/413] add workarounds for OAI issues --- openair2/LAYER2/MAC/ue_procedures.c | 37 ++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 28520802c7..886ccff238 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -70,6 +70,8 @@ #define DEBUG_HEADER_PARSING 1 #define ENABLE_MAC_PAYLOAD_DEBUG 1 +extern uint8_t usim_test; + /* #ifndef USER_MODE #define msg debug_msg @@ -1408,6 +1410,13 @@ for (lcid=DCCH; lcid < DTCH ; lcid++) { //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)) { + // 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)) { + + // Skip SRB2 multiplex if at least one SRB1 SDU is already multiplexed + break; + } + buflen_remain = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); rlc_status = mac_rlc_status_ind(module_idP, @@ -1419,8 +1428,21 @@ for (lcid=DCCH; lcid < DTCH ; lcid++) { 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) { @@ -1535,8 +1557,21 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) lcid, buflen_remain); - 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", + // 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) { From bff8e40d003921641886221fde90e5dc53680cc0 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 5 Dec 2016 17:30:13 +0100 Subject: [PATCH 369/413] T: add widget 'textarea' It's like a label but with fixed dimensions and maximum characters' capacity at creation time. --- common/utils/T/tracer/gui/Makefile | 4 +- common/utils/T/tracer/gui/gui.h | 3 + common/utils/T/tracer/gui/gui_defs.h | 13 ++++- common/utils/T/tracer/gui/textarea.c | 83 ++++++++++++++++++++++++++++ common/utils/T/tracer/gui/widget.c | 3 +- 5 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 common/utils/T/tracer/gui/textarea.c diff --git a/common/utils/T/tracer/gui/Makefile b/common/utils/T/tracer/gui/Makefile index 53f2077eac..2edec111d7 100644 --- a/common/utils/T/tracer/gui/Makefile +++ b/common/utils/T/tracer/gui/Makefile @@ -2,8 +2,8 @@ CC=gcc CFLAGS=-Wall -g -pthread -I/usr/include/X11/Xft -I/usr/include/freetype2 OBJS=init.o loop.o toplevel_window.o x.o container.o widget.o \ - gui.o label.o event.o xy_plot.o textlist.o notify.o positioner.o \ - timeline.o space.o image.o + gui.o label.o textarea.o event.o xy_plot.o textlist.o notify.o \ + positioner.o timeline.o space.o image.o gui.a: $(OBJS) ar cr gui.a $(OBJS) diff --git a/common/utils/T/tracer/gui/gui.h b/common/utils/T/tracer/gui/gui.h index c61c2dc6c0..43b955f91a 100644 --- a/common/utils/T/tracer/gui/gui.h +++ b/common/utils/T/tracer/gui/gui.h @@ -30,6 +30,7 @@ widget *new_toplevel_window(gui *gui, int width, int height, char *title); widget *new_container(gui *gui, int vertical); widget *new_positioner(gui *gui); widget *new_label(gui *gui, const char *text); +widget *new_textarea(gui *gui, int width, int height, int maxsize); widget *new_xy_plot(gui *gui, int width, int height, char *label, int vruler_width); widget *new_textlist(gui *gui, int width, int nlines, int background_color); @@ -41,6 +42,8 @@ widget *new_image(gui *gui, unsigned char *data, int length); void label_set_clickable(gui *gui, widget *label, int clickable); void label_set_text(gui *gui, widget *label, char *text); +void textarea_set_text(gui *gui, widget *textarea, char *text); + void container_set_child_growable(gui *_gui, widget *_this, widget *child, int growable); diff --git a/common/utils/T/tracer/gui/gui_defs.h b/common/utils/T/tracer/gui/gui_defs.h index 938641178c..9cb94dc98a 100644 --- a/common/utils/T/tracer/gui/gui_defs.h +++ b/common/utils/T/tracer/gui/gui_defs.h @@ -31,7 +31,7 @@ extern int volatile gui_logd; enum widget_type { TOPLEVEL_WINDOW, CONTAINER, POSITIONER, TEXT_LIST, XY_PLOT, BUTTON, LABEL, - TIMELINE, SPACE, IMAGE + TEXTAREA, TIMELINE, SPACE, IMAGE }; struct widget_list; @@ -148,6 +148,17 @@ struct label_widget { int baseline; /* as given by the graphic's backend */ }; +struct textarea_widget { + struct widget common; + char *t; + int tmaxsize; + int color; + int wanted_width; + int wanted_height; + int baseline; /* as given by the graphic's backend */ + int text_width; /* as given by the graphic's backend */ +}; + struct space_widget { struct widget common; int wanted_width; diff --git a/common/utils/T/tracer/gui/textarea.c b/common/utils/T/tracer/gui/textarea.c new file mode 100644 index 0000000000..da84f850ca --- /dev/null +++ b/common/utils/T/tracer/gui/textarea.c @@ -0,0 +1,83 @@ +#include "gui.h" +#include "gui_defs.h" +#include "x.h" +#include +#include +#include + +static void paint(gui *_gui, widget *_w) +{ + struct gui *g = _gui; + struct textarea_widget *t = _w; + LOGD("PAINT textarea '%s'\n", t->t); + x_fill_rectangle(g->x, g->xwin, BACKGROUND_COLOR, + t->common.x, t->common.y, + t->common.width, t->common.height); + x_draw_clipped_string(g->x, g->xwin, DEFAULT_FONT, t->color, + t->common.x + t->common.width - t->text_width, + t->common.y + t->baseline, t->t, + t->common.x, t->common.y, + t->common.width, t->common.height); +} + +static void hints(gui *_gui, widget *_w, int *width, int *height) +{ + struct textarea_widget *t = _w; + LOGD("HINTS textarea '%s'\n", t->t); + *width = t->wanted_width; + *height = t->wanted_height; +} + +widget *new_textarea(gui *_gui, int width, int height, int maxsize) +{ + struct gui *g = _gui; + struct textarea_widget *w; + int _; + + glock(g); + + w = new_widget(g, TEXTAREA, sizeof(struct textarea_widget)); + + w->t = calloc(maxsize, 1); + if (w->t == NULL) OOM; + w->tmaxsize = maxsize; + w->wanted_width = width; + w->wanted_height = height; + w->color = FOREGROUND_COLOR; + w->text_width = 0; + + x_text_get_dimensions(g->x, DEFAULT_FONT, "jlM", + &_, &_, &w->baseline); + + w->common.paint = paint; + w->common.hints = hints; + + gunlock(g); + + return w; +} + +/*************************************************************************/ +/* public functions */ +/*************************************************************************/ + +void textarea_set_text(gui *_g, widget *_this, char *text) +{ + struct gui *g = _g; + struct textarea_widget *this = _this; + int _; + int len = strlen(text); + if (len >= this->tmaxsize) { + fprintf(stderr, "ERROR: string '%s' too big for textarea\n", text); + return; + } + + glock(g); + + strcpy(this->t, text); + x_text_get_dimensions(g->x, DEFAULT_FONT, text, + &this->text_width, &_, &this->baseline); + send_event(g, DIRTY, this->common.id); + + gunlock(g); +} diff --git a/common/utils/T/tracer/gui/widget.c b/common/utils/T/tracer/gui/widget.c index 362d2e1e48..b8ccba6d54 100644 --- a/common/utils/T/tracer/gui/widget.c +++ b/common/utils/T/tracer/gui/widget.c @@ -265,7 +265,7 @@ void widget_dirty(gui *_gui, widget *_this) static const char *names[] = { "TOPLEVEL_WINDOW", "CONTAINER", "POSITIONER", "TEXT_LIST", - "XY_PLOT", "BUTTON", "LABEL", "TIMELINE", "SPACE", "IMAGE" + "XY_PLOT", "BUTTON", "LABEL", "TEXTAREA", "TIMELINE", "SPACE", "IMAGE" }; const char *widget_name(enum widget_type type) { @@ -277,6 +277,7 @@ const char *widget_name(enum widget_type type) case XY_PLOT: case BUTTON: case LABEL: + case TEXTAREA: case TIMELINE: case SPACE: case IMAGE: From 5b6a83fc7f1f47b18305037d02763167da4a66c1 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 5 Dec 2016 17:37:22 +0100 Subject: [PATCH 370/413] T: some work on XY plot - change paint function: when the XY plot is resized we scale. Previously the last range was put in the middle of the new range (say when we increase the size). We may get aspect ratio changes if the resize is not identical vertically and horizontally, but I think this behaviour is more 'natural'. - fix a bug: the last horizontal tick label was printed to far on the right, out of the bouding box of the XY plot. This is not totally fixed in the case the label is larger than the XY plot. Now the part out of the bounding box will be printed on the left. No big deal, make the plot big enough. (Before, even if big enough you had a problem.) - add a new vertical tick display, to be used for throughput mostly. See in enb.c the difference between 'input signal' and throughput plots (those throughput plots will come in later commits). --- common/utils/T/tracer/gui/gui.h | 5 + common/utils/T/tracer/gui/gui_defs.h | 1 + common/utils/T/tracer/gui/xy_plot.c | 202 +++++++++++++++++++++++++++ 3 files changed, 208 insertions(+) diff --git a/common/utils/T/tracer/gui/gui.h b/common/utils/T/tracer/gui/gui.h index 43b955f91a..0fb96db325 100644 --- a/common/utils/T/tracer/gui/gui.h +++ b/common/utils/T/tracer/gui/gui.h @@ -14,6 +14,10 @@ typedef void widget; #define DEFAULT_FONT 0 +/* tic type for XY plot */ +#define XY_PLOT_DEFAULT_TICK 0 +#define XY_PLOT_SCROLL_TICK 1 + /* key modifiers */ #define KEY_SHIFT (1<<0) #define KEY_CONTROL (1<<1) @@ -54,6 +58,7 @@ void xy_plot_set_points(gui *gui, widget *this, int plot, int npoints, float *x, float *y); void xy_plot_get_dimensions(gui *gui, widget *this, int *width, int *height); void xy_plot_set_title(gui *gui, widget *this, char *label); +void xy_plot_set_tick_type(gui *gui, widget *this, int type); void textlist_add(gui *gui, widget *this, const char *text, int position, int color); diff --git a/common/utils/T/tracer/gui/gui_defs.h b/common/utils/T/tracer/gui/gui_defs.h index 9cb94dc98a..88b8121ec9 100644 --- a/common/utils/T/tracer/gui/gui_defs.h +++ b/common/utils/T/tracer/gui/gui_defs.h @@ -117,6 +117,7 @@ struct xy_plot_widget { int wanted_height; struct xy_plot_plot *plots; int nplots; + int tick_type; }; struct timeline_subline { diff --git a/common/utils/T/tracer/gui/xy_plot.c b/common/utils/T/tracer/gui/xy_plot.c index 3baac92c04..4115f92103 100644 --- a/common/utils/T/tracer/gui/xy_plot.c +++ b/common/utils/T/tracer/gui/xy_plot.c @@ -1,11 +1,20 @@ #include "gui.h" #include "gui_defs.h" #include "x.h" +#include "../utils.h" #include #include #include #include +#if 0 +/* this version behaves differently when you resize the XY plot. Say + * you increase the size. The old (smaller) view is put at the center + * of the new view. Everything inside keeps the same size/aspect ratio. + * The other version below resizes the old view so that it fully occupies + * the new view. It may introduce aspect ratio changes, but usage seems + * to suggest it's a better behaviour. + */ static void paint(gui *_gui, widget *_this) { struct gui *g = _gui; @@ -155,6 +164,184 @@ static void paint(gui *_gui, widget *_this) x_plot_points(g->x, g->xwin, this->plots[n].color); } } +#endif + +static void paint(gui *_gui, widget *_this) +{ + struct gui *g = _gui; + struct xy_plot_widget *this = _this; + int allocated_plot_width; + int allocated_plot_height; + float pxsize; + float ticdist; + float tic; + float ticstep; + int k, kmin, kmax; + float allocated_xmin, allocated_xmax; + float allocated_ymin, allocated_ymax; + int i; + int n; + char v[64]; + int vwidth, dummy; + +# define FLIP(v) (-(v) + allocated_plot_height-1) + + LOGD("PAINT xy plot xywh %d %d %d %d\n", this->common.x, this->common.y, this->common.width, this->common.height); + +//x_draw_rectangle(g->x, g->xwin, 1, this->common.x, this->common.y, this->common.width, this->common.height); + + allocated_plot_width = this->common.width - this->vrule_width; + allocated_plot_height = this->common.height - this->label_height * 2; + + if (allocated_plot_width <= 1 || allocated_plot_height <= 1) { + WARN("PAINT xy plot: width (%d) or height (%d) is wrong, not painting\n", + this->common.width, this->common.height); + return; + } + + /* plot zone */ + /* TODO: refine height - height of hrule text may be != from label */ + x_draw_rectangle(g->x, g->xwin, 1, + this->common.x + this->vrule_width, + this->common.y, + this->common.width - this->vrule_width -1, /* -1 to see right border */ + this->common.height - this->label_height * 2); + + /* horizontal tics */ + pxsize = (this->xmax - this->xmin) / allocated_plot_width; + ticdist = 100; + tic = floor(log10(ticdist * pxsize)); + ticstep = powf(10, tic); + allocated_xmin = this->xmin; + allocated_xmax = this->xmax; + /* adjust tic if too tight */ + LOGD("pre x ticstep %g\n", ticstep); + while (1) { + if (ticstep / (allocated_xmax - allocated_xmin) + * (allocated_plot_width - 1) > 40) break; + ticstep *= 2; + } + LOGD("post x ticstep %g\n", ticstep); + LOGD("xmin/max %g %g width allocated %d alloc xmin/max %g %g ticstep %g\n", this->xmin, this->xmax, allocated_plot_width, allocated_xmin, allocated_xmax, ticstep); + kmin = ceil(allocated_xmin / ticstep); + kmax = floor(allocated_xmax / ticstep); + for (k = kmin; k <= kmax; k++) { +/* + (k * ticstep - allocated_xmin) / (allocated_max - allocated_xmin) = + (x - 0) / (allocated_plot_width-1 - 0) + */ + int x = (k * ticstep - allocated_xmin) / + (allocated_xmax - allocated_xmin) * + (allocated_plot_width - 1); + int px; + x_draw_line(g->x, g->xwin, FOREGROUND_COLOR, + this->common.x + this->vrule_width + x, + this->common.y + this->common.height - this->label_height * 2, + this->common.x + this->vrule_width + x, + this->common.y + this->common.height - this->label_height * 2 - 5); + sprintf(v, "%g", k * ticstep); + x_text_get_dimensions(g->x, DEFAULT_FONT, v, &vwidth, &dummy, &dummy); + + /* do not draw after the widget ('width-1' for if we use 'width' + * it is still off by 1 pixel for whatever reason) */ + px = this->vrule_width + x - vwidth/2; + if (px + vwidth > this->common.width-1) + px = this->common.width-1 - vwidth; + + x_draw_string(g->x, g->xwin, DEFAULT_FONT, FOREGROUND_COLOR, + this->common.x + px, + this->common.y + this->common.height - this->label_height * 2 + + this->label_baseline, + v); + LOGD("tic k %d val %g x %d\n", k, k * ticstep, x); + } + + /* vertical tics */ + allocated_ymin = this->ymin; + allocated_ymax = this->ymax; + switch (this->tick_type) { + case XY_PLOT_DEFAULT_TICK: + pxsize = (this->ymax - this->ymin) / allocated_plot_height; + ticdist = 30; + tic = floor(log10(ticdist * pxsize)); + ticstep = powf(10, tic); + /* adjust tic if too tight */ + LOGD("pre y ticstep %g\n", ticstep); + while (1) { + if (ticstep / (allocated_ymax - allocated_ymin) + * (allocated_plot_height - 1) > 20) break; + ticstep *= 2; + } + LOGD("post y ticstep %g\n", ticstep); + LOGD("ymin/max %g %g height allocated %d alloc " + "ymin/max %g %g ticstep %g\n", this->ymin, this->ymax, + allocated_plot_height, allocated_ymin, allocated_ymax, ticstep); + kmin = ceil(allocated_ymin / ticstep); + kmax = floor(allocated_ymax / ticstep); + for (k = kmin; k <= kmax; k++) { + int y = (k * ticstep - allocated_ymin) / + (allocated_ymax - allocated_ymin) * + (allocated_plot_height - 1); + sprintf(v, "%g", k * ticstep); + x_text_get_dimensions(g->x, DEFAULT_FONT, v, &vwidth, &dummy, &dummy); + x_draw_line(g->x, g->xwin, FOREGROUND_COLOR, + this->common.x + this->vrule_width, + this->common.y + FLIP(y), + this->common.x + this->vrule_width + 5, + this->common.y + FLIP(y)); + x_draw_string(g->x, g->xwin, DEFAULT_FONT, FOREGROUND_COLOR, + this->common.x + this->vrule_width - vwidth - 2, + this->common.y + FLIP(y)-this->label_height/2+this->label_baseline, + v); + } + break; + case XY_PLOT_SCROLL_TICK: + /* print only max value, formatted using 'bps' for readability */ + bps(v, this->ymax, ""); + x_text_get_dimensions(g->x, DEFAULT_FONT, v, &vwidth, &dummy, &dummy); + x_draw_string(g->x, g->xwin, DEFAULT_FONT, FOREGROUND_COLOR, + this->common.x + this->vrule_width - vwidth - 2, + this->common.y + +this->label_baseline, + v); + /* vertically divide into 5 */ + for (k = 1; k < 5; k++) { + int y = round((k * (allocated_plot_height - 1)) / 5.); + x_draw_line(g->x, g->xwin, FOREGROUND_COLOR, + this->common.x + this->vrule_width, + this->common.y + y, + this->common.x + this->vrule_width + 5, + this->common.y + y); + } + break; + } /* swich (this->tick_type) */ + + /* label at bottom, in the middle */ + x_draw_string(g->x, g->xwin, DEFAULT_FONT, FOREGROUND_COLOR, + this->common.x + (this->common.width - this->label_width) / 2, + this->common.y + this->common.height - this->label_height + + this->label_baseline, + this->label); + + for (n = 0; n < this->nplots; n++) { + /* points */ + float ax, bx, ay, by; + ax = (allocated_plot_width-1) / (allocated_xmax - allocated_xmin); + bx = -ax * allocated_xmin; + ay = (allocated_plot_height-1) / (allocated_ymax - allocated_ymin); + by = -ay * allocated_ymin; + for (i = 0; i < this->plots[n].npoints; i++) { + int x, y; + x = ax * this->plots[n].x[i] + bx; + y = ay * this->plots[n].y[i] + by; + if (x >= 0 && x < allocated_plot_width && + y >= 0 && y < allocated_plot_height) + x_add_point(g->x, + this->common.x + this->vrule_width + x, + this->common.y + FLIP(y)); + } + x_plot_points(g->x, g->xwin, this->plots[n].color); + } +} static void hints(gui *_gui, widget *_w, int *width, int *height) { @@ -191,6 +378,7 @@ widget *new_xy_plot(gui *_gui, int width, int height, char *label, w->ymax = 1; w->plots = NULL; w->nplots = 0; + w->tick_type = XY_PLOT_DEFAULT_TICK; w->common.paint = paint; w->common.hints = hints; @@ -309,3 +497,17 @@ void xy_plot_set_title(gui *_gui, widget *_this, char *label) gunlock(g); } + +void xy_plot_set_tick_type(gui *_gui, widget *_this, int type) +{ + struct gui *g = _gui; + struct xy_plot_widget *this = _this; + + glock(g); + + this->tick_type = type; + + send_event(g, DIRTY, this->common.id); + + gunlock(g); +} From 2270dae1e722d7410ba99ed29c7b17672504fae0 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 5 Dec 2016 17:49:03 +0100 Subject: [PATCH 371/413] T: new view 'scolltti' This view is used to display throughput (to come in next commits). --- common/utils/T/tracer/view/Makefile | 2 +- common/utils/T/tracer/view/scrolltti.c | 100 +++++++++++++++++++++++++ common/utils/T/tracer/view/view.h | 2 + 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 common/utils/T/tracer/view/scrolltti.c diff --git a/common/utils/T/tracer/view/Makefile b/common/utils/T/tracer/view/Makefile index 32b267ec24..370c317e66 100644 --- a/common/utils/T/tracer/view/Makefile +++ b/common/utils/T/tracer/view/Makefile @@ -1,7 +1,7 @@ CC=gcc CFLAGS=-Wall -g -pthread -I.. -I../logger -OBJS=stdout.o textlist.o xy.o tti.o time.o ticktime.o +OBJS=stdout.o textlist.o xy.o tti.o time.o ticktime.o scrolltti.o view.a: $(OBJS) ar cr view.a $(OBJS) diff --git a/common/utils/T/tracer/view/scrolltti.c b/common/utils/T/tracer/view/scrolltti.c new file mode 100644 index 0000000000..ad83cbc756 --- /dev/null +++ b/common/utils/T/tracer/view/scrolltti.c @@ -0,0 +1,100 @@ +#include "view.h" +#include "../utils.h" +#include +#include +#include +#include +#include +#include + +struct scrolltti { + view common; + gui *g; + widget *w; + widget *throughput_textarea; + int plot; + float refresh_rate; + pthread_mutex_t lock; + unsigned long data[1000]; + unsigned long total; /* sum data[0..999] to have smoother value printed */ + float xout[1000]; + float yout[1000]; + int insert_point; +}; + +/* this array is used to get Y range 1000, 2000, 5000, 10000, ... */ +static int tolog[11] = { -1, 1, 2, 5, 5, 5, 10, 10, 10, 10, 10 }; + +static void *scrolltti_thread(void *_this) +{ + struct scrolltti *this = _this; + int i; + int p; + float max, mlog; + char o[64]; + + while (1) { + if (pthread_mutex_lock(&this->lock)) abort(); + /* TODO: optimize */ + p = this->insert_point; + max = 0; + for (i = 0; i < 1000; i++) { + this->xout[i] = i; + this->yout[i] = this->data[p]; + if (this->data[p] > max) max = this->data[p]; + p = (p + 1) % 1000; + } + bps(o, this->total/1000., "b/s"); + textarea_set_text(this->g, this->throughput_textarea, o); + /* for Y range we want 1000, 2000, 5000, 10000, 20000, 50000, etc. */ + if (max < 1000) max = 1000; + mlog = pow(10, floor(log10(max))); + max = tolog[(int)ceil(max/mlog)] * mlog; + xy_plot_set_range(this->g, this->w, 0, 1000, 0, max); + xy_plot_set_points(this->g, this->w, this->plot, + 1000, this->xout, this->yout); + if (pthread_mutex_unlock(&this->lock)) abort(); + sleepms(1000/this->refresh_rate); + } + + return 0; +} + +static void clear(view *this) +{ + /* TODO */ +} + +static void append(view *_this, int frame, int subframe, double value) +{ + struct scrolltti *this = (struct scrolltti *)_this; + + if (pthread_mutex_lock(&this->lock)) abort(); + this->total -= this->data[this->insert_point]; + this->data[this->insert_point] = value; + this->total += this->data[this->insert_point]; + this->insert_point = (this->insert_point + 1) % 1000; + if (pthread_mutex_unlock(&this->lock)) abort(); +} + +view *new_view_scrolltti(float refresh_rate, gui *g, widget *w, int color, + widget *throughput_textarea) +{ + struct scrolltti *ret = calloc(1, sizeof(struct scrolltti)); + if (ret == NULL) abort(); + + ret->common.clear = clear; + ret->common.append = (void (*)(view *, ...))append; + + ret->refresh_rate = refresh_rate; + ret->g = g; + ret->w = w; + ret->throughput_textarea = throughput_textarea; + ret->plot = xy_plot_new_plot(g, w, color); + + if (pthread_mutex_init(&ret->lock, NULL)) abort(); + + new_thread(scrolltti_thread, ret); + + return (view *)ret; +} diff --git a/common/utils/T/tracer/view/view.h b/common/utils/T/tracer/view/view.h index 2173c842ce..8167a00ccd 100644 --- a/common/utils/T/tracer/view/view.h +++ b/common/utils/T/tracer/view/view.h @@ -19,6 +19,8 @@ view *new_view_xy(int length, float refresh_rate, gui *g, widget *w, int color, enum xy_mode mode); view *new_view_tti(float refresh_rate, gui *g, widget *w, int color); +view *new_view_scrolltti(float refresh_rate, gui *g, widget *w, + int color, widget *throughput_label); view *new_view_time(int number_of_seconds, float refresh_rate, gui *g, widget *w); view *new_subview_time(view *time, int line, int color, int size); From 41582eb340f0cdd8ac4d03e8f99ba2ca02752d8e Mon Sep 17 00:00:00 2001 From: Xiwen JIANG Date: Mon, 5 Dec 2016 17:56:58 +0100 Subject: [PATCH 372/413] fix compliation problems for unitary tests --- openair1/SIMULATION/LTE_PHY/mbmssim.c | 3 ++- openair1/SIMULATION/LTE_PHY/pbchsim.c | 2 +- openair1/SIMULATION/LTE_PHY/pdcchsim.c | 7 ++++--- openair1/SIMULATION/LTE_PHY/prachsim.c | 1 + openair1/SIMULATION/LTE_PHY/pucchsim.c | 1 + openair1/SIMULATION/LTE_PHY/ulsim.c | 2 +- 6 files changed, 10 insertions(+), 6 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/mbmssim.c b/openair1/SIMULATION/LTE_PHY/mbmssim.c index 65d9112c9d..7849dec1ab 100644 --- a/openair1/SIMULATION/LTE_PHY/mbmssim.c +++ b/openair1/SIMULATION/LTE_PHY/mbmssim.c @@ -238,6 +238,7 @@ int main(int argc, char **argv) n_tx=2; lte_param_init(n_tx, + n_tx, n_rx, transmission_mode, extended_prefix_flag, @@ -301,7 +302,7 @@ int main(int argc, char **argv) 0); // Create transport channel structures for 2 transport blocks (MIMO) - eNB->dlsch_MCH = new_eNB_dlsch(1,8,Nsoft,N_RB_DL,0,&eNB->lte_frame_parms); + eNB->dlsch_MCH = new_eNB_dlsch(1,8,Nsoft,N_RB_DL,0,&eNB->frame_parms); if (!eNB->dlsch_MCH) { printf("Can't get eNB dlsch structures\n"); diff --git a/openair1/SIMULATION/LTE_PHY/pbchsim.c b/openair1/SIMULATION/LTE_PHY/pbchsim.c index f696cc8da4..83906d7322 100644 --- a/openair1/SIMULATION/LTE_PHY/pbchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pbchsim.c @@ -325,7 +325,7 @@ int main(int argc, char **argv) if (transmission_mode>=2) n_tx=2; - lte_param_init(n_tx,n_rx,transmission_mode,extended_prefix_flag,frame_type,Nid_cell,3,N_RB_DL,0,osf,0); + lte_param_init(n_tx, n_tx,n_rx,transmission_mode,extended_prefix_flag,frame_type,Nid_cell,3,N_RB_DL,0,osf,0); eNB1 = malloc(sizeof(PHY_VARS_eNB)); eNB2 = malloc(sizeof(PHY_VARS_eNB)); diff --git a/openair1/SIMULATION/LTE_PHY/pdcchsim.c b/openair1/SIMULATION/LTE_PHY/pdcchsim.c index d8b096a8cd..04b9d304b3 100644 --- a/openair1/SIMULATION/LTE_PHY/pdcchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pdcchsim.c @@ -694,6 +694,7 @@ int main(int argc, char **argv) n_tx=2; lte_param_init(n_tx, + n_tx, n_rx, transmission_mode, extended_prefix_flag, @@ -737,7 +738,7 @@ int main(int argc, char **argv) subframe,NUMBER_OF_OFDM_CARRIERS, eNB->frame_parms.Ncp,eNB->frame_parms.samples_per_tti,nsymb); - eNB2UE = new_channel_desc_scm(eNB->frame_parms.nb_antennas_tx_eNB, + eNB2UE = new_channel_desc_scm(eNB->frame_parms.nb_antennas_tx, UE->frame_parms.nb_antennas_rx, channel_model, N_RB2sampling_rate(eNB->frame_parms.N_RB_DL), @@ -812,7 +813,7 @@ int main(int argc, char **argv) for (trial=0; trialcommon_vars.txdataF[eNb_id][aa][512*14*subframe],&eNB->common_vars.txdataF[eNb_id][aa][0]); - for (aa=0; aaframe_parms.nb_antennas_tx_eNB; aa++) { + for (aa=0; aaframe_parms.nb_antennas_tx; aa++) { memset(&eNB->common_vars.txdataF[eNb_id][aa][0],0,FRAME_LENGTH_COMPLEX_SAMPLES_NO_PREFIX*sizeof(int32_t)); } @@ -958,7 +959,7 @@ int main(int argc, char **argv) tx_lev = 0; - for (aa=0; aalte_frame_parms.nb_antenna_ports_eNB; aa++) { + for (aa=0; aaframe_parms.nb_antenna_ports_eNB; aa++) { if (eNB->frame_parms.Ncp == 1) PHY_ofdm_mod(&eNB->common_vars.txdataF[eNb_id][aa][subframe*nsymb*eNB->frame_parms.ofdm_symbol_size], // input, &txdata[aa][subframe*eNB->frame_parms.samples_per_tti], // output diff --git a/openair1/SIMULATION/LTE_PHY/prachsim.c b/openair1/SIMULATION/LTE_PHY/prachsim.c index ad57d17507..7acc07528c 100644 --- a/openair1/SIMULATION/LTE_PHY/prachsim.c +++ b/openair1/SIMULATION/LTE_PHY/prachsim.c @@ -308,6 +308,7 @@ int main(int argc, char **argv) n_tx=2; lte_param_init(n_tx, + n_tx, n_rx, transmission_mode, extended_prefix_flag, diff --git a/openair1/SIMULATION/LTE_PHY/pucchsim.c b/openair1/SIMULATION/LTE_PHY/pucchsim.c index 843cd27a54..77bfcb18cf 100644 --- a/openair1/SIMULATION/LTE_PHY/pucchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pucchsim.c @@ -296,6 +296,7 @@ int main(int argc, char **argv) n_tx=2; lte_param_init(n_tx, + n_tx, n_rx, transmission_mode, extended_prefix_flag, diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 52d6b6b347..cf9e5aaa30 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -680,7 +680,7 @@ int main(int argc, char **argv) } // Create transport channel structures for 2 transport blocks (MIMO) for (i=0; i<2; i++) { - eNB->dlsch[0][i] = new_eNB_dlsch(1,8,1827072,N_RB_DL,0,eNB->frame_parms); + eNB->dlsch[0][i] = new_eNB_dlsch(1,8,1827072,N_RB_DL,0,&eNB->frame_parms); UE->dlsch[0][i] = new_ue_dlsch(1,8,1827072,MAX_TURBO_ITERATIONS,N_RB_DL,0); if (!eNB->dlsch[0][i]) { From 9a0f32aa1d0d1d28b6a206f6311bc37a7d9532a8 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 5 Dec 2016 17:58:16 +0100 Subject: [PATCH 373/413] T: add 'throughputlog' logger Normally it is used to display throughput. The computation it does is to sum up the wanted value for the last second (1000 TTIs) and send this value to the views associated to this logger, at each TTI. --- common/utils/T/tracer/logger/Makefile | 2 +- common/utils/T/tracer/logger/logger.h | 3 + common/utils/T/tracer/logger/throughputlog.c | 194 +++++++++++++++++++ 3 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 common/utils/T/tracer/logger/throughputlog.c diff --git a/common/utils/T/tracer/logger/Makefile b/common/utils/T/tracer/logger/Makefile index 897c36e66f..28f0e0b813 100644 --- a/common/utils/T/tracer/logger/Makefile +++ b/common/utils/T/tracer/logger/Makefile @@ -2,7 +2,7 @@ CC=gcc CFLAGS=-Wall -g -pthread -I.. OBJS=logger.o textlog.o framelog.o ttilog.o timelog.o ticklog.o iqlog.o \ - iqdotlog.o ticked_ttilog.o + iqdotlog.o ticked_ttilog.o throughputlog.o logger.a: $(OBJS) ar cr logger.a $(OBJS) diff --git a/common/utils/T/tracer/logger/logger.h b/common/utils/T/tracer/logger/logger.h index 70fe7cab1f..434cf5a90f 100644 --- a/common/utils/T/tracer/logger/logger.h +++ b/common/utils/T/tracer/logger/logger.h @@ -14,6 +14,9 @@ logger *new_ticked_ttilog(void *event_handler, void *database, char *tick_event_name, char *frame_varname, char *subframe_varname, char *event_name, char *data_varname, int convert_to_dB, float empty_value); +logger *new_throughputlog(void *event_handler, void *database, + char *tick_event_name, char *frame_varname, char *subframe_varname, + char *event_name, char *data_varname); logger *new_timelog(void *event_handler, void *database, char *event_name); logger *new_ticklog(void *event_handler, void *database, char *event_name, char *frame_name, char *subframe_name); diff --git a/common/utils/T/tracer/logger/throughputlog.c b/common/utils/T/tracer/logger/throughputlog.c new file mode 100644 index 0000000000..8a2d46da91 --- /dev/null +++ b/common/utils/T/tracer/logger/throughputlog.c @@ -0,0 +1,194 @@ +#include "logger.h" +#include "logger_defs.h" +#include "event.h" +#include "database.h" +#include "handler.h" +#include "filter/filter.h" +#include +#include +#include +#include + +struct throughputlog { + struct logger common; + void *database; + int tick_frame_arg; + int tick_subframe_arg; + int data_frame_arg; + int data_subframe_arg; + int data_arg; + int last_tick_frame; + int last_tick_subframe; + unsigned long bits[1000]; + unsigned long total; + int insert_point; + char *tick_event_name; + unsigned long tick_handler_id; + /* tick filter - NULL is no filter set */ + void *tick_filter; +}; + +static void _event(void *p, event e) +{ + struct throughputlog *l = p; + int frame; + int subframe; + unsigned long value; + + if (l->common.filter != NULL && filter_eval(l->common.filter, e) == 0) + return; + + frame = e.e[l->data_frame_arg].i; + subframe = e.e[l->data_subframe_arg].i; + + if (frame != l->last_tick_frame || subframe != l->last_tick_subframe) { + printf("WARNING: %s:%d: data comes without previous tick!\n", + __FILE__, __LINE__); + return; + } + + switch (e.e[l->data_arg].type) { + case EVENT_INT: value = e.e[l->data_arg].i; break; + case EVENT_ULONG: value = e.e[l->data_arg].ul; break; + default: printf("%s:%d: unsupported type\n", __FILE__, __LINE__); abort(); + } + + l->total += value; + l->bits[l->insert_point] += value; +} + +static void _tick_event(void *p, event e) +{ + struct throughputlog *l = p; + int i; + int frame; + int subframe; + + if (l->tick_filter != NULL && filter_eval(l->tick_filter, e) == 0) + return; + + frame = e.e[l->tick_frame_arg].i; + subframe = e.e[l->tick_subframe_arg].i; + + for (i = 0; i < l->common.vsize; i++) + l->common.v[i]->append(l->common.v[i], frame, subframe, (double)l->total); + + l->insert_point = (l->insert_point + 1) % 1000; + l->total -= l->bits[l->insert_point]; + l->bits[l->insert_point] = 0; + + l->last_tick_frame = frame; + l->last_tick_subframe = subframe; +} + +logger *new_throughputlog(event_handler *h, void *database, + char *tick_event_name, char *frame_varname, char *subframe_varname, + char *event_name, char *data_varname) +{ + struct throughputlog *ret; + int event_id; + database_event_format f; + int i; + + ret = calloc(1, sizeof(struct throughputlog)); if (ret == NULL) abort(); + + ret->common.event_name = strdup(event_name); + if (ret->common.event_name == NULL) abort(); + ret->database = database; + + ret->tick_event_name = strdup(tick_event_name); + if (ret->tick_event_name == NULL) abort(); + + /* tick event */ + event_id = event_id_from_name(database, tick_event_name); + + ret->tick_handler_id=register_handler_function(h,event_id,_tick_event,ret); + + f = get_format(database, event_id); + + /* look for frame and subframe */ + ret->tick_frame_arg = -1; + ret->tick_subframe_arg = -1; + for (i = 0; i < f.count; i++) { + if (!strcmp(f.name[i], frame_varname)) ret->tick_frame_arg = i; + if (!strcmp(f.name[i], subframe_varname)) ret->tick_subframe_arg = i; + } + if (ret->tick_frame_arg == -1) { + printf("%s:%d: frame argument '%s' not found in event '%s'\n", + __FILE__, __LINE__, frame_varname, event_name); + abort(); + } + if (ret->tick_subframe_arg == -1) { + printf("%s:%d: subframe argument '%s' not found in event '%s'\n", + __FILE__, __LINE__, subframe_varname, event_name); + abort(); + } + if (strcmp(f.type[ret->tick_frame_arg], "int") != 0) { + printf("%s:%d: argument '%s' has wrong type (should be 'int')\n", + __FILE__, __LINE__, frame_varname); + abort(); + } + if (strcmp(f.type[ret->tick_subframe_arg], "int") != 0) { + printf("%s:%d: argument '%s' has wrong type (should be 'int')\n", + __FILE__, __LINE__, subframe_varname); + abort(); + } + + /* data event */ + event_id = event_id_from_name(database, event_name); + + ret->common.handler_id = register_handler_function(h,event_id,_event,ret); + + f = get_format(database, event_id); + + /* look for frame, subframe and data args */ + ret->data_frame_arg = -1; + ret->data_subframe_arg = -1; + ret->data_arg = -1; + for (i = 0; i < f.count; i++) { + if (!strcmp(f.name[i], frame_varname)) ret->data_frame_arg = i; + if (!strcmp(f.name[i], subframe_varname)) ret->data_subframe_arg = i; + if (!strcmp(f.name[i], data_varname)) ret->data_arg = i; + } + if (ret->data_frame_arg == -1) { + printf("%s:%d: frame argument '%s' not found in event '%s'\n", + __FILE__, __LINE__, frame_varname, event_name); + abort(); + } + if (ret->data_subframe_arg == -1) { + printf("%s:%d: subframe argument '%s' not found in event '%s'\n", + __FILE__, __LINE__, subframe_varname, event_name); + abort(); + } + if (ret->data_arg == -1) { + printf("%s:%d: data argument '%s' not found in event '%s'\n", + __FILE__, __LINE__, data_varname, event_name); + abort(); + } + if (strcmp(f.type[ret->data_frame_arg], "int") != 0) { + printf("%s:%d: argument '%s' has wrong type (should be 'int')\n", + __FILE__, __LINE__, frame_varname); + abort(); + } + if (strcmp(f.type[ret->data_subframe_arg], "int") != 0) { + printf("%s:%d: argument '%s' has wrong type (should be 'int')\n", + __FILE__, __LINE__, subframe_varname); + abort(); + } + if (strcmp(f.type[ret->data_arg], "int") != 0 && + strcmp(f.type[ret->data_arg], "float") != 0) { + printf("%s:%d: argument '%s' has wrong type" + " (should be 'int' or 'float')\n", + __FILE__, __LINE__, data_varname); + abort(); + } + + return ret; +} + +void throughputlog_set_tick_filter(logger *_l, void *filter) +{ + struct throughputlog *l = (struct throughputlog *)_l; + free(l->tick_filter); + l->tick_filter = filter; +} From 8def47c4881ab140d16d04faff815e3a95c345e7 Mon Sep 17 00:00:00 2001 From: Xenofon Foukas Date: Mon, 5 Dec 2016 22:04:12 +0200 Subject: [PATCH 374/413] Changed old licenses in FlexRAN agent source files --- .../CONTROL_MODULES/MAC/flexran_agent_mac.c | 48 ++++++++---------- .../CONTROL_MODULES/MAC/flexran_agent_mac.h | 48 ++++++++---------- .../MAC/flexran_agent_mac_defs.h | 48 ++++++++---------- .../MAC/flexran_agent_mac_internal.c | 48 ++++++++---------- .../MAC/flexran_agent_mac_internal.h | 48 ++++++++---------- openair2/ENB_APP/flexran_agent.c | 48 ++++++++---------- openair2/ENB_APP/flexran_agent.h | 49 ++++++++----------- openair2/ENB_APP/flexran_agent_async.c | 48 ++++++++---------- openair2/ENB_APP/flexran_agent_async.h | 48 ++++++++---------- openair2/ENB_APP/flexran_agent_common.c | 48 ++++++++---------- openair2/ENB_APP/flexran_agent_common.h | 48 ++++++++---------- .../ENB_APP/flexran_agent_common_internal.c | 48 ++++++++---------- .../ENB_APP/flexran_agent_common_internal.h | 48 ++++++++---------- openair2/ENB_APP/flexran_agent_defs.h | 48 ++++++++---------- openair2/ENB_APP/flexran_agent_extern.h | 48 ++++++++---------- openair2/ENB_APP/flexran_agent_handler.c | 48 ++++++++---------- openair2/ENB_APP/flexran_agent_net_comm.c | 48 ++++++++---------- openair2/ENB_APP/flexran_agent_net_comm.h | 48 ++++++++---------- openair2/ENB_APP/flexran_agent_task_manager.c | 47 ++++++++---------- openair2/ENB_APP/flexran_agent_task_manager.h | 47 ++++++++---------- openair2/LAYER2/MAC/flexran_agent_mac_proto.h | 48 ++++++++---------- .../MAC/flexran_agent_scheduler_dataplane.c | 48 ++++++++---------- .../MAC/flexran_agent_scheduler_dlsch_ue.c | 48 ++++++++---------- .../flexran_agent_scheduler_dlsch_ue_remote.c | 48 ++++++++---------- .../flexran_agent_scheduler_dlsch_ue_remote.h | 48 ++++++++---------- openair2/LAYER2/MAC/flexran_dci_conversions.h | 48 ++++++++---------- openair2/UTIL/ASYNC_IF/link_manager.c | 47 ++++++++---------- openair2/UTIL/ASYNC_IF/link_manager.h | 47 ++++++++---------- openair2/UTIL/ASYNC_IF/message_queue.c | 47 ++++++++---------- openair2/UTIL/ASYNC_IF/message_queue.h | 47 ++++++++---------- openair2/UTIL/ASYNC_IF/ringbuffer_queue.c | 47 ++++++++---------- openair2/UTIL/ASYNC_IF/ringbuffer_queue.h | 47 ++++++++---------- openair2/UTIL/ASYNC_IF/socket_link.c | 47 ++++++++---------- openair2/UTIL/ASYNC_IF/socket_link.h | 47 ++++++++---------- 34 files changed, 680 insertions(+), 943 deletions(-) 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 34b6ef345f..b9cad28278 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.c @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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 message handler for MAC layer 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 fbb13ceca9..e2378e9311 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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.h * \brief FlexRAN agent message handler APIs for MAC layer 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 e42847c371..bb6aed1d8e 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 @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_defs.h * \brief FlexRAN agent - mac interface primitives 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 04a90250eb..a63225e657 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 @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_internal.c * \brief Helper functions for the MAC agent diff --git a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h index e7a922d503..9a7d4a8555 100644 --- a/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h +++ b/openair2/ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac_internal.h @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_internal.h * \brief Implementation specific definitions for the FlexRAN MAC agent diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index 8984e39971..beca1062bd 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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.h * \brief top level flexran agent receive thread and itti task diff --git a/openair2/ENB_APP/flexran_agent.h b/openair2/ENB_APP/flexran_agent.h index beed4b9885..21ea21aafc 100644 --- a/openair2/ENB_APP/flexran_agent.h +++ b/openair2/ENB_APP/flexran_agent.h @@ -1,32 +1,23 @@ - -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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.h * \brief top level flexran agent diff --git a/openair2/ENB_APP/flexran_agent_async.c b/openair2/ENB_APP/flexran_agent_async.c index ae0273a668..978b44929d 100644 --- a/openair2/ENB_APP/flexran_agent_async.c +++ b/openair2/ENB_APP/flexran_agent_async.c @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_async.c * \brief channel implementation for async interface diff --git a/openair2/ENB_APP/flexran_agent_async.h b/openair2/ENB_APP/flexran_agent_async.h index 3e5c21463a..b097b15c25 100644 --- a/openair2/ENB_APP/flexran_agent_async.h +++ b/openair2/ENB_APP/flexran_agent_async.h @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_async.h * \brief channel implementation for async interface diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index 00f938f4fb..2ccca6602b 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_common.c * \brief common primitives for all agents diff --git a/openair2/ENB_APP/flexran_agent_common.h b/openair2/ENB_APP/flexran_agent_common.h index caa2eeb900..56a52cd0b6 100644 --- a/openair2/ENB_APP/flexran_agent_common.h +++ b/openair2/ENB_APP/flexran_agent_common.h @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_common.h * \brief common message primitves and utilities diff --git a/openair2/ENB_APP/flexran_agent_common_internal.c b/openair2/ENB_APP/flexran_agent_common_internal.c index f35cd8666f..3026190863 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.c +++ b/openair2/ENB_APP/flexran_agent_common_internal.c @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_common_internal.c * \brief internal functions for common message primitves and utilities diff --git a/openair2/ENB_APP/flexran_agent_common_internal.h b/openair2/ENB_APP/flexran_agent_common_internal.h index 45f4a73ffb..c8f78aafe9 100644 --- a/openair2/ENB_APP/flexran_agent_common_internal.h +++ b/openair2/ENB_APP/flexran_agent_common_internal.h @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_common_internal.h * \brief internal agent functions for common message primitves and utilities diff --git a/openair2/ENB_APP/flexran_agent_defs.h b/openair2/ENB_APP/flexran_agent_defs.h index 7da0487120..d60510b0c7 100644 --- a/openair2/ENB_APP/flexran_agent_defs.h +++ b/openair2/ENB_APP/flexran_agent_defs.h @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_defs.h * \brief FlexRAN agent common definitions diff --git a/openair2/ENB_APP/flexran_agent_extern.h b/openair2/ENB_APP/flexran_agent_extern.h index 602b1d6ce3..3a03239e6f 100644 --- a/openair2/ENB_APP/flexran_agent_extern.h +++ b/openair2/ENB_APP/flexran_agent_extern.h @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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 ENB_APP/extern.h * \brief FlexRAN agent - mac interface primitives diff --git a/openair2/ENB_APP/flexran_agent_handler.c b/openair2/ENB_APP/flexran_agent_handler.c index c077827c66..4967e46923 100644 --- a/openair2/ENB_APP/flexran_agent_handler.c +++ b/openair2/ENB_APP/flexran_agent_handler.c @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_handler.c * \brief FlexRAN agent tx and rx message handler diff --git a/openair2/ENB_APP/flexran_agent_net_comm.c b/openair2/ENB_APP/flexran_agent_net_comm.c index 986c819fb0..6e39d6089f 100644 --- a/openair2/ENB_APP/flexran_agent_net_comm.c +++ b/openair2/ENB_APP/flexran_agent_net_comm.c @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_net_comm.c * \brief FlexRAN agent network interface abstraction diff --git a/openair2/ENB_APP/flexran_agent_net_comm.h b/openair2/ENB_APP/flexran_agent_net_comm.h index ca26de7c16..e4aa854c70 100644 --- a/openair2/ENB_APP/flexran_agent_net_comm.h +++ b/openair2/ENB_APP/flexran_agent_net_comm.h @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_net_comm.h * \brief FlexRAN agent network interface abstraction diff --git a/openair2/ENB_APP/flexran_agent_task_manager.c b/openair2/ENB_APP/flexran_agent_task_manager.c index e278386ba4..eaa6a58af8 100644 --- a/openair2/ENB_APP/flexran_agent_task_manager.c +++ b/openair2/ENB_APP/flexran_agent_task_manager.c @@ -1,31 +1,24 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2015 Eurecom +/* + * 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 + */ - 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@eurecom.fr - - Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ /*! \file flexran_agent_task_manager.h * \brief Implementation of scheduled tasks manager for the FlexRAN agent * \author Xenofon Foukas diff --git a/openair2/ENB_APP/flexran_agent_task_manager.h b/openair2/ENB_APP/flexran_agent_task_manager.h index 9faa0e3db7..1b14f1f6f6 100644 --- a/openair2/ENB_APP/flexran_agent_task_manager.h +++ b/openair2/ENB_APP/flexran_agent_task_manager.h @@ -1,31 +1,24 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2015 Eurecom +/* + * 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 + */ - 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@eurecom.fr - - Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ /*! \file flexran_agent_task_manager.h * \brief Implementation of scheduled tasks manager for the FlexRAN agent * \author Xenofon Foukas diff --git a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h index 9e46e0904a..060e8ab6ca 100644 --- a/openair2/LAYER2/MAC/flexran_agent_mac_proto.h +++ b/openair2/LAYER2/MAC/flexran_agent_mac_proto.h @@ -1,31 +1,23 @@ -/******************************************************************************* - 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ +/* + * 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_proto.h * \brief MAC functions for FlexRAN agent diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c index aff196681e..6d3c32a516 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c @@ -1,31 +1,23 @@ -/******************************************************************************* - 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ +/* + * 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_scheduler_dataplane.c * \brief data plane procedures related to eNB scheduling diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index bc0187cd56..8975465e77 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -1,31 +1,23 @@ -/******************************************************************************* - 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ +/* + * 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_scheduler_dlsch_ue.c * \brief procedures related to eNB for the DLSCH transport channel 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 78b093c27d..7dec8d0c56 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.c @@ -1,31 +1,23 @@ -/******************************************************************************* - 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ +/* + * 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_scheduler_dlsch_ue_remote.c * \brief procedures related to remote scheduling in the DLSCH transport channel diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h index 2cfad85771..7a02ff2f1d 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h @@ -1,31 +1,23 @@ -/******************************************************************************* - 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ +/* + * 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_scheduler_dlsch_ue_remote.h * \brief Local stub for remote scheduler used by the controller diff --git a/openair2/LAYER2/MAC/flexran_dci_conversions.h b/openair2/LAYER2/MAC/flexran_dci_conversions.h index 038290d1b2..a417c39d20 100644 --- a/openair2/LAYER2/MAC/flexran_dci_conversions.h +++ b/openair2/LAYER2/MAC/flexran_dci_conversions.h @@ -1,31 +1,23 @@ -/******************************************************************************* - 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. - - *******************************************************************************/ +/* + * 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_dci_conversions.h * \brief Conversion helpers from flexran messages to OAI formats DCI diff --git a/openair2/UTIL/ASYNC_IF/link_manager.c b/openair2/UTIL/ASYNC_IF/link_manager.c index 0ab2ecc2b2..1c9fb72bfe 100644 --- a/openair2/UTIL/ASYNC_IF/link_manager.c +++ b/openair2/UTIL/ASYNC_IF/link_manager.c @@ -1,31 +1,24 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2015 Eurecom +/* + * 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 + */ - 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@eurecom.fr - - Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ /*! \file link_manager.c * \brief this is the implementation of a link manager * \author Cedric Roux diff --git a/openair2/UTIL/ASYNC_IF/link_manager.h b/openair2/UTIL/ASYNC_IF/link_manager.h index 4f0628c0ee..a25c072b41 100644 --- a/openair2/UTIL/ASYNC_IF/link_manager.h +++ b/openair2/UTIL/ASYNC_IF/link_manager.h @@ -1,31 +1,24 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2015 Eurecom +/* + * 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 + */ - 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@eurecom.fr - - Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ /*! \file link_manager.h * \brief this is the implementation of a link manager * \author Cedric Roux diff --git a/openair2/UTIL/ASYNC_IF/message_queue.c b/openair2/UTIL/ASYNC_IF/message_queue.c index 3e06b5021a..ee6c92d852 100644 --- a/openair2/UTIL/ASYNC_IF/message_queue.c +++ b/openair2/UTIL/ASYNC_IF/message_queue.c @@ -1,31 +1,24 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2015 Eurecom +/* + * 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 + */ - 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@eurecom.fr - - Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ /*! \file message_queue.c * \brief this is the implementation of a message queue * \author Cedric Roux diff --git a/openair2/UTIL/ASYNC_IF/message_queue.h b/openair2/UTIL/ASYNC_IF/message_queue.h index 15fc4335a1..4e46ec08d6 100644 --- a/openair2/UTIL/ASYNC_IF/message_queue.h +++ b/openair2/UTIL/ASYNC_IF/message_queue.h @@ -1,31 +1,24 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2015 Eurecom +/* + * 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 + */ - 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@eurecom.fr - - Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ /*! \file message_queue.h * \brief this is the implementation of a message queue * \author Cedric Roux diff --git a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c index 0d63e41431..047e3f716c 100644 --- a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c +++ b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.c @@ -1,31 +1,24 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2015 Eurecom +/* + * 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 + */ - 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@eurecom.fr - - Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ /*! \file ringbuffer_queue.c * \brief Lock-free ringbuffer used for async message passing of agent * \author Xenofon Foukas diff --git a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h index 756a35ae4a..7dc4637404 100644 --- a/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h +++ b/openair2/UTIL/ASYNC_IF/ringbuffer_queue.h @@ -1,31 +1,24 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2015 Eurecom +/* + * 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 + */ - 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@eurecom.fr - - Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ /*! \file ringbuffer_queue.h * \brief Lock-free ringbuffer used for async message passing of agent * \author Xenofon Foukas diff --git a/openair2/UTIL/ASYNC_IF/socket_link.c b/openair2/UTIL/ASYNC_IF/socket_link.c index f4bd248f78..720a55398c 100644 --- a/openair2/UTIL/ASYNC_IF/socket_link.c +++ b/openair2/UTIL/ASYNC_IF/socket_link.c @@ -1,31 +1,24 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2015 Eurecom +/* + * 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 + */ - 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@eurecom.fr - - Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ /*! \file socket_link.c * \brief this is the implementation of a TCP socket ASYNC IF * \author Cedric Roux diff --git a/openair2/UTIL/ASYNC_IF/socket_link.h b/openair2/UTIL/ASYNC_IF/socket_link.h index c9e99b839f..5b9f438c8a 100644 --- a/openair2/UTIL/ASYNC_IF/socket_link.h +++ b/openair2/UTIL/ASYNC_IF/socket_link.h @@ -1,31 +1,24 @@ -/******************************************************************************* - OpenAirInterface - Copyright(c) 1999 - 2015 Eurecom +/* + * 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 + */ - 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@eurecom.fr - - Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - -*******************************************************************************/ /*! \file socket_link.h * \brief this is the implementation of a TCP socket ASYNC IF * \author Cedric Roux From 726a543abf90b99e5fd54ca30e9b39f61c406019 Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Thu, 24 Nov 2016 20:07:55 +0800 Subject: [PATCH 375/413] fixed missing a slot_fep() processing on the 1st OFDM symbol of the first DL subframe after UL, causing no SI-RNTI DCI detected --- openair1/SCHED/phy_procedures_lte_ue.c | 41 +++++++++++++++++++------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 5dc629b90b..91d5fefb66 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -3299,11 +3299,23 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin l2 = (ue->frame_parms.symbols_per_tti/2)-1; } - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // RX processing of symbols l=1...l2 (l=0 is done in last scheduling epoch) - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - +#if 1 // 2016-11-24 wilson fixed missing slot_fep on 1st ofdm symbol of the first DL subframe after UL + int prev_subframe_rx = (subframe_rx - 1)<0? 9: (subframe_rx - 1); + if (subframe_select(&ue->frame_parms,prev_subframe_rx) != SF_DL) { + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // RX processing of symbols l=0...l2 + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + l=0; + } else { + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // RX processing of symbols l=1...l2 (l=0 is done in last scheduling epoch) + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + l=1; + } + for (; l<=l2; l++) { +#else for (l=1; l<=l2; l++) { +#endif if (abstraction_flag == 0) { start_meas(&ue->ofdm_demod_stats); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP, VCD_FUNCTION_IN); @@ -3424,13 +3436,20 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin ue_measurement_procedures(l-1,ue,proc,eNB_id,abstraction_flag,mode); } // for l=1..l2 - // do first symbol of next subframe for channel estimation - slot_fep(ue, - 0, - (2+(subframe_rx<<1))%20, - ue->rx_offset, - 0, - 0); + +#if 1 // 2016-11-24 wilson fixed missing slot_fep on 1st ofdm symbol of the first DL subframe after UL + // do first symbol of next downlink subframe for channel estimation + int next_subframe_rx = (1+subframe_rx)%10; + if (subframe_select(&ue->frame_parms,next_subframe_rx) != SF_UL) +#endif + { + slot_fep(ue, + 0, + (next_subframe_rx<<1), + ue->rx_offset, + 0, + 0); + } } // not an S-subframe // run pbch procedures if subframe is 0 From ae253f45b25cf246cfdca085531c472e30537a3c Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Fri, 25 Nov 2016 18:49:02 +0800 Subject: [PATCH 376/413] added more logs to debug missing SI-RNTI DCIs --- openair1/PHY/LTE_TRANSPORT/dci.c | 11 ++++++-- targets/RT/USER/lte-ue.c | 46 ++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index 38cfc2c8c9..c27d156ad2 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -1126,6 +1126,9 @@ void pdcch_extract_rbs_dual(int32_t **rxdataF, int nushiftmod3 = frame_parms->nushift%3; symbol_mod = (symbol>=(7-frame_parms->Ncp)) ? symbol-(7-frame_parms->Ncp) : symbol; +#ifdef DEBUG_DCI_DECODING + LOG_I(PHY, "extract_rbs_dual: symbol_mod %d\n",symbol_mod); +#endif for (aarx=0; aarxnb_antennas_rx; aarx++) { @@ -2679,11 +2682,15 @@ void dci_decoding_procedure0(LTE_UE_PDCCH **pdcch_vars, nCCE = get_nCCE(pdcch_vars[eNB_id]->num_pdcch_symbols,frame_parms,mi); - if (nCCE > get_nCCE(3,frame_parms,1)) + if (nCCE > get_nCCE(3,frame_parms,1)) { + LOG_D(PHY,"skip DCI decoding: nCCE=%d > get_nCCE(3,frame_parms,1)=%d\n", nCCE, get_nCCE(3,frame_parms,1)); return; + } - if (nCCEmode ) == 0) { hw_slot_offset = (UE->rx_offset<<1) / UE->frame_parms.samples_per_tti; - LOG_I( HW, "Got synch: hw_slot_offset %d\n", hw_slot_offset ); + LOG_I( HW, "Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %d (DL %u, UL %u), UE_scan_carrier %d\n", + hw_slot_offset, + freq_offset, + UE->rx_total_gain_dB, + downlink_frequency[0][0]+freq_offset, + downlink_frequency[0][0]+uplink_frequency_offset[0][0]+freq_offset, + UE->UE_scan_carrier ); + if (UE->UE_scan_carrier == 1) { UE->UE_scan_carrier = 0; @@ -710,10 +717,21 @@ static void *UE_thread_rxn_txnp4(void *arg) while (sync_var<0) pthread_cond_wait(&sync_cond, &sync_mutex); +#if 1 // 2016-11-23 wilson add pthread name to the logging +#define THREAD_NAME_LEN 16 + char threadname[THREAD_NAME_LEN]; + ret = pthread_getname_np(proc->pthread_rxtx, threadname, THREAD_NAME_LEN); + if (ret != 0) + { + perror("pthread_getname_np : "); + exit_fun("Error getting thread name"); + } +#endif + pthread_mutex_unlock(&sync_mutex); printf("unlocked sync_mutex, waiting (UE_thread_rxtx)\n"); - printf("Starting UE RXN_TXNP4 thread\n"); + printf("Starting UE RXN_TXNP4 thread (%s)\n", threadname); while (!oai_exit) { if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) { @@ -739,10 +757,27 @@ static void *UE_thread_rxn_txnp4(void *arg) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_UE+(proc->subframe_rx&1), proc->frame_rx ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_UE+(proc->subframe_tx&1), proc->frame_tx ); - if ((subframe_select( &UE->frame_parms, proc->subframe_rx) == SF_DL) || - (UE->frame_parms.frame_type == FDD) || - (subframe_select( &UE->frame_parms, proc->subframe_rx ) == SF_S)) { + lte_subframe_t sf_type = subframe_select( &UE->frame_parms, proc->subframe_rx); + if ((sf_type == SF_DL) || + (UE->frame_parms.frame_type == FDD) || + (sf_type == SF_S)) { + if (UE->frame_parms.frame_type == TDD) { + LOG_D(PHY, "%s,TDD%d,%s: calling UE_RX\n", + threadname, + UE->frame_parms.tdd_config, + (sf_type==SF_DL? "SF_DL" : + (sf_type==SF_UL? "SF_UL" : + (sf_type==SF_S ? "SF_S" : "UNKNOWN_SF_TYPE")))); + } else { + LOG_D(PHY, "%s,%s,%s: calling UE_RX\n", + threadname, + (UE->frame_parms.frame_type==FDD? "FDD": + (UE->frame_parms.frame_type==TDD? "TDD":"UNKNOWN_DUPLEX_MODE")), + (sf_type==SF_DL? "SF_DL" : + (sf_type==SF_UL? "SF_UL" : + (sf_type==SF_S ? "SF_S" : "UNKNOWN_SF_TYPE")))); + } phy_procedures_UE_RX( UE, proc, 0, 0, UE->mode, no_relay, NULL ); } @@ -1122,6 +1157,7 @@ void *UE_thread(void *arg) { exit_fun("nothing to add"); return &UE_thread_retval; } + LOG_D(PHY, "firing up rxtx_thread[%d] at subframe %d\n", sf&1, sf); } else { LOG_E( PHY, "[SCHED][UE] UE RX thread busy (IC %d)!!\n", instance_cnt_rxtx); if (instance_cnt_rxtx > 2) { From e1b95332007859fb720d7ae9b0924962db85d3df Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Fri, 25 Nov 2016 18:56:08 +0800 Subject: [PATCH 377/413] enabled extra logs --- openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c | 4 ++-- openair1/PHY/LTE_TRANSPORT/dci.c | 10 +++++----- openair1/PHY/LTE_TRANSPORT/initial_sync.c | 2 +- openair1/PHY/LTE_TRANSPORT/pcfich.c | 6 +++--- openair1/SCHED/phy_procedures_lte_ue.c | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c index b7b36efa0b..c7fc5c4e7d 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c @@ -32,7 +32,7 @@ #define k1 ((long long int) 1000) #define k2 ((long long int) (1024-k1)) -//#define DEBUG_MEAS +#define DEBUG_MEAS #ifdef USER_MODE void print_shorts(char *s,short *x) @@ -287,7 +287,7 @@ void ue_rrc_measurements(PHY_VARS_UE *ue, for (l=0,nu=0; l<=(4-ue->frame_parms.Ncp); l+=(4-ue->frame_parms.Ncp),nu=3) { k = (nu + nushift)%6; #ifdef DEBUG_MEAS - LOG_I(PHY,"[UE %d] Frame %d subframe %d Doing ue_rrc_measurements rsrp/rssi (Nid_cell %d, nushift %d, eNB_offset %d, k %d, l %d)\n",ue->Mod_id,ue->proc.proc_rxtx[subframe&1].frame_rx,subframe,Nid_cell,nushift, + LOG_D(PHY,"[UE %d] Frame %d subframe %d Doing ue_rrc_measurements rsrp/rssi (Nid_cell %d, nushift %d, eNB_offset %d, k %d, l %d)\n",ue->Mod_id,ue->proc.proc_rxtx[subframe&1].frame_rx,subframe,Nid_cell,nushift, eNB_offset,k,l); #endif diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index c27d156ad2..9554da33db 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -403,7 +403,7 @@ void pdcch_demapping(uint16_t *llr,uint16_t *wbar,LTE_DL_FRAME_PARMS *frame_parm for (i=0; i<4; i++) { wbar[mprime] = llr[tti_offset0+i]; #ifdef DEBUG_DCI_DECODING - LOG_I(PHY,"PDCCH demapping mprime %d.%d <= llr %d (symbol %d re %d) -> (%d,%d)\n",mprime/4,i,tti_offset0+i,symbol_offset,re_offset0,*(char*)&wbar[mprime],*(1+(char*)&wbar[mprime])); + LOG_D(PHY,"PDCCH demapping mprime %d.%d <= llr %d (symbol %d re %d) -> (%d,%d)\n",mprime/4,i,tti_offset0+i,symbol_offset,re_offset0,*(char*)&wbar[mprime],*(1+(char*)&wbar[mprime])); #endif mprime++; re_offset0++; @@ -419,7 +419,7 @@ void pdcch_demapping(uint16_t *llr,uint16_t *wbar,LTE_DL_FRAME_PARMS *frame_parm for (i=0; i<4; i++) { wbar[mprime] = llr[tti_offset+i]; #ifdef DEBUG_DCI_DECODING - LOG_I(PHY,"PDCCH demapping mprime %d.%d <= llr %d (symbol %d re %d) -> (%d,%d)\n",mprime/4,i,tti_offset+i,symbol_offset,re_offset+i,*(char*)&wbar[mprime],*(1+(char*)&wbar[mprime])); + LOG_D(PHY,"PDCCH demapping mprime %d.%d <= llr %d (symbol %d re %d) -> (%d,%d)\n",mprime/4,i,tti_offset+i,symbol_offset,re_offset+i,*(char*)&wbar[mprime],*(1+(char*)&wbar[mprime])); #endif mprime++; } @@ -2473,16 +2473,16 @@ void dci_decoding(uint8_t DCI_LENGTH, #ifdef DEBUG_DCI_DECODING for (i=0; i<16+DCI_LENGTH; i++) - LOG_I(PHY," DCI %d : (%d,%d,%d)\n",i,*(d_rx+96+(3*i)),*(d_rx+97+(3*i)),*(d_rx+98+(3*i))); + LOG_D(PHY," DCI %d : (%d,%d,%d)\n",i,*(d_rx+96+(3*i)),*(d_rx+97+(3*i)),*(d_rx+98+(3*i))); #endif memset(decoded_output,0,2+((16+DCI_LENGTH)>>3)); #ifdef DEBUG_DCI_DECODING - printf("Before Viterbi\n"); + LOG_D(PHY, "Before Viterbi\n"); for (i=0; i<16+DCI_LENGTH; i++) - printf("%d : (%d,%d,%d)\n",i,*(d_rx+96+(3*i)),*(d_rx+97+(3*i)),*(d_rx+98+(3*i))); + LOG_D(PHY, "%d : (%d,%d,%d)\n",i,*(d_rx+96+(3*i)),*(d_rx+97+(3*i)),*(d_rx+98+(3*i))); #endif //debug_printf("Doing DCI Viterbi \n"); diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c index 663978e92c..7df08a8382 100644 --- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c +++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c @@ -41,7 +41,7 @@ #include "common_lib.h" extern openair0_config_t openair0_cfg[]; -//#define DEBUG_INITIAL_SYNCH +#define DEBUG_INITIAL_SYNCH int pbch_detection(PHY_VARS_UE *ue, runmode_t mode) { diff --git a/openair1/PHY/LTE_TRANSPORT/pcfich.c b/openair1/PHY/LTE_TRANSPORT/pcfich.c index 8af540eea1..1d73d020a0 100644 --- a/openair1/PHY/LTE_TRANSPORT/pcfich.c +++ b/openair1/PHY/LTE_TRANSPORT/pcfich.c @@ -34,7 +34,7 @@ //uint16_t pcfich_reg[4]; //uint8_t pcfich_first_reg_idx = 0; -//#define DEBUG_PCFICH +#define DEBUG_PCFICH void generate_pcfich_reg_mapping(LTE_DL_FRAME_PARMS *frame_parms) { @@ -301,7 +301,7 @@ uint8_t rx_pcfich(LTE_DL_FRAME_PARMS *frame_parms, } #ifdef DEBUG_PCFICH - msg("metric %d : %d\n",i,metric); + LOG_I(PHY, "metric %d : %d\n",i,metric); #endif if (metric > old_metric) { @@ -311,7 +311,7 @@ uint8_t rx_pcfich(LTE_DL_FRAME_PARMS *frame_parms, } #ifdef DEBUG_PCFICH - msg("[PHY] PCFICH detected for %d PDCCH symbols\n",num_pdcch_symbols); + LOG_I(PHY, "PCFICH detected for %d PDCCH symbols\n",num_pdcch_symbols); #endif return(num_pdcch_symbols); } diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 91d5fefb66..cc3f5e6e10 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -3279,7 +3279,7 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin #ifdef DEBUG_PHY_PROC - LOG_D(PHY,"[%s %d] Frame %d subframe %d: Doing phy_procedures_UE_RX (%d)\n", + LOG_I(PHY,"[%s %d] Frame %d subframe %d: Doing phy_procedures_UE_RX (-)\n", (r_type == multicast_relay) ? "RN/UE" : "UE", ue->Mod_id,frame_rx, subframe_rx); #endif From 81daba1931c308e254b65f4735a1c04bf115c599 Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Fri, 25 Nov 2016 18:57:33 +0800 Subject: [PATCH 378/413] Revert "enabled extra logs" This reverts commit 5466562b16d70f2729f6103e1c0d3ee619470191. --- openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c | 4 ++-- openair1/PHY/LTE_TRANSPORT/dci.c | 10 +++++----- openair1/PHY/LTE_TRANSPORT/initial_sync.c | 2 +- openair1/PHY/LTE_TRANSPORT/pcfich.c | 6 +++--- openair1/SCHED/phy_procedures_lte_ue.c | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c index c7fc5c4e7d..b7b36efa0b 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ue_measurements.c @@ -32,7 +32,7 @@ #define k1 ((long long int) 1000) #define k2 ((long long int) (1024-k1)) -#define DEBUG_MEAS +//#define DEBUG_MEAS #ifdef USER_MODE void print_shorts(char *s,short *x) @@ -287,7 +287,7 @@ void ue_rrc_measurements(PHY_VARS_UE *ue, for (l=0,nu=0; l<=(4-ue->frame_parms.Ncp); l+=(4-ue->frame_parms.Ncp),nu=3) { k = (nu + nushift)%6; #ifdef DEBUG_MEAS - LOG_D(PHY,"[UE %d] Frame %d subframe %d Doing ue_rrc_measurements rsrp/rssi (Nid_cell %d, nushift %d, eNB_offset %d, k %d, l %d)\n",ue->Mod_id,ue->proc.proc_rxtx[subframe&1].frame_rx,subframe,Nid_cell,nushift, + LOG_I(PHY,"[UE %d] Frame %d subframe %d Doing ue_rrc_measurements rsrp/rssi (Nid_cell %d, nushift %d, eNB_offset %d, k %d, l %d)\n",ue->Mod_id,ue->proc.proc_rxtx[subframe&1].frame_rx,subframe,Nid_cell,nushift, eNB_offset,k,l); #endif diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index 9554da33db..c27d156ad2 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -403,7 +403,7 @@ void pdcch_demapping(uint16_t *llr,uint16_t *wbar,LTE_DL_FRAME_PARMS *frame_parm for (i=0; i<4; i++) { wbar[mprime] = llr[tti_offset0+i]; #ifdef DEBUG_DCI_DECODING - LOG_D(PHY,"PDCCH demapping mprime %d.%d <= llr %d (symbol %d re %d) -> (%d,%d)\n",mprime/4,i,tti_offset0+i,symbol_offset,re_offset0,*(char*)&wbar[mprime],*(1+(char*)&wbar[mprime])); + LOG_I(PHY,"PDCCH demapping mprime %d.%d <= llr %d (symbol %d re %d) -> (%d,%d)\n",mprime/4,i,tti_offset0+i,symbol_offset,re_offset0,*(char*)&wbar[mprime],*(1+(char*)&wbar[mprime])); #endif mprime++; re_offset0++; @@ -419,7 +419,7 @@ void pdcch_demapping(uint16_t *llr,uint16_t *wbar,LTE_DL_FRAME_PARMS *frame_parm for (i=0; i<4; i++) { wbar[mprime] = llr[tti_offset+i]; #ifdef DEBUG_DCI_DECODING - LOG_D(PHY,"PDCCH demapping mprime %d.%d <= llr %d (symbol %d re %d) -> (%d,%d)\n",mprime/4,i,tti_offset+i,symbol_offset,re_offset+i,*(char*)&wbar[mprime],*(1+(char*)&wbar[mprime])); + LOG_I(PHY,"PDCCH demapping mprime %d.%d <= llr %d (symbol %d re %d) -> (%d,%d)\n",mprime/4,i,tti_offset+i,symbol_offset,re_offset+i,*(char*)&wbar[mprime],*(1+(char*)&wbar[mprime])); #endif mprime++; } @@ -2473,16 +2473,16 @@ void dci_decoding(uint8_t DCI_LENGTH, #ifdef DEBUG_DCI_DECODING for (i=0; i<16+DCI_LENGTH; i++) - LOG_D(PHY," DCI %d : (%d,%d,%d)\n",i,*(d_rx+96+(3*i)),*(d_rx+97+(3*i)),*(d_rx+98+(3*i))); + LOG_I(PHY," DCI %d : (%d,%d,%d)\n",i,*(d_rx+96+(3*i)),*(d_rx+97+(3*i)),*(d_rx+98+(3*i))); #endif memset(decoded_output,0,2+((16+DCI_LENGTH)>>3)); #ifdef DEBUG_DCI_DECODING - LOG_D(PHY, "Before Viterbi\n"); + printf("Before Viterbi\n"); for (i=0; i<16+DCI_LENGTH; i++) - LOG_D(PHY, "%d : (%d,%d,%d)\n",i,*(d_rx+96+(3*i)),*(d_rx+97+(3*i)),*(d_rx+98+(3*i))); + printf("%d : (%d,%d,%d)\n",i,*(d_rx+96+(3*i)),*(d_rx+97+(3*i)),*(d_rx+98+(3*i))); #endif //debug_printf("Doing DCI Viterbi \n"); diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c index 7df08a8382..663978e92c 100644 --- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c +++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c @@ -41,7 +41,7 @@ #include "common_lib.h" extern openair0_config_t openair0_cfg[]; -#define DEBUG_INITIAL_SYNCH +//#define DEBUG_INITIAL_SYNCH int pbch_detection(PHY_VARS_UE *ue, runmode_t mode) { diff --git a/openair1/PHY/LTE_TRANSPORT/pcfich.c b/openair1/PHY/LTE_TRANSPORT/pcfich.c index 1d73d020a0..8af540eea1 100644 --- a/openair1/PHY/LTE_TRANSPORT/pcfich.c +++ b/openair1/PHY/LTE_TRANSPORT/pcfich.c @@ -34,7 +34,7 @@ //uint16_t pcfich_reg[4]; //uint8_t pcfich_first_reg_idx = 0; -#define DEBUG_PCFICH +//#define DEBUG_PCFICH void generate_pcfich_reg_mapping(LTE_DL_FRAME_PARMS *frame_parms) { @@ -301,7 +301,7 @@ uint8_t rx_pcfich(LTE_DL_FRAME_PARMS *frame_parms, } #ifdef DEBUG_PCFICH - LOG_I(PHY, "metric %d : %d\n",i,metric); + msg("metric %d : %d\n",i,metric); #endif if (metric > old_metric) { @@ -311,7 +311,7 @@ uint8_t rx_pcfich(LTE_DL_FRAME_PARMS *frame_parms, } #ifdef DEBUG_PCFICH - LOG_I(PHY, "PCFICH detected for %d PDCCH symbols\n",num_pdcch_symbols); + msg("[PHY] PCFICH detected for %d PDCCH symbols\n",num_pdcch_symbols); #endif return(num_pdcch_symbols); } diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index cc3f5e6e10..91d5fefb66 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -3279,7 +3279,7 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin #ifdef DEBUG_PHY_PROC - LOG_I(PHY,"[%s %d] Frame %d subframe %d: Doing phy_procedures_UE_RX (-)\n", + LOG_D(PHY,"[%s %d] Frame %d subframe %d: Doing phy_procedures_UE_RX (%d)\n", (r_type == multicast_relay) ? "RN/UE" : "UE", ue->Mod_id,frame_rx, subframe_rx); #endif From 4a0e4b5e146bd882de0f1938734fb5ba91f8af57 Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Fri, 2 Dec 2016 18:35:19 +0800 Subject: [PATCH 379/413] fixing thread busy crash: add more VCD logs to debug timing issues --- openair1/PHY/LTE_TRANSPORT/rar_tools.c | 6 ++++ openair1/SCHED/phy_procedures_lte_ue.c | 17 +++++++++- openair2/UTIL/LOG/vcd_signal_dumper.c | 24 ++++++++++++++ openair2/UTIL/LOG/vcd_signal_dumper.h | 24 ++++++++++++++ targets/RT/USER/lte-ue.c | 43 +++++++++++++++++--------- 5 files changed, 98 insertions(+), 16 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/rar_tools.c b/openair1/PHY/LTE_TRANSPORT/rar_tools.c index f86c009543..60fa52df16 100644 --- a/openair1/PHY/LTE_TRANSPORT/rar_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/rar_tools.c @@ -34,6 +34,7 @@ #include "SCHED/extern.h" #include "LAYER2/MAC/defs.h" #include "SCHED/defs.h" +#include "UTIL/LOG/vcd_signal_dumper.h" #include "assertions.h" @@ -171,6 +172,8 @@ int generate_ue_ulsch_params_from_rar(PHY_VARS_UE *ue, unsigned char eNB_id ) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_RAR,VCD_FUNCTION_IN); + // RA_HEADER_RAPID *rarh = (RA_HEADER_RAPID *)rar_pdu; uint8_t transmission_mode = ue->transmission_mode[eNB_id]; unsigned char *rar_pdu = ue->dlsch_ra[eNB_id]->harq_processes[0]->b; @@ -315,6 +318,9 @@ int generate_ue_ulsch_params_from_rar(PHY_VARS_UE *ue, msg("ulsch ra (UE): TPC %d\n",ulsch->harq_processes[harq_pid]->TPC); msg("ulsch ra (UE): O %d\n",ulsch->O); msg("ulsch ra (UE): ORI %d\n",ulsch->O_RI); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_RAR,VCD_FUNCTION_OUT); + //#endif return(0); } diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 5dc629b90b..a4ef075726 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -942,6 +942,8 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc) { int dummy_tx_buffer[3840*4] __attribute__((aligned(16))); #endif + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_COMMON,VCD_FUNCTION_IN); + start_meas(&ue->ofdm_mod_stats); nsymb = (frame_parms->Ncp == 0) ? 14 : 12; @@ -1043,7 +1045,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc) { stop_meas(&ue->ofdm_mod_stats); - + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_COMMON,VCD_FUNCTION_OUT); } @@ -1054,6 +1056,8 @@ void ue_prach_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin int prach_power; PRACH_RESOURCES_t prach_resources_local; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_FUNCTION_IN); + ue->generate_prach=0; if (ue->mac_enabled==0){ @@ -1170,6 +1174,8 @@ void ue_prach_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin if (ue->prach_cnt==3) ue->generate_prach=0; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_FUNCTION_OUT); } void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t abstraction_flag) { @@ -1189,6 +1195,8 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB uint8_t ulsch_input_buffer[5477] __attribute__ ((aligned(32))); uint8_t access_mode; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_UESPEC,VCD_FUNCTION_IN); + // get harq_pid from subframe relationship harq_pid = subframe2harq_pid(&ue->frame_parms, frame_tx, @@ -1455,6 +1463,9 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB ue->sr[subframe_tx]=0; } } // subframe_scheduling_flag==1 + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_UESPEC,VCD_FUNCTION_OUT); + } void ue_srs_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t abstraction_flag) @@ -1552,6 +1563,8 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin int tx_amp; int8_t Po_PUCCH; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PUCCH,VCD_FUNCTION_IN); + SOUNDINGRS_UL_CONFIG_DEDICATED *pSoundingrs_ul_config_dedicated=&ue->soundingrs_ul_config_dedicated[eNB_id]; // 36.213 8.2 @@ -1742,6 +1755,8 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin } } // SR_Payload==1 + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PUCCH,VCD_FUNCTION_OUT); + // PUCCH 2x if (ue->generate_ul_signal[eNB_id] == 0) { // we have not generated ACK/NAK/SR in this subframe diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.c b/openair2/UTIL/LOG/vcd_signal_dumper.c index d367ec7766..b65839cd90 100644 --- a/openair2/UTIL/LOG/vcd_signal_dumper.c +++ b/openair2/UTIL/LOG/vcd_signal_dumper.c @@ -174,6 +174,10 @@ const char* eurecomVariablesNames[] = { "ue0_SFN5", "ue0_SFN6", "ue0_SFN7", +#if 1 // 2016-11-29 wilson debug thread busy crash + "ue0_trx_read_ns", + "ue0_trx_write_ns", +#endif }; const char* eurecomFunctionsNames[] = { @@ -188,6 +192,19 @@ const char* eurecomFunctionsNames[] = { "ue_thread_synch", "ue_thread_rxtx0", "ue_thread_rxtx1", +#if 1 // 2016-11-29 wilson debug thread busy crash + "trx_read_sf9", + "trx_write_sf9", + "ue_signal_cond_rxtx", + "ue_wait_cond_rxtx0", + "ue_wait_cond_rxtx1", + "ue_lock_mutex_rxtx_for_cond_wait0", + "ue_lock_mutex_rxtx_for_cond_wait1", + "ue_lock_mutex_rxtx_for_cnt_decrement0", + "ue_lock_mutex_rxtx_for_cnt_decrement1", + "ue_lock_mutex_rxtx_for_cnt_increment0", + "ue_lock_mutex_rxtx_for_cnt_increment1", +#endif /* RRH signals */ "eNB_tx", @@ -218,6 +235,13 @@ const char* eurecomFunctionsNames[] = { "phy_eNB_slot_fep", "phy_procedures_ue_tx", "phy_procedures_ue_rx", +#if 1 // 2016-12-01 wilson debug long TX runtime in special subframe + "phy_procedures_ue_tx_ulsch_uespec", + "phy_procedures_ue_tx_pucch", + "phy_procedures_ue_tx_ulsch_common", + "phy_procedures_ue_tx_prach", + "phy_procedures_ue_tx_ulsch_rar", +#endif "phy_procedures_eNB_lte", "phy_procedures_UE_lte", "pdsch_thread", diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.h b/openair2/UTIL/LOG/vcd_signal_dumper.h index 1e03e95002..f90775d824 100644 --- a/openair2/UTIL/LOG/vcd_signal_dumper.h +++ b/openair2/UTIL/LOG/vcd_signal_dumper.h @@ -146,6 +146,10 @@ typedef enum { VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN5, VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN6, VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN7, +#if 1 // 2016-11-29 wilson debug thread busy crash + VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_READ_NS, + VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_WRITE_NS, +#endif VCD_SIGNAL_DUMPER_VARIABLES_LAST, VCD_SIGNAL_DUMPER_VARIABLES_END = VCD_SIGNAL_DUMPER_VARIABLES_LAST, } vcd_signal_dump_variables; @@ -162,6 +166,19 @@ typedef enum { VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_SYNCH, VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RXTX0, VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RXTX1, +#if 1 // 2016-11-29 wilson debug thread busy crash + VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_SF9, + VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_SF9, + VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SIGNAL_COND_RXTX, + VCD_SIGNAL_DUMPER_FUNCTIONS_UE_WAIT_COND_RXTX0, + VCD_SIGNAL_DUMPER_FUNCTIONS_UE_WAIT_COND_RXTX1, + VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_COND_WAIT0, + VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_COND_WAIT1, + VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_DECREMENT0, + VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_DECREMENT1, + VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT0, + VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT1, +#endif /* RRH signals */ VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX, @@ -192,6 +209,13 @@ typedef enum { VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_SLOT_FEP, VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX, VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, +#if 1 // 2016-12-01 wilson debug long TX runtime in special subframe + VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_UESPEC, + VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PUCCH, + VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_COMMON, + VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, + VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_RAR, +#endif VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_LTE, VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_LTE, VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_THREAD, diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 8e11a82638..395d767ad8 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -716,6 +716,7 @@ static void *UE_thread_rxn_txnp4(void *arg) printf("Starting UE RXN_TXNP4 thread\n"); while (!oai_exit) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_COND_WAIT0+(proc->subframe_rx&1), 1 ); if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) { LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RXTX\n" ); exit_fun("nothing to add"); @@ -723,15 +724,18 @@ static void *UE_thread_rxn_txnp4(void *arg) } while (proc->instance_cnt_rxtx < 0) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_WAIT_COND_RXTX0+(proc->subframe_rx&1), 1 ); // most of the time, the thread is waiting here pthread_cond_wait( &proc->cond_rxtx, &proc->mutex_rxtx ); } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_WAIT_COND_RXTX0+(proc->subframe_rx&1), 0 ); if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) { LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RXn_TXnp4\n" ); exit_fun("nothing to add"); return &UE_thread_rxtx_retval; } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_COND_WAIT0+(proc->subframe_rx&1), 0 ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RXTX0+(proc->subframe_rx&1), 1 ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_UE+(proc->subframe_rx&1), proc->subframe_rx ); @@ -782,6 +786,7 @@ static void *UE_thread_rxn_txnp4(void *arg) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RXTX0+(proc->subframe_rx&1), 0 ); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_DECREMENT0+(proc->subframe_rx&1), 1 ); if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) { LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RXTX\n" ); exit_fun("noting to add"); @@ -796,6 +801,7 @@ static void *UE_thread_rxn_txnp4(void *arg) exit_fun("noting to add"); return &UE_thread_rxtx_retval; } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_DECREMENT0+(proc->subframe_rx&1), 0 ); } // thread finished @@ -1013,20 +1019,22 @@ void *UE_thread(void *arg) { for (i=0; iframe_parms.nb_antennas_rx; i++) rxp[i] = (void*)&rxdata[i][UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0+(sf*UE->frame_parms.samples_per_tti)]; // grab signal for subframe - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 ); if (UE->mode != loop_through_memory) { if (sf<9) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 ); rxs = UE->rfdevice.trx_read_func(&UE->rfdevice, ×tamp, rxp, UE->frame_parms.samples_per_tti, UE->frame_parms.nb_antennas_rx); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 ); - // prepare tx buffer pointers + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_READ_NS, rxs ); + // prepare tx buffer pointers for (i=0; iframe_parms.nb_antennas_tx; i++) txp[i] = (void*)&UE->common_vars.txdata[i][((sf+2)%10)*UE->frame_parms.samples_per_tti]; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 ); txs = UE->rfdevice.trx_write_func(&UE->rfdevice, timestamp+ (2*UE->frame_parms.samples_per_tti) - @@ -1036,27 +1044,25 @@ void *UE_thread(void *arg) { UE->frame_parms.samples_per_tti, UE->frame_parms.nb_antennas_tx, 1); - if (txs != UE->frame_parms.samples_per_tti) { - LOG_E(PHY,"TX : Timeout (sent %d/%d)\n",txs, UE->frame_parms.samples_per_tti); - exit_fun( "problem transmitting samples" ); - } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); - + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_WRITE_NS, rxs ); } else { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_SF9, 1 ); rxs = UE->rfdevice.trx_read_func(&UE->rfdevice, ×tamp, rxp, UE->frame_parms.samples_per_tti-UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0, UE->frame_parms.nb_antennas_rx); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 ); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_SF9, 0 ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_READ_NS, rxs ); + // prepare tx buffer pointers - for (i=0; iframe_parms.nb_antennas_tx; i++) txp[i] = (void*)&UE->common_vars.txdata[i][((sf+2)%10)*UE->frame_parms.samples_per_tti]; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_SF9, 1 ); txs = UE->rfdevice.trx_write_func(&UE->rfdevice, timestamp+ (2*UE->frame_parms.samples_per_tti) - @@ -1066,25 +1072,29 @@ void *UE_thread(void *arg) { UE->frame_parms.samples_per_tti - rx_off_diff, UE->frame_parms.nb_antennas_tx, 1); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_SF9, 0 ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_WRITE_NS, rxs ); if (txs != UE->frame_parms.samples_per_tti - rx_off_diff) { LOG_E(PHY,"TX : Timeout (sent %d/%d)\n",txs, UE->frame_parms.samples_per_tti-rx_off_diff); exit_fun( "problem transmitting samples" ); } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_SF9, 1 ); // read in first symbol of next frame and adjust for timing drift rxs = UE->rfdevice.trx_read_func(&UE->rfdevice, ×tamp1, (void**)rxdata, - UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0 - rx_off_diff, + UE->frame_parms.ofdm_symbol_size + UE->frame_parms.nb_prefix_samples0 - rx_off_diff, UE->frame_parms.nb_antennas_rx); - rx_off_diff = 0; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_SF9, 0 ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_READ_NS, rxs ); + rx_off_diff = 0; } } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); // operate on thread sf mod 2 UE_rxtx_proc_t *proc = &UE->proc.proc_rxtx[sf&1]; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT0+(proc->subframe_rx&1), 1 ); // lock mutex if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) { LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RX\n" ); @@ -1114,14 +1124,17 @@ void *UE_thread(void *arg) { exit_fun("nothing to add"); return &UE_thread_retval; } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT0+(proc->subframe_rx&1), 0 ); if (instance_cnt_rxtx == 0) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SIGNAL_COND_RXTX, 1 ); if (pthread_cond_signal(&proc->cond_rxtx) != 0) { LOG_E( PHY, "[SCHED][UE] ERROR pthread_cond_signal for UE RX thread\n" ); exit_fun("nothing to add"); return &UE_thread_retval; } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SIGNAL_COND_RXTX, 0 ); } else { LOG_E( PHY, "[SCHED][UE] UE RX thread busy (IC %d)!!\n", instance_cnt_rxtx); if (instance_cnt_rxtx > 2) { From 8daa6897e9a0d4fced1a62d3556ccec4932b1982 Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Fri, 2 Dec 2016 18:37:34 +0800 Subject: [PATCH 380/413] fixing thread busy crash: add more error checking to catch timing issues --- openair1/SCHED/phy_procedures_lte_ue.c | 4 +-- targets/RT/USER/lte-ue.c | 37 ++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index a4ef075726..98168926c2 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -1225,8 +1225,8 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB } else { if (harq_pid==255) { - LOG_E(PHY,"[UE%d] Frame %d ulsch_decoding.c: FATAL ERROR: illegal harq_pid, returning\n", - Mod_id,frame_tx); + LOG_E(PHY,"[UE%d] Frame %d subframe %d ulsch_decoding.c: FATAL ERROR: illegal harq_pid, returning\n", + Mod_id,frame_tx, subframe_tx); mac_xface->macphy_exit("Error in ulsch_decoding"); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX, VCD_FUNCTION_OUT); stop_meas(&ue->phy_proc_tx); diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 395d767ad8..14f841df4b 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -924,10 +924,11 @@ void *UE_thread(void *arg) { rxp, UE->frame_parms.samples_per_tti*10, UE->frame_parms.nb_antennas_rx); - + if (rxs!=UE->frame_parms.samples_per_tti*10) { - exit_fun("problem in rx"); + LOG_E(PHY, "problem in rx 1! want #samples=%d but got only %d!\n", UE->frame_parms.samples_per_tti*10, rxs); + exit_fun("problem in rx 1"); return &UE_thread_retval; } } @@ -960,7 +961,8 @@ void *UE_thread(void *arg) { UE->frame_parms.nb_antennas_rx); if (rxs!=UE->frame_parms.samples_per_tti){ - exit_fun("problem in rx"); + LOG_E(PHY, "problem in rx 2! want #samples=%d but got only %d!\n", UE->frame_parms.samples_per_tti, rxs); + exit_fun("problem in rx 2"); return &UE_thread_retval; } @@ -982,7 +984,8 @@ void *UE_thread(void *arg) { UE->rx_offset, UE->frame_parms.nb_antennas_rx); if (rxs != UE->rx_offset) { - exit_fun("problem in rx"); + LOG_E(PHY, "problem in rx 3! want #samples=%d but got only %d!\n", UE->rx_offset, rxs); + exit_fun("problem in rx 3!"); return &UE_thread_retval; } } @@ -996,6 +999,11 @@ void *UE_thread(void *arg) { (void**)rxdata, UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0, UE->frame_parms.nb_antennas_rx); + if (rxs != (UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0)) { + LOG_E(PHY, "problem in rx 4! want #samples=%d but got only %d!\n", UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0, rxs); + exit_fun("problem in rx 4!"); + return &UE_thread_retval; + } slot_fep(UE, 0, 0, @@ -1029,6 +1037,11 @@ void *UE_thread(void *arg) { UE->frame_parms.nb_antennas_rx); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_READ_NS, rxs ); + if (rxs != UE->frame_parms.samples_per_tti) { + LOG_E(PHY, "problem in rx 5! want #samples=%d but got only %d!\n", UE->frame_parms.samples_per_tti, rxs); + exit_fun("problem in rx 5!"); + return &UE_thread_retval; + } // prepare tx buffer pointers for (i=0; iframe_parms.nb_antennas_tx; i++) @@ -1046,6 +1059,10 @@ void *UE_thread(void *arg) { 1); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_WRITE_NS, rxs ); + if (txs != UE->frame_parms.samples_per_tti) { + LOG_E(PHY,"TX : Timeout (sent %d/%d)\n",txs, UE->frame_parms.samples_per_tti); + exit_fun( "problem transmitting samples" ); + } } else { @@ -1057,6 +1074,11 @@ void *UE_thread(void *arg) { UE->frame_parms.nb_antennas_rx); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_SF9, 0 ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_READ_NS, rxs ); + if (rxs != (UE->frame_parms.samples_per_tti-UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0)) { + LOG_E(PHY, "problem in rx 6! want #samples=%d but got only %d!\n", UE->frame_parms.samples_per_tti-UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0, rxs); + exit_fun("problem in rx 6!"); + return &UE_thread_retval; + } // prepare tx buffer pointers for (i=0; iframe_parms.nb_antennas_tx; i++) @@ -1088,7 +1110,12 @@ void *UE_thread(void *arg) { UE->frame_parms.nb_antennas_rx); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_SF9, 0 ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_READ_NS, rxs ); - rx_off_diff = 0; + if (rxs != (UE->frame_parms.ofdm_symbol_size + UE->frame_parms.nb_prefix_samples0 - rx_off_diff)) { + LOG_E(PHY, "problem in rx 7! want #samples=%d but got only %d! rx_off_diff=%d\n", UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0 - rx_off_diff, rxs, rx_off_diff); + exit_fun("problem in rx 7!"); + return &UE_thread_retval; + } + rx_off_diff = 0; } } // operate on thread sf mod 2 From 675e0b10cbc1e595b33982f3eb1ab59ff44d632c Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Fri, 2 Dec 2016 18:40:24 +0800 Subject: [PATCH 381/413] fixing thread busy crash: fixed incorrect processing of special-subframe TX as a normal TX --- targets/RT/USER/lte-ue.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 14f841df4b..b78bf36ed7 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -775,14 +775,21 @@ static void *UE_thread_rxn_txnp4(void *arg) } if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) || - (UE->frame_parms.frame_type == FDD) || - (subframe_select( &UE->frame_parms, proc->subframe_tx ) == SF_S)) { + (UE->frame_parms.frame_type == FDD) ) { if (UE->mode != loop_through_memory) { phy_procedures_UE_TX(UE,proc,0,0,UE->mode,no_relay); } } + if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_S) && + (UE->frame_parms.frame_type == TDD)) { + + if (UE->mode != loop_through_memory) { + phy_procedures_UE_S_TX(UE,0,0,no_relay); + } + } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RXTX0+(proc->subframe_rx&1), 0 ); From 086520f50ec75ce9aca49cc6bd324df6628453f9 Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Fri, 25 Nov 2016 18:58:21 +0800 Subject: [PATCH 382/413] clean up changes for change submission issue #42 --- targets/RT/USER/lte-ue.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index a35c0e59e3..3caaac7b7c 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -717,7 +717,6 @@ static void *UE_thread_rxn_txnp4(void *arg) while (sync_var<0) pthread_cond_wait(&sync_cond, &sync_mutex); -#if 1 // 2016-11-23 wilson add pthread name to the logging #define THREAD_NAME_LEN 16 char threadname[THREAD_NAME_LEN]; ret = pthread_getname_np(proc->pthread_rxtx, threadname, THREAD_NAME_LEN); @@ -726,7 +725,6 @@ static void *UE_thread_rxn_txnp4(void *arg) perror("pthread_getname_np : "); exit_fun("Error getting thread name"); } -#endif pthread_mutex_unlock(&sync_mutex); printf("unlocked sync_mutex, waiting (UE_thread_rxtx)\n"); From 6c6d20b622517552448d824649c373d305ff148b Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Tue, 6 Dec 2016 21:10:53 +0800 Subject: [PATCH 383/413] added logging to debug PRACH --- openair1/PHY/LTE_TRANSPORT/prach.c | 7 +++++++ openair1/SCHED/phy_procedures_lte_ue.c | 13 +++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index d9f5434cf5..33780a7def 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -629,6 +629,13 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 #if defined(EXMIMO) || defined(OAI_USRP) prach_start = (ue->rx_offset+subframe*ue->frame_parms.samples_per_tti-ue->hw_timing_advance-ue->N_TA_offset); +#ifdef PRACH_DEBUG + LOG_I(PHY,"[UE %d] prach_start %d, rx_offset %d, hw_timing_advance %d, N_TA_offset %d\n", ue->Mod_id, + prach_start, + ue->rx_offset, + ue->hw_timing_advance, + ue->N_TA_offset); +#endif if (prach_start<0) prach_start+=(ue->frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME); diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 5dc629b90b..f0811476eb 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -1142,14 +1142,15 @@ void ue_prach_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin } else { UE_transport_info[ue->Mod_id][ue->CC_id].cntl.prach_flag=1; UE_transport_info[ue->Mod_id][ue->CC_id].cntl.prach_id=ue->prach_resources[eNB_id]->ra_PreambleIndex; - if (ue->mac_enabled==1){ - mac_xface->Msg1_transmitted(ue->Mod_id, - ue->CC_id, - frame_tx, - eNB_id); - } } + if (ue->mac_enabled==1){ + mac_xface->Msg1_transmitted(ue->Mod_id, + ue->CC_id, + frame_tx, + eNB_id); + } + LOG_D(PHY,"[UE %d][RAPROC] Frame %d, subframe %d: Generating PRACH (eNB %d) preamble index %d for UL, TX power %d dBm (PL %d dB), l3msg \n", ue->Mod_id,frame_tx,subframe_tx,eNB_id, ue->prach_resources[eNB_id]->ra_PreambleIndex, From 53777043c338e7a1a9e107078d2f2be4698c54ad Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Tue, 6 Dec 2016 21:10:30 +0800 Subject: [PATCH 384/413] fixed PRACH TA default value in TDD mode see issue #43 --- targets/RT/USER/lte-softmodem.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 9f98aaada1..e28f70a8c9 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -1594,8 +1594,16 @@ int main( int argc, char **argv ) UE[CC_id]->rx_total_gain_dB = (int)rx_gain[CC_id][0] + rx_gain_off; UE[CC_id]->tx_power_max_dBm = tx_max_power[CC_id]; - UE[CC_id]->N_TA_offset = 0; - + if (UE[CC_id]->frame_parms.frame_type == TDD) { + if (UE[CC_id]->frame_parms.N_RB_DL == 100) + UE[CC_id]->N_TA_offset = 624; + else if (UE[CC_id]->frame_parms.N_RB_DL == 50) + UE[CC_id]->N_TA_offset = 624/2; + else if (UE[CC_id]->frame_parms.N_RB_DL == 25) + UE[CC_id]->N_TA_offset = 624/4; + } else { + UE[CC_id]->N_TA_offset = 0; + } } // printf("tx_max_power = %d -> amp %d\n",tx_max_power,get_tx_amp(tx_max_poHwer,tx_max_power)); From 488b84cb4632fc081a4426028542a057ed30352e Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Fri, 2 Dec 2016 18:41:50 +0800 Subject: [PATCH 385/413] fixing thread busy crash: disabled timing consuming NAS logs see issue #44 --- openair3/NAS/COMMON/IES/EsmMessageContainer.c | 2 +- openair3/NAS/COMMON/UTIL/TLVDecoder.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair3/NAS/COMMON/IES/EsmMessageContainer.c b/openair3/NAS/COMMON/IES/EsmMessageContainer.c index 1a7f88d299..a223f36820 100644 --- a/openair3/NAS/COMMON/IES/EsmMessageContainer.c +++ b/openair3/NAS/COMMON/IES/EsmMessageContainer.c @@ -28,7 +28,7 @@ #include "EsmMessageContainer.h" #include "nas_log.h" -#define NAS_DEBUG 1 +//#define NAS_DEBUG 1 int decode_esm_message_container(EsmMessageContainer *esmmessagecontainer, uint8_t iei, uint8_t *buffer, uint32_t len) { diff --git a/openair3/NAS/COMMON/UTIL/TLVDecoder.h b/openair3/NAS/COMMON/UTIL/TLVDecoder.h index 801ab77c8d..37834c5660 100644 --- a/openair3/NAS/COMMON/UTIL/TLVDecoder.h +++ b/openair3/NAS/COMMON/UTIL/TLVDecoder.h @@ -26,7 +26,7 @@ #include "nas_log.h" #ifndef NAS_DEBUG -# define NAS_DEBUG 1 +//# define NAS_DEBUG 1 #endif #define DECODE_U8(bUFFER, vALUE, sIZE) \ From 4041a661fc7f86eb65ab37d86498b9b5a3703d9d Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Thu, 27 Oct 2016 14:33:52 +0800 Subject: [PATCH 386/413] fixed incorrect wiresahrk SFN/SF for UL/DL data --- openair1/SCHED/phy_procedures_lte_ue.c | 14 +++++----- openair2/LAYER2/MAC/defs.h | 12 ++++++--- openair2/LAYER2/MAC/openair2_proc.c | 2 +- openair2/LAYER2/MAC/proto.h | 11 +++++--- openair2/LAYER2/MAC/ra_procedures.c | 4 +-- openair2/LAYER2/MAC/ue_procedures.c | 36 ++++++++++++++------------ openair2/PHY_INTERFACE/defs.h | 2 +- targets/RT/USER/lte-ue.c | 12 +++++---- 8 files changed, 55 insertions(+), 38 deletions(-) diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 5dc629b90b..9d1279c302 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -3684,12 +3684,14 @@ void phy_procedures_UE_lte(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,u if (ue->mac_enabled==1) { if (slot==0) { - ret = mac_xface->ue_scheduler(ue->Mod_id, - frame_tx, - subframe_rx, - subframe_select(&ue->frame_parms,subframe_tx), - eNB_id, - 0/*FIXME CC_id*/); + ret = mac_xface->ue_scheduler(ue->Mod_id, + frame_rx, + subframe_rx, + frame_tx, + subframe_tx, + subframe_select(&ue->frame_parms,subframe_tx), + eNB_id, + 0/*FIXME CC_id*/); if (ret == CONNECTION_LOST) { LOG_E(PHY,"[UE %d] Frame %d, subframe %d RRC Connection lost, returning to PRACH\n",ue->Mod_id, diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h index 2235c3e1c4..96855dd1cd 100644 --- a/openair2/LAYER2/MAC/defs.h +++ b/openair2/LAYER2/MAC/defs.h @@ -995,10 +995,14 @@ typedef struct { /*!\brief Top level UE MAC structure */ typedef struct { uint16_t Node_id; - /// frame counter - frame_t frame; - /// subframe counter - sub_frame_t subframe; + /// RX frame counter + frame_t rxFrame; + /// RX subframe counter + sub_frame_t rxSubframe; + /// TX frame counter + frame_t txFrame; + /// TX subframe counter + sub_frame_t txSubframe; /// C-RNTI of UE uint16_t crnti; /// C-RNTI of UE before HO diff --git a/openair2/LAYER2/MAC/openair2_proc.c b/openair2/LAYER2/MAC/openair2_proc.c index 950713de5a..4b63571277 100644 --- a/openair2/LAYER2/MAC/openair2_proc.c +++ b/openair2/LAYER2/MAC/openair2_proc.c @@ -82,7 +82,7 @@ int openair2_stats_read(char *buffer, char **my_buffer, off_t off, int length) // mod_id used for PDCP and RLC Mod_id = NB_eNB_INST + ue_id ; - len+=sprintf(&buffer[len],"UE TTI: %d\n",UE_mac_inst[ue_id].frame); + len+=sprintf(&buffer[len],"UE RX TTI: %d\n",UE_mac_inst[ue_id].rxFrame); for (enb_id= 0; enb_id ra_SupervisionInfo.mac_ContentionResolutionTimer)<<3)); UE_mac_inst[module_idP].RA_contention_resolution_cnt++; @@ -1727,10 +1731,10 @@ ue_scheduler( } } - if (update_bsr(module_idP,frameP, eNB_indexP, lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid])) { + if (update_bsr(module_idP,txFrameP, eNB_indexP, lcid, UE_mac_inst[module_idP].scheduling_info.LCGID[lcid])) { UE_mac_inst[module_idP].scheduling_info.SR_pending= 1; LOG_D(MAC,"[UE %d][SR] Frame %d subframe %d SR for PUSCH is pending for LCGID %d with BSR level %d (%d bytes in RLC)\n", - module_idP, frameP,subframeP,UE_mac_inst[module_idP].scheduling_info.LCGID[lcid], + module_idP, txFrameP,txSubframeP,UE_mac_inst[module_idP].scheduling_info.LCGID[lcid], UE_mac_inst[module_idP].scheduling_info.BSR[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); } diff --git a/openair2/PHY_INTERFACE/defs.h b/openair2/PHY_INTERFACE/defs.h index 0892b4d0b1..e29ccdcc5e 100644 --- a/openair2/PHY_INTERFACE/defs.h +++ b/openair2/PHY_INTERFACE/defs.h @@ -169,7 +169,7 @@ typedef struct { void (*dl_phy_sync_success) (module_id_t Mod_id,frame_t frameP, uint8_t CH_index,uint8_t first_sync); /// Only calls the PDCP for now - UE_L2_STATE_t (*ue_scheduler)(module_id_t Mod_id, frame_t frameP,sub_frame_t subframe, lte_subframe_t direction, uint8_t eNB_id, int CC_id); + UE_L2_STATE_t (*ue_scheduler)(module_id_t Mod_id, frame_t rxFrameP,sub_frame_t rxSubframe, frame_t txFrameP,sub_frame_t txSubframe, lte_subframe_t direction, uint8_t eNB_id, int CC_id); /// PHY-Config-Dedicated UE void (*phy_config_dedicated_ue)(module_id_t Mod_id,int CC_id,uint8_t CH_index, diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c index 8e11a82638..932e875752 100644 --- a/targets/RT/USER/lte-ue.c +++ b/targets/RT/USER/lte-ue.c @@ -749,11 +749,13 @@ static void *UE_thread_rxn_txnp4(void *arg) if (UE->mac_enabled==1) { ret = mac_xface->ue_scheduler(UE->Mod_id, - proc->frame_tx, - proc->subframe_rx, - subframe_select(&UE->frame_parms,proc->subframe_tx), - 0, - 0/*FIXME CC_id*/); + proc->frame_rx, + proc->subframe_rx, + proc->frame_tx, + proc->subframe_tx, + subframe_select(&UE->frame_parms,proc->subframe_tx), + 0, + 0/*FIXME CC_id*/); if (ret == CONNECTION_LOST) { LOG_E( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u RRC Connection lost, returning to PRACH\n", From 55e50b20523bbe6ec94881c2b6836b911f132353 Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Fri, 2 Dec 2016 18:45:34 +0800 Subject: [PATCH 387/413] enhanced wireshark logging. also logs BCH, PRACH and RAR. Tested with wireshark 2.2.2 on linux and windows see issue #45 --- openair1/SCHED/phy_procedures_lte_ue.c | 13 +++++++++++++ openair2/LAYER2/MAC/proto.h | 4 ++++ openair2/LAYER2/MAC/ra_procedures.c | 2 +- openair2/LAYER2/MAC/rar_tools.c | 7 +++++++ openair2/PHY_INTERFACE/defs.h | 2 +- openair2/UTIL/OPT/probe.c | 16 +++++++++++----- 6 files changed, 37 insertions(+), 7 deletions(-) diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 9d1279c302..db2c2788e5 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -56,6 +56,7 @@ fifo_dump_emos_UE emos_dump_UE; #endif #include "UTIL/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" #if defined(ENABLE_ITTI) # include "intertask_interface.h" @@ -2302,6 +2303,17 @@ void ue_pbch_procedures(uint8_t eNB_id,PHY_VARS_UE *ue,UE_rxtx_proc_t *proc, uin if ((pbch_tx_ant>0) && (pbch_tx_ant<=4)) { + if (opt_enabled) { + static uint8_t dummy[3]; + dummy[0] = ue->pbch_vars[eNB_id]->decoded_output[2]; + dummy[1] = ue->pbch_vars[eNB_id]->decoded_output[1]; + dummy[2] = ue->pbch_vars[eNB_id]->decoded_output[0]; + trace_pdu(1, dummy, 3, ue->Mod_id, 0, 0, + frame_rx, subframe_rx, 0, 0); + LOG_D(OPT,"[UE %d][PBCH] Frame %d trace pdu for PBCH\n", + ue->Mod_id, subframe_rx); + } + if (pbch_tx_ant>2) { LOG_W(PHY,"[openair][SCHED][SYNCH] PBCH decoding: pbch_tx_ant>2 not supported\n"); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PBCH_PROCEDURES, VCD_FUNCTION_OUT); @@ -2980,6 +2992,7 @@ void process_rar(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, int eNB_id, runmode_t mo timing_advance = mac_xface->ue_process_rar(ue->Mod_id, ue->CC_id, frame_rx, + ue->prach_resources[eNB_id]->ra_RNTI, dlsch0->harq_processes[0]->b, &ue->pdcch_vars[eNB_id]->crnti, ue->prach_resources[eNB_id]->ra_PreambleIndex); diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index 08f29f8f47..f6f59c1ed5 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -426,6 +426,9 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP,u /* \brief Function called by PHY to process the received RAR. It checks that the preamble matches what was sent by the eNB and provides the timing advance and t-CRNTI. @param Mod_id Index of UE instance +@param CC_id Index to a component carrier +@param frame Frame index +@param ra_rnti RA_RNTI value @param dlsch_buffer Pointer to dlsch_buffer containing RAR PDU @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 @@ -437,6 +440,7 @@ ue_process_rar( const module_id_t module_idP, const int CC_id, const frame_t frameP, + const rnti_t ra_rnti, uint8_t * const dlsch_buffer, rnti_t * const t_crnti, const uint8_t preamble_index diff --git a/openair2/LAYER2/MAC/ra_procedures.c b/openair2/LAYER2/MAC/ra_procedures.c index 7d562bb353..c62fa1a8a7 100644 --- a/openair2/LAYER2/MAC/ra_procedures.c +++ b/openair2/LAYER2/MAC/ra_procedures.c @@ -271,7 +271,7 @@ void Msg1_tx(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id UE_mac_inst[module_idP].RA_attempt_number++; if (opt_enabled) { - trace_pdu(0, NULL, 0, module_idP, 2, UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex, + trace_pdu(0, NULL, 0, module_idP, 0 , UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex, UE_mac_inst[module_idP].txFrame, UE_mac_inst[module_idP].txSubframe, 0, UE_mac_inst[module_idP].RA_attempt_number); LOG_D(OPT,"[UE %d][RAPROC] TX MSG1 Frame %d trace pdu for rnti %x with size %d\n", module_idP, frameP, 1, UE_mac_inst[module_idP].RA_Msg3_size); diff --git a/openair2/LAYER2/MAC/rar_tools.c b/openair2/LAYER2/MAC/rar_tools.c index c7bc9120c3..b453b5cca8 100644 --- a/openair2/LAYER2/MAC/rar_tools.c +++ b/openair2/LAYER2/MAC/rar_tools.c @@ -133,6 +133,7 @@ ue_process_rar( const module_id_t module_idP, const int CC_id, const frame_t frameP, + const rnti_t ra_rnti, uint8_t* const dlsch_buffer, rnti_t* const t_crnti, const uint8_t preamble_index @@ -168,6 +169,12 @@ ue_process_rar( LOG_D(MAC,"[UE %d][RAPROC] rar->t_crnti %x\n",module_idP,(uint16_t)rar[5]+(rar[4]<<8)); #endif + 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, + UE_mac_inst[module_idP].rxFrame, UE_mac_inst[module_idP].rxSubframe, 0, 0); + } if (preamble_index == rarh->RAPID) { *t_crnti = (uint16_t)rar[5]+(rar[4]<<8);//rar->t_crnti; diff --git a/openair2/PHY_INTERFACE/defs.h b/openair2/PHY_INTERFACE/defs.h index e29ccdcc5e..b4a04e0b16 100644 --- a/openair2/PHY_INTERFACE/defs.h +++ b/openair2/PHY_INTERFACE/defs.h @@ -160,7 +160,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,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); /// 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/UTIL/OPT/probe.c b/openair2/UTIL/OPT/probe.c index a3836f5777..1c6b8e814b 100644 --- a/openair2/UTIL/OPT/probe.c +++ b/openair2/UTIL/OPT/probe.c @@ -304,19 +304,25 @@ static void SendFrame(guint8 radioType, guint8 direction, guint8 rntiType, frameBuffer[frameOffset++] = retx; } -#ifdef WIRESHARK_DEV +//#ifdef WIRESHARK_DEV /* Relating to out-of-band events */ /* N.B. dissector will only look to these fields if length is 0... */ if (pdu_buffer_size==0) { switch (oob_event) { case ltemac_send_preamble : - LOG_D(OPT,"oob event %d %d\n",ltemac_send_preamble ); + LOG_D(OPT,"oob ltemac_send_preamble event %02x." + //"%02x." + "%02x.%02x\n", + MAC_LTE_OOB_EVENT_TAG, + //ltemac_send_preamble, + rnti, + oob_event_value); //frameBuffer[frameOffset++]=0; //frameBuffer[frameOffset++]=0; //frameBuffer[frameOffset++]=0; frameBuffer[frameOffset++] = MAC_LTE_OOB_EVENT_TAG; - frameBuffer[frameOffset++]=ltemac_send_preamble; + //frameBuffer[frameOffset++]=ltemac_send_preamble; frameBuffer[frameOffset++]=rnti; // is the preamble frameBuffer[frameOffset++]=oob_event_value; break; @@ -329,12 +335,12 @@ static void SendFrame(guint8 radioType, guint8 direction, guint8 rntiType, case ltemac_sr_failure: default: - LOG_D(OPT,"not implemeneted yet\n"); + LOG_W(OPT,"not implemeneted yet\n"); break; } } -#endif +//#endif /***************************************/ /* Now write the MAC PDU */ frameBuffer[frameOffset++] = MAC_LTE_PAYLOAD_TAG; From 05a261ae6699903690b946e52037c6cd36077310 Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Wed, 7 Dec 2016 14:35:50 +0800 Subject: [PATCH 388/413] further clean up changes for change submission --- openair1/SCHED/phy_procedures_lte_ue.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 91d5fefb66..e6f27cca15 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -3299,7 +3299,6 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin l2 = (ue->frame_parms.symbols_per_tti/2)-1; } -#if 1 // 2016-11-24 wilson fixed missing slot_fep on 1st ofdm symbol of the first DL subframe after UL int prev_subframe_rx = (subframe_rx - 1)<0? 9: (subframe_rx - 1); if (subframe_select(&ue->frame_parms,prev_subframe_rx) != SF_DL) { //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -3313,9 +3312,6 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin l=1; } for (; l<=l2; l++) { -#else - for (l=1; l<=l2; l++) { -#endif if (abstraction_flag == 0) { start_meas(&ue->ofdm_demod_stats); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP, VCD_FUNCTION_IN); @@ -3437,11 +3433,9 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin } // for l=1..l2 -#if 1 // 2016-11-24 wilson fixed missing slot_fep on 1st ofdm symbol of the first DL subframe after UL // do first symbol of next downlink subframe for channel estimation int next_subframe_rx = (1+subframe_rx)%10; if (subframe_select(&ue->frame_parms,next_subframe_rx) != SF_UL) -#endif { slot_fep(ue, 0, From e6671827bb78a59620bdaaaa73b86e27005905f7 Mon Sep 17 00:00:00 2001 From: "Wilson W.K. Thong" Date: Wed, 7 Dec 2016 14:42:26 +0800 Subject: [PATCH 389/413] clean up changes for submission --- openair2/UTIL/LOG/vcd_signal_dumper.c | 6 ------ openair2/UTIL/LOG/vcd_signal_dumper.h | 6 ------ 2 files changed, 12 deletions(-) diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.c b/openair2/UTIL/LOG/vcd_signal_dumper.c index b65839cd90..86a7fbea3d 100644 --- a/openair2/UTIL/LOG/vcd_signal_dumper.c +++ b/openair2/UTIL/LOG/vcd_signal_dumper.c @@ -174,10 +174,8 @@ const char* eurecomVariablesNames[] = { "ue0_SFN5", "ue0_SFN6", "ue0_SFN7", -#if 1 // 2016-11-29 wilson debug thread busy crash "ue0_trx_read_ns", "ue0_trx_write_ns", -#endif }; const char* eurecomFunctionsNames[] = { @@ -192,7 +190,6 @@ const char* eurecomFunctionsNames[] = { "ue_thread_synch", "ue_thread_rxtx0", "ue_thread_rxtx1", -#if 1 // 2016-11-29 wilson debug thread busy crash "trx_read_sf9", "trx_write_sf9", "ue_signal_cond_rxtx", @@ -204,7 +201,6 @@ const char* eurecomFunctionsNames[] = { "ue_lock_mutex_rxtx_for_cnt_decrement1", "ue_lock_mutex_rxtx_for_cnt_increment0", "ue_lock_mutex_rxtx_for_cnt_increment1", -#endif /* RRH signals */ "eNB_tx", @@ -235,13 +231,11 @@ const char* eurecomFunctionsNames[] = { "phy_eNB_slot_fep", "phy_procedures_ue_tx", "phy_procedures_ue_rx", -#if 1 // 2016-12-01 wilson debug long TX runtime in special subframe "phy_procedures_ue_tx_ulsch_uespec", "phy_procedures_ue_tx_pucch", "phy_procedures_ue_tx_ulsch_common", "phy_procedures_ue_tx_prach", "phy_procedures_ue_tx_ulsch_rar", -#endif "phy_procedures_eNB_lte", "phy_procedures_UE_lte", "pdsch_thread", diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.h b/openair2/UTIL/LOG/vcd_signal_dumper.h index f90775d824..19f5e8aab1 100644 --- a/openair2/UTIL/LOG/vcd_signal_dumper.h +++ b/openair2/UTIL/LOG/vcd_signal_dumper.h @@ -146,10 +146,8 @@ typedef enum { VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN5, VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN6, VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN7, -#if 1 // 2016-11-29 wilson debug thread busy crash VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_READ_NS, VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_WRITE_NS, -#endif VCD_SIGNAL_DUMPER_VARIABLES_LAST, VCD_SIGNAL_DUMPER_VARIABLES_END = VCD_SIGNAL_DUMPER_VARIABLES_LAST, } vcd_signal_dump_variables; @@ -166,7 +164,6 @@ typedef enum { VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_SYNCH, VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RXTX0, VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RXTX1, -#if 1 // 2016-11-29 wilson debug thread busy crash VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_SF9, VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_SF9, VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SIGNAL_COND_RXTX, @@ -178,7 +175,6 @@ typedef enum { VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_DECREMENT1, VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT0, VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT1, -#endif /* RRH signals */ VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX, @@ -209,13 +205,11 @@ typedef enum { VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_SLOT_FEP, VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX, VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, -#if 1 // 2016-12-01 wilson debug long TX runtime in special subframe VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_UESPEC, VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PUCCH, VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_COMMON, VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_RAR, -#endif VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_LTE, VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_LTE, VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_THREAD, From bd30471076e9624c9c3041fb138fba87e9f8248e Mon Sep 17 00:00:00 2001 From: gabrielC Date: Thu, 8 Dec 2016 11:07:38 +0100 Subject: [PATCH 390/413] [OAI-UE] merge com4Innov branch to integration branch --- cmake_targets/CMakeLists.txt | 4 +- openair1/PHY/defs.h | 2 +- openair2/COMMON/commonDef.h | 2 +- openair2/LAYER2/MAC/ue_procedures.c | 2 +- openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 2 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c | 18 +++++- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h | 2 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c | 8 +-- openair2/LAYER2/RLC/rlc_mac.c | 2 +- openair2/NETWORK_DRIVER/UE_IP/common.c | 5 +- openair3/NAS/COMMON/EMM/MSG/AttachAccept.c | 3 +- .../COMMON/EMM/MSG/AuthenticationRequest.c | 2 +- .../NAS/COMMON/EMM/MSG/SecurityModeCommand.c | 2 + .../NAS/COMMON/EMM/MSG/SecurityModeComplete.c | 5 +- openair3/NAS/COMMON/IES/EmergencyNumberList.c | 54 ++++++++++++++---- openair3/NAS/COMMON/IES/EmergencyNumberList.h | 10 +++- openair3/NAS/COMMON/IES/MobileIdentity.c | 15 +++-- openair3/NAS/COMMON/IES/MobileIdentity.h | 57 ++++++++++++++++++- openair3/NAS/UE/EMM/SAP/emm_asDef.h | 1 + openair3/NAS/UE/EMM/SAP/emm_recv.c | 4 +- openair3/NAS/UE/EMM/SAP/emm_send.c | 29 ++++++++++ openair3/NAS/UE/EMM/SecurityModeControl.c | 3 +- openair3/NAS/UE/EMM/emm_proc.h | 2 +- targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c | 4 +- 24 files changed, 194 insertions(+), 44 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 07d92a1b05..891001ecbc 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -644,7 +644,7 @@ add_boolean_option(ENABLE_USE_CPU_EXECUTION_TIME True "Add data in vcd traces: d add_boolean_option(ENABLE_VCD True "always true now, time measurements of proc calls and var displays") add_boolean_option(ENABLE_VCD_FIFO True "time measurements of proc calls and var displays sent to FIFO (one more thread)") add_boolean_option(HARD_RT False "???") -add_boolean_option(LINUX False "used in weird memcpy() in pdcp.c ???") +add_boolean_option(LINUX True "used in weird memcpy() in pdcp.c ???") add_boolean_option(LINUX_LIST False "used only in lists.c: either use OAI implementation of lists or Linux one (should be True, but it is False") add_boolean_option(LOG_NO_THREAD True "Disable thread for log, seems always set to true") add_boolean_option(OPENAIR_LTE True "Seems legacy: keep it to true") @@ -727,7 +727,7 @@ add_boolean_option(TRACE_RLC_UM_TX_STATUS False "TRACE for RLC UM, TO BE CHANGE ########################## # PDCP LAYER OPTIONS ########################## -add_boolean_option(PDCP_USE_NETLINK False "For eNB, PDCP communicate with a NETLINK socket if connected to network driver, else could use a RT-FIFO") +add_boolean_option(PDCP_USE_NETLINK True "For eNB, PDCP communicate with a NETLINK socket if connected to network driver, else could use a RT-FIFO") add_boolean_option(PDCP_USE_NETLINK_QUEUES False "When PDCP_USE_NETLINK is true, incoming IP packets are stored in queues") add_boolean_option(LINK_ENB_PDCP_TO_IP_DRIVER False "For eNB, PDCP communicate with a IP driver") add_boolean_option(LINK_ENB_PDCP_TO_GTPV1U True "For eNB, PDCP communicate with GTP-U protocol (eNB<->S-GW)") diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 375efa5fea..0e69265d20 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -656,7 +656,7 @@ typedef struct { /// \brief Total gains with bypassed RF gain stage (ExpressMIMO2/Lime) uint32_t rx_gain_byp[4]; /// \brief Current transmit power - int8_t tx_power_dBm[10]; + int16_t tx_power_dBm[10]; /// \brief Total number of REs in current transmission int tx_total_RE[10]; /// \brief Maximum transmit power diff --git a/openair2/COMMON/commonDef.h b/openair2/COMMON/commonDef.h index cfd5d68e40..ae1bdaf994 100644 --- a/openair2/COMMON/commonDef.h +++ b/openair2/COMMON/commonDef.h @@ -119,7 +119,7 @@ typedef struct { Byte_t digit14:4; Byte_t digit13:4; #define EVEN_PARITY 0 -#define ODD_PARITY 1 +#define ODD_PARITY 0xf Byte_t parity:4; Byte_t digit15:4; } num; diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 886ccff238..642475a063 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -1356,7 +1356,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf // Trigger BSR Periodic UE_mac_inst[module_idP].BSR_reporting_active |= BSR_TRIGGER_PERIODIC; - LOG_I(MAC,"[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry at frame%d subframe %d TBS=%d\n", + LOG_D(MAC,"[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry at frame%d subframe %d TBS=%d\n", module_idP, frameP, subframe, buflen); } diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index 17808c03ff..fedef42b60 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -493,7 +493,7 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const ctxt_pP) ctxt.enb_flag = ctxt_cpy.enb_flag; #ifdef PDCP_DEBUG - LOG_I(PDCP, "[PDCP][NETLINK] pdcp_read_header_g.rb_id = %d\n", pdcp_read_header_g.rb_id); + LOG_D(PDCP, "[PDCP][NETLINK] pdcp_read_header_g.rb_id = %d\n", pdcp_read_header_g.rb_id); #endif if (ctxt_cpy.enb_flag) { 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 3232399d10..51440d0bfa 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c @@ -426,7 +426,7 @@ rlc_um_rx (const protocol_ctxt_t* const ctxt_pP, void *argP, struct mac_data_ind //----------------------------------------------------------------------------- struct mac_status_resp -rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP) +rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP,const eNB_flag_t enb_flagP) { struct mac_status_resp status_resp; uint16_t sdu_size = 0; @@ -434,6 +434,7 @@ 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; @@ -453,7 +454,20 @@ 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)) { - status_resp.buffer_occupancy_in_bytes += rlc_p->tx_header_min_length_in_bytes; + //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); 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; 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 d87f1e29d0..5951eaf149 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h @@ -186,7 +186,7 @@ protected_rlc_um( void rlc_um_rx (const protocol_ctxt_t* const ctxt_pP, rlc_ * \param[in] tx_statusP Transmission status given by MAC on previous MAC transmission of the PDU. * \return The maximum number of bytes that can be served by RLC instance to MAC. */ -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);) +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) * \brief Gives PDUs to lower layer MAC. diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c index c9a82e12f6..92f18e72d7 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_test.c @@ -471,9 +471,9 @@ void rlc_um_v9_3_0_test_exchange_pdus(rlc_um_entity_t *um_txP, memset(&mac_rlc_status_resp_tx, 0, sizeof(struct mac_status_resp)); memset(&mac_rlc_status_resp_rx, 0, sizeof(struct mac_status_resp)); - mac_rlc_status_resp_tx = rlc_um_mac_status_indication(um_txP, g_frame, 1, bytes_txP, tx_status); + mac_rlc_status_resp_tx = rlc_um_mac_status_indication(um_txP, g_frame, 1, bytes_txP, tx_status,ENB_FLAG_YES); data_request_tx = rlc_um_mac_data_request(um_txP, g_frame); - mac_rlc_status_resp_rx = rlc_um_mac_status_indication(um_rxP, g_frame, 0, bytes_rxP, tx_status); + mac_rlc_status_resp_rx = rlc_um_mac_status_indication(um_rxP, g_frame, 0, bytes_rxP, tx_status,ENB_FLAG_YES); data_request_rx = rlc_um_mac_data_request(um_rxP, g_frame); @@ -517,9 +517,9 @@ void rlc_um_v9_3_0_test_exchange_delayed_pdus(rlc_um_entity_t *um_txP, memset(&mac_rlc_status_resp_tx, 0, sizeof(struct mac_status_resp)); memset(&mac_rlc_status_resp_rx, 0, sizeof(struct mac_status_resp)); - mac_rlc_status_resp_tx = rlc_um_mac_status_indication(um_txP, g_frame, 1, bytes_txP, tx_status); + mac_rlc_status_resp_tx = rlc_um_mac_status_indication(um_txP, g_frame, 1, bytes_txP, tx_status,ENB_FLAG_YES); data_request_tx = rlc_um_mac_data_request(um_txP, g_frame); - mac_rlc_status_resp_rx = rlc_um_mac_status_indication(um_rxP, g_frame, 0, bytes_rxP, tx_status); + mac_rlc_status_resp_rx = rlc_um_mac_status_indication(um_rxP, g_frame, 0, bytes_rxP, tx_status,ENB_FLAG_YES); data_request_rx = rlc_um_mac_data_request(um_rxP, g_frame); diff --git a/openair2/LAYER2/RLC/rlc_mac.c b/openair2/LAYER2/RLC/rlc_mac.c index 6462bb9abb..d59b187dc7 100644 --- a/openair2/LAYER2/RLC/rlc_mac.c +++ b/openair2/LAYER2/RLC/rlc_mac.c @@ -406,7 +406,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind( break; case RLC_MODE_UM: - status_resp = rlc_um_mac_status_indication(&ctxt, &rlc_union_p->rlc.um, tb_sizeP, tx_status); + status_resp = rlc_um_mac_status_indication(&ctxt, &rlc_union_p->rlc.um, tb_sizeP, tx_status, enb_flagP); mac_rlc_status_resp.bytes_in_buffer = status_resp.buffer_occupancy_in_bytes; mac_rlc_status_resp.pdus_in_buffer = status_resp.buffer_occupancy_in_pdus; mac_rlc_status_resp.head_sdu_creation_time = status_resp.head_sdu_creation_time; diff --git a/openair2/NETWORK_DRIVER/UE_IP/common.c b/openair2/NETWORK_DRIVER/UE_IP/common.c index 6bef269de8..8696801597 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/common.c +++ b/openair2/NETWORK_DRIVER/UE_IP/common.c @@ -99,7 +99,8 @@ ue_ip_common_class_wireless2ip( hard_header_len = ue_ip_dev[instP]->hard_header_len; skb_set_mac_header(skb_p, 0); - + skb_set_network_header(skb_p, hard_header_len); +skb_p->mark = rb_idP; //printk("[NAC_COMMIN_RECEIVE]: Packet Type %d (%d,%d)",skb_p->pkt_type,PACKET_HOST,PACKET_BROADCAST); skb_p->pkt_type = PACKET_HOST; @@ -344,7 +345,7 @@ void ue_ip_common_wireless2ip(struct nlmsghdr *nlh_pP) ue_ip_common_class_wireless2ip(pdcph_p->data_size, (unsigned char *)NLMSG_DATA(nlh_pP) + UE_IP_PDCPH_SIZE, - pdcph_p->inst, + 1, //pdcph_p->inst, pdcph_p->rb_id); } diff --git a/openair3/NAS/COMMON/EMM/MSG/AttachAccept.c b/openair3/NAS/COMMON/EMM/MSG/AttachAccept.c index cec2d16977..248540dff3 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AttachAccept.c +++ b/openair3/NAS/COMMON/EMM/MSG/AttachAccept.c @@ -188,10 +188,11 @@ int decode_attach_accept(attach_accept_msg *attach_accept, uint8_t *buffer, uint default: errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + LOG_TRACE(WARNING, "DECODE_UNEXPECTED_IEI %x (4 bits)", ieiDecoded); return TLV_DECODE_UNEXPECTED_IEI; } } - + LOG_TRACE(WARNING, "DECODED %d\n", decoded); return decoded; } diff --git a/openair3/NAS/COMMON/EMM/MSG/AuthenticationRequest.c b/openair3/NAS/COMMON/EMM/MSG/AuthenticationRequest.c index fac93c5df3..3e0bffde2d 100644 --- a/openair3/NAS/COMMON/EMM/MSG/AuthenticationRequest.c +++ b/openair3/NAS/COMMON/EMM/MSG/AuthenticationRequest.c @@ -38,7 +38,7 @@ int decode_authentication_request(authentication_request_msg *authentication_req CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, AUTHENTICATION_REQUEST_MINIMUM_LENGTH, len); /* Decoding mandatory fields */ - if ((decoded_result = decode_u8_nas_key_set_identifier(&authentication_request->naskeysetidentifierasme, 0, *(buffer + decoded) >> 4, len - decoded)) < 0) + if ((decoded_result = decode_u8_nas_key_set_identifier(&authentication_request->naskeysetidentifierasme, 0, *(buffer + decoded), len - decoded)) < 0) return decoded_result; decoded++; diff --git a/openair3/NAS/COMMON/EMM/MSG/SecurityModeCommand.c b/openair3/NAS/COMMON/EMM/MSG/SecurityModeCommand.c index aeec3d4024..c89a9f5bb7 100644 --- a/openair3/NAS/COMMON/EMM/MSG/SecurityModeCommand.c +++ b/openair3/NAS/COMMON/EMM/MSG/SecurityModeCommand.c @@ -72,6 +72,8 @@ int decode_security_mode_command(security_mode_command_msg *security_mode_comman decoded += decoded_result; /* Set corresponding mask to 1 in presencemask */ security_mode_command->presencemask |= SECURITY_MODE_COMMAND_IMEISV_REQUEST_PRESENT; + LOG_I(NAS," SECURITY MODE COMMAND: IMEISV_REQUEST: %d \n",security_mode_command->imeisvrequest); + break; case SECURITY_MODE_COMMAND_REPLAYED_NONCEUE_IEI: diff --git a/openair3/NAS/COMMON/EMM/MSG/SecurityModeComplete.c b/openair3/NAS/COMMON/EMM/MSG/SecurityModeComplete.c index f10401d09a..80ceeb34d7 100644 --- a/openair3/NAS/COMMON/EMM/MSG/SecurityModeComplete.c +++ b/openair3/NAS/COMMON/EMM/MSG/SecurityModeComplete.c @@ -76,8 +76,11 @@ int encode_security_mode_complete(security_mode_complete_msg *security_mode_comp /* Checking IEI and pointer */ CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, SECURITY_MODE_COMPLETE_MINIMUM_LENGTH, len); + LOG_I(NAS,"SECURITY MODE COMMAND COMPLETE: presencemask: %d \n",security_mode_complete->presencemask); + if ((security_mode_complete->presencemask & SECURITY_MODE_COMPLETE_IMEISV_PRESENT) == SECURITY_MODE_COMPLETE_IMEISV_PRESENT) { + LOG_I(NAS,"SECURITY MODE COMMAND COMPLETE: encode imeisv \n"); if ((encode_result = encode_mobile_identity(&security_mode_complete->imeisv, SECURITY_MODE_COMPLETE_IMEISV_IEI, buffer + encoded, len - @@ -87,7 +90,7 @@ int encode_security_mode_complete(security_mode_complete_msg *security_mode_comp else encoded += encode_result; } - + LOG_I(NAS,"SECURITY MODE COMMAND COMPLETE done !!! \n"); return encoded; } diff --git a/openair3/NAS/COMMON/IES/EmergencyNumberList.c b/openair3/NAS/COMMON/IES/EmergencyNumberList.c index 39b59ef0ca..9330fdc312 100644 --- a/openair3/NAS/COMMON/IES/EmergencyNumberList.c +++ b/openair3/NAS/COMMON/IES/EmergencyNumberList.c @@ -41,10 +41,24 @@ int decode_emergency_number_list(EmergencyNumberList *emergencynumberlist, uint8 ielen = *(buffer + decoded); decoded++; CHECK_LENGTH_DECODER(len - decoded, ielen); - emergencynumberlist->lengthofemergency = *(buffer + decoded); - decoded++; - emergencynumberlist->emergencyservicecategoryvalue = *(buffer + decoded) & 0x1f; - decoded++; + int information_element_index = 0; + while ((decoded < ielen) && (information_element_index < EMERGENCY_NUMBER_LIST_MAX_NUMBER_INFORMATION)) { + emergencynumberlist->emergency_number_information[information_element_index].lengthofemergency = *(buffer + decoded); + decoded++; + emergencynumberlist->emergency_number_information[information_element_index].emergencyservicecategoryvalue = *(buffer + decoded) & 0x1f; + decoded++; + int remaining_len = emergencynumberlist->emergency_number_information[information_element_index].lengthofemergency - 1; + int digit_index = 0; + while (remaining_len > 0) { + emergencynumberlist->emergency_number_information[information_element_index].bcd_digits[digit_index++] = *(buffer + decoded); + decoded++; + remaining_len --; + } + while (digit_index < EMERGENCY_NUMBER_LIST_MAX_2DIGITS) { + emergencynumberlist->emergency_number_information[information_element_index].bcd_digits[digit_index++] = 0xFF; + } + information_element_index++; + } #if defined (NAS_DEBUG) dump_emergency_number_list_xml(emergencynumberlist, iei); #endif @@ -67,11 +81,16 @@ int encode_emergency_number_list(EmergencyNumberList *emergencynumberlist, uint8 lenPtr = (buffer + encoded); encoded ++; - *(buffer + encoded) = emergencynumberlist->lengthofemergency; - encoded++; - *(buffer + encoded) = 0x00 | - (emergencynumberlist->emergencyservicecategoryvalue & 0x1f); - encoded++; + for ( int ie_index = 0; ie_index < emergencynumberlist->num_emergency_elements; ie_index++) { + *(buffer + encoded) = emergencynumberlist->emergency_number_information[ie_index].lengthofemergency; + encoded++; + *(buffer + encoded) = 0x00 | + (emergencynumberlist->emergency_number_information[ie_index].emergencyservicecategoryvalue & 0x1f); + encoded++; + for (int bcd2_index = 0; bcd2_index < (emergencynumberlist->emergency_number_information[ie_index].lengthofemergency - 1); bcd2_index++) { + *(buffer + encoded) = emergencynumberlist->emergency_number_information[ie_index].bcd_digits[bcd2_index]; + } + } *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); return encoded; } @@ -83,9 +102,20 @@ void dump_emergency_number_list_xml(EmergencyNumberList *emergencynumberlist, ui if (iei > 0) /* Don't display IEI if = 0 */ printf(" 0x%X\n", iei); - - printf(" %u\n", emergencynumberlist->lengthofemergency); - printf(" %u\n", emergencynumberlist->emergencyservicecategoryvalue); + for ( int ie_index = 0; ie_index < emergencynumberlist->num_emergency_elements; ie_index++) { + printf(" %u\n", emergencynumberlist->emergency_number_information[ie_index].lengthofemergency); + printf(" %u\n", emergencynumberlist->emergency_number_information[ie_index].emergencyservicecategoryvalue); + for (int bcd2_index = 0; bcd2_index < (emergencynumberlist->emergency_number_information[ie_index].lengthofemergency - 1); bcd2_index++) { + uint8_t bcd1 = emergencynumberlist->emergency_number_information[ie_index].bcd_digits[bcd2_index] & 0x0f; + uint8_t bcd2 = (emergencynumberlist->emergency_number_information[ie_index].bcd_digits[bcd2_index] & 0xf0) >> 4; + if (bcd1 < 10) { + printf(" %u\n", (bcd2_index*2)+1, bcd1, (bcd2_index*2)+1); + if (bcd2 < 10) { + printf(" %u\n", (bcd2_index*2)+2, bcd2, (bcd2_index*2)+2); + } + } + } + } printf("\n"); } diff --git a/openair3/NAS/COMMON/IES/EmergencyNumberList.h b/openair3/NAS/COMMON/IES/EmergencyNumberList.h index d2fd149dc0..ab47c1ff06 100644 --- a/openair3/NAS/COMMON/IES/EmergencyNumberList.h +++ b/openair3/NAS/COMMON/IES/EmergencyNumberList.h @@ -32,8 +32,14 @@ #define EMERGENCY_NUMBER_LIST_MAXIMUM_LENGTH 50 typedef struct EmergencyNumberList_tag { - uint8_t lengthofemergency; - uint8_t emergencyservicecategoryvalue:5; + uint8_t num_emergency_elements; + struct { + uint8_t lengthofemergency; + uint8_t emergencyservicecategoryvalue:5; +#define EMERGENCY_NUMBER_LIST_MAX_2DIGITS 6 + uint8_t bcd_digits[EMERGENCY_NUMBER_LIST_MAX_2DIGITS]; // length to be fixed +#define EMERGENCY_NUMBER_LIST_MAX_NUMBER_INFORMATION 2 + } emergency_number_information[EMERGENCY_NUMBER_LIST_MAX_NUMBER_INFORMATION]; } EmergencyNumberList; int encode_emergency_number_list(EmergencyNumberList *emergencynumberlist, uint8_t iei, uint8_t *buffer, uint32_t len); diff --git a/openair3/NAS/COMMON/IES/MobileIdentity.c b/openair3/NAS/COMMON/IES/MobileIdentity.c index 7ab30011ce..59cf4dc44f 100644 --- a/openair3/NAS/COMMON/IES/MobileIdentity.c +++ b/openair3/NAS/COMMON/IES/MobileIdentity.c @@ -575,6 +575,8 @@ static int encode_imei_mobile_identity(ImeiMobileIdentity_t *imei, uint8_t *buff static int encode_imeisv_mobile_identity(ImeisvMobileIdentity_t *imeisv, uint8_t *buffer) { uint32_t encoded = 0; + LOG_I(NAS,"SECURITY MODE COMMAND COMPLETE: encode_imeisv_mobile_identity \n"); + *(buffer + encoded) = 0x00 | (imeisv->digit1 << 4) | (imeisv->oddeven << 3) | (imeisv->typeofidentity); encoded++; @@ -590,12 +592,15 @@ static int encode_imeisv_mobile_identity(ImeisvMobileIdentity_t *imeisv, uint8_t encoded++; *(buffer + encoded) = 0x00 | (imeisv->digit13 << 4) | imeisv->digit12; encoded++; + *(buffer + encoded) = 0x00 | (imeisv->digit15 << 4) | imeisv->digit14; + encoded++; + *(buffer + encoded) = 0x00 | (imeisv->parity << 4) | imeisv->digit16; - if (imeisv->oddeven != MOBILE_IDENTITY_EVEN) { - *(buffer + encoded) = 0x00 | (imeisv->digit15 << 4) | imeisv->digit14; - } else { - *(buffer + encoded) = 0xf0 | imeisv->digit14; - } + //if (imeisv->oddeven != MOBILE_IDENTITY_EVEN) { + // *(buffer + encoded) = 0x00 | (imeisv->digit15 << 4) | imeisv->digit14; + //} else { + // *(buffer + encoded) = 0xf0 | imeisv->digit14; + //} encoded++; return encoded; diff --git a/openair3/NAS/COMMON/IES/MobileIdentity.h b/openair3/NAS/COMMON/IES/MobileIdentity.h index 8d1c5cdbe5..9c082c12df 100644 --- a/openair3/NAS/COMMON/IES/MobileIdentity.h +++ b/openair3/NAS/COMMON/IES/MobileIdentity.h @@ -73,8 +73,63 @@ typedef struct { uint8_t mbmssessionid; } TmgiMobileIdentity_t; +typedef struct imeisv_s{ + uint8_t digit1:4; + uint8_t oddeven:1; + uint8_t typeofidentity:3; + uint8_t digit2:4; + uint8_t digit3:4; + uint8_t digit4:4; + uint8_t digit5:4; + uint8_t digit6:4; + uint8_t digit7:4; + uint8_t digit8:4; + uint8_t digit9:4; + uint8_t digit10:4; + uint8_t digit11:4; + uint8_t digit12:4; + uint8_t digit13:4; + uint8_t digit14:4; + uint8_t digit15:4; + uint8_t digit16:4; +#define EVEN_PARITY 0 +#define ODD_PARITY 1 + uint8_t parity:4; +} imeisv_t; + +#if 0 +typedef struct imeisv_s { + uint8_t length; + union { + struct { + uint8_t tac2:4; + uint8_t tac1:4; + uint8_t tac4:4; + uint8_t tac3:4; + uint8_t tac6:4; + uint8_t tac5:4; + uint8_t tac8:4; + uint8_t tac7:4; + uint8_t snr2:4; + uint8_t snr1:4; + uint8_t snr4:4; + uint8_t snr3:4; + uint8_t snr6:4; + uint8_t snr5:4; + uint8_t svn2:4; + uint8_t svn1:4; +#define EVEN_PARITY 0 +#define ODD_PARITY 1 + uint8_t parity:4; + } num; +#define IMEISV_BCD8_SIZE 9 + uint8_t value[IMEISV_BCD8_SIZE]; + } u; +} imeisv_t; +#endif + typedef ImsiMobileIdentity_t ImeiMobileIdentity_t; -typedef ImsiMobileIdentity_t ImeisvMobileIdentity_t; +typedef imeisv_t ImeisvMobileIdentity_t; typedef ImsiMobileIdentity_t TmsiMobileIdentity_t; typedef ImsiMobileIdentity_t NoMobileIdentity_t; diff --git a/openair3/NAS/UE/EMM/SAP/emm_asDef.h b/openair3/NAS/UE/EMM/SAP/emm_asDef.h index bf0e6f6c37..69ea979b63 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_asDef.h +++ b/openair3/NAS/UE/EMM/SAP/emm_asDef.h @@ -120,6 +120,7 @@ typedef struct emm_as_security_s { uint8_t ucs2; uint8_t uia; /* Replayed UMTS integrity algorithms */ uint8_t gea; /* Replayed GPRS encryption algorithms */ + uint8_t imeisv_request; uint8_t umts_present; uint8_t gprs_present; diff --git a/openair3/NAS/UE/EMM/SAP/emm_recv.c b/openair3/NAS/UE/EMM/SAP/emm_recv.c index a79a14d9c1..60b504f1ce 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_recv.c +++ b/openair3/NAS/UE/EMM/SAP/emm_recv.c @@ -472,13 +472,15 @@ int emm_recv_security_mode_command(security_mode_command_msg *msg, * Message processing */ /* Execute the security mode control procedure initiated by the network */ + LOG_I(NAS,"Execute the security mode control procedure initiated by the network: imeisvrequest %d\n",msg->imeisvrequest); rc = emm_proc_security_mode_command( msg->naskeysetidentifier.tsc != NAS_KEY_SET_IDENTIFIER_MAPPED, msg->naskeysetidentifier.naskeysetidentifier, msg->selectednassecurityalgorithms.typeofcipheringalgorithm, msg->selectednassecurityalgorithms.typeofintegrityalgorithm, msg->replayeduesecuritycapabilities.eea, - msg->replayeduesecuritycapabilities.eia); + msg->replayeduesecuritycapabilities.eia, + msg->imeisvrequest & 0x7); LOG_FUNC_RETURN (rc); } diff --git a/openair3/NAS/UE/EMM/SAP/emm_send.c b/openair3/NAS/UE/EMM/SAP/emm_send.c index 7e13d03c7b..e960b85848 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_send.c +++ b/openair3/NAS/UE/EMM/SAP/emm_send.c @@ -855,6 +855,35 @@ int emm_send_security_mode_complete(const emm_as_security_t *msg, /* Mandatory - Message type */ emm_msg->messagetype = SECURITY_MODE_COMPLETE; + if(msg->imeisv_request) + { + // configure imeisv param + emm_msg->presencemask |= SECURITY_MODE_COMPLETE_IMEISV_PRESENT; + + // 33 85 76 02 05 26 84 01 F1 + emm_msg->imeisv.imeisv; + emm_msg->imeisv.imeisv.digit1 = 0x3; + emm_msg->imeisv.imeisv.oddeven = 0x0; + emm_msg->imeisv.imeisv.typeofidentity = 0x3; + emm_msg->imeisv.imeisv.digit2 = 0x5; + emm_msg->imeisv.imeisv.digit3 = 0x7; + emm_msg->imeisv.imeisv.digit4 = 0x4; + emm_msg->imeisv.imeisv.digit5 = 0x7; + emm_msg->imeisv.imeisv.digit6 = 0x3; + emm_msg->imeisv.imeisv.digit7 = 0x0; + emm_msg->imeisv.imeisv.digit8 = 0x4; + emm_msg->imeisv.imeisv.digit9 = 0x0; + emm_msg->imeisv.imeisv.digit10 = 0x0; + emm_msg->imeisv.imeisv.digit11 = 0x7; + emm_msg->imeisv.imeisv.digit12 = 0x0; + emm_msg->imeisv.imeisv.digit13 = 0x5; + emm_msg->imeisv.imeisv.digit14 = 0x3; + emm_msg->imeisv.imeisv.digit15 = 0x0; + emm_msg->imeisv.imeisv.digit16 = 0x0; + emm_msg->imeisv.imeisv.parity = ODD_PARITY; + + size += SECURITY_MODE_COMPLETE_MAXIMUM_LENGTH; + } LOG_FUNC_RETURN (size); } diff --git a/openair3/NAS/UE/EMM/SecurityModeControl.c b/openair3/NAS/UE/EMM/SecurityModeControl.c index 7d19808481..f27eb7b4af 100644 --- a/openair3/NAS/UE/EMM/SecurityModeControl.c +++ b/openair3/NAS/UE/EMM/SecurityModeControl.c @@ -146,7 +146,7 @@ static void _security_release(emm_security_context_t *ctx); ** ** ***************************************************************************/ int emm_proc_security_mode_command(int native_ksi, int ksi, - int seea, int seia, int reea, int reia) + int seea, int seia, int reea, int reia, int imeisv_request) { LOG_FUNC_IN; @@ -329,6 +329,7 @@ int emm_proc_security_mode_command(int native_ksi, int ksi, emm_sap.u.emm_as.u.security.guti = _emm_data.guti; emm_sap.u.emm_as.u.security.ueid = 0; emm_sap.u.emm_as.u.security.msgType = EMM_AS_MSG_TYPE_SMC; + emm_sap.u.emm_as.u.security.imeisv_request = imeisv_request; emm_sap.u.emm_as.u.security.emm_cause = emm_cause; /* Setup EPS NAS security data */ emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, diff --git a/openair3/NAS/UE/EMM/emm_proc.h b/openair3/NAS/UE/EMM/emm_proc.h index e6a3ae0cdd..60f71f11c2 100644 --- a/openair3/NAS/UE/EMM/emm_proc.h +++ b/openair3/NAS/UE/EMM/emm_proc.h @@ -174,7 +174,7 @@ int emm_proc_authentication_delete(void); * -------------------------------------------------------------------------- */ int emm_proc_security_mode_command(int native_ksi, int ksi, int seea, int seia, - int reea, int reia); + int reea, int reia,int imeisv_request); /* *--------------------------------------------------------------------------- diff --git a/targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c b/targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c index 0c1500fd5e..dc395281dc 100644 --- a/targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c +++ b/targets/TEST/PDCP/with_rlc/test_pdcp_rlc.c @@ -188,9 +188,9 @@ void pdcp_rlc_test_exchange_pdus(rlc_um_entity_t *um_txP, memset(&mac_rlc_status_resp_tx, 0, sizeof(struct mac_status_resp)); memset(&mac_rlc_status_resp_rx, 0, sizeof(struct mac_status_resp)); - mac_rlc_status_resp_tx = rlc_um_mac_status_indication(um_txP, bytes_txP, tx_status); + mac_rlc_status_resp_tx = rlc_um_mac_status_indication(um_txP, bytes_txP, tx_status, ENB_FLAG_YES); data_request_tx = rlc_um_mac_data_request(um_txP); - mac_rlc_status_resp_rx = rlc_um_mac_status_indication(um_rxP, bytes_rxP, tx_status); + mac_rlc_status_resp_rx = rlc_um_mac_status_indication(um_rxP, bytes_rxP, tx_status, ENB_FLAG_YES); data_request_rx = rlc_um_mac_data_request(um_rxP); From 179ff736584b6dfd5956bc5c3b1a2033bb3af035 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 8 Dec 2016 16:47:30 +0100 Subject: [PATCH 391/413] integration fix: use old CMakeLists.txt Another way to set those two variables has to be used for the specific UE case (use a sub CMakeLists.txt, see in build_oai). --- cmake_targets/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 891001ecbc..07d92a1b05 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -644,7 +644,7 @@ add_boolean_option(ENABLE_USE_CPU_EXECUTION_TIME True "Add data in vcd traces: d add_boolean_option(ENABLE_VCD True "always true now, time measurements of proc calls and var displays") add_boolean_option(ENABLE_VCD_FIFO True "time measurements of proc calls and var displays sent to FIFO (one more thread)") add_boolean_option(HARD_RT False "???") -add_boolean_option(LINUX True "used in weird memcpy() in pdcp.c ???") +add_boolean_option(LINUX False "used in weird memcpy() in pdcp.c ???") add_boolean_option(LINUX_LIST False "used only in lists.c: either use OAI implementation of lists or Linux one (should be True, but it is False") add_boolean_option(LOG_NO_THREAD True "Disable thread for log, seems always set to true") add_boolean_option(OPENAIR_LTE True "Seems legacy: keep it to true") @@ -727,7 +727,7 @@ add_boolean_option(TRACE_RLC_UM_TX_STATUS False "TRACE for RLC UM, TO BE CHANGE ########################## # PDCP LAYER OPTIONS ########################## -add_boolean_option(PDCP_USE_NETLINK True "For eNB, PDCP communicate with a NETLINK socket if connected to network driver, else could use a RT-FIFO") +add_boolean_option(PDCP_USE_NETLINK False "For eNB, PDCP communicate with a NETLINK socket if connected to network driver, else could use a RT-FIFO") add_boolean_option(PDCP_USE_NETLINK_QUEUES False "When PDCP_USE_NETLINK is true, incoming IP packets are stored in queues") add_boolean_option(LINK_ENB_PDCP_TO_IP_DRIVER False "For eNB, PDCP communicate with a IP driver") add_boolean_option(LINK_ENB_PDCP_TO_GTPV1U True "For eNB, PDCP communicate with GTP-U protocol (eNB<->S-GW)") From e4a84606b94bcf26a9b076f6bfaa785d0d670327 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 8 Dec 2016 17:09:39 +0100 Subject: [PATCH 392/413] integration fix: send SRS configuration to UE only if SRS active Manually testing with the Samsung Galaxy Note 4 failed, probably because the phone didn't like to receive SRS configuration. Let's send it only if activated. --- openair2/RRC/LITE/MESSAGES/asn1_msg.c | 30 ++++++++++++++++----------- openair2/RRC/LITE/MESSAGES/asn1_msg.h | 2 ++ openair2/RRC/LITE/rrc_eNB.c | 1 + 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.c b/openair2/RRC/LITE/MESSAGES/asn1_msg.c index 7d2fc3a3d8..b4290e8b9d 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.c @@ -1388,6 +1388,7 @@ uint8_t do_RRCConnectionSetup( const protocol_ctxt_t* const ctxt_pP, rrc_eNB_ue_context_t* const ue_context_pP, + int CC_id, uint8_t* const buffer, const uint8_t transmission_mode, const uint8_t Transaction_id, @@ -1492,7 +1493,10 @@ do_RRCConnectionSetup( physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH = CALLOC(1,sizeof(*physicalConfigDedicated2->tpc_PDCCH_ConfigPUCCH)); physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH = CALLOC(1,sizeof(*physicalConfigDedicated2->tpc_PDCCH_ConfigPUSCH)); physicalConfigDedicated2->cqi_ReportConfig = CALLOC(1,sizeof(*physicalConfigDedicated2->cqi_ReportConfig)); - physicalConfigDedicated2->soundingRS_UL_ConfigDedicated = CALLOC(1,sizeof(*physicalConfigDedicated2->soundingRS_UL_ConfigDedicated)); + if (enb_properties.properties[ctxt_pP->module_id]->srs_enable[CC_id]) + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated = CALLOC(1,sizeof(*physicalConfigDedicated2->soundingRS_UL_ConfigDedicated)); + else + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated = NULL; physicalConfigDedicated2->antennaInfo = CALLOC(1,sizeof(*physicalConfigDedicated2->antennaInfo)); physicalConfigDedicated2->schedulingRequestConfig = CALLOC(1,sizeof(*physicalConfigDedicated2->schedulingRequestConfig)); #ifdef CBA @@ -1578,17 +1582,19 @@ do_RRCConnectionSetup( */ //soundingRS-UL-ConfigDedicated - physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->present = SoundingRS_UL_ConfigDedicated_PR_setup; - physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth = - SoundingRS_UL_ConfigDedicated__setup__srs_Bandwidth_bw0; - physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth = - SoundingRS_UL_ConfigDedicated__setup__srs_HoppingBandwidth_hbw0; - physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition=0; - physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.duration=1; - physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex=45; - physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb=0; - physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift= - SoundingRS_UL_ConfigDedicated__setup__cyclicShift_cs0; + if (enb_properties.properties[ctxt_pP->module_id]->srs_enable[CC_id]) { + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->present = SoundingRS_UL_ConfigDedicated_PR_setup; + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth = + SoundingRS_UL_ConfigDedicated__setup__srs_Bandwidth_bw0; + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth = + SoundingRS_UL_ConfigDedicated__setup__srs_HoppingBandwidth_hbw0; + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition=0; + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.duration=1; + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex=45; + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb=0; + physicalConfigDedicated2->soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift= + SoundingRS_UL_ConfigDedicated__setup__cyclicShift_cs0; + } //AntennaInfoDedicated diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg.h b/openair2/RRC/LITE/MESSAGES/asn1_msg.h index 661914ea6e..881a778030 100644 --- a/openair2/RRC/LITE/MESSAGES/asn1_msg.h +++ b/openair2/RRC/LITE/MESSAGES/asn1_msg.h @@ -133,6 +133,7 @@ do_RRCConnectionReconfigurationComplete( PhysicalConfigDedicated IEs. The latter does not enable periodic CQI reporting (PUCCH format 2/2a/2b) or SRS. @param ctxt_pP Running context @param ue_context_pP UE context +@param CC_id Component Carrier ID @param buffer Pointer to PER-encoded ASN.1 description of DL-CCCH-Message PDU @param transmission_mode Transmission mode for UE (1-9) @param UE_id UE index for this message @@ -144,6 +145,7 @@ uint8_t do_RRCConnectionSetup( const protocol_ctxt_t* const ctxt_pP, rrc_eNB_ue_context_t* const ue_context_pP, + int CC_id, uint8_t* const buffer, const uint8_t transmission_mode, const uint8_t Transaction_id, diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 747522e01b..08d50da39c 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -3743,6 +3743,7 @@ rrc_eNB_generate_RRCConnectionSetup( eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.payload_size = do_RRCConnectionSetup(ctxt_pP, ue_context_pP, + CC_id, (uint8_t*) eNB_rrc_inst[ctxt_pP->module_id].carrier[CC_id].Srb0.Tx_buffer.Payload, (fp->nb_antennas_tx_eNB==2)?2:1, //at this point we do not have the UE capability information, so it can only be TM1 or TM2 rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id), From 497e89d97e88b6ffddc138c024243c26ad9be73e Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 8 Dec 2016 17:48:56 +0100 Subject: [PATCH 393/413] integration fix: bugfix: wrong enum used --- openair1/PHY/INIT/lte_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 3fcc37f6bd..035410eb25 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -483,7 +483,7 @@ void phy_config_dedicated_eNB_step2(PHY_VARS_eNB *eNB) } if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated) { - if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated->present == SchedulingRequestConfig_PR_setup) { + if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) { eNB->soundingrs_ul_config_dedicated[UE_id].duration = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.duration; eNB->soundingrs_ul_config_dedicated[UE_id].cyclicShift = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift; @@ -876,7 +876,7 @@ void phy_config_dedicated_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated) { phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srsConfigDedicatedSetup = 0; - if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated->present == SchedulingRequestConfig_PR_setup) { + if (physicalConfigDedicated->soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) { phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].srsConfigDedicatedSetup = 1; phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].duration = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.duration; phy_vars_ue->soundingrs_ul_config_dedicated[eNB_id].cyclicShift = physicalConfigDedicated->soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift; From 752ceb19221001ec18d22425157beae83a2436ba Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 8 Dec 2016 17:49:56 +0100 Subject: [PATCH 394/413] integration fix: remove compilation warnings --- openair1/PHY/LTE_TRANSPORT/srs_modulation.c | 2 +- openair3/NAS/UE/EMM/SAP/emm_send.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/srs_modulation.c b/openair1/PHY/LTE_TRANSPORT/srs_modulation.c index 15561e6b28..7e29d998a1 100644 --- a/openair1/PHY/LTE_TRANSPORT/srs_modulation.c +++ b/openair1/PHY/LTE_TRANSPORT/srs_modulation.c @@ -133,7 +133,7 @@ int32_t generate_srs_tx(PHY_VARS_UE *ue, uint16_t msrsb=0,Nb=0,nb,b,msrs0=0,k,Msc_RS,Msc_RS_idx,carrier_pos,symbol_offset; uint16_t *Msc_idx_ptr; int32_t k0; - uint32_t subframe_offset; + //uint32_t subframe_offset; uint8_t Bsrs = soundingrs_ul_config_dedicated->srs_Bandwidth; uint8_t Csrs = frame_parms->soundingrs_ul_config_common.srs_BandwidthConfig; uint8_t Ssrs = frame_parms->soundingrs_ul_config_common.srs_SubframeConfig; diff --git a/openair3/NAS/UE/EMM/SAP/emm_send.c b/openair3/NAS/UE/EMM/SAP/emm_send.c index e960b85848..554c556932 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_send.c +++ b/openair3/NAS/UE/EMM/SAP/emm_send.c @@ -861,7 +861,6 @@ int emm_send_security_mode_complete(const emm_as_security_t *msg, emm_msg->presencemask |= SECURITY_MODE_COMPLETE_IMEISV_PRESENT; // 33 85 76 02 05 26 84 01 F1 - emm_msg->imeisv.imeisv; emm_msg->imeisv.imeisv.digit1 = 0x3; emm_msg->imeisv.imeisv.oddeven = 0x0; emm_msg->imeisv.imeisv.typeofidentity = 0x3; From 46b2ee9577073261163349f03057f2587186b955 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 8 Dec 2016 17:51:02 +0100 Subject: [PATCH 395/413] integration fix: attempt to clarify ODD_PARITY This may need to be refined. The variable ODD_PARITY is defined at various places, with different values, causing compilation warnings. It's wrong to define a variable with different values. A new variable is created, specific to IMEI case: IMEI_ODD_PARITY. Maybe ODD_PARITY should also have 0xf as value, and so maybe only one variable is necessary. To be checked at some point... --- openair2/COMMON/commonDef.h | 2 +- openair3/NAS/COMMON/IES/MobileIdentity.h | 4 ++-- openair3/NAS/UE/EMM/SAP/emm_send.c | 2 +- openair3/NAS/UE/EMM/emm_main.c | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/openair2/COMMON/commonDef.h b/openair2/COMMON/commonDef.h index ae1bdaf994..cfd5d68e40 100644 --- a/openair2/COMMON/commonDef.h +++ b/openair2/COMMON/commonDef.h @@ -119,7 +119,7 @@ typedef struct { Byte_t digit14:4; Byte_t digit13:4; #define EVEN_PARITY 0 -#define ODD_PARITY 0xf +#define ODD_PARITY 1 Byte_t parity:4; Byte_t digit15:4; } num; diff --git a/openair3/NAS/COMMON/IES/MobileIdentity.h b/openair3/NAS/COMMON/IES/MobileIdentity.h index 9c082c12df..72abcb9ed4 100644 --- a/openair3/NAS/COMMON/IES/MobileIdentity.h +++ b/openair3/NAS/COMMON/IES/MobileIdentity.h @@ -93,7 +93,7 @@ typedef struct imeisv_s{ uint8_t digit15:4; uint8_t digit16:4; #define EVEN_PARITY 0 -#define ODD_PARITY 1 +#define IMEI_ODD_PARITY 0xf uint8_t parity:4; } imeisv_t; @@ -119,7 +119,7 @@ typedef struct imeisv_s { uint8_t svn2:4; uint8_t svn1:4; #define EVEN_PARITY 0 -#define ODD_PARITY 1 +#define IMEI_ODD_PARITY 0xf uint8_t parity:4; } num; #define IMEISV_BCD8_SIZE 9 diff --git a/openair3/NAS/UE/EMM/SAP/emm_send.c b/openair3/NAS/UE/EMM/SAP/emm_send.c index 554c556932..e3fc4fa7f9 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_send.c +++ b/openair3/NAS/UE/EMM/SAP/emm_send.c @@ -879,7 +879,7 @@ int emm_send_security_mode_complete(const emm_as_security_t *msg, emm_msg->imeisv.imeisv.digit14 = 0x3; emm_msg->imeisv.imeisv.digit15 = 0x0; emm_msg->imeisv.imeisv.digit16 = 0x0; - emm_msg->imeisv.imeisv.parity = ODD_PARITY; + emm_msg->imeisv.imeisv.parity = IMEI_ODD_PARITY; size += SECURITY_MODE_COMPLETE_MAXIMUM_LENGTH; } diff --git a/openair3/NAS/UE/EMM/emm_main.c b/openair3/NAS/UE/EMM/emm_main.c index 82946a634e..2eb4d8fa24 100644 --- a/openair3/NAS/UE/EMM/emm_main.c +++ b/openair3/NAS/UE/EMM/emm_main.c @@ -40,6 +40,7 @@ Description Defines the EPS Mobility Management procedure call manager, #include "emm_main.h" #include "nas_log.h" #include "emmData.h" +#include "MobileIdentity.h" #include "memory.h" #include "usim_api.h" @@ -919,7 +920,7 @@ static int _emm_main_get_imei(imei_t *imei, const char *imei_str) int len = strlen(imei_str); if (len % 2) { - imei->u.num.parity = ODD_PARITY; + imei->u.num.parity = IMEI_ODD_PARITY; } else { imei->u.num.parity = EVEN_PARITY; } From 3750ebc2d60091742444139cc38d1949b0786f19 Mon Sep 17 00:00:00 2001 From: ROBERT Benoit Date: Fri, 9 Dec 2016 16:13:06 +0100 Subject: [PATCH 396/413] Update UE autotest testsuite for OAI1B develop1B_integration_w49 branch --- .../autotests/patches/CmakeLists.patch | 2 +- .../autotest_ue_cell_synch_event.patch | 4 +- .../autotest_ue_dlsch_bitrate_metric.patch | 4 +- .../patches/autotest_ue_offsets_metric.patch | 18 +- .../autotests/patches/build_oai.patch | 10 +- cmake_targets/autotests/testsuite_ue_noS1.xml | 1154 +++++++++++------ 6 files changed, 752 insertions(+), 440 deletions(-) diff --git a/cmake_targets/autotests/patches/CmakeLists.patch b/cmake_targets/autotests/patches/CmakeLists.patch index 9f2731ca73..1e54e3a0f3 100644 --- a/cmake_targets/autotests/patches/CmakeLists.patch +++ b/cmake_targets/autotests/patches/CmakeLists.patch @@ -1,5 +1,5 @@ diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt -index 3169c6c..eaf5417 100644 +index 07d92a1..b6a02d1 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -235,6 +235,7 @@ add_boolean_option(DEBUG_OMG False "???") diff --git a/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch b/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch index 33f5ac339f..766b724c6c 100644 --- a/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch +++ b/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch @@ -1,8 +1,8 @@ diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c -index 661fe96..782305d 100644 +index 663978e..b77cb1b 100644 --- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c +++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c -@@ -469,6 +469,15 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) +@@ -476,6 +476,15 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) //#endif if (ue->UE_scan_carrier == 0) { diff --git a/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch b/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch index b7a7dbfa02..74139109f2 100644 --- a/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch +++ b/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch @@ -1,8 +1,8 @@ diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c -index 3ed4c79..6023886 100644 +index 5dc629b..353a049 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c -@@ -2944,6 +2944,13 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin +@@ -3551,6 +3551,13 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin LOG_D(PHY,"[UE %d] Calculating bitrate Frame %d: total_TBS = %d, total_TBS_last = %d, bitrate %f kbits\n", ue->Mod_id,frame_rx,ue->total_TBS[eNB_id], ue->total_TBS_last[eNB_id],(float) ue->bitrate[eNB_id]/1000.0); diff --git a/cmake_targets/autotests/patches/autotest_ue_offsets_metric.patch b/cmake_targets/autotests/patches/autotest_ue_offsets_metric.patch index 3fca1a70fd..85afe8703e 100644 --- a/cmake_targets/autotests/patches/autotest_ue_offsets_metric.patch +++ b/cmake_targets/autotests/patches/autotest_ue_offsets_metric.patch @@ -1,14 +1,12 @@ diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c -index 3ed4c79..7185e5a 100644 +index 5dc629b..4d31ad3 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c -@@ -2748,7 +2748,25 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin - 0); +@@ -3347,6 +3347,22 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin // first slot has been processed (FFTs + Channel Estimation, PCFICH/PHICH/PDCCH) -- -+ -+ /* SYRTEM */ + ++ #if UE_AUTOTEST_TRACE + if ( (frame_rx % 10 == 0) && (subframe_rx == 0)) { + printf("AUTOTEST Metric : UE_FREQ_OFFSET = %d Hz (frame = %d) \n", ue->common_vars.freq_offset, frame_rx); + printf("AUTOTEST Metric : UE_RX_OFFSET = %d (frame = %d) \n", ue->rx_offset, frame_rx); @@ -21,11 +19,9 @@ index 3ed4c79..7185e5a 100644 + (double)ue->measurements.n0_power_tot_dBm+132.24, + frame_rx); + } ++ #endif + -+ -+ -+ -+ ++ // do procedures for C-RNTI if (ue->dlsch[eNB_id][0]->active == 1) { - ue_pdsch_procedures(ue, + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN); diff --git a/cmake_targets/autotests/patches/build_oai.patch b/cmake_targets/autotests/patches/build_oai.patch index d6cecda6e5..cf93b466e7 100644 --- a/cmake_targets/autotests/patches/build_oai.patch +++ b/cmake_targets/autotests/patches/build_oai.patch @@ -1,8 +1,8 @@ diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai -index b77a9ba..8e3021d 100755 +index 25e9a1c..0b04bb7 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai -@@ -53,6 +53,7 @@ BUILD_DOXYGEN=0 +@@ -54,6 +54,7 @@ BUILD_DOXYGEN=0 T_TRACER="False" DISABLE_HARDWARE_DEPENDENCY="False" CMAKE_BUILD_TYPE="" @@ -10,7 +10,7 @@ index b77a9ba..8e3021d 100755 trap handle_ctrl_c INT function print_help() { -@@ -127,6 +128,8 @@ Options +@@ -130,6 +131,8 @@ Options Enables the T tracer. --disable-hardware-dependency Disable HW dependency during installation @@ -19,7 +19,7 @@ index b77a9ba..8e3021d 100755 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 -@@ -278,6 +281,10 @@ function main() { +@@ -285,6 +288,10 @@ function main() { echo_info "Disabling hardware dependency for compiling software" DISABLE_HARDWARE_DEPENDENCY="True" shift 1;; @@ -30,7 +30,7 @@ index b77a9ba..8e3021d 100755 -h | --help) print_help exit 1;; -@@ -447,6 +454,7 @@ function main() { +@@ -457,6 +464,7 @@ function main() { echo "set (DEADLINE_SCHEDULER \"${DEADLINE_SCHEDULER_FLAG_USER}\" )" >>$cmake_file echo "set (CPU_AFFINITY \"${CPU_AFFINITY_FLAG_USER}\" )" >>$cmake_file echo "set ( T_TRACER $T_TRACER )" >> $cmake_file diff --git a/cmake_targets/autotests/testsuite_ue_noS1.xml b/cmake_targets/autotests/testsuite_ue_noS1.xml index 19b945dc28..c5403feab2 100644 --- a/cmake_targets/autotests/testsuite_ue_noS1.xml +++ b/cmake_targets/autotests/testsuite_ue_noS1.xml @@ -2,22 +2,27 @@ imb182-desktop yanbo-M4HM87P-00 /mnt/sradio/TEST_RESULTS/ - - https://gitlab.eurecom.fr/oai/openairinterface5g.git --> - + https://gitlab.eurecom.fr/oai1B/openairinterface5g.git + + https://gitlab.eurecom.fr/oai/openair-cn.git --> - Enhancement-142-OAI_UE_autotest_framework - + develop1B + develop1B_integration_w49 --> + - develop @@ -30,12 +35,21 @@ yanbo-M4HM87P-00 - + + + + + + + + + + lte-softmodem-noS1 @@ -62,7 +76,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -164,7 +178,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -271,7 +285,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -373,7 +387,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -475,7 +489,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -577,7 +591,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -679,7 +693,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -781,7 +795,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -884,7 +898,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -986,7 +1000,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -1088,7 +1102,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -1190,7 +1204,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -1292,7 +1306,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -1395,7 +1409,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -1497,7 +1511,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -1599,7 +1613,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -1675,57 +1689,6 @@ unit_of_meas = ""/> - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 --single-thread-disable --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB --ue-autotest-trace - source ./targets/bin/init_nas_nos1 UE - - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS28 - 36 - - - - - lte-softmodem-noS1 @@ -1804,7 +1767,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -1907,7 +1870,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r50 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r50 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -2010,7 +1973,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r50 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r50 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test @@ -2089,54 +2052,6 @@ - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 512K - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB --ue-autotest-trace - source ./targets/bin/init_nas_nos1 UE - - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS00 - 36 - - - - lte-softmodem-noS1 @@ -2152,7 +2067,7 @@ $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf -W -m 28 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 6M + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 30M @@ -2164,7 +2079,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r50 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r50 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S iperf -s -i 1 -u @@ -2240,54 +2155,6 @@ unit_of_meas = ""/> - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB --ue-autotest-trace - source ./targets/bin/init_nas_nos1 UE - - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS09 - 36 - - - - @@ -2340,55 +2207,6 @@ - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB --ue-autotest-trace - source ./targets/bin/init_nas_nos1 UE - - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS10 - 36 - - - - - lte-softmodem-noS1 @@ -2441,54 +2259,6 @@ - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB --ue-autotest-trace - source ./targets/bin/init_nas_nos1 UE - - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS16 - 36 - - - - @@ -2542,55 +2312,6 @@ - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB --ue-autotest-trace - source ./targets/bin/init_nas_nos1 UE - - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS17 - 36 - - - - - lte-softmodem-noS1 @@ -2645,54 +2366,6 @@ - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB --ue-autotest-trace - source ./targets/bin/init_nas_nos1 UE - - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS19 - 36 - - - - @@ -2745,54 +2418,6 @@ - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 - sleep 30;iperf -c 10.0.1.9 -i 1 -u -b 10M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB --ue-autotest-trace - source ./targets/bin/init_nas_nos1 UE - - sleep 5; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS27 - 36 - - - - @@ -2821,7 +2446,7 @@ -c --UE -w USRP --noS1 --eNB --ue-autotest-trace source ./targets/bin/init_nas_nos1 UE - sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S iperf -s -i 1 -u @@ -2894,5 +2519,696 @@ unit_of_meas = ""/> + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 512K + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS00 + 36 + + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS09 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS10 + 36 + + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS16 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS17 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS19 + 36 + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 + sleep 30;iperf -c 10.0.1.9 -i 1 -u -b 15M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 5; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS27 + 36 + + + + + + + + + + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + + + + UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS28 + 36 + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 18000 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 --single-thread-disable --phy-test + + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S --phy-test + + + + + + False + + + + UE_USRP.NOS1.PHYTEST_STAB.BAND7.5MHZ.MCS28 + 16 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 + sleep 30;iperf -c 10.0.1.9 -i 1 -u -b 13700K + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 5; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 200 + + False + + + + + UE_USRP.NOS1.DATA_IPERF_DL.BAND7.5MHZ.MCS28 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 3600 + UE_USRP.NOS1.DATA_IPERF_STAB_DL.BAND7.5MHZ.MCS28 + 16 + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 + sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 -u + + 2800 + + False + + + + + + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 + sleep 30;iperf -c 10.0.1.9 -i 1 + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 5; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r25 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 + + 200 + + False + + + + + UE_USRP.NOS1.DATA_IPERF_TCP_DL.BAND7.5MHZ.MCS28 + 36 + + + + + lte-softmodem-noS1 + + imb182-desktop + yanbo-M4HM87P-00 + 300 + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c -w USRP --eNB --noS1 + source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB + + $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 + -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.50PRB.usrpb210.conf -W -m 28 + sleep 80;iperf -c 10.0.1.9 -i 1 + + + + False + + /tmp + + $OPENAIR_DIR/cmake_targets/build_oai + -c --UE -w USRP --noS1 --eNB --ue-autotest-trace + source ./targets/bin/init_nas_nos1 UE + + sleep 20; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2660000000 -r50 --ue-scan-carrier --ue-txgain 85 -A 20 --ue-rxgain 125 -S + + iperf -s -i 1 + + 200 + + False + UE_USRP.NOS1.DATA_IPERF_TCP_DL.BAND7.10MHZ.MCS28 + 36 + + + + + + + + + + + + From 8db3583b09d8be1ef5e95a146fa7f1c3c014821a Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 9 Dec 2016 17:47:29 +0100 Subject: [PATCH 397/413] integration fix: add usim_test to at_nas --- openair3/NAS/UE/UEprocess.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair3/NAS/UE/UEprocess.c b/openair3/NAS/UE/UEprocess.c index 248633c3a1..20af58dac6 100644 --- a/openair3/NAS/UE/UEprocess.c +++ b/openair3/NAS/UE/UEprocess.c @@ -71,6 +71,8 @@ static void _nas_signal_handler(int signal); static void _nas_clean(int usr_fd, int net_fd); +uint8_t usim_test = 0; + /****************************************************************************/ /****************** E X P O R T E D F U N C T I O N S ******************/ /****************************************************************************/ From 0a9d013f59c24f7f56c1629ef02e494f3442fc05 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 9 Dec 2016 17:47:49 +0100 Subject: [PATCH 398/413] integration fix: LOG_I/LOG_D do not exist when compiling at_nas_ue Use LOG_TRACE instead. --- openair3/NAS/COMMON/EMM/MSG/SecurityModeCommand.c | 2 +- openair3/NAS/COMMON/EMM/MSG/SecurityModeComplete.c | 6 +++--- openair3/NAS/COMMON/IES/MobileIdentity.c | 2 +- openair3/NAS/UE/EMM/SAP/emm_recv.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openair3/NAS/COMMON/EMM/MSG/SecurityModeCommand.c b/openair3/NAS/COMMON/EMM/MSG/SecurityModeCommand.c index c89a9f5bb7..a1a34f9495 100644 --- a/openair3/NAS/COMMON/EMM/MSG/SecurityModeCommand.c +++ b/openair3/NAS/COMMON/EMM/MSG/SecurityModeCommand.c @@ -72,7 +72,7 @@ int decode_security_mode_command(security_mode_command_msg *security_mode_comman decoded += decoded_result; /* Set corresponding mask to 1 in presencemask */ security_mode_command->presencemask |= SECURITY_MODE_COMMAND_IMEISV_REQUEST_PRESENT; - LOG_I(NAS," SECURITY MODE COMMAND: IMEISV_REQUEST: %d \n",security_mode_command->imeisvrequest); + LOG_TRACE(INFO," SECURITY MODE COMMAND: IMEISV_REQUEST: %d \n",security_mode_command->imeisvrequest); break; diff --git a/openair3/NAS/COMMON/EMM/MSG/SecurityModeComplete.c b/openair3/NAS/COMMON/EMM/MSG/SecurityModeComplete.c index 80ceeb34d7..3258134feb 100644 --- a/openair3/NAS/COMMON/EMM/MSG/SecurityModeComplete.c +++ b/openair3/NAS/COMMON/EMM/MSG/SecurityModeComplete.c @@ -76,11 +76,11 @@ int encode_security_mode_complete(security_mode_complete_msg *security_mode_comp /* Checking IEI and pointer */ CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, SECURITY_MODE_COMPLETE_MINIMUM_LENGTH, len); - LOG_I(NAS,"SECURITY MODE COMMAND COMPLETE: presencemask: %d \n",security_mode_complete->presencemask); + LOG_TRACE(INFO,"SECURITY MODE COMMAND COMPLETE: presencemask: %d \n",security_mode_complete->presencemask); if ((security_mode_complete->presencemask & SECURITY_MODE_COMPLETE_IMEISV_PRESENT) == SECURITY_MODE_COMPLETE_IMEISV_PRESENT) { - LOG_I(NAS,"SECURITY MODE COMMAND COMPLETE: encode imeisv \n"); + LOG_TRACE(INFO,"SECURITY MODE COMMAND COMPLETE: encode imeisv \n"); if ((encode_result = encode_mobile_identity(&security_mode_complete->imeisv, SECURITY_MODE_COMPLETE_IMEISV_IEI, buffer + encoded, len - @@ -90,7 +90,7 @@ int encode_security_mode_complete(security_mode_complete_msg *security_mode_comp else encoded += encode_result; } - LOG_I(NAS,"SECURITY MODE COMMAND COMPLETE done !!! \n"); + LOG_TRACE(INFO,"SECURITY MODE COMMAND COMPLETE done !!! \n"); return encoded; } diff --git a/openair3/NAS/COMMON/IES/MobileIdentity.c b/openair3/NAS/COMMON/IES/MobileIdentity.c index 59cf4dc44f..4651fa0047 100644 --- a/openair3/NAS/COMMON/IES/MobileIdentity.c +++ b/openair3/NAS/COMMON/IES/MobileIdentity.c @@ -575,7 +575,7 @@ static int encode_imei_mobile_identity(ImeiMobileIdentity_t *imei, uint8_t *buff static int encode_imeisv_mobile_identity(ImeisvMobileIdentity_t *imeisv, uint8_t *buffer) { uint32_t encoded = 0; - LOG_I(NAS,"SECURITY MODE COMMAND COMPLETE: encode_imeisv_mobile_identity \n"); + LOG_TRACE(INFO,"SECURITY MODE COMMAND COMPLETE: encode_imeisv_mobile_identity \n"); *(buffer + encoded) = 0x00 | (imeisv->digit1 << 4) | (imeisv->oddeven << 3) | (imeisv->typeofidentity); diff --git a/openair3/NAS/UE/EMM/SAP/emm_recv.c b/openair3/NAS/UE/EMM/SAP/emm_recv.c index 60b504f1ce..0ad41b09d8 100644 --- a/openair3/NAS/UE/EMM/SAP/emm_recv.c +++ b/openair3/NAS/UE/EMM/SAP/emm_recv.c @@ -140,7 +140,7 @@ int emm_recv_attach_accept(attach_accept_msg *msg, int *emm_cause) // supported cases: // typeoflist = 1 Or // typeoflist = 0 and numberofelements = 1 (ie numberofelements equal to zero see 3gpp 24.301 9.9.3.33.1) - LOG_D(NAS,"attach accept type of list: %d, number of element: %d\n",msg->tailist.typeoflist, msg->tailist.numberofelements); + LOG_TRACE(DEBUG,"attach accept type of list: %d, number of element: %d\n",msg->tailist.typeoflist, msg->tailist.numberofelements); if (!( (msg->tailist.typeoflist == TRACKING_AREA_IDENTITY_LIST_ONE_PLMN_CONSECUTIVE_TACS) || ((msg->tailist.typeoflist == 0) && ( msg->tailist.numberofelements == 0)) ) @@ -472,7 +472,7 @@ int emm_recv_security_mode_command(security_mode_command_msg *msg, * Message processing */ /* Execute the security mode control procedure initiated by the network */ - LOG_I(NAS,"Execute the security mode control procedure initiated by the network: imeisvrequest %d\n",msg->imeisvrequest); + LOG_TRACE(INFO,"Execute the security mode control procedure initiated by the network: imeisvrequest %d\n",msg->imeisvrequest); rc = emm_proc_security_mode_command( msg->naskeysetidentifier.tsc != NAS_KEY_SET_IDENTIFIER_MAPPED, msg->naskeysetidentifier.naskeysetidentifier, From a574c3d31bc4c7b13c3831e162b97acf10715242 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 12 Dec 2016 09:22:01 +0100 Subject: [PATCH 399/413] integration fix: wrong license --- openair1/SCHED/srs_pc.c | 48 +++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/openair1/SCHED/srs_pc.c b/openair1/SCHED/srs_pc.c index 461d230975..98049b2ed0 100644 --- a/openair1/SCHED/srs_pc.c +++ b/openair1/SCHED/srs_pc.c @@ -1,31 +1,23 @@ -/******************************************************************************* - 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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE - - *******************************************************************************/ +/* + * 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 srs_pc.c * \brief Implementation of UE SRS Power Control procedures from 36.213 LTE specifications (Section From 5976ea4a95a585b78674ac89b14394cf3e96d6ce Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 12 Dec 2016 09:22:50 +0100 Subject: [PATCH 400/413] hotfix: attempt for a better gitlab CI setup Not sure it's the right thing to do, but this commit should reduce fake builds. --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index aa11892fa6..15c44aed22 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -34,4 +34,5 @@ job1: - sshpass -p "$OAI_PASS" rsync -az -e "ssh -o StrictHostKeyChecking=no " --rsync-path="mkdir -p $NFS_TEST_RESULTS_DIR && rsync" $OPENAIR_DIR/cmake_targets/autotests/log $OAI_USER@localhost:$NFS_TEST_RESULTS_DIR - sshpass -p "$OAI_PASS" rsync -az -e "ssh -o StrictHostKeyChecking=no " --rsync-path="mkdir -p $EXTERNAL_SHARE_DIR && rsync" $OPENAIR_DIR/cmake_targets/autotests/log $OAI_USER@localhost:$EXTERNAL_SHARE_DIR - cat $OPENAIR_DIR/cmake_targets/autotests/log/results_autotests.xml - when: manual + only: + - triggers From e04e8a62cc3e35221d5150c56c5be38d8defe8ab Mon Sep 17 00:00:00 2001 From: hbilel Date: Mon, 12 Dec 2016 11:45:22 +0100 Subject: [PATCH 401/413] remove mac-struct usage from phy --- openair1/PHY/INIT/lte_init.c | 8 ++++++++ openair1/PHY/LTE_TRANSPORT/dci_tools.c | 4 ++-- openair1/PHY/LTE_TRANSPORT/defs.h | 2 ++ openair1/PHY/LTE_TRANSPORT/phich.c | 6 +++--- openair1/SCHED/phy_procedures_lte_ue.c | 4 ++-- openair2/LAYER2/MAC/config.c | 1 + openair2/PHY_INTERFACE/defs.h | 3 +++ 7 files changed, 21 insertions(+), 7 deletions(-) diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c index 035410eb25..c10e4dd3c1 100644 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -746,6 +746,14 @@ void phy_config_dedicated_scell_eNB(uint8_t Mod_id, } #endif +void phy_config_harq_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, + uint16_t max_harq_tx ) +{ + + PHY_VARS_UE *phy_vars_ue = PHY_vars_UE_g[Mod_id][CC_id]; + phy_vars_ue->ulsch[eNB_id]->Mlimit = max_harq_tx; +} + void phy_config_dedicated_ue(uint8_t Mod_id,int CC_id,uint8_t eNB_id, struct PhysicalConfigDedicated *physicalConfigDedicated ) { diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 92836ebcf9..e73bb94d41 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -6451,7 +6451,7 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, // ue->Mod_id,harq_pid, // proc->frame_rx, // subframe, - // UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx); + // ulsch->Mlimit); //#endif if (ulsch->harq_processes[harq_pid]->round > 0) // NACK detected on phich @@ -6460,7 +6460,7 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, ulsch->harq_processes[harq_pid] = ulsch->harq_processes[8]; // LOG_I(PHY," Adaptative retransmission - copy temporary harq Process to current harq process. [harqId %d round %d] \n",harq_pid, ulsch->harq_processes[8]->round); - if (ulsch->harq_processes[harq_pid]->round >= UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx) + if (ulsch->harq_processes[harq_pid]->round >= ulsch->Mlimit) //UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx) { ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 0; ulsch->harq_processes[harq_pid]->round = 0; diff --git a/openair1/PHY/LTE_TRANSPORT/defs.h b/openair1/PHY/LTE_TRANSPORT/defs.h index f8d36d3bd4..c41df6c931 100644 --- a/openair1/PHY/LTE_TRANSPORT/defs.h +++ b/openair1/PHY/LTE_TRANSPORT/defs.h @@ -346,6 +346,8 @@ typedef struct { uint8_t num_cba_dci[10]; /// allocated CBA RNTI uint16_t cba_rnti[4];//NUM_MAX_CBA_GROUP]; + /// UL max-harq-retransmission + uint8_t Mlimit; } LTE_UE_ULSCH_t; typedef struct { diff --git a/openair1/PHY/LTE_TRANSPORT/phich.c b/openair1/PHY/LTE_TRANSPORT/phich.c index 9a32876602..c7cc188893 100644 --- a/openair1/PHY/LTE_TRANSPORT/phich.c +++ b/openair1/PHY/LTE_TRANSPORT/phich.c @@ -1381,13 +1381,13 @@ void rx_phich(PHY_VARS_UE *ue, HI16, nseq_PHICH, ngroup_PHICH, - UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx); + ulsch->Mlimit); //#endif // ulsch->harq_processes[harq_pid]->Ndi = 0; ulsch->harq_processes[harq_pid]->round++; - if ( ulsch->harq_processes[harq_pid]->round >= (UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx - 1) ) + if ( ulsch->harq_processes[harq_pid]->round >= (ulsch->Mlimit - 1) ) { // this is last push re transmission ulsch->harq_processes[harq_pid]->rvidx = rv_table[ulsch->harq_processes[harq_pid]->round&3]; @@ -1402,7 +1402,7 @@ void rx_phich(PHY_VARS_UE *ue, //ulsch->harq_processes[harq_pid]->round = 0; //LOG_I(PHY,"PUSCH MAX Retransmission acheived ==> flush harq buff (%d) \n",harq_pid); - //LOG_I(PHY,"[HARQ-UL harqId: %d] PHICH NACK MAX RETRANS(%d) ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag, ulsch->harq_processes[harq_pid]->round); + //LOG_I(PHY,"[HARQ-UL harqId: %d] PHICH NACK MAX RETRANS(%d) ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, ulsch->Mlimit, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag, ulsch->harq_processes[harq_pid]->round); } else { diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 5dc629b90b..883099be30 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -1235,8 +1235,8 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB // deactivate service request // ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 0; - LOG_D(PHY,"Generating PUSCH (Abssubframe: %d.%d): harq-Id: %d, round: %d, MaxReTrans: %d \n",frame_tx,subframe_tx,harq_pid,ue->ulsch[eNB_id]->harq_processes[harq_pid]->round,UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx); - if (ue->ulsch[eNB_id]->harq_processes[harq_pid]->round >= (UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx - 1)) + LOG_D(PHY,"Generating PUSCH (Abssubframe: %d.%d): harq-Id: %d, round: %d, MaxReTrans: %d \n",frame_tx,subframe_tx,harq_pid,ue->ulsch[eNB_id]->harq_processes[harq_pid]->round,ue->ulsch[eNB_id]->Mlimit); + if (ue->ulsch[eNB_id]->harq_processes[harq_pid]->round >= (ue->ulsch[eNB_id]->Mlimit - 1)) { LOG_D(PHY,"PUSCH MAX Retransmission acheived ==> send last pusch (%d) \n"); ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 0; diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c index 2ec37a423e..e4252ed500 100644 --- a/openair2/LAYER2/MAC/config.c +++ b/openair2/LAYER2/MAC/config.c @@ -221,6 +221,7 @@ rrc_mac_config_req( } else { UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx = (uint16_t) MAC_MainConfig__ul_SCH_Config__maxHARQ_Tx_n5; } + mac_xface->phy_config_harq_ue(Mod_idP,0,eNB_index,UE_mac_inst[Mod_idP].scheduling_info.maxHARQ_Tx); if (mac_MainConfig->ul_SCH_Config->retxBSR_Timer) { UE_mac_inst[Mod_idP].scheduling_info.retxBSR_Timer = (uint16_t) mac_MainConfig->ul_SCH_Config->retxBSR_Timer; diff --git a/openair2/PHY_INTERFACE/defs.h b/openair2/PHY_INTERFACE/defs.h index 8c711e971d..aeab9dfe66 100644 --- a/openair2/PHY_INTERFACE/defs.h +++ b/openair2/PHY_INTERFACE/defs.h @@ -185,6 +185,9 @@ typedef struct { void (*phy_config_dedicated_ue)(module_id_t Mod_id,int CC_id,uint8_t CH_index, struct PhysicalConfigDedicated *physicalConfigDedicated); + /// PHY-Config-harq UE + void (*phy_config_harq_ue)(module_id_t Mod_id,int CC_id,uint8_t CH_index, + uint16_t max_harq_tx); /// Configure Common PHY parameters from SIB1 void (*phy_config_sib1_ue)(module_id_t Mod_id,int CC_id,uint8_t CH_index, TDD_Config_t *tdd_config, From e0bf855fbf38f1e2373f6b9b36d1c45acbe5f9a8 Mon Sep 17 00:00:00 2001 From: hbilel Date: Mon, 12 Dec 2016 12:12:27 +0100 Subject: [PATCH 402/413] initialize max retans tx Mlimit --- openair1/PHY/INIT/defs.h | 12 ++++++++++++ openair1/PHY/LTE_TRANSPORT/ulsch_coding.c | 2 ++ openair2/LAYER2/MAC/main.c | 1 + 3 files changed, 15 insertions(+) diff --git a/openair1/PHY/INIT/defs.h b/openair1/PHY/INIT/defs.h index 1874c4e8c7..2b65bebc8d 100644 --- a/openair1/PHY/INIT/defs.h +++ b/openair1/PHY/INIT/defs.h @@ -206,7 +206,19 @@ void phy_config_dedicated_ue(module_id_t Mod_id, uint8_t CH_index, struct PhysicalConfigDedicated *physicalConfigDedicated); +/*! +\fn void phy_config_harq_ue(module_id_t Mod_id,uint8_t CC_id,uint8_t CH_index, + uint16_t max_harq_tx) +\brief Configure UE UL max harq Tx. +\details Invoked upon reception of RRCConnectionSetup or RRCConnectionReconfiguration from eNB. +@param Mod_id Instance ID for eNB +@param CC_id Component Carrier index +@param CH_index Index of eNB for this configuration +@param max_harq_tx max harq tx information + */ +void phy_config_harq_ue(module_id_t Mod_id,int CC_id,uint8_t CH_index, + uint16_t max_harq_tx); /** \brief Configure UE MBSFN common parameters. \details Invoked upon reception of SIB13 from eNB. diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c index fe4e05747a..4559aaa326 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_coding.c @@ -140,6 +140,8 @@ LTE_UE_ULSCH_t *new_ue_ulsch(unsigned char N_RB_UL, uint8_t abstraction_flag) if (ulsch) { memset(ulsch,0,sizeof(LTE_UE_ULSCH_t)); + ulsch->Mlimit = 4; + for (i=0; i<8; i++) { ulsch->harq_processes[i] = (LTE_UL_UE_HARQ_t *)malloc16(sizeof(LTE_UL_UE_HARQ_t)); diff --git a/openair2/LAYER2/MAC/main.c b/openair2/LAYER2/MAC/main.c index 0fe9d63b6f..203bd3f36f 100644 --- a/openair2/LAYER2/MAC/main.c +++ b/openair2/LAYER2/MAC/main.c @@ -527,6 +527,7 @@ int l2_init(LTE_DL_FRAME_PARMS *frame_parms,int eMBMS_active, char *uecap_xer,ui mac_xface->phy_config_dedicated_eNB = phy_config_dedicated_eNB; mac_xface->phy_config_dedicated_ue = phy_config_dedicated_ue; + mac_xface->phy_config_harq_ue = phy_config_harq_ue; mac_xface->get_lte_frame_parms = get_lte_frame_parms; mac_xface->get_mu_mimo_mode = get_mu_mimo_mode; From 17aefade3fece7f4e0fdbbb84c1e8fc8c236ace0 Mon Sep 17 00:00:00 2001 From: hbilel Date: Mon, 12 Dec 2016 12:48:48 +0100 Subject: [PATCH 403/413] remove temporary harq process for ue (ul) --- openair1/PHY/LTE_TRANSPORT/dci_tools.c | 6 +++--- openair1/PHY/LTE_TRANSPORT/defs.h | 2 +- openair1/PHY/LTE_TRANSPORT/phich.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index e73bb94d41..a1c118529a 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -6453,11 +6453,11 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, // subframe, // ulsch->Mlimit); //#endif - +/* if (ulsch->harq_processes[harq_pid]->round > 0) // NACK detected on phich { // ulsch->harq_processes[harq_pid]->round++; already done on phich_rx - ulsch->harq_processes[harq_pid] = ulsch->harq_processes[8]; + // ulsch->harq_processes[harq_pid] = ulsch->harq_processes[8]; // LOG_I(PHY," Adaptative retransmission - copy temporary harq Process to current harq process. [harqId %d round %d] \n",harq_pid, ulsch->harq_processes[8]->round); if (ulsch->harq_processes[harq_pid]->round >= ulsch->Mlimit) //UE_mac_inst[eNB_id].scheduling_info.maxHARQ_Tx) @@ -6479,7 +6479,7 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, //LOG_I(PHY," [HARQ-UL harqId: %d] Adaptative retransmission NACK ==> subframe_scheduling_flag = %d round: %d\n", harq_pid, ulsch->harq_processes[harq_pid]->subframe_scheduling_flag,ulsch->harq_processes[harq_pid]->round); } } - +*/ } } diff --git a/openair1/PHY/LTE_TRANSPORT/defs.h b/openair1/PHY/LTE_TRANSPORT/defs.h index c41df6c931..442fd82167 100644 --- a/openair1/PHY/LTE_TRANSPORT/defs.h +++ b/openair1/PHY/LTE_TRANSPORT/defs.h @@ -283,7 +283,7 @@ typedef struct { /// SRS active flag uint8_t srs_active; /// Pointers to 8 HARQ processes for the ULSCH - LTE_UL_UE_HARQ_t *harq_processes[9]; + LTE_UL_UE_HARQ_t *harq_processes[8]; /// Pointer to CQI data uint8_t o[MAX_CQI_BYTES]; /// Length of CQI data (bits) diff --git a/openair1/PHY/LTE_TRANSPORT/phich.c b/openair1/PHY/LTE_TRANSPORT/phich.c index c7cc188893..989567ca34 100644 --- a/openair1/PHY/LTE_TRANSPORT/phich.c +++ b/openair1/PHY/LTE_TRANSPORT/phich.c @@ -1441,7 +1441,7 @@ void rx_phich(PHY_VARS_UE *ue, // rely only on DCI0 decoding and check if NDI has toggled // save current harq_processes content in temporary struct // harqId-8 corresponds to the temporary struct. In total we have 8 harq process(0 ..7) + 1 temporary harq process() - ulsch->harq_processes[8] = ulsch->harq_processes[harq_pid]; + //ulsch->harq_processes[8] = ulsch->harq_processes[harq_pid]; ulsch->harq_processes[harq_pid]->subframe_scheduling_flag =0; ulsch->harq_processes[harq_pid]->status = IDLE; From 7f4c961d82dca3c7e10be4a07e18729ea3e6bb57 Mon Sep 17 00:00:00 2001 From: Chia-Yu Chang Date: Mon, 12 Dec 2016 18:41:26 +0100 Subject: [PATCH 404/413] add T messages for FLEXRAN and fix a complication error in FLEXRAN --- common/utils/T/T_messages.txt | 21 +++++++++++++++++++ .../MAC/flexran_agent_scheduler_dataplane.c | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index 2d2ee3c489..af2579cb1b 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -423,6 +423,27 @@ ID = LEGACY_ENB_APP_TRACE GROUP = ALL:LEGACY_ENB_APP:LEGACY_GROUP_TRACE:LEGACY FORMAT = string,log +ID = LEGACY_FLEXRAN_AGENT_INFO + DESC = FLEXRAN_AGENT legacy logs - info level + GROUP = ALL:LEGACY_FLEXRAN_AGENT:LEGACY_GROUP_INFO:LEGACY + FORMAT = string,log +ID = LEGACY_FLEXRAN_AGENT_ERROR + DESC = FLEXRAN_AGENT legacy logs - error level + GROUP = ALL:LEGACY_FLEXRAN_AGENT:LEGACY_GROUP_ERROR:LEGACY + FORMAT = string,log +ID = LEGACY_FLEXRAN_AGENT_WARNING + DESC = FLEXRAN_AGENT legacy logs - warning level + GROUP = ALL:LEGACY_FLEXRAN_AGENT:LEGACY_GROUP_WARNING:LEGACY + FORMAT = string,log +ID = LEGACY_FLEXRAN_AGENT_DEBUG + DESC = FLEXRAN_AGENT legacy logs - debug level + GROUP = ALL:LEGACY_FLEXRAN_AGENT:LEGACY_GROUP_DEBUG:LEGACY + FORMAT = string,log +ID = LEGACY_FLEXRAN_AGENT_TRACE + DESC = FLEXRAN_AGENT legacy logs - trace level + GROUP = ALL:LEGACY_FLEXRAN_AGENT:LEGACY_GROUP_TRACE:LEGACY + FORMAT = string,log + ID = LEGACY_SCTP_INFO DESC = SCTP legacy logs - info level GROUP = ALL:LEGACY_SCTP:LEGACY_GROUP_INFO:LEGACY diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c index 6d3c32a516..ff3ef32bd6 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c @@ -303,7 +303,7 @@ void flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, if (opt_enabled == 1) { trace_pdu(1, (uint8_t *)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS, mod_id, 3, UE_RNTI(mod_id, UE_id), - eNB->subframe,0,0); + eNB->frame, eNB->subframe,0,0); LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", mod_id, CC_id, frame, UE_RNTI(mod_id,UE_id), TBS); } From 01c50449c3c7a8ced78f6d0907e0bc56a9ddbf66 Mon Sep 17 00:00:00 2001 From: Chia-Yu Chang Date: Mon, 12 Dec 2016 18:43:37 +0100 Subject: [PATCH 405/413] fix the AVX2 compilation directive --- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 0ce810a52c..7f4f4cf5f6 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -1442,7 +1442,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, } #if defined(__x86_64__)||defined(__i386__) -#ifndef __AVX2 +#ifndef __AVX2__ for (iprime=0; iprimee[iprime]) = *((__m128i *)&y[j2]); #else From ca078ff54945b97c84be7ddcf2e6703cbd8dba13 Mon Sep 17 00:00:00 2001 From: hbilel Date: Tue, 13 Dec 2016 17:38:43 +0100 Subject: [PATCH 406/413] fix compilation error --- openair2/LAYER2/MAC/ue_procedures.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 0761177a19..cdac22c486 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -2127,14 +2127,14 @@ ue_scheduler( } //Check whether Regular BSR is triggered - if (update_bsr(module_idP,frameP, subframeP,eNB_indexP) == TRUE) { + if (update_bsr(module_idP,txFrameP, txSubframeP,eNB_indexP) == TRUE) { // call SR procedure to generate pending SR and BSR for next PUCCH/PUSCH TxOp. This should implement the procedures // outlined in Sections 5.4.4 an 5.4.5 of 36.321 UE_mac_inst[module_idP].scheduling_info.SR_pending= 1; // Regular BSR trigger UE_mac_inst[module_idP].BSR_reporting_active |= BSR_TRIGGER_REGULAR; LOG_D(MAC,"[UE %d][BSR] Regular BSR Triggered Frame %d subframe %d SR for PUSCH is pending\n", - module_idP, frameP,subframeP); + module_idP, txFrameP,txSubframeP); } // UE has no valid phy config dedicated || no valid/released SR From 1167dd6b33b44d5c078108874cbe9f6d6478711b Mon Sep 17 00:00:00 2001 From: gabrielC Date: Wed, 14 Dec 2016 10:16:54 +0100 Subject: [PATCH 407/413] ue autotest merge part2 --- .../autotests/patches/CmakeLists.patch | 12 - .../autotest_ue_cell_synch_event.patch | 20 - .../autotest_ue_dlsch_bitrate_metric.patch | 18 - .../patches/autotest_ue_offsets_metric.patch | 27 - .../autotests/patches/build_oai.patch | 40 - .../autotests/run_lte-softmodem-nos1_tests.py | 2595 ------------- .../autotests/testsuite_ue_noS1_eurecom.xml | 3214 ----------------- .../CODING/3gpplte_turbo_decoder_sse_8bit.c | 5 - 8 files changed, 5931 deletions(-) delete mode 100644 cmake_targets/autotests/patches/CmakeLists.patch delete mode 100644 cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch delete mode 100644 cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch delete mode 100644 cmake_targets/autotests/patches/autotest_ue_offsets_metric.patch delete mode 100644 cmake_targets/autotests/patches/build_oai.patch delete mode 100755 cmake_targets/autotests/run_lte-softmodem-nos1_tests.py delete mode 100644 cmake_targets/autotests/testsuite_ue_noS1_eurecom.xml diff --git a/cmake_targets/autotests/patches/CmakeLists.patch b/cmake_targets/autotests/patches/CmakeLists.patch deleted file mode 100644 index 1e54e3a0f3..0000000000 --- a/cmake_targets/autotests/patches/CmakeLists.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt -index 07d92a1..b6a02d1 100644 ---- a/cmake_targets/CMakeLists.txt -+++ b/cmake_targets/CMakeLists.txt -@@ -235,6 +235,7 @@ add_boolean_option(DEBUG_OMG False "???") - add_boolean_option(XFORMS False "This adds the possibility to see the signal oscilloscope") - add_boolean_option(PRINT_STATS False "This adds the possibility to see the status") - add_boolean_option(T_TRACER False "Activate the T tracer, a debugging/monitoring framework" ) -+add_boolean_option(UE_AUTOTEST_TRACE False "Activate UE autotest specific logs") - - add_boolean_option(DEBUG_CONSOLE False "makes debugging easier, disables stdout/stderr buffering") - diff --git a/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch b/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch deleted file mode 100644 index 766b724c6c..0000000000 --- a/cmake_targets/autotests/patches/autotest_ue_cell_synch_event.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c -index 663978e..b77cb1b 100644 ---- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c -+++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c -@@ -476,6 +476,15 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) - //#endif - - if (ue->UE_scan_carrier == 0) { -+ -+ #if UE_AUTOTEST_TRACE -+ LOG_I(PHY,"[UE %d] AUTOTEST Cell Sync : frame = %d, rx_offset %d, freq_offset %d \n", -+ ue->Mod_id, -+ ue->proc.proc_rxtx[0].frame_rx, -+ ue->rx_offset, -+ ue->common_vars.freq_offset ); -+ #endif -+ - if (ue->mac_enabled==1) { - LOG_I(PHY,"[UE%d] Sending synch status to higher layers\n",ue->Mod_id); - //mac_resynch(); diff --git a/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch b/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch deleted file mode 100644 index 74139109f2..0000000000 --- a/cmake_targets/autotests/patches/autotest_ue_dlsch_bitrate_metric.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c -index 5dc629b..353a049 100644 ---- a/openair1/SCHED/phy_procedures_lte_ue.c -+++ b/openair1/SCHED/phy_procedures_lte_ue.c -@@ -3551,6 +3551,13 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin - LOG_D(PHY,"[UE %d] Calculating bitrate Frame %d: total_TBS = %d, total_TBS_last = %d, bitrate %f kbits\n", - ue->Mod_id,frame_rx,ue->total_TBS[eNB_id], - ue->total_TBS_last[eNB_id],(float) ue->bitrate[eNB_id]/1000.0); -+ -+ #if UE_AUTOTEST_TRACE -+ if ((frame_rx % 100 == 0)) { -+ LOG_I(PHY,"[UE %d] AUTOTEST Metric : UE_DLSCH_BITRATE = %5.2f kbps (frame = %d) \n", ue->Mod_id, (float) ue->bitrate[eNB_id]/1000.0, frame_rx); -+ } -+ #endif -+ - } - - diff --git a/cmake_targets/autotests/patches/autotest_ue_offsets_metric.patch b/cmake_targets/autotests/patches/autotest_ue_offsets_metric.patch deleted file mode 100644 index 85afe8703e..0000000000 --- a/cmake_targets/autotests/patches/autotest_ue_offsets_metric.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c -index 5dc629b..4d31ad3 100644 ---- a/openair1/SCHED/phy_procedures_lte_ue.c -+++ b/openair1/SCHED/phy_procedures_lte_ue.c -@@ -3347,6 +3347,22 @@ int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin - - // first slot has been processed (FFTs + Channel Estimation, PCFICH/PHICH/PDCCH) - -+ #if UE_AUTOTEST_TRACE -+ if ( (frame_rx % 10 == 0) && (subframe_rx == 0)) { -+ printf("AUTOTEST Metric : UE_FREQ_OFFSET = %d Hz (frame = %d) \n", ue->common_vars.freq_offset, frame_rx); -+ printf("AUTOTEST Metric : UE_RX_OFFSET = %d (frame = %d) \n", ue->rx_offset, frame_rx); -+ -+ printf("AUTOTEST Metric : RRC Measurments RSRP[0] %.2f dBm/RE, RSSI %.2f dBm, RSRQ[0] %.2f dB, N0 %d dBm/RE, NF %.1f dB (frame = %d)\n", -+ 10*log10(ue->measurements.rsrp[0])-ue->rx_total_gain_dB, -+ 10*log10(ue->measurements.rssi)-ue->rx_total_gain_dB, -+ 10*log10(ue->measurements.rsrq[0]), -+ ue->measurements.n0_power_tot_dBm, -+ (double)ue->measurements.n0_power_tot_dBm+132.24, -+ frame_rx); -+ } -+ #endif -+ -+ - // do procedures for C-RNTI - if (ue->dlsch[eNB_id][0]->active == 1) { - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN); diff --git a/cmake_targets/autotests/patches/build_oai.patch b/cmake_targets/autotests/patches/build_oai.patch deleted file mode 100644 index cf93b466e7..0000000000 --- a/cmake_targets/autotests/patches/build_oai.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai -index 25e9a1c..0b04bb7 100755 ---- a/cmake_targets/build_oai -+++ b/cmake_targets/build_oai -@@ -54,6 +54,7 @@ BUILD_DOXYGEN=0 - T_TRACER="False" - DISABLE_HARDWARE_DEPENDENCY="False" - CMAKE_BUILD_TYPE="" -+UE_AUTOTEST_TRACE="False" - trap handle_ctrl_c INT - - function print_help() { -@@ -130,6 +131,8 @@ Options - Enables the T tracer. - --disable-hardware-dependency - Disable HW dependency during installation -+--ue-autotest-trace -+ Enable specific traces for UE autotest framework - 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 -@@ -285,6 +288,10 @@ function main() { - echo_info "Disabling hardware dependency for compiling software" - DISABLE_HARDWARE_DEPENDENCY="True" - shift 1;; -+ --ue-autotest-trace) -+ UE_AUTOTEST_TRACE="True" -+ echo_info "Enabling autotest specific trace for UE" -+ shift 1;; - -h | --help) - print_help - exit 1;; -@@ -457,6 +464,7 @@ function main() { - echo "set (DEADLINE_SCHEDULER \"${DEADLINE_SCHEDULER_FLAG_USER}\" )" >>$cmake_file - echo "set (CPU_AFFINITY \"${CPU_AFFINITY_FLAG_USER}\" )" >>$cmake_file - echo "set ( T_TRACER $T_TRACER )" >> $cmake_file -+ echo "set (UE_AUTOTEST_TRACE $UE_AUTOTEST_TRACE)" >> $cmake_file - echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file - cd $DIR/$lte_build_dir/build - cmake .. diff --git a/cmake_targets/autotests/run_lte-softmodem-nos1_tests.py b/cmake_targets/autotests/run_lte-softmodem-nos1_tests.py deleted file mode 100755 index 2ece62ae16..0000000000 --- a/cmake_targets/autotests/run_lte-softmodem-nos1_tests.py +++ /dev/null @@ -1,2595 +0,0 @@ -#! /usr/bin/python -#/* -# * 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 -# */ - -# \author Rohit Gupta - Benoit ROBERT (benoit.robert@syrtem.com) -# \version 0.1 -# @ingroup _test - -# \Changelog -# 2016-11-18 : -# - Add progess bar during test execution update_progress() - -import tempfile -import threading -import sys -import traceback -import wave -import os -import time -import datetime -import getpass -import math #from time import clock -import xml.etree.ElementTree as ET -import re - -#from dict2xml import dict2xml as xmlify - -from colorama import Fore, Back, Style - -import numpy as np - -import log - -from openair import * - -import paramiko - -import subprocess -import commands -sys.path.append('/opt/ssh') -sys.path.append(os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/tools/')) - -from lib_autotest import * -import ssh -from ssh import SSHSession -import argparse - - -# update_progress() : Displays or updates a console progress bar -## Accepts a float between 0 and 1. Any int will be converted to a float. -## A value under 0 represents a 'halt'. -## A value at 1 or bigger represents 100% -def update_progress(progress, prefix_string): - barLength = 20 # Modify this to change the length of the progress bar - status = "" - #print "progress = "+ str(progress) - if isinstance(progress, int): - progress = float(progress) - if not isinstance(progress, float): - progress = 0 - status = "error: progress var must be float\r\n" - if progress < 0: - progress = 0 - status = "Halt...\r\n" - if progress >= 1: - progress = 1 - status = "Done...\r\n" - block = int(round(barLength*progress)) - text = "\r"+prefix_string+" [{0}] {1}% {2}".format( "="*block + " "*(barLength-block), progress*100, status) - sys.stdout.write(text) - sys.stdout.flush() - - -def exit_prog(exit_val): - print(Style.RESET_ALL), - sys.exit(exit_val) - -# \brief write a string to a file -# \param filename name of file -# \param string string to write -# \mode file opening mode (default=write) -def write_file(filename, string, mode="w"): - text_file = open(filename, mode) - text_file.write(string) - text_file.close() - -# \brief function to check if test case passed throughput test -# \param filename name of file which has throughput results (usually from iperf -s ... -# \param min_tput minimum throughput -# \param max_tuput maximum throughput -# \param average average throughput -# \param min_duration minimum duration of throughput -#The throughput values found in file must be higher than values from from arguments 2,3,4,5 -#The function returns True if throughput conditions are saisfied else it returns fails -def tput_test(filename, min_tput, max_tput, average, min_duration): - - if os.path.exists(filename): - with open (filename, "r") as myfile: - data=myfile.read() - p=re.compile('(\d*.\d*) Mbits/sec') - array=p.findall(data) - array = [ float(x) for x in array ] - duration = array.__len__() - if duration !=0: - min_list = min(array) - max_list = max(array) - average_list = np.mean(array) - else: - min_list = 0 - max_list = 0 - average_list=0 - tput_string=' ( '+ "min=%0.2f" % min_list + ' Mbps / ' + "max=%0.2f" % max_list + ' Mbps / ' + "avg=%0.2f" % average_list + ' Mbps / ' + "dur=%0.2f" % duration + ' s) ' - if (min_list >= min_tput and max_list >= max_tput and average_list >= average and duration >= min_duration): - return True , tput_string - else: - return False , tput_string - else: - return False , tput_string - -# \brief Convert string to float or return None if there is exception -def try_convert_to_float(string, fail=None): - try: - return float(string) - except Exception: - return fail; - -# \brief get throughput statistics from log file -# \param search_expr search expression found in test_case_list.xml file -# \param logfile_traffic logfile which has traffic statistics -def tput_test_search_expr (search_expr, logfile_traffic): - result=0 - tput_string='' - if search_expr !='': - if search_expr.find('throughput_test')!= -1 : - p= re.compile('min\s*=\s*(\d*.\d*)\s*Mbits/sec') - min_tput=p.findall(search_expr) - if min_tput.__len__()==1: - min_tput = min_tput[0] - else: - min_tput = None - - p= re.compile('max\s*=\s*(\d*.\d*)\s*Mbits/sec') - max_tput=p.findall(search_expr) - if max_tput.__len__()==1: - max_tput = max_tput[0] - else: - max_tput = None - - p= re.compile('average\s*=\s*(\d*.\d*)\s*Mbits/sec') - avg_tput=p.findall(search_expr) - if avg_tput.__len__()==1: - avg_tput=avg_tput[0] - else: - avg_tput = None - - p= re.compile('duration\s*=\s*(\d*.\d*)\s*s') - duration=p.findall(search_expr) - if duration.__len__()==1: - duration = duration[0] - else: - duration = None - - min_tput = try_convert_to_float(min_tput) - max_tput = try_convert_to_float(max_tput) - avg_tput = try_convert_to_float(avg_tput) - duration = try_convert_to_float(duration) - - if (min_tput != None and max_tput != None and avg_tput != None and duration != None ): - result, tput_string = tput_test(logfile_traffic, min_tput, max_tput, avg_tput, duration) - else: - result=1 - - return result, tput_string - -# \brief function to copy files to/from remote machine -# \param username user with which to make sftp connection -# \param password password of user -# \param hostname host to connect -# \ports port of remote machine on which server is listening -# \paramList This is list of operations as a set {operation: "get/put", localfile: "filename", remotefile: "filename" -# \param logfile Ignored currently and set once at the beginning of program -def sftp_module (username, password, hostname, ports, paramList,logfile): - #localD = localfile - #remoteD = remotefile - #fd, paramiko_logfile = tempfile.mkstemp() - #res = os.close(fd ) - #paramiko logfile path should not be changed with multiple calls. The logs seem to in first file regardless - error = "" - #The lines below are outside exception loop to be sure to terminate the test case if the network connectivity goes down or there is authentication failure - transport = paramiko.Transport((hostname, ports)) - transport.connect(username = username, password = password) - sftp = paramiko.SFTPClient.from_transport(transport) - # index =0 - for param in paramList: - try: - operation = param["operation"] - localD = param["localfile"] - remoteD = param["remotefile"] - if operation == "put": - sftp.put(remotepath=remoteD, localpath=localD) - elif operation == "get": - sftp.get(remotepath=remoteD, localpath=localD) - else : - print "sftp_module: unidentified operation:<" + operation + "> Exiting now" - print "hostname = " + hostname - print "ports = " + ports - print "localfile = " + localD - print "remotefile = " + remoteD - print "operation = " + operation - sys.exit() - except Exception, e: - error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) - error = error + '\n username = ' + username + '\n hostname = ' + hostname + '\n localfile = ' + localD + '\n remotefile = ' + remoteD + '\n operation = ' + operation + '\nlogfile = ' + logfile + '\n ports = ' + str(ports) + '\n' - error = error + traceback.format_exc() - print error - - sftp.close() - transport.close() - res = os.system('\n echo \'SFTP Module Log for Machine: <' + hostname + '> starts...\' >> ' + logfile + ' 2>&1 ') - res = os.system('cat ' + paramiko_logfile + ' >> ' + logfile + ' 2>&1 \n') - write_file(logfile, error, "a") - res = os.system('\n echo \'SFTP Module Log for Machine: <' + hostname + '> ends...\' >> ' + logfile + ' 2>&1 \n') - -# \brief bash script stub put at the end of scripts to terminate it -# \param timeout_cmd terminate script after timeout_cmd seconds -# \param terminate_missing_procs if True terminate all the processes launched by script if one of them terminates prematurely (due to error) -def finalize_deploy_script (timeout_cmd, terminate_missing_procs='False'): - cmd = 'declare -i timeout_cmd='+str(timeout_cmd) + '\n' - if terminate_missing_procs == 'True': - cmd = cmd + """ - #The code below checks if one the processes launched in background has crashed. - #If it does, then the code below terminates all the child processes created by this script - declare -i wakeup_interval=1 - declare -i step=0 - echo \"Array pid = ${array_exec_pid[@]}\" - while [ "$step" -lt "$timeout_cmd" ] - do - declare -i break_while_loop=0 - #Iterate over each process ID in array_exec_pid - for i in "${array_exec_pid[@]}" - do - numchild=`pstree -p $i | perl -ne 's/\((\d+)\)/print " $1"/ge' |wc -w` - echo "PID = $i, numchild = $numchild" - if [ "$numchild" -eq "0" ] ; then - echo "Process ID $i has finished unexpectedly. Now preparing to kill all the processes " - break_while_loop=1 - break - fi - done - if [ "$break_while_loop" -eq "1" ] ; then - break - fi - step=$(( step + wakeup_interval )) - sleep $wakeup_interval - done - echo "Final time step (Duration of test case) = $step " - date - """ - else: - #We do not terminate the script if one of the processes has existed prematurely - cmd = cmd + 'sleep ' + str(timeout_cmd) + ' ; date \n' - - return cmd - -# \brief run python script and update config file params of test case -# \param oai module with already open connection -# \param config_string config string taken from xml file -# \param logdirRepo directory of remote repository -# \param python_script python script location -def update_config_file(oai, config_string, logdirRepo, python_script): - cmd="" - if config_string : - stringArray = config_string.splitlines() - #python_script = '$OPENAIR_DIR/targets/autotests/tools/search_repl.py' - for string in stringArray: - #split the string based on space now - string1=string.split() - cmd = cmd + 'python ' + python_script + ' ' + logdirRepo+'/'+string1[0] + ' ' + string1[1] + ' '+ string1[2] + '\n' - #cmd = cmd + 'perl -p -i -e \'s/'+ string1[1] + '\\s*=\\s*"\\S*"\\s*/' + string1[1] + ' = "' + string1[2] +'"' + '/g\' ' + logdirRepo + '/' +string1[0] + '\n' - return cmd - #result = oai.send_recv(cmd) - -# \brief thread safe sshsession wrapper due to occasional connection issues with ssh -# \param machine name of machine -# \param username user login for remote machine -# \param key_file file name which has keys to enable passwordless login -# \param password password for remote machine -# \param logdir_remote remote directory -# \param logdir_local_base local directory -# \param operation operation to perform (get_all, put_all) transfers recursively for directories -def SSHSessionWrapper(machine, username, key_file, password, logdir_remote, logdir_local_base, operation): - max_tries = 10 - i=0 - while i <= max_tries: - i = i +1 - try: - ssh = SSHSession(machine , username, key_file, password) - if operation == "get_all": - ssh.get_all(logdir_remote , logdir_local_base) - elif operation == "put_all": - ssh.put_all(logdir_local_base, logdir_remote ) - else: - print "Error: Uknown operation in SSHSessionWrapper. Exiting now..." - sys.exit(1) - break - except Exception, e: - error='' - error = error + ' In Class = function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) - error = error + '\n username = ' + username + '\n machine = ' + machine + '\n logdir_remote = ' + logdir_remote + '\n logdir_local_base = ' + logdir_local_base - error = error + traceback.format_exc() - print error - print " Retrying again in 1 seconds" - time.sleep(1) - print "Continuing ..." - if i ==max_tries: - print "Fatal Error: Max no of retries reached. Exiting now..." - sys.exit(1) - - - -# \briefFunction to clean old programs that might be running from earlier execution -# \param oai - parameter for making connection to machine -# \parm programList list of programs that must be terminated before execution of any test case -# \param CleanUpAluLteBox program to terminate AlU Bell Labs LTE Box -# \param ExmimoRfStop String to stop EXMIMO card (specified in test_case_list.xml) -def cleanOldPrograms(oai, programList, CleanUpAluLteBox, ExmimoRfStop, logdir, logdirOAI5GRepo): - cmd = 'killall -9 ' + programList - result = oai.send(cmd, True) -# print "\t\t > "+cmd -# print "\t\t < "+result - -# print "Killing old programs on ..." + result - programArray = programList.split() - programListJoin = '|'.join(programArray) - cmd = " ( date ;echo \"Starting cleaning old programs.. \" ; dmesg|tail ; echo \"Current disk space.. \" ; df -h )>& " + logdir + "/oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync" - result=oai.send_recv(cmd) -# print "\t\t > "+cmd -# print "\t\t < "+result - - cmd = cleanupOldProgramsScript + ' ' + '\''+programListJoin+'\'' - #result = oai.send_recv(cmd) - #print result - result = oai.send_expect_false(cmd, 'Match found', False) -# print "\t\t > "+cmd -# print "\t\t < "+result - -# print "Looking for old programs..." + result - res=oai.send_recv(CleanUpAluLteBox, True) -# print "\t\t > "+CleanUpAluLteBox -# print "\t\t < "+res - cmd= " echo \"Starting EXmimoRF Stop... \" >> " + logdir + "/oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync "; - result = oai.send_recv(cmd) -# print "\t\t > "+cmd -# print "\t\t < "+result - cmd = "( " + "cd " + logdirOAI5GRepo + " ; source oaienv ; " + ExmimoRfStop + " ) >> " + logdir + "/oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync " -# print "cleanoldprograms cmd = " + cmd - res=oai.send_recv(cmd, False, timeout=600) -# print "\t\t > "+cmd -# print "\t\t < "+res - - cmd= " echo \"Stopping EXmimoRF Stop... \" >> " + logdir + "/oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync "; - result = oai.send_recv(cmd) -# print "\t\t > "+cmd -# print "\t\t < "+result - - #res = oai.send_recv(ExmimoRfStop, False) - cmd = " ( date ;echo \"Finished cleaning old programs.. \" ; dmesg | tail)>> $HOME/.oai_test_setup_cleanup.log.`hostname` 2>&1 ; sync" - res=oai.send_recv(cmd) -# print "\t\t > "+cmd -# print "\t\t < "+res - -# \brief Class thread to launch a generic command on remote machine -# \param threadID number of thread (for book keeping) -# \param threadname string of threadname (for book keeping) -# \param machine machine name on which to run the command -# \param username username with which to login -# \param password password with which to login -# \param cmd command as a string to run on remote machine -# \parma sudo if True sudo is set -# \param timeout timeout of command in seconds -class oaiThread (threading.Thread): - def __init__(self, threadID, threadname, machine, username, password, cmd, sudo, timeout): - threading.Thread.__init__(self) - self.threadID = threadID - self.threadname = threadname - self.machine = machine - self.username = username - self.password = password - self.cmd = cmd - self.sudo = sudo - self.timeout = timeout - def run(self): - try: - oai = openair('localdomain',self.machine) - oai.connect(self.username, self.password) - # print "Starting " + self.threadname + " on machine " + self.machine - result = oai.send_recv(self.cmd, self.sudo, self.timeout) - #print "result = " + result - #print "Exiting " + self.threadname - oai.disconnect() - except Exception, e: - error='' - error = error + ' In class oaiThread, function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) - error = error + '\n threadID = ' + str(self.threadID) + '\n threadname = ' + self.threadname + '\n timeout = ' + str(self.timeout) + '\n machine = ' + self.machine + '\n cmd = ' + self.cmd + '\n timeout = ' + str(self.timeout) + '\n username = ' + self.username + '\n' - error = error + traceback.format_exc() - print error - - -# \brief This class runs test cases with class {execution, compilatation} -# \param threadID number of thread (for book keeping) -# \param name string of threadname (for book keeping) -# \param machine machine name on which to run the command -# \param logdirOAI5GRepo directory on remote machine which as openairinterface5g repo installed -# \param testcasename name of test case to run on remote machine -# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) -# \param user username with which to login -# \param password password with which to login -# \param timeout timeout of command in seconds -# \param ExmimoRfStop command to stop EXMIMO Card -class testCaseThread_generic (threading.Thread): - def __init__(self, threadID, name, machine, logdirOAI5GRepo, testcasename,oldprogramList, CleanupAluLteBox, user, password, timeout, ExmimoRfStop): - threading.Thread.__init__(self) - self.threadID = threadID - self.name = name - self.testcasename = testcasename - self.timeout = timeout - self.machine = machine - self.logdirOAI5GRepo = logdirOAI5GRepo - self.oldprogramList = oldprogramList - self.CleanupAluLteBox = CleanupAluLteBox - self.password=password - self.ExmimoRfStop = ExmimoRfStop - self.user = user - def run(self): - try: - mypassword='' - #addsudo = 'echo \'' + mypassword + '\' | sudo -S -E ' - addpass = 'echo \'' + mypassword + '\' | ' - #user = getpass.getuser() - print "Starting test case : " + self.testcasename + " On machine " + self.machine + " timeout = " + str(self.timeout) - oai = openair('localdomain',self.machine) - oai.connect(self.user, self.password) - #cleanOldPrograms(oai, self.oldprogramList, self.CleanupAluLteBox, self.ExmimoRfStop) - logdir_local = os.environ.get('OPENAIR_DIR') - logdir_local_testcase = logdir_local +'/cmake_targets/autotests/log/'+ self.testcasename - logdir_local_base = logdir_local +'/cmake_targets/autotests/log/' - logdir_remote_testcase = self.logdirOAI5GRepo + '/cmake_targets/autotests/log/' + self.testcasename - logdir_remote = self.logdirOAI5GRepo + '/cmake_targets/autotests/log/' - logfile_task_testcasename = logdir_local_testcase + '/test_task' + '_' + self.testcasename + '_.log' - logfile_task_testcasename_out = logdir_remote + '/test_task_out' + '_' + self.testcasename + '_.log' - #print "logdir_local_testcase = " + logdir_local_testcase - #print "logdir_remote_testcase = " + logdir_remote_testcase - #if os.path.exists(logdir_local_testcase) == True : - # os.removedirs(logdir_local_testcase) - #os.mkdir(logdir_local_testcase) - os.system("rm -fr " + logdir_local_testcase ) - os.system("mkdir -p " + logdir_local_testcase) - cmd = "mkdir -p " + logdir_remote_testcase - res = oai.send_recv(cmd, False, self.timeout) - #print "res = " + res - - cmd = "( cd " + self.logdirOAI5GRepo + " \n " - cmd = cmd + "source oaienv \n" - cmd = cmd + "$OPENAIR_DIR/cmake_targets/autotests/run_exec_autotests.bash --run-group \"" + self.testcasename + "\" -p \'\'" - cmd = cmd + " ) >& " + logfile_task_testcasename_out + " ; " + "mkdir -p " + logdir_remote_testcase + "; mv " + logfile_task_testcasename_out + " " +logdir_remote_testcase - - #print "cmd = " + cmd - res = oai.send_recv(cmd, False, self.timeout) - #print "res = " + res - #print "ThreadID = " + str(self.threadID) + "ThreadName: " + self.name + " testcasename: " + self.testcasename + "Execution Result = " + res - write_file(logfile_task_testcasename, cmd, mode="w") - #Now we copy all the remote files - #ssh = SSHSession(self.machine , username=user, key_file=None, password=self.password) - #ssh.get_all(logdir_remote_testcase , logdir_local_base) - SSHSessionWrapper(self.machine, self.user, None, self.password, logdir_remote_testcase, logdir_local_base, "get_all") - print "Finishing test case : " + self.testcasename + " On machine " + self.machine - #cleanOldPrograms(oai, self.oldprogramList, self.CleanupAluLteBox, self.ExmimoRfStop) - #oai.kill(user,mypassword) - oai.disconnect() - except Exception, e: - error='' - error = error + ' In Class = testCaseThread_generic, function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) - error = error + '\n threadID = ' + str(self.threadID) + '\n threadName = ' + self.name + '\n testcasename = ' + self.testcasename + '\n machine = ' + self.machine + '\n logdirOAI5GRepo = ' + self.logdirOAI5GRepo + '\n' + '\n timeout = ' + str(self.timeout) + '\n user = ' + self.user - error = error + traceback.format_exc() - print error - print "Continuing with next test case..." - #sys.exit() - - - -# \bried function to run a command as a sudo -# \param cmd command as a string -# \param password password to be supplied -def addsudo (cmd, password=""): - cmd = 'echo \'' + password + '\' | sudo -S -E bash -c \' ' + cmd + '\' ' - return cmd - -# \brief handler for executing test cases (compilation, execution) -# \param name of testcase -# \param threadListGeneric list of threads which are already running on remote machines -# \param oldprogramList list of programs which must be terminated before running a test case -# \param logdirOAI5GRepo directory on remote machine which as openairinterface5g repo installed -# \param MachineList list of all machines on which generic test cases can be run -# \param user username with which to login -# \param password password with which to login -# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) -# \param timeout timeout of command in seconds -# \param ExmimoRfStop command to stop EXMIMO Card -def handle_testcaseclass_generic (testcasename, threadListGeneric, oldprogramList, logdirOAI5GRepo, MachineList, user, password, CleanupAluLteBox,timeout, ExmimoRfStop): - try: - mypassword=password - MachineListFree=[] - threadListNew=[] - while MachineListFree.__len__() == 0 : - MachineListBusy=[] - MachineListFree=[] - threadListNew=[] - #first we need to find the list of free machines that we could run our test case - if threadListGeneric.__len__() ==0 : - #This means no thread is started yet - MachineListFree = MachineList[:] - else : - for param in threadListGeneric : - thread_id = param["thread_id"] - machine = param["Machine"] - testcasenameold = param["testcasename"] - thread_id.join(1) - if thread_id.isAlive() == True: - threadListNew.append(param) - print "thread_id is alive: testcasename: " + testcasenameold + " on machine "+ machine - if machine not in MachineListBusy: - MachineListBusy.append(machine) - else : - print "thread_id is finished: testcasename: " + testcasenameold + " on machine " + machine - #threadListGeneric.remove(param) - #if machine not in MachineListFree: - # MachineListFree.append(machine) - #Now we check if there is at least one free machine - MachineListFree = MachineList[:] - for machine in MachineListBusy: - if machine in MachineListFree: - MachineListFree.remove(machine) - print "MachineListFree = " + ','.join(MachineListFree) - print "MachineListBusy = " + ','.join(MachineListBusy) - print "MachineList = " + ','.join(MachineList) - machine = MachineListFree[0] - thread = testCaseThread_generic(1,"Generic Thread_"+testcasename+"_"+ "machine_", machine, logdirOAI5GRepo, testcasename, oldprogramList, CleanupAluLteBox, user, password, timeout, ExmimoRfStop) - param={"thread_id":thread, "Machine":machine, "testcasename":testcasename} - thread.start() - threadListNew.append(param) - return threadListNew - except Exception, e: - error='' - error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) - error = error + '\n testcasename = ' + testcasename + '\n logdirOAI5GRepo = ' + logdirOAI5GRepo + '\n MachineList = ' + ','.join(MachineList) + '\n timeout = ' + str(timeout) + '\n' + 'user = ' + user - error = error + traceback.format_exc() - print error - print "Continuing..." - #sys.exit(1) - -# \brief Blocking wait for all threads related to generic testcase execution, class (compilation and execution) -# \param threadListGeneric list of threads which are running on remote machines -# \param timeout time to wait on threads in seconds -def wait_testcaseclass_generic_threads(threadListGeneric, timeout = 1): - threadListGenericNew=[] - for param in threadListGeneric: - thread_id = param["thread_id"] - machine = param["Machine"] - testcasenameold = param["testcasename"] - thread_id.join(timeout) - if thread_id.isAlive() == True: - threadListGenericNew.append(param) - print "thread_id on machine: " + machine + " is still alive: testcasename: " + testcasenameold - print " Exiting now..." - sys.exit(1) - else: - print "thread_id on machine: " + machine + " is stopped: testcasename: " + testcasenameold - #threadListGeneric.remove(param) - return threadListGenericNew - - -# \brief handler for executing test cases (lte-softmodem) -# \param testcase name of testcase -# \param oldprogramList list of programs which must be terminated before running a test case -# \param logdirOAI5GRepo directory on remote machine which has openairinterface5g repo installed -# \param logdirOpenaircnRepo directory on remote machine which has openair-cn repo installed -# \param MachineList list of all machines on which test cases can be run -# \param user username with which to login -# \param password password with which to login -# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) -# \param ExmimoRfStop command to stop EXMIMO Card -# \param nruns_lte-softmodem global parameter to override number of runs (nruns) within the test case -def handle_testcaseclass_softmodem (testcase, oldprogramList, logdirOAI5GRepo , logdirOpenaircnRepo, MachineList, user, password, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, timeout_cmd): - #We ignore the password sent to this function for secuirity reasons for password present in log files - #It is recommended to add a line in /etc/sudoers that looks something like below. The line below will run sudo without password prompt - # your_user_name ALL=(ALL:ALL) NOPASSWD: ALL - mypassword='' - #addsudo = 'echo \'' + mypassword + '\' | sudo -S -E ' - addpass = 'echo \'' + mypassword + '\' | ' - #user = getpass.getuser() - testcasename = testcase.get('id') - testcaseclass = testcase.findtext('class',default='') - if timeout_cmd == '': - timeout_cmd = testcase.findtext('TimeOut_cmd',default='') - timeout_cmd = int(float(timeout_cmd)) - #Timeout_thread is more than that of cmd to have room for compilation time, etc - timeout_thread = timeout_cmd + 300 - if nruns_lte_softmodem == '': - nruns = testcase.findtext('nruns',default='') - else: - nruns = nruns_lte_softmodem - nruns = int(float(nruns)) - tags = testcase.findtext('tags',default='') - - RRHMachine = testcase.findtext('RRH',default='') - RRH_compile_prog = testcase.findtext('RRH_compile_prog',default='') - RRH_compile_prog_args = testcase.findtext('RRH_compile_prog_args',default='') - RRH_pre_exec = testcase.findtext('RRH_pre_exec',default='') - RRH_pre_exec_args = testcase.findtext('RRH_pre_exec_args',default='') - RRH_main_exec = testcase.findtext('RRH_main_exec',default='') - RRH_main_exec_args = testcase.findtext('RRH_main_exec_args',default='') - RRH_terminate_missing_procs = testcase.findtext('RRH_terminate_missing_procs',default='False') - - - eNBMachine = testcase.findtext('eNB',default='') - eNB_config_file = testcase.findtext('eNB_config_file',default='') - eNB_compile_prog = testcase.findtext('eNB_compile_prog',default='') - eNB_compile_prog_args = testcase.findtext('eNB_compile_prog_args',default='') - eNB_pre_exec = testcase.findtext('eNB_pre_exec',default='') - eNB_pre_exec_args = testcase.findtext('eNB_pre_exec_args',default='') - eNB_main_exec = testcase.findtext('eNB_main_exec',default='') - eNB_main_exec_args = testcase.findtext('eNB_main_exec_args',default='') - eNB_traffic_exec = testcase.findtext('eNB_traffic_exec',default='') - eNB_traffic_exec_args = testcase.findtext('eNB_traffic_exec_args',default='') - eNB_terminate_missing_procs = testcase.findtext('eNB_terminate_missing_procs',default='False') - eNB_search_expr_true = testcase.findtext('eNB_search_expr_true','') - if re.compile('\w+').match(eNB_search_expr_true) != None: - eNB_search_expr_true = eNB_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' - - UEMachine = testcase.findtext('UE',default='') - UE_config_file = testcase.findtext('UE_config_file',default='') - UE_compile_prog = testcase.findtext('UE_compile_prog',default='') - UE_compile_prog_args = testcase.findtext('UE_compile_prog_args',default='') - UE_pre_exec = testcase.findtext('UE_pre_exec',default='') - UE_pre_exec_args = testcase.findtext('UE_pre_exec_args',default='') - UE_main_exec = testcase.findtext('UE_main_exec',default='') - UE_main_exec_args = testcase.findtext('UE_main_exec_args',default='') - UE_traffic_exec = testcase.findtext('UE_traffic_exec',default='') - UE_traffic_exec_args = testcase.findtext('UE_traffic_exec_args',default='') - UE_terminate_missing_procs = testcase.findtext('UE_terminate_missing_procs',default='False') - UE_search_expr_true = testcase.findtext('UE_search_expr_true','') - UE_stop_script = testcase.findtext('UE_stop_script','') - if re.compile('\w+').match(UE_search_expr_true) != None: - UE_search_expr_true = UE_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' - - EPCMachine = testcase.findtext('EPC',default='') - EPC_config_file = testcase.findtext('EPC_config_file',default='') - EPC_compile_prog = testcase.findtext('EPC_compile_prog',default='') - EPC_compile_prog_args = testcase.findtext('EPC_compile_prog_args',default='') - HSS_compile_prog = testcase.findtext('HSS_compile_prog',default='') - HSS_compile_prog_args = testcase.findtext('HSS_compile_prog_args',default='') - - EPC_pre_exec= testcase.findtext('EPC_pre_exec',default='') - EPC_pre_exec_args = testcase.findtext('EPC_pre_exec_args',default='') - EPC_main_exec= testcase.findtext('EPC_main_exec',default='') - EPC_main_exec_args = testcase.findtext('EPC_main_exec_args',default='') - HSS_main_exec= testcase.findtext('HSS_main_exec',default='') - HSS_main_exec_args = testcase.findtext('HSS_main_exec_args',default='') - EPC_traffic_exec = testcase.findtext('EPC_traffic_exec',default='') - EPC_traffic_exec_args = testcase.findtext('EPC_traffic_exec_args',default='') - EPC_terminate_missing_procs = testcase.findtext('EPC_terminate_missing_procs',default='False') - EPC_search_expr_true = testcase.findtext('EPC_search_expr_true','') - if re.compile('\w+').match(EPC_search_expr_true) != None: - EPC_search_expr_true = EPC_search_expr_true + ' duration=' + str(timeout_cmd-90) + 's' - - index_eNBMachine = MachineList.index(eNBMachine) - index_UEMachine = MachineList.index(UEMachine) - index_EPCMachine = MachineList.index(EPCMachine) - cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep OPENAIR' - oai_eNB = openair('localdomain', eNBMachine) - oai_eNB.connect(user, password) - res= oai_eNB.send_recv(cmd) - oai_UE = openair('localdomain', UEMachine) - oai_UE.connect(user, password) - res = oai_eNB.send_recv(cmd) - oai_EPC = openair('localdomain', EPCMachine) - oai_EPC.connect(user, password) - res = oai_eNB.send_recv(cmd) - if RRHMachine != '': - cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep OPENAIR' - index_RRHMachine = MachineList.index(RRHMachine) - oai_RRH = openair('localdomain', RRHMachine) - oai_RRH.connect(user, password) - res= oai_RRH.send_recv(cmd) - #cleanOldPrograms(oai_eNB, oldprogramList, CleanUpAluLteBox, ExmimoRfStop) - #cleanOldPrograms(oai_UE, oldprogramList, CleanUpAluLteBox, ExmimoRfStop) - #cleanOldPrograms(oai_EPC, oldprogramList, CleanUpAluLteBox, ExmimoRfStop) - logdir_local = os.environ.get('OPENAIR_DIR') - if logdir_local is None: - print "Environment variable OPENAIR_DIR not set correctly" - sys.exit() - - #Make the log directory of test case - #cmd = 'mkdir -p ' + logdir_eNB - #result = oai_eNB.send_recv(cmd) - #cmd = 'mkdir -p ' + logdir_UE - #result = oai_UE.send_recv(cmd) - #cmd = 'mkdir -p ' + logdir_EPC - #result = oai_EPC.send_recv(cmd) - - print "Updating the config files for ENB/UE/EPC..." - #updating the eNB/UE/EPC configuration file from the test case - #update_config_file(oai_eNB, eNB_config_file, logdirOAI5GRepo) - #update_config_file(oai_UE, UE_config_file, logdirOAI5GRepo) - #update_config_file(oai_EPC, EPC_config_file, logdirOpenaircnRepo) - test_result=1 - test_result_string='' - start_time=time.time() - for run in range(0,nruns): - run_result=1 - run_result_string='' - logdir_eNB = logdirOAI5GRepo+'/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) - logdir_RRH = logdirOAI5GRepo+'/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) - logdir_UE = logdirOAI5GRepo+'/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) - logdir_EPC = logdirOpenaircnRepo+'/TEST/autotests/log/'+ testcasename + '/run_' + str(run) - logdir_local_testcase = logdir_local + '/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) - #Make the log directory of test case - if RRHMachine != '': - cmd = 'rm -fr ' + logdir_RRH + ' ; mkdir -p ' + logdir_RRH - result = oai_RRH.send_recv(cmd) - cmd = 'rm -fr ' + logdir_eNB + ' ; mkdir -p ' + logdir_eNB - result = oai_eNB.send_recv(cmd) - cmd = 'rm -fr ' + logdir_UE + ' ; mkdir -p ' + logdir_UE - result = oai_UE.send_recv(cmd) - cmd = 'rm -fr ' + logdir_EPC + '; mkdir -p ' + logdir_EPC - result = oai_EPC.send_recv(cmd) - cmd = ' rm -fr ' + logdir_local_testcase + ' ; mkdir -p ' + logdir_local_testcase - result = os.system(cmd) - - if RRHMachine != '': - logfile_compile_RRH = logdir_RRH + '/RRH_compile' + '_' + str(run) + '_.log' - logfile_exec_RRH = logdir_RRH + '/RRH_exec' + '_' + str(run) + '_.log' - logfile_pre_exec_RRH = logdir_RRH + '/RRH_pre_exec' + '_' + str(run) + '_.log' - logfile_task_RRH_compile_out = logdir_RRH + '/RRH_task_compile_out' + '_' + str(run) + '_.log' - logfile_task_RRH_compile = logdir_local_testcase + '/RRH_task_compile' + '_' + str(run) + '_.log' - logfile_task_RRH_out = logdir_RRH + '/RRH_task_out' + '_' + str(run) + '_.log' - logfile_task_RRH = logdir_local_testcase + '/RRH_task' + '_' + str(run) + '_.log' - task_RRH_compile = ' ( uname -a ; date \n' - task_RRH_compile = task_RRH_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' - task_RRH_compile = task_RRH_compile + 'env |grep OPENAIR \n' - if RRH_compile_prog != "": - task_RRH_compile = task_RRH_compile + ' ( ' + RRH_compile_prog + ' '+ RRH_compile_prog_args + ' ) > ' + logfile_compile_RRH + ' 2>&1 \n' - task_RRH_compile = task_RRH_compile + ' date ) > ' + logfile_task_RRH_compile_out + ' 2>&1 ' - write_file(logfile_task_RRH_compile, task_RRH_compile, mode="w") - - task_RRH = ' ( uname -a ; date \n' - task_RRH = task_RRH + ' export OPENAIR_TESTDIR=' + logdir_RRH + '\n' - task_RRH = task_RRH + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' - task_RRH = task_RRH + 'env |grep OPENAIR \n' + 'array_exec_pid=() \n' - - if RRH_pre_exec != "": - task_RRH = task_RRH + ' ( date; ' + RRH_pre_exec + ' '+ RRH_pre_exec_args + ' ) > ' + logfile_pre_exec_RRH + ' 2>&1 \n' - if RRH_main_exec != "": - task_RRH = task_RRH + ' ( date; ' + addsudo(RRH_main_exec + ' ' + RRH_main_exec_args, mypassword) + ' ) > ' + logfile_exec_RRH + ' 2>&1 & \n' - task_RRH = task_RRH + 'array_exec_pid+=($!) \n' - task_RRH = task_RRH + 'echo eNB_main_exec PID = $! \n' - #terminate the eNB test case after timeout_cmd seconds - task_RRH = task_RRH + finalize_deploy_script (timeout_cmd, RRH_terminate_missing_procs) + ' \n' - task_RRH = task_RRH + 'handle_ctrl_c' + '\n' - task_RRH = task_RRH + ' ) > ' + logfile_task_RRH_out + ' 2>&1 ' - write_file(logfile_task_RRH, task_RRH, mode="w") - - logfile_compile_eNB = logdir_eNB + '/eNB_compile' + '_' + str(run) + '_.log' - logfile_exec_eNB = logdir_eNB + '/eNB_exec' + '_' + str(run) + '_.log' - logfile_pre_exec_eNB = logdir_eNB + '/eNB_pre_exec' + '_' + str(run) + '_.log' - logfile_traffic_eNB = logdir_eNB + '/eNB_traffic' + '_' + str(run) + '_.log' - logfile_task_eNB_compile_out = logdir_eNB + '/eNB_task_compile_out' + '_' + str(run) + '_.log' - logfile_task_eNB_compile = logdir_local_testcase + '/eNB_task_compile' + '_' + str(run) + '_.log' - logfile_task_eNB_out = logdir_eNB + '/eNB_task_out' + '_' + str(run) + '_.log' - logfile_task_eNB = logdir_local_testcase + '/eNB_task' + '_' + str(run) + '_.log' - logfile_local_traffic_eNB_out = logdir_local_testcase + '/eNB_traffic' + '_' + str(run) + '_.log' - logfile_tshark_eNB = logdir_eNB + '/eNB_tshark' + '_' + str(run) + '_.log' - logfile_pcap_eNB = logdir_eNB + '/eNB_tshark' + '_' + str(run) + '_.pcap' - logfile_pcap_zip_eNB = logdir_eNB + '/eNB_tshark' + '_' + str(run) + '_.pcap.zip' - logfile_pcap_tmp_eNB = '/tmp/' + '/eNB_tshark' + '_' + str(run) + '_.pcap' - - task_eNB_compile = ' ( uname -a ; date \n' - task_eNB_compile = task_eNB_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' - task_eNB_compile = task_eNB_compile + 'env |grep OPENAIR \n' - task_eNB_compile = task_eNB_compile + update_config_file(oai_eNB, eNB_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' - if eNB_compile_prog != "": - task_eNB_compile = task_eNB_compile + ' ( ' + eNB_compile_prog + ' '+ eNB_compile_prog_args + ' ) > ' + logfile_compile_eNB + ' 2>&1 \n' - task_eNB_compile = task_eNB_compile + ' date ) > ' + logfile_task_eNB_compile_out + ' 2>&1 ' - write_file(logfile_task_eNB_compile, task_eNB_compile, mode="w") - - task_eNB = ' ( uname -a ; date \n' - task_eNB = task_eNB + ' export OPENAIR_TESTDIR=' + logdir_eNB + '\n' - task_eNB = task_eNB + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' - task_eNB = task_eNB + 'env |grep OPENAIR \n' + 'array_exec_pid=() \n' - - if eNB_pre_exec != "": - task_eNB = task_eNB + ' ( date; ' + eNB_pre_exec + ' '+ eNB_pre_exec_args + ' ) > ' + logfile_pre_exec_eNB + ' 2>&1 \n' - if eNB_main_exec != "": - task_eNB = task_eNB + ' ( date; ' + addsudo(eNB_main_exec + ' ' + eNB_main_exec_args, mypassword) + ' ) > ' + logfile_exec_eNB + ' 2>&1 & \n' - task_eNB = task_eNB + 'array_exec_pid+=($!) \n' - task_eNB = task_eNB + 'echo eNB_main_exec PID = $! \n' - if eNB_traffic_exec != "": - cmd_traffic = eNB_traffic_exec + ' ' + eNB_traffic_exec_args - if cmd_traffic.find('-c') >= 0: - cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 60) - task_eNB = task_eNB + ' (date; ' + cmd_traffic + ' ) > ' + logfile_traffic_eNB + ' 2>&1 & \n' - task_eNB = task_eNB + 'array_exec_pid+=($!) \n' - task_eNB = task_eNB + 'echo eNB_traffic_exec PID = $! \n' - - task_eNB = task_eNB + ' (date; sudo rm -f ' + logfile_pcap_tmp_eNB + ' ; sudo -E tshark -i lo -s 65535 -a duration:' + str(timeout_cmd-10)+ ' -w ' + logfile_pcap_tmp_eNB+ ' ; sudo -E chown ' + user + ' ' + logfile_pcap_tmp_eNB + ' ; zip -j -9 ' + logfile_pcap_zip_eNB + ' ' + logfile_pcap_tmp_eNB + ' ) > ' + logfile_tshark_eNB + ' 2>&1 & \n ' - task_eNB = task_eNB + 'array_exec_pid+=($!) \n' - task_eNB = task_eNB + 'echo eNB_tshark_exec PID = $! \n' - #terminate the eNB test case after timeout_cmd seconds - task_eNB = task_eNB + finalize_deploy_script (timeout_cmd, eNB_terminate_missing_procs) + ' \n' - #task_eNB = task_eNB + 'sleep ' + str(timeout_cmd) + ' \n' - task_eNB = task_eNB + 'handle_ctrl_c' + '\n' - task_eNB = task_eNB + ' ) > ' + logfile_task_eNB_out + ' 2>&1 ' - write_file(logfile_task_eNB, task_eNB, mode="w") - - #task_eNB = 'echo \" ' + task_eNB + '\" > ' + logfile_script_eNB + ' 2>&1 ; ' + task_eNB - logfile_compile_UE = logdir_UE + '/UE_compile' + '_' + str(run) + '_.log' - logfile_exec_UE = logdir_UE + '/UE_exec' + '_' + str(run) + '_.log' - logfile_pre_exec_UE = logdir_UE + '/UE_pre_exec' + '_' + str(run) + '_.log' - logfile_traffic_UE = logdir_UE + '/UE_traffic' + '_' + str(run) + '_.log' - logfile_task_UE_out = logdir_UE + '/UE_task_out' + '_' + str(run) + '_.log' - logfile_task_UE = logdir_local_testcase + '/UE_task' + '_' + str(run) + '_.log' - logfile_task_UE_compile_out = logdir_UE + '/UE_task_compile_out' + '_' + str(run) + '_.log' - logfile_task_UE_compile = logdir_local_testcase + '/UE_task_compile' + '_' + str(run) + '_.log' - logfile_local_traffic_UE_out = logdir_local_testcase + '/UE_traffic' + '_' + str(run) + '_.log' - - task_UE_compile = ' ( uname -a ; date \n' - task_UE_compile = task_UE_compile + 'array_exec_pid=()' + '\n' - task_UE_compile = task_UE_compile + 'cd ' + logdirOAI5GRepo + '\n' - task_UE_compile = task_UE_compile + 'source oaienv \n' - task_UE_compile = task_UE_compile + 'source cmake_targets/tools/build_helper \n' - task_UE_compile = task_UE_compile + 'env |grep OPENAIR \n' - task_UE_compile = task_UE_compile + update_config_file(oai_UE, UE_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' - if UE_compile_prog != "": - task_UE_compile = task_UE_compile + ' ( ' + UE_compile_prog + ' '+ UE_compile_prog_args + ' ) > ' + logfile_compile_UE + ' 2>&1 \n' - task_UE_compile = task_UE_compile + ' ) > ' + logfile_task_UE_compile_out + ' 2>&1 ' - write_file(logfile_task_UE_compile, task_UE_compile, mode="w") - - task_UE = ' ( uname -a ; date \n' - task_UE = task_UE + 'array_exec_pid=()' + '\n' - task_UE = task_UE + 'cd ' + logdirOAI5GRepo + '\n' - task_UE = task_UE + 'source oaienv \n' - task_UE = task_UE + 'source cmake_targets/tools/build_helper \n' - task_UE = task_UE + 'env |grep OPENAIR \n' - if UE_pre_exec != "": - task_UE = task_UE + ' ( date; ' + UE_pre_exec + ' '+ UE_pre_exec_args + ' ) > ' + logfile_pre_exec_UE + ' 2>&1 \n' - if UE_main_exec != "": - task_UE = task_UE + ' ( date; ' + addsudo(UE_main_exec + ' ' + UE_main_exec_args, mypassword) + ' ) > ' + logfile_exec_UE + ' 2>&1 & \n' - task_UE = task_UE + 'array_exec_pid+=($!) \n' - task_UE = task_UE + 'echo UE_main_exec PID = $! \n' - if UE_traffic_exec != "": - cmd_traffic = UE_traffic_exec + ' ' + UE_traffic_exec_args - if cmd_traffic.find('-c') >= 0: - cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 60) - task_UE = task_UE + ' ( date; ' + cmd_traffic + ' ) >' + logfile_traffic_UE + ' 2>&1 & \n' - task_UE = task_UE + 'array_exec_pid+=($!) \n' - task_UE = task_UE + 'echo UE_traffic_exec PID = $! \n' - #terminate the UE test case after timeout_cmd seconds - task_UE = task_UE + finalize_deploy_script (timeout_cmd, UE_terminate_missing_procs) + ' \n' - #task_UE = task_UE + 'sleep ' + str(timeout_cmd) + ' \n' - task_UE = task_UE + 'handle_ctrl_c' + '\n' - task_UE = task_UE + ' ) > ' + logfile_task_UE_out + ' 2>&1 ' - write_file(logfile_task_UE, task_UE, mode="w") - #task_UE = 'echo \" ' + task_UE + '\" > ' + logfile_script_UE + ' 2>&1 ; ' + task_UE - - logfile_compile_EPC = logdir_EPC + '/EPC_compile' + '_' + str(run) + '_.log' - logfile_compile_HSS = logdir_EPC + '/HSS_compile' + '_' + str(run) + '_.log' - logfile_exec_EPC = logdir_EPC + '/EPC_exec' + '_' + str(run) + '_.log' - logfile_pre_exec_EPC = logdir_EPC + '/EPC_pre_exec' + '_' + str(run) + '_.log' - logfile_exec_HSS = logdir_EPC + '/HSS_exec' + '_' + str(run) + '_.log' - logfile_traffic_EPC = logdir_EPC + '/EPC_traffic' + '_' + str(run) + '_.log' - logfile_task_EPC_out = logdir_EPC + '/EPC_task_out' + '_' + str(run) + '_.log' - logfile_task_EPC = logdir_local_testcase + '/EPC_task' + '_' + str(run) + '_.log' - logfile_task_EPC_compile_out = logdir_EPC + '/EPC_task_compile_out' + '_' + str(run) + '_.log' - logfile_task_EPC_compile = logdir_local_testcase + '/EPC_task_compile' + '_' + str(run) + '_.log' - logfile_local_traffic_EPC_out = logdir_local_testcase + '/EPC_traffic' + '_' + str(run) + '_.log' - - task_EPC_compile = ' ( uname -a ; date \n' - task_EPC_compile = task_EPC_compile + 'array_exec_pid=()' + '\n' - task_EPC_compile = task_EPC_compile + 'cd ' + logdirOpenaircnRepo + ' ; source oaienv \n' - task_EPC_compile = task_EPC_compile + update_config_file(oai_EPC, EPC_config_file, logdirOpenaircnRepo, logdirOpenaircnRepo+'/TEST/autotests/tools/search_repl.py') + '\n' - task_EPC_compile = task_EPC_compile + 'source BUILD/TOOLS/build_helper \n' - if EPC_compile_prog != "": - task_EPC_compile = task_EPC_compile + '(' + EPC_compile_prog + ' ' + EPC_compile_prog_args + ' ) > ' + logfile_compile_EPC + ' 2>&1 \n' - if HSS_compile_prog != "": - task_EPC_compile = task_EPC_compile + '(' + HSS_compile_prog + ' ' + HSS_compile_prog_args + ' ) > ' + logfile_compile_HSS + ' 2>&1 \n' - task_EPC_compile = task_EPC_compile + ' ) > ' + logfile_task_EPC_compile_out + ' 2>&1 ' - write_file(logfile_task_EPC_compile, task_EPC_compile, mode="w") - - task_EPC = ' ( uname -a ; date \n' - task_EPC = task_EPC + ' export OPENAIRCN_TESTDIR=' + logdir_EPC + '\n' - task_EPC = task_EPC + 'array_exec_pid=()' + '\n' - task_EPC = task_EPC + 'cd ' + logdirOpenaircnRepo + '; source oaienv\n' - task_EPC = task_EPC + 'source BUILD/TOOLS/build_helper \n' - if EPC_pre_exec != "": - task_EPC = task_EPC + ' ( date; ' + EPC_pre_exec + ' '+ EPC_pre_exec_args + ' ) > ' + logfile_pre_exec_EPC + ' 2>&1 \n' - if HSS_main_exec != "": - task_EPC = task_EPC + '( date; ' + addsudo (HSS_main_exec + ' ' + HSS_main_exec_args, mypassword) + ' ) > ' + logfile_exec_HSS + ' 2>&1 & \n' - task_EPC = task_EPC + 'array_exec_pid+=($!) \n' - task_EPC = task_EPC + 'echo HSS_main_exec PID = $! \n' - if EPC_main_exec != "": - task_EPC = task_EPC + '( date; ' + addsudo (EPC_main_exec + ' ' + EPC_main_exec_args, mypassword) + ' ) > ' + logfile_exec_EPC + ' 2>&1 & \n' - task_EPC = task_EPC + 'array_exec_pid+=($!) \n' - task_EPC = task_EPC + 'echo EPC_main_exec PID = $! \n' - if EPC_traffic_exec != "": - cmd_traffic = EPC_traffic_exec + ' ' + EPC_traffic_exec_args - if cmd_traffic.find('-c') >= 0: - cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 60) - task_EPC = task_EPC + '( date; ' + cmd_traffic + ' ) > ' + logfile_traffic_EPC + ' 2>&1 & \n' - task_EPC = task_EPC + 'array_exec_pid+=($!) \n' - task_EPC = task_EPC + 'echo EPC_traffic_exec PID = $! \n' - #terminate the EPC test case after timeout_cmd seconds - task_EPC = task_EPC + finalize_deploy_script (timeout_cmd, EPC_terminate_missing_procs) + '\n' - #task_EPC = task_EPC + 'sleep ' + str(timeout_cmd) + '\n' - task_EPC = task_EPC + 'handle_ctrl_c' '\n' - task_EPC = task_EPC + ' ) > ' + logfile_task_EPC_out + ' 2>&1 ' - write_file(logfile_task_EPC, task_EPC, mode="w") - - #first we compile all the programs but only for run_0 - if run == 0: - thread_EPC = oaiThread(1, "EPC_thread", EPCMachine, user, password , task_EPC_compile, False, timeout_thread) - thread_eNB = oaiThread(2, "eNB_thread", eNBMachine, user, password , task_eNB_compile, False, timeout_thread) - thread_UE = oaiThread(3, "UE_thread", UEMachine, user, password , task_UE_compile, False, timeout_thread) - if RRHMachine != '': - thread_RRH = oaiThread(4, "RRH_thread", RRHMachine, user, password , task_RRH_compile, False, timeout_thread) - threads=[] - threads.append(thread_eNB) - threads.append(thread_UE) - threads.append(thread_EPC) - if RRHMachine != '': - threads.append(thread_RRH) - # Start new Threads - thread_eNB.start() - thread_UE.start() - thread_EPC.start() - if RRHMachine != '': - thread_RRH.start() - #Wait for all the compile threads to complete - for t in threads: - t.join() - - #Now we execute all the threads - thread_EPC = oaiThread(1, "EPC_thread", EPCMachine, user, password , task_EPC, False, timeout_thread) - thread_eNB = oaiThread(2, "eNB_thread", eNBMachine, user, password , task_eNB, False, timeout_thread) - thread_UE = oaiThread(3, "UE_thread", UEMachine, user, password , task_UE, False, timeout_thread) - if RRHMachine != '': - thread_RRH = oaiThread(4, "RRH_thread", RRHMachine, user, password , task_RRH, False, timeout_thread) - threads=[] - threads.append(thread_eNB) - threads.append(thread_UE) - threads.append(thread_EPC) - if RRHMachine != '': - threads.append(thread_RRH) - # Start new Threads - - thread_eNB.start() - thread_UE.start() - thread_EPC.start() - if RRHMachine != '': - thread_RRH.start() - #Wait for all the compile threads to complete - for t in threads: - t.join() - #Now we get the log files from remote machines on the local machine - if RRHMachine != '': - cleanOldProgramsAllMachines([oai_eNB, oai_UE, oai_EPC, oai_RRH] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB, logdir_UE, logdir_EPC, logdir_RRH], logdirOAI5GRepo) - else: - cleanOldProgramsAllMachines([oai_eNB, oai_UE, oai_EPC] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB, logdir_UE, logdir_EPC], logdirOAI5GRepo) - logfile_UE_stop_script_out = logdir_UE + '/UE_stop_script_out' + '_' + str(run) + '_.log' - logfile_UE_stop_script = logdir_local_testcase + '/UE_stop_script' + '_' + str(run) + '_.log' - - if UE_stop_script != "": - cmd = ' ( uname -a ; date \n' - cmd = cmd + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' - cmd = cmd + 'env |grep OPENAIR \n' + 'array_exec_pid=() \n' - cmd = cmd + UE_stop_script + '\n' - cmd = cmd + ') > ' + logfile_UE_stop_script_out + ' 2>&1 ' - write_file(logfile_UE_stop_script , cmd, mode="w") - thread_UE = oaiThread(4, "UE_thread", UEMachine, user, password , cmd, False, timeout_thread) - thread_UE.start() - thread_UE.join() - - #Now we change the permissions of the logfiles to avoid some of them being with root permissions - cmd = 'sudo -E chown -R ' + user + ' ' + logdir_eNB - res= oai_eNB.send_recv(cmd) - print "Changing permissions of logdir <" + logdir_eNB + "> in eNB machine..." + res - - cmd = 'sudo -E chown -R ' + user + ' ' + logdir_UE - res= oai_UE.send_recv(cmd) - print "Changing permissions of logdir <" + logdir_UE + "> in UE machine..." + res - - cmd = 'sudo -E chown -R ' + user + ' ' + logdir_EPC - res= oai_EPC.send_recv(cmd) - print "Changing permissions of logdir <" + logdir_EPC + "> in EPC machine..." + res - - if RRHMachine != '': - cmd = 'sudo -E chown -R ' + user + ' ' + logdir_RRH - res= oai_RRH.send_recv(cmd) - print "Changing permissions of logdir <" + logdir_RRH + "> in RRH machine..." + res - - print "Copying files from EPCMachine : " + EPCMachine + "logdir_EPC = " + logdir_EPC - SSHSessionWrapper(EPCMachine, user, None, password, logdir_EPC, logdir_local + '/cmake_targets/autotests/log/'+ testcasename, "get_all") - - print "Copying files from eNBMachine " + eNBMachine + "logdir_eNB = " + logdir_eNB - SSHSessionWrapper(eNBMachine, user, None, password, logdir_eNB, logdir_local + '/cmake_targets/autotests/log/'+ testcasename, "get_all") - - print "Copying files from UEMachine : " + UEMachine + "logdir_UE = " + logdir_UE - SSHSessionWrapper(UEMachine, user, None, password, logdir_UE, logdir_local + '/cmake_targets/autotests/log/'+ testcasename, "get_all") - - if RRHMachine != '': - print "Copying files from RRHMachine : " + RRHMachine + "logdir_RRH = " + logdir_RRH - SSHSessionWrapper(RRHMachine, user, None, password, logdir_RRH, logdir_local + '/cmake_targets/autotests/log/'+ testcasename, "get_all") - - - #Currently we only perform throughput tests - tput_run_string='' - result, tput_string = tput_test_search_expr(eNB_search_expr_true, logfile_local_traffic_eNB_out) - tput_run_string = tput_run_string + tput_string - run_result=run_result&result - result, tput_string = tput_test_search_expr(EPC_search_expr_true, logfile_local_traffic_EPC_out) - run_result=run_result&result - tput_run_string = tput_run_string + tput_string - result, tput_string = tput_test_search_expr(UE_search_expr_true, logfile_local_traffic_UE_out) - run_result=run_result&result - tput_run_string = tput_run_string + tput_string - - if run_result == 1: - run_result_string = ' RUN_'+str(run) + ' = PASS' - else: - run_result_string = ' RUN_'+str(run) + ' = FAIL' - - #If there is assertion, we mark the test case as failure as most likely eNB crashed - cmd = "grep -ilr \"assertion\" " + logdir_local_testcase + " | cat " - cmd_out = subprocess.check_output ([cmd], shell=True) - if len(cmd_out) !=0 : - run_result=0 - run_result_string = ' RUN_'+str(run) + ' = FAIL(Assert)' - - #If there is thread busy error, we mark the test case as failure as most likely eNB crashed - cmd = "grep -ilr \"thread busy\" " + logdir_local_testcase + " | cat " - cmd_out = subprocess.check_output ([cmd], shell=True) - if len(cmd_out) !=0: - run_result=0 - run_result_string = ' RUN_'+str(run) + ' = FAIL(Thread_Busy)' - - #If there is Segmentation fault, we mark the test case as failure as most likely eNB crashed - cmd = "grep -ilr \"segmentation fault\" " + logdir_local_testcase + " | cat " - cmd_out = subprocess.check_output ([cmd], shell=True) - if len(cmd_out) !=0: - run_result=0 - run_result_string = ' RUN_'+str(run) + ' = FAIL(SEGFAULT)' - - run_result_string = run_result_string + tput_run_string - - test_result=test_result & run_result - test_result_string=test_result_string + run_result_string - - oai_eNB.disconnect() - oai_UE.disconnect() - oai_EPC.disconnect() - #We need to close the new ssh session that was created - #if index_eNBMachine == index_EPCMachine: - # oai_EPC.disconnect() - #Now we finalize the xml file of the test case - end_time=time.time() - duration= end_time - start_time - xmlFile = logdir_local + '/cmake_targets/autotests/log/'+ testcasename + '/test.' + testcasename + '.xml' - if test_result ==0: - result='FAIL' - else: - result = 'PASS' - xml="\n \n" - write_file(xmlFile, xml, mode="w") - - - - -# \brief handler for executing test cases (lte-softmodem-noS1) -# \param testcase name of testcase -# \param oldprogramList list of programs which must be terminated before running a test case -# \param logdirOAI5GRepo directory on remote machine which has openairinterface5g repo installed -# \param logdirOpenaircnRepo directory on remote machine which has openair-cn repo installed -# \param MachineList list of all machines on which test cases can be run -# \param user username with which to login -# \param password password with which to login -# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) -# \param ExmimoRfStop command to stop EXMIMO Card -# \param nruns_lte-softmodem global parameter to override number of runs (nruns) within the test case -def handle_testcaseclass_softmodem_noS1 (testcase, oldprogramList, logdirOAI5GRepo , logdirOpenaircnRepo, MachineList, user, password, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, timeout_cmd): - #We ignore the password sent to this function for secuirity reasons for password present in log files - #It is recommended to add a line in /etc/sudoers that looks something like below. The line below will run sudo without password prompt - # your_user_name ALL=(ALL:ALL) NOPASSWD: ALL - - indent="\t" - threads=[] - - # - # Test case parameters - # ----------------------------------------------------------------------------- - testcase_verdict = 'PASS' - testcase_time_start = datetime.datetime.now() - testcase_name = testcase.get('id') - testcase_class = testcase.findtext('class',default='') - testcase_desc = testcase.findtext('desc',default='') - if timeout_cmd == '': - timeout_cmd = testcase.findtext('TimeOut_cmd',default='') - timeout_cmd = int(float(timeout_cmd)) - timeout_thread = timeout_cmd + 60 #Timeout_thread is more than that of cmd to have room for compilation time, etc - if nruns_lte_softmodem == '': - nruns = testcase.findtext('nruns',default='') - else: - nruns = nruns_lte_softmodem - nruns = int(float(nruns)) - tags = testcase.findtext('tags',default='') - - max_ntries = testcase.findtext('max_ntries',default='') - if max_ntries : - max_ntries = int(float(max_ntries)) - else : - max_ntries = nruns - - print( indent + "> testcase time start : " + str(testcase_time_start) ) - print( indent + "> testcase class : " + testcase_class ) - print( indent + "> testcase description : " + testcase_desc ) - print( indent + "> testcase timeout : " + str(timeout_cmd) ) - print( indent + "> testcase thread timeout : " + str(timeout_thread) ) - print( indent + "> number of runs : " + str(nruns) ) - print( indent + "> number of max tries : " + str(max_ntries) ) - print( indent + "> testcase tags : " + tags ) - - logdir_local_testcase = openairdir_local + '/cmake_targets/autotests/log/'+ testcasename - logdir_eNB_testcase = logdirOAI5GRepo +'/cmake_targets/autotests/log/'+ testcasename - logdir_UE_testcase = logdirOAI5GRepo +'/cmake_targets/autotests/log/'+ testcasename - - # - # Local checks for test cases - # ----------------------------------------------- - - # Logging directory - if (not os.path.exists(logdir_local_testcase)): - os.system('mkdir -p ' + logdir_local_testcase) - - # - # REMOTE MACHINE COMPILATION - # ------------------------------------------------ - - eNBMachine = testcase.findtext('eNB',default='') - eNB_config_file = testcase.findtext('eNB_config_file',default='') - eNB_compile_prog = testcase.findtext('eNB_compile_prog',default='') - eNB_compile_prog_args = testcase.findtext('eNB_compile_prog_args',default='') - - logfile_compile_eNB = logdir_eNB_testcase + '/eNB_compile.log' - logfile_task_eNB_compile_out = logdir_eNB_testcase + '/eNB_task_compile_out.log' - logfile_task_eNB_compile = logdir_local_testcase + '/eNB_task_compile.log' - - # Check that machine is in test setup machine list - print( Fore.WHITE + indent + "> testcase eNB machine :"), - if (eNBMachine not in MachineList): - print( Fore.RED + eNBMachine + " not in test setup machine list") - testcase_verdict = 'INCON' - else : - print eNBMachine, - # get machine description - eNBMachineDesc = MachineDescDic[eNBMachine] - index_eNBMachine = MachineList.index(eNBMachine) - # check that openairinterface is installed on machine - oai_eNB = openair('localdomain', eNBMachine) - oai_eNB.connect(user, password) - cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep --color=never OPENAIR' - res= oai_eNB.send_recv(cmd) - m = re.search('OPENAIR_HOME', res, re.DOTALL) - if m: - print - # Create testcase directory on remote eNB - cmd = 'rm -fr ' + logdir_eNB_testcase + ' ; mkdir -p ' + logdir_eNB_testcase - result = oai_eNB.send_recv(cmd) - - # Check if we need to compile lte-softmodem-noS1 on remote machine - eNB_compile_cmd = eNB_compile_prog + ' '+ eNB_compile_prog_args - if ('last_compile_prog' in eNBMachineDesc) and eNBMachineDesc['last_compile_prog'] == eNB_compile_cmd: - print( Fore.WHITE + indent + "> eNB machine compilation : skipped -> "+eNB_compile_cmd ) - else: - print( Fore.WHITE + indent + "> eNB machine compilation : triggered -> "+eNB_compile_cmd ) - eNBMachineDesc['last_compile_prog'] = eNB_compile_prog + ' '+ eNB_compile_prog_args # if last compilation is the same do not compile again - task_eNB_compile = ' ( uname -a ; date \n' - task_eNB_compile = task_eNB_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' - task_eNB_compile = task_eNB_compile + 'env |grep OPENAIR \n' - task_eNB_compile = task_eNB_compile + update_config_file(oai_eNB, eNB_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' - if eNB_compile_cmd != "": - task_eNB_compile = task_eNB_compile + ' ( ' + eNB_compile_cmd + ' ) > ' + logfile_compile_eNB + ' 2>&1 \n' - task_eNB_compile = task_eNB_compile + ' date ) > ' + logfile_task_eNB_compile_out + ' 2>&1 ' - write_file(logfile_task_eNB_compile, task_eNB_compile, mode="w") - - - thread_eNB = oaiThread(1, "eNB_thread_compile", eNBMachine, user, password , task_eNB_compile, False, timeout_thread) - threads.append(thread_eNB) - thread_eNB.start() - - else: - print( Fore.RED + " -> OAI5G not properly setup ! please check REMOTE MACHINE PREPARATION step") - testcase_verdict = 'INCON' - - - UEMachine = testcase.findtext('UE',default='') - UE_config_file = testcase.findtext('UE_config_file',default='') - UE_compile_prog = testcase.findtext('UE_compile_prog',default='') - UE_compile_prog_args = testcase.findtext('UE_compile_prog_args',default='') - - logfile_compile_UE = logdir_UE_testcase + '/UE_compile.log' - logfile_task_UE_compile_out = logdir_UE_testcase + '/UE_task_compile_out.log' - logfile_task_UE_compile = logdir_local_testcase + '/UE_task_compile.log' - - # Check that machine is in test setup machine list - print( Fore.WHITE + indent + "> testcase UE machine :"), - if (UEMachine not in MachineList): - print( Fore.RED + UEMachine + " not in test setup machine list") - testcase_verdict = 'INCON' - else : - print UEMachine, - # get machine description - UEMachineDesc = MachineDescDic[UEMachine] - index_UEMachine = MachineList.index(UEMachine) - # check that openairinterface is installed on machine - oai_UE = openair('localdomain', UEMachine) - oai_UE.connect(user, password) - cmd = 'cd ' + logdirOAI5GRepo + '; source oaienv ; env|grep --color=never OPENAIR' - res= oai_UE.send_recv(cmd) - m = re.search('OPENAIR_HOME', res, re.DOTALL) - if m: - print - # Create testcase directory on remote UE - cmd = 'rm -fr ' + logdir_UE_testcase + ' ; mkdir -p ' + logdir_UE_testcase - result = oai_UE.send_recv(cmd) - - # Check if we need to compile lte-softmodem-noS1 on remote machine - UE_compile_cmd = UE_compile_prog + ' '+ UE_compile_prog_args - if ('last_compile_prog' in UEMachineDesc) and UEMachineDesc['last_compile_prog'] == UE_compile_cmd: - print( Fore.WHITE + indent + "> UE machine compilation : skipped -> "+UE_compile_cmd ) - else: - print( Fore.WHITE + indent + "> UE machine compilation : triggered -> "+UE_compile_cmd ) - UEMachineDesc['last_compile_prog'] = UE_compile_prog + ' '+ UE_compile_prog_args - task_UE_compile = ' ( uname -a ; date \n' - task_UE_compile = task_UE_compile + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' - task_UE_compile = task_UE_compile + 'env |grep OPENAIR \n' - task_UE_compile = task_UE_compile + update_config_file(oai_UE, UE_config_file, logdirOAI5GRepo, '$OPENAIR_DIR/cmake_targets/autotests/tools/search_repl.py') + '\n' - if UE_compile_cmd != "": - task_UE_compile = task_UE_compile + ' ( ' + UE_compile_cmd + ' ) > ' + logfile_compile_UE + ' 2>&1 \n' - task_UE_compile = task_UE_compile + ' date ) > ' + logfile_task_UE_compile_out + ' 2>&1 ' - write_file(logfile_task_UE_compile, task_UE_compile, mode="w") - - thread_UE = oaiThread(2, "UE_thread_compile", UEMachine, user, password , task_UE_compile, False, timeout_thread) - threads.append(thread_UE) - thread_UE.start() - - else: - print( Fore.RED + " -> OAI5G not properly setup ! please check REMOTE MACHINE PREPARATION step") - testcase_verdict = 'INCON' - - - - - - - # Wait for Compilation thread to terminate - #----------------------------------------- - for t in threads: - t.join() - - # TODO check that compilation is succeed - - #first we compile all the programs -# thread_UE = oaiThread(3, "UE_thread", UEMachine, user, password , task_UE_compile, False, timeout_thread) -# threads.append(thread_UE) -# thread_UE.start() - - - - - -# index_UEMachine = MachineList.index(UEMachine) -# oai_UE = openair('localdomain', UEMachine) -# oai_UE.connect(user, password) -# res = oai_UE.send_recv(cmd) -# res = oai_eNB.send_recv(cmd) - - - - # - # RUN LOOP - # ------------------------------------------------ - if testcase_verdict != 'PASS': # if something went wrong to not run test cases - max_ntries=0 - - indent="\t\t" - - runs_results = [] - nb_runs = 0 - nb_run_pass = 0 - nb_run_failed = 0 - nb_run_inc = 0 - nb_run_skip = 0 - - nb_seg_fault = 0 - - for run in range(0,max_ntries): - - if nruns == nb_run_pass + nb_run_failed: - break - - nb_runs += 1 - - # - # RUN initialization - # ---------------------------------------------------- - - prefix_string = Fore.WHITE + indent + "> RUN_"+str(run).zfill(2)+" :" - -# print (Fore.WHITE + indent + "> RUN_"+str(run).zfill(2)+" : " ), -# sys.stdout.flush() - - run_start_time=datetime.datetime.now() - - logdir_local_run = openairdir_local + '/cmake_targets/autotests/log/'+ testcasename + '/run_' + str(run) - logdir_eNB_run = logdirOAI5GRepo +'/cmake_targets/autotests/log/' + testcasename + '/run_' + str(run) - logdir_UE_run = logdirOAI5GRepo +'/cmake_targets/autotests/log/' + testcasename + '/run_' + str(run) - - cmd = 'rm -fr ' + logdir_eNB_run + ' ; mkdir -p ' + logdir_eNB_run - result = oai_eNB.send_recv(cmd) - cmd = 'rm -fr ' + logdir_UE_run + ' ; mkdir -p ' + logdir_UE_run - result = oai_UE.send_recv(cmd) - cmd = ' rm -fr ' + logdir_local_run + ' ; mkdir -p ' + logdir_local_run - result = os.system(cmd) - - - # - # RUN parametrization - # ---------------------------------------------------- - eNB_pre_exec = testcase.findtext('eNB_pre_exec',default='') - eNB_pre_exec_args = testcase.findtext('eNB_pre_exec_args',default='') - eNB_main_exec = testcase.findtext('eNB_main_exec',default='') - eNB_main_exec_args = testcase.findtext('eNB_main_exec_args',default='') - eNB_traffic_exec = testcase.findtext('eNB_traffic_exec',default='') - eNB_traffic_exec_args = testcase.findtext('eNB_traffic_exec_args',default='') - eNB_terminate_missing_procs = testcase.findtext('eNB_terminate_missing_procs',default='True') - - logfile_exec_eNB = logdir_eNB_run + '/eNB_exec' + '_' + str(run) + '_.log' - logfile_pre_exec_eNB = logdir_eNB_run + '/eNB_pre_exec' + '_' + str(run) + '_.log' - logfile_task_eNB_out = logdir_eNB_run + '/eNB_task_out' + '_' + str(run) + '_.log' - logfile_traffic_eNB = logdir_eNB_run + '/eNB_traffic' + '_' + str(run) + '_.log' - logfile_task_eNB = logdir_local_run + '/eNB_task' + '_' + str(run) + '_.log' - - task_eNB = ' ( uname -a ; date \n' - task_eNB = task_eNB + 'cd ' + logdirOAI5GRepo + ' ; source oaienv ; source cmake_targets/tools/build_helper \n' - task_eNB = task_eNB + 'env |grep OPENAIR \n' + 'array_exec_pid=() \n' - if eNB_pre_exec != "": - task_eNB = task_eNB + ' ( date; ' + eNB_pre_exec + ' '+ eNB_pre_exec_args + ' ) > ' + logfile_pre_exec_eNB + ' 2>&1 \n' - if eNB_main_exec != "": - task_eNB = task_eNB + ' ( date; ' + addsudo(eNB_main_exec + ' ' + eNB_main_exec_args, '') + ' ) > ' + logfile_exec_eNB + ' 2>&1 & \n' - task_eNB = task_eNB + 'array_exec_pid+=($!) \n' - task_eNB = task_eNB + 'echo eNB_main_exec PID = $! \n' - if eNB_traffic_exec != "": - cmd_traffic = eNB_traffic_exec + ' ' + eNB_traffic_exec_args - if cmd_traffic.find('-c') >= 0: - cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 80) - task_eNB = task_eNB + ' (date; ' + cmd_traffic + ' ) > ' + logfile_traffic_eNB + ' 2>&1 & \n' - task_eNB = task_eNB + 'array_exec_pid+=($!) \n' - task_eNB = task_eNB + 'echo eNB_traffic_exec PID = $! \n' - #terminate the eNB test case after timeout_cmd seconds - task_eNB = task_eNB + finalize_deploy_script (timeout_cmd, eNB_terminate_missing_procs) + ' \n' - #task_eNB = task_eNB + 'sleep ' + str(timeout_cmd) + ' \n' - task_eNB = task_eNB + 'handle_ctrl_c' + '\n' - task_eNB = task_eNB + ' ) > ' + logfile_task_eNB_out + ' 2>&1 ' - write_file(logfile_task_eNB, task_eNB, mode="w") - - - UE_pre_exec = testcase.findtext('UE_pre_exec',default='') - UE_pre_exec_args = testcase.findtext('UE_pre_exec_args',default='') - UE_main_exec = testcase.findtext('UE_main_exec',default='') - UE_main_exec_args = testcase.findtext('UE_main_exec_args',default='') - UE_traffic_exec = testcase.findtext('UE_traffic_exec',default='') - UE_traffic_exec_args = testcase.findtext('UE_traffic_exec_args',default='') - UE_terminate_missing_procs = testcase.findtext('UE_terminate_missing_procs',default='True') - UE_search_expr_true = testcase.findtext('UE_search_expr_true','') - - logfile_exec_UE = logdir_UE_run + '/UE_exec' + '_' + str(run) + '_.log' - logfile_pre_exec_UE = logdir_UE_run + '/UE_pre_exec' + '_' + str(run) + '_.log' - logfile_task_UE_out = logdir_UE_run + '/UE_task_out' + '_' + str(run) + '_.log' - logfile_traffic_UE = logdir_UE_run + '/UE_traffic' + '_' + str(run) + '_.log' - logfile_task_UE = logdir_local_run + '/UE_task' + '_' + str(run) + '_.log' - - - task_UE = ' ( uname -a ; date \n' - task_UE = task_UE + 'array_exec_pid=()' + '\n' - task_UE = task_UE + 'cd ' + logdirOAI5GRepo + '\n' - task_UE = task_UE + 'source oaienv \n' - task_UE = task_UE + 'source cmake_targets/tools/build_helper \n' - task_UE = task_UE + 'env |grep OPENAIR \n' - if UE_pre_exec != "": - task_UE = task_UE + ' ( date; ' + UE_pre_exec + ' '+ UE_pre_exec_args + ' ) > ' + logfile_pre_exec_UE + ' 2>&1 \n' - if UE_main_exec != "": - task_UE = task_UE + ' ( date; ' + addsudo(UE_main_exec + ' ' + UE_main_exec_args, '') + ' ) > ' + logfile_exec_UE + ' 2>&1 & \n' - task_UE = task_UE + 'array_exec_pid+=($!) \n' - task_UE = task_UE + 'echo UE_main_exec PID = $! \n' - if UE_traffic_exec != "": - cmd_traffic = UE_traffic_exec + ' ' + UE_traffic_exec_args - if cmd_traffic.find('-c') >= 0: - cmd_traffic = cmd_traffic + ' -t ' + str(timeout_cmd - 60) - task_UE = task_UE + ' ( date; ' + cmd_traffic + ' ) >' + logfile_traffic_UE + ' 2>&1 & \n' - task_UE = task_UE + 'array_exec_pid+=($!) \n' - task_UE = task_UE + 'echo UE_traffic_exec PID = $! \n' - #terminate the UE test case after timeout_cmd seconds - task_UE = task_UE + finalize_deploy_script (timeout_cmd, UE_terminate_missing_procs) + ' \n' - #task_UE = task_UE + 'sleep ' + str(timeout_cmd) + ' \n' - task_UE = task_UE + 'handle_ctrl_c' + '\n' - task_UE = task_UE + ' ) > ' + logfile_task_UE_out + ' 2>&1 ' - write_file(logfile_task_UE, task_UE, mode="w") - #task_UE = 'echo \" ' + task_UE + '\" > ' + logfile_script_UE + ' 2>&1 ; ' + task_UE - - - - - - - - # - # RUN work - # ---------------------------------------------------- - thread_eNB = oaiThread(1, "eNB_thread", eNBMachine, user, password , task_eNB, False, timeout_thread) - thread_UE = oaiThread(2, "UE_thread", UEMachine, user, password , task_UE, False, timeout_thread) - threads=[] - threads.append(thread_eNB) - threads.append(thread_UE) - thread_eNB.start() - thread_UE.start() - - run_work_inprogress_flag = True - progress_step = timeout_thread/20 - progress_count = 0 - - while (run_work_inprogress_flag): - - - update_progress(float(progress_count)/float(timeout_thread),prefix_string) - - time.sleep(progress_step) - - progress_count += progress_step - -# sys.stdout.write ('#') -# sys.stdout.flush() - - run_work_inprogress_flag = False - for t in threads: - if t.isAlive(): - run_work_inprogress_flag = True - - - update_progress(1,prefix_string) - - for t in threads: - t.join() - - - # - # - #----------------------------------------------------- - cleanOldProgramsAllMachines([oai_eNB, oai_UE] , oldprogramList, CleanUpAluLteBox, ExmimoRfStop, [logdir_eNB_run, logdir_UE_run], logdirOAI5GRepo) - - SSHSessionWrapper(eNBMachine, user, None, password, logdir_eNB_run, logdir_local_testcase, "get_all") - #print "Copying files from UEMachine : " + UEMachine + "logdir_UE = " + logdir_UE - SSHSessionWrapper(UEMachine, user, None, password, logdir_UE_run, logdir_local_testcase, "get_all") - - metric_checks_flag = 1 - - fname = logdir_local_run+ '/UE_exec' + '_' + str(run) + '_.log' - cell_synch_status = analyser.check_cell_synchro(fname) - print (Fore.WHITE + indent + "> Check Cell synchro :"), - - if cell_synch_status == 'CELL_SYNCH': - print ( Fore.GREEN + cell_synch_status) - else : - print ( Fore.RED + cell_synch_status) - metric_checks_flag = 0 - - ue_seg_fault_status = analyser.check_exec_seg_fault(fname) - if ue_seg_fault_status == 'SEG_FAULT' : - nb_seg_fault += 1 - - # - # Check metrics - #---------------------------------------------------- - runs_metrics = [] - run_traffic = [] - - if metric_checks_flag : - verdict = 'PASS' - - # UE side metrics - metricList=testcase.findall('UE_metric') - for metric in metricList: - - metric_verdict = 'PASS' - - metric_def = {} - metric_def['id'] = metric.get('id') - metric_def['description'] = metric.get('description') - metric_def['regex'] = metric.get('regex') - metric_def['unit_of_meas'] = metric.get('unit_of_meas') - metric_def['pass_fail_stat']= metric.get('pass_fail_stat') - metric_min_lim = metric.get('min_limit') - if metric_min_lim: - metric_def['min_limit'] = float(metric_min_lim) - metric_max_lim = metric.get('max_limit') - if metric_max_lim: - metric_def['max_limit'] = float(metric_max_lim) - - fname = logdir_local_run+ '/UE_exec' + '_' + str(run) + '_.log' - - args = {'metric' : metric_def, - 'file' : fname } - - metric_extracted = analyser.do_extract_metrics(args) - - print (Fore.WHITE + indent + "> Metric : "+metric_def['id']), - print ("(min="+str( metric_extracted['metric_min'])+", max="+str( metric_extracted['metric_max'])+", mean="+str( metric_extracted['metric_mean'])+", median="+str( metric_extracted['metric_median'])+")") - -# print "\t > Metric "+metric_def['id']+" :" -# print "\t\t> min = "+ str( metric_extracted['metric_min'] ) -# print "\t\t> min_index = "+ str( metric_extracted['metric_min_index'] ) -# print "\t\t> max = "+ str( metric_extracted['metric_max'] ) -# print "\t\t> max_index = "+ str( metric_extracted['metric_max_index'] ) -# print "\t\t> mean = "+ str( metric_extracted['metric_mean'] ) -# print "\t\t> median = "+ str( metric_extracted['metric_median'] ) - - if metric_def['pass_fail_stat'] : - metric_verdict = analyser.do_check_verdict(metric_def, metric_extracted) - - metric_fig = logdir_local_run+ '/UE_metric_'+ metric_def['id']+'_' + str(run) + '_.png' - analyser.do_img_metrics(metric_def, metric_extracted, metric_fig) - - - metric_fig_report = '../log/'+ testcasename + '/run_' + str(run) + '/UE_metric_'+ metric_def['id']+'_' + str(run) + '_.png' - - run_metrics = dict( metric_id = metric_def['id'], - metric_desc = metric_def['description'], - metric_uom = metric_def['unit_of_meas'], - metric_min = metric_extracted['metric_min'], - metric_min_index= metric_extracted['metric_min_index'], - metric_max = metric_extracted['metric_max'], - metric_max_index= metric_extracted['metric_max_index'], - metric_mean = metric_extracted['metric_mean'], - metric_median = metric_extracted['metric_median'], - metric_fig = metric_fig_report) - - if metric_def['pass_fail_stat'] : - run_metrics['pass_fail_stat'] = metric_def['pass_fail_stat'] - if metric_min_lim : - run_metrics['pass_fail_min_limit'] = metric_def['min_limit'] - if metric_max_lim : - run_metrics['pass_fail_max_limit'] = metric_def['max_limit'] - - runs_metrics.append(run_metrics) - - if metric_verdict != 'PASS': - verdict = metric_verdict - - # End Metrics LOOP - # --------------------- - - - # Traffic analysis - if UE_traffic_exec != "": - - fname = logdir_local_run+ '/UE_traffic' + '_' + str(run) + '_.log' - args = {'file' : fname } - traffic_metrics = analyser.do_extract_traffic_metrics(args) - traffic_fig = logdir_local_run+ '/UE_traffic'+'_' + str(run) + '_.png' - analyser.do_img_traffic(traffic_metrics, traffic_fig) - - traffic_fig_report= '../log/'+ testcasename + '/run_' + str(run) + '/UE_traffic'+'_' + str(run) + '_.png' - - dur_pass_fail_crit = 'none' - if traffic_metrics['traffic_count'] == 0 : - verdict = 'FAIL' - elif UE_search_expr_true != "": - traffic_duration_limit = float(UE_search_expr_true) - dur_pass_fail_crit = str(traffic_duration_limit) - # print 'traffic_duration_limit = '+str(traffic_duration_limit) - # print 'traffic_metrics[interval_stop_max] = '+str(traffic_metrics['interval_stop_max']) - if traffic_metrics['interval_stop_max'] < traffic_duration_limit : - verdict = 'FAIL' - - - run_traffic = dict( traffic_count = traffic_metrics['traffic_count'], - bw_min = traffic_metrics['bw_min'], - bw_max = traffic_metrics['bw_max'], - bw_mean = traffic_metrics['bw_mean'], - bw_median = traffic_metrics['bw_median'], - jitter_min = traffic_metrics['jitter_min'], - jitter_max = traffic_metrics['jitter_max'], - jitter_mean = traffic_metrics['jitter_mean'], - jitter_median = traffic_metrics['jitter_median'], - rl_min = traffic_metrics['rl_min'], - rl_max = traffic_metrics['rl_max'], - rl_mean = traffic_metrics['rl_mean'], - rl_median = traffic_metrics['rl_median'], - iperf_duration = traffic_metrics['interval_stop_max'], - dur_pass_fail_crit = dur_pass_fail_crit, - traffic_fig = traffic_fig_report ) - else: - run_traffic = dict( traffic_count = 0) - - else : - verdict = 'SKIP' - - - - # - # RUN verdict and finalization - # ---------------------------------------------------- - run_stop_time=datetime.datetime.now() - run_duration = run_stop_time-run_start_time -# print (Fore.WHITE + ("duration=" :"), - print (Fore.WHITE + indent + "> RUN duration : "+ str(run_duration) +"s" ) - - print (Fore.WHITE + indent + "> RUN verdict :"), - - if verdict == 'PASS': - nb_run_pass += 1 - print ( Fore.GREEN + verdict) - elif verdict == 'FAIL': - nb_run_failed += 1 - testcase_verdict = 'FAIL' - print ( Fore.RED + verdict) - elif verdict == 'SKIP': - nb_run_skip += 1 - print ( Fore.YELLOW + verdict) - else: - nb_run_inc += 1 - if testcase_verdict == 'PASS' : testcase_verdict = 'INCON' - print (Fore.YELLOW+'INCONCLUSIVE') - - run_results = dict( run_id=str(run), - run_start_time = run_start_time, - run_stop_time = run_stop_time , - run_verdict = verdict, - ue_seg_fault_status = ue_seg_fault_status, - run_duration = run_duration, - runs_metrics = runs_metrics, - run_traffic = run_traffic) - runs_results.append(run_results) - - # END RUN LOOP - #---------------------------------------------------- - - indent="\t" - - # Test case duration - # ---------------------------------- - testcase_time_stop = datetime.datetime.now() - print(Fore.WHITE + indent + "> testcase time stop : " + str(testcase_time_start) ), - print " -> TestCase duration = "+str(testcase_time_stop - testcase_time_start) - - # Save remote log files - # ----------------------------------- - #Now we change the permissions of the logfiles to avoid some of them being with root permissions - cmd = 'sudo -E chown -R ' + user + ' ' + logdir_eNB_testcase - res= oai_eNB.send_recv(cmd) - cmd = 'sudo -E chown -R ' + user + ' ' + logdir_UE_testcase - res= oai_UE.send_recv(cmd) - - # Save remote log files on MTC - #print "Copying files from eNBMachine " + eNBMachine + "logdir_eNB = " + logdir_eNB - SSHSessionWrapper(eNBMachine, user, None, password, logdir_eNB_testcase, openairdir_local + '/cmake_targets/autotests/log/', "get_all") - #print "Copying files from UEMachine : " + UEMachine + "logdir_UE = " + logdir_UE - SSHSessionWrapper(UEMachine, user, None, password, logdir_UE_testcase, openairdir_local + '/cmake_targets/autotests/log/', "get_all") - - oai_eNB.disconnect() - oai_UE.disconnect() - - # Set test case final verdict - # ----------------------------------- - test_result_string = 'do be completed' - - if testcase_verdict == 'PASS': - if nb_run_pass == 0 : - testcase_verdict = 'INCON' - - print(Fore.WHITE + indent + "> testcase final verdict :"), - if testcase_verdict == 'PASS': - print ( Fore.GREEN + testcase_verdict) - elif testcase_verdict == 'FAIL': - print ( Fore.RED + testcase_verdict) - else: - print (Fore.YELLOW+'INCONCLUSIVE') - - print(Style.RESET_ALL) - - duration= testcase_time_stop - testcase_time_start - - test_result = dict(testcase_name=testcasename, - testcaseclass=testcaseclass, - testcase_verdict = testcase_verdict, - testcase_time_start=testcase_time_start, - testcase_time_stop=testcase_time_stop, - tags=tags, - nruns=nb_runs, - nb_run_pass = nb_run_pass, - nb_run_skip = nb_run_skip, - nb_run_failed = nb_run_failed, - nb_run_inc=nb_run_inc, - nb_seg_fault = nb_seg_fault, - testcase_timeout=timeout_cmd, - testcase_duration = duration, - testcase_eNBMachine =eNBMachine, - testcase_UEMachine =UEMachine, - runs_results = runs_results) - test_results.append(test_result) - - xmlFile = logdir_local_testcase + '/test.' + testcasename + '.xml' - xml="\n \n" - write_file(xmlFile, xml, mode="w") - - xmlFile_ng = logdir_local_testcase + '/test.' + testcasename + '_ng.xml' - xml_ng = xmlify(test_result, wrap=testcasename, indent=" ") - write_file(xmlFile_ng, xml_ng, mode="w") - - - - return testcase_verdict - - - - -# \brief This function searches if test case is present in list of test cases that need to be executed by user -# \param testcasename the test case to search for -# \param testcasegroup list that is passed from the arguments -# \param test_case_exclude list of test cases excluded from execution (specified in test_case_list.xml) -def search_test_case_group(testcasename, testcasegroup, test_case_exclude): - - if test_case_exclude != "": - testcase_exclusion_list=test_case_exclude.split() - for entry in testcase_exclusion_list: - if entry.find('+') >=0: - match = re.search(entry, testcasename) - if match: - #print "\nSkipping test case as it is found in black list: " + testcasename - return False - else: - match = entry.find(testcasename) - if match >=0: - #print "\nSkipping test case as it is found in black list: " + testcasename - return False - if testcasegroup == '': - return True - else: - testcaselist = testcasegroup.split() - for entry in testcaselist: - if entry.find('+') >=0: - match = re.search(entry, testcasename) - if match: - return True - else: - match = testcasename.find(entry) - if match >=0: - return True - return False - -# \brief thread that cleans up remote machines from pre-existing test case executions -# \param threadID number of thread (for book keeping) -# \param threadname name of thread (for book keeping) -# \param oai handler that can be used to execute programs on remote machines -# \param CleanUpOldProgs list of programs which must be terminated before running a test case (specified in test_case_list.xml) -# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) -# \param ExmimoRfStop command to stop EXMIMO Card -class oaiCleanOldProgramThread (threading.Thread): - def __init__(self, threadID, threadname, oai, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop, logdir, logdirOAI5GRepo): - threading.Thread.__init__(self) - self.threadID = threadID - self.threadname = threadname - self.oai = oai - self.CleanUpOldProgs = CleanUpOldProgs - self.CleanUpAluLteBox = CleanUpAluLteBox - self.ExmimoRfStop = ExmimoRfStop - self.logdir = logdir - self.logdirOAI5GRepo = logdirOAI5GRepo - def run(self): - try: - cleanOldPrograms(self.oai, self.CleanUpOldProgs, self.CleanUpAluLteBox, self.ExmimoRfStop, self.logdir, self.logdirOAI5GRepo) - except Exception, e: - error='' - error = error + ' In class oaiCleanOldProgramThread, function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) - error = error + '\n threadID = ' + str(self.threadID) + '\n threadname = ' + self.threadname + '\n CleanUpOldProgs = ' + self.CleanUpOldProgs + '\n CleanUpAluLteBox = ' + self.CleanUpAluLteBox + '\n ExmimoRfStop = ' + self.ExmimoRfStop + '\n' - error = error + traceback.format_exc() - print error - print "There is error in cleaning up old programs....." - #sys.exit(1) - -# \brief Run parallel threads in all machines for clean up old execution of test cases -# \param oai_list list of handlers that can be used to execute programs on remote machines -# \param CleanUpOldProgs list of programs which must be terminated before running a test case (specified in test_case_list.xml) -# \param CleanupAluLteBox string that contains commands to stop ALU Bell Labs LTEBox (specified in test_case_list.xml) -# \param ExmimoRfStop command to stop EXMIMO Card -def cleanOldProgramsAllMachines(oai_list, CleanOldProgs, CleanUpAluLteBox, ExmimoRfStop, logdir_list, logdirOAI5GRepo): - threadId=0 - threadList=[] - index=0 - if len(oai_list)!=len(logdir_list) : - logdir_list=[logdir[0]]*len(oai_list) - - for oai in oai_list: - threadName="cleanup_thread_"+str(threadId) - thread=oaiCleanOldProgramThread(threadId, threadName, oai, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop, logdir_list[index],logdirOAI5GRepo) - threadList.append(thread) - thread.start() - threadId = threadId + 1 - index = index+1 - for t in threadList: - t.join() - - -debug = 0 -pw ='' -i = 0 -dlsim=0 -localshell=0 -GitOAI5GRepo='' -GitOAI5GRepoBranch='' -GitOAI5GHeadVersion='' -user='' -pw='' -testcasegroup='' -NFSResultsShare='' -cleanUpRemoteMachines=False -openairdir_local = os.environ.get('OPENAIR_DIR') -if openairdir_local is None: - print "Environment variable OPENAIR_DIR not set correctly" - sys.exit() -locallogdir = openairdir_local + '/cmake_targets/autotests/log' -reportdir = openairdir_local + '/cmake_targets/autotests/report' -MachineList = '' -MachineListGeneric='' -MachineDescDic={} -flag_remove_logdir=False -flag_start_testcase=False -nruns_lte_softmodem='' -flag_skip_git_head_check=False -flag_skip_oai_install=False -flag_skip_machine_preparation=False -flag_skip_sanity_check=False -Timeout_cmd='' -xmlInputFile='' - -#print "Number of arguments argc = " + str(len(sys.argv)) -#for index in range(1,len(sys.argv) ): -# print "argv_" + str(index) + " : " + sys.argv[index] - -oai_list = [] - - -i=1 -while i < len (sys.argv): - arg=sys.argv[i] - if arg == '-r': - flag_remove_logdir=True - elif arg == '-s' : - flag_start_testcase=True - elif arg == '-g' : - testcasegroup = sys.argv[i+1].replace("\"","") - i = i +1 - elif arg == '-c': - cleanUpRemoteMachines=True - elif arg == '-5GRepo': - GitOAI5GRepo = sys.argv[i+1] - i = i +1 - elif arg == '-5GRepoBranch': - GitOAI5GRepoBranch = sys.argv[i+1] - i = i +1 - elif arg == '-5GRepoHeadVersion': - GitOAI5GHeadVersion = sys.argv[i+1] - #We now find the branch that corresponds to this Git Head Commit - cmd = "git show-ref --head " + " | grep " + GitOAI5GHeadVersion - cmd_out = subprocess.check_output ([cmd], shell=True) - cmd_out=cmd_out.replace("\n","") - cmd_out = cmd_out.split('/') - GitOAI5GRepoBranch = cmd_out[-1] - if GitOAI5GRepoBranch == '': - print "Error extracting GitBranch from head commit. Exiting now..." - sys.exit(1) - i = i +1 - elif arg == '-u': - user = sys.argv[i+1] - i = i +1 - elif arg == '-p': - pw = sys.argv[i+1] - i = i +1 - elif arg == '-n': - NFSResultsShare = sys.argv[i+1] - i = i +1 - elif arg == '--nrun_lte_softmodem': - nruns_lte_softmodem = sys.argv[i+1] - i = i +1 - elif arg == '-MachineList': - MachineList = sys.argv[i+1] - MachineList = MachineList.replace("\"","") - MachineList = MachineList.replace("\'","") - i = i +1 - elif arg == '-MachineListGeneric': - MachineListGeneric = sys.argv[i+1] - MachineListGeneric = MachineListGeneric.replace("\"","") - MachineListGeneric = MachineListGeneric.replace("\'","") - i = i +1 - elif arg == '--skip-git-head-check': - flag_skip_git_head_check=True - elif arg == '--timeout_cmd': - Timeout_cmd = sys.argv[i+1] - i = i +1 - elif arg == '--skip-oai-install': - flag_skip_oai_install=True - elif arg == '--skip-machine-preparation': - flag_skip_machine_preparation=True - elif arg == '--skip-sanity-check': - flag_skip_sanity_check=True - elif arg == '--test-suite' : - xmlInputFile = sys.argv[i+1] - i = i +1 - elif arg == '-h' : - print "-s: This flag *MUST* be set to start the test cases" - print "-r: Remove the log directory in autotests" - print "-g: Run test cases in a group" - print "-c: Run cleanup scripts on remote machines and exit" - print "-5GRepo: Repository for OAI 5G to use to run tests (overrides GitOAI5GRepo in test_case_list.xml)" - print "-5GRepoBranch: Branch for OAI 5G Repository to run tests (overrides the branch in test_case_list.xml)" - print "-5GRepoHeadVersion: Head commit on which to run tests (overrides the branch in test_case_list.xml)" - print "-u: use the user name passed as argument" - print "-p: use the password passed as an argument" - print "-n: Set the NFS share passed as an argument" - print "--nrun_lte_softmodem: Set the number of runs for lte-softmodem test case class" - print "-MachineList : overrides the MachineList parameter in test_case_list.xml" - print "-MachineListGeneric : overrides the MachineListGeneric parameter in test_case_list.xml" - print "--skip-git-head-check: skip checking of GitHead remote/local branch (only for debugging)" - print "--timeout_cmd: Override the default parameter (timeout_cmd) in test_case_list.xml. This parameter is in seconds and should be > 120" - print "--skip-oai-install: Skips the openairinterface5g installer" - print "--skip-machine-preparation: skipp the whole system preparation -> direct to test cases" - print "--skip-sanity-check: skipp the machine sanity checks" - print "--test-suite: Select a XML test-suite file" - sys.exit() - else : - print "Unrecongnized Option: <" + arg + ">. Use -h to see valid options" - sys.exit() - i= i + 1 - -logdir = '/tmp/' + 'OAITestFrameWork-' + user + '/' -logdirOAI5GRepo = logdir + 'openairinterface5g/' -logdirOpenaircnRepo = logdir + 'openair-cn/' -patchdir = logdirOAI5GRepo + 'cmake_targets/autotests/patches/' -NFSResultsDir = '/mnt/sradio' -cleanupOldProgramsScript = '$OPENAIR_DIR/cmake_targets/autotests/tools/remove_old_programs.bash' - -#Now we parse the xml file for basic configuration -xmlTree = ET.parse(xmlInputFile) -xmlRoot = xmlTree.getroot() - -# -# Read test session configuration -# --------------------------------------------------------------------------------- -print (Fore.YELLOW + '\nStep 0.1 - Read test session configuration') -print (Fore.YELLOW + '-------------------------------------------------') - -test_session_start_time = datetime.datetime.now() -print (Fore.WHITE + ' - start time : '+ str(test_session_start_time)) - -host = os.uname()[1] -print (Fore.WHITE + ' - MTC host : '+host) - - -if user=='': - user = getpass.getuser() -print (Fore.WHITE + ' - user : '+user) - -if pw=='': - pw = getpass.getpass() -print (Fore.WHITE + ' - password : '+pw) - -print (Fore.WHITE + ' - cmd line flags : ') -print (Fore.WHITE + ' + -s : '+str(flag_start_testcase)) -print (Fore.WHITE + ' + -r : '+str(flag_remove_logdir)) -print (Fore.WHITE + ' + -c : '+str(cleanUpRemoteMachines)) -print (Fore.WHITE + ' + --skip-git-head-check : '+str(flag_skip_git_head_check)) -print (Fore.WHITE + ' + --skip-oai-install : '+str(flag_skip_oai_install)) -print (Fore.WHITE + ' + --skip-machine-preparation : '+str(flag_skip_machine_preparation)) -print (Fore.WHITE + ' + --skip-sanity-check : '+str(flag_skip_sanity_check)) - - -print (Fore.WHITE + ' - Test setup basic config : (* -> overwrite by cmd line parameter)') -print (Fore.WHITE + ' + test setup config file : '+str(xmlInputFile)) -print (Fore.WHITE + ' + remote setup dir : '+str(logdir)) -print (Fore.WHITE + ' + remote OAI5G repo : '+str(logdirOAI5GRepo)) -print (Fore.WHITE + ' + remote OpenAirCN repo : '+str(logdirOpenaircnRepo)) - - -if MachineList =='': - MachineList = xmlRoot.findtext('MachineList',default='') -NFSResultsShare = xmlRoot.findtext('NFSResultsShare',default='') -GitOpenaircnRepo = xmlRoot.findtext('GitOpenair-cnRepo',default='') - -if GitOAI5GRepo == '': - GitOAI5GRepo = xmlRoot.findtext('GitOAI5GRepo',default='') - -if GitOAI5GRepoBranch == '': - GitOAI5GRepoBranch = xmlRoot.findtext('GitOAI5GRepoBranch',default='') -if GitOAI5GHeadVersion == '': - GitOAI5GHeadVersion = xmlRoot.findtext('GitOAI5GHeadVersion',default='') - -GitOpenaircnRepoBranch = xmlRoot.findtext('GitOpenair-cnRepoBranch',default='') -CleanUpOldProgs = xmlRoot.findtext('CleanUpOldProgs',default='') -CleanUpAluLteBox = xmlRoot.findtext('CleanUpAluLteBox',default='') -Timeout_execution = int (xmlRoot.findtext('Timeout_execution')) -if MachineListGeneric == '': - MachineListGeneric = xmlRoot.findtext('MachineListGeneric',default='') -TestCaseExclusionList = xmlRoot.findtext('TestCaseExclusionList',default='') -ExmimoRfStop = xmlRoot.findtext('ExmimoRfStop',default='') -if nruns_lte_softmodem == '': - nruns_lte_softmodem = xmlRoot.findtext('nruns_lte-softmodem',default='') - -print (Fore.WHITE + ' + MachineList : '+ MachineList) -print (Fore.WHITE + ' + GitOpenair-cnRepo : '+ GitOpenaircnRepo) -print (Fore.WHITE + ' + GitOAI5GRepo : '+ GitOAI5GRepo) -print (Fore.WHITE + ' + GitOAI5GBranch : '+ GitOAI5GRepoBranch) -print (Fore.WHITE + ' + GitOpenaircnRepoBranch : '+ GitOpenaircnRepoBranch) -print (Fore.WHITE + ' + NFSResultsShare : '+ NFSResultsShare) -print (Fore.WHITE + ' + nruns_lte_softmodem : '+ nruns_lte_softmodem) -print (Fore.WHITE + ' + Timeout_cmd : '+ Timeout_cmd) - - -if GitOAI5GHeadVersion == '': - cmd = "git log --pretty=format:\'%H\' -n 1" # origin/"+ GitOAI5GRepoBranch -# cmd = "git show-ref --heads -s "+ GitOAI5GRepoBranch - GitOAI5GHeadVersion = subprocess.check_output ([cmd], shell=True) - GitOAI5GHeadVersion=GitOAI5GHeadVersion.replace("\n","") - - # Print commiter and date : git log -1 --pretty=format:"%an %ad" - -print (Fore.WHITE + ' + GitOAI5GHeadVersion : '+ GitOAI5GHeadVersion) -#print "CleanUpOldProgs = " + CleanUpOldProgs -print (Fore.WHITE + ' + Timeout_execution (s) : '+ str(Timeout_execution)) - -if GitOAI5GHeadVersion == '': - print "Error getting the OAI5GBranch Head version...Exiting" - sys.exit() - -NFSTestsResultsDir = NFSResultsShare + '/'+ GitOAI5GRepoBranch + '/' + GitOAI5GHeadVersion - -#print "NFSTestsResultsDir = " + NFSTestsResultsDir - -OAI5GpatchFileList=xmlRoot.findall('OAI5GPatchFile') - - - -MachineList = MachineList.split() -MachineListGeneric = MachineListGeneric.split() - - -MachineDescDic - - -# -# 'Check Mater Test Controller sanity (MTC)' -# --------------------------------------------------------------------------------- -print (Fore.YELLOW + '\nStep 0.2 - Check Mater Test Controller sanity (MTC)') -print (Fore.YELLOW + '-------------------------------------------------') - -try: - print (Fore.WHITE + ' - check OpenAirInterface environment variable OPENAIR1_DIR... '), - os.environ["OPENAIR1_DIR"] -except KeyError: - print (Fore.RED + 'FAILED') - print "Please set the environment variable OPENAIR1_DIR in the .bashrc or run 'source oaienv' " - exit_prog(1) -print (Fore.GREEN + 'OK') - -try: - print (Fore.WHITE + ' - check OpenAirInterface environment variable OPENAIR2_DIR... '), - os.environ["OPENAIR2_DIR"] -except KeyError: - print (Fore.RED + 'FAILED') - print "Please set the environment variable OPENAIR2_DIR in the .bashrc or run 'source oaienv' " - exit_prog(1) -print (Fore.GREEN + 'OK') - -try: - os.environ["OPENAIR_TARGETS"] -except KeyError: - print "Please set the environment variable OPENAIR_TARGETS in the .bashrc or run 'source oaienv' " - sexit_prog(1) - -print (Fore.WHITE + ' - kill zombie ssh sessions from earlier sessions... '), -cmd='ps aux |grep \"/usr/bin/ssh -q -l ' + user + '\"| tr -s \" \" :| cut -f 2 -d :| xargs kill -9 ' -os.system(cmd) -print (Fore.GREEN + 'DONE') - -if flag_start_testcase == False: - print "You need to start the testcase by passing option -s. Use -h to see all options. Aborting now..." - exit_prog(1) - - -#print "Killing zombie ssh sessions from earlier sessions..." -#cmd='ps aux |grep \"/usr/bin/ssh -q -l guptar\"|tr -s \" \" :|cut -f 2 -d :|xargs kill -9 ' -#cmd = cmd + '; ps aux |grep \"/usr/bin/ssh -q -l ' + user + '\"| tr -s \" \" :| cut -f 2 -d :| xargs kill -9 ' -#os.system(cmd) -#print cmd - -try: - analyser = __import__("lib_autotest_analyser") -except ImportError as err: - print('Import error: ' + str(err)) - exit(0) - -if flag_remove_logdir == True: - print "Removing directory: " + locallogdir - os.system(' rm -fr ' + locallogdir + '; mkdir -p ' + locallogdir ) - -if not os.path.exists(locallogdir): - os.system('mkdir -p ' + locallogdir ) - - -paramiko_logfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/log/paramiko.log') -res=os.system(' echo > ' + paramiko_logfile) -paramiko.util.log_to_file(paramiko_logfile) - - -# -# 'REMOTE MACHINE SANITY CHEKS' -# --------------------------------------------------------------------------------- -print (Fore.YELLOW + '\nStep 0.3 - REMOTE MACHINE SANITY CHEKS') -print (Fore.YELLOW + '-------------------------------------------------') - - -for machine in MachineList: - oai_list.append( openair('localdomain',machine)) - MachineDescDic[machine]={} - - -if not flag_skip_sanity_check: - - if localshell == 0: - try: - index=0 - for machine in MachineList: - print (Fore.WHITE + " - Check sanity for remote machine "+machine) - - oai_list[index].connect(user,pw) - print (Fore.WHITE + " > Checking for sudo permissions for user "+user+ " : "), - result = oai_list[index].send_expect_false('sudo -S -v','may not run sudo',True) - if (result == 'OK'): - print (Fore.GREEN + result ) - else: - print (Fore.RED + result ) - - print (Fore.WHITE + " > Cleaning Older running programs : "), - cleanOldPrograms(oai_list[index], CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop, '$HOME', '/tmp') - print (Fore.WHITE + " Done") - - #result = oai_list[index].send('mount ' + NFSResultsDir, True) - #print "Mounting NFS Share " + NFSResultsDir + "..." + result - - # Check if NFS share is mounted correctly. - #print 'Checking if NFS Share<' + NFSResultsDir + '> is mounted correctly...' - #cmd = 'if grep -qs '+NFSResultsDir+ ' /proc/mounts; then echo \'' + NFSResultsDir + ' is mounted\' ; fi' - #search_expr = NFSResultsDir + ' is mounted' - #print "cmd = " + cmd - #print "search_expr = " + search_expr - #result = oai_list[index].send_expect(cmd, search_expr) - #print "Mount NFS_Results_Dir..." + result - index = index + 1 - - #oai.connect2(user,pw) - #oai.get_shell() - except : - print 'Fail to connect to the machine: '+ machine - sys.exit(1) - else: - pw = '' - oai_list[0].connect_localshell() -else: - print (Fore.RED + " Skipping Machine sanity check...") - - -# -# 'REMOTE MACHINE TEST SETUP CONFIGURATION' -# --------------------------------------------------------------------------------- -print (Fore.YELLOW + '\nStep 0.4 - REMOTE MACHINE PREPARATION') -print (Fore.YELLOW + '-------------------------------------------------') - -if not flag_skip_machine_preparation: - index=0 - threads_init_setup=[] - for oai in oai_list: - try: - print "setting up machine: " + MachineList[index] - #print oai_list[oai].send_recv('echo \''+pw+'\' |sudo -S -v') - #print oai_list[oai].send_recv('sudo su') - #print oai_list[oai].send_recv('who am i') - #cleanUpPrograms(oai_list[oai] - cmd = 'sudo -S -E rm -fr ' + logdir + ' ; mkdir -p ' + logdir - result = oai.send_recv(cmd) - print cmd - - setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' - setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' - - #Sometimes git fails so the script below retries in that case - localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/tools/git-retry.sh') - remotefile = logdir + '/git-retry.sh' - paramList=[] - port=22 - paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) - sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') - sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) - - cmd = ' ( \n' - #cmd = cmd + 'rm -fR ' + logdir + '\n' - #cmd = cmd + 'mkdir -p ' + logdir + '\n' - cmd = cmd + 'cd '+ logdir + '\n' - cmd = cmd + 'sudo apt-get install -y git \n' - cmd = cmd + 'chmod 700 ' + logdir + '/git-retry.sh \n' - cmd = cmd + logdir + '/git-retry.sh clone '+ GitOAI5GRepo +' \n' - cmd = cmd + logdir + '/git-retry.sh clone '+ GitOpenaircnRepo + ' \n' - cmd = cmd + 'cd ' + logdirOAI5GRepo + '\n' - cmd = cmd + 'git checkout ' + GitOAI5GRepoBranch + '\n' - if GitOAI5GHeadVersion : - cmd = cmd + 'git checkout ' + GitOAI5GHeadVersion + '\n' - cmd = cmd + 'git_head=`git ls-remote |grep \'' + GitOAI5GRepoBranch + '\'` \n' - cmd = cmd + 'git_head=($git_head) \n' - cmd = cmd + 'git_head=${git_head[0]} \n' - cmd = cmd + 'echo \"GitOAI5GHeadVersion_remote = $git_head\" \n' - cmd = cmd + 'echo \"GitOAI5GHeadVersion_local = ' + GitOAI5GHeadVersion + '\" \n' - if flag_skip_git_head_check==True: - cmd = cmd + 'echo \"skipping GitHead check...\" \n ' - else: - cmd = cmd + 'if [ \"$git_head\" != \"'+ GitOAI5GHeadVersion + '\" ]; then echo \"error: Git openairinterface5g head version does not match\" ; fi \n' - cmd = cmd + 'source oaienv' + '\n' - if flag_skip_oai_install == False: - cmd = cmd + 'source $OPENAIR_DIR/cmake_targets/tools/build_helper \n' - cmd = cmd + 'echo \"Installing core OAI dependencies...Start\" \n' - cmd = cmd + '$OPENAIR_DIR/cmake_targets/build_oai -I --install-optional-packages \n' - cmd = cmd + 'echo \"Installing core OAI dependencies...Finished\" \n' - #cmd = cmd + 'echo \"Installing BLADERF OAI dependencies...Start\" \n' - #cmd = cmd + 'check_install_bladerf_driver \n' - #cmd = cmd + 'echo \"Installing BLADERF OAI dependencies...Finished\" \n' - #cmd = cmd + 'echo \"Installing USRP OAI dependencies...Start\" \n' - #cmd = cmd + 'check_install_usrp_uhd_driver \n' - #cmd = cmd + 'echo \"Installing USRP OAI dependencies...Finished\" \n' - cmd = cmd + 'cd ' + logdirOpenaircnRepo + '\n' - cmd = cmd + 'git checkout ' + GitOpenaircnRepoBranch + '\n' - cmd = cmd + 'env |grep OPENAIR' + '\n' - cmd = cmd + ' cd ' + logdir + '\n' - cmd = cmd + 'mkdir -p ' + patchdir + '\n' - cmd = cmd + ' ) > ' + setuplogfile + ' 2>&1 \n' - #cmd = cmd + 'echo \' ' + cmd + '\' > ' + setup_script + ' 2>&1 \n ' - #result = oai_list[index].send_recv(cmd, False, 300 ) - write_file(setup_script, cmd, mode="w") - tempThread = oaiThread(index, 'thread_setup_'+str(index)+'_' + MachineList[index] , MachineList[index] , user, pw, cmd, False, 3000) - threads_init_setup.append(tempThread ) - tempThread.start() - index = index + 1 - except Exception, e: - print 'There is error in one of the commands to setup the machine '+ MachineList[index] - error='' - error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) - error = error + traceback.format_exc() - print error - sys.exit(1) - - #Now we wait for all the threads to complete - index = 0 - for t in threads_init_setup: - t.join() - - port = 22 - paramList=[] - sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') - - #Now we copy patch files and apply them - print( Fore.WHITE + " - Installating patch files on machine " + MachineList[index]) - for patchFile in OAI5GpatchFileList: - localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/patches/')+patchFile.get('name') - remotefile = logdirOAI5GRepo + '/cmake_targets/autotests/patches/'+patchFile.get('name') - if patchFile.get('machine') == MachineList[index] or patchFile.get('machine') == None: - if os.path.isfile(localfile): - print( Fore.WHITE + "\t> PATCH FILE :"+localfile) - paramList=[] - paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) - sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) - cmd = ' cd ' + logdirOAI5GRepo + ' ;git apply cmake_targets/autotests/patches/'+patchFile.get('name') - res = oai_list[index].send_recv(cmd) - #print res - - paramList=[] - - setuplogfile = logdir + '/setup_log_' + MachineList[index] + '_.txt' - setup_script = locallogdir + '/setup_script_' + MachineList[index] + '_.txt' - localfile = locallogdir + '/setup_log_' + MachineList[index] + '_.txt' - remotefile = logdir + '/setup_log_' + MachineList[index] + '_.txt' - sftp_log = os.path.expandvars(locallogdir + '/sftp_module.log') - paramList.append ( {"operation":'get', "localfile":localfile, "remotefile":remotefile} ) - #sftp_module (user, pw, MachineList[index], port, localfile, remotefile, sftp_log, "get") - - #Now we copy test_case_list.xml on the remote machines - localfile = os.path.expandvars('$OPENAIR_DIR/cmake_targets/autotests/test_case_list.xml') - remotefile = logdirOAI5GRepo + '/cmake_targets/autotests/test_case_list.xml' - # paramList.append ( {"operation":'put', "localfile":localfile, "remotefile":remotefile} ) - # sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) - - sftp_module (user, pw, MachineList[index], port, paramList, sftp_log) - - - cmd = ' cd ' + logdirOAI5GRepo + ' ; source oaienv ; env|grep OPENAIR \n' - res = oai_list[index].send_recv(cmd) - index = index +1 - if os.path.exists(localfile) == 0: - print "Setup log file <" + localfile + "> missing for machine <" + MachineList[index] + ">. Please check the setup log files. Exiting now" - sys.exit(1) - - #Now we process all the test cases - #Now we check if there was error in setup files - - status, out = commands.getstatusoutput('grep ' + ' -il \'error\' ' + locallogdir + '/setup_log*') - if (out != '') : - print "There is error in setup of machines" - print "status = " + str(status) + "\n Check files for error = " + out - print "Exiting now..." - sys.exit(1) - - cleanOldProgramsAllMachines(oai_list, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop, '$HOME' , logdirOAI5GRepo) - if cleanUpRemoteMachines == True: - print "Error while cleaning Remote machines" - print "Exiting now..." - sys.exit(0) - - -else: - print (Fore.RED + " Skipping Machine preparation...") - -# ************************************************************************** -# ************************************************************************** -# STEP 2 - TEST SELECTION AND PARAMETRIZATION -# ************************************************************************** -# ************************************************************************** - -print (Fore.YELLOW + '\nStep 2 - TEST SELECTION') -print (Fore.YELLOW + '-------------------------------------------------') - -print (Fore.WHITE + " Parsing test case list for test selection...") -print (Fore.WHITE + " - TestCaseExclusionList : "+TestCaseExclusionList) -print (Fore.WHITE + " - testcasegroup : "+testcasegroup) - - - - -testcaseList=xmlRoot.findall('testCase') - -nb_total_testcases = 0 -nb_total_testcases_softmodem = 0 -nb_total_testcases_softmodem_noS1 = 0 -nb_total_testcases_compilation = 0 -nb_total_testcases_execution = 0 - -nb_run_testcases = 0 -nb_run_testcases_softmodem = 0 -nb_run_testcases_softmodem_noS1 = 0 -nb_run_testcases_compilation = 0 -nb_run_testcases_execution = 0 - - -for testcase in testcaseList: - try: - testcasename = testcase.get('id') - testcaseclass = testcase.findtext('class',default='') - desc = testcase.findtext('desc',default='') - nb_total_testcases+=1 - - run_flag = search_test_case_group(testcasename, testcasegroup, TestCaseExclusionList) - if (run_flag): - nb_run_testcases+=1 - - if testcaseclass == 'lte-softmodem' : - nb_total_testcases_softmodem+=1 - if (run_flag): nb_run_testcases_softmodem+=1 - elif testcaseclass == 'lte-softmodem-noS1': - nb_total_testcases_softmodem_noS1+=1 - if (run_flag): nb_run_testcases_softmodem_noS1+=1 - elif testcaseclass == 'compilation': - nb_total_testcases_compilation+=1 - if (run_flag): nb_run_testcases_compilation+=1 - elif testcaseclass == 'execution': - nb_total_testcases_execution+=1 - if (run_flag): nb_run_testcases_execution+=1 - else : - print "Unknown test case class: " + testcaseclass - sys.exit() - - except Exception, e: - error='' - error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) - error = error + '\n testcasename = ' + testcasename + '\n testcaseclass = ' + testcaseclass + '\n desc = ' + 'desc' + '\n' - error = error + traceback.format_exc() - print error - print "Continuing to next test case..." - -print (Fore.WHITE + " Parsing done...") - -print (Fore.WHITE + " - Total number of test cases : "+str(nb_total_testcases)) -print (Fore.WHITE + " - Total number class softmodem : "+str(nb_total_testcases_softmodem)) -print (Fore.WHITE + " - Total number class softmodem-noS1 : "+str(nb_total_testcases_softmodem_noS1)) -print (Fore.WHITE + " - Total number class compilation : "+str(nb_total_testcases_compilation)) -print (Fore.WHITE + " - Total number class execution : "+str(nb_total_testcases_execution)) -print -print (Fore.WHITE + " - Selected number of test cases : "+str(nb_run_testcases)) -print (Fore.WHITE + " - Selected class softmodem : "+str(nb_run_testcases_softmodem)) -print (Fore.WHITE + " - Selected class softmodem_noS1 : "+str(nb_run_testcases_softmodem_noS1)) -print (Fore.WHITE + " - Selected class compilation : "+str(nb_run_testcases_compilation)) -print (Fore.WHITE + " - Selected class execution : "+str(nb_run_testcases_execution)) - -# ************************************************************************** -# ************************************************************************** -# STEP 3 - TEST CAMPAIGNS -# ************************************************************************** -# ************************************************************************** - -test_results = [] - - -print (Fore.YELLOW + '\nStep 3 - TEST CAMPAIGNS') -print (Fore.YELLOW + '-------------------------------------------------') - -print (Fore.WHITE + " Start test campaign...") - -run_count = 0 -for testcase in testcaseList: - try: - testcasename = testcase.get('id') - testcaseclass = testcase.findtext('class',default='') - desc = testcase.findtext('desc',default='') - #print "Machine list top level = " + ','.join(MachineList) - - if search_test_case_group(testcasename, testcasegroup, TestCaseExclusionList) == True: - run_count+=1 - print (Fore.WHITE + " ("+str(run_count).zfill(3)+"/"+str(nb_run_testcases).zfill(3)+") - test case "+testcasename+" : "), - if testcaseclass == 'lte-softmodem' : - eNBMachine = testcase.findtext('eNB',default='') - UEMachine = testcase.findtext('UE',default='') - EPCMachine = testcase.findtext('EPC',default='') - #index_eNBMachine = MachineList.index(eNBMachine) - #index_UEMachine = MachineList.index(UEMachine) - #index_EPCMachine = MachineList.index(EPCMachine) - if (eNBMachine not in MachineList)|(UEMachine not in MachineList)|(UEMachine not in MachineList): - print "One of the machines is not in the machine list" - print "eNBMachine : " + eNBMachine + "UEMachine : " + UEMachine + "EPCMachine : " + EPCMachine + "MachineList : " + ','.join(MachineList) - print "testcasename = " + testcasename + " class = " + testcaseclass - threadListGlobal = wait_testcaseclass_generic_threads(threadListGlobal, Timeout_execution) - #cleanOldProgramsAllMachines(oai_list, CleanUpOldProgs, CleanUpAluLteBox, ExmimoRfStop) - handle_testcaseclass_softmodem (testcase, CleanUpOldProgs, logdirOAI5GRepo, logdirOpenaircnRepo, MachineList, user, pw, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, Timeout_cmd ) - - #The lines below are copied from below to trace the failure of some of the machines in test setup. These lines below need to be removed in long term - print "Creating xml file for overall results..." - cmd = "cat $OPENAIR_DIR/cmake_targets/autotests/log/*/*.xml > $OPENAIR_DIR/cmake_targets/autotests/log/results_autotests.xml " - res=os.system(cmd) - os.system('sync') - print "Now copying files to NFS Share" - oai_localhost = openair('localdomain','localhost') - oai_localhost.connect(user,pw) - cmd = ' mkdir -p ' + NFSTestsResultsDir - res = oai_localhost.send_recv(cmd) - - print "Copying files from GilabCI Runner Machine : " + host + " .locallogdir = " + locallogdir + ", NFSTestsResultsDir = " + NFSTestsResultsDir - SSHSessionWrapper('localhost', user, None, pw , NFSTestsResultsDir , locallogdir, "put_all") - oai_localhost.disconnect() - - elif testcaseclass == 'lte-softmodem-noS1' : - eNBMachine = testcase.findtext('eNB',default='') - UEMachine = testcase.findtext('UE',default='') - if (eNBMachine not in MachineList)|(UEMachine not in MachineList): - print "One of the machines is not in the machine list" - print "eNBMachine : " + eNBMachine + "UEMachine : " + UEMachine + "MachineList : " + ','.join(MachineList) - print "testcasename = " + testcasename + " class = " + testcaseclass - threadListGlobal = wait_testcaseclass_generic_threads(threadListGlobal, Timeout_execution) - - handle_testcaseclass_softmodem_noS1 (testcase, CleanUpOldProgs, logdirOAI5GRepo, logdirOpenaircnRepo, MachineList, user, pw, CleanUpAluLteBox, ExmimoRfStop, nruns_lte_softmodem, Timeout_cmd ) - - #The lines below are copied from below to trace the failure of some of the machines in test setup. These lines below need to be removed in long term - print "Creating xml file for overall results..." - cmd = "cat $OPENAIR_DIR/cmake_targets/autotests/log/*/*.xml > $OPENAIR_DIR/cmake_targets/autotests/log/results_autotests.xml " - res=os.system(cmd) - os.system('sync') - - elif (testcaseclass == 'compilation'): - threadListGlobal = handle_testcaseclass_generic (testcasename, threadListGlobal, CleanUpOldProgs, logdirOAI5GRepo, MachineListGeneric, user, pw, CleanUpAluLteBox,Timeout_execution, ExmimoRfStop) - elif (testcaseclass == 'execution'): - threadListGlobal = handle_testcaseclass_generic (testcasename, threadListGlobal, CleanUpOldProgs, logdirOAI5GRepo, MachineListGeneric, user, pw, CleanUpAluLteBox, Timeout_execution, ExmimoRfStop) - else : - print "Unknown test case class: " + testcaseclass - sys.exit() - - except Exception, e: - error='' - error = error + ' In function: ' + sys._getframe().f_code.co_name + ': *** Caught exception: ' + str(e.__class__) + " : " + str( e) - error = error + '\n testcasename = ' + testcasename + '\n testcaseclass = ' + testcaseclass + '\n desc = ' + 'desc' + '\n' - error = error + traceback.format_exc() - print error - print "Continuing to next test case..." - #sys.exit(1) - - -print "Exiting the test cases execution now. Waiting for existing threads to complete..." - -for param in threadListGlobal: - thread_id = param["thread_id"] - thread_id.join() - - -# ************************************************************************** -# ************************************************************************** -# STEP 4 - TEST REPORT PRODUCTION -# ************************************************************************** -# ************************************************************************** - - - -test_session_stop_time = datetime.datetime.now() - -print (Fore.YELLOW + '\nStep 4 - TEST REPORT PRODUCTION') -print (Fore.YELLOW + '-------------------------------------------------') - -report_dir = reportdir + '/'+ test_session_start_time.strftime("%Y-%m-%d_%H-%M")+"_"+host - -cmd = 'mkdir -p ' + report_dir -result = os.system(cmd) - -cmd = 'cp -r '+locallogdir+' '+report_dir -result = os.system(cmd) - -context = { - 'report_path' : report_dir, - 'test_session_start_time' : test_session_start_time, - 'test_session_stop_time' : test_session_stop_time, - 'test_session_duration' : test_session_stop_time-test_session_start_time, - 'mtc_host' : host, - 'user' : user, - 'password' : pw, - 'test_results' : test_results, -} - -for test_result in test_results: - cmd = 'mkdir -p ' + report_dir + '/'+ test_result['testcase_name'] - result = os.system(cmd) - - report_file = report_dir + '/'+ test_result['testcase_name'] + '/'+ test_result['testcase_name']+ '_report.html' - - analyser.create_test_report_detailed_html(test_result, report_file ) - - print test_result - - -analyser.create_report_html(context) - -exit_prog(0) - diff --git a/cmake_targets/autotests/testsuite_ue_noS1_eurecom.xml b/cmake_targets/autotests/testsuite_ue_noS1_eurecom.xml deleted file mode 100644 index 25a4a652e5..0000000000 --- a/cmake_targets/autotests/testsuite_ue_noS1_eurecom.xml +++ /dev/null @@ -1,3214 +0,0 @@ - - -imb182-desktop yanbo-M4HM87P-00 - /mnt/sradio/TEST_RESULTS/ - https://gitlab.eurecom.fr/oai/openairinterface5g.git - https://gitlab.eurecom.fr/oai/openair-cn.git --> - develop - - - - - - - - - develop - oaisim oaisim_nos1 lte-softmodem lte-softmodem-nos1 mme_gw run_epc auth_request run_hss oai_hss mme spgw hss hss_sim configure_cots* wvdial iperf iperf_script iperf_script_phone ping tshark rrh_gw iperf3 iperf3_script iperf3_script_phone pppd - sudo -S -E /opt/ltebox/tools/stop_ltebox -$OPENAIR_DIR/cmake_targets/build_oai -w EXMIMO -c; sudo -S -E $OPENAIR_DIR/cmake_targets/tools/stop_exmimo2; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_bandrich_ue.py --reset-ue; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_huaweiE398_ue.py --reset-ue; sudo -E $OPENAIR_DIR/cmake_targets/autotests/tools/configure_cots_sony_experia_m4_ue.py --stop-ue; uname -a; sudo -E dmesg - 36000 - - - yanbo-M4HM87P-00 - - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS00 - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS00 - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 1 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS01 - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 1 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS01 - 36 - - - - - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS09 - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS09 - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS16 - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS16 - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS10 - - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS10 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS17 - - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS17 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 18 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS18 - - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 18 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS18 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS19 - - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS19 - 36 - - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 20 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS20 - - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 20 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS20 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 21 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS21 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 21 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS21 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 22 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS22 - - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 22 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS22 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 23 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS23 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 23 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS23 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 24 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS24 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 24 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS24 - 36 - - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 25 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS25 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 25 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS25 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 26 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS26 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 26 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS26 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS27 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS27 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS28 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.5MHZ.MCS28 - 36 - - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 18000 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_STAB.BAND7.5MHZ.MCS27 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_STAB.BAND7.5MHZ.MCS27 - 36 - - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 50 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r50 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.10MHZ.MCS27 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 50 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r50 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.10MHZ.MCS27 - 36 - - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 50 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 28 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636. -r50 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S --phy-test -g 4 - - - - - - False - UE_USRP.NOS1.PHYTEST_PERF.BAND7.10MHZ.MCS28 - 36 - - - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 50 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 --phy-test - - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r50 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 --phy-test -g 4 - - - - - - False - UE_UEDV1.NOS1.PHYTEST_PERF.BAND7.10MHZ.MCS19 - 36 - - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 512K - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS00 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 0 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 512K - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS00 - 36 - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS09 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 9 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS09 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS10 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 10 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS10 - 36 - - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS16 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 16 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS16 - 36 - - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS17 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 17 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS17 - 36 - - - - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS19 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 19 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS19 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_USRP.NOS1.DATA_IPERF.BAND7.5MHZ.MCS27 - 36 - - - - - lte-softmodem-noS1 - - imb182-desktop - yanbo-M4HM87P-00 - 3600 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w USRP --noS1 --eNB - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C2685004636 -r25 --ue-scan-carrier --ue-txgain 90 -A 20 --ue-rxgain 125 -S -g 4 - - iperf -s -i 1 -u - - 2800 - - False - UE_USRP.NOS1.DATA_IPERF_STAB.BAND7.5MHZ.MCS27 - 16 - - - - - lte-softmodem-noS1 - - imb182-desktop - ued-PRM-130 - 300 - /tmp - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tracking_area_code \"1\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_country_code \"208\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mobile_network_code \"95\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf N_RB_DL 25 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf mme_ip_address "ipv4=\"192.168.12.26\";ipv6=\"192:168:30::17\";active=\"yes\";preference=\"ipv4\";" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf downlink_frequency 2685000000L - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf uplink_frequency_offset -120000000 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf tx_gain 90 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf rx_gain 125 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf frame_type \"FDD\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_rx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf nb_antennas_tx 1 - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_INTERFACE_NAME_FOR_S1U \"eth5\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\" - targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf ENB_PORT_FOR_S1U 2152 - $OPENAIR_DIR/cmake_targets/build_oai - -c -w USRP --eNB --noS1 - source $OPENAIR_DIR/cmake_targets/tools/init_nas_nos1 eNB - - $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 - -O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf -W -m 27 - sleep 80;iperf -c 10.0.1.9 -i 1 -u -b 2M - - - - False - - /tmp - - $OPENAIR_DIR/cmake_targets/build_oai - -c --UE -w EXMIMO --noS1 - source ./targets/bin/init_nas_nos1 UE - - sleep 50; ./cmake_targets/autotests/tools/run_gdb ./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2685000000 -r25 --ue-scan-carrier --ue-txgain 15 --ue-rxgain 5 -S -A 6 -F myriadRF_FMX --ue-max-power -25 -g 4 - - iperf -s -i 1 -u - - 200 - - False - UE_UEDV1.NOS1.DATA_IPERF.BAND7.5MHZ.MCS27 - 36 - - - diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c index 5ae2ec2ecd..ff7e02a239 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c @@ -972,11 +972,6 @@ unsigned char phy_threegpplte_turbo_decoder8(short *y, } else n2 = n; - if(n2<256) - { - printf("phy_threegpplte_turbo_decoder8 : frame length < 256\n"); - return 255; - } for (iind=0; iind < 188 && f1f2mat[iind].nb_bits != n; iind++); From 2f3483d1d30457961e9cfa5bd80d471417728967 Mon Sep 17 00:00:00 2001 From: Benoit ROBERT Date: Wed, 14 Dec 2016 12:26:01 +0100 Subject: [PATCH 408/413] correct issue 154 on PDCP fifo for noS1 mode --- openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c index fedef42b60..eb78a4ca7c 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c @@ -424,18 +424,22 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const ctxt_pP) return 0; # else /* PDCP_USE_NETLINK_QUEUES*/ int len = 1; + int msg_len; rb_id_t rab_id = 0; - - while (len > 0) { + int rlc_data_req_flag = 3; + + while ((len > 0) && (rlc_data_req_flag !=0)) { len = recvmsg(nas_sock_fd, &nas_msg_rx, 0); if (len<=0) { // nothing in pdcp NAS socket //LOG_D(PDCP, "[PDCP][NETLINK] Nothing in socket, length %d \n", len); } else { + + msg_len = len; for (nas_nlh_rx = (struct nlmsghdr *) nl_rx_buf; - NLMSG_OK (nas_nlh_rx, len); - nas_nlh_rx = NLMSG_NEXT (nas_nlh_rx, len)) { + NLMSG_OK (nas_nlh_rx, msg_len); + nas_nlh_rx = NLMSG_NEXT (nas_nlh_rx, msg_len)) { if (nas_nlh_rx->nlmsg_type == NLMSG_DONE) { LOG_D(PDCP, "[PDCP][NETLINK] RX NLMSG_DONE\n"); @@ -493,7 +497,7 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const ctxt_pP) ctxt.enb_flag = ctxt_cpy.enb_flag; #ifdef PDCP_DEBUG - LOG_D(PDCP, "[PDCP][NETLINK] pdcp_read_header_g.rb_id = %d\n", pdcp_read_header_g.rb_id); + LOG_I(PDCP, "[PDCP][NETLINK] pdcp_read_header_g.rb_id = %d\n", pdcp_read_header_g.rb_id); #endif if (ctxt_cpy.enb_flag) { From 82437cccb756d05e0546aceefaf346e938793f67 Mon Sep 17 00:00:00 2001 From: ROBERT Benoit Date: Thu, 1 Dec 2016 16:31:05 +0100 Subject: [PATCH 409/413] - Problem in DCI NDI : the implementation use 5 HARQ processes, but process 0 NDI never toggled because it was reused on subframe 5 that is not carrying format 1 DCI. Fix -> use 8 harq processes instead of 5. - SI scheduled on every subframe 5 (even and odd frames) instead of only on even frames - Add DLSCH scheduling on subframe 5 for odd frames - change default rballoc from 0x7FFF to 0x1FFFF to support maximum 10MHz throughput --- openair1/SCHED/phy_mac_stub.c | 79 ++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/openair1/SCHED/phy_mac_stub.c b/openair1/SCHED/phy_mac_stub.c index 0ac194d051..7753e9c2e3 100644 --- a/openair1/SCHED/phy_mac_stub.c +++ b/openair1/SCHED/phy_mac_stub.c @@ -40,14 +40,21 @@ #include "SCHED/phy_procedures_emos.h" #endif +/* SYRTEM */ +uint8_t dci_ndi_toggle_even[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint8_t dci_ndi_toggle_odd[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { - +/* SYRTEM */ + uint8_t *dci_ndi_toggle_tmp = NULL; + uint8_t harq_pid_value = 0; +/* End of SYRTEM */ //uint8_t cooperation_flag = eNB->cooperation_flag; uint8_t transmission_mode = eNB->transmission_mode[0]; - uint32_t rballoc = 0x7FFF; + uint32_t rballoc = 0x1FFFF; //uint32_t rballoc2 = 0x000F; int subframe = proc->subframe_tx; @@ -68,12 +75,14 @@ void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) switch (subframe) { case 5: - DCI_pdu->Num_common_dci = 1; - DCI_pdu->dci_alloc[0].L = 2; - DCI_pdu->dci_alloc[0].firstCCE = 0; - DCI_pdu->dci_alloc[0].rnti = SI_RNTI; - DCI_pdu->dci_alloc[0].format = format1A; - DCI_pdu->dci_alloc[0].ra_flag = 0; + if ( !(proc->frame_tx&1) ) // SI message on even frame only (SFN mod 2 == 0) + { + DCI_pdu->Num_common_dci = 1; + DCI_pdu->dci_alloc[0].L = 2; + DCI_pdu->dci_alloc[0].firstCCE = 0; + DCI_pdu->dci_alloc[0].rnti = SI_RNTI; + DCI_pdu->dci_alloc[0].format = format1A; + DCI_pdu->dci_alloc[0].ra_flag = 0; switch (eNB->frame_parms.N_RB_DL) { case 6: @@ -187,6 +196,12 @@ void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) } break; //subframe switch + } // if ( !(proc->frame_tx&1) ) + else // No SI message on odd frame (SFN mod 2 == 1) + { + /* warning: work around to send dlsch on subframe 5 odd frame !!! */ + /* todo: clean up, espacially if subframe cases are added next !!! */ + } /* case 6: DCI_pdu->Num_ue_spec_dci = 1; @@ -225,15 +240,23 @@ void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) if (eNB->frame_parms.frame_type == FDD) { DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_5MHz_FDD_t; + harq_pid_value = ( ((proc->frame_tx * 10) + subframe) % 8 ); + + if (!(subframe&1)) // even subframe + dci_ndi_toggle_tmp = &(dci_ndi_toggle_even[harq_pid_value]); + else // odd subframe + dci_ndi_toggle_tmp = &(dci_ndi_toggle_odd[harq_pid_value]); + ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(25,10,3); ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->TPC = 0; - ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->harq_pid = subframe % 5; + ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->harq_pid = harq_pid_value; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = eNB->target_ue_dl_mcs; - //((DCI1_5MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((eNB->frame%1024)%28); - ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = subframe / 5; + ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->ndi = (*dci_ndi_toggle_tmp); ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rv = 0; ((DCI1_5MHz_FDD_t *)&dlsch_pdu)->rah = 0; + (*dci_ndi_toggle_tmp) = ((*dci_ndi_toggle_tmp) + 1) & 1; + memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_5MHz_FDD_t)); /* @@ -296,36 +319,24 @@ void fill_dci(DCI_PDU *DCI_pdu,PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) if (eNB->frame_parms.frame_type == FDD) { DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_10MHz_FDD_t; + harq_pid_value = ( ((proc->frame_tx * 10) + subframe) % 8 ); + + if (!(subframe&1)) // even subframe + dci_ndi_toggle_tmp = &(dci_ndi_toggle_even[harq_pid_value]); + else // odd subframe + dci_ndi_toggle_tmp = &(dci_ndi_toggle_odd[harq_pid_value]); + ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc; //computeRIV(50,10,3); ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->TPC = 0; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->harq_pid = subframe % 5; + ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->harq_pid = harq_pid_value; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = eNB->target_ue_dl_mcs; - //((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((eNB->frame%1024)%28); - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = subframe / 5; + ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = (*dci_ndi_toggle_tmp); ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rv = 0; ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rah = 0; + (*dci_ndi_toggle_tmp) = ((*dci_ndi_toggle_tmp) + 1) & 1; + memcpy((void*)&DCI_pdu->dci_alloc[0].dci_pdu[0],(void *)&dlsch_pdu,sizeof(DCI1_10MHz_FDD_t)); - - /* - //user2 - DCI_pdu->dci_alloc[1].dci_length = sizeof_DCI1_10MHz_TDD_t; - DCI_pdu->dci_alloc[1].L = 2; - DCI_pdu->dci_alloc[1].rnti = 0x1236; - DCI_pdu->dci_alloc[1].format = format1; - DCI_pdu->dci_alloc[1].ra_flag = 0; - - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rballoc = rballoc2; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->TPC = 0; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->dai = 0; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->harq_pid = 1; - //((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = (unsigned char) ((eNB->proc[subframe].frame%1024)%28); - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->mcs = eNB->target_ue_dl_mcs; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->ndi = 1; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rv = 0; - ((DCI1_10MHz_FDD_t *)&dlsch_pdu)->rah = 0; - memcpy((void*)&DCI_pdu->dci_alloc[1].dci_pdu[0],(void *)&((DCI1_10MHz_FDD_t *)&dlsch_pdu)->,sizeof(DCI1_10MHz_TDD_t)); - */ } else { DCI_pdu->dci_alloc[0].dci_length = sizeof_DCI1_10MHz_TDD_t; From 17d62a67776b13e2af75b464ee85c9c1fd6bb735 Mon Sep 17 00:00:00 2001 From: ROBERT Benoit Date: Mon, 5 Dec 2016 15:41:47 +0100 Subject: [PATCH 410/413] correct issue 147 : --phy-test mode : error msg " DL Received HarqReTx round=1 mcs=28 rballoc=8191 rv=0 " --- openair1/SCHED/phy_procedures_lte_eNb.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index a7d9e73e2f..ff12ac7fef 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -1124,7 +1124,7 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, int frame=proc->frame_tx; int subframe=proc->subframe_tx; // uint16_t input_buffer_length; - uint32_t i,aa; + uint32_t i,j,aa; uint8_t harq_pid; DCI_PDU *DCI_pdu; DCI_PDU DCI_pdu_tmp; @@ -1222,6 +1222,14 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, fill_dci_emos(DCI_pdu,eNB); #else fill_dci(DCI_pdu,eNB,proc); + // clear previous allocation information for all UEs + for (i=0; idlsch[i][0]){ + for (j=0; j<8; j++) + eNB->dlsch[i][0]->harq_processes[j]->round = 0; + } + } + #endif } From a525be94c3640eeea5c6ebc70a92f7a26018684c Mon Sep 17 00:00:00 2001 From: Florian Kaltenberger Date: Thu, 15 Dec 2016 17:00:53 +0100 Subject: [PATCH 411/413] changing antenna number back to 1 --- .../PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf index 2942832d94..5ef5a4f50b 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.usrpb210.conf @@ -37,8 +37,8 @@ eNBs = N_RB_DL = 25; Nid_cell_mbsfn = 0; nb_antenna_ports = 1; - nb_antennas_tx = 2; - nb_antennas_rx = 2; + nb_antennas_tx = 1; + nb_antennas_rx = 1; tx_gain = 90; rx_gain = 125; prach_root = 0; From 66c292b95b35203e3fb714777f8b431dbd5b7dbe Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 19 Dec 2016 11:19:05 +0100 Subject: [PATCH 412/413] integration fix: update T messages --- common/utils/T/T_messages.txt | 104 +++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index af2579cb1b..d1807080bc 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -1267,6 +1267,14 @@ ID = VCD_VARIABLE_UE0_SFN7 DESC = VCD variable UE0_SFN7 GROUP = ALL:VCD:ENB:VCD_VARIABLE FORMAT = ulong,value +ID = VCD_VARIABLE_UE0_TRX_READ_NS + DESC = VCD variable UE0_TRX_READ_NS + GROUP = ALL:VCD:ENB:VCD_VARIABLE + FORMAT = ulong,value +ID = VCD_VARIABLE_UE0_TRX_WRITE_NS + DESC = VCD variable UE0_TRX_WRITE_NS + GROUP = ALL:VCD:ENB:VCD_VARIABLE + FORMAT = ulong,value #functions @@ -1310,6 +1318,50 @@ ID = VCD_FUNCTION_UE_THREAD_RXTX1 DESC = VCD function UE_THREAD_RXTX1 GROUP = ALL:VCD:UE:VCD_FUNCTION FORMAT = int,value +ID = VCD_FUNCTION_TRX_READ_SF9 + DESC = VCD function TRX_READ_SF9 + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_TRX_WRITE_SF9 + DESC = VCD function TRX_WRITE_SF9 + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_UE_SIGNAL_COND_RXTX + DESC = VCD function UE_SIGNAL_COND_RXTX + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_UE_WAIT_COND_RXTX0 + DESC = VCD function UE_WAIT_COND_RXTX0 + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_UE_WAIT_COND_RXTX1 + DESC = VCD function UE_WAIT_COND_RXTX1 + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_UE_LOCK_MUTEX_RXTX_FOR_COND_WAIT0 + DESC = VCD function UE_LOCK_MUTEX_RXTX_FOR_COND_WAIT0 + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_UE_LOCK_MUTEX_RXTX_FOR_COND_WAIT1 + DESC = VCD function UE_LOCK_MUTEX_RXTX_FOR_COND_WAIT1 + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_UE_LOCK_MUTEX_RXTX_FOR_CNT_DECREMENT0 + DESC = VCD function UE_LOCK_MUTEX_RXTX_FOR_CNT_DECREMENT0 + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_UE_LOCK_MUTEX_RXTX_FOR_CNT_DECREMENT1 + DESC = VCD function UE_LOCK_MUTEX_RXTX_FOR_CNT_DECREMENT1 + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT0 + DESC = VCD function UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT0 + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT1 + DESC = VCD function UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT1 + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value ID = VCD_FUNCTION_eNB_TX DESC = VCD function eNB_TX GROUP = ALL:VCD:ENB:VCD_FUNCTION @@ -1402,8 +1454,8 @@ ID = VCD_FUNCTION_PHY_PROCEDURES_ENB_RX_UESPEC1 DESC = VCD function PHY_PROCEDURES_ENB_RX_UESPEC1 GROUP = ALL:VCD:ENB:VCD_FUNCTION FORMAT = int,value -ID = VCD_FUNCTION_PHY_PROCEDURES_ENB_SLOT_FEP - DESC = VCD function PHY_PROCEDURES_ENB_SLOT_FEP +ID = VCD_FUNCTION_ENB_SLOT_FEP + DESC = VCD function ENB_SLOT_FEP GROUP = ALL:VCD:ENB:VCD_FUNCTION FORMAT = int,value ID = VCD_FUNCTION_PHY_PROCEDURES_UE_TX @@ -1414,6 +1466,26 @@ ID = VCD_FUNCTION_PHY_PROCEDURES_UE_RX DESC = VCD function PHY_PROCEDURES_UE_RX GROUP = ALL:VCD:UE:VCD_FUNCTION FORMAT = int,value +ID = VCD_FUNCTION_PHY_PROCEDURES_UE_TX_ULSCH_UESPEC + DESC = VCD function PHY_PROCEDURES_UE_TX_ULSCH_UESPEC + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PHY_PROCEDURES_UE_TX_PUCCH + DESC = VCD function PHY_PROCEDURES_UE_TX_PUCCH + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PHY_PROCEDURES_UE_TX_ULSCH_COMMON + DESC = VCD function PHY_PROCEDURES_UE_TX_ULSCH_COMMON + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PHY_PROCEDURES_UE_TX_PRACH + DESC = VCD function PHY_PROCEDURES_UE_TX_PRACH + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PHY_PROCEDURES_UE_TX_ULSCH_RAR + DESC = VCD function PHY_PROCEDURES_UE_TX_ULSCH_RAR + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value ID = VCD_FUNCTION_PHY_PROCEDURES_ENB_LTE DESC = VCD function PHY_PROCEDURES_ENB_LTE GROUP = ALL:VCD:ENB:VCD_FUNCTION @@ -1502,6 +1574,22 @@ ID = VCD_FUNCTION_RX_PHICH DESC = VCD function RX_PHICH GROUP = ALL:VCD:ENB:VCD_FUNCTION FORMAT = int,value +ID = VCD_FUNCTION_PDSCH_PROC + DESC = VCD function PDSCH_PROC + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PDSCH_PROC_SI + DESC = VCD function PDSCH_PROC_SI + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PDSCH_PROC_P + DESC = VCD function PDSCH_PROC_P + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_PDSCH_PROC_RA + DESC = VCD function PDSCH_PROC_RA + GROUP = ALL:VCD:UE:VCD_FUNCTION + FORMAT = int,value ID = VCD_FUNCTION_PHY_UE_CONFIG_SIB2 DESC = VCD function PHY_UE_CONFIG_SIB2 GROUP = ALL:VCD:UE:VCD_FUNCTION @@ -1606,6 +1694,14 @@ ID = VCD_FUNCTION_ENB_DLSCH_SCRAMBLING DESC = VCD function ENB_DLSCH_SCRAMBLING GROUP = ALL:VCD:ENB:VCD_FUNCTION FORMAT = int,value +ID = VCD_FUNCTION_ENB_BEAM_PRECODING + DESC = VCD function ENB_BEAM_PRECODING + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value +ID = VCD_FUNCTION_ENB_OFDM_MODULATION + DESC = VCD function ENB_OFDM_MODULATION + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value ID = VCD_FUNCTION_MACPHY_INIT DESC = VCD function MACPHY_INIT GROUP = ALL:VCD:ENB:VCD_FUNCTION @@ -1718,6 +1814,10 @@ ID = VCD_FUNCTION_RLC_DATA_REQ DESC = VCD function RLC_DATA_REQ GROUP = ALL:VCD:ENB:VCD_FUNCTION FORMAT = int,value +ID = VCD_FUNCTION_RLC_DATA_IND + DESC = VCD function RLC_DATA_IND + GROUP = ALL:VCD:ENB:VCD_FUNCTION + FORMAT = int,value ID = VCD_FUNCTION_MAC_RLC_STATUS_IND DESC = VCD function MAC_RLC_STATUS_IND GROUP = ALL:VCD:ENB:VCD_FUNCTION From 5ebdbf9f2d99a675844d5a63f02876a807d94859 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 19 Dec 2016 12:25:35 +0100 Subject: [PATCH 413/413] integration fix: align32 missing (NOT DEFINITIVE!) We have a crash: Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0x7fff7387d700 (LWP 1944)] ulsch_decoding (eNB=eNB@entry=0x7fffaf73b010, proc=proc@entry=0x7fffaf73b480, UE_id=UE_id@entry=0 '\000', control_only_flag=control_only_flag@entry=0 '\000', Nbundled=, llr8_flag=) at /roux/merge/openairinterface5g/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c:1450 1450 *((__m256i *)&ulsch_harq->e[iprime]) = *((__m256i *)&y[j2]); This commit reduces the apparition of the crash, but does not eliminate it completely. To be fixed after integration. --- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 7f4f4cf5f6..68f3abc094 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -872,7 +872,7 @@ unsigned int ulsch_decoding(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, int16_t ys,c; uint32_t wACK_idx; uint8_t dummy_w_cc[3*(MAX_CQI_BITS+8+32)]; - int16_t y[6*14*1200]; + int16_t y[6*14*1200] __attribute__((aligned(32))); uint8_t ytag[14*1200]; // uint8_t ytag2[6*14*1200],*ytag2_ptr; int16_t cseq[6*14*1200];

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

$nnc~6QuIY)ANfVZ9a1pe;4 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