diff --git a/CMakeLists.txt b/CMakeLists.txt index 232445013..ad478f047 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,14 +55,20 @@ if(NOT CMAKE_BUILD_TYPE) endif(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") +# Generate CMake to include build information +configure_file( + ${CMAKE_SOURCE_DIR}/cmake/modules/SRSLTEbuildinfo.cmake.in + ${CMAKE_BINARY_DIR}/SRSLTEbuildinfo.cmake +) + ######################################################################## # Options ######################################################################## option(ENABLE_SRSUE "Build srsUE application" ON) option(ENABLE_SRSENB "Build srsENB application" ON) option(ENABLE_SRSEPC "Build srsEPC application" ON) +option(DISABLE_SIMD "disable simd instructions" OFF) -option(ENABLE_VOLK "Enable use of VOLK SIMD library" ON) option(ENABLE_GUI "Enable GUI (using srsGUI)" ON) option(ENABLE_BLADERF "Enable BladeRF" ON) @@ -190,21 +196,6 @@ if(ENABLE_GUI) endif(SRSGUI_FOUND) endif(ENABLE_GUI) -# VOLK -include(CheckFunctionExistsMath) -if(ENABLE_VOLK) - find_package(Volk) - if(VOLK_FOUND) - include_directories(${VOLK_INCLUDE_DIRS}) - link_directories(${VOLK_LIBRARY_DIRS}) - message(STATUS "Compiling with VOLK SIMD library.") - else(VOLK_FOUND) - message(STATUS "VOLK SIMD library NOT found. Using generic implementation.") - endif(VOLK_FOUND) -else(ENABLE_VOLK) - message(STATUS "VOLK library disabled") -endif(ENABLE_VOLK) - ######################################################################## # Install Dirs ######################################################################## @@ -283,6 +274,11 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") endif(HAVE_AVX) endif (HAVE_AVX2) + if (HAVE_AVX512) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx512f -mavx512cd -DLV_HAVE_AVX512") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx512f -mavx512cd -DLV_HAVE_AVX512") + endif(HAVE_AVX512) + if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") if(HAVE_SSE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Ofast -funroll-loops") @@ -293,9 +289,16 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon -march=native -DIS_ARM -DHAVE_NEON") message(STATUS "have ARM") + set(HAVE_NEON "True") + else(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") + set(HAVE_NEON "False") endif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") set(CMAKE_REQUIRED_FLAGS ${CMAKE_C_FLAGS}) + if(NOT HAVE_SSE AND NOT HAVE_NEON AND NOT DISABLE_SIMD) + message(FATAL_ERROR "no SIMD instructions found") + endif(NOT HAVE_SSE AND NOT HAVE_NEON AND NOT DISABLE_SIMD) + if(NOT WIN32) ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) endif(NOT WIN32) diff --git a/cmake/modules/FindSSE.cmake b/cmake/modules/FindSSE.cmake index 3440f01c1..4c9673a9d 100644 --- a/cmake/modules/FindSSE.cmake +++ b/cmake/modules/FindSSE.cmake @@ -4,10 +4,11 @@ include(CheckCSourceRuns) -option(ENABLE_SSE "Enable compile-time SSE4.1 support." ON) -option(ENABLE_AVX "Enable compile-time AVX support." ON) -option(ENABLE_AVX2 "Enable compile-time AVX2 support." ON) -option(ENABLE_FMA "Enable compile-time FMA support." ON) +option(ENABLE_SSE "Enable compile-time SSE4.1 support." ON) +option(ENABLE_AVX "Enable compile-time AVX support." ON) +option(ENABLE_AVX2 "Enable compile-time AVX2 support." ON) +option(ENABLE_FMA "Enable compile-time FMA support." ON) +option(ENABLE_AVX512 "Enable compile-time AVX512 support." ON) if (ENABLE_SSE) # @@ -135,6 +136,41 @@ if (ENABLE_SSE) endif() endif() + if (ENABLE_AVX512) + + # + # Check compiler for AVX intrinsics + # + if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG ) + set(CMAKE_REQUIRED_FLAGS "-mavx512f") + check_c_source_runs(" + #include + int main() + { + __m512i a, b, c; + const int src[16] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 , 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}; + int dst[16]; + a = _mm512_loadu_si512( (__m512i*)src ); + b = _mm512_loadu_si512( (__m512i*)src ); + c = _mm512_add_epi32( a, b ); + _mm512_storeu_si512( (__m512i*)dst, c ); + int i = 0; + for( i = 0; i < 16; i++ ){ + if( ( src[i] + src[i] ) != dst[i] ){ + return -1; + } + } + return 0; + }" + HAVE_AVX512) + endif() + + if (HAVE_AVX512) + message(STATUS "AVX512 is enabled - target CPU must support it") + endif() + endif() + + endif() -mark_as_advanced(HAVE_SSE, HAVE_AVX, HAVE_AVX2, HAVE_FMA) +mark_as_advanced(HAVE_SSE, HAVE_AVX, HAVE_AVX2, HAVE_FMA, HAVE_AVX512) diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake deleted file mode 100644 index 96262a3b8..000000000 --- a/cmake/modules/FindVolk.cmake +++ /dev/null @@ -1,161 +0,0 @@ -INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(PC_VOLK volk QUIET) - -FIND_PATH( - VOLK_INCLUDE_DIRS - NAMES volk/volk.h - HINTS $ENV{VOLK_DIR}/include - ${CMAKE_INSTALL_PREFIX}/include - ${PC_VOLK_INCLUDE_DIR} - PATHS /usr/local/include - /usr/include -) - -FIND_LIBRARY( - VOLK_LIBRARIES - NAMES volk - HINTS $ENV{VOLK_DIR}/lib - ${CMAKE_INSTALL_PREFIX}/lib - ${CMAKE_INSTALL_PREFIX}/lib64 - ${PC_VOLK_LIBDIR} - PATHS /usr/local/lib - /usr/local/lib64 - /usr/lib - /usr/lib64 -) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS) -MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_DEFINITIONS) - -IF(VOLK_FOUND) - SET(CMAKE_REQUIRED_LIBRARIES ${VOLK_LIBRARIES} m) - CHECK_FUNCTION_EXISTS_MATH(volk_16i_s32f_convert_32f HAVE_VOLK_CONVERT_IF_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32f_index_max_16u HAVE_VOLK_MAX_FUNCTION_16) - CHECK_FUNCTION_EXISTS_MATH(volk_32f_index_max_32u HAVE_VOLK_MAX_FUNCTION_32) - CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_max_32f HAVE_VOLK_MAX_VEC_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32f_accumulator_s32f HAVE_VOLK_ACC_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32fc_multiply_32fc HAVE_VOLK_MULT_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_conjugate_32fc HAVE_VOLK_CONJ_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_32fc HAVE_VOLK_MULT2_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_conjugate_32fc HAVE_VOLK_MULT2_CONJ_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_multiply_32fc HAVE_VOLK_MULT_REAL_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_multiply_32f HAVE_VOLK_MULT_FLOAT_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_32f HAVE_VOLK_MAG_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_squared_32f HAVE_VOLK_MAG_SQUARE_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_divide_32f HAVE_VOLK_DIVIDE_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_dot_prod_32fc HAVE_VOLK_DOTPROD_FC_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_dot_prod_32fc HAVE_VOLK_DOTPROD_CFC_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_conjugate_dot_prod_32fc HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_dot_prod_32f HAVE_VOLK_DOTPROD_F_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32f_atan2_32f HAVE_VOLK_ATAN_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_convert_16i HAVE_VOLK_CONVERT_FI_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_32f_x2 HAVE_VOLK_DEINTERLEAVE_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_interleave_32fc HAVE_VOLK_INTERLEAVE_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_add_32f HAVE_VOLK_ADD_FLOAT_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_square_dist_32f HAVE_VOLK_SQUARE_DIST_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_real_32f HAVE_VOLK_DEINTERLEAVE_REAL_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_index_max_16u HAVE_VOLK_MAX_ABS_FUNCTION_16) - CHECK_FUNCTION_EXISTS_MATH(volk_32fc_index_max_32u HAVE_VOLK_MAX_ABS_FUNCTION_32) - CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_multiply_32f HAVE_VOLK_MULT_REAL2_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_16i_max_star_16i HAVE_VOLK_MAX_STAR_S_FUNCTION) - CHECK_FUNCTION_EXISTS_MATH(volk_8i_convert_16i HAVE_VOLK_CONVERT_CI_FUNCTION) - - - - SET(VOLK_DEFINITIONS "HAVE_VOLK") - IF(${HAVE_VOLK_CONVERT_IF_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_IF_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_MULT_REAL2_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_REAL2_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_CONVERT_CI_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_CI_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_MAX_STAR_S_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_STAR_S_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_MAX_ABS_FUNCTION_16}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_ABS_FUNCTION_16") - ENDIF() - IF(${HAVE_VOLK_MAX_ABS_FUNCTION_32}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_ABS_FUNCTION_32") - ENDIF() - IF(${HAVE_VOLK_MAX_VEC_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_VEC_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_MAG_SQUARE_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_SQUARE_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_SQUARE_DIST_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SQUARE_DIST_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_INTERLEAVE_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_INTERLEAVE_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_SUB_FLOAT_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SUB_FLOAT_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_ADD_FLOAT_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ADD_FLOAT_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_MULT2_CONJ_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_CONJ_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_DEINTERLEAVE_REAL_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_REAL_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_CONVERT_FI_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_FI_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_MAX_FUNCTION_16}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION_16") - ENDIF() - IF(${HAVE_VOLK_MAX_FUNCTION_32}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION_32") - ENDIF() - IF(${HAVE_VOLK_ACC_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ACC_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_MULT_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_CONJ_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONJ_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_MULT2_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_MULT_FLOAT_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FLOAT_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_MULT_REAL_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_REAL_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_MAG_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_DIVIDE_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DIVIDE_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_DOTPROD_FC_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_FC_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_DOTPROD_CFC_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CFC_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_DOTPROD_F_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_F_FUNCTION") - ENDIF() - IF(${HAVE_VOLK_ATAN_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ATAN_FUNCTION") - ENDIF() -ENDIF(VOLK_FOUND) diff --git a/cmake/modules/SRSLTEbuildinfo.cmake.in b/cmake/modules/SRSLTEbuildinfo.cmake.in new file mode 100644 index 000000000..d8715afbc --- /dev/null +++ b/cmake/modules/SRSLTEbuildinfo.cmake.in @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.6) + +execute_process( +COMMAND git rev-parse --abbrev-ref HEAD +WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@" +OUTPUT_VARIABLE GIT_BRANCH +OUTPUT_STRIP_TRAILING_WHITESPACE +) + +execute_process( +COMMAND git log -1 --format=%h +WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@" +OUTPUT_VARIABLE GIT_COMMIT_HASH +OUTPUT_STRIP_TRAILING_WHITESPACE +) + +message(STATUS "Generating build_info.h") +configure_file( + @CMAKE_SOURCE_DIR@/lib/include/srslte/build_info.h.in + @CMAKE_BINARY_DIR@/lib/include/srslte/build_info.h +) diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index 37796682f..71c0864c8 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -163,6 +163,8 @@ int main(int argc, char **argv) { float cfo = 0; bool acks[SRSLTE_MAX_CODEWORDS] = {false}; + srslte_debug_handle_crash(argc, argv); + if (parse_args(&prog_args, argc, argv)) { exit(-1); } @@ -249,7 +251,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Error initiating ue_sync\n"); return -1; } - if (srslte_ue_dl_init(&ue_dl, cell.nof_prb, 1)) { + if (srslte_ue_dl_init(&ue_dl, sf_buffer, cell.nof_prb, 1)) { fprintf(stderr, "Error initiating UE downlink processing module\n"); return -1; } @@ -257,7 +259,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Error initiating UE downlink processing module\n"); return -1; } - if (srslte_ue_mib_init(&ue_mib, cell.nof_prb)) { + if (srslte_ue_mib_init(&ue_mib, sf_buffer, cell.nof_prb)) { fprintf(stderr, "Error initaiting UE MIB decoder\n"); return -1; } @@ -271,8 +273,16 @@ int main(int argc, char **argv) { /* Initialize subframe counter */ sf_cnt = 0; - - if (srslte_ofdm_rx_init(&fft, cell.cp, cell.nof_prb)) { + + int sf_re = SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); + + cf_t *sf_symbols = srslte_vec_malloc(sf_re * sizeof(cf_t)); + + for (int i=0;ifile_offset_freq = 0; args->rf_args = ""; args->rf_freq = -1.0; - args->rf_nof_rx_ant = 1; + args->rf_nof_rx_ant = 1; + args->enable_cfo_ref = false; + args->average_subframe = false; #ifdef ENABLE_AGC_DEFAULT args->rf_gain = -1.0; #else @@ -137,7 +141,7 @@ void args_default(prog_args_t *args) { } void usage(prog_args_t *args, char *prog) { - printf("Usage: %s [agpPoOcildDnruMNv] -f rx_frequency (in Hz) | -i input_file\n", prog); + printf("Usage: %s [agpPoOcildFRDnruMNv] -f rx_frequency (in Hz) | -i input_file\n", prog); #ifndef DISABLE_RF printf("\t-a RF args [Default %s]\n", args->rf_args); printf("\t-A Number of RX antennas [Default %d]\n", args->rf_nof_rx_ant); @@ -158,6 +162,8 @@ void usage(prog_args_t *args, char *prog) { printf("\t-r RNTI in Hex [Default 0x%x]\n",args->rnti); printf("\t-l Force N_id_2 [Default best]\n"); printf("\t-C Disable CFO correction [Default %s]\n", args->disable_cfo?"Disabled":"Enabled"); + printf("\t-F Enable RS-based CFO correction [Default %s]\n", args->enable_cfo_ref?"Disabled":"Enabled"); + printf("\t-R Average channel estimates on 1 ms [Default %s]\n", args->average_subframe?"Disabled":"Enabled"); printf("\t-t Add time offset [Default %d]\n", args->time_offset); #ifndef DISABLE_GRAPHICS printf("\t-d disable plots [Default enabled]\n"); @@ -179,7 +185,7 @@ void usage(prog_args_t *args, char *prog) { void parse_args(prog_args_t *args, int argc, char **argv) { int opt; args_default(args); - while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZyWMN")) != -1) { + while ((opt = getopt(argc, argv, "aAoglipPcOCtdDFRnvrfuUsSZyWMN")) != -1) { switch (opt) { case 'i': args->input_file_name = argv[optind]; @@ -211,6 +217,12 @@ void parse_args(prog_args_t *args, int argc, char **argv) { case 'C': args->disable_cfo = true; break; + case 'F': + args->enable_cfo_ref = true; + break; + case 'R': + args->average_subframe = true; + break; case 't': args->time_offset = atoi(argv[optind]); break; @@ -326,7 +338,8 @@ srslte_netsink_t net_sink, net_sink_signal; #define PRINT_LINE_ADVANCE_CURSOR() printf("\033[%dB", prev_nof_lines + 1) int main(int argc, char **argv) { - int ret; + struct timeval t[3]; + int ret; int decimate = 1; srslte_cell_t cell; int64_t sf_cnt; @@ -339,7 +352,9 @@ int main(int argc, char **argv) { uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; int sfn_offset; float cfo = 0; - + + srslte_debug_handle_crash(argc, argv); + parse_args(&prog_args, argc, argv); for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) { @@ -402,8 +417,8 @@ int main(int argc, char **argv) { fprintf(stderr, "Error opening rf\n"); exit(-1); } - srslte_rf_set_rx_gain(&rf, 50); - cell_detect_config.init_agc = 50; + srslte_rf_set_rx_gain(&rf, srslte_rf_get_rx_gain(&rf)); + cell_detect_config.init_agc = srslte_rf_get_rx_gain(&rf); } sigset_t sigset; @@ -510,7 +525,10 @@ int main(int argc, char **argv) { #endif } - if (srslte_ue_mib_init(&ue_mib, cell.nof_prb)) { + for (int i=0;i0){ @@ -691,6 +719,8 @@ int main(int argc, char **argv) { INFO("mbsfn PDU size is %d\n", n); } } + gettimeofday(&t[2], NULL); + get_time_interval(t); if (n < 0) { // fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); } else if (n > 0) { @@ -724,16 +754,19 @@ int main(int argc, char **argv) { } - nof_trials++; - - + nof_trials++; + + uint32_t nof_bits = ((acks[0]?ue_dl.pdsch_cfg.grant.mcs[0].tbs:0) + (acks[1]?ue_dl.pdsch_cfg.grant.mcs[1].tbs:0)); rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1f); rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05f); rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05f); noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05f); - enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs[0].tbs + ue_dl.pdsch_cfg.grant.mcs[1].tbs)/1000.0f, enodebrate, 0.05f); - uerate = SRSLTE_VEC_EMA(((acks[0]?ue_dl.pdsch_cfg.grant.mcs[0].tbs:0) + (acks[1]?ue_dl.pdsch_cfg.grant.mcs[1].tbs:0))/1000.0f, uerate, 0.01f); - + enodebrate = SRSLTE_VEC_EMA(nof_bits/1000.0f, enodebrate, 0.05f); + uerate = SRSLTE_VEC_EMA(nof_bits/1000.0f, uerate, 0.001f); + float elapsed = (float) t[0].tv_usec + t[0].tv_sec*1.0e+6f; + if (elapsed != 0.0f) { + procrate = SRSLTE_VEC_EMA(nof_bits/elapsed, procrate, 0.01f); + } nframes++; if (isnan(rsrq)) { @@ -768,9 +801,9 @@ int main(int argc, char **argv) { /* Print basic Parameters */ PRINT_LINE(" nof layers: %d", ue_dl.pdsch_cfg.nof_layers); PRINT_LINE("nof codewords: %d", SRSLTE_RA_DL_GRANT_NOF_TB(&ue_dl.pdsch_cfg.grant)); - PRINT_LINE(" CFO: %+5.2f kHz", srslte_ue_sync_get_cfo(&ue_sync) / 1000); + PRINT_LINE(" CFO: %+7.2f Hz", srslte_ue_sync_get_cfo(&ue_sync)); PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise)); - PRINT_LINE(" Rb: %6.2f / %6.2f Mbps (net/maximum)", uerate, enodebrate); + PRINT_LINE(" Rb: %6.2f / %6.2f / %6.2f Mbps (net/maximum/processing)", uerate, enodebrate, procrate); PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pdsch_pkt_errors / ue_dl.pdsch_pkts_total); if(prog_args.mbsfn_area_id > -1){ @@ -968,11 +1001,11 @@ void *plot_thread_run(void *arg) { tmp_plot2[g+i] = -80; } } - plot_real_setNewData(&pce, tmp_plot2, sz); + plot_real_setNewData(&pce, tmp_plot2, sz); if (!prog_args.input_file_name) { if (plot_track) { - srslte_pss_synch_t *pss_obj = srslte_sync_get_cur_pss_obj(&ue_sync.strack); + srslte_pss_t *pss_obj = srslte_sync_get_cur_pss_obj(&ue_sync.strack); int max = srslte_vec_max_fi(pss_obj->conv_output_avg, pss_obj->frame_size+pss_obj->fft_size-1); srslte_vec_sc_prod_fff(pss_obj->conv_output_avg, 1/pss_obj->conv_output_avg[max], diff --git a/lib/examples/synch_file.c b/lib/examples/synch_file.c index 178e56e99..4d553bd38 100644 --- a/lib/examples/synch_file.c +++ b/lib/examples/synch_file.c @@ -102,8 +102,8 @@ void parse_args(int argc, char **argv) { int main(int argc, char **argv) { srslte_filesource_t fsrc; srslte_filesink_t fsink; - srslte_pss_synch_t pss[3]; // One for each N_id_2 - srslte_sss_synch_t sss[3]; // One for each N_id_2 + srslte_pss_t pss[3]; // One for each N_id_2 + srslte_sss_t sss[3]; // One for each N_id_2 srslte_cfo_t cfocorr; int peak_pos[3]; float *cfo; @@ -163,19 +163,19 @@ int main(int argc, char **argv) { * a) requries more memory but has less latency and is paralellizable. */ for (N_id_2=0;N_id_2<3;N_id_2++) { - if (srslte_pss_synch_init(&pss[N_id_2], frame_length)) { + if (srslte_pss_init(&pss[N_id_2], frame_length)) { fprintf(stderr, "Error initializing PSS object\n"); exit(-1); } - if (srslte_pss_synch_set_N_id_2(&pss[N_id_2], N_id_2)) { + if (srslte_pss_set_N_id_2(&pss[N_id_2], N_id_2)) { fprintf(stderr, "Error initializing N_id_2\n"); exit(-1); } - if (srslte_sss_synch_init(&sss[N_id_2], 128)) { + if (srslte_sss_init(&sss[N_id_2], 128)) { fprintf(stderr, "Error initializing SSS object\n"); exit(-1); } - if (srslte_sss_synch_set_N_id_2(&sss[N_id_2], N_id_2)) { + if (srslte_sss_set_N_id_2(&sss[N_id_2], N_id_2)) { fprintf(stderr, "Error initializing N_id_2\n"); exit(-1); } @@ -199,10 +199,10 @@ int main(int argc, char **argv) { if (force_N_id_2 != -1) { N_id_2 = force_N_id_2; - peak_pos[N_id_2] = srslte_pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); + peak_pos[N_id_2] = srslte_pss_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); } else { for (N_id_2=0;N_id_2<3;N_id_2++) { - peak_pos[N_id_2] = srslte_pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); + peak_pos[N_id_2] = srslte_pss_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); } float max_value=-99999; N_id_2=-1; @@ -220,13 +220,13 @@ int main(int argc, char **argv) { sss_idx = peak_pos[N_id_2]-2*(symbol_sz+SRSLTE_CP_LEN(symbol_sz,SRSLTE_CP_NORM_LEN)); if (sss_idx >= 0) { - srslte_sss_synch_m0m1_diff(&sss[N_id_2], &input[sss_idx], + srslte_sss_m0m1_diff(&sss[N_id_2], &input[sss_idx], &m0, &m0_value, &m1, &m1_value); - cfo[frame_cnt] = srslte_pss_synch_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]); + cfo[frame_cnt] = srslte_pss_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]); printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n", - frame_cnt,N_id_2, srslte_sss_synch_N_id_1(&sss[N_id_2], m0, m1), - srslte_sss_synch_subframe(m0, m1), peak_value[N_id_2], + frame_cnt,N_id_2, srslte_sss_N_id_1(&sss[N_id_2], m0, m1), + srslte_sss_subframe(m0, m1), peak_value[N_id_2], peak_pos[N_id_2], m0, m1, cfo[frame_cnt]); } @@ -254,8 +254,8 @@ int main(int argc, char **argv) { printf("Average CFO: %.3f\n", cfo_mean); for (N_id_2=0;N_id_2<3;N_id_2++) { - srslte_pss_synch_free(&pss[N_id_2]); - srslte_sss_synch_free(&sss[N_id_2]); + srslte_pss_free(&pss[N_id_2]); + srslte_sss_free(&sss[N_id_2]); } srslte_filesource_free(&fsrc); diff --git a/lib/examples/usrp_capture.c b/lib/examples/usrp_capture.c index 02b543c0e..a0136e913 100644 --- a/lib/examples/usrp_capture.c +++ b/lib/examples/usrp_capture.c @@ -153,7 +153,7 @@ int main(int argc, char **argv) { printf("Correctly RX rate: %.2f MHz\n", srate*1e-6); srslte_rf_rx_wait_lo_locked(&rf); - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); while((sample_count < nof_samples || nof_samples == -1) diff --git a/lib/examples/usrp_capture_sync.c b/lib/examples/usrp_capture_sync.c index bac17698a..613f26d84 100644 --- a/lib/examples/usrp_capture_sync.c +++ b/lib/examples/usrp_capture_sync.c @@ -158,7 +158,7 @@ int main(int argc, char **argv) { exit(-1); } srslte_rf_rx_wait_lo_locked(&rf); - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); cell.cp = SRSLTE_CP_NORM; cell.id = N_id_2; diff --git a/lib/examples/usrp_txrx.c b/lib/examples/usrp_txrx.c index 508b4b397..42f610d65 100644 --- a/lib/examples/usrp_txrx.c +++ b/lib/examples/usrp_txrx.c @@ -175,7 +175,7 @@ int main(int argc, char **argv) { srslte_timestamp_t tstamp; - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); uint32_t nframe=0; diff --git a/lib/include/srslte/asn1/liblte_mme.h b/lib/include/srslte/asn1/liblte_mme.h index e730ec822..78e2cae69 100644 --- a/lib/include/srslte/asn1/liblte_mme.h +++ b/lib/include/srslte/asn1/liblte_mme.h @@ -2545,6 +2545,9 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_transaction_identifier_ie(uint8 // Enums // Structs // Functions +LIBLTE_ERROR_ENUM liblte_mme_parse_msg_sec_header(LIBLTE_BYTE_MSG_STRUCT *msg, + uint8 *pd, + uint8 *sec_hdr_type); LIBLTE_ERROR_ENUM liblte_mme_parse_msg_header(LIBLTE_BYTE_MSG_STRUCT *msg, uint8 *pd, uint8 *msg_type); @@ -2721,6 +2724,10 @@ typedef struct{ // Functions LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req, LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req); diff --git a/lib/include/srslte/asn1/liblte_rrc.h b/lib/include/srslte/asn1/liblte_rrc.h index 5a8515dbb..e0fb43aef 100644 --- a/lib/include/srslte/asn1/liblte_rrc.h +++ b/lib/include/srslte/asn1/liblte_rrc.h @@ -1218,6 +1218,9 @@ typedef enum{ }LIBLTE_RRC_REPORT_AMOUNT_ENUM; static const char liblte_rrc_report_amount_text[LIBLTE_RRC_REPORT_AMOUNT_N_ITEMS][20] = { "r1", "r2", "r4", "r8", "r16", "r32", "r64", "INFINITY"}; + +static const int8 liblte_rrc_report_amount_num[LIBLTE_RRC_REPORT_AMOUNT_N_ITEMS] = {1, 2, 4, 8, 16, 32, 64, -1}; + typedef enum{ LIBLTE_RRC_THRESHOLD_UTRA_TYPE_RSCP = 0, LIBLTE_RRC_THRESHOLD_UTRA_TYPE_ECNO, @@ -2681,6 +2684,7 @@ typedef enum{ }LIBLTE_RRC_T304_ENUM; static const char liblte_rrc_t304_text[LIBLTE_RRC_T304_N_ITEMS][20] = { "50", "100", "150", "200", "500", "1000", "2000", "SPARE"}; +static const int32 liblte_rrc_t304_num[LIBLTE_RRC_T304_N_ITEMS] = {50, 100, 150, 200, 500, 1000, 2000, -1}; // Structs typedef struct{ uint8 p_b; @@ -3926,7 +3930,7 @@ typedef enum{ }LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM; static const char liblte_rrc_pdsch_config_p_a_text[LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS][20] = { "-6", "-4.77", "-3", "-1.77", "0", "1", "2", "3"}; -static const double liblte_rrc_pdsch_config_p_a_num[LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS] = {-6, -4.77, -3, -1.77, 0, 1, 2, 3}; +static const float liblte_rrc_pdsch_config_p_a_num[LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS] = {-6, -4.77f, -3, -1.77f, 0, 1, 2, 3}; // Structs // PDSCH Config Common struct defined above // Functions @@ -6435,11 +6439,102 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_mobility_from_eutra_command_msg(LIBLTE_BIT_M Document Reference: 36.331 v10.0.0 Section 6.2.2 *********************************************************************/ -// Defines -// Enums +typedef struct{ + LIBLTE_RRC_CELL_GLOBAL_ID_EUTRA_STRUCT cell_global_id; + uint16 tracking_area_code; + LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_identity_list[5]; + uint32 n_plmn_identity_list; + bool have_plmn_identity_list; +}LIBLTE_RRC_CGI_INFO_STRUCT; +LIBLTE_ERROR_ENUM liblte_rrc_pack_cgi_info_ie(LIBLTE_RRC_CGI_INFO_STRUCT *cgi_info, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cgi_info_ie(uint8 **ie_ptr, + LIBLTE_RRC_CGI_INFO_STRUCT *cgi_info); + +typedef struct{ + uint8 rsrp_result; + bool have_rsrp; + uint8 rsrq_result; + bool have_rsrq; +}LIBLTE_RRC_MEAS_RESULT_STRUCT; +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_result_ie(LIBLTE_RRC_MEAS_RESULT_STRUCT *meas_result, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_result_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_RESULT_STRUCT *meas_result); + +typedef struct{ + uint16 phys_cell_id; + LIBLTE_RRC_CGI_INFO_STRUCT cgi_info; + bool have_cgi_info; + LIBLTE_RRC_MEAS_RESULT_STRUCT meas_result; +}LIBLTE_RRC_MEAS_RESULT_EUTRA_STRUCT; +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_result_eutra_ie(LIBLTE_RRC_MEAS_RESULT_EUTRA_STRUCT *meas_result_eutra, + uint8 **ie_ptr); +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_result_eutra_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_RESULT_EUTRA_STRUCT *meas_result_eutra); + +typedef struct{ + //FIXME +}LIBLTE_RRC_MEAS_RESULT_UTRA_STRUCT; +typedef struct{ + //FIXME +}LIBLTE_RRC_MEAS_RESULT_GERAN_STRUCT; +typedef struct{ + //FIXME +}LIBLTE_RRC_MEAS_RESULT_CDMA2000_STRUCT; + + + +typedef struct{ + LIBLTE_RRC_MEAS_RESULT_EUTRA_STRUCT result_eutra_list[8]; + uint8 n_result; +}LIBLTE_RRC_MEAS_RESULT_LIST_EUTRA_STRUCT; + +typedef struct{ + LIBLTE_RRC_MEAS_RESULT_UTRA_STRUCT result_utra_list[8]; + uint8 n_result; +}LIBLTE_RRC_MEAS_RESULT_LIST_UTRA_STRUCT; + +typedef struct{ + LIBLTE_RRC_MEAS_RESULT_GERAN_STRUCT result_geran_list[8]; + uint8 n_result; +}LIBLTE_RRC_MEAS_RESULT_LIST_GERAN_STRUCT; + + +typedef struct{ + bool pre_registration_status_HRPD; + LIBLTE_RRC_MEAS_RESULT_CDMA2000_STRUCT cdma2000[8]; +}LIBLTE_RRC_MEAS_RESULTS_CDMA2000_STRUCT; + +typedef enum{ + LIBLTE_RRC_MEAS_RESULT_LIST_EUTRA = 0, + LIBLTE_RRC_MEAS_RESULT_LIST_UTRA, + LIBLTE_RRC_MEAS_RESULT_LIST_GERAN, + LIBLTE_RRC_MEAS_RESULTS_CDMA2000, + LIBLTE_RRC_MEAS_RESULT_N_ITEMS, +}LIBLTE_RRC_MEAS_RESULT_NEIGH_CELLS_ENUM; +static const char liblte_rrc_meas_reult_neigh_cells_text[LIBLTE_RRC_MEAS_RESULT_N_ITEMS][32] = { "measResultListEUTRA", "measResultListUTRA", "measResultListGERAN", "measResultsCDMA2000"}; + + +typedef union{ + LIBLTE_RRC_MEAS_RESULT_LIST_EUTRA_STRUCT eutra; + LIBLTE_RRC_MEAS_RESULT_LIST_UTRA_STRUCT utra; + LIBLTE_RRC_MEAS_RESULT_LIST_GERAN_STRUCT geran; + LIBLTE_RRC_MEAS_RESULTS_CDMA2000_STRUCT cdma2000; +}LIBLTE_RRC_MEAS_RESULT_NEIGH_CELLS_UNION; + +//TODO: pack/unpack for the result lists + + // Structs typedef struct{ - // FIXME + uint8 meas_id; + uint8 pcell_rsrp_result; + uint8 pcell_rsrq_result; + + LIBLTE_RRC_MEAS_RESULT_NEIGH_CELLS_UNION meas_result_neigh_cells; + LIBLTE_RRC_MEAS_RESULT_NEIGH_CELLS_ENUM meas_result_neigh_cells_choice; + bool have_meas_result_neigh_cells; }LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT; // Functions LIBLTE_ERROR_ENUM liblte_rrc_pack_measurement_report_msg(LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *meas_report, diff --git a/lib/include/srslte/build_info.h.in b/lib/include/srslte/build_info.h.in new file mode 100644 index 000000000..a8acb306b --- /dev/null +++ b/lib/include/srslte/build_info.h.in @@ -0,0 +1,56 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef BUILD_INFO_ +#define BUILD_INFO_ + +# ifdef __cplusplus +extern "C" { +# endif + +#ifdef NDEBUG + static char build_mode[] = "Release"; +#else + static char build_mode[] = "Debug"; +#endif + +// the configured build options for srsLTE +static char build_info[] = "commit @GIT_COMMIT_HASH@ on branch @GIT_BRANCH@"; + +SRSLTE_API char* srslte_get_build_info() { + return build_info; +}; + +SRSLTE_API char* srslte_get_build_mode() { + return build_mode; +} + +# ifdef __cplusplus +} +# endif + +#endif // BUILD_INFO_ diff --git a/lib/include/srslte/common/buffer_pool.h b/lib/include/srslte/common/buffer_pool.h index 94439387a..567203c75 100644 --- a/lib/include/srslte/common/buffer_pool.h +++ b/lib/include/srslte/common/buffer_pool.h @@ -93,7 +93,7 @@ public: available.pop(); if (available.size() < capacity/20) { - printf("Warning buffer pool capacity is %f %%\n", (float) available.size()/capacity); + printf("Warning buffer pool capacity is %f %%\n", (float) 100*available.size()/capacity); } #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED if (debug_name) { @@ -123,8 +123,6 @@ public: used.erase(elem); available.push(b); ret = true; - } else { - printf("Error deallocating from buffer pool: buffer not created in this pool.\n"); } pthread_mutex_unlock(&mutex); return ret; diff --git a/lib/include/srslte/common/common.h b/lib/include/srslte/common/common.h index 7156fbfc9..3fd71422b 100644 --- a/lib/include/srslte/common/common.h +++ b/lib/include/srslte/common/common.h @@ -44,6 +44,19 @@ #define SRSLTE_N_DRB 8 #define SRSLTE_N_RADIO_BEARERS 11 +#define HARQ_DELAY_MS 4 +#define MSG3_DELAY_MS 2 // Delay added to HARQ_DELAY_MS +#define TTI_RX(tti) (tti>HARQ_DELAY_MS?((tti-HARQ_DELAY_MS)%10240):(10240+tti-HARQ_DELAY_MS)) +#define TTI_TX(tti) ((tti+HARQ_DELAY_MS)%10240) +#define TTI_RX_ACK(tti) ((tti+(2*HARQ_DELAY_MS))%10240) + +#define UL_PIDOF(tti) (tti%(2*HARQ_DELAY_MS)) + +#define TTIMOD_SZ (((2*HARQ_DELAY_MS) < 10)?10:20) +#define TTIMOD(tti) (tti%TTIMOD_SZ) + +#define ASYNC_DL_SCHED (HARQ_DELAY_MS <= 4) + // Cat 3 UE - Max number of DL-SCH transport block bits received within a TTI // 3GPP 36.306 Table 4.1.1 #define SRSLTE_MAX_BUFFER_SIZE_BITS 102048 @@ -83,6 +96,35 @@ static const char error_text[ERROR_N_ITEMS][20] = { "None", "Can't start", "Already started"}; +// Radio bearers +typedef enum{ + RB_ID_SRB0 = 0, + RB_ID_SRB1, + RB_ID_SRB2, + RB_ID_DRB1, + RB_ID_DRB2, + RB_ID_DRB3, + RB_ID_DRB4, + RB_ID_DRB5, + RB_ID_DRB6, + RB_ID_DRB7, + RB_ID_DRB8, + RB_ID_MAX +} rb_id_t; + +static const char rb_id_str[RB_ID_MAX][8] = {"SRB0", "SRB1", "SRB2", + "DRB1", "DRB2", "DRB3", + "DRB4", "DRB5", "DRB6", + "DRB7", "DRB8"}; + +inline const char* get_rb_name(uint32_t lcid) { + if (lcid < RB_ID_MAX) { + return rb_id_str[lcid]; + } else { + return "INVALID_RB"; + } +} + /****************************************************************************** * Byte and Bit buffers * diff --git a/lib/include/srslte/common/interfaces_common.h b/lib/include/srslte/common/interfaces_common.h index a027b6230..5fe26bc13 100644 --- a/lib/include/srslte/common/interfaces_common.h +++ b/lib/include/srslte/common/interfaces_common.h @@ -52,14 +52,12 @@ public: :direction(direction_) ,is_control(is_control_) ,is_data(is_data_) - ,do_security(false) ,sn_len(12) {} - uint8_t direction; - bool is_control; - bool is_data; - bool do_security; - uint8_t sn_len; + uint8_t direction; + bool is_control; + bool is_data; + uint8_t sn_len; // TODO: Support the following configurations // bool do_rohc; diff --git a/lib/include/srslte/common/liblte_security.h b/lib/include/srslte/common/liblte_security.h index b49f7211b..02cc42ca8 100644 --- a/lib/include/srslte/common/liblte_security.h +++ b/lib/include/srslte/common/liblte_security.h @@ -86,6 +86,15 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_enb(uint8 *k_asme, uint32 nas_count, uint8 *k_enb); +LIBLTE_ERROR_ENUM liblte_security_generate_k_enb_star(uint8 *k_enb, + uint32 pci, + uint32_t earfcn, + uint8 *k_enb_star); + +LIBLTE_ERROR_ENUM liblte_security_generate_nh( uint8_t *k_asme, + uint8_t *sync, + uint8_t *nh); + /********************************************************************* Name: liblte_security_generate_k_nas @@ -121,6 +130,8 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_nas(uint8 uint8 *k_nas_enc, uint8 *k_nas_int); + + /********************************************************************* Name: liblte_security_generate_k_rrc @@ -185,6 +196,73 @@ LIBLTE_ERROR_ENUM liblte_security_128_eia2(uint8 *key, LIBLTE_BIT_MSG_STRUCT *msg, uint8 *mac); +/********************************************************************* + Name: liblte_security_encryption_eea1 + + Description: 128-bit encryption algorithm EEA1. + + Document Reference: 33.401 v13.1.0 Annex B.1.2 + 35.215 v13.0.0 References + Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D1 v2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_encryption_eea1(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *msg, + uint32 msg_len, + uint8 *out); + +/********************************************************************* + Name: liblte_security_decryption_eea1 + + Description: 128-bit decryption algorithm EEA1. + + Document Reference: 33.401 v13.1.0 Annex B.1.2 + 35.215 v13.0.0 References + Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D1 v2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_decryption_eea1(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *ct, + uint32 ct_len, + uint8 *out); + +/********************************************************************* + Name: liblte_security_encryption_eea2 + + Description: 128-bit encryption algorithm EEA2. + + Document Reference: 33.401 v13.1.0 Annex B.1.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_encryption_eea2(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *msg, + uint32 msg_len, + uint8 *out); + +/********************************************************************* + Name: liblte_security_decryption_eea2 + + Description: 128-bit decryption algorithm EEA2. + + Document Reference: 33.401 v13.1.0 Annex B.1.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *ct, + uint32 ct_len, + uint8 *out); + + /********************************************************************* Name: liblte_security_milenage_f1 diff --git a/lib/include/srslte/common/liblte_ssl.h b/lib/include/srslte/common/liblte_ssl.h index 886d557b1..d96c728ab 100644 --- a/lib/include/srslte/common/liblte_ssl.h +++ b/lib/include/srslte/common/liblte_ssl.h @@ -38,6 +38,18 @@ int aes_crypt_ecb( aes_context *ctx, return mbedtls_aes_crypt_ecb(ctx, mode, input, output); } +int aes_crypt_ctr(aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + return mbedtls_aes_crypt_ctr(ctx, length, nc_off, nonce_counter, + stream_block, input, output); +} + void sha256(const unsigned char *key, size_t keylen, const unsigned char *input, size_t ilen, unsigned char output[32], int is224 ) diff --git a/lib/include/srslte/common/log.h b/lib/include/srslte/common/log.h index 9bec779df..71f47d197 100644 --- a/lib/include/srslte/common/log.h +++ b/lib/include/srslte/common/log.h @@ -54,6 +54,12 @@ static const char log_level_text[LOG_LEVEL_N_ITEMS][16] = {"None ", "Info ", "Debug "}; +static const char log_level_text_short[LOG_LEVEL_N_ITEMS][16] = {"[-]", + "[E]", + "[W]", + "[I]", + "[D]"}; + class log { public: @@ -63,6 +69,7 @@ public: tti = 0; level = LOG_LEVEL_NONE; hex_limit = 0; + show_layer_en = true; } log(std::string service_name_) { @@ -70,12 +77,20 @@ public: tti = 0; level = LOG_LEVEL_NONE; hex_limit = 0; + show_layer_en = true; } // This function shall be called at the start of every tti for printing tti void step(uint32_t tti_) { tti = tti_; + add_string_en = false; } + + void prepend_string(std::string s) { + add_string_en = true; + add_string_val = s; + } + uint32_t get_tti() { return tti; } @@ -93,6 +108,12 @@ public: int get_hex_limit() { return hex_limit; } + void set_log_level_short(bool enable) { + level_text_short = enable; + } + void show_layer(bool enable) { + show_layer_en = enable; + } // Pure virtual methods for logging virtual void console(std::string message, ...) = 0; @@ -107,18 +128,17 @@ public: virtual void info_hex(uint8_t *hex, int size, std::string message, ...){error("info_hex not implemented.\n");} virtual void debug_hex(uint8_t *hex, int size, std::string message, ...){error("debug_hex not implemented.\n");} - // Same with line and file info - virtual void error_line(std::string file, int line, std::string message, ...){error("error_line not implemented.\n");} - virtual void warning_line(std::string file, int line, std::string message, ...){error("warning_line not implemented.\n");} - virtual void info_line(std::string file, int line, std::string message, ...){error("info_line not implemented.\n");} - virtual void debug_line(std::string file, int line, std::string message, ...){error("debug_line not implemented.\n");} - protected: std::string get_service_name() { return service_name; } uint32_t tti; LOG_LEVEL_ENUM level; int hex_limit; std::string service_name; + + bool show_layer_en; + bool level_text_short; + bool add_string_en; + std::string add_string_val; }; } // namespace srslte diff --git a/lib/include/srslte/common/log_filter.h b/lib/include/srslte/common/log_filter.h index ae232f135..7e4014190 100644 --- a/lib/include/srslte/common/log_filter.h +++ b/lib/include/srslte/common/log_filter.h @@ -37,6 +37,8 @@ #include #include + +#include "srslte/phy/common/timestamp.h" #include "srslte/common/log.h" #include "srslte/common/logger.h" #include "srslte/common/logger_stdout.h" @@ -66,15 +68,25 @@ public: void info_hex(uint8_t *hex, int size, std::string message, ...); void debug_hex(uint8_t *hex, int size, std::string message, ...); - void error_line(std::string file, int line, std::string message, ...); - void warning_line(std::string file, int line, std::string message, ...); - void info_line(std::string file, int line, std::string message, ...); - void debug_line(std::string file, int line, std::string message, ...); + class time_itf { + public: + virtual srslte_timestamp_t get_time() = 0; + }; + + typedef enum { + TIME, + EPOCH + } time_format_t; + + void set_time_src(time_itf *source, time_format_t format); private: logger *logger_h; bool do_tti; + time_itf *time_src; + time_format_t time_format; + logger_stdout def_logger_stdout; void all_log(srslte::LOG_LEVEL_ENUM level, uint32_t tti, char *msg); diff --git a/lib/include/srslte/common/mac_pcap.h b/lib/include/srslte/common/mac_pcap.h index f441e1aed..26a8f20bb 100644 --- a/lib/include/srslte/common/mac_pcap.h +++ b/lib/include/srslte/common/mac_pcap.h @@ -35,10 +35,13 @@ namespace srslte { class mac_pcap { public: - mac_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; }; + mac_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; }; void enable(bool en); void open(const char *filename, uint32_t ue_id = 0); - void close(); + void close(); + + void set_ue_id(uint16_t ue_id); + void write_ul_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, uint32_t reTX, uint32_t tti); void write_dl_crnti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t crnti, bool crc_ok, uint32_t tti); void write_dl_ranti(uint8_t *pdu, uint32_t pdu_len_bytes, uint16_t ranti, bool crc_ok, uint32_t tti); @@ -51,8 +54,8 @@ public: private: bool enable_write; FILE *pcap_file; - uint32_t ue_id; - void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, + uint32_t ue_id; + void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, uint16_t crnti_, uint8_t direction, uint8_t rnti_type); }; diff --git a/lib/include/srslte/common/metrics_hub.h b/lib/include/srslte/common/metrics_hub.h index 7ea3c3190..ca6d0beac 100644 --- a/lib/include/srslte/common/metrics_hub.h +++ b/lib/include/srslte/common/metrics_hub.h @@ -24,15 +24,20 @@ template class metrics_listener { public: - virtual void set_metrics(metrics_t &m, float report_period_secs=1.0) = 0; -}; + virtual void set_metrics(metrics_t &m) = 0; +}; template class metrics_hub : public periodic_thread { public: - bool init(metrics_interface *m_, float report_period_secs=1.0) { - m = m_; + metrics_hub() + :m(NULL) + ,report_period_secs(1) + {} + bool init(metrics_interface *m_, float report_period_secs_=1.0) { + m = m_; + report_period_secs = report_period_secs_; start_periodic(report_period_secs*1e6); return true; } @@ -47,16 +52,17 @@ public: private: void run_period() { - metrics_t metric; - bzero(&metric, sizeof(metrics_t)); - m->get_metrics(metric); - for (uint32_t i=0;iset_metrics(metric); + if (m) { + metrics_t metric; + m->get_metrics(metric); + for (uint32_t i=0;iset_metrics(metric); + } } } metrics_interface *m; - std::vector*> listeners; - + std::vector*> listeners; + float report_period_secs; }; } // namespace srslte diff --git a/lib/include/srslte/common/nas_pcap.h b/lib/include/srslte/common/nas_pcap.h new file mode 100644 index 000000000..68fcabb73 --- /dev/null +++ b/lib/include/srslte/common/nas_pcap.h @@ -0,0 +1,25 @@ +#ifndef NAS_PCAP_H +#define NAS_PCAP_H + +#include "srslte/common/pcap.h" + +namespace srslte { + +class nas_pcap +{ +public: + nas_pcap() {enable_write=false; ue_id=0; pcap_file = NULL; } + void enable(); + void open(const char *filename, uint32_t ue_id=0); + void close(); + void write_nas(uint8_t *pdu, uint32_t pdu_len_bytes); +private: + bool enable_write; + FILE *pcap_file; + uint32_t ue_id; + void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes); +}; + +} //namespace srsue + +#endif // NAS_PCAP_H diff --git a/lib/include/srslte/common/pcap.h b/lib/include/srslte/common/pcap.h index d9937c060..ce4fcf541 100644 --- a/lib/include/srslte/common/pcap.h +++ b/lib/include/srslte/common/pcap.h @@ -32,7 +32,8 @@ #include #include -#define MAC_LTE_DLT 147 +#define MAC_LTE_DLT 147 +#define NAS_LTE_DLT 148 /* This structure gets written to the start of the file */ @@ -72,29 +73,15 @@ typedef struct pcaprec_hdr_s { #define SPS_RNTI 5 #define M_RNTI 6 -#define MAC_LTE_START_STRING "mac-lte" - +#define MAC_LTE_START_STRING "mac-lte" +#define MAC_LTE_PAYLOAD_TAG 0x01 #define MAC_LTE_RNTI_TAG 0x02 -/* 2 bytes, network order */ - #define MAC_LTE_UEID_TAG 0x03 -/* 2 bytes, network order */ - -#define MAC_LTE_SUBFRAME_TAG 0x04 -/* 2 bytes, network order */ - +#define MAC_LTE_FRAME_SUBFRAME_TAG 0x04 #define MAC_LTE_PREDFINED_DATA_TAG 0x05 -/* 1 byte */ - #define MAC_LTE_RETX_TAG 0x06 -/* 1 byte */ - #define MAC_LTE_CRC_STATUS_TAG 0x07 -/* 1 byte */ -/* MAC PDU. Following this tag comes the actual MAC PDU (there is no length, the PDU - continues until the end of the frame) */ -#define MAC_LTE_PAYLOAD_TAG 0x01 /* Context information for every MAC PDU that will be logged */ @@ -109,17 +96,20 @@ typedef struct MAC_Context_Info_t { unsigned short sysFrameNumber; unsigned short subFrameNumber; - } MAC_Context_Info_t; +/* Context information for every NAS PDU that will be logged */ +typedef struct NAS_Context_Info_s { + // No Context yet +} NAS_Context_Info_t; - -/**************************************************************************/ -/* API functions for opening/writing/closing MAC-LTE PCAP files */ +/************************************************************************** + * API functions for opening/closing LTE PCAP files * + **************************************************************************/ /* Open the file and write file header */ -inline FILE *MAC_LTE_PCAP_Open(const char *fileName) +inline FILE *LTE_PCAP_Open(uint32_t DLT, const char *fileName) { pcap_hdr_t file_header = { @@ -128,7 +118,7 @@ inline FILE *MAC_LTE_PCAP_Open(const char *fileName) 0, /* timezone */ 0, /* sigfigs - apparently all tools do this */ 65535, /* snaplen - this should be long enough */ - MAC_LTE_DLT /* Data Link Type (DLT). Set as unused value 147 for now */ + DLT /* Data Link Type (DLT). Set as unused value 147 for now */ }; FILE *fd = fopen(fileName, "w"); @@ -143,14 +133,26 @@ inline FILE *MAC_LTE_PCAP_Open(const char *fileName) return fd; } +/* Close the PCAP file */ +inline void LTE_PCAP_Close(FILE *fd) +{ + if(fd) + fclose(fd); +} + + +/************************************************************************** + * API functions for writing MAC-LTE PCAP files * + **************************************************************************/ + /* Write an individual PDU (PCAP packet header + mac-context + mac-pdu) */ -inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context, - const unsigned char *PDU, unsigned int length) +inline int LTE_PCAP_MAC_WritePDU(FILE *fd, MAC_Context_Info_t *context, + const unsigned char *PDU, unsigned int length) { pcaprec_hdr_t packet_header; char context_header[256]; int offset = 0; - unsigned short tmp16; + uint16_t tmp16; /* Can't write if file wasn't successfully opened */ if (fd == NULL) { @@ -176,9 +178,11 @@ inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context, memcpy(context_header+offset, &tmp16, 2); offset += 2; - /* Subframe number */ - context_header[offset++] = MAC_LTE_SUBFRAME_TAG; - tmp16 = htons(context->subFrameNumber); + /* Subframe Number and System Frame Number */ + /* SFN is stored in 12 MSB and SF in 4 LSB */ + context_header[offset++] = MAC_LTE_FRAME_SUBFRAME_TAG; + tmp16 = (context->sysFrameNumber << 4) | context->subFrameNumber; + tmp16 = htons(tmp16); memcpy(context_header+offset, &tmp16, 2); offset += 2; @@ -208,11 +212,39 @@ inline int MAC_LTE_PCAP_WritePDU(FILE *fd, MAC_Context_Info_t *context, return 1; } -/* Close the PCAP file */ -inline void MAC_LTE_PCAP_Close(FILE *fd) + + +/************************************************************************** + * API functions for writing NAS-EPS PCAP files * + **************************************************************************/ + +/* Write an individual PDU (PCAP packet header + nas-context + nas-pdu) */ +inline int LTE_PCAP_NAS_WritePDU(FILE *fd, NAS_Context_Info_t *context, + const unsigned char *PDU, unsigned int length) { - if(fd) - fclose(fd); + pcaprec_hdr_t packet_header; + + /* Can't write if file wasn't successfully opened */ + if (fd == NULL) { + printf("Error: Can't write to empty file handle\n"); + return 0; + } + + /****************************************************************/ + /* PCAP Header */ + struct timeval t; + gettimeofday(&t, NULL); + packet_header.ts_sec = t.tv_sec; + packet_header.ts_usec = t.tv_usec; + packet_header.incl_len = length; + packet_header.orig_len = length; + + /***************************************************************/ + /* Now write everything to the file */ + fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd); + fwrite(PDU, 1, length, fd); + + return 1; } -#endif /* UEPCAP_H */ \ No newline at end of file +#endif /* UEPCAP_H */ diff --git a/lib/include/srslte/common/security.h b/lib/include/srslte/common/security.h index 080f1848f..9ba2616d1 100644 --- a/lib/include/srslte/common/security.h +++ b/lib/include/srslte/common/security.h @@ -76,6 +76,15 @@ uint8_t security_generate_k_enb( uint8_t *k_asme, uint32_t nas_count, uint8_t *k_enb); +uint8_t security_generate_k_enb_star( uint8_t *k_enb, + uint32_t pci, + uint32_t earfcn, + uint8_t *k_enb_star); + +uint8_t security_generate_nh( uint8_t *k_asme, + uint8_t *sync, + uint8_t *nh); + uint8_t security_generate_k_nas( uint8_t *k_asme, CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, @@ -114,6 +123,26 @@ uint8_t security_128_eia2( uint8_t *key, uint32_t msg_len, uint8_t *mac); +/****************************************************************************** + * Encryption / Decryption + *****************************************************************************/ + +uint8_t security_128_eea1( uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *msg_out); + +uint8_t security_128_eea2(uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *msg_out); + /****************************************************************************** * Authentication *****************************************************************************/ diff --git a/lib/include/srslte/common/threads.h b/lib/include/srslte/common/threads.h index a8807ba9b..077dda72b 100644 --- a/lib/include/srslte/common/threads.h +++ b/lib/include/srslte/common/threads.h @@ -78,22 +78,30 @@ class periodic_thread : public thread { public: void start_periodic(int period_us_, int priority = -1) { + run_enable = true; period_us = period_us_; start(priority); } + void stop() { + run_enable = false; + wait_thread_finish(); + } protected: virtual void run_period() = 0; private: int wakeups_missed; int timer_fd; - int period_us; + int period_us; + bool run_enable; void run_thread() { if (make_periodic()) { return; } - while(1) { + while(run_enable) { run_period(); - wait_period(); + if (run_enable) { + wait_period(); + } } } int make_periodic() { diff --git a/lib/include/srslte/common/timers.h b/lib/include/srslte/common/timers.h index a8563af37..d77692d5a 100644 --- a/lib/include/srslte/common/timers.h +++ b/lib/include/srslte/common/timers.h @@ -64,7 +64,7 @@ public: return (counter < timeout) && running; } bool is_expired() { - return callback && (counter >= timeout || !running); + return (timeout > 0) && (counter >= timeout || !running); } uint32_t get_timeout() { return timeout; @@ -72,6 +72,9 @@ public: void reset() { counter = 0; } + uint32_t value() { + return counter; + } void step() { if (running) { counter++; diff --git a/lib/include/srslte/common/tti_sync.h b/lib/include/srslte/common/tti_sync.h index 23061ea2d..fd62f442b 100644 --- a/lib/include/srslte/common/tti_sync.h +++ b/lib/include/srslte/common/tti_sync.h @@ -50,6 +50,7 @@ class tti_sync init_counters(0); } virtual void increase() = 0; + virtual void increase(uint32_t cnt) = 0; virtual void resync() = 0; virtual uint32_t wait() = 0; virtual void set_producer_cntr(uint32_t) = 0; @@ -60,6 +61,7 @@ class tti_sync } protected: void increase_producer() { producer_cntr = (producer_cntr + increment)%modulus; } + void increase_producer(uint32_t cnt) { producer_cntr = cnt%modulus; } void increase_consumer() { consumer_cntr = (consumer_cntr + increment)%modulus; } bool wait_condition() { return producer_cntr == consumer_cntr; } void init_counters(uint32_t val) diff --git a/lib/include/srslte/common/tti_sync_cv.h b/lib/include/srslte/common/tti_sync_cv.h index c04fa71f0..887ac4f04 100644 --- a/lib/include/srslte/common/tti_sync_cv.h +++ b/lib/include/srslte/common/tti_sync_cv.h @@ -44,7 +44,8 @@ class tti_sync_cv : public tti_sync tti_sync_cv(uint32_t modulus = 10240); ~tti_sync_cv(); void increase(); - uint32_t wait(); + void increase(uint32_t cnt); + uint32_t wait(); void resync(); void set_producer_cntr(uint32_t producer_cntr); diff --git a/lib/include/srslte/config.h b/lib/include/srslte/config.h index 68076c0c8..8a988a971 100644 --- a/lib/include/srslte/config.h +++ b/lib/include/srslte/config.h @@ -59,5 +59,6 @@ // cf_t definition typedef _Complex float cf_t; +typedef _Complex short int c16_t; #endif // CONFIG_H diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index 9c85814f8..cd7d10020 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -64,9 +64,11 @@ public: virtual int sr_detected(uint32_t tti, uint16_t rnti) = 0; virtual int rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv) = 0; + virtual int ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value) = 0; + virtual int pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) = 0; virtual int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) = 0; virtual int snr_info(uint32_t tti, uint16_t rnti, float snr_db) = 0; - virtual int ack_info(uint32_t tti, uint16_t rnti, bool ack) = 0; + virtual int ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack) = 0; virtual int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res) = 0; virtual int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) = 0; @@ -93,7 +95,8 @@ public: class phy_interface_rrc { public: - virtual void set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) = 0; + virtual void set_conf_dedicated_ack(uint16_t rnti, bool rrc_completed) = 0; + virtual void set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) = 0; }; @@ -111,6 +114,7 @@ public: /* Manages UE bearers and associated configuration */ virtual int bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bearer_cfg_t *cfg) = 0; virtual int bearer_ue_rem(uint16_t rnti, uint32_t lc_id) = 0; + virtual int set_dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dl_ant_info) = 0; virtual void phy_config_enabled(uint16_t rnti, bool enabled) = 0; }; @@ -147,6 +151,7 @@ public: /* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls * RLC PDUs according to TB size. */ virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual bool rb_is_um(uint16_t rnti, uint32_t lcid) = 0; }; // RLC interface for RRC diff --git a/lib/include/srslte/interfaces/sched_interface.h b/lib/include/srslte/interfaces/sched_interface.h index a717b4293..562499dfb 100644 --- a/lib/include/srslte/interfaces/sched_interface.h +++ b/lib/include/srslte/interfaces/sched_interface.h @@ -131,13 +131,14 @@ public: typedef struct { uint32_t rnti; + srslte_dci_format_t dci_format; srslte_ra_dl_dci_t dci; srslte_dci_location_t dci_location; - uint32_t tbs; + uint32_t tbs[SRSLTE_MAX_TB]; bool mac_ce_ta; bool mac_ce_rnti; - uint32_t nof_pdu_elems; - dl_sched_pdu_t pdu[MAX_RLC_PDU_LIST]; + uint32_t nof_pdu_elems[SRSLTE_MAX_TB]; + dl_sched_pdu_t pdu[SRSLTE_MAX_TB][MAX_RLC_PDU_LIST]; } dl_sched_data_t; typedef struct { @@ -225,8 +226,10 @@ public: virtual int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code) = 0; /* DL information */ - virtual int dl_ack_info(uint32_t tti, uint16_t rnti, bool ack) = 0; + virtual int dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack) = 0; virtual int dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size) = 0; + virtual int dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value) = 0; + virtual int dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) = 0; virtual int dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) = 0; /* UL information */ diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 8561ba55c..e8a33c207 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -52,16 +52,20 @@ class ue_interface class usim_interface_nas { public: - virtual void get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; - virtual void get_imei_vec(uint8_t* imei_, uint32_t n) = 0; - virtual int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0; + virtual std::string get_imsi_str() = 0; + virtual std::string get_imei_str() = 0; + virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; + virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0; + virtual bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0; virtual void generate_authentication_response(uint8_t *rand, uint8_t *autn_enb, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res) = 0; - virtual void generate_nas_keys(uint8_t *k_nas_enc, + uint8_t *res, + uint8_t *k_asme) = 0; + virtual void generate_nas_keys(uint8_t *k_asme, + uint8_t *k_nas_enc, uint8_t *k_nas_int, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; @@ -71,13 +75,23 @@ public: class usim_interface_rrc { public: - virtual void generate_as_keys(uint32_t count_ul, + virtual void generate_as_keys(uint8_t *k_asme, + uint32_t count_ul, uint8_t *k_rrc_enc, uint8_t *k_rrc_int, uint8_t *k_up_enc, uint8_t *k_up_int, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; + virtual void generate_as_keys_ho(uint32_t pci, + uint32_t earfcn, + int ncc, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; }; // GW interface for NAS @@ -104,6 +118,7 @@ public: virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; virtual uint32_t get_ul_count() = 0; virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0; + virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0; virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0; virtual void plmn_search_end() = 0; }; @@ -112,15 +127,15 @@ public: class nas_interface_ue { public: - virtual void attach_request() = 0; - virtual void deattach_request() = 0; + virtual void attach_request() = 0; + virtual void deattach_request() = 0; }; // NAS interface for UE class nas_interface_gw { public: - virtual void attach_request() = 0; + virtual void attach_request() = 0; }; // RRC interface for MAC @@ -133,7 +148,9 @@ public: class rrc_interface_mac : public rrc_interface_mac_common { public: + virtual void ho_ra_completed(bool ra_successful) = 0; virtual void release_pucch_srs() = 0; + virtual void run_tti(uint32_t tti) = 0; }; // RRC interface for PHY @@ -144,6 +161,7 @@ public: virtual void out_of_sync() = 0; virtual void earfcn_end() = 0; virtual void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) = 0; + virtual void new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn = 0, uint32_t pci = 0) = 0; }; // RRC interface for NAS @@ -156,7 +174,6 @@ public: virtual void enable_capabilities() = 0; virtual void plmn_search() = 0; virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0; - virtual std::string get_rb_name(uint32_t lcid) = 0; }; // RRC interface for PDCP @@ -167,7 +184,6 @@ public: virtual void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu_pcch(srslte::byte_buffer_t *pdu) = 0; - virtual std::string get_rb_name(uint32_t lcid) = 0; }; // RRC interface for RLC @@ -175,7 +191,6 @@ class rrc_interface_rlc { public: virtual void max_retx_attempted() = 0; - virtual std::string get_rb_name(uint32_t lcid) = 0; }; // PDCP interface for GW @@ -190,14 +205,21 @@ public: class pdcp_interface_rrc { public: + virtual void reestablish() = 0; virtual void reset() = 0; virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_pdcp_config_t cnfg = srslte::srslte_pdcp_config_t()) = 0; virtual void config_security(uint32_t lcid, - uint8_t *k_rrc_enc_, - uint8_t *k_rrc_int_, + uint8_t *k_enc_, + uint8_t *k_int_, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; + virtual void config_security_all(uint8_t *k_enc_, + uint8_t *k_int_, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) = 0; + virtual void enable_integrity(uint32_t lcid) = 0; + virtual void enable_encryption(uint32_t lcid) = 0; }; // PDCP interface for RLC @@ -216,6 +238,7 @@ class rlc_interface_rrc { public: virtual void reset() = 0; + virtual void reestablish() = 0; virtual void add_bearer(uint32_t lcid) = 0; virtual void add_bearer(uint32_t lcid, srslte::srslte_rlc_config_t cnfg) = 0; }; @@ -227,6 +250,7 @@ public: /* PDCP calls RLC to push an RLC SDU. SDU gets placed into the RLC buffer and MAC pulls * RLC PDUs according to TB size. */ virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual bool rb_is_um(uint32_t lcid) = 0; }; //RLC interface for MAC @@ -390,8 +414,8 @@ public: LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT rach; LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT sr; ul_harq_params_t ul_harq_params; - uint32_t prach_config_index; - } mac_cfg_t; + uint32_t prach_config_index; + } mac_cfg_t; /* Instructs the MAC to start receiving BCCH */ virtual void bcch_start_rx() = 0; @@ -406,7 +430,7 @@ public: virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0; virtual uint32_t get_current_tti() = 0; - + virtual void set_config(mac_cfg_t *mac_cfg) = 0; virtual void set_config_main(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *main_cfg) = 0; virtual void set_config_rach(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cfg, uint32_t prach_config_index) = 0; @@ -415,10 +439,14 @@ public: virtual void get_rntis(ue_rnti_t *rntis) = 0; virtual void set_contention_id(uint64_t uecri) = 0; + virtual void set_ho_rnti(uint16_t crnti, uint16_t target_pci) = 0; + + virtual void start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask) = 0; + virtual void start_cont_ho() = 0; - virtual void reconfiguration() = 0; virtual void reset() = 0; + virtual void wait_uplink() = 0; }; @@ -445,12 +473,22 @@ typedef struct { float snr_ema_coeff; std::string snr_estim_alg; bool cfo_integer_enabled; - float cfo_correct_tol_hz; + float cfo_correct_tol_hz; + float cfo_pss_ema; + float cfo_ref_ema; + float cfo_loop_bw_pss; + float cfo_loop_bw_ref; + float cfo_loop_ref_min; + float cfo_loop_pss_tol; + uint32_t cfo_loop_pss_conv; + uint32_t cfo_ref_mask; + bool average_subframe_enabled; int time_correct_period; bool sfo_correct_disable; std::string sss_algorithm; float estimator_fil_w; bool rssi_sensor_enabled; + bool sic_pss_enabled; } phy_args_t; @@ -520,19 +558,28 @@ public: bool enable_64qam; } phy_cfg_t; - virtual void get_current_cell(srslte_cell_t *cell) = 0; - virtual void get_config(phy_cfg_t *phy_cfg) = 0; + virtual void get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn = NULL) = 0; + virtual uint32_t get_current_earfcn() = 0; + virtual uint32_t get_current_pci() = 0; + + virtual void get_config(phy_cfg_t *phy_cfg) = 0; virtual void set_config(phy_cfg_t *phy_cfg) = 0; virtual void set_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated) = 0; virtual void set_config_common(phy_cfg_common_t *common) = 0; virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0; virtual void set_config_64qam_en(bool enable) = 0; + /* Measurements interface */ + virtual void meas_reset() = 0; + virtual int meas_start(uint32_t earfcn, int pci = -1) = 0; + virtual int meas_stop(uint32_t earfcn, int pci = -1) = 0; + /* Cell search and selection procedures */ virtual void cell_search_start() = 0; virtual void cell_search_stop() = 0; virtual void cell_search_next() = 0; virtual bool cell_select(uint32_t earfcn, srslte_cell_t cell) = 0; + virtual bool cell_handover(srslte_cell_t cell) = 0; /* Is the PHY downlink synchronized? */ virtual bool sync_status() = 0; diff --git a/lib/include/srslte/phy/ch_estimation/chest_dl.h b/lib/include/srslte/phy/ch_estimation/chest_dl.h index 0e43d113c..0bd6e9afe 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_dl.h +++ b/lib/include/srslte/phy/ch_estimation/chest_dl.h @@ -68,7 +68,8 @@ typedef struct { cf_t *pilot_estimates_average; cf_t *pilot_recv_signal; cf_t *tmp_noise; - + cf_t *tmp_cfo_estimate; + #ifdef FREQ_SEL_SNR float snr_vector[12000]; float pilot_power[12000]; @@ -82,7 +83,11 @@ typedef struct { float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - + float cfo; + + bool cfo_estimate_enable; + uint32_t cfo_estimate_sf_mask; + /* Use PSS for noise estimation in LS linear interpolation mode */ cf_t pss_signal[SRSLTE_PSS_LEN]; cf_t tmp_pss[SRSLTE_PSS_LEN]; @@ -91,6 +96,7 @@ typedef struct { srslte_chest_dl_noise_alg_t noise_alg; int last_nof_antennas; + bool average_subframe; } srslte_chest_dl_t; @@ -144,14 +150,35 @@ SRSLTE_API int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, uint32_t port_id, uint32_t rxant_id); -SRSLTE_API float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q); +SRSLTE_API void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, + bool enable, + uint32_t mask); + +SRSLTE_API void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q, + bool enable); + +SRSLTE_API float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q); + +SRSLTE_API float srslte_chest_dl_get_cfo(srslte_chest_dl_t *q); SRSLTE_API float srslte_chest_dl_get_snr(srslte_chest_dl_t *q); +SRSLTE_API float srslte_chest_dl_get_snr_ant_port(srslte_chest_dl_t *q, + uint32_t ant_idx, + uint32_t port_idx); + SRSLTE_API float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q); SRSLTE_API float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q); +SRSLTE_API float srslte_chest_dl_get_rsrq_ant_port(srslte_chest_dl_t *q, + uint32_t ant_idx, + uint32_t port); + +SRSLTE_API float srslte_chest_dl_get_rsrp_ant_port(srslte_chest_dl_t *q, + uint32_t ant_idx, + uint32_t port); + SRSLTE_API float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, uint32_t port); diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index 148a12974..c55713cfc 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -101,8 +101,8 @@ typedef enum {SRSLTE_SF_NORM, SRSLTE_SF_MBSFN} srslte_sf_t; #define SRSLTE_CP_ISEXT(cp) (cp==SRSLTE_CP_EXT) #define SRSLTE_CP_NSYMB(cp) (SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_NORM_NSYMB:SRSLTE_CP_EXT_NSYMB) -#define SRSLTE_CP_LEN(symbol_sz, c) ((int) ceil((((float) (c)*(symbol_sz))/2048))) -#define SRSLTE_CP_LEN_NORM(symbol, symbol_sz) ((symbol==0)?SRSLTE_CP_LEN((symbol_sz),SRSLTE_CP_NORM_0_LEN):SRSLTE_CP_LEN((symbol_sz),SRSLTE_CP_NORM_LEN)) +#define SRSLTE_CP_LEN(symbol_sz, c) ((int) ceilf((((float) (c)*(symbol_sz))/2048.0f))) +#define SRSLTE_CP_LEN_NORM(symbol, symbol_sz) (((symbol)==0)?SRSLTE_CP_LEN((symbol_sz),SRSLTE_CP_NORM_0_LEN):SRSLTE_CP_LEN((symbol_sz),SRSLTE_CP_NORM_LEN)) #define SRSLTE_CP_LEN_EXT(symbol_sz) (SRSLTE_CP_LEN((symbol_sz),SRSLTE_CP_EXT_LEN)) #define SRSLTE_SLOT_LEN(symbol_sz) (symbol_sz*15/2) @@ -197,7 +197,8 @@ typedef enum SRSLTE_API { SRSLTE_MOD_BPSK = 0, SRSLTE_MOD_QPSK, SRSLTE_MOD_16QAM, - SRSLTE_MOD_64QAM + SRSLTE_MOD_64QAM, + SRSLTE_MOD_LAST } srslte_mod_t; typedef struct SRSLTE_API { @@ -300,7 +301,8 @@ SRSLTE_API int srslte_str2mimotype(char *mimo_type_str, SRSLTE_API char *srslte_mimotype2str(srslte_mimo_type_t mimo_type); -SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1, +/* Returns the interval tti1-tti2 mod 10240 */ +SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1, uint32_t tti2); #endif diff --git a/lib/include/srslte/phy/common/phy_logger.h b/lib/include/srslte/phy/common/phy_logger.h new file mode 100644 index 000000000..d02efbb47 --- /dev/null +++ b/lib/include/srslte/phy/common/phy_logger.h @@ -0,0 +1,59 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: phy_logger.h + * Description: Interface for logging output + *****************************************************************************/ + +#ifndef PHY_LOGGER_H +#define PHY_LOGGER_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif // __cplusplus +typedef enum {LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_ERROR} phy_logger_level_t; + +typedef void (*phy_log_handler_t)(phy_logger_level_t log_level, void *ctx, char *str); + +void srslte_phy_log_register_handler(void *ctx, phy_log_handler_t handler); + + void srslte_phy_log_print(phy_logger_level_t log_level, const char *format, ...); + +#ifdef __cplusplus +} +#endif // C++ + +#endif // LOGGER_H diff --git a/lib/include/srslte/phy/dft/dft.h b/lib/include/srslte/phy/dft/dft.h index b7fc663d8..afe8024d2 100644 --- a/lib/include/srslte/phy/dft/dft.h +++ b/lib/include/srslte/phy/dft/dft.h @@ -63,6 +63,7 @@ typedef struct SRSLTE_API { void *in; // Input buffer void *out; // Output buffer void *p; // DFT plan + bool is_guru; bool forward; // Forward transform? bool mirror; // Shift negative and positive frequencies? bool db; // Provide output in dB? @@ -85,6 +86,17 @@ SRSLTE_API int srslte_dft_plan_c(srslte_dft_plan_t *plan, int dft_points, srslte_dft_dir_t dir); +SRSLTE_API int srslte_dft_plan_guru_c(srslte_dft_plan_t *plan, + int dft_points, + srslte_dft_dir_t dir, + cf_t *in_buffer, + cf_t *out_buffer, + int istride, + int ostride, + int how_many, + int idist, + int odist); + SRSLTE_API int srslte_dft_plan_r(srslte_dft_plan_t *plan, int dft_points, srslte_dft_dir_t dir); @@ -92,6 +104,16 @@ SRSLTE_API int srslte_dft_plan_r(srslte_dft_plan_t *plan, SRSLTE_API int srslte_dft_replan(srslte_dft_plan_t *plan, const int new_dft_points); +SRSLTE_API int srslte_dft_replan_guru_c(srslte_dft_plan_t *plan, + const int new_dft_points, + cf_t *in_buffer, + cf_t *out_buffer, + int istride, + int ostride, + int how_many, + int idist, + int odist); + SRSLTE_API int srslte_dft_replan_c(srslte_dft_plan_t *plan, int new_dft_points); @@ -117,20 +139,22 @@ SRSLTE_API void srslte_dft_plan_set_dc(srslte_dft_plan_t *plan, /* Compute DFT */ -SRSLTE_API void srslte_dft_run(srslte_dft_plan_t *plan, - void *in, +SRSLTE_API void srslte_dft_run(srslte_dft_plan_t *plan, + const void *in, void *out); -SRSLTE_API void srslte_dft_run_c_zerocopy(srslte_dft_plan_t *plan, - cf_t *in, +SRSLTE_API void srslte_dft_run_c_zerocopy(srslte_dft_plan_t *plan, + const cf_t *in, cf_t *out); -SRSLTE_API void srslte_dft_run_c(srslte_dft_plan_t *plan, - cf_t *in, +SRSLTE_API void srslte_dft_run_c(srslte_dft_plan_t *plan, + const cf_t *in, cf_t *out); +SRSLTE_API void srslte_dft_run_guru_c(srslte_dft_plan_t *plan); + SRSLTE_API void srslte_dft_run_r(srslte_dft_plan_t *plan, - float *in, + const float *in, float *out); #endif // DFT_H_ diff --git a/lib/include/srslte/phy/dft/ofdm.h b/lib/include/srslte/phy/dft/ofdm.h index 1363f5638..e48c240b9 100644 --- a/lib/include/srslte/phy/dft/ofdm.h +++ b/lib/include/srslte/phy/dft/ofdm.h @@ -47,14 +47,18 @@ /* This is common for both directions */ typedef struct SRSLTE_API{ srslte_dft_plan_t fft_plan; + srslte_dft_plan_t fft_plan_sf[2]; uint32_t max_prb; uint32_t nof_symbols; uint32_t symbol_sz; uint32_t nof_guards; uint32_t nof_re; uint32_t slot_sz; + uint32_t sf_sz; srslte_cp_t cp; cf_t *tmp; // for removing zero padding + cf_t *in_buffer; + cf_t *out_buffer; bool mbsfn_subframe; uint32_t mbsfn_guard_len; @@ -69,12 +73,16 @@ typedef struct SRSLTE_API{ SRSLTE_API int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, + cf_t *in_buffer, + cf_t *out_buffer, int symbol_sz, int nof_prb, srslte_dft_dir_t dir); SRSLTE_API int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, srslte_cp_t cp, + cf_t *in_buffer, + cf_t *out_buffer, int symbol_sz, int nof_prb, srslte_dft_dir_t dir, @@ -82,12 +90,14 @@ SRSLTE_API int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, SRSLTE_API int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp_type, + cf_t *in_buffer, + cf_t *out_buffer, uint32_t nof_prb); - - SRSLTE_API int srslte_ofdm_rx_init(srslte_ofdm_t *q, srslte_cp_t cp_type, + cf_t *in_buffer, + cf_t *out_buffer, uint32_t max_prb); SRSLTE_API int srslte_ofdm_tx_set_prb(srslte_ofdm_t *q, @@ -100,39 +110,43 @@ SRSLTE_API int srslte_ofdm_rx_set_prb(srslte_ofdm_t *q, SRSLTE_API void srslte_ofdm_rx_free(srslte_ofdm_t *q); -SRSLTE_API void srslte_ofdm_rx_slot(srslte_ofdm_t *q, - cf_t *input, - cf_t *output); +SRSLTE_API void srslte_ofdm_rx_slot(srslte_ofdm_t *q, + int slot_in_sf); -SRSLTE_API void srslte_ofdm_rx_sf(srslte_ofdm_t *q, - cf_t *input, - cf_t *output); +SRSLTE_API void srslte_ofdm_rx_slot_ng(srslte_ofdm_t *q, + cf_t *input, + cf_t *output); +SRSLTE_API void srslte_ofdm_rx_sf(srslte_ofdm_t *q); +SRSLTE_API void srslte_ofdm_rx_sf_ng(srslte_ofdm_t *q, + cf_t *input, + cf_t *output); SRSLTE_API int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp_type, + cf_t *in_buffer, + cf_t *out_buffer, uint32_t nof_prb); SRSLTE_API int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, + cf_t *in_buffer, + cf_t *out_buffer, uint32_t nof_prb); SRSLTE_API void srslte_ofdm_tx_free(srslte_ofdm_t *q); -SRSLTE_API void srslte_ofdm_tx_slot(srslte_ofdm_t *q, - cf_t *input, - cf_t *output); +SRSLTE_API void srslte_ofdm_tx_slot(srslte_ofdm_t *q, + int slot_in_sf); SRSLTE_API void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t *q, cf_t *input, cf_t *output); -SRSLTE_API void srslte_ofdm_tx_sf(srslte_ofdm_t *q, - cf_t *input, - cf_t *output); +SRSLTE_API void srslte_ofdm_tx_sf(srslte_ofdm_t *q); SRSLTE_API int srslte_ofdm_set_freq_shift(srslte_ofdm_t *q, float freq_shift); @@ -144,4 +158,4 @@ SRSLTE_API void srslte_ofdm_set_non_mbsfn_region(srslte_ofdm_t *q, uint8_t non_mbsfn_region); -#endif \ No newline at end of file +#endif diff --git a/lib/include/srslte/phy/enb/enb_dl.h b/lib/include/srslte/phy/enb/enb_dl.h index 7c3166e5c..f326d4b09 100644 --- a/lib/include/srslte/phy/enb/enb_dl.h +++ b/lib/include/srslte/phy/enb/enb_dl.h @@ -68,7 +68,7 @@ typedef struct SRSLTE_API { cf_t *sf_symbols[SRSLTE_MAX_PORTS]; cf_t *slot1_symbols[SRSLTE_MAX_PORTS]; - srslte_ofdm_t ifft; + srslte_ofdm_t ifft[SRSLTE_MAX_PORTS]; srslte_pbch_t pbch; srslte_pcfich_t pcfich; srslte_regs_t regs; @@ -95,10 +95,11 @@ typedef struct SRSLTE_API { typedef struct { uint16_t rnti; + srslte_dci_format_t dci_format; srslte_ra_dl_dci_t grant; srslte_dci_location_t location; - srslte_softbuffer_tx_t *softbuffer; - uint8_t *data; + srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_TB]; + uint8_t *data[SRSLTE_MAX_TB]; } srslte_enb_dl_pdsch_t; typedef struct { @@ -109,7 +110,8 @@ typedef struct { } srslte_enb_dl_phich_t; /* This function shall be called just after the initial synchronization */ -SRSLTE_API int srslte_enb_dl_init(srslte_enb_dl_t *q, +SRSLTE_API int srslte_enb_dl_init(srslte_enb_dl_t *q, + cf_t *out_buffer[SRSLTE_MAX_PORTS], uint32_t max_prb); SRSLTE_API void srslte_enb_dl_free(srslte_enb_dl_t *q); @@ -146,8 +148,7 @@ SRSLTE_API void srslte_enb_dl_put_phich(srslte_enb_dl_t *q, SRSLTE_API void srslte_enb_dl_put_base(srslte_enb_dl_t *q, uint32_t tti); -SRSLTE_API void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q, - cf_t *signal_buffer); +SRSLTE_API void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q); SRSLTE_API int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q, uint16_t rnti); @@ -162,8 +163,7 @@ SRSLTE_API int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, int rv_idx[SRSLTE_MAX_CODEWORDS], uint32_t sf_idx, uint8_t *data[SRSLTE_MAX_CODEWORDS], - srslte_mimo_type_t mimo_type, - uint32_t pmi); + srslte_mimo_type_t mimo_type); SRSLTE_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q, srslte_ra_dl_dci_t *grant, diff --git a/lib/include/srslte/phy/enb/enb_ul.h b/lib/include/srslte/phy/enb/enb_ul.h index 855b645ca..8699a2a37 100644 --- a/lib/include/srslte/phy/enb/enb_ul.h +++ b/lib/include/srslte/phy/enb/enb_ul.h @@ -101,6 +101,7 @@ typedef struct { /* This function shall be called just after the initial synchronization */ SRSLTE_API int srslte_enb_ul_init(srslte_enb_ul_t *q, + cf_t *in_buffer, uint32_t max_prb); SRSLTE_API void srslte_enb_ul_free(srslte_enb_ul_t *q); @@ -124,8 +125,7 @@ SRSLTE_API int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint16_t rnti, srslte_refsignal_srs_cfg_t *srs_cfg); -SRSLTE_API void srslte_enb_ul_fft(srslte_enb_ul_t *q, - cf_t *signal_buffer); +SRSLTE_API void srslte_enb_ul_fft(srslte_enb_ul_t *q); SRSLTE_API int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti, @@ -140,6 +140,7 @@ SRSLTE_API int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, uint32_t rv_idx, uint32_t current_tx_nb, uint8_t *data, + srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data, uint32_t tti); diff --git a/lib/include/srslte/phy/fec/rm_turbo.h b/lib/include/srslte/phy/fec/rm_turbo.h index df0720b95..182b49fb8 100644 --- a/lib/include/srslte/phy/fec/rm_turbo.h +++ b/lib/include/srslte/phy/fec/rm_turbo.h @@ -58,6 +58,8 @@ SRSLTE_API int srslte_rm_turbo_tx(uint8_t *w_buff, SRSLTE_API void srslte_rm_turbo_gentables(); +SRSLTE_API void srslte_rm_turbo_free_tables(); + SRSLTE_API int srslte_rm_turbo_tx_lut(uint8_t *w_buff, uint8_t *systematic, uint8_t *parity, diff --git a/lib/include/srslte/phy/mimo/precoding.h b/lib/include/srslte/phy/mimo/precoding.h index 58fe22a40..f8463d1cb 100644 --- a/lib/include/srslte/phy/mimo/precoding.h +++ b/lib/include/srslte/phy/mimo/precoding.h @@ -49,18 +49,21 @@ */ SRSLTE_API int srslte_precoding_single(cf_t *x, cf_t *y, - int nof_symbols); + int nof_symbols, + float scaling); SRSLTE_API int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_ports, - int nof_symbols); + int nof_symbols, + float scaling); SRSLTE_API int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, - int nof_symbols); + int nof_symbols, + float scaling); SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], @@ -68,6 +71,7 @@ SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], int nof_ports, int codebook_idx, int nof_symbols, + float scaling, srslte_mimo_type_t type); /* Estimates the vector "x" based on the received signal "y" and the channel estimates "h" @@ -76,6 +80,7 @@ SRSLTE_API int srslte_predecoding_single(cf_t *y, cf_t *h, cf_t *x, int nof_symbols, + float scaling, float noise_estimate); SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], @@ -83,42 +88,37 @@ SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, + float scaling, float noise_estimate); SRSLTE_API int srslte_predecoding_diversity(cf_t *y, cf_t *h[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_ports, - int nof_symbols); + int nof_symbols, + float scaling); SRSLTE_API int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_ports, - int nof_symbols); - -SRSLTE_API int srslte_predecoding_type(cf_t *y, - cf_t *h[SRSLTE_MAX_PORTS], - cf_t *x[SRSLTE_MAX_LAYERS], - int nof_ports, - int nof_layers, - int nof_symbols, - srslte_mimo_type_t type, - float noise_estimate); + int nof_symbols, + float scaling); SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder); -SRSLTE_API int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], - cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - cf_t *x[SRSLTE_MAX_LAYERS], - int nof_rxant, - int nof_ports, - int nof_layers, - int codebook_idx, - int nof_symbols, - srslte_mimo_type_t type, - float noise_estimate); +SRSLTE_API int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], + cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], + int nof_rxant, + int nof_ports, + int nof_layers, + int codebook_idx, + int nof_symbols, + srslte_mimo_type_t type, + float scaling, + float noise_estimate); SRSLTE_API int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, diff --git a/lib/include/srslte/phy/phch/cqi.h b/lib/include/srslte/phy/phch/cqi.h index cfc9e92e7..0d0c17fec 100644 --- a/lib/include/srslte/phy/phch/cqi.h +++ b/lib/include/srslte/phy/phch/cqi.h @@ -55,13 +55,22 @@ typedef struct { } srslte_cqi_periodic_cfg_t; /* Table 5.2.2.6.2-1: Fields for channel quality information feedback for higher layer configured subband -CQI reports -(transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and -transmission mode 8 configured without PMI/RI reporting). */ + CQI reports (transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and + transmission mode 8 configured without PMI/RI reporting). */ + +/* Table 5.2.2.6.2-2: Fields for channel quality information (CQI) feedback for higher layer configured subband CQI + reports (transmission mode 4, transmission mode 5 and transmission mode 6). */ + typedef struct SRSLTE_API { - uint8_t wideband_cqi; // 4-bit width - uint32_t subband_diff_cqi; // 2N-bit width - uint32_t N; + uint8_t wideband_cqi_cw0; // 4-bit width + uint32_t subband_diff_cqi_cw0; // 2N-bit width + uint8_t wideband_cqi_cw1; // if RI > 1 then 4-bit width otherwise 0-bit width + uint32_t subband_diff_cqi_cw1; // if RI > 1 then 2N-bit width otherwise 0-bit width + uint32_t pmi; // if RI > 1 then 2-bit width otherwise 1-bit width + uint32_t N; + bool pmi_present; + bool four_antenna_ports; // If cell has 4 antenna ports then true otherwise false + bool rank_is_not_one; // If rank > 1 then true otherwise false } srslte_cqi_hl_subband_t; /* Table 5.2.2.6.3-1: Fields for channel quality information feedback for UE selected subband CQI diff --git a/lib/include/srslte/phy/phch/dci.h b/lib/include/srslte/phy/phch/dci.h index 6976a6b24..79a79c4df 100644 --- a/lib/include/srslte/phy/phch/dci.h +++ b/lib/include/srslte/phy/phch/dci.h @@ -137,7 +137,9 @@ SRSLTE_API srslte_dci_format_t srslte_dci_format_from_string(char *str); SRSLTE_API char* srslte_dci_format_string(srslte_dci_format_t format); -SRSLTE_API int srslte_dci_location_set(srslte_dci_location_t *c, +SRSLTE_API char* srslte_dci_format_string_short(srslte_dci_format_t format); + +SRSLTE_API int srslte_dci_location_set(srslte_dci_location_t *c, uint32_t L, uint32_t nCCE); @@ -178,6 +180,15 @@ SRSLTE_API uint32_t srslte_dci_format_sizeof(srslte_dci_format_t format, uint32_t nof_prb, uint32_t nof_ports); +SRSLTE_API uint32_t srslte_dci_dl_info(char *info_str, + uint32_t str_len, + srslte_ra_dl_dci_t *dci_msg, + srslte_dci_format_t format); + +SRSLTE_API uint32_t srslte_dci_ul_info(char *info_str, + uint32_t len, + srslte_ra_ul_dci_t *dci_msg); + // This is for backwards compatibility only for tm1 formats SRSLTE_API uint32_t srslte_dci_format_sizeof_lut(srslte_dci_format_t format, uint32_t nof_prb); diff --git a/lib/include/srslte/phy/phch/pdcch.h b/lib/include/srslte/phy/phch/pdcch.h index 9bb896b34..0e0e63335 100644 --- a/lib/include/srslte/phy/phch/pdcch.h +++ b/lib/include/srslte/phy/phch/pdcch.h @@ -167,7 +167,15 @@ SRSLTE_API uint32_t srslte_pdcch_ue_locations(srslte_pdcch_t *q, SRSLTE_API uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, srslte_dci_location_t *c, uint32_t max_candidates, - uint32_t nsubframe, uint16_t rnti); + uint32_t nsubframe, + uint16_t rnti); + +SRSLTE_API uint32_t srslte_pdcch_ue_locations_ncce_L(uint32_t nof_cce, + srslte_dci_location_t *c, + uint32_t max_candidates, + uint32_t nsubframe, + uint16_t rnti, + int L); /* Function for generation of common search space DCI locations */ SRSLTE_API uint32_t srslte_pdcch_common_locations(srslte_pdcch_t *q, diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index 459bcc209..dab900d77 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -65,6 +65,9 @@ typedef struct SRSLTE_API { uint16_t ue_rnti; bool is_ue; + /* Power allocation parameter 3GPP 36.213 Clause 5.2 Rho_b */ + float rho_a; + /* buffers */ // void buffers are shared for tx and rx cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */ @@ -101,6 +104,9 @@ SRSLTE_API int srslte_pdsch_set_cell(srslte_pdsch_t *q, SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti); +SRSLTE_API void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q, + float rho_a); + SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t *q, uint16_t rnti); diff --git a/lib/include/srslte/phy/phch/pdsch_cfg.h b/lib/include/srslte/phy/phch/pdsch_cfg.h index eb4927fbb..569d1ef7e 100644 --- a/lib/include/srslte/phy/phch/pdsch_cfg.h +++ b/lib/include/srslte/phy/phch/pdsch_cfg.h @@ -39,6 +39,13 @@ #include "srslte/phy/fec/softbuffer.h" #include "srslte/phy/fec/cbsegm.h" +/* 3GPP 36.213 Table 5.2-1: The cell-specific ratio rho_B / rho_A for 1, 2, or 4 cell specific antenna ports */ +static const float pdsch_cfg_cell_specific_ratio_table[2][4] = + { /* One antenna port */ {1.0f / 1.0f, 4.0f / 5.0f, 3.0f / 5.0f, 2.0f / 5.0f}, + /* Two or more antenna port */ {5.0f / 4.0f, 1.0f / 1.0f, 3.0f / 4.0f, 1.0f / 2.0f} + }; + + typedef struct SRSLTE_API { srslte_cbsegm_t cb_segm[SRSLTE_MAX_CODEWORDS]; srslte_ra_dl_grant_t grant; @@ -48,6 +55,7 @@ typedef struct SRSLTE_API { uint32_t nof_layers; uint32_t codebook_idx; srslte_mimo_type_t mimo_type; + bool tb_cw_swap; } srslte_pdsch_cfg_t; #endif diff --git a/lib/include/srslte/phy/phch/pucch.h b/lib/include/srslte/phy/phch/pucch.h index 8aa1495c8..29785c09a 100644 --- a/lib/include/srslte/phy/phch/pucch.h +++ b/lib/include/srslte/phy/phch/pucch.h @@ -157,7 +157,8 @@ SRSLTE_API int srslte_pucch_decode(srslte_pucch_t *q, cf_t *sf_symbols, cf_t *ce, float noise_estimate, - uint8_t bits[SRSLTE_PUCCH_MAX_BITS]); + uint8_t bits[SRSLTE_PUCCH_MAX_BITS], + uint32_t nof_bits); SRSLTE_API float srslte_pucch_alpha_format1(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], srslte_pucch_cfg_t *cfg, diff --git a/lib/include/srslte/phy/phch/pusch.h b/lib/include/srslte/phy/phch/pusch.h index 2328c8ff3..01db068a5 100644 --- a/lib/include/srslte/phy/phch/pusch.h +++ b/lib/include/srslte/phy/phch/pusch.h @@ -142,6 +142,7 @@ SRSLTE_API int srslte_pusch_decode(srslte_pusch_t *q, float noise_estimate, uint16_t rnti, uint8_t *data, + srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data); SRSLTE_API float srslte_pusch_average_noi(srslte_pusch_t *q); diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index 3039455ed..f4274e416 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -103,13 +103,11 @@ typedef struct SRSLTE_API { bool prb_idx[2][SRSLTE_MAX_PRB]; uint32_t nof_prb; uint32_t Qm[SRSLTE_MAX_CODEWORDS]; - uint32_t Qm2[SRSLTE_MAX_CODEWORDS]; srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS]; - srslte_ra_mcs_t mcs2[SRSLTE_MAX_CODEWORDS]; - uint32_t nof_tb; srslte_sf_t sf_type; bool tb_en[SRSLTE_MAX_CODEWORDS]; uint32_t pinfo; + bool tb_cw_swap; } srslte_ra_dl_grant_t; #define SRSLTE_RA_DL_GRANT_NOF_TB(G) ((((G)->tb_en[0])?1:0)+(((G)->tb_en[1])?1:0)) @@ -226,8 +224,7 @@ SRSLTE_API uint32_t srslte_ra_dl_grant_nof_re(srslte_ra_dl_grant_t *grant, SRSLTE_API int srslte_ra_ul_dci_to_grant(srslte_ra_ul_dci_t *dci, uint32_t nof_prb, uint32_t n_rb_ho, - srslte_ra_ul_grant_t *grant, - uint32_t harq_pid); + srslte_ra_ul_grant_t *grant); SRSLTE_API void srslte_ra_ul_grant_to_nbits(srslte_ra_ul_grant_t *grant, srslte_cp_t cp, diff --git a/lib/include/srslte/phy/phch/uci.h b/lib/include/srslte/phy/phch/uci.h index ff315384e..6ea00c5d1 100644 --- a/lib/include/srslte/phy/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -57,8 +57,8 @@ typedef struct SRSLTE_API { } srslte_uci_cqi_pusch_t; typedef struct SRSLTE_API { - uint8_t *cqi_table[16]; - int16_t *cqi_table_s[16]; + uint8_t **cqi_table; + int16_t **cqi_table_s; } srslte_uci_cqi_pucch_t; typedef struct SRSLTE_API { @@ -73,6 +73,7 @@ typedef struct SRSLTE_API { uint8_t uci_ack; // 1st codeword bit for HARQ-ACK uint8_t uci_ack_2; // 2st codeword bit for HARQ-ACK uint32_t uci_ack_len; + bool ri_periodic_report; bool scheduling_request; bool channel_selection; bool cqi_ack; @@ -95,6 +96,11 @@ SRSLTE_API int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]); +SRSLTE_API int srslte_uci_encode_cqi_pucch_from_table(srslte_uci_cqi_pucch_t *q, + uint8_t *cqi_data, + uint32_t cqi_len, + uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]); + SRSLTE_API int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32], // aligned for simd uint8_t *cqi_data, @@ -130,31 +136,25 @@ SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint32_t H_prime_total, srslte_uci_bit_t *ri_bits); -SRSLTE_API int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, - int16_t *q_bits, - uint8_t *c_seq, - float beta, - uint32_t H_prime_total, - uint32_t O_cqi, - srslte_uci_bit_t *ack_bits, - uint8_t acks[2], - uint32_t nof_acks); - -SRSLTE_API int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg, - uint8_t data, +SRSLTE_API int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg, + uint8_t *data, + uint32_t data_len, uint32_t O_cqi, float beta, uint32_t H_prime_total, - srslte_uci_bit_t *ri_bits); - -SRSLTE_API int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, - int16_t *q_bits, - uint8_t *c_seq, - float beta, - uint32_t H_prime_total, - uint32_t O_cqi, srslte_uci_bit_t *ri_bits, - uint8_t *data); + bool is_ri); + +SRSLTE_API int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t *cfg, + int16_t *q_bits, + uint8_t *c_seq, + float beta, + uint32_t H_prime_total, + uint32_t O_cqi, + srslte_uci_bit_t *ack_ri_bits, + uint8_t data[2], + uint32_t nof_bits, + bool is_ri); #endif diff --git a/lib/include/srslte/phy/resampling/resample_arb.h b/lib/include/srslte/phy/resampling/resample_arb.h index 98d004b0b..4ebb8dc08 100644 --- a/lib/include/srslte/phy/resampling/resample_arb.h +++ b/lib/include/srslte/phy/resampling/resample_arb.h @@ -38,10 +38,13 @@ #define RESAMPLE_ARB_ #include +#include #include #include "srslte/config.h" + +#define SRSLTE_RESAMPLE_ARB_N_35 35 #define SRSLTE_RESAMPLE_ARB_N 32 // Polyphase filter rows #define SRSLTE_RESAMPLE_ARB_M 8 // Polyphase filter columns @@ -49,11 +52,13 @@ typedef struct SRSLTE_API { float rate; // Resample rate float step; // Step increment through filter float acc; // Index into filter + bool interpolate; cf_t reg[SRSLTE_RESAMPLE_ARB_M]; // Our window of samples + } srslte_resample_arb_t; SRSLTE_API void srslte_resample_arb_init(srslte_resample_arb_t *q, - float rate); + float rate, bool interpolate); SRSLTE_API int srslte_resample_arb_compute(srslte_resample_arb_t *q, cf_t *input, diff --git a/lib/include/srslte/phy/rf/rf.h b/lib/include/srslte/phy/rf/rf.h index 860e0a257..44bde9943 100644 --- a/lib/include/srslte/phy/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -73,16 +73,12 @@ SRSLTE_API int srslte_rf_open(srslte_rf_t *h, SRSLTE_API int srslte_rf_open_multi(srslte_rf_t *h, char *args, - uint32_t nof_rx_antennas); + uint32_t nof_channels); SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h, char *devname, - char *args); - -SRSLTE_API int srslte_rf_open_devname_multi(srslte_rf_t *h, - char *devname, - char *args, - uint32_t nof_rx_antennas); + char *args, + uint32_t nof_channels); SRSLTE_API const char *srslte_rf_name(srslte_rf_t *h); @@ -95,7 +91,7 @@ SRSLTE_API void srslte_rf_set_tx_cal(srslte_rf_t *h, srslte_rf_cal_t *cal); SRSLTE_API void srslte_rf_set_rx_cal(srslte_rf_t *h, srslte_rf_cal_t *cal); -SRSLTE_API int srslte_rf_start_rx_stream(srslte_rf_t *h); +SRSLTE_API int srslte_rf_start_rx_stream(srslte_rf_t *h, bool now); SRSLTE_API int srslte_rf_stop_rx_stream(srslte_rf_t *h); diff --git a/lib/include/srslte/phy/sync/cfo.h b/lib/include/srslte/phy/sync/cfo.h index fd2ab4d83..506732b74 100644 --- a/lib/include/srslte/phy/sync/cfo.h +++ b/lib/include/srslte/phy/sync/cfo.h @@ -40,9 +40,6 @@ #include "srslte/config.h" #include "srslte/phy/utils/cexptab.h" -/** If the frequency is changed more than the tolerance, a new table is generated */ -#define SRSLTE_CFO_TOLERANCE 0.00001 - #define SRSLTE_CFO_CEXPTAB_SIZE 4096 typedef struct SRSLTE_API { @@ -66,7 +63,7 @@ SRSLTE_API void srslte_cfo_set_tol(srslte_cfo_t *h, float tol); SRSLTE_API void srslte_cfo_correct(srslte_cfo_t *h, - cf_t *input, + const cf_t *input, cf_t *output, float freq); diff --git a/lib/include/srslte/phy/sync/cp.h b/lib/include/srslte/phy/sync/cp.h index 9daf7d4f6..d9da03722 100644 --- a/lib/include/srslte/phy/sync/cp.h +++ b/lib/include/srslte/phy/sync/cp.h @@ -47,7 +47,7 @@ SRSLTE_API int srslte_cp_synch_resize(srslte_cp_synch_t *q, uint32_t symbol_sz); SRSLTE_API uint32_t srslte_cp_synch(srslte_cp_synch_t *q, - cf_t *input, + const cf_t *input, uint32_t max_offset, uint32_t nof_symbols, uint32_t cp_len); diff --git a/lib/include/srslte/phy/sync/pss.h b/lib/include/srslte/phy/sync/pss.h index 9760a178c..922bc0286 100644 --- a/lib/include/srslte/phy/sync/pss.h +++ b/lib/include/srslte/phy/sync/pss.h @@ -29,9 +29,9 @@ * * Description: Primary synchronization signal (PSS) generation and detection. * - * The srslte_pss_synch_t object provides functions for fast + * The srslte_pss_t object provides functions for fast * computation of the crosscorrelation between the PSS and received - * signal and CFO estimation. Also, the function srslte_pss_synch_tperiodic() + * signal and CFO estimation. Also, the function srslte_pss_tperiodic() * is designed to be called periodically every subframe, taking * care of the correct data alignment with respect to the PSS sequence. * @@ -61,18 +61,14 @@ /* PSS processing options */ -#define SRSLTE_PSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to srslte_pss_synch_find_pss - -#define SRSLTE_PSS_ABS_SQUARE // If enabled, compute abs square, otherwise computes absolute value only +#define SRSLTE_PSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to srslte_pss_find_pss #define SRSLTE_PSS_RETURN_PSR // If enabled returns peak to side-lobe ratio, otherwise returns absolute peak value /* Low-level API */ typedef struct SRSLTE_API { - - srslte_dft_plan_t dftp_input; - + #ifdef CONVOLUTION_FFT srslte_conv_fft_cc_t conv_fft; srslte_filt_cc_t filter; @@ -87,46 +83,68 @@ typedef struct SRSLTE_API { uint32_t N_id_2; uint32_t fft_size; cf_t *pss_signal_freq_full[3]; - + cf_t *pss_signal_time[3]; - + cf_t *pss_signal_time_scale[3]; + cf_t pss_signal_freq[3][SRSLTE_PSS_LEN]; // One sequence for each N_id_2 cf_t *tmp_input; cf_t *conv_output; float *conv_output_abs; - float ema_alpha; + float ema_alpha; float *conv_output_avg; float peak_value; -}srslte_pss_synch_t; + + bool filter_pss_enable; + srslte_dft_plan_t dftp_input; + srslte_dft_plan_t idftp_input; + cf_t tmp_fft[SRSLTE_SYMBOL_SZ_MAX]; + cf_t tmp_fft2[SRSLTE_SYMBOL_SZ_MAX]; + + cf_t tmp_ce[SRSLTE_PSS_LEN]; + + bool chest_on_filter; + +}srslte_pss_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t; /* Basic functionality */ -SRSLTE_API int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_init_fft(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size); -SRSLTE_API int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_init_fft_offset(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int cfo_i); -SRSLTE_API int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_init_fft_offset_decim(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int cfo_i, int decimate); -SRSLTE_API int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, +SRSLTE_API int srslte_pss_resize(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int offset); -SRSLTE_API int srslte_pss_synch_init(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_init(srslte_pss_t *q, uint32_t frame_size); -SRSLTE_API void srslte_pss_synch_free(srslte_pss_synch_t *q); +SRSLTE_API void srslte_pss_free(srslte_pss_t *q); -SRSLTE_API void srslte_pss_synch_reset(srslte_pss_synch_t *q); +SRSLTE_API void srslte_pss_reset(srslte_pss_t *q); + +SRSLTE_API void srslte_pss_filter_enable(srslte_pss_t *q, + bool enable); + +SRSLTE_API void srslte_pss_sic(srslte_pss_t *q, + cf_t *input); + +SRSLTE_API void srslte_pss_filter(srslte_pss_t *q, + const cf_t *input, + cf_t *output); SRSLTE_API int srslte_pss_generate(cf_t *signal, uint32_t N_id_2); @@ -141,21 +159,21 @@ SRSLTE_API void srslte_pss_put_slot(cf_t *pss_signal, uint32_t nof_prb, srslte_cp_t cp); -SRSLTE_API void srslte_pss_synch_set_ema_alpha(srslte_pss_synch_t *q, +SRSLTE_API void srslte_pss_set_ema_alpha(srslte_pss_t *q, float alpha); -SRSLTE_API int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, +SRSLTE_API int srslte_pss_set_N_id_2(srslte_pss_t *q, uint32_t N_id_2); -SRSLTE_API int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, - cf_t *input, +SRSLTE_API int srslte_pss_find_pss(srslte_pss_t *q, + const cf_t *input, float *corr_peak_value); -SRSLTE_API int srslte_pss_synch_chest(srslte_pss_synch_t *q, - cf_t *input, +SRSLTE_API int srslte_pss_chest(srslte_pss_t *q, + const cf_t *input, cf_t ce[SRSLTE_PSS_LEN]); -SRSLTE_API float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, - cf_t *pss_recv); +SRSLTE_API float srslte_pss_cfo_compute(srslte_pss_t* q, + const cf_t *pss_recv); #endif // PSS_ diff --git a/lib/include/srslte/phy/sync/sss.h b/lib/include/srslte/phy/sync/sss.h index 35eedac8f..9f77d1ce6 100644 --- a/lib/include/srslte/phy/sync/sss.h +++ b/lib/include/srslte/phy/sync/sss.h @@ -83,17 +83,17 @@ typedef struct SRSLTE_API { float corr_output_m0[SRSLTE_SSS_N]; float corr_output_m1[SRSLTE_SSS_N]; -}srslte_sss_synch_t; +}srslte_sss_t; /* Basic functionality */ -SRSLTE_API int srslte_sss_synch_init(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_init(srslte_sss_t *q, uint32_t fft_size); -SRSLTE_API int srslte_sss_synch_resize(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_resize(srslte_sss_t *q, uint32_t fft_size); -SRSLTE_API void srslte_sss_synch_free(srslte_sss_synch_t *q); +SRSLTE_API void srslte_sss_free(srslte_sss_t *q); SRSLTE_API void srslte_sss_generate(float *signal0, float *signal5, @@ -104,11 +104,11 @@ SRSLTE_API void srslte_sss_put_slot(float *sss, uint32_t nof_prb, srslte_cp_t cp); -SRSLTE_API int srslte_sss_synch_set_N_id_2(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_set_N_id_2(srslte_sss_t *q, uint32_t N_id_2); -SRSLTE_API int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, - cf_t *input, +SRSLTE_API int srslte_sss_m0m1_partial(srslte_sss_t *q, + const cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, @@ -116,41 +116,41 @@ SRSLTE_API int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, uint32_t *m1, float *m1_value); -SRSLTE_API int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, - cf_t *input, +SRSLTE_API int srslte_sss_m0m1_diff_coh(srslte_sss_t *q, + const cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value); -SRSLTE_API int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, - cf_t *input, +SRSLTE_API int srslte_sss_m0m1_diff(srslte_sss_t *q, + const cf_t *input, uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value); -SRSLTE_API uint32_t srslte_sss_synch_subframe(uint32_t m0, +SRSLTE_API uint32_t srslte_sss_subframe(uint32_t m0, uint32_t m1); -SRSLTE_API int srslte_sss_synch_N_id_1(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_N_id_1(srslte_sss_t *q, uint32_t m0, uint32_t m1); -SRSLTE_API int srslte_sss_synch_frame(srslte_sss_synch_t *q, +SRSLTE_API int srslte_sss_frame(srslte_sss_t *q, cf_t *input, uint32_t *subframe_idx, uint32_t *N_id_1); -SRSLTE_API void srslte_sss_synch_set_threshold(srslte_sss_synch_t *q, +SRSLTE_API void srslte_sss_set_threshold(srslte_sss_t *q, float threshold); -SRSLTE_API void srslte_sss_synch_set_symbol_sz(srslte_sss_synch_t *q, +SRSLTE_API void srslte_sss_set_symbol_sz(srslte_sss_t *q, uint32_t symbol_sz); -SRSLTE_API void srslte_sss_synch_set_subframe_sz(srslte_sss_synch_t *q, +SRSLTE_API void srslte_sss_set_subframe_sz(srslte_sss_t *q, uint32_t subframe_sz); #endif // SSS_ diff --git a/lib/include/srslte/phy/sync/sync.h b/lib/include/srslte/phy/sync/sync.h index 1c70b2449..232bc5fc4 100644 --- a/lib/include/srslte/phy/sync/sync.h +++ b/lib/include/srslte/phy/sync/sync.h @@ -60,9 +60,9 @@ typedef enum {SSS_DIFF=0, SSS_PARTIAL_3=2, SSS_FULL=1} sss_alg_t; typedef struct SRSLTE_API { - srslte_pss_synch_t pss; - srslte_pss_synch_t pss_i[2]; - srslte_sss_synch_t sss; + srslte_pss_t pss; + srslte_pss_t pss_i[2]; + srslte_sss_t sss; srslte_cp_synch_t cp_synch; cf_t *cfo_i_corr[2]; int decimate; @@ -74,19 +74,8 @@ typedef struct SRSLTE_API { uint32_t fft_size; uint32_t frame_size; uint32_t max_offset; - bool enable_cfo_corr; - bool mean_cfo2_isunset; - bool mean_cfo_isunset; - float mean_cfo; - float mean_cfo2; - int cfo_i; - bool find_cfo_i; - bool find_cfo_i_initiated; - float cfo_ema_alpha; uint32_t nof_symbols; uint32_t cp_len; - srslte_cfo_t cfocorr; - srslte_cfo_t cfocorr2; float current_cfo_tol; sss_alg_t sss_alg; bool detect_cp; @@ -102,6 +91,33 @@ typedef struct SRSLTE_API { uint32_t max_frame_size; + + // variables for various CFO estimation methods + bool cfo_cp_enable; + bool cfo_pss_enable; + bool cfo_i_enable; + + bool cfo_cp_is_set; + bool cfo_pss_is_set; + bool cfo_i_initiated; + + float cfo_cp_mean; + float cfo_pss; + float cfo_pss_mean; + int cfo_i_value; + + float cfo_ema_alpha; + + uint32_t cfo_cp_nsymbols; + + srslte_cfo_t cfo_corr_frame; + srslte_cfo_t cfo_corr_symbol; + + bool sss_channel_equalize; + bool pss_filtering_enabled; + cf_t sss_filt[SRSLTE_SYMBOL_SZ_MAX]; + cf_t pss_filt[SRSLTE_SYMBOL_SZ_MAX]; + }srslte_sync_t; typedef enum { @@ -135,29 +151,23 @@ SRSLTE_API void srslte_sync_reset(srslte_sync_t *q); /* Finds a correlation peak in the input signal around position find_offset */ SRSLTE_API srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, - cf_t *input, + const cf_t *input, uint32_t find_offset, uint32_t *peak_position); /* Estimates the CP length */ SRSLTE_API srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, - cf_t *input, + const cf_t *input, uint32_t peak_pos); /* Sets the threshold for peak comparison */ SRSLTE_API void srslte_sync_set_threshold(srslte_sync_t *q, float threshold); -SRSLTE_API void srslte_sync_set_cfo_tol(srslte_sync_t *q, - float tol); - /* Gets the subframe idx (0 or 5) */ SRSLTE_API uint32_t srslte_sync_get_sf_idx(srslte_sync_t *q); -/* Gets the last peak value */ -SRSLTE_API float srslte_sync_get_last_peak_value(srslte_sync_t *q); - -/* Gets the mean peak value */ +/* Gets the peak value */ SRSLTE_API float srslte_sync_get_peak_value(srslte_sync_t *q); /* Choose SSS detection algorithm */ @@ -175,23 +185,42 @@ SRSLTE_API int srslte_sync_set_N_id_2(srslte_sync_t *q, /* Gets the Physical CellId from the last call to synch_run() */ SRSLTE_API int srslte_sync_get_cell_id(srslte_sync_t *q); +/* Enables/disables filtering of the central PRBs before PSS CFO estimation or SSS correlation*/ +SRSLTE_API void srslte_sync_set_pss_filt_enable(srslte_sync_t *q, + bool enable); + +SRSLTE_API void srslte_sync_set_sss_eq_enable(srslte_sync_t *q, + bool enable); + /* Gets the CFO estimation from the last call to synch_run() */ SRSLTE_API float srslte_sync_get_cfo(srslte_sync_t *q); -/* Sets known CFO to avoid long transients due to average */ -SRSLTE_API void srslte_sync_set_cfo(srslte_sync_t *q, float cfo); +/* Resets internal CFO state */ +SRSLTE_API void srslte_sync_cfo_reset(srslte_sync_t *q); -/* Set integer CFO */ -SRSLTE_API void srslte_sync_set_cfo_i(srslte_sync_t *q, - int cfo_i); +/* Copies CFO internal state from another object to avoid long transients */ +SRSLTE_API void srslte_sync_copy_cfo(srslte_sync_t *q, + srslte_sync_t *src_obj); -SRSLTE_API void srslte_sync_set_cfo_enable(srslte_sync_t *q, - bool enable); +/* Enable different CFO estimation stages */ +SRSLTE_API void srslte_sync_set_cfo_i_enable(srslte_sync_t *q, + bool enable); +SRSLTE_API void srslte_sync_set_cfo_cp_enable(srslte_sync_t *q, + bool enable, + uint32_t nof_symbols); + +SRSLTE_API void srslte_sync_set_cfo_pss_enable(srslte_sync_t *q, + bool enable); + +/* Sets CFO correctors tolerance (in Hz) */ +SRSLTE_API void srslte_sync_set_cfo_tol(srslte_sync_t *q, + float tol); /* Sets the exponential moving average coefficient for CFO averaging */ SRSLTE_API void srslte_sync_set_cfo_ema_alpha(srslte_sync_t *q, float alpha); + /* Gets the CP length estimation from the last call to synch_run() */ SRSLTE_API srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q); @@ -199,20 +228,14 @@ SRSLTE_API srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q); SRSLTE_API void srslte_sync_set_cp(srslte_sync_t *q, srslte_cp_t cp); -/* Enable integer CFO detection */ -SRSLTE_API void srslte_sync_cfo_i_detec_en(srslte_sync_t *q, - bool enabled); - /* Enables/Disables SSS detection */ SRSLTE_API void srslte_sync_sss_en(srslte_sync_t *q, bool enabled); -SRSLTE_API srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q); +SRSLTE_API srslte_pss_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q); SRSLTE_API bool srslte_sync_sss_detected(srslte_sync_t *q); -SRSLTE_API bool srslte_sync_sss_is_en(srslte_sync_t *q); - /* Enables/Disables CP detection */ SRSLTE_API void srslte_sync_cp_en(srslte_sync_t *q, bool enabled); diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 0b0fc44d2..6974a0b99 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -80,7 +80,7 @@ typedef struct SRSLTE_API { srslte_pmch_t pmch; srslte_phich_t phich; srslte_regs_t regs; - srslte_ofdm_t fft; + srslte_ofdm_t fft[SRSLTE_MAX_PORTS]; srslte_ofdm_t fft_mbsfn; srslte_chest_dl_t chest; @@ -104,6 +104,9 @@ typedef struct SRSLTE_API { uint32_t pmi[SRSLTE_MAX_LAYERS]; uint32_t ri; + /* Power allocation parameter 3GPP 36.213 Clause 5.2 Rho_b */ + float rho_b; + srslte_dci_format_t dci_format; uint64_t pkt_errors; uint64_t pkts_total; @@ -123,11 +126,14 @@ typedef struct SRSLTE_API { srslte_dci_msg_t pending_ul_dci_msg; uint16_t pending_ul_dci_rnti; - float sample_offset; + float sample_offset; + + float last_phich_corr; }srslte_ue_dl_t; /* This function shall be called just after the initial synchronization */ SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q, + cf_t *input[SRSLTE_MAX_PORTS], uint32_t max_prb, uint32_t nof_rx_antennas); @@ -137,20 +143,22 @@ SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell); int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], - uint32_t sf_idx, + uint32_t sf_idx, uint32_t *cfi); SRSLTE_API int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], - uint32_t sf_idx, + uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type); +SRSLTE_API int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q, + cf_t *input[SRSLTE_MAX_PORTS], + uint32_t sf_idx, + uint32_t *cfi); -int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, - uint32_t sf_idx, - uint32_t *cfi); +SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, + uint32_t sf_idx, + uint32_t *cfi); SRSLTE_API int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, @@ -191,14 +199,12 @@ SRSLTE_API void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset); SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]); SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, @@ -212,7 +218,6 @@ SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, * srslte_pmch_decode_multi */ SRSLTE_API int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, - cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti); @@ -243,6 +248,9 @@ SRSLTE_API int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t *q, SRSLTE_API void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q, uint8_t non_mbsfn_region_length); +SRSLTE_API void srslte_ue_dl_set_power_alloc(srslte_ue_dl_t *q, + float rho_a, + float rho_b); SRSLTE_API void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, diff --git a/lib/include/srslte/phy/ue/ue_mib.h b/lib/include/srslte/phy/ue/ue_mib.h index 5d2ef14fa..ee52b31d4 100644 --- a/lib/include/srslte/phy/ue/ue_mib.h +++ b/lib/include/srslte/phy/ue/ue_mib.h @@ -79,6 +79,7 @@ typedef struct SRSLTE_API { } srslte_ue_mib_t; SRSLTE_API int srslte_ue_mib_init(srslte_ue_mib_t *q, + cf_t *in_buffer[SRSLTE_MAX_PORTS], uint32_t max_prb); SRSLTE_API void srslte_ue_mib_free(srslte_ue_mib_t *q); @@ -89,7 +90,6 @@ SRSLTE_API int srslte_ue_mib_set_cell(srslte_ue_mib_t * q, SRSLTE_API void srslte_ue_mib_reset(srslte_ue_mib_t * q); SRSLTE_API int srslte_ue_mib_decode(srslte_ue_mib_t * q, - cf_t *input, uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, int *sfn_offset); diff --git a/lib/include/srslte/phy/ue/ue_sync.h b/lib/include/srslte/phy/ue/ue_sync.h index bd280acd0..233b87b11 100644 --- a/lib/include/srslte/phy/ue/ue_sync.h +++ b/lib/include/srslte/phy/ue/ue_sync.h @@ -62,6 +62,16 @@ #include "srslte/phy/io/filesource.h" +#define DEFAULT_CFO_BW_PSS 0.05 +#define DEFAULT_CFO_PSS_MIN 400 // typical bias of PSS estimation. +#define DEFAULT_CFO_BW_REF 0.08 +#define DEFAULT_CFO_REF_MIN 0 // typical bias of REF estimation +#define DEFAULT_CFO_REF_MAX DEFAULT_CFO_PSS_MIN // Maximum detection offset of REF based estimation + +#define DEFAULT_PSS_STABLE_TIMEOUT 20 // Time after which the PSS is considered to be stable and we accept REF-CFO + +#define DEFAULT_CFO_EMA_TRACK 0.05 + typedef enum SRSLTE_API { SF_FIND, SF_TRACK} srslte_ue_sync_state_t; //#define MEASURE_EXEC_TIME @@ -110,8 +120,21 @@ typedef struct SRSLTE_API { uint32_t sf_idx; bool decode_sss_on_track; - bool correct_cfo; - + + bool cfo_is_copied; + bool cfo_correct_enable_track; + bool cfo_correct_enable_find; + float cfo_current_value; + float cfo_loop_bw_pss; + float cfo_loop_bw_ref; + float cfo_pss_min; + float cfo_ref_min; + float cfo_ref_max; + + uint32_t pss_stable_cnt; + uint32_t pss_stable_timeout; + bool pss_is_stable; + uint32_t peak_idx; int next_rf_sample_offset; int last_sample_offset; @@ -165,6 +188,10 @@ SRSLTE_API void srslte_ue_sync_free(srslte_ue_sync_t *q); SRSLTE_API int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell); +SRSLTE_API void srslte_ue_sync_cfo_reset(srslte_ue_sync_t *q); + +SRSLTE_API void srslte_ue_sync_reset(srslte_ue_sync_t *q); + SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, double (set_gain_callback)(void*, double), float init_gain_value); @@ -175,31 +202,40 @@ SRSLTE_API void srslte_ue_sync_set_agc_period(srslte_ue_sync_t *q, uint32_t period); /* CAUTION: input_buffer MUST have space for 2 subframes */ -SRSLTE_API int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, +SRSLTE_API int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer); -SRSLTE_API int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, +SRSLTE_API int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]); SRSLTE_API void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t *q, float tol); -SRSLTE_API void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q, - float cfo); +SRSLTE_API void srslte_ue_sync_copy_cfo(srslte_ue_sync_t *q, + srslte_ue_sync_t *src_obj); -SRSLTE_API void srslte_ue_sync_cfo_i_detec_en(srslte_ue_sync_t *q, - bool enable); +SRSLTE_API void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q, + float bw_pss, + float bw_ref, + float pss_tol, + float ref_tol, + float ref_max, + uint32_t pss_stable_timeout); -SRSLTE_API void srslte_ue_sync_reset(srslte_ue_sync_t *q); +SRSLTE_API void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, + float ema); -SRSLTE_API void srslte_ue_sync_set_N_id_2(srslte_ue_sync_t *q, +SRSLTE_API void srslte_ue_sync_set_cfo_ref(srslte_ue_sync_t *q, float res_cfo); + +SRSLTE_API void srslte_ue_sync_set_cfo_i_enable(srslte_ue_sync_t *q, + bool enable); + +SRSLTE_API void srslte_ue_sync_set_N_id_2(srslte_ue_sync_t *q, uint32_t N_id_2); SRSLTE_API void srslte_ue_sync_decode_sss_on_track(srslte_ue_sync_t *q, bool enabled); -SRSLTE_API srslte_ue_sync_state_t srslte_ue_sync_get_state(srslte_ue_sync_t *q); - SRSLTE_API uint32_t srslte_ue_sync_get_sfidx(srslte_ue_sync_t *q); SRSLTE_API float srslte_ue_sync_get_cfo(srslte_ue_sync_t *q); @@ -215,8 +251,5 @@ SRSLTE_API void srslte_ue_sync_get_last_timestamp(srslte_ue_sync_t *q, srslte_timestamp_t *timestamp); - - - #endif // SYNC_FRAME_ diff --git a/lib/include/srslte/phy/ue/ue_ul.h b/lib/include/srslte/phy/ue/ue_ul.h index 3492180e3..617833a61 100644 --- a/lib/include/srslte/phy/ue/ue_ul.h +++ b/lib/include/srslte/phy/ue/ue_ul.h @@ -108,6 +108,7 @@ typedef struct SRSLTE_API { /* This function shall be called just after the initial synchronization */ SRSLTE_API int srslte_ue_ul_init(srslte_ue_ul_t *q, + cf_t *out_buffer, uint32_t max_prb); SRSLTE_API void srslte_ue_ul_free(srslte_ue_ul_t *q); diff --git a/lib/include/srslte/phy/utils/bit.h b/lib/include/srslte/phy/utils/bit.h index c02ecd6bb..e4289b790 100644 --- a/lib/include/srslte/phy/utils/bit.h +++ b/lib/include/srslte/phy/utils/bit.h @@ -40,6 +40,25 @@ #include "srslte/config.h" +typedef struct { + uint32_t nof_bits; + uint16_t *interleaver; + uint16_t *byte_idx; + uint8_t *bit_mask; + uint8_t n_128; +} srslte_bit_interleaver_t; + +SRSLTE_API void srslte_bit_interleaver_init(srslte_bit_interleaver_t *q, + uint16_t *interleaver, + uint32_t nof_bits); + +SRSLTE_API void srslte_bit_interleaver_free(srslte_bit_interleaver_t *q); + +SRSLTE_API void srslte_bit_interleaver_run(srslte_bit_interleaver_t *q, + uint8_t *input, + uint8_t *output, + uint16_t w_offset); + SRSLTE_API void srslte_bit_interleave(uint8_t *input, uint8_t *output, uint16_t *interleaver, diff --git a/lib/include/srslte/phy/utils/convolution.h b/lib/include/srslte/phy/utils/convolution.h index fcb321ce5..a93dfb955 100644 --- a/lib/include/srslte/phy/utils/convolution.h +++ b/lib/include/srslte/phy/utils/convolution.h @@ -66,18 +66,18 @@ SRSLTE_API int srslte_conv_fft_cc_replan(srslte_conv_fft_cc_t *q, SRSLTE_API void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q); -SRSLTE_API uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, - cf_t *input, - cf_t *filter, +SRSLTE_API uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, + const cf_t *input, + const cf_t *filter, cf_t *output); -SRSLTE_API uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q, - cf_t *input, - cf_t *filter_freq, +SRSLTE_API uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q, + const cf_t *input, + const cf_t *filter_freq, cf_t *output); -SRSLTE_API uint32_t srslte_conv_cc(cf_t *input, - cf_t *filter, +SRSLTE_API uint32_t srslte_conv_cc(const cf_t *input, + const cf_t *filter, cf_t *output, uint32_t input_len, uint32_t filter_len); diff --git a/lib/include/srslte/phy/utils/debug.h b/lib/include/srslte/phy/utils/debug.h index c88e1a3ce..52290ca11 100644 --- a/lib/include/srslte/phy/utils/debug.h +++ b/lib/include/srslte/phy/utils/debug.h @@ -37,6 +37,7 @@ #include #include "srslte/config.h" +#include "srslte/phy/common/phy_logger.h" #define SRSLTE_VERBOSE_DEBUG 2 #define SRSLTE_VERBOSE_INFO 1 @@ -48,6 +49,7 @@ SRSLTE_API void get_time_interval(struct timeval * tdata); #define SRSLTE_DEBUG_ENABLED 1 SRSLTE_API extern int srslte_verbose; +SRSLTE_API extern int handler_registered; #define SRSLTE_VERBOSE_ISINFO() (srslte_verbose>=SRSLTE_VERBOSE_INFO) #define SRSLTE_VERBOSE_ISDEBUG() (srslte_verbose>=SRSLTE_VERBOSE_DEBUG) @@ -57,17 +59,25 @@ SRSLTE_API extern int srslte_verbose; #define PRINT_INFO srslte_verbose=SRSLTE_VERBOSE_INFO #define PRINT_NONE srslte_verbose=SRSLTE_VERBOSE_NONE -#define DEBUG(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG) \ - fprintf(stdout, "[DEBUG]: " _fmt, ##__VA_ARGS__) +#define DEBUG(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered)\ + { fprintf(stdout, "[DEBUG]: " _fmt, ##__VA_ARGS__); }\ + else{ srslte_phy_log_print(LOG_LEVEL_DEBUG, _fmt, ##__VA_ARGS__); } -#define INFO(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO) \ - fprintf(stdout, "[INFO]: " _fmt, ##__VA_ARGS__) +#define INFO(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) \ + { fprintf(stdout, "[INFO]: " _fmt, ##__VA_ARGS__); }\ + else{ srslte_phy_log_print(LOG_LEVEL_INFO, _fmt, ##__VA_ARGS__); } #if CMAKE_BUILD_TYPE==Debug /* In debug mode, it prints out the */ -#define ERROR(_fmt, ...) fprintf(stderr, "%s.%d: " _fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__) +#define ERROR(_fmt, ...) if (!handler_registered)\ + { fprintf(stderr, "\e[31m%s.%d: " _fmt "\e[0m\n", __FILE__, __LINE__, ##__VA_ARGS__);}\ + else {srslte_phy_log_print(LOG_LEVEL_ERROR, _fmt, ##__VA_ARGS__);} // #else -#define ERROR(_fmt, ...) fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__) +#define ERROR(_fmt, ...) if (!handler_registered)\ + { fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__);}\ + else{srslte_phy_log_print(LOG_LEVEL_ERROR, _fmt, ##__VA_ARGS__);} // #endif /* CMAKE_BUILD_TYPE==Debug */ +void srslte_debug_handle_crash(int argc, char **argv); + #endif // DEBUG_H diff --git a/lib/include/srslte/phy/utils/mat.h b/lib/include/srslte/phy/utils/mat.h index d960590c4..339cfea23 100644 --- a/lib/include/srslte/phy/utils/mat.h +++ b/lib/include/srslte/phy/utils/mat.h @@ -27,14 +27,8 @@ #ifndef SRSLTE_MAT_H #define SRSLTE_MAT_H -#include "srslte/phy/utils/simd.h" #include "srslte/config.h" - - -/* - * Generic Macros - */ -#define RANDOM_CF() (((float)rand())/((float)RAND_MAX) + _Complex_I*((float)rand())/((float)RAND_MAX)) +#include "srslte/phy/utils/simd.h" /* Generic implementation for complex reciprocal */ SRSLTE_API cf_t srslte_mat_cf_recip_gen(cf_t a); @@ -66,7 +60,6 @@ SRSLTE_API float srslte_mat_2x2_cn(cf_t h00, #ifdef LV_HAVE_SSE -#include /* SSE implementation for complex reciprocal */ SRSLTE_API __m128 srslte_mat_cf_recip_sse(__m128 a); @@ -90,8 +83,6 @@ SRSLTE_API void srslte_mat_2x2_mmse_sse(__m128 y0, __m128 y1, #ifdef LV_HAVE_AVX -#include - /* AVX implementation for complex reciprocal */ SRSLTE_API __m256 srslte_mat_cf_recip_avx(__m256 a); diff --git a/lib/include/srslte/phy/utils/ringbuffer.h b/lib/include/srslte/phy/utils/ringbuffer.h index 9cbe0ddd6..e590131ff 100644 --- a/lib/include/srslte/phy/utils/ringbuffer.h +++ b/lib/include/srslte/phy/utils/ringbuffer.h @@ -17,18 +17,21 @@ typedef struct { } srslte_ringbuffer_t; -SRSLTE_API int srslte_ringbuffer_init(srslte_ringbuffer_t *q, +SRSLTE_API int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity); -SRSLTE_API void srslte_ringbuffer_free(srslte_ringbuffer_t *q, - int capacity); +SRSLTE_API void srslte_ringbuffer_free(srslte_ringbuffer_t *q); -SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t *q, - uint8_t *ptr, +SRSLTE_API void srslte_ringbuffer_reset(srslte_ringbuffer_t *q); + +SRSLTE_API int srslte_ringbuffer_status(srslte_ringbuffer_t *q); + +SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t *q, + void *ptr, int nof_bytes); -SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t *q, - uint8_t *ptr, +SRSLTE_API int srslte_ringbuffer_read(srslte_ringbuffer_t *q, + void *ptr, int nof_bytes); diff --git a/lib/include/srslte/phy/utils/simd.h b/lib/include/srslte/phy/utils/simd.h index 420d07213..7ea203290 100644 --- a/lib/include/srslte/phy/utils/simd.h +++ b/lib/include/srslte/phy/utils/simd.h @@ -27,6 +27,18 @@ #ifndef SRSLTE_SIMD_H_H #define SRSLTE_SIMD_H_H +#ifdef LV_HAVE_SSE /* AVX, AVX2, FMA, AVX512 are in this group */ +#ifndef __OPTIMIZE__ +#define __OPTIMIZE__ +#endif +#include +#endif /* LV_HAVE_SSE */ +#include + +#ifdef HAVE_NEON +#include +#endif + /* * SSE Macros */ @@ -78,4 +90,1535 @@ _mm256_fmsubadd_ps(_mm256_shuffle_ps(A,A,0xB1),_mm256_movehdup_ps(B), C)) #endif /* LV_HAVE_FMA */ + + +/* Memory Sizes for Single Floating Point and fixed point */ +#ifdef LV_HAVE_AVX512 + +#define SRSLTE_SIMD_F_SIZE 16 +#define SRSLTE_SIMD_CF_SIZE 16 + +#define SRSLTE_SIMD_I_SIZE 16 + +#define SRSLTE_SIMD_S_SIZE 32 +#define SRSLTE_SIMD_C16_SIZE 0 + +#else +#ifdef LV_HAVE_AVX2 + +#define SRSLTE_SIMD_F_SIZE 8 +#define SRSLTE_SIMD_CF_SIZE 8 + +#define SRSLTE_SIMD_I_SIZE 8 + +#define SRSLTE_SIMD_S_SIZE 16 +#define SRSLTE_SIMD_C16_SIZE 16 + +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + +#define SRSLTE_SIMD_F_SIZE 4 +#define SRSLTE_SIMD_CF_SIZE 4 + +#define SRSLTE_SIMD_I_SIZE 4 + +#define SRSLTE_SIMD_S_SIZE 8 +#define SRSLTE_SIMD_C16_SIZE 8 + +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + +#define SRSLTE_SIMD_F_SIZE 4 +#define SRSLTE_SIMD_CF_SIZE 4 + +#define SRSLTE_SIMD_I_SIZE 4 + +#define SRSLTE_SIMD_S_SIZE 8 +#define SRSLTE_SIMD_C16_SIZE 8 + +#else /* LV_HAVE_NEON */ +#define SRSLTE_SIMD_F_SIZE 0 +#define SRSLTE_SIMD_CF_SIZE 0 + +#define SRSLTE_SIMD_I_SIZE 0 + +#define SRSLTE_SIMD_S_SIZE 0 +#define SRSLTE_SIMD_C16_SIZE 0 + +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + + + +#if SRSLTE_SIMD_F_SIZE + +/* Data types */ +#ifdef LV_HAVE_AVX512 +typedef __m512 simd_f_t; +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 +typedef __m256 simd_f_t; +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE +typedef __m128 simd_f_t; +#else /* HAVE_NEON */ +#ifdef HAVE_NEON +typedef float32x4_t simd_f_t; +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + +/* Single precision Floating point functions */ +static inline simd_f_t srslte_simd_f_load(const float *ptr) { +#ifdef LV_HAVE_AVX512 + return _mm512_load_ps(ptr); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_load_ps(ptr); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_load_ps(ptr); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vld1q_f32(ptr); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_f_t srslte_simd_f_loadu(const float *ptr) { +#ifdef LV_HAVE_AVX512 + return _mm512_loadu_ps(ptr); +#else /* LV_HAVE_AVX512 */ + #ifdef LV_HAVE_AVX2 + return _mm256_loadu_ps(ptr); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_loadu_ps(ptr); +#else /* LV_HAVE_SSE */ + #ifdef HAVE_NEON + return vld1q_f32(ptr); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline void srslte_simd_f_store(float *ptr, simd_f_t simdreg) { +#ifdef LV_HAVE_AVX512 + _mm512_store_ps(ptr, simdreg); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + _mm256_store_ps(ptr, simdreg); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + _mm_store_ps(ptr, simdreg); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + vst1q_f32(ptr, simdreg); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline void srslte_simd_f_storeu(float *ptr, simd_f_t simdreg) { +#ifdef LV_HAVE_AVX512 + _mm512_storeu_ps(ptr, simdreg); +#else /* LV_HAVE_AVX512 */ + #ifdef LV_HAVE_AVX2 + _mm256_storeu_ps(ptr, simdreg); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + _mm_storeu_ps(ptr, simdreg); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + vst1q_f32(ptr, simdreg); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_f_t srslte_simd_f_set1(float x) { +#ifdef LV_HAVE_AVX512 + return _mm512_set1_ps(x); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_set1_ps(x); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_set1_ps(x); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vdupq_n_f32(x); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_f_t srslte_simd_f_mul(simd_f_t a, simd_f_t b) { +#ifdef LV_HAVE_AVX512 + return _mm512_mul_ps(a, b); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_mul_ps(a, b); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_mul_ps(a, b); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vmulq_f32(a,b); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_f_t srslte_simd_f_rcp(simd_f_t a) { +#ifdef LV_HAVE_AVX512 + return _mm512_rcp14_ps(a); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_rcp_ps(a); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_rcp_ps(a); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vmulq_f32(vrecpeq_f32(a), vrecpsq_f32(vrecpeq_f32(a), a)); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_f_t srslte_simd_f_addsub(simd_f_t a, simd_f_t b) { +#ifdef LV_HAVE_AVX512 + __m512 r = _mm512_add_ps(a, b); + return _mm512_mask_sub_ps(r, 0b0101010101010101, a, b); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_addsub_ps(a, b); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_addsub_ps(a, b); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON // CURRENTLY USES GENERIC IMPLEMENTATION FOR NEON + float* a_ptr = (float*) &a; + float* b_ptr = (float*) &b; + simd_f_t ret; + float* c_ptr = (float*) &ret; + for(int i = 0; i<4;i++){ + if(i%2==0){ + c_ptr[i] = a_ptr[i] - b_ptr[i]; + }else{ + c_ptr[i] = a_ptr[i] + b_ptr[i]; + } + } + + return ret; +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + + + + +static inline simd_f_t srslte_simd_f_sub(simd_f_t a, simd_f_t b) { +#ifdef LV_HAVE_AVX512 + return _mm512_sub_ps(a, b); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_sub_ps(a, b); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_sub_ps(a, b); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vsubq_f32(a, b); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_f_t srslte_simd_f_add(simd_f_t a, simd_f_t b) { +#ifdef LV_HAVE_AVX512 + return _mm512_add_ps(a, b); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_add_ps(a, b); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_add_ps(a, b); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vaddq_f32(a, b); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_f_t srslte_simd_f_zero (void) { +#ifdef LV_HAVE_AVX512 + return _mm512_setzero_ps(); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_setzero_ps(); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_setzero_ps(); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vdupq_n_f32(0); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_f_t srslte_simd_f_swap(simd_f_t a) { +#ifdef LV_HAVE_AVX512 + return _mm512_permute_ps(a, 0b10110001); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_permute_ps(a, 0b10110001); +#else /* LV_HAVE_AVX2 */ + #ifdef LV_HAVE_SSE + return _mm_shuffle_ps(a, a, 0b10110001); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vcombine_f32(vrev64_f32(vget_low_f32(a)), vrev64_f32(vget_high_f32(a))); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_f_t srslte_simd_f_hadd(simd_f_t a, simd_f_t b) { +#ifdef LV_HAVE_AVX512 + const __m512i idx1 = _mm512_setr_epi32((0b00000), (0b00010), + (0b00100), (0b00110), + (0b01000), (0b01010), + (0b01100), (0b01110), + (0b10000), (0b10010), + (0b10100), (0b10110), + (0b11000), (0b11010), + (0b11100), (0b11110)); + const __m512i idx2 = _mm512_or_epi32(idx1, _mm512_set1_epi32(1)); + + simd_f_t a1 = _mm512_permutex2var_ps(a, idx1, b); + simd_f_t b1 = _mm512_permutex2var_ps(a, idx2, b); + return _mm512_add_ps(a1, b1); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + simd_f_t a1 = _mm256_permute2f128_ps(a, b, 0b00100000); + simd_f_t b1 = _mm256_permute2f128_ps(a, b, 0b00110001); + return _mm256_hadd_ps(a1, b1); +#else /* LV_HAVE_AVX2 */ + #ifdef LV_HAVE_SSE + return _mm_hadd_ps(a, b); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vcombine_f32( vpadd_f32( vget_low_f32(a), vget_high_f32(a) ), vpadd_f32( vget_low_f32(b), vget_high_f32(b) ) ); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_f_t srslte_simd_f_sqrt(simd_f_t a) { +#ifdef LV_HAVE_AVX512 + return _mm512_sqrt_ps(a); +#else /* LV_HAVE_AVX512 */ + #ifdef LV_HAVE_AVX2 + return _mm256_sqrt_ps(a); +#else /* LV_HAVE_AVX2 */ + #ifdef LV_HAVE_SSE + return _mm_sqrt_ps(a); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + float32x4_t sqrt_reciprocal = vrsqrteq_f32(a); + sqrt_reciprocal = vmulq_f32(vrsqrtsq_f32(vmulq_f32(a,sqrt_reciprocal), sqrt_reciprocal),sqrt_reciprocal); + float32x4_t result = vmulq_f32(a,sqrt_reciprocal); + + /* Detect zeros in NEON 1/sqrtf for preventing NaN */ + float32x4_t zeros = vmovq_n_f32(0); /* Zero vector */ + uint32x4_t mask = vceqq_f32(a, zeros); /* Zero vector mask */ + return vbslq_f32(mask, zeros, result); /* Force zero results and return */ +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +#endif /* SRSLTE_SIMD_F_SIZE */ + + +#if SRSLTE_SIMD_CF_SIZE + +#ifdef HAVE_NEON + typedef float32x4x2_t simd_cf_t; +#else +typedef struct { + simd_f_t re; + simd_f_t im; + +} simd_cf_t; +#endif + +/* Complex Single precission Floating point functions */ +static inline simd_cf_t srslte_simd_cfi_load(const cf_t *ptr) { + simd_cf_t ret; +#ifdef LV_HAVE_AVX512 + __m512 in1 = _mm512_load_ps((float*)(ptr)); + __m512 in2 = _mm512_load_ps((float*)(ptr + SRSLTE_SIMD_CF_SIZE/2)); + ret.re = _mm512_permutex2var_ps(in1, _mm512_setr_epi32(0x00, 0x02, 0x04, 0x06, + 0x08, 0x0A, 0x0C, 0x0E, + 0x10, 0x12, 0x14, 0x16, + 0x18, 0x1A, 0x1C, 0x1E), in2); + ret.im = _mm512_permutex2var_ps(in1, _mm512_setr_epi32(0x01, 0x03, 0x05, 0x07, + 0x09, 0x0B, 0x0D, 0x0F, + 0x11, 0x13, 0x15, 0x17, + 0x19, 0x1B, 0x1D, 0x1F), in2); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + __m256 in1 = _mm256_permute_ps(_mm256_load_ps((float*)(ptr)), 0b11011000); + __m256 in2 = _mm256_permute_ps(_mm256_load_ps((float*)(ptr + 4)), 0b11011000); + ret.re = _mm256_unpacklo_ps(in1, in2); + ret.im = _mm256_unpackhi_ps(in1, in2); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + __m128 i1 = _mm_load_ps((float*)(ptr)); + __m128 i2 = _mm_load_ps((float*)(ptr + 2)); + ret.re = _mm_shuffle_ps(i1, i2, _MM_SHUFFLE(2,0,2,0)); + ret.im = _mm_shuffle_ps(i1, i2, _MM_SHUFFLE(3,1,3,1)); +#else +#ifdef HAVE_NEON + ret = vld2q_f32((float*)(ptr)); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + return ret; +} + +/* Complex Single precission Floating point functions */ +static inline simd_cf_t srslte_simd_cfi_loadu(const cf_t *ptr) { + simd_cf_t ret; +#ifdef LV_HAVE_AVX512 + __m512 in1 = _mm512_loadu_ps((float*)(ptr)); + __m512 in2 = _mm512_loadu_ps((float*)(ptr + SRSLTE_SIMD_CF_SIZE/2)); + ret.re = _mm512_permutex2var_ps(in1, _mm512_setr_epi32(0x00, 0x02, 0x04, 0x06, + 0x08, 0x0A, 0x0C, 0x0E, + 0x10, 0x12, 0x14, 0x16, + 0x18, 0x1A, 0x1C, 0x1E), in2); + ret.im = _mm512_permutex2var_ps(in1, _mm512_setr_epi32(0x01, 0x03, 0x05, 0x07, + 0x09, 0x0B, 0x0D, 0x0F, + 0x11, 0x13, 0x15, 0x17, + 0x19, 0x1B, 0x1D, 0x1F), in2); +#else /* LV_HAVE_AVX512 */ + #ifdef LV_HAVE_AVX2 + __m256 in1 = _mm256_permute_ps(_mm256_loadu_ps((float*)(ptr)), 0b11011000); + __m256 in2 = _mm256_permute_ps(_mm256_loadu_ps((float*)(ptr + 4)), 0b11011000); + ret.re = _mm256_unpacklo_ps(in1, in2); + ret.im = _mm256_unpackhi_ps(in1, in2); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + __m128 i1 = _mm_loadu_ps((float*)(ptr)); + __m128 i2 = _mm_loadu_ps((float*)(ptr + 2)); + ret.re = _mm_shuffle_ps(i1, i2, _MM_SHUFFLE(2,0,2,0)); + ret.im = _mm_shuffle_ps(i1, i2, _MM_SHUFFLE(3,1,3,1)); +#else +#ifdef HAVE_NEON + ret = vld2q_f32((float*)(ptr)); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + return ret; +} + +static inline simd_cf_t srslte_simd_cf_load(const float *re, const float *im) { + simd_cf_t ret; +#ifdef LV_HAVE_AVX512 + ret.re = _mm512_load_ps(re); + ret.im = _mm512_load_ps(im); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + ret.re = _mm256_load_ps(re); + ret.im = _mm256_load_ps(im); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + ret.re = _mm_load_ps(re); + ret.im = _mm_load_ps(im); +#else /*HAVE_NEON*/ +#ifdef HAVE_NEON + ret.val[0] = vld1q_f32(re); + ret.val[1] = vld1q_f32(im); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + return ret; +} + +static inline simd_cf_t srslte_simd_cf_loadu(const float *re, const float *im) { + simd_cf_t ret; +#ifdef LV_HAVE_AVX512 + ret.re = _mm512_loadu_ps(re); + ret.im = _mm512_loadu_ps(im); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + ret.re = _mm256_loadu_ps(re); + ret.im = _mm256_loadu_ps(im); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + ret.re = _mm_loadu_ps(re); + ret.im = _mm_loadu_ps(im); +#else /*HAVE_NEON*/ +#ifdef HAVE_NEON + ret.val[0] = vld1q_f32(re); + ret.val[1] = vld1q_f32(im); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + return ret; +} + +static inline void srslte_simd_cfi_store(cf_t *ptr, simd_cf_t simdreg) { +#ifdef LV_HAVE_AVX512 + __m512 s1 = _mm512_permutex2var_ps(simdreg.re, _mm512_setr_epi32(0x00, 0x10, 0x01, 0x11, + 0x02, 0x12, 0x03, 0x13, + 0x04, 0x14, 0x05, 0x15, + 0x06, 0x16, 0x07, 0x17), simdreg.im); + __m512 s2 = _mm512_permutex2var_ps(simdreg.re, _mm512_setr_epi32(0x08, 0x18, 0x09, 0x19, + 0x0A, 0x1A, 0x0B, 0x1B, + 0x0C, 0x1C, 0x0D, 0x1D, + 0x0E, 0x1E, 0x0F, 0x1F), simdreg.im); + _mm512_store_ps((float*)(ptr), s1); + _mm512_store_ps((float*)(ptr + 8), s2); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + __m256 out1 = _mm256_permute_ps(simdreg.re, 0b11011000); + __m256 out2 = _mm256_permute_ps(simdreg.im, 0b11011000); + _mm256_store_ps((float*)(ptr), _mm256_unpacklo_ps(out1, out2)); + _mm256_store_ps((float*)(ptr + 4), _mm256_unpackhi_ps(out1, out2)); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + _mm_store_ps((float*)(ptr), _mm_unpacklo_ps(simdreg.re, simdreg.im)); + _mm_store_ps((float*)(ptr + 2), _mm_unpackhi_ps(simdreg.re, simdreg.im)); +#else /*HAVE_NEON*/ +#ifdef HAVE_NEON + vst2q_f32((float*)(ptr), simdreg); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline void srslte_simd_cfi_storeu(cf_t *ptr, simd_cf_t simdreg) { +#ifdef LV_HAVE_AVX512 + __m512 s1 = _mm512_permutex2var_ps(simdreg.re, _mm512_setr_epi32(0x00, 0x10, 0x01, 0x11, + 0x02, 0x12, 0x03, 0x13, + 0x04, 0x14, 0x05, 0x15, + 0x06, 0x16, 0x07, 0x17), simdreg.im); + __m512 s2 = _mm512_permutex2var_ps(simdreg.re, _mm512_setr_epi32(0x08, 0x18, 0x09, 0x19, + 0x0A, 0x1A, 0x0B, 0x1B, + 0x0C, 0x1C, 0x0D, 0x1D, + 0x0E, 0x1E, 0x0F, 0x1F), simdreg.im); + _mm512_storeu_ps((float*)(ptr), s1); + _mm512_storeu_ps((float*)(ptr + 8), s2); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + __m256 out1 = _mm256_permute_ps(simdreg.re, 0b11011000); + __m256 out2 = _mm256_permute_ps(simdreg.im, 0b11011000); + _mm256_storeu_ps((float*)(ptr), _mm256_unpacklo_ps(out1, out2)); + _mm256_storeu_ps((float*)(ptr + 4), _mm256_unpackhi_ps(out1, out2)); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + _mm_storeu_ps((float*)(ptr), _mm_unpacklo_ps(simdreg.re, simdreg.im)); + _mm_storeu_ps((float*)(ptr + 2), _mm_unpackhi_ps(simdreg.re, simdreg.im)); +#else /*HAVE_NEON*/ +#ifdef HAVE_NEON + vst2q_f32((float*)(ptr), simdreg); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline void srslte_simd_cf_store(float *re, float *im, simd_cf_t simdreg) { +#ifdef LV_HAVE_AVX512 + _mm512_store_ps(re, simdreg.re); + _mm512_store_ps(im, simdreg.im); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + _mm256_store_ps((float *) re, simdreg.re); + _mm256_store_ps((float *) im, simdreg.im); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_SSE + _mm_store_ps((float *) re, simdreg.re); + _mm_store_ps((float *) im, simdreg.im); +#else /*HAVE_NEON*/ +#ifdef HAVE_NEON + vst1q_f32((float *) re, simdreg.val[0]); + vst1q_f32((float *) im, simdreg.val[1]); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline void srslte_simd_cf_storeu(float *re, float *im, simd_cf_t simdreg) { +#ifdef LV_HAVE_AVX512 + _mm512_storeu_ps(re, simdreg.re); + _mm512_storeu_ps(im, simdreg.im); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + _mm256_storeu_ps((float *) re, simdreg.re); + _mm256_storeu_ps((float *) im, simdreg.im); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_SSE + _mm_storeu_ps((float *) re, simdreg.re); + _mm_storeu_ps((float *) im, simdreg.im); +#else /*HAVE_NEON*/ +#ifdef HAVE_NEON + vst1q_f32((float *) re, simdreg.val[0]); + vst1q_f32((float *) im, simdreg.val[1]); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_cf_t srslte_simd_cf_set1 (cf_t x) { + simd_cf_t ret; +#ifdef LV_HAVE_AVX512 + ret.re = _mm512_set1_ps(__real__ x); + ret.im = _mm512_set1_ps(__imag__ x); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + ret.re = _mm256_set1_ps(__real__ x); + ret.im = _mm256_set1_ps(__imag__ x); +#else +#ifdef LV_HAVE_SSE + ret.re = _mm_set1_ps(__real__ x); + ret.im = _mm_set1_ps(__imag__ x); +#else /*HAVE_NEON*/ +#ifdef HAVE_NEON + ret.val[0] = vdupq_n_f32(__real__ x); + ret.val[1] = vdupq_n_f32(__imag__ x); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + return ret; +} + +static inline simd_cf_t srslte_simd_cf_prod (simd_cf_t a, simd_cf_t b) { + simd_cf_t ret; +#ifdef LV_HAVE_AVX512 + ret.re = _mm512_sub_ps(_mm512_mul_ps(a.re, b.re), + _mm512_mul_ps(a.im, b.im)); + ret.im = _mm512_add_ps(_mm512_mul_ps(a.re, b.im), + _mm512_mul_ps(a.im, b.re)); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + ret.re = _mm256_sub_ps(_mm256_mul_ps(a.re, b.re), + _mm256_mul_ps(a.im, b.im)); + ret.im = _mm256_add_ps(_mm256_mul_ps(a.re, b.im), + _mm256_mul_ps(a.im, b.re)); +#else +#ifdef LV_HAVE_SSE + ret.re = _mm_sub_ps(_mm_mul_ps(a.re, b.re), + _mm_mul_ps(a.im, b.im)); + ret.im = _mm_add_ps(_mm_mul_ps(a.re, b.im), + _mm_mul_ps(a.im, b.re)); +#else +#ifdef HAVE_NEON + ret.val[0] = vsubq_f32(vmulq_f32(a.val[0],b.val[0]), + vmulq_f32(a.val[1],b.val[1])); + ret.val[1] = vaddq_f32(vmulq_f32(a.val[0],b.val[1]), + vmulq_f32(a.val[1],b.val[0])); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + return ret; +} + +static inline simd_cf_t srslte_simd_cf_conjprod (simd_cf_t a, simd_cf_t b) { + simd_cf_t ret; +#ifdef LV_HAVE_AVX512 + ret.re = _mm512_add_ps(_mm512_mul_ps(a.re, b.re), + _mm512_mul_ps(a.im, b.im)); + ret.im = _mm512_sub_ps(_mm512_mul_ps(a.im, b.re), + _mm512_mul_ps(a.re, b.im)); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + ret.re = _mm256_add_ps(_mm256_mul_ps(a.re, b.re), + _mm256_mul_ps(a.im, b.im)); + ret.im = _mm256_sub_ps(_mm256_mul_ps(a.im, b.re), + _mm256_mul_ps(a.re, b.im)); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + ret.re = _mm_add_ps(_mm_mul_ps(a.re, b.re), + _mm_mul_ps(a.im, b.im)); + ret.im = _mm_sub_ps(_mm_mul_ps(a.im, b.re), + _mm_mul_ps(a.re, b.im)); + #else +#ifdef HAVE_NEON + ret.val[0] = vaddq_f32(vmulq_f32(a.val[0],b.val[0]), + vmulq_f32(a.val[1],b.val[1])); + ret.val[1] = vsubq_f32(vmulq_f32(a.val[1],b.val[0]), + vmulq_f32(a.val[0],b.val[1])); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + return ret; +} + +static inline simd_cf_t srslte_simd_cf_add (simd_cf_t a, simd_cf_t b) { + simd_cf_t ret; +#ifdef LV_HAVE_AVX512 + ret.re = _mm512_add_ps(a.re, b.re); + ret.im = _mm512_add_ps(a.im, b.im); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + ret.re = _mm256_add_ps(a.re, b.re); + ret.im = _mm256_add_ps(a.im, b.im); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + ret.re = _mm_add_ps(a.re, b.re); + ret.im = _mm_add_ps(a.im, b.im); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + ret.val[0] = vaddq_f32(a.val[0],b.val[0]); + ret.val[1] = vaddq_f32(a.val[1],b.val[1]); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + return ret; +} + +static inline simd_cf_t srslte_simd_cf_mul (simd_cf_t a, simd_f_t b) { + simd_cf_t ret; +#ifdef LV_HAVE_AVX512 + ret.re = _mm512_mul_ps(a.re, b); + ret.im = _mm512_mul_ps(a.im, b); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + b = _mm256_permutevar8x32_ps(b, _mm256_setr_epi32(0,4,1,5,2,6,3,7)); + ret.re = _mm256_mul_ps(a.re, b); + ret.im = _mm256_mul_ps(a.im, b); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + ret.re = _mm_mul_ps(a.re, b); + ret.im = _mm_mul_ps(a.im, b); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + ret.val[0] = vmulq_f32(a.val[0],b); + ret.val[1] = vmulq_f32(a.val[1],b); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + return ret; +} + +static inline simd_cf_t srslte_simd_cf_rcp (simd_cf_t a) { + simd_cf_t ret; +#ifdef LV_HAVE_AVX512 + simd_f_t a2re = _mm512_mul_ps(a.re, a.re); + simd_f_t a2im = _mm512_mul_ps(a.im, a.im); + simd_f_t mod2 = _mm512_add_ps(a2re, a2im); + simd_f_t rcp = _mm512_rcp14_ps(mod2); + simd_f_t neg_a_im = _mm512_xor_ps(_mm512_set1_ps(-0.0f), a.im); + ret.re = _mm512_mul_ps(a.re, rcp); + ret.im = _mm512_mul_ps(neg_a_im, rcp); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + simd_f_t a2re = _mm256_mul_ps(a.re, a.re); + simd_f_t a2im = _mm256_mul_ps(a.im, a.im); + simd_f_t mod2 = _mm256_add_ps(a2re, a2im); + simd_f_t rcp = _mm256_rcp_ps(mod2); + simd_f_t neg_a_im = _mm256_xor_ps(_mm256_set1_ps(-0.0f), a.im); + ret.re = _mm256_mul_ps(a.re, rcp); + ret.im = _mm256_mul_ps(neg_a_im, rcp); +#else /* LV_HAVE_AVX2 */ + #ifdef LV_HAVE_SSE + simd_f_t a2re = _mm_mul_ps(a.re, a.re); + simd_f_t a2im = _mm_mul_ps(a.im, a.im); + simd_f_t mod2 = _mm_add_ps(a2re, a2im); + simd_f_t rcp = _mm_rcp_ps(mod2); + simd_f_t neg_a_im = _mm_xor_ps(_mm_set1_ps(-0.0f), a.im); + ret.re = _mm_mul_ps(a.re, rcp); + ret.im = _mm_mul_ps(neg_a_im, rcp); + #else /* LV_HAVE_SSE */ + #ifdef HAVE_NEON + simd_f_t a2re = vmulq_f32(a.val[0], a.val[0]); + simd_f_t a2im = vmulq_f32(a.val[1], a.val[1]); + simd_f_t mod2 = vaddq_f32(a2re, a2im); + simd_f_t rcp = vmulq_f32(vrecpeq_f32(mod2), vrecpsq_f32(vrecpeq_f32(mod2), mod2)); + simd_f_t neg_a_im = vnegq_f32(a.val[1]); + ret.val[0] = vmulq_f32(a.val[0], rcp); + ret.val[1] = vmulq_f32(neg_a_im, rcp); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + return ret; +} + +static inline simd_cf_t srslte_simd_cf_zero (void) { + simd_cf_t ret; +#ifdef LV_HAVE_AVX512 + ret.re = _mm512_setzero_ps(); + ret.im = _mm512_setzero_ps(); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + ret.re = _mm256_setzero_ps(); + ret.im = _mm256_setzero_ps(); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + ret.re = _mm_setzero_ps(); + ret.im = _mm_setzero_ps(); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + ret.val[0] = vdupq_n_f32(0); + ret.val[1] = vdupq_n_f32(0); +#endif /* HAVE_NEON */ +#endif /* HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + return ret; +} + +#endif /* SRSLTE_SIMD_CF_SIZE */ + +#if SRSLTE_SIMD_I_SIZE + +#ifdef LV_HAVE_AVX512 +typedef __m512i simd_i_t; +typedef __mmask16 simd_sel_t; +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 +typedef __m256i simd_i_t; +typedef __m256 simd_sel_t; +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE +typedef __m128i simd_i_t; +typedef __m128 simd_sel_t; +#else /* LV_HAVE_AVX2 */ +#ifdef HAVE_NEON +typedef int32x4_t simd_i_t; +typedef int32x4_t simd_sel_t; +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + +static inline simd_i_t srslte_simd_i_load(int *x) { +#ifdef LV_HAVE_AVX512 + return _mm512_load_epi32((__m512i*)x); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_load_si256((__m256i*)x); +#else + #ifdef LV_HAVE_SSE + return _mm_load_si128((__m128i*)x); +#else + #ifdef HAVE_NEON + return vld1q_s32((int*)x); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline void srslte_simd_i_store(int *x, simd_i_t reg) { +#ifdef LV_HAVE_AVX512 + _mm512_store_epi32((__m512i*)x, reg); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + _mm256_store_si256((__m256i*)x, reg); +#else +#ifdef LV_HAVE_SSE + _mm_store_si128((__m128i*)x, reg); +#else +#ifdef HAVE_NEON + vst1q_s32((int*)x, reg); +#endif /*HAVE_NEON*/ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_i_t srslte_simd_i_set1(int x) { +#ifdef LV_HAVE_AVX512 + return _mm512_set1_epi32(x); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_set1_epi32(x); +#else + #ifdef LV_HAVE_SSE + return _mm_set1_epi32(x); +#else + #ifdef HAVE_NEON + return vdupq_n_s32(x); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_i_t srslte_simd_i_add(simd_i_t a, simd_i_t b) { +#ifdef LV_HAVE_AVX512 + return _mm512_add_epi32(a, b); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_add_epi32(a, b); +#else +#ifdef LV_HAVE_SSE + return _mm_add_epi32(a, b); +#else +#ifdef HAVE_NEON + return vaddq_s32(a, b); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_sel_t srslte_simd_f_max(simd_f_t a, simd_f_t b) { +#ifdef LV_HAVE_AVX512 + return _mm512_cmp_ps_mask(a, b, _CMP_GT_OS); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_cmp_ps(a, b, _CMP_GT_OS); +#else /* LV_HAVE_AVX2 */ + #ifdef LV_HAVE_SSE + return (simd_sel_t) _mm_cmpgt_ps(a, b); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return (simd_sel_t) vcgtq_f32(a, b); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_i_t srslte_simd_i_select(simd_i_t a, simd_i_t b, simd_sel_t selector) { +#ifdef LV_HAVE_AVX512 + return (__m512i) _mm512_mask_blend_ps( selector, (__m512)a, (__m512) b); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return (__m256i) _mm256_blendv_ps((__m256) a,(__m256) b, selector); +#else + #ifdef LV_HAVE_SSE + return (__m128i) _mm_blendv_ps((__m128)a, (__m128)b, selector); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON // CURRENTLY USES GENERIC IMPLEMENTATION FOR NEON + int* a_ptr = (int*) &a; + int* b_ptr = (int*) &b; + simd_i_t ret; + int* sel = (int*) &selector; + int* c_ptr = (int*) &ret; + for(int i = 0;i<4;i++) + { + if(sel[i] == -1){ + c_ptr[i] = b_ptr[i]; + }else{ + c_ptr[i] = a_ptr[i]; + } + } + return ret; +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +#endif /* SRSLTE_SIMD_I_SIZE*/ + + +#if SRSLTE_SIMD_S_SIZE + + +#ifdef LV_HAVE_AVX512 +typedef __m512i simd_s_t; +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 +typedef __m256i simd_s_t; +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE +typedef __m128i simd_s_t; +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON +typedef int16x8_t simd_s_t; +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + +static inline simd_s_t srslte_simd_s_load(const int16_t *ptr) { +#ifdef LV_HAVE_AVX512 + return _mm512_load_si512(ptr); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_load_si256((__m256i*) ptr); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_load_si128((__m128i*) ptr); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vld1q_s16(ptr); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_s_t srslte_simd_s_loadu(const int16_t *ptr) { +#ifdef LV_HAVE_AVX512 + return _mm512_loadu_si512(ptr); +#else /* LV_HAVE_AVX512 */ + #ifdef LV_HAVE_AVX2 + return _mm256_loadu_si256((__m256i*) ptr); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_loadu_si128((__m128i*) ptr); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vld1q_s16(ptr); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline void srslte_simd_s_store(int16_t *ptr, simd_s_t simdreg) { +#ifdef LV_HAVE_AVX512 + _mm512_store_si512(ptr, simdreg); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + _mm256_store_si256((__m256i*) ptr, simdreg); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + _mm_store_si128((__m128i*) ptr, simdreg); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + vst1q_s16( ptr, simdreg); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline void srslte_simd_s_storeu(int16_t *ptr, simd_s_t simdreg) { +#ifdef LV_HAVE_AVX512 + _mm512_storeu_si512(ptr, simdreg); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + _mm256_storeu_si256((__m256i*) ptr, simdreg); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + _mm_storeu_si128((__m128i*) ptr, simdreg); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + vst1q_s16(ptr, simdreg); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} +static inline simd_s_t srslte_simd_s_zero(void) { +#ifdef LV_HAVE_AVX512 + return _mm512_setzero_si512(); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_setzero_si256(); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_setzero_si128(); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vdupq_n_s16(0); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_s_t srslte_simd_s_mul(simd_s_t a, simd_s_t b) { +#ifdef LV_HAVE_AVX512 + return _mm512_mullo_epi16(a, b); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_mullo_epi16(a, b); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_mullo_epi16(a, b); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vmulq_s16(a, b); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_s_t srslte_simd_s_add(simd_s_t a, simd_s_t b) { +#ifdef LV_HAVE_AVX512 + return _mm512_add_epi16(a, b); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_add_epi16(a, b); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_add_epi16(a, b); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vaddq_s16(a, b); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_s_t srslte_simd_s_sub(simd_s_t a, simd_s_t b) { +#ifdef LV_HAVE_AVX512 + return _mm512_sub_epi16(a, b); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_sub_epi16(a, b); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_sub_epi16(a, b); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vsubq_s16(a, b); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +#endif /* SRSLTE_SIMD_S_SIZE */ + + +#if SRSLTE_SIMD_C16_SIZE + +typedef +#ifdef LV_HAVE_AVX512 + struct { + union { + __m512i m512; + int16_t i16[32]; + } re; + union { + __m512i m512; + int16_t i16[32]; + } im; +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + struct { + union { + __m256i m256; + int16_t i16[16]; + } re; + union { + __m256i m256; + int16_t i16[16]; + } im; +#else +#ifdef LV_HAVE_SSE + struct { + union { + __m128i m128; + int16_t i16[8]; + } re; + union { + __m128i m128; + int16_t i16[8]; + } im; +#else +#ifdef HAVE_NEON + union { + int16x8x2_t m128; + int16_t i16[16]; +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} simd_c16_t; + +/* Fixed point precision (16-bit) functions */ +static inline simd_c16_t srslte_simd_c16i_load(const c16_t *ptr) { + simd_c16_t ret; +#ifdef LV_HAVE_AVX512 + __m512i in1 = _mm512_load_si512((__m512i*)(ptr)); + __m512i in2 = _mm512_load_si512((__m512i*)(ptr + 8)); + ret.re.m512 = _mm512_mask_blend_epi16(0xAAAAAAAA, in1,_mm512_shufflelo_epi16(_mm512_shufflehi_epi16(in2, 0b10100000), 0b10100000)); + ret.im.m512 = _mm512_mask_blend_epi16(0xAAAAAAAA, _mm512_shufflelo_epi16(_mm512_shufflehi_epi16(in1, 0b11110101), 0b11110101),in2); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_AVX2 + __m256i in1 = _mm256_load_si256((__m256i*)(ptr)); + __m256i in2 = _mm256_load_si256((__m256i*)(ptr + 8)); + ret.re.m256 = _mm256_blend_epi16(in1,_mm256_shufflelo_epi16(_mm256_shufflehi_epi16(in2, 0b10100000), 0b10100000), 0b10101010); + ret.im.m256 = _mm256_blend_epi16(_mm256_shufflelo_epi16(_mm256_shufflehi_epi16(in1, 0b11110101), 0b11110101),in2, 0b10101010); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + __m128i in1 = _mm_load_si128((__m128i*)(ptr)); + __m128i in2 = _mm_load_si128((__m128i*)(ptr + 8)); + ret.re.m128 = _mm_blend_epi16(in1,_mm_shufflelo_epi16(_mm_shufflehi_epi16(in2, 0b10100000), 0b10100000), 0b10101010); + ret.im.m128 = _mm_blend_epi16(_mm_shufflelo_epi16(_mm_shufflehi_epi16(in1, 0b11110101), 0b11110101),in2, 0b10101010); +#else /* LV_HAVE_SSE*/ +#ifdef HAVE_NEON + ret.m128 = vld2q_s16((int16_t*)(ptr)); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + return ret; +} + +static inline simd_c16_t srslte_simd_c16_load(const int16_t *re, const int16_t *im) { + simd_c16_t ret; +#ifdef LV_HAVE_AVX2 + ret.re.m256 = _mm256_load_si256((__m256i*)(re)); + ret.im.m256 = _mm256_load_si256((__m256i*)(im)); +#else +#ifdef LV_HAVE_SSE + ret.re.m128 = _mm_load_si128((__m128i*)(re)); + ret.im.m128 = _mm_load_si128((__m128i*)(im)); +#else /* LV_HAVE_SSE*/ +#ifdef HAVE_NEON + ret.m128.val[0] = vld1q_s16((int16_t*)(re)); + ret.m128.val[1] = vld1q_s16((int16_t*)(im)); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ + return ret; +} + +static inline simd_c16_t srslte_simd_c16_loadu(const int16_t *re, const int16_t *im) { + simd_c16_t ret; +#ifdef LV_HAVE_AVX2 + ret.re.m256 = _mm256_loadu_si256((__m256i*)(re)); + ret.im.m256 = _mm256_loadu_si256((__m256i*)(im)); +#else +#ifdef LV_HAVE_SSE + ret.re.m128 = _mm_loadu_si128((__m128i*)(re)); + ret.im.m128 = _mm_loadu_si128((__m128i*)(im)); +#else /* LV_HAVE_SSE*/ +#ifdef HAVE_NEON + ret.m128.val[0] = vld1q_s16((int16_t*)(re)); + ret.m128.val[1] = vld1q_s16((int16_t*)(im)); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ + return ret; +} + +static inline void srslte_simd_c16i_store(c16_t *ptr, simd_c16_t simdreg) { +#ifdef LV_HAVE_AVX2 + __m256i re_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.re.m256, 0b10110001), 0b10110001); + __m256i im_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.im.m256, 0b10110001), 0b10110001); + _mm256_store_si256((__m256i *) (ptr), _mm256_blend_epi16(simdreg.re.m256, im_sw, 0b10101010)); + _mm256_store_si256((__m256i *) (ptr + 8), _mm256_blend_epi16(re_sw, simdreg.im.m256, 0b10101010)); +#else +#ifdef LV_HAVE_SSE + __m128i re_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.re.m128, 0b10110001), 0b10110001); + __m128i im_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.im.m128, 0b10110001), 0b10110001); + _mm_store_si128((__m128i *) (ptr), _mm_blend_epi16(simdreg.re.m128, im_sw, 0b10101010)); + _mm_store_si128((__m128i *) (ptr + 8), _mm_blend_epi16(re_sw, simdreg.im.m128, 0b10101010)); +#else /*HAVE_NEON*/ +#ifdef HAVE_NEON + vst2q_s16((int16_t*)(ptr) ,simdreg.m128); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +} + +static inline void srslte_simd_c16i_storeu(c16_t *ptr, simd_c16_t simdreg) { +#ifdef LV_HAVE_AVX2 + __m256i re_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.re.m256, 0b10110001), 0b10110001); + __m256i im_sw = _mm256_shufflelo_epi16(_mm256_shufflehi_epi16(simdreg.im.m256, 0b10110001), 0b10110001); + _mm256_storeu_si256((__m256i *) (ptr), _mm256_blend_epi16(simdreg.re.m256, im_sw, 0b10101010)); + _mm256_storeu_si256((__m256i *) (ptr + 8), _mm256_blend_epi16(re_sw, simdreg.im.m256, 0b10101010)); +#else +#ifdef LV_HAVE_SSE + __m128i re_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.re.m128, 0b10110001), 0b10110001); + __m128i im_sw = _mm_shufflelo_epi16(_mm_shufflehi_epi16(simdreg.im.m128, 0b10110001), 0b10110001); + _mm_storeu_si128((__m128i *) (ptr), _mm_blend_epi16(simdreg.re.m128, im_sw, 0b10101010)); + _mm_storeu_si128((__m128i *) (ptr + 8), _mm_blend_epi16(re_sw, simdreg.im.m128, 0b10101010)); +#else /*HAVE_NEON*/ +#ifdef HAVE_NEON + vst2q_s16((int16_t*)(ptr) ,simdreg.m128); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +} + +static inline void srslte_simd_c16_store(int16_t *re, int16_t *im, simd_c16_t simdreg) { +#ifdef LV_HAVE_AVX2 + _mm256_store_si256((__m256i *) re, simdreg.re.m256); + _mm256_store_si256((__m256i *) im, simdreg.im.m256); +#else +#ifdef LV_HAVE_SSE + _mm_store_si128((__m128i *) re, simdreg.re.m128); + _mm_store_si128((__m128i *) im, simdreg.im.m128); +#else +#ifdef HAVE_NEON + vst1q_s16((int16_t *) re, simdreg.m128.val[0]); + vst1q_s16((int16_t *) im, simdreg.m128.val[1]); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +} + +static inline void srslte_simd_c16_storeu(int16_t *re, int16_t *im, simd_c16_t simdreg) { +#ifdef LV_HAVE_AVX2 + _mm256_storeu_si256((__m256i *) re, simdreg.re.m256); + _mm256_storeu_si256((__m256i *) im, simdreg.im.m256); +#else +#ifdef LV_HAVE_SSE + _mm_storeu_si128((__m128i *) re, simdreg.re.m128); + _mm_storeu_si128((__m128i *) im, simdreg.im.m128); +#else +#ifdef HAVE_NEON + vst1q_s16((int16_t *) re, simdreg.m128.val[0]); + vst1q_s16((int16_t *) im, simdreg.m128.val[1]); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +} + +static inline simd_c16_t srslte_simd_c16_prod (simd_c16_t a, simd_c16_t b) { + simd_c16_t ret; +#ifdef LV_HAVE_AVX2 + ret.re.m256 = _mm256_sub_epi16(_mm256_mulhrs_epi16(a.re.m256, _mm256_slli_epi16(b.re.m256, 1)), + _mm256_mulhrs_epi16(a.im.m256, _mm256_slli_epi16(b.im.m256, 1))); + ret.im.m256 = _mm256_add_epi16(_mm256_mulhrs_epi16(a.re.m256, _mm256_slli_epi16(b.im.m256, 1)), + _mm256_mulhrs_epi16(a.im.m256, _mm256_slli_epi16(b.re.m256, 1))); +#else +#ifdef LV_HAVE_SSE + ret.re.m128 = _mm_sub_epi16(_mm_mulhrs_epi16(a.re.m128, _mm_slli_epi16(b.re.m128, 1)), + _mm_mulhrs_epi16(a.im.m128, _mm_slli_epi16(b.im.m128, 1))); + ret.im.m128 = _mm_add_epi16(_mm_mulhrs_epi16(a.re.m128, _mm_slli_epi16(b.im.m128, 1)), + _mm_mulhrs_epi16(a.im.m128, _mm_slli_epi16(b.re.m128, 1))); +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ + return ret; +} + +static inline simd_c16_t srslte_simd_c16_add (simd_c16_t a, simd_c16_t b) { + simd_c16_t ret; +#ifdef LV_HAVE_AVX2 + ret.re.m256 = _mm256_add_epi16(a.re.m256, b.re.m256); + ret.im.m256 = _mm256_add_epi16(a.im.m256, b.im.m256); +#else +#ifdef LV_HAVE_SSE + ret.re.m128 = _mm_add_epi16(a.re.m128, b.re.m128); + ret.im.m128 = _mm_add_epi16(a.im.m128, b.im.m128); +#else +#ifdef HAVE_NEON + ret.m128.val[0] = vaddq_s16(a.m128.val[0],a.m128.val[0]); + ret.m128.val[1] = vaddq_s16(a.m128.val[1],a.m128.val[1]); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ + return ret; +} + +static inline simd_c16_t srslte_simd_c16_zero (void) { + simd_c16_t ret; +#ifdef LV_HAVE_AVX2 + ret.re.m256 = _mm256_setzero_si256(); + ret.im.m256 = _mm256_setzero_si256(); +#else +#ifdef LV_HAVE_SSE + ret.re.m128 = _mm_setzero_si128(); + ret.im.m128 = _mm_setzero_si128(); +#else +#ifdef HAVE_NEON + ret.m128.val[0] = vdupq_n_s16(0); + ret.m128.val[1] = vdupq_n_s16(0); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ + return ret; +} + +#endif /* SRSLTE_SIMD_C16_SIZE */ + +#if SRSLTE_SIMD_F_SIZE && SRSLTE_SIMD_S_SIZE + +static inline simd_s_t srslte_simd_convert_2f_s(simd_f_t a, simd_f_t b) { +#ifdef LV_HAVE_AVX512 + __m512 aa = _mm512_permutex2var_ps(a, _mm512_setr_epi32(0x00, 0x01, 0x02, 0x03, + 0x08, 0x09, 0x0A, 0x0B, + 0x10, 0x11, 0x12, 0x13, + 0x18, 0x19, 0x1A, 0x1B), b); + __m512 bb = _mm512_permutex2var_ps(a, _mm512_setr_epi32(0x04, 0x05, 0x06, 0x07, + 0x0C, 0x0D, 0x0E, 0x0F, + 0x14, 0x15, 0x16, 0x17, + 0x1C, 0x1D, 0x1E, 0x1F), b); + __m512i ai = _mm512_cvttps_epi32(aa); + __m512i bi = _mm512_cvttps_epi32(bb); + return _mm512_packs_epi32(ai, bi); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + __m256 aa = _mm256_permute2f128_ps(a, b, 0x20); + __m256 bb = _mm256_permute2f128_ps(a, b, 0x31); + __m256i ai = _mm256_cvttps_epi32(aa); + __m256i bi = _mm256_cvttps_epi32(bb); + return _mm256_packs_epi32(ai, bi); +#else +#ifdef LV_HAVE_SSE + __m128i ai = _mm_cvttps_epi32(a); + __m128i bi = _mm_cvttps_epi32(b); + return _mm_packs_epi32(ai, bi); + #else +#ifdef HAVE_NEON + int32x4_t ai = vcvtq_s32_f32(a); + int32x4_t bi = vcvtq_s32_f32(b); + return (simd_s_t)vcombine_s16(vqmovn_s32(ai), vqmovn_s32(bi)); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +#endif /* SRSLTE_SIMD_F_SIZE && SRSLTE_SIMD_C16_SIZE */ + +#if SRSLTE_SIMD_B_SIZE +/* Data types */ +#ifdef LV_HAVE_AVX512 +typedef __m512i simd_b_t; +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 +typedef __m256i simd_b_t; +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE +typedef __m128i simd_b_t; +#else /* HAVE_NEON */ +#ifdef HAVE_NEON +typedef int8x16_t simd_b_t; +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + + + +static inline simd_b_t srslte_simd_b_load(int8_t *ptr){ +#ifdef LV_HAVE_AVX512 + return _mm512_load_si512(ptr); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_load_si256((__m256i*) ptr); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_load_si128((__m128i*) ptr); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vld1q_s8(ptr); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_b_t srslte_simd_b_loadu(int8_t *ptr){ +#ifdef LV_HAVE_AVX512 + return _mm512_loadu_si512(ptr); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_loadu_si256((__m256i*) ptr); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_loadu_si128((__m128i*) ptr); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vld1q_s8(ptr); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline void srslte_simd_b_store(int8_t *ptr, simd_b_t simdreg) { +#ifdef LV_HAVE_AVX512 + _mm512_store_si512(ptr, simdreg); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + _mm256_store_si256((__m256i*) ptr, simdreg); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + _mm_store_si128((__m128i*) ptr, simdreg); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + vst1q_s8( ptr, simdreg); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline void srslte_simd_b_storeu(int8_t *ptr, simd_b_t simdreg) { +#ifdef LV_HAVE_AVX512 + _mm512_storeu_si512(ptr, simdreg); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + _mm256_storeu_si256((__m256i*) ptr, simdreg); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + _mm_storeu_si128((__m128i*) ptr, simdreg); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + vst1q_s8(ptr, simdreg); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + + +static inline simd_b_t srslte_simd_b_xor(simd_b_t a, simd_b_t b) { + +#ifdef LV_HAVE_AVX512 + return _mm512_xor_epi32(a, b); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_xor_si256(a, b); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_xor_si128 (a, b); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return veorq_s8(a, b); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +#endif /*SRSLTE_SIMD_B_SIZE */ + + #endif //SRSLTE_SIMD_H_H diff --git a/lib/include/srslte/phy/utils/vector.h b/lib/include/srslte/phy/utils/vector.h index 4a55d18b6..a4028e495 100644 --- a/lib/include/srslte/phy/utils/vector.h +++ b/lib/include/srslte/phy/utils/vector.h @@ -53,130 +53,102 @@ extern "C" { // Exponential moving average #define SRSLTE_VEC_EMA(data, average, alpha) ((alpha)*(data)+(1-alpha)*(average)) + +/*logical operations */ +SRSLTE_API void srslte_vec_xor_bbb(int8_t *x,int8_t *y,int8_t *z, const uint32_t len); + /** Return the sum of all the elements */ -SRSLTE_API int srslte_vec_acc_ii(int *x, uint32_t len); -SRSLTE_API float srslte_vec_acc_ff(float *x, uint32_t len); -SRSLTE_API cf_t srslte_vec_acc_cc(cf_t *x, uint32_t len); +SRSLTE_API float srslte_vec_acc_ff(const float *x, const uint32_t len); +SRSLTE_API cf_t srslte_vec_acc_cc(const cf_t *x, const uint32_t len); SRSLTE_API void *srslte_vec_malloc(uint32_t size); SRSLTE_API void *srslte_vec_realloc(void *ptr, uint32_t old_size, uint32_t new_size); /* print vectors */ -SRSLTE_API void srslte_vec_fprint_c(FILE *stream, cf_t *x, uint32_t len); -SRSLTE_API void srslte_vec_fprint_f(FILE *stream, float *x, uint32_t len); -SRSLTE_API void srslte_vec_fprint_b(FILE *stream, uint8_t *x, uint32_t len); -SRSLTE_API void srslte_vec_fprint_byte(FILE *stream, uint8_t *x, uint32_t len); -SRSLTE_API void srslte_vec_fprint_i(FILE *stream, int *x, uint32_t len); -SRSLTE_API void srslte_vec_fprint_s(FILE *stream, short *x, uint32_t len); -SRSLTE_API void srslte_vec_fprint_hex(FILE *stream, uint8_t *x, uint32_t len); -SRSLTE_API void srslte_vec_sprint_hex(char *str, uint8_t *x, uint32_t len); +SRSLTE_API void srslte_vec_fprint_c(FILE *stream, cf_t *x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_f(FILE *stream, float *x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_b(FILE *stream, uint8_t *x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_byte(FILE *stream, uint8_t *x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_i(FILE *stream, int *x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_s(FILE *stream, short *x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_hex(FILE *stream, uint8_t *x, const uint32_t len); +SRSLTE_API void srslte_vec_sprint_hex(char *str, uint8_t *x, const uint32_t len); /* Saves/loads a vector to a file */ -SRSLTE_API void srslte_vec_save_file(char *filename, void *buffer, uint32_t len); -SRSLTE_API void srslte_vec_load_file(char *filename, void *buffer, uint32_t len); +SRSLTE_API void srslte_vec_save_file(char *filename, const void *buffer, const uint32_t len); +SRSLTE_API void srslte_vec_load_file(char *filename, void *buffer, const uint32_t len); /* sum two vectors */ -SRSLTE_API void srslte_vec_sum_ch(uint8_t *x, uint8_t *y, char *z, uint32_t len); -SRSLTE_API void srslte_vec_sum_fff(float *x, float *y, float *z, uint32_t len); -SRSLTE_API void srslte_vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); -SRSLTE_API void srslte_vec_sub_sss(short *x, short *y, short *z, uint32_t len); -SRSLTE_API void srslte_vec_sum_sss(short *x, short *y, short *z, uint32_t len); +SRSLTE_API void srslte_vec_sum_fff(const float *x, const float *y, float *z, const uint32_t len); +SRSLTE_API void srslte_vec_sum_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_sub_sss(const int16_t *x, const int16_t *y, int16_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_sum_sss(const int16_t *x, const int16_t *y, int16_t *z, const uint32_t len); /* substract two vectors z=x-y */ -SRSLTE_API void srslte_vec_sub_fff(float *x, float *y, float *z, uint32_t len); -SRSLTE_API void srslte_vec_sub_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); - -/* EMA filter: output=coeff*new_data + (1-coeff)*average */ -SRSLTE_API void srslte_vec_ema_filter(cf_t *new_data, cf_t *average, cf_t *output, float coeff, uint32_t len); - -/* Square distance */ -SRSLTE_API void srslte_vec_square_dist(cf_t symbol, cf_t *points, float *distance, uint32_t npoints); - -/* scalar addition */ -SRSLTE_API void srslte_vec_sc_add_fff(float *x, float h, float *z, uint32_t len); -SRSLTE_API void srslte_vec_sc_add_cfc(cf_t *x, float h, cf_t *z, uint32_t len); -SRSLTE_API void srslte_vec_sc_add_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len); -SRSLTE_API void srslte_vec_sc_add_sss(int16_t *x, int16_t h, int16_t *z, uint32_t len); +SRSLTE_API void srslte_vec_sub_fff(const float *x, const float *y, float *z, const uint32_t len); +SRSLTE_API void srslte_vec_sub_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len); /* scalar product */ -SRSLTE_API void srslte_vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len); -SRSLTE_API void srslte_vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len); -SRSLTE_API void srslte_vec_sc_prod_fff(float *x, float h, float *z, uint32_t len); -SRSLTE_API void srslte_vec_sc_prod_sfs(short *x, float h, short *z, uint32_t len); -SRSLTE_API void srslte_vec_sc_div2_sss(short *x, int pow2_div, short *z, uint32_t len); +SRSLTE_API void srslte_vec_sc_prod_cfc(const cf_t *x, const float h, cf_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_sc_prod_ccc(const cf_t *x, const cf_t h, cf_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_sc_prod_fff(const float *x, const float h, float *z, const uint32_t len); -/* Normalization */ -SRSLTE_API void srslte_vec_norm_cfc(cf_t *x, float amplitude, cf_t *y, uint32_t len); -SRSLTE_API void srslte_vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len); -SRSLTE_API void srslte_vec_convert_if(int16_t *x, float *z, float scale, uint32_t len); -SRSLTE_API void srslte_vec_convert_ci(int8_t *x, int16_t *z, uint32_t len); +SRSLTE_API void srslte_vec_convert_fi(const float *x, const float scale, int16_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_convert_if(const int16_t *x, const float scale, float *z, const uint32_t len); -SRSLTE_API void srslte_vec_lut_fuf(float *x, uint32_t *lut, float *y, uint32_t len); -SRSLTE_API void srslte_vec_lut_sss(short *x, unsigned short *lut, short *y, uint32_t len); - -SRSLTE_API void srslte_vec_deinterleave_cf(cf_t *x, float *real, float *imag, uint32_t len); -SRSLTE_API void srslte_vec_deinterleave_real_cf(cf_t *x, float *real, uint32_t len); - -SRSLTE_API void srslte_vec_interleave_cf(float *real, float *imag, cf_t *x, uint32_t len); +SRSLTE_API void srslte_vec_lut_sss(const short *x, const unsigned short *lut, short *y, const uint32_t len); /* vector product (element-wise) */ -SRSLTE_API void srslte_vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); +SRSLTE_API void srslte_vec_prod_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_prod_ccc_split(const float *x_re, const float *x_im, const float *y_re, const float *y_im, float *z_re, float *z_im, const uint32_t len); /* vector product (element-wise) */ -SRSLTE_API void srslte_vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len); +SRSLTE_API void srslte_vec_prod_cfc(const cf_t *x, const float *y, cf_t *z, const uint32_t len); /* conjugate vector product (element-wise) */ -SRSLTE_API void srslte_vec_prod_conj_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); +SRSLTE_API void srslte_vec_prod_conj_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len); /* real vector product (element-wise) */ -SRSLTE_API void srslte_vec_prod_fff(float *x, float *y, float *z, uint32_t len); -SRSLTE_API void srslte_vec_prod_sss(short *x, short *y, short *z, uint32_t len); +SRSLTE_API void srslte_vec_prod_fff(const float *x, const float *y, float *z, const uint32_t len); +SRSLTE_API void srslte_vec_prod_sss(const int16_t *x, const int16_t *y, int16_t *z, const uint32_t len); /* Dot-product */ -SRSLTE_API cf_t srslte_vec_dot_prod_cfc(cf_t *x, float *y, uint32_t len); -SRSLTE_API cf_t srslte_vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len); -SRSLTE_API cf_t srslte_vec_dot_prod_conj_ccc(cf_t *x, cf_t *y, uint32_t len); -SRSLTE_API float srslte_vec_dot_prod_fff(float *x, float *y, uint32_t len); -SRSLTE_API int32_t srslte_vec_dot_prod_sss(int16_t *x, int16_t *y, uint32_t len); +SRSLTE_API cf_t srslte_vec_dot_prod_cfc(const cf_t *x, const float *y, const uint32_t len); +SRSLTE_API cf_t srslte_vec_dot_prod_ccc(const cf_t *x, const cf_t *y, const uint32_t len); +SRSLTE_API cf_t srslte_vec_dot_prod_conj_ccc(const cf_t *x, const cf_t *y, const uint32_t len); +SRSLTE_API float srslte_vec_dot_prod_fff(const float *x, const float *y, const uint32_t len); +SRSLTE_API int32_t srslte_vec_dot_prod_sss(const int16_t *x, const int16_t *y, const uint32_t len); /* z=x/y vector division (element-wise) */ -SRSLTE_API void srslte_vec_div_ccc(cf_t *x, cf_t *y, float *y_mod, cf_t *z, float *z_real, float *z_imag, uint32_t len); -void srslte_vec_div_cfc(cf_t *x, float *y, cf_t *z, float *z_real, float *z_imag, uint32_t len); -SRSLTE_API void srslte_vec_div_fff(float *x, float *y, float *z, uint32_t len); +SRSLTE_API void srslte_vec_div_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_div_cfc(const cf_t *x, const float *y, cf_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_div_fff(const float *x, const float *y, float *z, const uint32_t len); /* conjugate */ -SRSLTE_API void srslte_vec_conj_cc(cf_t *x, cf_t *y, uint32_t len); +SRSLTE_API void srslte_vec_conj_cc(const cf_t *x, cf_t *y, const uint32_t len); /* average vector power */ -SRSLTE_API float srslte_vec_avg_power_cf(cf_t *x, uint32_t len); +SRSLTE_API float srslte_vec_avg_power_cf(const cf_t *x, const uint32_t len); /* Correlation between complex vectors x and y */ -SRSLTE_API float srslte_vec_corr_ccc(cf_t *x, cf_t *y, uint32_t len); +SRSLTE_API float srslte_vec_corr_ccc(const cf_t *x, cf_t *y, const uint32_t len); /* return the index of the maximum value in the vector */ -SRSLTE_API uint32_t srslte_vec_max_fi(float *x, uint32_t len); -SRSLTE_API uint32_t srslte_vec_max_abs_ci(cf_t *x, uint32_t len); -SRSLTE_API int16_t srslte_vec_max_star_si(int16_t *x, uint32_t len); -SRSLTE_API int16_t srslte_vec_max_abs_star_si(int16_t *x, uint32_t len); - -/* maximum between two vectors */ -SRSLTE_API void srslte_vec_max_fff(float *x, float *y, float *z, uint32_t len); +SRSLTE_API uint32_t srslte_vec_max_fi(const float *x, const uint32_t len); +SRSLTE_API uint32_t srslte_vec_max_abs_ci(const cf_t *x, const uint32_t len); /* quantify vector of floats or int16 and convert to uint8_t */ -SRSLTE_API void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, float clip, uint32_t len); -SRSLTE_API void srslte_vec_quant_suc(int16_t *in, uint8_t *out, float gain, int16_t offset, int16_t clip, uint32_t len); +SRSLTE_API void srslte_vec_quant_fuc(const float *in, uint8_t *out, const float gain, const float offset, const float clip, const uint32_t len); +SRSLTE_API void srslte_vec_quant_suc(const int16_t *in, uint8_t *out, const float gain, const int16_t offset, const int16_t clip, const uint32_t len); /* magnitude of each vector element */ -SRSLTE_API void srslte_vec_abs_cf(cf_t *x, float *abs, uint32_t len); -SRSLTE_API void srslte_vec_abs_square_cf(cf_t *x, float *abs_square, uint32_t len); - -/* argument of each vector element */ -SRSLTE_API void srslte_vec_arg_cf(cf_t *x, float *arg, uint32_t len); +SRSLTE_API void srslte_vec_abs_cf(const cf_t *x, float *abs, const uint32_t len); +SRSLTE_API void srslte_vec_abs_square_cf(const cf_t *x, float *abs_square, const uint32_t len); /* Copy 256 bit aligned vector */ -SRSLTE_API void srs_vec_cf_cpy(cf_t *src, cf_t *dst, int len); +SRSLTE_API void srs_vec_cf_cpy(const cf_t *src, cf_t *dst, const int len); #ifdef __cplusplus } diff --git a/lib/include/srslte/phy/utils/vector_simd.h b/lib/include/srslte/phy/utils/vector_simd.h index 1894a0803..54ac55f98 100644 --- a/lib/include/srslte/phy/utils/vector_simd.h +++ b/lib/include/srslte/phy/utils/vector_simd.h @@ -35,32 +35,99 @@ extern "C" { #include #include "srslte/config.h" -SRSLTE_API int srslte_vec_dot_prod_sss_sse(short *x, short *y, uint32_t len); - -SRSLTE_API int srslte_vec_dot_prod_sss_avx2(short *x, short *y, uint32_t len); - -SRSLTE_API void srslte_vec_sum_sss_sse(short *x, short *y, short *z, uint32_t len); - -SRSLTE_API void srslte_vec_sum_sss_avx2(short *x, short *y, short *z, uint32_t len); - -SRSLTE_API void srslte_vec_sub_sss_sse(short *x, short *y, short *z, uint32_t len); - -SRSLTE_API void srslte_vec_sub_sss_avx2(short *x, short *y, short *z, uint32_t len); - -SRSLTE_API void srslte_vec_prod_sss_sse(short *x, short *y, short *z, uint32_t len); - -SRSLTE_API void srslte_vec_prod_sss_avx2(short *x, short *y, short *z, uint32_t len); +#ifdef LV_HAVE_AVX512 +#define SRSLTE_SIMD_BIT_ALIGN 512 +#define SRSLTE_IS_ALIGNED(PTR) (((size_t)(PTR) & 0x3F) == 0) +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX +#define SRSLTE_SIMD_BIT_ALIGN 256 +#define SRSLTE_IS_ALIGNED(PTR) (((size_t)(PTR) & 0x1F) == 0) +#else /* LV_HAVE_AVX */ +#ifdef LV_HAVE_SSE +#define SRSLTE_SIMD_BIT_ALIGN 128 +#define SRSLTE_IS_ALIGNED(PTR) (((size_t)(PTR) & 0x0F) == 0) +#else /* LV_HAVE_SSE */ +#define SRSLTE_SIMD_BIT_ALIGN 64 +#define SRSLTE_IS_ALIGNED(PTR) (1) +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX */ +#endif /* LV_HAVE_AVX512 */ -SRSLTE_API void srslte_vec_sc_div2_sss_sse(short *x, int n_rightshift, short *z, uint32_t len); +/*SIMD Logical operations*/ +SRSLTE_API void srslte_vec_xor_bbb_simd(const int8_t *x, const int8_t *y, int8_t *z, int len); -SRSLTE_API void srslte_vec_sc_div2_sss_avx2(short *x, int k, short *z, uint32_t len); +/* SIMD Basic vector math */ +SRSLTE_API void srslte_vec_sum_sss_simd(const int16_t *x, const int16_t *y, int16_t *z, int len); -SRSLTE_API void srslte_vec_lut_sss_sse(short *x, unsigned short *lut, short *y, uint32_t len); +SRSLTE_API void srslte_vec_sub_sss_simd(const int16_t *x, const int16_t *y, int16_t *z, int len); -SRSLTE_API void srslte_vec_convert_fi_sse(float *x, int16_t *z, float scale, uint32_t len); +SRSLTE_API float srslte_vec_acc_ff_simd(const float *x, int len); + +SRSLTE_API cf_t srslte_vec_acc_cc_simd(const cf_t *x, int len); + +SRSLTE_API void srslte_vec_add_fff_simd(const float *x, const float *y, float *z, int len); + +SRSLTE_API void srslte_vec_sub_fff_simd(const float *x, const float *y, float *z, int len); + +/* SIMD Vector Scalar Product */ +SRSLTE_API void srslte_vec_sc_prod_cfc_simd(const cf_t *x, const float h,cf_t *y, const int len); + +SRSLTE_API void srslte_vec_sc_prod_fff_simd(const float *x, const float h, float *z, const int len); + +SRSLTE_API void srslte_vec_sc_prod_ccc_simd(const cf_t *x, const cf_t h, cf_t *z, const int len); + +/* SIMD Vector Product */ +SRSLTE_API void srslte_vec_prod_ccc_split_simd(const float *a_re, const float *a_im, const float *b_re, const float *b_im, + float *r_re, float *r_im, const int len); + +SRSLTE_API void srslte_vec_prod_ccc_c16_simd(const int16_t *a_re, const int16_t *a_im, const int16_t *b_re, const int16_t *b_im, + int16_t *r_re, int16_t *r_im, const int len); + +SRSLTE_API void srslte_vec_prod_sss_simd(const int16_t *x, const int16_t *y, int16_t *z, const int len); + +SRSLTE_API void srslte_vec_prod_cfc_simd(const cf_t *x, const float *y, cf_t *z, const int len); + +SRSLTE_API void srslte_vec_prod_fff_simd(const float *x, const float *y, float *z, const int len); + +SRSLTE_API void srslte_vec_prod_ccc_simd(const cf_t *x, const cf_t *y, cf_t *z, const int len); + +SRSLTE_API void srslte_vec_prod_conj_ccc_simd(const cf_t *x, const cf_t *y, cf_t *z, const int len); + +/* SIMD Division */ +SRSLTE_API void srslte_vec_div_ccc_simd(const cf_t *x, const cf_t *y, cf_t *z, const int len); + +SRSLTE_API void srslte_vec_div_cfc_simd(const cf_t *x, const float *y, cf_t *z, const int len); + +SRSLTE_API void srslte_vec_div_fff_simd(const float *x, const float *y, float *z, const int len); + +/* SIMD Dot product */ +SRSLTE_API cf_t srslte_vec_dot_prod_conj_ccc_simd(const cf_t *x, const cf_t *y, const int len); + +SRSLTE_API cf_t srslte_vec_dot_prod_ccc_simd(const cf_t *x, const cf_t *y, const int len); + +SRSLTE_API c16_t srslte_vec_dot_prod_ccc_c16i_simd(const c16_t *x, const c16_t *y, const int len); + +SRSLTE_API int srslte_vec_dot_prod_sss_simd(const int16_t *x, const int16_t *y, const int len); + +/* SIMD Modulus functions */ +SRSLTE_API void srslte_vec_abs_cf_simd(const cf_t *x, float *z, const int len); + +SRSLTE_API void srslte_vec_abs_square_cf_simd(const cf_t *x, float *z, const int len); + +/* Other Functions */ +SRSLTE_API void srslte_vec_lut_sss_simd(const short *x, const unsigned short *lut, short *y, const int len); + +SRSLTE_API void srslte_vec_convert_fi_simd(const float *x, int16_t *z, const float scale, const int len); + +SRSLTE_API void srslte_vec_cp_simd(const cf_t *src, cf_t *dst, int len); + + +/* SIMD Find Max functions */ +SRSLTE_API uint32_t srslte_vec_max_fi_simd(const float *x, const int len); + +SRSLTE_API uint32_t srslte_vec_max_ci_simd(const cf_t *x, const int len); -SRSLTE_API void srslte_vec_sc_prod_cfc_avx(const cf_t *x,const float h,cf_t *y,const uint32_t len); #ifdef __cplusplus } #endif diff --git a/lib/include/srslte/radio/radio.h b/lib/include/srslte/radio/radio.h index 329dd825a..6ff0c5100 100644 --- a/lib/include/srslte/radio/radio.h +++ b/lib/include/srslte/radio/radio.h @@ -74,7 +74,7 @@ namespace srslte { agc_enabled = false; }; - bool init(char *args = NULL, char *devname = NULL); + bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1); void stop(); void reset(); bool start_agc(bool tx_gain_same_rx); @@ -86,9 +86,10 @@ namespace srslte { void set_manual_calibration(rf_cal_t *calibration); void get_time(srslte_timestamp_t *now); - bool tx(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); + bool tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); + bool tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time); void tx_end(); - bool rx_now(void *buffer, uint32_t nof_samples, srslte_timestamp_t *rxd_time); + bool rx_now(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time); bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time); void set_tx_gain(float gain); @@ -117,7 +118,7 @@ namespace srslte { void start_trace(); void write_trace(std::string filename); - void start_rx(); + void start_rx(bool now = false); void stop_rx(); void set_tti(uint32_t tti); @@ -166,6 +167,7 @@ namespace srslte { uint32_t tti; bool agc_enabled; + uint32_t saved_nof_channels; char saved_args[128]; char saved_devname[128]; diff --git a/lib/include/srslte/srslte.h b/lib/include/srslte/srslte.h index f44f5325d..36af629d7 100644 --- a/lib/include/srslte/srslte.h +++ b/lib/include/srslte/srslte.h @@ -39,6 +39,7 @@ #include "srslte/version.h" #include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/ringbuffer.h" #include "srslte/phy/utils/convolution.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/cexptab.h" @@ -47,6 +48,7 @@ #include "srslte/phy/common/timestamp.h" #include "srslte/phy/common/sequence.h" #include "srslte/phy/common/phy_common.h" +#include "srslte/phy/common/phy_logger.h" #include "srslte/phy/ch_estimation/chest_ul.h" #include "srslte/phy/ch_estimation/chest_dl.h" diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index ce6ece151..584b231a3 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -54,14 +54,21 @@ public: bool is_drb_enabled(uint32_t lcid); // RRC interface + void reestablish(); void reset(); void write_sdu(uint32_t lcid, byte_buffer_t *sdu); void add_bearer(uint32_t lcid, srslte_pdcp_config_t cnfg = srslte_pdcp_config_t()); void config_security(uint32_t lcid, - uint8_t *k_rrc_enc, - uint8_t *k_rrc_int, + uint8_t *k_enc, + uint8_t *k_int, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + void config_security_all(uint8_t *k_enc, + uint8_t *k_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + void enable_integrity(uint32_t lcid); + void enable_encryption(uint32_t lcid); // RLC interface void write_pdu(uint32_t lcid, byte_buffer_t *sdu); diff --git a/lib/include/srslte/upper/pdcp_entity.h b/lib/include/srslte/upper/pdcp_entity.h index 0ff005d07..186da3767 100644 --- a/lib/include/srslte/upper/pdcp_entity.h +++ b/lib/include/srslte/upper/pdcp_entity.h @@ -32,6 +32,8 @@ #include "srslte/common/common.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/security.h" +#include "srslte/common/msg_queue.h" +#include "srslte/common/threads.h" namespace srslte { @@ -59,6 +61,7 @@ static const char pdcp_d_c_text[PDCP_D_C_N_ITEMS][20] = {"Control PDU", * Common interface for all PDCP entities ***************************************************************************/ class pdcp_entity + :public thread { public: pdcp_entity(); @@ -68,16 +71,20 @@ public: srslte::log *log_, uint32_t lcid_, srslte_pdcp_config_t cfg_); + void stop(); void reset(); + void reestablish(); bool is_active(); // RRC interface void write_sdu(byte_buffer_t *sdu); - void config_security(uint8_t *k_rrc_enc_, - uint8_t *k_rrc_int_, + void config_security(uint8_t *k_enc_, + uint8_t *k_int_, CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, INTEGRITY_ALGORITHM_ID_ENUM integ_algo_); + void enable_integrity(); + void enable_encryption(); // RLC interface void write_pdu(byte_buffer_t *pdu); @@ -90,26 +97,46 @@ private: srsue::rrc_interface_pdcp *rrc; srsue::gw_interface_pdcp *gw; + static const int PDCP_THREAD_PRIO = 7; + srslte::msg_queue rx_pdu_queue; + bool running; + bool active; uint32_t lcid; srslte_pdcp_config_t cfg; + uint8_t sn_len_bytes; + bool do_integrity; + bool do_encryption; uint32_t rx_count; uint32_t tx_count; - uint8_t k_rrc_enc[32]; - uint8_t k_rrc_int[32]; + uint8_t k_enc[32]; + uint8_t k_int[32]; CIPHERING_ALGORITHM_ID_ENUM cipher_algo; INTEGRITY_ALGORITHM_ID_ENUM integ_algo; - void integrity_generate(uint8_t *key_128, - uint32_t count, - uint8_t rb_id, - uint8_t direction, - uint8_t *msg, + void integrity_generate(uint8_t *msg, uint32_t msg_len, uint8_t *mac); + bool integrity_verify(uint8_t *msg, + uint32_t count, + uint32_t msg_len, + uint8_t *mac); + + void cipher_encrypt(uint8_t *msg, + uint32_t msg_len, + uint8_t *ct); + + void cipher_decrypt(uint8_t *ct, + uint32_t count, + uint32_t ct_len, + uint8_t *msg); + + void run_thread(); + + uint8_t get_bearer_id(uint8_t lcid); }; /**************************************************************************** diff --git a/lib/include/srslte/upper/rlc.h b/lib/include/srslte/upper/rlc.h index 349a7952d..17f6bd82c 100644 --- a/lib/include/srslte/upper/rlc.h +++ b/lib/include/srslte/upper/rlc.h @@ -64,7 +64,8 @@ public: // PDCP interface void write_sdu(uint32_t lcid, byte_buffer_t *sdu); - std::string get_rb_name(uint32_t lcid); + + bool rb_is_um(uint32_t lcid); // MAC interface uint32_t get_buffer_state(uint32_t lcid); @@ -76,6 +77,7 @@ public: void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes); // RRC interface + void reestablish(); void reset(); void empty_queue(); void add_bearer(uint32_t lcid); diff --git a/lib/include/srslte/upper/rlc_am.h b/lib/include/srslte/upper/rlc_am.h index afbd18544..c0289956c 100644 --- a/lib/include/srslte/upper/rlc_am.h +++ b/lib/include/srslte/upper/rlc_am.h @@ -78,6 +78,7 @@ public: mac_interface_timers *mac_timers); void configure(srslte_rlc_config_t cnfg); void reset(); + void reestablish(); void stop(); void empty_queue(); @@ -163,6 +164,8 @@ private: static const int reordering_timeout_id = 1; + static const int poll_periodicity = 8; // After how many data PDUs a status PDU shall be requested + // Timer checks bool status_prohibited(); bool poll_retx(); diff --git a/lib/include/srslte/upper/rlc_entity.h b/lib/include/srslte/upper/rlc_entity.h index e9c41fa30..de4a396fe 100644 --- a/lib/include/srslte/upper/rlc_entity.h +++ b/lib/include/srslte/upper/rlc_entity.h @@ -56,6 +56,7 @@ public: void configure(srslte_rlc_config_t cnfg); void reset(); + void reestablish(); void stop(); void empty_queue(); bool active(); diff --git a/lib/src/asn1/liblte_mme.cc b/lib/src/asn1/liblte_mme.cc index 54c6eb5ba..ea7729519 100644 --- a/lib/src/asn1/liblte_mme.cc +++ b/lib/src/asn1/liblte_mme.cc @@ -1411,9 +1411,9 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_eps_mobile_id_ie(LIBLTE_MME_EPS_MOBILE_ID_STRU **ie_ptr = (((eps_mobile_id->guti.mnc/10) % 10) << 4) | ((eps_mobile_id->guti.mnc/100) % 10); *ie_ptr += 1; } - **ie_ptr = (eps_mobile_id->guti.mme_group_id >> 8) & 0x0F; + **ie_ptr = (eps_mobile_id->guti.mme_group_id >> 8) & 0xFF; *ie_ptr += 1; - **ie_ptr = eps_mobile_id->guti.mme_group_id & 0x0F; + **ie_ptr = eps_mobile_id->guti.mme_group_id & 0xFF; *ie_ptr += 1; **ie_ptr = eps_mobile_id->guti.mme_code; *ie_ptr += 1; @@ -4922,6 +4922,32 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_transaction_identifier_ie(uint8 MESSAGE FUNCTIONS *******************************************************************************/ +/********************************************************************* + Message Name: Security Message Header (Plain NAS Message) + + Description: Security header for NAS messages. + + Document Reference: 24.301 v10.2.0 Section 9.1 +*********************************************************************/ + +LIBLTE_ERROR_ENUM liblte_mme_parse_msg_sec_header(LIBLTE_BYTE_MSG_STRUCT *msg, + uint8 *pd, + uint8 *sec_hdr_type) +{ + + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if (msg != NULL && + pd != NULL && + sec_hdr_type != NULL) + { + *sec_hdr_type = (uint8) ((msg->msg[0] & 0xF0) >> 4); + err = LIBLTE_SUCCESS; + } + return(err); +} + + /********************************************************************* Message Name: Message Header (Plain NAS Message) @@ -5518,6 +5544,14 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_reject_msg(LIBLTE_BYTE_MSG_STRUCT *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req, LIBLTE_BYTE_MSG_STRUCT *msg) +{ + return liblte_mme_pack_attach_request_msg(attach_req, LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS, 0, msg); +} + +LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8 *msg_ptr = msg->msg; @@ -5525,6 +5559,20 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_M if(attach_req != NULL && msg != NULL) { + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) + { + // Protocol Discriminator and Security Header Type + *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg_ptr++; + + // MAC will be filled in later + msg_ptr += 4; + + // Sequence Number + *msg_ptr = count & 0xFF; + msg_ptr++; + } + // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; diff --git a/lib/src/asn1/liblte_rrc.cc b/lib/src/asn1/liblte_rrc.cc index e4621994e..c53399384 100644 --- a/lib/src/asn1/liblte_rrc.cc +++ b/lib/src/asn1/liblte_rrc.cc @@ -4764,6 +4764,9 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_plmn_identity_ie(LIBLTE_RRC_PLMN_IDENTITY_STRU if(plmn_id != NULL && ie_ptr != NULL) { + if(0xFFFF == plmn_id->mcc) { + mcc_opt = false; + } liblte_value_2_bits(mcc_opt, ie_ptr, 1); if(true == mcc_opt) @@ -12754,7 +12757,241 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_paging_msg(LIBLTE_BIT_MSG_STRUCT *msg, Document Reference: 36.331 v10.0.0 Section 6.2.2 *********************************************************************/ -// FIXME +LIBLTE_ERROR_ENUM liblte_rrc_pack_cgi_info_ie(LIBLTE_RRC_CGI_INFO_STRUCT *cgi_info, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(cgi_info != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(cgi_info->have_plmn_identity_list, ie_ptr, 1); + liblte_rrc_pack_cell_global_id_eutra_ie(&cgi_info->cell_global_id, ie_ptr); + liblte_rrc_pack_tracking_area_code_ie(cgi_info->tracking_area_code, ie_ptr); + if(cgi_info->have_plmn_identity_list) { + liblte_value_2_bits(cgi_info->n_plmn_identity_list-1, ie_ptr, 3); + for(uint32 i=0; in_plmn_identity_list; i++) { + liblte_rrc_pack_plmn_identity_ie(&cgi_info->plmn_identity_list[i], ie_ptr); + } + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_cgi_info_ie(uint8 **ie_ptr, + LIBLTE_RRC_CGI_INFO_STRUCT *cgi_info) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + cgi_info != NULL) + { + cgi_info->have_plmn_identity_list = (bool)liblte_bits_2_value(ie_ptr, 1); + liblte_rrc_unpack_cell_global_id_eutra_ie(ie_ptr, &cgi_info->cell_global_id); + liblte_rrc_unpack_tracking_area_code_ie(ie_ptr, &cgi_info->tracking_area_code); + if(cgi_info->have_plmn_identity_list) { + cgi_info->n_plmn_identity_list = liblte_bits_2_value(ie_ptr, 3) + 1; + for(uint32 i=0; in_plmn_identity_list; i++) { + liblte_rrc_unpack_plmn_identity_ie(ie_ptr, &cgi_info->plmn_identity_list[i]); + } + } + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_result_ie(LIBLTE_RRC_MEAS_RESULT_STRUCT *meas_result, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(meas_result != NULL && + ie_ptr != NULL) + { + //ext + liblte_value_2_bits(0, ie_ptr, 1); + + //options + liblte_value_2_bits(meas_result->have_rsrp, ie_ptr, 1); + liblte_value_2_bits(meas_result->have_rsrq, ie_ptr, 1); + + if(meas_result->have_rsrp) { + liblte_rrc_pack_rsrp_range_ie(meas_result->rsrp_result, ie_ptr); + } + if(meas_result->have_rsrq) { + liblte_rrc_pack_rsrq_range_ie(meas_result->rsrq_result, ie_ptr); + } + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_result_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_RESULT_STRUCT *meas_result) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + meas_result != NULL) + { + //ext + bool ext = liblte_bits_2_value(ie_ptr, 1); + + //options + meas_result->have_rsrp = liblte_bits_2_value(ie_ptr, 1); + meas_result->have_rsrq = liblte_bits_2_value(ie_ptr, 1); + + if(meas_result->have_rsrp) { + liblte_rrc_unpack_rsrp_range_ie(ie_ptr, &meas_result->rsrp_result); + } + if(meas_result->have_rsrq) { + liblte_rrc_unpack_rsrq_range_ie(ie_ptr, &meas_result->rsrq_result); + } + + //skip extensions + liblte_rrc_consume_noncrit_extension(ext, __func__, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_pack_meas_result_eutra_ie(LIBLTE_RRC_MEAS_RESULT_EUTRA_STRUCT *meas_result_eutra, + uint8 **ie_ptr) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(meas_result_eutra != NULL && + ie_ptr != NULL) + { + liblte_value_2_bits(meas_result_eutra->have_cgi_info, ie_ptr, 1); + liblte_rrc_pack_phys_cell_id_ie(meas_result_eutra->phys_cell_id, ie_ptr); + if(meas_result_eutra->have_cgi_info) { + liblte_rrc_pack_cgi_info_ie(&meas_result_eutra->cgi_info, ie_ptr); + } + liblte_rrc_pack_meas_result_ie(&meas_result_eutra->meas_result, ie_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_meas_result_eutra_ie(uint8 **ie_ptr, + LIBLTE_RRC_MEAS_RESULT_EUTRA_STRUCT *meas_result_eutra) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + + if(ie_ptr != NULL && + meas_result_eutra != NULL) + { + meas_result_eutra->have_cgi_info = liblte_bits_2_value(ie_ptr, 1); + liblte_rrc_unpack_phys_cell_id_ie(ie_ptr, &meas_result_eutra->phys_cell_id); + if(meas_result_eutra->have_cgi_info) { + liblte_rrc_unpack_cgi_info_ie(ie_ptr, &meas_result_eutra->cgi_info); + } + liblte_rrc_unpack_meas_result_ie(ie_ptr, &meas_result_eutra->meas_result); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +LIBLTE_ERROR_ENUM liblte_rrc_pack_measurement_report_msg(LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *meas_report, + LIBLTE_BIT_MSG_STRUCT *msg) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(meas_report != NULL && + msg != NULL) + { + //MeasurementReport + liblte_value_2_bits(0, &msg_ptr, 1); //critical extensions + liblte_value_2_bits(0, &msg_ptr, 3); //c1 + + //MeasurementReport-r8-IEs + liblte_value_2_bits(0, &msg_ptr, 1); //non-critical extensions + + //MeasResults + liblte_value_2_bits(0, &msg_ptr, 1); //ext + liblte_value_2_bits(meas_report->have_meas_result_neigh_cells, &msg_ptr, 1); + liblte_rrc_pack_meas_id_ie(meas_report->meas_id, &msg_ptr); + liblte_rrc_pack_rsrp_range_ie(meas_report->pcell_rsrp_result, &msg_ptr); + liblte_rrc_pack_rsrq_range_ie(meas_report->pcell_rsrq_result, &msg_ptr); + if(meas_report->have_meas_result_neigh_cells) { + liblte_value_2_bits(0, &msg_ptr, 1); //choice from before extension marker + liblte_value_2_bits(meas_report->meas_result_neigh_cells_choice, &msg_ptr, 2); + if(meas_report->meas_result_neigh_cells_choice != LIBLTE_RRC_MEAS_RESULT_LIST_EUTRA) { + printf("NOT HANDLING %s\n", liblte_rrc_meas_reult_neigh_cells_text[meas_report->meas_result_neigh_cells_choice]); + } else { + //MeasResultListEUTRA + liblte_value_2_bits(meas_report->meas_result_neigh_cells.eutra.n_result-1, &msg_ptr, 3); + for(uint32 i=0; imeas_result_neigh_cells.eutra.n_result; i++) { + liblte_rrc_pack_meas_result_eutra_ie(&meas_report->meas_result_neigh_cells.eutra.result_eutra_list[i], &msg_ptr); + } + } + } + + // Fill in the number of bits used + msg->N_bits = msg_ptr - msg->msg; + + err = LIBLTE_SUCCESS; + } + + return(err); +} +LIBLTE_ERROR_ENUM liblte_rrc_unpack_measurement_report_msg(LIBLTE_BIT_MSG_STRUCT *msg, + LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *meas_report) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 *msg_ptr = msg->msg; + + if(msg != NULL && + meas_report != NULL) + { + //MeasurementReport + bool crit_ext = liblte_bits_2_value(&msg_ptr, 1); //critical extensions + liblte_bits_2_value(&msg_ptr, 3); //c1 + + //MeasurementReport-r8-IEs + bool non_crit_ext = liblte_bits_2_value(&msg_ptr, 1); //non-critical extensions + + //MeasResults + bool ext = liblte_bits_2_value(&msg_ptr, 1); + meas_report->have_meas_result_neigh_cells = liblte_bits_2_value(&msg_ptr, 1); + liblte_rrc_unpack_meas_id_ie(&msg_ptr, &meas_report->meas_id); + liblte_rrc_unpack_rsrp_range_ie(&msg_ptr, &meas_report->pcell_rsrp_result); + liblte_rrc_unpack_rsrq_range_ie(&msg_ptr, &meas_report->pcell_rsrq_result); + if(meas_report->have_meas_result_neigh_cells) { + liblte_bits_2_value(&msg_ptr, 1); //choice from before extension marker + meas_report->meas_result_neigh_cells_choice = (LIBLTE_RRC_MEAS_RESULT_NEIGH_CELLS_ENUM) liblte_bits_2_value(&msg_ptr, 2); + if(meas_report->meas_result_neigh_cells_choice != LIBLTE_RRC_MEAS_RESULT_LIST_EUTRA) { + printf("NOT HANDLING %s\n", liblte_rrc_meas_reult_neigh_cells_text[meas_report->meas_result_neigh_cells_choice]); + } else { + //MeasResultListEUTRA + meas_report->meas_result_neigh_cells.eutra.n_result = liblte_bits_2_value(&msg_ptr, 3) + 1; + for(uint32 i=0; imeas_result_neigh_cells.eutra.n_result; i++) { + liblte_rrc_unpack_meas_result_eutra_ie(&msg_ptr, &meas_report->meas_result_neigh_cells.eutra.result_eutra_list[i]); + } + } + } + + //skip extensions + liblte_rrc_consume_noncrit_extension(crit_ext, __func__, &msg_ptr); + liblte_rrc_consume_noncrit_extension(non_crit_ext, __func__, &msg_ptr); + liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} /********************************************************************* Message Name: MBSFN Area Configuration @@ -13550,9 +13787,8 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_ul_dcch_msg(LIBLTE_RRC_UL_DCCH_MSG_STRUCT *ul_ err = liblte_rrc_pack_csfb_parameters_request_cdma2000_msg((LIBLTE_RRC_CSFB_PARAMETERS_REQUEST_CDMA2000_STRUCT *)&ul_dcch_msg->msg, &global_msg); }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_MEASUREMENT_REPORT == ul_dcch_msg->msg_type){ - printf("NOT HANDLING MEASUREMENT REPORT\n"); -// err = liblte_rrc_pack_measurement_report_msg((LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *)&ul_dcch_msg->msg, -// &global_msg); + err = liblte_rrc_pack_measurement_report_msg((LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *)&ul_dcch_msg->msg, + &global_msg); }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_RECONFIG_COMPLETE == ul_dcch_msg->msg_type){ err = liblte_rrc_pack_rrc_connection_reconfiguration_complete_msg((LIBLTE_RRC_CONNECTION_RECONFIGURATION_COMPLETE_STRUCT *)&ul_dcch_msg->msg, &global_msg); @@ -13630,9 +13866,8 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_ul_dcch_msg(LIBLTE_BIT_MSG_STRUCT *m err = liblte_rrc_unpack_csfb_parameters_request_cdma2000_msg(&global_msg, (LIBLTE_RRC_CSFB_PARAMETERS_REQUEST_CDMA2000_STRUCT *)&ul_dcch_msg->msg); }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_MEASUREMENT_REPORT == ul_dcch_msg->msg_type){ - printf("NOT HANDLING MEASUREMENT REPORT\n"); -// err = liblte_rrc_unpack_measurement_report_msg(&global_msg, -// (LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *)&ul_dcch_msg->msg); + err = liblte_rrc_unpack_measurement_report_msg(&global_msg, + (LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *)&ul_dcch_msg->msg); }else if(LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_RECONFIG_COMPLETE == ul_dcch_msg->msg_type){ err = liblte_rrc_unpack_rrc_connection_reconfiguration_complete_msg(&global_msg, (LIBLTE_RRC_CONNECTION_RECONFIGURATION_COMPLETE_STRUCT *)&ul_dcch_msg->msg); diff --git a/lib/src/common/CMakeLists.txt b/lib/src/common/CMakeLists.txt index 723085e24..010f8f730 100644 --- a/lib/src/common/CMakeLists.txt +++ b/lib/src/common/CMakeLists.txt @@ -22,7 +22,9 @@ file(GLOB CXX_SOURCES "*.cc") file(GLOB C_SOURCES "*.c") add_library(srslte_common STATIC ${C_SOURCES} ${CXX_SOURCES}) +add_custom_target(gen_build_info COMMAND cmake -P ${CMAKE_BINARY_DIR}/SRSLTEbuildinfo.cmake) +add_dependencies(srslte_common gen_build_info) + target_include_directories(srslte_common PUBLIC ${SEC_INCLUDE_DIRS}) target_link_libraries(srslte_common ${SEC_LIBRARIES}) install(TARGETS srslte_common DESTINATION ${LIBRARY_DIR}) - diff --git a/lib/src/common/liblte_security.cc b/lib/src/common/liblte_security.cc index 95f9617cd..1cf83e5b3 100644 --- a/lib/src/common/liblte_security.cc +++ b/lib/src/common/liblte_security.cc @@ -55,6 +55,11 @@ typedef struct{ uint8 state[4][4]; }STATE_STRUCT; +typedef struct{ + uint32 * lfsr; + uint32 * fsm; +}S3G_STATE; + /******************************************************************************* GLOBAL VARIABLES *******************************************************************************/ @@ -76,6 +81,35 @@ static const uint8 S[256] = { 99,124,119,123,242,107,111,197, 48, 1,103, 43,254 225,248,152, 17,105,217,142,148,155, 30,135,233,206, 85, 40,223, 140,161,137, 13,191,230, 66,104, 65,153, 45, 15,176, 84,187, 22}; +/* S-box SQ */ +static const uint8 SQ[256] = { 0x25, 0x24, 0x73, 0x67, 0xD7, 0xAE, + 0x5C, 0x30, 0xA4, 0xEE, 0x6E, 0xCB, 0x7D, 0xB5, 0x82, 0xDB, + 0xE4, 0x8E, 0x48, 0x49, 0x4F, 0x5D, 0x6A, 0x78, 0x70, 0x88, + 0xE8, 0x5F, 0x5E, 0x84, 0x65, 0xE2, 0xD8, 0xE9, 0xCC, 0xED, + 0x40, 0x2F, 0x11, 0x28, 0x57, 0xD2, 0xAC, 0xE3, 0x4A, 0x15, + 0x1B, 0xB9, 0xB2, 0x80, 0x85, 0xA6, 0x2E, 0x02, 0x47, 0x29, + 0x07, 0x4B, 0x0E, 0xC1, 0x51, 0xAA, 0x89, 0xD4, 0xCA, 0x01, + 0x46, 0xB3, 0xEF, 0xDD, 0x44, 0x7B, 0xC2, 0x7F, 0xBE, 0xC3, + 0x9F, 0x20, 0x4C, 0x64, 0x83, 0xA2, 0x68, 0x42, 0x13, 0xB4, + 0x41, 0xCD, 0xBA, 0xC6, 0xBB, 0x6D, 0x4D, 0x71, 0x21, 0xF4, + 0x8D, 0xB0, 0xE5, 0x93, 0xFE, 0x8F, 0xE6, 0xCF, 0x43, 0x45, + 0x31, 0x22, 0x37, 0x36, 0x96, 0xFA, 0xBC, 0x0F, 0x08, 0x52, + 0x1D, 0x55, 0x1A, 0xC5, 0x4E, 0x23, 0x69, 0x7A, 0x92, 0xFF, + 0x5B, 0x5A, 0xEB, 0x9A, 0x1C, 0xA9, 0xD1, 0x7E, 0x0D, 0xFC, + 0x50, 0x8A, 0xB6, 0x62, 0xF5, 0x0A, 0xF8, 0xDC, 0x03, 0x3C, + 0x0C, 0x39, 0xF1, 0xB8, 0xF3, 0x3D, 0xF2, 0xD5, 0x97, 0x66, + 0x81, 0x32, 0xA0, 0x00, 0x06, 0xCE, 0xF6, 0xEA, 0xB7, 0x17, + 0xF7, 0x8C, 0x79, 0xD6, 0xA7, 0xBF, 0x8B, 0x3F, 0x1F, 0x53, + 0x63, 0x75, 0x35, 0x2C, 0x60, 0xFD, 0x27, 0xD3, 0x94, 0xA5, + 0x7C, 0xA1, 0x05, 0x58, 0x2D, 0xBD, 0xD9, 0xC7, 0xAF, 0x6B, + 0x54, 0x0B, 0xE0, 0x38, 0x04, 0xC8, 0x9D, 0xE7, 0x14, 0xB1, + 0x87, 0x9C, 0xDF, 0x6F, 0xF9, 0xDA, 0x2A, 0xC4, 0x59, 0x16, + 0x74, 0x91, 0xAB, 0x26, 0x61, 0x76, 0x34, 0x2B, 0xAD, 0x99, + 0xFB, 0x72, 0xEC, 0x33, 0x12, 0xDE, 0x98, 0x3B, 0xC0, 0x9B, + 0x3E, 0x18, 0x10, 0x3A, 0x56, 0xE1, 0x77, 0xC9, 0x1E, 0x9E, + 0x95, 0xA3, 0x90, 0x19, 0xA8, 0x6C, 0x09, 0xD0, 0xF0, 0x86 }; + + static const uint8 X_TIME[256] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, @@ -195,6 +229,136 @@ void shift_row(STATE_STRUCT *state); // Functions void mix_column(STATE_STRUCT *state); +/********************************************************************* + Name: zero_tailing_bits + + Description: Fill tailing bits with zeros. + + Document Reference: - +*********************************************************************/ +void zero_tailing_bits(uint8 * data, uint32 length_bits); + +/********************************************************************* + Name: s3g_mul_x + + Description: Multiplication with reduction. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.1.1 +*********************************************************************/ +uint8 s3g_mul_x(uint8 v, uint8 c); + +/********************************************************************* + Name: s3g_mul_x_pow + + Description: Recursive multiplication with reduction. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.1.2 +*********************************************************************/ +uint8 s3g_mul_x_pow(uint8 v, uint8 i, uint8 c); + +/********************************************************************* + Name: s3g_mul_alpha + + Description: Multiplication with alpha. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.2 +*********************************************************************/ +uint32 s3g_mul_alpha(uint8 c); + +/********************************************************************* + Name: s3g_div_alpha + + Description: Division by alpha. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.3 +*********************************************************************/ +uint32 s3g_div_alpha(uint8 c); + +/********************************************************************* + Name: s3g_s1 + + Description: S-Box S1. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.3.1 +*********************************************************************/ +uint32 s3g_s1(uint32 w); + +/********************************************************************* + Name: s3g_s2 + + Description: S-Box S2. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.3.2 +*********************************************************************/ +uint32 s3g_s2(uint32 w); + +/********************************************************************* + Name: s3g_clock_lfsr + + Description: Clocking LFSR. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.4 and Section 3.4.5 +*********************************************************************/ +void s3g_clock_lfsr(S3G_STATE * state, uint32 f); + +/********************************************************************* + Name: s3g_clock_fsm + + Description: Clocking FSM. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.6 +*********************************************************************/ +uint32 s3g_clock_fsm(S3G_STATE * state); + +/********************************************************************* + Name: s3g_initialize + + Description: Initialization. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 4.1 +*********************************************************************/ +void s3g_initialize(S3G_STATE * state, uint32 k[4], uint32 iv[4]); + +/********************************************************************* + Name: s3g_deinitialize + + Description: Deinitialization. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 +*********************************************************************/ +void s3g_deinitialize(S3G_STATE * state); + +/********************************************************************* + Name: s3g_generate_keystream + + Description: Generation of Keystream. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 4.2 +*********************************************************************/ +void s3g_generate_keystream(S3G_STATE * state, uint32 n, uint32 *ks); + + /******************************************************************************* FUNCTIONS *******************************************************************************/ @@ -298,6 +462,71 @@ LIBLTE_ERROR_ENUM liblte_security_generate_k_enb(uint8 *k_asme, return(err); } +/********************************************************************* + Name: liblte_security_generate_k_enb_star + + Description: Generate the security key Kenb*. + + Document Reference: 33.401 v10.0.0 Annex A.5 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_generate_k_enb_star(uint8 *k_enb, + uint32 pci, + uint32_t earfcn, + uint8 *k_enb_star) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 s[9]; + + if (k_enb_star != NULL && + k_enb != NULL) { + // Construct S + s[0] = 0x13; // FC + s[1] = (pci >> 8) & 0xFF; // First byte of P0 + s[2] = pci & 0xFF; // Second byte of P0 + s[3] = 0x00; // First byte of L0 + s[4] = 0x02; // Second byte of L0 + s[5] = (earfcn >> 8) & 0xFF; // First byte of P0 + s[6] = earfcn & 0xFF; // Second byte of P0 + s[7] = 0x00; // First byte of L0 + s[8] = 0x02; // Second byte of L0 + + // Derive Kenb + sha256(k_enb, 32, s, 9, k_enb_star, 0); + + err = LIBLTE_SUCCESS; + } + + return (err); +} + +LIBLTE_ERROR_ENUM liblte_security_generate_nh( uint8_t *k_asme, + uint8_t *sync, + uint8_t *nh) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + uint8 s[35]; + + if (k_asme != NULL && + sync != NULL && + nh != NULL) + { + // Construct S + s[0] = 0x12; // FC + for (int i=0;i<32;i++) { + s[1+i] = sync[i]; + } + s[33] = 0x00; // First byte of L0 + s[34] = 0x20, // Second byte of L0 + + // Derive NH + sha256(k_asme, 32, s, 35, nh, 0); + + err = LIBLTE_SUCCESS; + } + + return (err); +} + /********************************************************************* Name: liblte_security_generate_k_nas @@ -682,6 +911,183 @@ LIBLTE_ERROR_ENUM liblte_security_128_eia2(uint8 *key, return(err); } +/********************************************************************* + Name: liblte_security_encryption_eea1 + + Description: 128-bit encryption algorithm EEA1. + + Document Reference: 33.401 v13.1.0 Annex B.1.2 + 35.215 v13.0.0 References + Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D1 v2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_encryption_eea1(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *msg, + uint32 msg_len, + uint8 *out) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + S3G_STATE state, *state_ptr; + uint32 k[] = {0,0,0,0}; + uint32 iv[] = {0,0,0,0}; + uint32 *ks; + int32 i; + uint32 msg_len_block_8, msg_len_block_32, m; + + if (key != NULL && + msg != NULL && + out != NULL) + { + state_ptr = &state; + msg_len_block_8 = (msg_len + 7) / 8; + msg_len_block_32 = (msg_len + 31) / 32; + + // Transform key + for (i = 3; i >= 0; i--) { + k[i] = (key[4 * (3 - i) + 0] << 24) | + (key[4 * (3 - i) + 1] << 16) | + (key[4 * (3 - i) + 2] << 8) | + (key[4 * (3 - i) + 3]); + } + + // Construct iv + iv[3] = count; + iv[2] = ((bearer & 0x1F) << 27) | ((direction & 0x01) << 26); + iv[1] = iv[3]; + iv[0] = iv[2]; + + // Initialize keystream + s3g_initialize(state_ptr, k, iv); + + // Generate keystream + + ks = (uint32 *) calloc(msg_len_block_32, sizeof(uint32)); + s3g_generate_keystream(state_ptr, msg_len_block_32, ks); + + // Generate output except last block + for (i = 0; i < (int32_t)msg_len_block_32 - 1; i++) { + out[4 * i + 0] = msg[4 * i + 0] ^ ((ks[i] >> 24) & 0xFF); + out[4 * i + 1] = msg[4 * i + 1] ^ ((ks[i] >> 16) & 0xFF); + out[4 * i + 2] = msg[4 * i + 2] ^ ((ks[i] >> 8) & 0xFF); + out[4 * i + 3] = msg[4 * i + 3] ^ ((ks[i] & 0xFF)); + } + + // Process last bytes + for (i = (msg_len_block_32 - 1) * 4; i < (int32_t)msg_len_block_8; i++) { + out[i] = msg[i] ^ ((ks[i / 4] >> ((3 - (i % 4)) * 8)) & 0xFF); + } + + // Zero tailing bits + zero_tailing_bits(out, msg_len); + + // Clean up + free(ks); + s3g_deinitialize(state_ptr); + + err = LIBLTE_SUCCESS; + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_decryption_eea1 + + Description: 128-bit decryption algorithm EEA1. + + Document Reference: 33.401 v13.1.0 Annex B.1.2 + 35.215 v13.0.0 References + Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D1 v2.1 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_decryption_eea1(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *ct, + uint32 ct_len, + uint8 *out) { + return liblte_security_encryption_eea1(key, count, bearer, + direction, ct, ct_len, out); +} + +/********************************************************************* + Name: liblte_security_encryption_eea2 + + Description: 128-bit encryption algorithm EEA2. + + Document Reference: 33.401 v13.1.0 Annex B.1.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_encryption_eea2(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *msg, + uint32 msg_len, + uint8 *out) +{ + LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; + aes_context ctx; + unsigned char stream_blk[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + unsigned char nonce_cnt[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + int32 i; + int ret; + size_t nc_off = 0; + + if(key != NULL && + msg != NULL && + out != NULL) + { + ret = aes_setkey_enc(&ctx, key, 128); + + if (ret == 0) { + // Construct nonce + nonce_cnt[0] = (count >> 24) & 0xFF; + nonce_cnt[1] = (count >> 16) & 0xFF; + nonce_cnt[2] = (count >> 8) & 0xFF; + nonce_cnt[3] = (count) & 0xFF; + nonce_cnt[4] = ((bearer & 0x1F) << 3) | + ((direction & 0x01) << 2); + + // Encryption + ret = aes_crypt_ctr(&ctx, (msg_len + 7) / 8, &nc_off, nonce_cnt, + stream_blk, msg, out); + } + + if (ret == 0) { + // Zero tailing bits + zero_tailing_bits(out, msg_len); + err = LIBLTE_SUCCESS; + } + } + + return(err); +} + +/********************************************************************* + Name: liblte_security_decryption_eea2 + + Description: 128-bit decryption algorithm EEA2. + + Document Reference: 33.401 v13.1.0 Annex B.1.3 +*********************************************************************/ +LIBLTE_ERROR_ENUM liblte_security_decryption_eea2(uint8 *key, + uint32 count, + uint8 bearer, + uint8 direction, + uint8 *ct, + uint32 ct_len, + uint8 *out) +{ + return liblte_security_encryption_eea2(key, count, bearer, + direction, ct, ct_len, out); +} + + + /********************************************************************* Name: liblte_security_milenage_f1 @@ -1243,3 +1649,293 @@ void mix_column(STATE_STRUCT *state) state->state[3][i] ^= temp ^ tmp; } } + +/********************************************************************* + Name: zero_tailing_bits + + Description: Fill tailing bits with zeros. + + Document Reference: - +*********************************************************************/ +void zero_tailing_bits(uint8 * data, uint32 length_bits) { + uint8 bits = (8 - (length_bits & 0x07)) & 0x07; + data[(length_bits + 7) / 8 - 1] &= (uint8) (0xFF << bits); +} + +/********************************************************************* + Name: s3g_mul_x + + Description: Multiplication with reduction. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.1.1 +*********************************************************************/ +uint8 s3g_mul_x(uint8 v, uint8 c) { + if (v & 0x80) + return ((v << 1) ^ c); + else + return (v << 1); +} + +/********************************************************************* + Name: s3g_mul_x_pow + + Description: Recursive multiplication with reduction. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.1.2 +*********************************************************************/ +uint8 s3g_mul_x_pow(uint8 v, uint8 i, uint8 c) { + if (i == 0) + return v; + else + return s3g_mul_x(s3g_mul_x_pow(v, i - 1, c), c); +} + +/********************************************************************* + Name: s3g_mul_alpha + + Description: Multiplication with alpha. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.2 +*********************************************************************/ +uint32 s3g_mul_alpha(uint8 c) { + return ((((uint32) s3g_mul_x_pow(c, 23, 0xa9)) << 24) | + (((uint32) s3g_mul_x_pow(c, 245, 0xa9)) << 16) | + (((uint32) s3g_mul_x_pow(c, 48, 0xa9)) << 8) | + (((uint32) s3g_mul_x_pow(c, 239, 0xa9)))); +} + +/********************************************************************* + Name: s3g_div_alpha + + Description: Division by alpha. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.3 +*********************************************************************/ +uint32 s3g_div_alpha(uint8 c) { + return ((((uint32) s3g_mul_x_pow(c, 16, 0xa9)) << 24) | + (((uint32) s3g_mul_x_pow(c, 39, 0xa9)) << 16) | + (((uint32) s3g_mul_x_pow(c, 6, 0xa9)) << 8) | + (((uint32) s3g_mul_x_pow(c, 64, 0xa9)))); +} + +/********************************************************************* + Name: s3g_s1 + + Description: S-Box S1. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.3.1 +*********************************************************************/ +uint32 s3g_s1(uint32 w) { + uint8 r0 = 0, r1 = 0, r2 = 0, r3 = 0; + uint8 srw0 = S[(uint8) ((w >> 24) & 0xff)]; + uint8 srw1 = S[(uint8) ((w >> 16) & 0xff)]; + uint8 srw2 = S[(uint8) ((w >> 8) & 0xff)]; + uint8 srw3 = S[(uint8) ((w) & 0xff)]; + + r0 = ((s3g_mul_x(srw0, 0x1b)) ^ + (srw1) ^ + (srw2) ^ + ((s3g_mul_x(srw3, 0x1b)) ^ srw3)); + + r1 = (((s3g_mul_x(srw0, 0x1b)) ^ srw0) ^ + (s3g_mul_x(srw1, 0x1b)) ^ + (srw2) ^ + (srw3)); + + r2 = ((srw0) ^ + ((s3g_mul_x(srw1, 0x1b)) ^ srw1) ^ + (s3g_mul_x(srw2, 0x1b)) ^ + (srw3)); + + r3 = ((srw0) ^ + (srw1) ^ + ((s3g_mul_x(srw2, 0x1b)) ^ srw2) ^ + (s3g_mul_x(srw3, 0x1b))); + + return ((((uint32) r0) << 24) | + (((uint32) r1) << 16) | + (((uint32) r2) << 8) | + (((uint32) r3))); +} + +/********************************************************************* + Name: s3g_s2 + + Description: S-Box S2. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.3.2 +*********************************************************************/ +uint32 s3g_s2(uint32 w) { + uint8 r0 = 0, r1 = 0, r2 = 0, r3 = 0; + uint8 sqw0 = SQ[(uint8) ((w >> 24) & 0xff)]; + uint8 sqw1 = SQ[(uint8) ((w >> 16) & 0xff)]; + uint8 sqw2 = SQ[(uint8) ((w >> 8) & 0xff)]; + uint8 sqw3 = SQ[(uint8) ((w) & 0xff)]; + + r0 = ((s3g_mul_x(sqw0, 0x69)) ^ + (sqw1) ^ + (sqw2) ^ + ((s3g_mul_x(sqw3, 0x69)) ^ sqw3)); + + r1 = (((s3g_mul_x(sqw0, 0x69)) ^ sqw0) ^ + (s3g_mul_x(sqw1, 0x69)) ^ + (sqw2) ^ + (sqw3)); + + r2 = ((sqw0) ^ + ((s3g_mul_x(sqw1, 0x69)) ^ sqw1) ^ + (s3g_mul_x(sqw2, 0x69)) ^ + (sqw3)); + + r3 = ((sqw0) ^ + (sqw1) ^ + ((s3g_mul_x(sqw2, 0x69)) ^ sqw2) ^ + (s3g_mul_x(sqw3, 0x69))); + + return ((((uint32) r0) << 24) | + (((uint32) r1) << 16) | + (((uint32) r2) << 8) | + (((uint32) r3))); +} + +/********************************************************************* + Name: s3g_clock_lfsr + + Description: Clocking LFSR. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.4 and Section 3.4.5 +*********************************************************************/ +void s3g_clock_lfsr(S3G_STATE * state, uint32 f) { + uint32 v = ( + ((state->lfsr[0] << 8) & 0xffffff00) ^ + (s3g_mul_alpha((uint8) ((state->lfsr[0] >> 24) & 0xff))) ^ + (state->lfsr[2]) ^ + ((state->lfsr[11] >> 8) & 0x00ffffff) ^ + (s3g_div_alpha((uint8) ((state->lfsr[11]) & 0xff))) ^ + (f) + ); + uint8 i; + + for (i = 0; i < 15; i++) { + state->lfsr[i] = state->lfsr[i + 1]; + } + state->lfsr[15] = v; +} + +/********************************************************************* + Name: s3g_clock_fsm + + Description: Clocking FSM. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 3.4.6 +*********************************************************************/ +uint32 s3g_clock_fsm(S3G_STATE * state) { + uint32 f = ((state->lfsr[15] + state->fsm[0]) & 0xffffffff) ^ + state->fsm[1]; + uint32 r = (state->fsm[1] + (state->fsm[2] ^ state->lfsr[5])) & + 0xffffffff; + + state->fsm[2] = s3g_s2(state->fsm[1]); + state->fsm[1] = s3g_s1(state->fsm[0]); + state->fsm[0] = r; + + return f; +} + +/********************************************************************* + Name: s3g_initialize + + Description: Initialization. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 4.1 +*********************************************************************/ +void s3g_initialize(S3G_STATE * state, uint32 k[4], uint32 iv[4]) { + uint8 i = 0; + uint32 f = 0x0; + + state->lfsr = (uint32 *) calloc(16, sizeof(uint32)); + state->fsm = (uint32 *) calloc( 3, sizeof(uint32)); + + state->lfsr[15] = k[3] ^ iv[0]; + state->lfsr[14] = k[2]; + state->lfsr[13] = k[1]; + state->lfsr[12] = k[0] ^ iv[1]; + + state->lfsr[11] = k[3] ^ 0xffffffff; + state->lfsr[10] = k[2] ^ 0xffffffff ^ iv[2]; + state->lfsr[ 9] = k[1] ^ 0xffffffff ^ iv[3]; + state->lfsr[ 8] = k[0] ^ 0xffffffff; + state->lfsr[ 7] = k[3]; + state->lfsr[ 6] = k[2]; + state->lfsr[ 5] = k[1]; + state->lfsr[ 4] = k[0]; + state->lfsr[ 3] = k[3] ^ 0xffffffff; + state->lfsr[ 2] = k[2] ^ 0xffffffff; + state->lfsr[ 1] = k[1] ^ 0xffffffff; + state->lfsr[ 0] = k[0] ^ 0xffffffff; + + state->fsm[0] = 0x0; + state->fsm[1] = 0x0; + state->fsm[2] = 0x0; + for (i = 0; i < 32; i++) { + f = s3g_clock_fsm(state); + s3g_clock_lfsr(state, f); + } +} + +/********************************************************************* + Name: s3g_deinitialize + + Description: Deinitialization. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 +*********************************************************************/ +void s3g_deinitialize(S3G_STATE * state) { + free(state->lfsr); + free(state->fsm); +} + +/********************************************************************* + Name: s3g_generate_keystream + + Description: Generation of Keystream. + + Document Reference: Specification of the 3GPP Confidentiality and + Integrity Algorithms UEA2 & UIA2 D2 v1.1 + Section 4.2 +*********************************************************************/ +void s3g_generate_keystream(S3G_STATE * state, uint32 n, uint32 *ks) { + uint32 t = 0; + uint32 f = 0x0; + + // Clock FSM once. Discard the output. + s3g_clock_fsm(state); + // Clock LFSR in keystream mode once. + s3g_clock_lfsr(state, 0x0); + + for (t = 0; t < n; t++) { + f = s3g_clock_fsm(state); + // Note that ks[t] corresponds to z_{t+1} in section 4.2 + ks[t] = f ^ state->lfsr[0]; + s3g_clock_lfsr(state, 0x0); + } +} diff --git a/lib/src/common/log_filter.cc b/lib/src/common/log_filter.cc index 899a224d6..5879f49a8 100644 --- a/lib/src/common/log_filter.cc +++ b/lib/src/common/log_filter.cc @@ -37,7 +37,9 @@ namespace srslte{ log_filter::log_filter() { - do_tti = false; + do_tti = false; + time_src = NULL; + time_format = TIME; } log_filter::log_filter(std::string layer) @@ -65,10 +67,20 @@ void log_filter::all_log(srslte::LOG_LEVEL_ENUM level, std::stringstream ss; ss << now_time() << " "; - ss << "[" <log(s_ptr); - } -} - void log_filter::console(std::string message, ...) { char *args_msg; va_list args; @@ -226,75 +228,45 @@ void log_filter::debug_hex(uint8_t *hex, int size, std::string message, ...) { } } -void log_filter::error_line(std::string file, int line, std::string message, ...) -{ - if (level >= LOG_LEVEL_ERROR) { - char *args_msg; - va_list args; - va_start(args, message); - if(vasprintf(&args_msg, message.c_str(), args) > 0) - all_log_line(LOG_LEVEL_ERROR, tti, file, line, args_msg); - va_end(args); - free(args_msg); - } +void log_filter::set_time_src(time_itf *source, time_format_t format) { + this->time_src = source; + this->time_format = format; } -void log_filter::warning_line(std::string file, int line, std::string message, ...) -{ - if (level >= LOG_LEVEL_WARNING) { - char *args_msg; - va_list args; - va_start(args, message); - if(vasprintf(&args_msg, message.c_str(), args) > 0) - all_log_line(LOG_LEVEL_WARNING, tti, file, line, args_msg); - va_end(args); - free(args_msg); - } -} - -void log_filter::info_line(std::string file, int line, std::string message, ...) -{ - if (level >= LOG_LEVEL_INFO) { - char *args_msg; - va_list args; - va_start(args, message); - if(vasprintf(&args_msg, message.c_str(), args) > 0) - all_log_line(LOG_LEVEL_INFO, tti, file, line, args_msg); - va_end(args); - free(args_msg); - } -} - -void log_filter::debug_line(std::string file, int line, std::string message, ...) -{ - if (level >= LOG_LEVEL_DEBUG) { - char *args_msg; - va_list args; - va_start(args, message); - if(vasprintf(&args_msg, message.c_str(), args) > 0) - all_log_line(LOG_LEVEL_DEBUG, tti, file, line, args_msg); - va_end(args); - free(args_msg); - } -} - - - std::string log_filter::now_time() { struct timeval rawtime; struct tm * timeinfo; char buffer[64]; char us[16]; - - gettimeofday(&rawtime, NULL); - timeinfo = localtime(&rawtime.tv_sec); - - strftime(buffer,64,"%H:%M:%S",timeinfo); - strcat(buffer,"."); - snprintf(us,16,"%06ld",rawtime.tv_usec); - strcat(buffer,us); - + + srslte_timestamp_t now; + uint64_t usec_epoch; + + if (!time_src) { + gettimeofday(&rawtime, NULL); + timeinfo = localtime(&rawtime.tv_sec); + + if (time_format == TIME) { + strftime(buffer, 64, "%H:%M:%S", timeinfo); + strcat(buffer, "."); + snprintf(us, 16, "%06ld", rawtime.tv_usec); + strcat(buffer, us); + } else { + usec_epoch = rawtime.tv_sec * 1000000 + rawtime.tv_usec; + snprintf(buffer, 64, "%ld", usec_epoch); + } + } else { + now = time_src->get_time(); + + if (time_format == TIME) { + snprintf(buffer, 64, "%ld:%06u", now.full_secs, (uint32_t) (now.frac_secs * 1e6)); + } else { + usec_epoch = now.full_secs * 1000000 + (uint32_t) (now.frac_secs * 1e6); + snprintf(buffer, 64, "%ld", usec_epoch); + } + } + return std::string(buffer); } diff --git a/lib/src/common/logger_file.cc b/lib/src/common/logger_file.cc index c1c31523e..ffbcf5134 100644 --- a/lib/src/common/logger_file.cc +++ b/lib/src/common/logger_file.cc @@ -55,7 +55,7 @@ void logger_file::init(std::string file) { filename = file; logfile = fopen(filename.c_str(), "w"); if(logfile==NULL) { - printf("Error: could not create log file, no messages will be logged"); + printf("Error: could not create log file, no messages will be logged!\n"); } start(); inited = true; diff --git a/lib/src/common/mac_pcap.cc b/lib/src/common/mac_pcap.cc index ff30670ed..caca254a3 100644 --- a/lib/src/common/mac_pcap.cc +++ b/lib/src/common/mac_pcap.cc @@ -40,14 +40,18 @@ void mac_pcap::enable(bool en) } void mac_pcap::open(const char* filename, uint32_t ue_id) { - pcap_file = MAC_LTE_PCAP_Open(filename); - ue_id = ue_id; - enable_write = true; + pcap_file = LTE_PCAP_Open(MAC_LTE_DLT, filename); + this->ue_id = ue_id; + enable_write = true; } void mac_pcap::close() { - fprintf(stdout, "Saving PCAP file\n"); - MAC_LTE_PCAP_Close(pcap_file); + fprintf(stdout, "Saving MAC PCAP file\n"); + LTE_PCAP_Close(pcap_file); +} + +void mac_pcap::set_ue_id(uint16_t ue_id) { + this->ue_id = ue_id; } void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reTX, bool crc_ok, uint32_t tti, @@ -65,7 +69,7 @@ void mac_pcap::pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes, uint32_t reT (uint16_t)(tti%10) /* Subframe number */ }; if (pdu) { - MAC_LTE_PCAP_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + LTE_PCAP_MAC_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); } } } diff --git a/lib/src/common/nas_pcap.cc b/lib/src/common/nas_pcap.cc new file mode 100644 index 000000000..94e2cd9b0 --- /dev/null +++ b/lib/src/common/nas_pcap.cc @@ -0,0 +1,35 @@ +#include +#include "srslte/srslte.h" +#include "srslte/common/pcap.h" +#include "srslte/common/nas_pcap.h" + + +namespace srslte { + +void nas_pcap::enable() +{ + enable_write = true; +} +void nas_pcap::open(const char* filename, uint32_t ue_id) +{ + pcap_file = LTE_PCAP_Open(NAS_LTE_DLT, filename); + ue_id = ue_id; + enable_write = true; +} +void nas_pcap::close() +{ + fprintf(stdout, "Saving NAS PCAP file\n"); + LTE_PCAP_Close(pcap_file); +} + +void nas_pcap::write_nas(uint8_t *pdu, uint32_t pdu_len_bytes) +{ + if (enable_write) { + NAS_Context_Info_t context; + if (pdu) { + LTE_PCAP_NAS_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + } + } +} + +} diff --git a/lib/src/common/pdu.cc b/lib/src/common/pdu.cc index 57bc07043..b8d17d984 100644 --- a/lib/src/common/pdu.cc +++ b/lib/src/common/pdu.cc @@ -823,7 +823,7 @@ void rar_subh::write_subheader(uint8_t** ptr, bool is_last) // Section 6.2.3 void rar_subh::write_payload(uint8_t** ptr) { - *(*ptr + 0) = (uint8_t) (ta&0x7f0)>>4; + *(*ptr + 0) = (uint8_t) ((ta&0x7f0)>>4); *(*ptr + 1) = (uint8_t) ((ta&0xf) <<4) | (grant[0]<<3) | (grant[1]<<2) | (grant[2]<<1) | grant[3]; uint8_t *x = &grant[4]; *(*ptr + 2) = (uint8_t) srslte_bit_pack(&x, 8); diff --git a/lib/src/common/pdu_queue.cc b/lib/src/common/pdu_queue.cc index 6b4c8bfd9..3a116e641 100644 --- a/lib/src/common/pdu_queue.cc +++ b/lib/src/common/pdu_queue.cc @@ -25,10 +25,10 @@ */ -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #include "srslte/common/pdu_queue.h" diff --git a/lib/src/common/security.cc b/lib/src/common/security.cc index f0ad1ce7e..fba1b37d9 100644 --- a/lib/src/common/security.cc +++ b/lib/src/common/security.cc @@ -61,6 +61,26 @@ uint8_t security_generate_k_enb( uint8_t *k_asme, k_enb); } +uint8_t security_generate_k_enb_star( uint8_t *k_enb, + uint32_t pci, + uint32_t earfcn, + uint8_t *k_enb_star) +{ + return liblte_security_generate_k_enb_star(k_enb, + pci, + earfcn, + k_enb_star); +} + +uint8_t security_generate_nh( uint8_t *k_asme, + uint8_t *sync, + uint8_t *nh) +{ + return liblte_security_generate_nh( k_asme, + sync, + nh); +} + uint8_t security_generate_k_nas( uint8_t *k_asme, CIPHERING_ALGORITHM_ID_ENUM enc_alg_id, INTEGRITY_ALGORITHM_ID_ENUM int_alg_id, @@ -146,6 +166,46 @@ uint8_t security_128_eia2( uint8_t *key, mac); } +/****************************************************************************** + * Encryption / Decryption + *****************************************************************************/ + +uint8_t security_128_eea1(uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *msg_out){ + + return liblte_security_encryption_eea1(key, + count, + bearer, + direction, + msg, + msg_len * 8, + msg_out); + +} + + +uint8_t security_128_eea2(uint8_t *key, + uint32_t count, + uint8_t bearer, + uint8_t direction, + uint8_t *msg, + uint32_t msg_len, + uint8_t *msg_out){ + + return liblte_security_encryption_eea2(key, + count, + bearer, + direction, + msg, + msg_len * 8, + msg_out); +} + /****************************************************************************** * Authentication *****************************************************************************/ diff --git a/lib/src/common/threads.c b/lib/src/common/threads.c index ec730d5de..0533aa1b6 100644 --- a/lib/src/common/threads.c +++ b/lib/src/common/threads.c @@ -51,6 +51,8 @@ bool threads_new_rt_cpu(pthread_t *thread, void *(*start_routine) (void*), void pthread_attr_t attr; struct sched_param param; cpu_set_t cpuset; + bool attr_enable = false; + if (prio_offset >= 0) { param.sched_priority = sched_get_priority_max(SCHED_FIFO) - prio_offset; pthread_attr_init(&attr); @@ -64,6 +66,21 @@ bool threads_new_rt_cpu(pthread_t *thread, void *(*start_routine) (void*), void perror("pthread_attr_setschedparam"); fprintf(stderr, "Error not enough privileges to set Scheduling priority\n"); } + attr_enable = true; + } else if (prio_offset == -2) { + param.sched_priority = 0; + pthread_attr_init(&attr); + if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) { + perror("pthread_attr_setinheritsched"); + } + if (pthread_attr_setschedpolicy(&attr, SCHED_OTHER)) { + perror("pthread_attr_setschedpolicy"); + } + if (pthread_attr_setschedparam(&attr, ¶m)) { + perror("pthread_attr_setschedparam"); + fprintf(stderr, "Error not enough privileges to set Scheduling priority\n"); + } + attr_enable = true; } if(cpu > 0) { if(cpu > 50) { @@ -86,7 +103,7 @@ bool threads_new_rt_cpu(pthread_t *thread, void *(*start_routine) (void*), void } } - int err = pthread_create(thread, prio_offset >= 0 ? &attr : NULL, start_routine, arg); + int err = pthread_create(thread, attr_enable ? &attr : NULL, start_routine, arg); if (err) { if (EPERM == err) { perror("Warning: Failed to create thread with real-time priority. Creating it with normal priority"); @@ -102,7 +119,7 @@ bool threads_new_rt_cpu(pthread_t *thread, void *(*start_routine) (void*), void } else { ret = true; } - if (prio_offset >= 0) { + if (attr_enable) { pthread_attr_destroy(&attr); } return ret; diff --git a/lib/src/common/tti_sync_cv.cc b/lib/src/common/tti_sync_cv.cc index a3fc7ce4b..c48f0772a 100644 --- a/lib/src/common/tti_sync_cv.cc +++ b/lib/src/common/tti_sync_cv.cc @@ -75,4 +75,11 @@ namespace srslte { pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); } + void tti_sync_cv::increase(uint32_t tti) + { + pthread_mutex_lock(&mutex); + increase_producer(tti); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + } } diff --git a/lib/src/phy/CMakeLists.txt b/lib/src/phy/CMakeLists.txt index 572ff19c3..b52af7b1d 100644 --- a/lib/src/phy/CMakeLists.txt +++ b/lib/src/phy/CMakeLists.txt @@ -57,9 +57,5 @@ set(srslte_srcs $ add_library(srslte_phy STATIC ${srslte_srcs}) target_link_libraries(srslte_phy ${FFT_LIBRARIES}) -if(VOLK_FOUND) - target_link_libraries(srslte_phy ${VOLK_LIBRARIES}) -endif(VOLK_FOUND) - target_link_libraries(srslte_phy pthread m) install(TARGETS srslte_phy DESTINATION ${LIBRARY_DIR}) diff --git a/lib/src/phy/agc/agc.c b/lib/src/phy/agc/agc.c index 3134de729..42a6ef09d 100644 --- a/lib/src/phy/agc/agc.c +++ b/lib/src/phy/agc/agc.c @@ -117,7 +117,7 @@ void srslte_agc_lock(srslte_agc_t *q, bool enable) { void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { if (!q->lock) { float gain_db = 10*log10(q->gain); - float gain_uhd_db = 1.0; + float gain_uhd_db = 50.0; //float gain_uhd = 1.0; float y = 0; // Apply current gain to input signal @@ -125,12 +125,12 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { srslte_vec_sc_prod_cfc(signal, q->gain, signal, len); } else { if (gain_db < 0) { - gain_db = 0.0; + gain_db = 5.0; } if (isinf(gain_db) || isnan(gain_db)) { - gain_db = 10.0; + gain_db = 40.0; } else { - gain_uhd_db = q->set_gain_callback(q->uhd_handler, gain_db); + gain_uhd_db = q->set_gain_callback(q->uhd_handler, gain_db); q->gain = pow(10, gain_uhd_db/10); } } @@ -166,7 +166,7 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { } } - double gg = 1.0; + double gg = 1.0; if (q->isfirst) { q->y_out = y; q->isfirst = false; @@ -177,7 +177,7 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { gg = expf(-0.5*q->bandwidth*logf(q->y_out/q->target)); q->gain *= gg; } - DEBUG("AGC gain: %.2f (%.2f) y_out=%.3f, y=%.3f target=%.1f gg=%.2f\n", gain_db, gain_uhd_db, q->y_out, y, q->target, gg); + DEBUG("AGC gain: %.2f (%.2f) y_out=%.3f, y=%.3f target=%.1f gg=%.2f\n", gain_db, gain_uhd_db, q->y_out, y, q->target, gg); } } } diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index 0f8ae8074..113870cc9 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -102,25 +102,30 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb) } q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); - - if (!q->tmp_noise) { perror("malloc"); goto clean_exit; } - q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); + q->tmp_cfo_estimate = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); + if (!q->tmp_cfo_estimate) { + perror("malloc"); + goto clean_exit; + } + + q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); if (!q->pilot_estimates) { perror("malloc"); goto clean_exit; } + q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); if (!q->pilot_estimates_average) { perror("malloc"); goto clean_exit; - } - q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); + } + q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); if (!q->pilot_recv_signal) { perror("malloc"); goto clean_exit; @@ -175,6 +180,9 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q) if (q->tmp_noise) { free(q->tmp_noise); } + if (q->tmp_cfo_estimate) { + free(q->tmp_cfo_estimate); + } srslte_interp_linear_vector_free(&q->srslte_interp_linvec); srslte_interp_linear_free(&q->srslte_interp_lin); srslte_interp_linear_free(&q->srslte_interp_lin_mbsfn); @@ -241,6 +249,10 @@ static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id) { int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); + if (q->average_subframe) { + nref /= 4; + } + /* Substract noisy pilot estimates */ srslte_vec_sub_ccc(q->pilot_estimates_average, q->pilot_estimates, q->tmp_noise, nref); @@ -305,9 +317,13 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN ) ? srslte_refsignal_mbsfn_nof_symbols() + 1 : srslte_refsignal_cs_nof_symbols(port_id); uint32_t fidx_offset = 0; /* Interpolate in the frequency domain */ - + + if (q->average_subframe) { + nsymbols = 1; + } + // we add one to nsymbols to allow for inclusion of the non-mbms references in the channel estimation - for (l=0;l<(nsymbols);l++) { + for (l=0;lcell, l, port_id, 0); @@ -329,34 +345,41 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t } /* Now interpolate in the time domain between symbols */ - if (ch_mode == SRSLTE_SF_MBSFN) { - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3); - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1); - } else { - if (SRSLTE_CP_ISNORM(q->cell.cp)) { - if (nsymbols == 4) { - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3); - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2); - } else { - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5); - } + if (q->average_subframe) { + // If we average per subframe, just copy the estimates in the time domain + for (l=0;l<2*SRSLTE_CP_NSYMB(q->cell.cp);l++) { + memcpy(&ce[l*SRSLTE_NRE*q->cell.nof_prb], ce, sizeof(cf_t)*SRSLTE_NRE*q->cell.nof_prb); + } + } else { + if (ch_mode == SRSLTE_SF_MBSFN) { + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1); } else { - if (nsymbols == 4) { - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2); - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2); + if (SRSLTE_CP_ISNORM(q->cell.cp)) { + if (nsymbols == 4) { + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2); + } else { + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5); + } } else { - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4); - } + if (nsymbols == 4) { + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2); + } else { + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4); + } + } } } } @@ -392,6 +415,15 @@ static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id); uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb; + // Average in the time domain if enabled + if (q->average_subframe) { + for (int l=1;lsmooth_filter, &output[l*nref], nref, q->smooth_filter_len); @@ -402,16 +434,44 @@ float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) uint32_t l; float rssi = 0; - uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); + uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); for (l=0;lcell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE]; - rssi += srslte_vec_dot_prod_conj_ccc(tmp, tmp, q->cell.nof_prb * SRSLTE_NRE); + rssi += srslte_vec_dot_prod_conj_ccc(tmp, tmp, q->cell.nof_prb * SRSLTE_NRE); } return rssi/nsymbols; } +// CFO estimation algorithm taken from "Carrier Frequency Synchronization in the +// Downlink of 3GPP LTE", Qi Wang, C. Mehlfuhrer, M. Rupp +float chest_estimate_cfo(srslte_chest_dl_t *q) +{ + float n = (float) srslte_symbol_sz(q->cell.nof_prb); + float ns = (float) SRSLTE_CP_NSYMB(q->cell.cp); + float ng = (float) SRSLTE_CP_LEN_NORM(1, n); + + uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, 0); + + // Compute angles between slots + for (int i=0;i<2;i++) { + srslte_vec_prod_conj_ccc(&q->pilot_estimates[i*npilots/4], + &q->pilot_estimates[(i+2)*npilots/4], + &q->tmp_cfo_estimate[i*npilots/4], + npilots/4); + } + // Average all angles + cf_t sum = srslte_vec_acc_cc(q->tmp_cfo_estimate, npilots/2); + + // Compute CFO + return -cargf(sum)*n/(ns*(n+ng))/2/M_PI; +} + void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, srslte_sf_t ch_mode){ - if (ce != NULL) { + if (q->cfo_estimate_enable && ((1<cfo_estimate_sf_mask)) { + q->cfo = chest_estimate_cfo(q); + } + + if (ce != NULL) { /* Smooth estimates (if applicable) and interpolate */ if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) { interpolate_pilots(q, q->pilot_estimates, ce, port_id, ch_mode); @@ -433,13 +493,12 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui } } } - + /* Compute RSRP for the channel estimates in this port */ - q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); - if (port_id == 0) { - /* compute rssi only for port 0 */ - q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id); - } + uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); + float energy = cabsf(srslte_vec_acc_cc(q->pilot_estimates, npilots)/npilots); + q->rsrp[rxant_id][port_id] = energy*energy; + q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id); } int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id) @@ -451,8 +510,9 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx], q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); + chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_NORM); - + return 0; } int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, uint16_t mbsfn_area_id) @@ -474,10 +534,6 @@ int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t return 0; } - - - - int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t nof_rx_antennas) { for (uint32_t rxant_id=0;rxant_idaverage_subframe = enable; +} +void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, bool enable, uint32_t mask) +{ + q->cfo_estimate_enable = enable; + q->cfo_estimate_sf_mask = mask; +} + +float srslte_chest_dl_get_cfo(srslte_chest_dl_t *q) { + return q->cfo; +} float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q) { float n = 0; @@ -532,10 +601,21 @@ float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) { int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, 0); return srslte_vec_acc_ff(q->snr_vector, nref)/nref; #else - return srslte_chest_dl_get_rsrp(q)/srslte_chest_dl_get_noise_estimate(q); + float rsrp = 0; + for (int i=0;ilast_nof_antennas;i++) { + for (int j=0;jcell.nof_ports;j++) { + rsrp += q->rsrp[i][j]/q->cell.nof_ports; + } + } + return rsrp/srslte_chest_dl_get_noise_estimate(q); #endif } + +float srslte_chest_dl_get_snr_ant_port(srslte_chest_dl_t *q, uint32_t ant_idx, uint32_t port_idx) { + return srslte_chest_dl_get_rsrp_ant_port(q, ant_idx, port_idx)/srslte_chest_dl_get_noise_estimate(q); +} + float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q) { float n = 0; for (int i=0;ilast_nof_antennas;i++) { @@ -556,6 +636,14 @@ float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q) { } +float srslte_chest_dl_get_rsrq_ant_port(srslte_chest_dl_t *q, uint32_t ant_idx, uint32_t port_idx) { + return q->cell.nof_prb*q->rsrp[ant_idx][port_idx] / q->rssi[ant_idx][port_idx]; +} + +float srslte_chest_dl_get_rsrp_ant_port(srslte_chest_dl_t *q, uint32_t ant_idx, uint32_t port) { + return q->rsrp[ant_idx][port]; +} + float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, uint32_t port) { float n = 0; for (int i = 0; i < q->last_nof_antennas; i++) { diff --git a/lib/src/phy/ch_estimation/refsignal_dl.c b/lib/src/phy/ch_estimation/refsignal_dl.c index 9adbc6c18..308be6877 100644 --- a/lib/src/phy/ch_estimation/refsignal_dl.c +++ b/lib/src/phy/ch_estimation/refsignal_dl.c @@ -86,11 +86,7 @@ uint32_t srslte_refsignal_cs_nof_symbols(uint32_t port_id) uint32_t srslte_refsignal_mbsfn_nof_symbols() { - if(false){ - return 3; - }else{ - return 3; - } + return 3; } diff --git a/lib/src/phy/ch_estimation/test/CMakeLists.txt b/lib/src/phy/ch_estimation/test/CMakeLists.txt index 8e1208ef5..c02c39043 100644 --- a/lib/src/phy/ch_estimation/test/CMakeLists.txt +++ b/lib/src/phy/ch_estimation/test/CMakeLists.txt @@ -39,10 +39,10 @@ add_test(chest_test_dl_cellid2 chest_test_dl -c 2 -r 50) ######################################################################## add_executable(chest_test_ul chest_test_ul.c) -target_link_libraries(chest_test_ul srslte_phy) +target_link_libraries(chest_test_ul srslte_phy srslte_common) add_executable(refsignal_ul_test_all refsignal_ul_test.c) -target_link_libraries(refsignal_ul_test_all srslte_phy) +target_link_libraries(refsignal_ul_test_all srslte_phy srslte_common) add_test(chest_test_ul_cellid0 chest_test_ul -c 0 -r 50) add_test(chest_test_ul_cellid1 chest_test_ul -c 1 -r 50) diff --git a/lib/src/phy/ch_estimation/test/chest_test_dl.c b/lib/src/phy/ch_estimation/test/chest_test_dl.c index 0f5a6d6ea..62f7e1c86 100644 --- a/lib/src/phy/ch_estimation/test/chest_test_dl.c +++ b/lib/src/phy/ch_estimation/test/chest_test_dl.c @@ -173,7 +173,7 @@ int main(int argc, char **argv) { gettimeofday(&t[1], NULL); for (int j=0;j<100;j++) { - srslte_predecoding_single(input, ce, output, num_re, 0); + srslte_predecoding_single(input, ce, output, num_re, 1.0f, 0); } gettimeofday(&t[2], NULL); get_time_interval(t); @@ -188,7 +188,7 @@ int main(int argc, char **argv) { gettimeofday(&t[1], NULL); for (int j=0;j<100;j++) { - srslte_predecoding_single(input, ce, output, num_re, srslte_chest_dl_get_noise_estimate(&est)); + srslte_predecoding_single(input, ce, output, num_re, 1.0f, srslte_chest_dl_get_noise_estimate(&est)); } gettimeofday(&t[2], NULL); get_time_interval(t); diff --git a/lib/src/phy/common/phy_common.c b/lib/src/phy/common/phy_common.c index b502fbd75..b4f5e122b 100644 --- a/lib/src/phy/common/phy_common.c +++ b/lib/src/phy/common/phy_common.c @@ -605,7 +605,7 @@ int srslte_band_get_fd_region(enum band_geographical_area region, srslte_earfcn_ /* Returns the interval tti1-tti2 mod 10240 */ uint32_t srslte_tti_interval(uint32_t tti1, uint32_t tti2) { - if (tti1 > tti2) { + if (tti1 >= tti2) { return tti1-tti2; } else { return 10240-tti2+tti1; diff --git a/lib/src/phy/common/phy_logger.c b/lib/src/phy/common/phy_logger.c new file mode 100644 index 000000000..09393236a --- /dev/null +++ b/lib/src/phy/common/phy_logger.c @@ -0,0 +1,61 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "srslte/srslte.h" +#include "srslte/phy/common/phy_logger.h" +/********************************************************************* + Functions for external logging +*********************************************************************/ +static phy_log_handler_t phy_log_handler; +static void *callback_ctx = NULL; + +void srslte_phy_log_register_handler(void *ctx, phy_log_handler_t handler) { + phy_log_handler = handler; + callback_ctx = ctx; + handler_registered++; +} + + void srslte_phy_log_print(phy_logger_level_t log_level, const char *format, ...) { + va_list args; + va_start(args, format); + if (phy_log_handler) { + char *args_msg = NULL; + if(vasprintf(&args_msg, format, args) > 0) { + phy_log_handler(log_level, callback_ctx, args_msg); + } + if (args_msg) { + free(args_msg); + } + } + va_end(args); +} \ No newline at end of file diff --git a/lib/src/phy/dft/dft_fftw.c b/lib/src/phy/dft/dft_fftw.c index b4a627742..e6eb70ecf 100644 --- a/lib/src/phy/dft/dft_fftw.c +++ b/lib/src/phy/dft/dft_fftw.c @@ -56,9 +56,7 @@ void srslte_dft_load() { void srslte_dft_exit() { #ifdef FFTW_WISDOM_FILE - if (!fftwf_export_wisdom_to_filename(FFTW_WISDOM_FILE)) { - fprintf(stderr, "Error saving FFTW wisdom to file %s\n", FFTW_WISDOM_FILE); - } + fftwf_export_wisdom_to_filename(FFTW_WISDOM_FILE); #endif } @@ -93,6 +91,27 @@ static void allocate(srslte_dft_plan_t *plan, int size_in, int size_out, int len plan->out = fftwf_malloc(size_out*len); } +int srslte_dft_replan_guru_c(srslte_dft_plan_t *plan, const int new_dft_points, cf_t *in_buffer, + cf_t *out_buffer, int istride, int ostride, int how_many, + int idist, int odist) { + int sign = (plan->forward) ? FFTW_FORWARD : FFTW_BACKWARD; + + const fftwf_iodim iodim = {new_dft_points, istride, ostride}; + const fftwf_iodim howmany_dims = {how_many, idist, odist}; + + /* Destroy current plan */ + fftwf_destroy_plan(plan->p); + + plan->p = fftwf_plan_guru_dft(1, &iodim, 1, &howmany_dims, in_buffer, out_buffer, sign, FFTW_TYPE); + if (!plan->p) { + return -1; + } + plan->size = new_dft_points; + plan->init_size = plan->size; + + return 0; +} + int srslte_dft_replan_c(srslte_dft_plan_t *plan, const int new_dft_points) { int sign = (plan->dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD; if (plan->p) { @@ -107,6 +126,32 @@ int srslte_dft_replan_c(srslte_dft_plan_t *plan, const int new_dft_points) { return 0; } +int srslte_dft_plan_guru_c(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir, cf_t *in_buffer, + cf_t *out_buffer, int istride, int ostride, int how_many, + int idist, int odist) { + int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD; + + const fftwf_iodim iodim = {dft_points, istride, ostride}; + const fftwf_iodim howmany_dims = {how_many, idist, odist}; + + plan->p = fftwf_plan_guru_dft(1, &iodim, 1, &howmany_dims, in_buffer, out_buffer, sign, FFTW_TYPE); + if (!plan->p) { + return -1; + } + plan->size = dft_points; + plan->init_size = plan->size; + plan->mode = SRSLTE_DFT_COMPLEX; + plan->dir = dir; + plan->forward = (dir==SRSLTE_DFT_FORWARD)?true:false; + plan->mirror = false; + plan->db = false; + plan->norm = false; + plan->dc = false; + plan->is_guru = true; + + return 0; +} + int srslte_dft_plan_c(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir) { allocate(plan,sizeof(fftwf_complex),sizeof(fftwf_complex), dft_points); int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD; @@ -123,6 +168,7 @@ int srslte_dft_plan_c(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_ plan->db = false; plan->norm = false; plan->dc = false; + plan->is_guru = false; return 0; } @@ -199,7 +245,7 @@ static void copy_post(uint8_t *dst, uint8_t *src, int size_d, int len, } } -void srslte_dft_run(srslte_dft_plan_t *plan, void *in, void *out) { +void srslte_dft_run(srslte_dft_plan_t *plan, const void *in, void *out) { if(plan->mode == SRSLTE_DFT_COMPLEX) { srslte_dft_run_c(plan,in,out); } else { @@ -207,11 +253,11 @@ void srslte_dft_run(srslte_dft_plan_t *plan, void *in, void *out) { } } -void srslte_dft_run_c_zerocopy(srslte_dft_plan_t *plan, cf_t *in, cf_t *out) { - fftwf_execute_dft(plan->p, in, out); +void srslte_dft_run_c_zerocopy(srslte_dft_plan_t *plan, const cf_t *in, cf_t *out) { + fftwf_execute_dft(plan->p, (cf_t*) in, out); } -void srslte_dft_run_c(srslte_dft_plan_t *plan, cf_t *in, cf_t *out) { +void srslte_dft_run_c(srslte_dft_plan_t *plan, const cf_t *in, cf_t *out) { float norm; int i; fftwf_complex *f_out = plan->out; @@ -232,7 +278,15 @@ void srslte_dft_run_c(srslte_dft_plan_t *plan, cf_t *in, cf_t *out) { plan->forward, plan->mirror, plan->dc); } -void srslte_dft_run_r(srslte_dft_plan_t *plan, float *in, float *out) { +void srslte_dft_run_guru_c(srslte_dft_plan_t *plan) { + if (plan->is_guru == true) { + fftwf_execute(plan->p); + } else { + fprintf(stderr, "srslte_dft_run_guru_c: the selected plan is not guru!\n"); + } +} + +void srslte_dft_run_r(srslte_dft_plan_t *plan, const float *in, float *out) { float norm; int i; int len = plan->size; @@ -255,8 +309,10 @@ void srslte_dft_run_r(srslte_dft_plan_t *plan, float *in, float *out) { void srslte_dft_plan_free(srslte_dft_plan_t *plan) { if (!plan) return; if (!plan->size) return; - if (plan->in) fftwf_free(plan->in); - if (plan->out) fftwf_free(plan->out); + if (!plan->is_guru) { + if (plan->in) fftwf_free(plan->in); + if (plan->out) fftwf_free(plan->out); + } if (plan->p) fftwf_destroy_plan(plan->p); bzero(plan, sizeof(srslte_dft_plan_t)); } diff --git a/lib/src/phy/dft/ofdm.c b/lib/src/phy/dft/ofdm.c index db5939274..e266023bb 100644 --- a/lib/src/phy/dft/ofdm.c +++ b/lib/src/phy/dft/ofdm.c @@ -37,23 +37,79 @@ #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" +/* Uncomment next line for avoiding Guru DFT call */ +//#define AVOID_GURU -int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb, srslte_dft_dir_t dir) { - return srslte_ofdm_init_mbsfn_(q, cp, symbol_sz, nof_prb, dir, SRSLTE_SF_NORM); +int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t *out_buffer, int symbol_sz, int nof_prb, srslte_dft_dir_t dir) { + return srslte_ofdm_init_mbsfn_(q, cp, in_buffer, out_buffer, symbol_sz, nof_prb, dir, SRSLTE_SF_NORM); } +int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t *out_buffer, int symbol_sz, int nof_prb, srslte_dft_dir_t dir, srslte_sf_t sf_type) { -int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb, srslte_dft_dir_t dir, srslte_sf_t sf_type) { + /* Set OFDM object attributes */ + q->symbol_sz = (uint32_t) symbol_sz; + q->nof_symbols = SRSLTE_CP_NSYMB(cp); + q->nof_symbols_mbsfn = SRSLTE_CP_NSYMB(SRSLTE_CP_EXT); + q->cp = cp; + q->freq_shift = false; + q->nof_re = (uint32_t) nof_prb * SRSLTE_NRE; + q->nof_guards = ((symbol_sz - q->nof_re) / 2); + q->slot_sz = (uint32_t) SRSLTE_SLOT_LEN(symbol_sz); + q->sf_sz = (uint32_t) SRSLTE_SF_LEN(symbol_sz); + q->in_buffer = in_buffer; + q->out_buffer= out_buffer; if (srslte_dft_plan_c(&q->fft_plan, symbol_sz, dir)) { fprintf(stderr, "Error: Creating DFT plan\n"); return -1; } + +#ifdef AVOID_GURU q->tmp = srslte_vec_malloc((uint32_t) symbol_sz * sizeof(cf_t)); if (!q->tmp) { perror("malloc"); return -1; } + bzero(q->tmp, sizeof(cf_t) * symbol_sz); +#else + int cp1 = SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN_NORM(0, symbol_sz):SRSLTE_CP_LEN_EXT(symbol_sz); + int cp2 = SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN_NORM(1, symbol_sz):SRSLTE_CP_LEN_EXT(symbol_sz); + + q->tmp = srslte_vec_malloc(sizeof(cf_t) * q->sf_sz); + if (!q->tmp) { + perror("malloc"); + return -1; + } + bzero(q->tmp, sizeof(cf_t) * q->sf_sz); + + if (dir == SRSLTE_DFT_BACKWARD) { + bzero(in_buffer, sizeof(cf_t) * SRSLTE_SF_LEN_RE(nof_prb, cp)); + }else { + bzero(in_buffer, sizeof(cf_t) * q->sf_sz); + } + + for (int slot = 0; slot < 2; slot++) { + //bzero(&q->fft_plan_sf[slot], sizeof(srslte_dft_plan_t)); + //bzero(q->tmp + SRSLTE_CP_NSYMB(cp)*symbol_sz*slot, sizeof(cf_t) * (cp1 + (SRSLTE_CP_NSYMB(cp) - 1)*cp2 + SRSLTE_CP_NSYMB(cp)*symbol_sz)); + if (dir == SRSLTE_DFT_FORWARD) { + if (srslte_dft_plan_guru_c(&q->fft_plan_sf[slot], symbol_sz, dir, + in_buffer + cp1 + q->slot_sz * slot, + q->tmp + q->nof_symbols * q->symbol_sz * slot, + 1, 1, SRSLTE_CP_NSYMB(cp), symbol_sz + cp2, symbol_sz)) { + fprintf(stderr, "Error: Creating DFT plan (1)\n"); + return -1; + } + } else { + if (srslte_dft_plan_guru_c(&q->fft_plan_sf[slot], symbol_sz, dir, + q->tmp + q->nof_symbols * q->symbol_sz * slot, + out_buffer + cp1 + q->slot_sz * slot, + 1, 1, SRSLTE_CP_NSYMB(cp), symbol_sz, symbol_sz + cp2)) { + fprintf(stderr, "Error: Creating DFT plan (1)\n"); + return -1; + } + } + } +#endif q->shift_buffer = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN(symbol_sz)); if (!q->shift_buffer) { @@ -64,15 +120,6 @@ int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int srslte_dft_plan_set_mirror(&q->fft_plan, true); srslte_dft_plan_set_dc(&q->fft_plan, true); - q->symbol_sz = (uint32_t) symbol_sz; - q->nof_symbols = SRSLTE_CP_NSYMB(cp); - q->nof_symbols_mbsfn = SRSLTE_CP_NSYMB(SRSLTE_CP_EXT); - q->cp = cp; - q->freq_shift = false; - q->nof_re = nof_prb * SRSLTE_NRE; - q->nof_guards = ((symbol_sz - q->nof_re) / 2); - q->slot_sz = SRSLTE_SLOT_LEN(symbol_sz); - DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp=%s, nof_re=%d, nof_guards=%d\n", dir==SRSLTE_DFT_FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols, q->cp==SRSLTE_CP_NORM?"Normal":"Extended", q->nof_re, q->nof_guards); @@ -101,9 +148,60 @@ int srslte_ofdm_replan_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof q->symbol_sz = (uint32_t) symbol_sz; q->nof_symbols = SRSLTE_CP_NSYMB(cp); q->cp = cp; - q->nof_re = nof_prb * SRSLTE_NRE; + q->nof_re = (uint32_t) nof_prb * SRSLTE_NRE; q->nof_guards = ((symbol_sz - q->nof_re) / 2); - q->slot_sz = SRSLTE_SLOT_LEN(symbol_sz); + q->slot_sz = (uint32_t) SRSLTE_SLOT_LEN(symbol_sz); + q->sf_sz = (uint32_t) SRSLTE_SF_LEN(symbol_sz); + +#ifndef AVOID_GURU + cf_t *in_buffer = q->in_buffer; + cf_t *out_buffer = q->out_buffer; + + int cp1 = SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN_NORM(0, symbol_sz):SRSLTE_CP_LEN_EXT(symbol_sz); + int cp2 = SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN_NORM(1, symbol_sz):SRSLTE_CP_LEN_EXT(symbol_sz); + + srslte_dft_dir_t dir = q->fft_plan_sf[0].dir; + + if (q->tmp) { + free(q->tmp); + } + + q->tmp = srslte_vec_malloc(sizeof(cf_t) * q->sf_sz); + if (!q->tmp) { + perror("malloc"); + return -1; + } + bzero(q->tmp, sizeof(cf_t) * q->sf_sz); + + if (dir == SRSLTE_DFT_BACKWARD) { + bzero(in_buffer, sizeof(cf_t) * SRSLTE_SF_LEN_RE(nof_prb, cp)); + }else { + bzero(in_buffer, sizeof(cf_t) * q->sf_sz); + } + + for (int slot = 0; slot < 2; slot++) { + srslte_dft_plan_free(&q->fft_plan_sf[slot]); + + if (dir == SRSLTE_DFT_FORWARD) { + if (srslte_dft_plan_guru_c(&q->fft_plan_sf[slot], symbol_sz, dir, + in_buffer + cp1 + q->slot_sz * slot, + q->tmp + q->nof_symbols * q->symbol_sz * slot, + 1, 1, SRSLTE_CP_NSYMB(cp), symbol_sz + cp2, symbol_sz)) { + fprintf(stderr, "Error: Creating DFT plan (1)\n"); + return -1; + } + } else { + if (srslte_dft_plan_guru_c(&q->fft_plan_sf[slot], symbol_sz, dir, + q->tmp + q->nof_symbols * q->symbol_sz * slot, + out_buffer + cp1 + q->slot_sz * slot, + 1, 1, SRSLTE_CP_NSYMB(cp), symbol_sz, symbol_sz + cp2)) { + fprintf(stderr, "Error: Creating DFT plan (1)\n"); + return -1; + } + } + } +#endif /* AVOID_GURU */ + if (q->freq_shift) { srslte_ofdm_set_freq_shift(q, q->freq_shift_f); @@ -118,6 +216,15 @@ int srslte_ofdm_replan_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof void srslte_ofdm_free_(srslte_ofdm_t *q) { srslte_dft_plan_free(&q->fft_plan); + +#ifndef AVOID_GURU + for (int slot = 0; slot < 2; slot++) { + if (q->fft_plan_sf[slot].init_size) { + srslte_dft_plan_free(&q->fft_plan_sf[slot]); + } + } +#endif + if (q->tmp) { free(q->tmp); } @@ -127,28 +234,28 @@ void srslte_ofdm_free_(srslte_ofdm_t *q) { bzero(q, sizeof(srslte_ofdm_t)); } -int srslte_ofdm_rx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) { +int srslte_ofdm_rx_init(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t *out_buffer, uint32_t max_prb) { int symbol_sz = srslte_symbol_sz(max_prb); if (symbol_sz < 0) { fprintf(stderr, "Error: Invalid nof_prb=%d\n", max_prb); return -1; } q->max_prb = max_prb; - return srslte_ofdm_init_(q, cp, symbol_sz, max_prb, SRSLTE_DFT_FORWARD); + return srslte_ofdm_init_(q, cp, in_buffer, out_buffer, symbol_sz, max_prb, SRSLTE_DFT_FORWARD); } -int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) +int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t *out_buffer, uint32_t nof_prb) { int symbol_sz = srslte_symbol_sz(nof_prb); if (symbol_sz < 0) { fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); return -1; } - return srslte_ofdm_init_mbsfn_(q, cp, symbol_sz, nof_prb, SRSLTE_DFT_FORWARD, SRSLTE_SF_MBSFN); + return srslte_ofdm_init_mbsfn_(q, cp, in_buffer, out_buffer, symbol_sz, nof_prb, SRSLTE_DFT_FORWARD, SRSLTE_SF_MBSFN); } -int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) { +int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t *out_buffer, uint32_t max_prb) { uint32_t i; int ret; @@ -158,7 +265,7 @@ int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) { return -1; } q->max_prb = max_prb; - ret = srslte_ofdm_init_(q, cp, symbol_sz, max_prb, SRSLTE_DFT_BACKWARD); + ret = srslte_ofdm_init_(q, cp, in_buffer, out_buffer, symbol_sz, max_prb, SRSLTE_DFT_BACKWARD); if (ret == SRSLTE_SUCCESS) { @@ -173,7 +280,7 @@ int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) { return ret; } -int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) +int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t *out_buffer, uint32_t nof_prb) { uint32_t i; int ret; @@ -184,7 +291,7 @@ int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb return -1; } - ret = srslte_ofdm_init_mbsfn_(q, cp, symbol_sz, nof_prb, SRSLTE_DFT_BACKWARD, SRSLTE_SF_MBSFN); + ret = srslte_ofdm_init_mbsfn_(q, cp, in_buffer, out_buffer, symbol_sz, nof_prb, SRSLTE_DFT_BACKWARD, SRSLTE_SF_MBSFN); if (ret == SRSLTE_SUCCESS) { srslte_dft_plan_set_norm(&q->fft_plan, false); @@ -207,7 +314,8 @@ int srslte_ofdm_rx_set_prb(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) { } return srslte_ofdm_replan_(q, cp, symbol_sz, nof_prb); } else { - fprintf(stderr, "OFDM: Error calling set_prb: nof_prb must be equal or lower initialized max_prb\n"); + fprintf(stderr, "OFDM (Rx): Error calling set_prb: nof_prb (%d) must be equal or lower initialized max_prb (%d)\n", + nof_prb, q->max_prb); return -1; } } @@ -234,7 +342,8 @@ int srslte_ofdm_tx_set_prb(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) { } return ret; } else { - fprintf(stderr, "OFDM: Error calling set_prb: nof_prb must be equal or lower initialized max_prb\n"); + fprintf(stderr, "OFDM (Tx): Error calling set_prb: nof_prb (%d) must be equal or lower initialized max_prb (%d)\n", + nof_prb, q->max_prb); return -1; } } @@ -271,10 +380,7 @@ void srslte_ofdm_tx_free(srslte_ofdm_t *q) { srslte_ofdm_free_(q); } -/* Transforms input samples into output OFDM symbols. - * Performs FFT on a each symbol and removes CP. - */ -void srslte_ofdm_rx_slot(srslte_ofdm_t *q, cf_t *input, cf_t *output) { +void srslte_ofdm_rx_slot_ng(srslte_ofdm_t *q, cf_t *input, cf_t *output) { uint32_t i; for (i=0;inof_symbols;i++) { input += SRSLTE_CP_ISNORM(q->cp)?SRSLTE_CP_LEN_NORM(i, q->symbol_sz):SRSLTE_CP_LEN_EXT(q->symbol_sz); @@ -285,6 +391,35 @@ void srslte_ofdm_rx_slot(srslte_ofdm_t *q, cf_t *input, cf_t *output) { } } +/* Transforms input samples into output OFDM symbols. + * Performs FFT on a each symbol and removes CP. + */ +void srslte_ofdm_rx_slot(srslte_ofdm_t *q, int slot_in_sf) { + cf_t *output = q->out_buffer + slot_in_sf * q->nof_re * q->nof_symbols; + +#ifdef AVOID_GURU + srslte_ofdm_rx_slot_ng(q, q->in_buffer + slot_in_sf * q->slot_sz, q->out_buffer + slot_in_sf * q->nof_re * q->nof_symbols); +#else + float norm = 1.0f/sqrtf(q->fft_plan.size); + cf_t *tmp = q->tmp + slot_in_sf * q->symbol_sz * q->nof_symbols; + uint32_t dc = (q->fft_plan.dc) ? 1:0; + + srslte_dft_run_guru_c(&q->fft_plan_sf[slot_in_sf]); + + for (int i = 0; i < q->nof_symbols; i++) { + memcpy(output, tmp + q->symbol_sz - q->nof_re / 2, sizeof(cf_t) * q->nof_re / 2); + memcpy(output + q->nof_re / 2, &tmp[dc], sizeof(cf_t) * q->nof_re / 2); + + if (q->fft_plan.norm) { + srslte_vec_sc_prod_cfc(output, norm, output, q->nof_re); + } + + tmp += q->symbol_sz; + output += q->nof_re; + } +#endif +} + void srslte_ofdm_rx_slot_mbsfn(srslte_ofdm_t *q, cf_t *input, cf_t *output) { uint32_t i; @@ -314,29 +449,48 @@ void srslte_ofdm_rx_slot_zerocopy(srslte_ofdm_t *q, cf_t *input, cf_t *output) { } } -void srslte_ofdm_rx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output) { - uint32_t n; +void srslte_ofdm_rx_sf(srslte_ofdm_t *q) { + uint32_t n; if (q->freq_shift) { - srslte_vec_prod_ccc(input, q->shift_buffer, input, 2*q->slot_sz); + srslte_vec_prod_ccc(q->in_buffer, q->shift_buffer, q->in_buffer, 2*q->slot_sz); } if(!q->mbsfn_subframe){ for (n=0;n<2;n++) { - srslte_ofdm_rx_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]); + srslte_ofdm_rx_slot(q, n); } } else{ - srslte_ofdm_rx_slot_mbsfn(q, &input[0*q->slot_sz], &output[0*q->nof_re*q->nof_symbols]); - srslte_ofdm_rx_slot(q, &input[1*q->slot_sz], &output[1*q->nof_re*q->nof_symbols]); + srslte_ofdm_rx_slot_mbsfn(q, &q->in_buffer[0*q->slot_sz], &q->out_buffer[0*q->nof_re*q->nof_symbols]); + srslte_ofdm_rx_slot(q, 1); + } +} + +void srslte_ofdm_rx_sf_ng(srslte_ofdm_t *q, cf_t *input, cf_t *output) { + uint32_t n; + if (q->freq_shift) { + srslte_vec_prod_ccc(q->in_buffer, q->shift_buffer, q->in_buffer, 2*q->slot_sz); + } + if(!q->mbsfn_subframe){ + for (n=0;n<2;n++) { + srslte_ofdm_rx_slot_ng(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]); + } + } + else{ + srslte_ofdm_rx_slot_mbsfn(q, &q->in_buffer[0*q->slot_sz], &q->out_buffer[0*q->nof_re*q->nof_symbols]); + srslte_ofdm_rx_slot(q, 1); } } /* Transforms input OFDM symbols into output samples. * Performs FFT on a each symbol and adds CP. */ -void srslte_ofdm_tx_slot(srslte_ofdm_t *q, cf_t *input, cf_t *output) { - uint32_t i, cp_len; - for (i=0;inof_symbols;i++) { - cp_len = SRSLTE_CP_ISNORM(q->cp)?SRSLTE_CP_LEN_NORM(i, q->symbol_sz):SRSLTE_CP_LEN_EXT(q->symbol_sz); +void srslte_ofdm_tx_slot(srslte_ofdm_t *q, int slot_in_sf) { + cf_t *input = q->in_buffer + slot_in_sf * q->nof_re * q->nof_symbols; + cf_t *output = q->out_buffer + slot_in_sf * q->slot_sz; + +#ifdef AVOID_GURU + for (int i=0;inof_symbols;i++) { + int cp_len = SRSLTE_CP_ISNORM(q->cp)?SRSLTE_CP_LEN_NORM(i, q->symbol_sz):SRSLTE_CP_LEN_EXT(q->symbol_sz); memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t)); srslte_dft_run_c(&q->fft_plan, q->tmp, &output[cp_len]); input += q->nof_re; @@ -344,6 +498,60 @@ void srslte_ofdm_tx_slot(srslte_ofdm_t *q, cf_t *input, cf_t *output) { memcpy(output, &output[q->symbol_sz], cp_len * sizeof(cf_t)); output += q->symbol_sz + cp_len; } +#else + float norm = 1.0f/sqrtf(q->symbol_sz); + cf_t *tmp = q->tmp + slot_in_sf * q->symbol_sz * q->nof_symbols; + + bzero(tmp, q->slot_sz); + uint32_t dc = (q->fft_plan.dc) ? 1:0; + + for (int i = 0; i < q->nof_symbols; i++) { + memcpy(&tmp[dc], &input[q->nof_re / 2], q->nof_re / 2 * sizeof(cf_t)); + memcpy(&tmp[q->symbol_sz - q->nof_re / 2], &input[0], q->nof_re / 2 * sizeof(cf_t)); + + input += q->nof_re; + tmp += q->symbol_sz; + } + + srslte_dft_run_guru_c(&q->fft_plan_sf[slot_in_sf]); + + for (int i=0;inof_symbols;i++) { + int cp_len = SRSLTE_CP_ISNORM(q->cp) ? SRSLTE_CP_LEN_NORM(i, q->symbol_sz) : SRSLTE_CP_LEN_EXT(q->symbol_sz); + + if (q->fft_plan.norm) { + srslte_vec_sc_prod_cfc(&output[cp_len], norm, &output[cp_len], q->symbol_sz); + } + + /* add CP */ + memcpy(output, &output[q->symbol_sz], cp_len * sizeof(cf_t)); + output += q->symbol_sz + cp_len; + } +#endif + + /*input = q->in_buffer + slot_in_sf * q->nof_re * q->nof_symbols; + cf_t *output2 = srslte_vec_malloc(sizeof(cf_t) * q->slot_sz); + cf_t *o2 = output2; + bzero(q->tmp, sizeof(cf_t)*q->symbol_sz); + //bzero(output2, sizeof(cf_t)*q->slot_sz); + for (int i=0;inof_symbols;i++) { + int cp_len = SRSLTE_CP_ISNORM(q->cp)?SRSLTE_CP_LEN_NORM(i, q->symbol_sz):SRSLTE_CP_LEN_EXT(q->symbol_sz); + memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t)); + srslte_dft_run_c(&q->fft_plan, q->tmp, &o2[cp_len]); + input += q->nof_re; + memcpy(o2, &o2[q->symbol_sz], cp_len * sizeof(cf_t)); + o2 += q->symbol_sz + cp_len; + } + cf_t *output1 = q->out_buffer + slot_in_sf * q->slot_sz;//srslte_vec_malloc(sizeof(cf_t) * q->slot_sz); + + for (int i = 0; i < q->slot_sz; i++) { + float error = cabsf(output1[i] - output2[i])/cabsf(output2[i]); + cf_t k = output1[i]/output2[i]; + if (error > 0.1) printf("%d/%05d error=%f output=%+f%+fi gold=%+f%+fi k=%+f%+fi\n", slot_in_sf, i, error, + __real__ output1[i], __imag__ output1[i], + __real__ output2[i], __imag__ output2[i], + __real__ k, __imag__ k); + } + free(output2);/**/ } void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t *q, cf_t *input, cf_t *output) @@ -369,20 +577,20 @@ void srslte_ofdm_set_normalize(srslte_ofdm_t *q, bool normalize_enable) { srslte_dft_plan_set_norm(&q->fft_plan, normalize_enable); } -void srslte_ofdm_tx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output) +void srslte_ofdm_tx_sf(srslte_ofdm_t *q) { - uint32_t n; + uint32_t n; if(!q->mbsfn_subframe){ for (n=0;n<2;n++) { - srslte_ofdm_tx_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]); + srslte_ofdm_tx_slot(q, n); } } else{ - srslte_ofdm_tx_slot_mbsfn(q, &input[0*q->nof_re*q->nof_symbols], &output[0*q->slot_sz]); - srslte_ofdm_tx_slot(q, &input[1*q->nof_re*q->nof_symbols], &output[1*q->slot_sz]); + srslte_ofdm_tx_slot_mbsfn(q, &q->in_buffer[0*q->nof_re*q->nof_symbols], &q->out_buffer[0*q->slot_sz]); + srslte_ofdm_tx_slot(q, 1); } if (q->freq_shift) { - srslte_vec_prod_ccc(output, q->shift_buffer, output, 2*q->slot_sz); + srslte_vec_prod_ccc(q->out_buffer, q->shift_buffer, q->out_buffer, 2*q->slot_sz); } } diff --git a/lib/src/phy/dft/test/ofdm_test.c b/lib/src/phy/dft/test/ofdm_test.c index 11aac7f4e..e77fcd39e 100644 --- a/lib/src/phy/dft/test/ofdm_test.c +++ b/lib/src/phy/dft/test/ofdm_test.c @@ -35,16 +35,28 @@ int nof_prb = -1; srslte_cp_t cp = SRSLTE_CP_NORM; +int nof_repetitions = 128; + +static double elapsed_us(struct timeval *ts_start, struct timeval *ts_end) { + if (ts_end->tv_usec > ts_start->tv_usec) { + return ((double) ts_end->tv_sec - (double) ts_start->tv_sec) * 1000000 + + (double) ts_end->tv_usec - (double) ts_start->tv_usec; + } else { + return ((double) ts_end->tv_sec - (double) ts_start->tv_sec - 1) * 1000000 + + ((double) ts_end->tv_usec + 1000000) - (double) ts_start->tv_usec; + } +} void usage(char *prog) { printf("Usage: %s\n", prog); printf("\t-n nof_prb [Default All]\n"); printf("\t-e extended cyclic prefix [Default Normal]\n"); + printf("\t-r nof_repetitions [Default %d]\n", nof_repetitions); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "ne")) != -1) { + while ((opt = getopt(argc, argv, "ner")) != -1) { switch (opt) { case 'n': nof_prb = atoi(argv[optind]); @@ -52,6 +64,9 @@ void parse_args(int argc, char **argv) { case 'e': cp = SRSLTE_CP_EXT; break; + case 'r': + nof_repetitions = atoi(argv[optind]); + break; default: usage(argv[0]); exit(-1); @@ -61,6 +76,7 @@ void parse_args(int argc, char **argv) { int main(int argc, char **argv) { + struct timeval start, end; srslte_ofdm_t fft, ifft; cf_t *input, *outfft, *outifft; float mse; @@ -81,48 +97,65 @@ int main(int argc, char **argv) { printf("Running test for %d PRB, %d RE... ", n_prb, n_re);fflush(stdout); - input = malloc(sizeof(cf_t) * n_re); + input = srslte_vec_malloc(sizeof(cf_t) * n_re * 2); if (!input) { perror("malloc"); exit(-1); } - outfft = malloc(sizeof(cf_t) * SRSLTE_SLOT_LEN(srslte_symbol_sz(n_prb))); + outfft = srslte_vec_malloc(sizeof(cf_t) * n_re * 2); if (!outfft) { perror("malloc"); exit(-1); } - outifft = malloc(sizeof(cf_t) * n_re); + outifft = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SLOT_LEN(srslte_symbol_sz(n_prb)) * 2); if (!outifft) { perror("malloc"); exit(-1); } + bzero(outifft, sizeof(cf_t) * SRSLTE_SLOT_LEN(srslte_symbol_sz(n_prb)) * 2); - if (srslte_ofdm_rx_init(&fft, cp, n_prb)) { + if (srslte_ofdm_rx_init(&fft, cp, outifft, outfft, n_prb)) { fprintf(stderr, "Error initializing FFT\n"); exit(-1); } - srslte_dft_plan_set_norm(&fft.fft_plan, true); + srslte_ofdm_set_normalize(&fft, true); - if (srslte_ofdm_tx_init(&ifft, cp, n_prb)) { + if (srslte_ofdm_tx_init(&ifft, cp, input, outifft, n_prb)) { fprintf(stderr, "Error initializing iFFT\n"); exit(-1); } - srslte_dft_plan_set_norm(&ifft.fft_plan, true); + srslte_ofdm_set_normalize(&ifft, true); for (i=0;i 1.0f) printf("%04d. %+.1f%+.1fi Vs. %+.1f%+.1f %+.1f%+.1f (mse=%f)\n", i, __real__ input[i], __imag__ input[i], __real__ outifft[i], __imag__ outifft[i], __real__ outfft[i], __imag__ outfft[i], mse); } - printf("MSE=%f\n", mse); + /*for (i=0;i= 0.07) { printf("MSE too large\n"); diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index 2ba179399..1e9044202 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -41,7 +41,7 @@ #define SRSLTE_ENB_RF_AMP 0.1 -int srslte_enb_dl_init(srslte_enb_dl_t *q, uint32_t max_prb) +int srslte_enb_dl_init(srslte_enb_dl_t *q, cf_t *out_buffer[SRSLTE_MAX_PORTS], uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -53,13 +53,22 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, uint32_t max_prb) q->cfi = 3; q->tx_amp = SRSLTE_ENB_RF_AMP; - - if (srslte_ofdm_tx_init(&q->ifft, SRSLTE_CP_NORM, max_prb)) { - fprintf(stderr, "Error initiating FFT\n"); - goto clean_exit; + + for (int i=0;isf_symbols[i] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); + if (!q->sf_symbols[i]) { + perror("malloc"); + goto clean_exit; + } + q->slot1_symbols[i] = &q->sf_symbols[i][SRSLTE_SLOT_LEN_RE(max_prb, SRSLTE_CP_NORM)]; } - srslte_ofdm_set_normalize(&q->ifft, true); + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + if (srslte_ofdm_tx_init(&q->ifft[i], SRSLTE_CP_NORM, q->sf_symbols[i], out_buffer[i], max_prb)) { + fprintf(stderr, "Error initiating FFT (%d)\n", i); + goto clean_exit; + } + } if (srslte_pbch_init(&q->pbch)) { fprintf(stderr, "Error creating PBCH object\n"); @@ -89,15 +98,6 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, uint32_t max_prb) goto clean_exit; } - for (int i=0;isf_symbols[i] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); - if (!q->sf_symbols[i]) { - perror("malloc"); - goto clean_exit; - } - q->slot1_symbols[i] = &q->sf_symbols[i][SRSLTE_SLOT_LEN_RE(max_prb, SRSLTE_CP_NORM)]; - } - ret = SRSLTE_SUCCESS; } else { @@ -114,7 +114,9 @@ clean_exit: void srslte_enb_dl_free(srslte_enb_dl_t *q) { if (q) { - srslte_ofdm_tx_free(&q->ifft); + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + srslte_ofdm_tx_free(&q->ifft[i]); + } srslte_regs_free(&q->regs); srslte_pbch_free(&q->pbch); srslte_pcfich_free(&q->pcfich); @@ -152,9 +154,11 @@ int srslte_enb_dl_set_cell(srslte_enb_dl_t *q, srslte_cell_t cell) fprintf(stderr, "Error resizing REGs\n"); return SRSLTE_ERROR; } - if (srslte_ofdm_rx_set_prb(&q->ifft, q->cell.cp, q->cell.nof_prb)) { - fprintf(stderr, "Error initiating FFT\n"); - return SRSLTE_ERROR; + for (int i = 0; i < q->cell.nof_ports; i++) { + if (srslte_ofdm_tx_set_prb(&q->ifft[i], q->cell.cp, q->cell.nof_prb)) { + fprintf(stderr, "Error re-planning iFFT (%d)\n", i); + return SRSLTE_ERROR; + } } if (srslte_pbch_set_cell(&q->pbch, q->cell)) { fprintf(stderr, "Error creating PBCH object\n"); @@ -219,15 +223,19 @@ void srslte_enb_dl_clear_sf(srslte_enb_dl_t *q) void srslte_enb_dl_put_sync(srslte_enb_dl_t *q, uint32_t sf_idx) { if (sf_idx == 0 || sf_idx == 5) { - srslte_pss_put_slot(q->pss_signal, q->sf_symbols[0], q->cell.nof_prb, q->cell.cp); - srslte_sss_put_slot(sf_idx ? q->sss_signal5 : q->sss_signal0, q->sf_symbols[0], - q->cell.nof_prb, SRSLTE_CP_NORM); + for (int p = 0; p < q->cell.nof_ports; p++) { + srslte_pss_put_slot(q->pss_signal, q->sf_symbols[p], q->cell.nof_prb, q->cell.cp); + srslte_sss_put_slot(sf_idx ? q->sss_signal5 : q->sss_signal0, q->sf_symbols[p], + q->cell.nof_prb, SRSLTE_CP_NORM); + } } } void srslte_enb_dl_put_refs(srslte_enb_dl_t *q, uint32_t sf_idx) { - srslte_refsignal_cs_put_sf(q->cell, 0, q->csr_signal.pilots[0][sf_idx], q->sf_symbols[0]); + for (int p = 0; p < q->cell.nof_ports; p++) { + srslte_refsignal_cs_put_sf(q->cell, (uint32_t) p, q->csr_signal.pilots[p / 2][sf_idx], q->sf_symbols[p]); + } } void srslte_enb_dl_put_mib(srslte_enb_dl_t *q, uint32_t tti) @@ -264,14 +272,15 @@ void srslte_enb_dl_put_base(srslte_enb_dl_t *q, uint32_t tti) } -void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q, cf_t *signal_buffer) +void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q) { - - srslte_ofdm_tx_sf(&q->ifft, q->sf_symbols[0], signal_buffer); - // TODO: PAPR control - float norm_factor = (float) sqrt(q->cell.nof_prb)/15; - srslte_vec_sc_prod_cfc(signal_buffer, q->tx_amp*norm_factor, signal_buffer, SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); + float norm_factor = (float) sqrt(q->cell.nof_prb)/15/sqrt(q->ifft[0].symbol_sz); + + for (int i = 0; i < q->cell.nof_ports; i++) { + srslte_ofdm_tx_sf(&q->ifft[i]); + srslte_vec_sc_prod_cfc(q->ifft[i].out_buffer, q->tx_amp*norm_factor, q->ifft[i].out_buffer, (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); + } } int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q, uint16_t rnti) @@ -321,11 +330,41 @@ int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant, int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS], uint16_t rnti, int rv_idx[SRSLTE_MAX_CODEWORDS], uint32_t sf_idx, - uint8_t *data[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type, uint32_t pmi) + uint8_t *data[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type) { + uint32_t pmi = 0; + uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(grant); + + /* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */ + if (mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { + switch(nof_tb) { + case 1: + if (grant->pinfo == 0) { + mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + } else if (grant->pinfo > 0 && grant->pinfo < 5) { + pmi = grant->pinfo - 1; + } else { + ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo); + return SRSLTE_ERROR; + } + break; + case 2: + if (grant->pinfo < 2) { + pmi = grant->pinfo; + } else { + ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo); + return SRSLTE_ERROR; + } + break; + default: + ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo); + return SRSLTE_ERROR; + } + } + /* Configure pdsch_cfg parameters */ if (srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, q->cfi, sf_idx, rv_idx, mimo_type, pmi)) { - fprintf(stderr, "Error configuring PDSCH\n"); + ERROR("Error configuring PDSCH (rnti=0x%04x)", rnti); return SRSLTE_ERROR; } diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index db05d44ea..8ea5dd3e4 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -40,6 +40,7 @@ #define MAX_CANDIDATES 16 int srslte_enb_ul_init(srslte_enb_ul_t *q, + cf_t *in_buffer, uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -55,8 +56,20 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, perror("malloc"); goto clean_exit; } - - if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, max_prb)) { + + q->sf_symbols = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); + if (!q->sf_symbols) { + perror("malloc"); + goto clean_exit; + } + + q->ce = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); + if (!q->ce) { + perror("malloc"); + goto clean_exit; + } + + if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, in_buffer, q->sf_symbols, max_prb)) { fprintf(stderr, "Error initiating FFT\n"); goto clean_exit; } @@ -80,18 +93,6 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, goto clean_exit; } - q->sf_symbols = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); - if (!q->sf_symbols) { - perror("malloc"); - goto clean_exit; - } - - q->ce = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); - if (!q->ce) { - perror("malloc"); - goto clean_exit; - } - ret = SRSLTE_SUCCESS; } else { @@ -252,18 +253,22 @@ int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint16_t rnti, } } -void srslte_enb_ul_fft(srslte_enb_ul_t *q, cf_t *signal_buffer) +void srslte_enb_ul_fft(srslte_enb_ul_t *q) { - srslte_ofdm_rx_sf(&q->fft, signal_buffer, q->sf_symbols); + srslte_ofdm_rx_sf(&q->fft); } int get_pucch(srslte_enb_ul_t *q, uint16_t rnti, uint32_t pdcch_n_cce, uint32_t sf_rx, - srslte_uci_data_t *uci_data, uint8_t bits[SRSLTE_PUCCH_MAX_BITS]) + srslte_uci_data_t *uci_data, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t nof_bits) { float noise_power = srslte_chest_ul_get_noise_estimate(&q->chest); srslte_pucch_format_t format = srslte_pucch_get_format(uci_data, q->cell.cp); + if (format == SRSLTE_PUCCH_FORMAT_ERROR) { + fprintf(stderr,"Error getting format\n"); + return SRSLTE_ERROR; + } uint32_t n_pucch = srslte_pucch_get_npucch(pdcch_n_cce, format, uci_data->scheduling_request, &q->users[rnti]->pucch_sched); @@ -272,7 +277,7 @@ int get_pucch(srslte_enb_ul_t *q, uint16_t rnti, return SRSLTE_ERROR; } - int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, rnti, q->sf_symbols, q->ce, noise_power, bits); + int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, rnti, q->sf_symbols, q->ce, noise_power, bits, nof_bits); if (ret_val < 0) { fprintf(stderr,"Error decoding PUCCH\n"); return SRSLTE_ERROR; @@ -285,16 +290,18 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti, srslte_uci_data_t *uci_data) { uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS]; - - if (q->users[rnti]) { - int ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits); + if (q->users[rnti]) { + uint32_t nof_uci_bits = uci_data->ri_periodic_report ? uci_data->uci_ri_len : (uci_data->uci_cqi_len + + uci_data->uci_dif_cqi_len + + uci_data->uci_pmi_len); + int ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits, nof_uci_bits); // If we are looking for SR and ACK at the same time and ret=0, means there is no SR. // try again to decode ACK only if (uci_data->scheduling_request && uci_data->uci_ack_len && ret_val != 1) { uci_data->scheduling_request = false; - ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits); + ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits, nof_uci_bits); } // update schedulign request @@ -304,12 +311,32 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti, // Save ACK bits if (uci_data->uci_ack_len > 0) { - uci_data->uci_ack = pucch_bits[0]; + uci_data->uci_ack = pucch_bits[0]; + } + + if (uci_data->uci_ack_len > 1) { + uci_data->uci_ack_2 = pucch_bits[1]; } // PUCCH2 CQI bits are decoded inside srslte_pucch_decode() if (uci_data->uci_cqi_len) { memcpy(uci_data->uci_cqi, pucch_bits, uci_data->uci_cqi_len*sizeof(uint8_t)); + } + + if (uci_data->uci_dif_cqi_len) { + memcpy(uci_data->uci_dif_cqi, pucch_bits + uci_data->uci_cqi_len, uci_data->uci_dif_cqi_len*sizeof(uint8_t)); + } + + if (uci_data->uci_pmi_len) { + memcpy(uci_data->uci_pmi, pucch_bits + uci_data->uci_cqi_len + uci_data->uci_dif_cqi_len, + uci_data->uci_pmi_len*sizeof(uint8_t)); + } + + if (uci_data->uci_ri_len) { + uci_data->uci_ri = pucch_bits[0]; /* Assume only one bit of RI */ + } + + if (uci_data->uci_cqi_len || uci_data->uci_ri_len) { if (uci_data->uci_ack_len >= 1) { uci_data->uci_ack = pucch_bits[20]; } @@ -327,7 +354,7 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti, int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint32_t rv_idx, uint32_t current_tx_nb, - uint8_t *data, srslte_uci_data_t *uci_data, uint32_t tti) + uint8_t *data, srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data, uint32_t tti) { if (q->users[rnti]) { if (srslte_pusch_cfg(&q->pusch, @@ -363,6 +390,7 @@ int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srs softbuffer, q->sf_symbols, q->ce, noise_power, rnti, data, + cqi_value, uci_data); } diff --git a/lib/src/phy/fec/rm_turbo.c b/lib/src/phy/fec/rm_turbo.c index 23929fff3..b1cc95a8c 100644 --- a/lib/src/phy/fec/rm_turbo.c +++ b/lib/src/phy/fec/rm_turbo.c @@ -61,7 +61,9 @@ static uint8_t RM_PERM_TC[NCOLS] = { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, /* Align tables to 16-byte boundary */ static uint16_t interleaver_systematic_bits[192][6160]; // 4 tail bits +static srslte_bit_interleaver_t bit_interleavers_systematic_bits[192]; static uint16_t interleaver_parity_bits[192][2*6160]; +static srslte_bit_interleaver_t bit_interleavers_parity_bits[192]; static uint16_t deinterleaver[192][4][18448]; static int k0_vec[SRSLTE_NOF_TC_CB_SIZES][4][2]; static bool rm_turbo_tables_generated = false; @@ -235,7 +237,12 @@ void srslte_rm_turbo_gentables() { k0_vec[cb_idx][i][1] = -1; } srslte_rm_turbo_gentable_systematic(interleaver_systematic_bits[cb_idx], k0_vec[cb_idx], nrows, ndummy); + srslte_bit_interleaver_init(&bit_interleavers_systematic_bits[cb_idx], interleaver_systematic_bits[cb_idx], + (uint32_t) srslte_cbsegm_cbsize(cb_idx)+4); + srslte_rm_turbo_gentable_parity(interleaver_parity_bits[cb_idx], k0_vec[cb_idx], in_len/3, nrows, ndummy); + srslte_bit_interleaver_init(&bit_interleavers_parity_bits[cb_idx], interleaver_parity_bits[cb_idx], + (uint32_t) (srslte_cbsegm_cbsize(cb_idx)+4)*2); for (int i=0;i<4;i++) { srslte_rm_turbo_gentable_receive(deinterleaver[cb_idx][i], in_len, i); @@ -244,6 +251,12 @@ void srslte_rm_turbo_gentables() { } } +void srslte_rm_turbo_free_tables () { + for (int i = 0; i < SRSLTE_NOF_TC_CB_SIZES; i++) { + srslte_bit_interleaver_free(&bit_interleavers_systematic_bits[i]); + srslte_bit_interleaver_free(&bit_interleavers_parity_bits[i]); + } +} /** * Rate matching for LTE Turbo Coder @@ -274,11 +287,13 @@ int srslte_rm_turbo_tx_lut(uint8_t *w_buff, uint8_t *systematic, uint8_t *parity if (rv_idx == 0) { // Systematic bits - srslte_bit_interleave(systematic, w_buff, interleaver_systematic_bits[cb_idx], in_len/3); + //srslte_bit_interleave(systematic, w_buff, interleaver_systematic_bits[cb_idx], in_len/3); + srslte_bit_interleaver_run(&bit_interleavers_systematic_bits[cb_idx], systematic, w_buff, 0); // Parity bits - srslte_bit_interleave_w_offset(parity, &w_buff[in_len/24], interleaver_parity_bits[cb_idx], 2*in_len/3, 4); + //srslte_bit_interleave_w_offset(parity, &w_buff[in_len/24], interleaver_parity_bits[cb_idx], 2*in_len/3, 4); + srslte_bit_interleaver_run(&bit_interleavers_parity_bits[cb_idx], parity, &w_buff[in_len/24], 4); } /* Bit selection and transmission 5.1.4.1.2 */ @@ -741,4 +756,3 @@ int srslte_rm_turbo_rx(float *w_buff, uint32_t w_buff_len, float *input, uint32_ return 0; } - diff --git a/lib/src/phy/fec/test/rm_turbo_test.c b/lib/src/phy/fec/test/rm_turbo_test.c index 6943c72d1..1c5b2abf5 100644 --- a/lib/src/phy/fec/test/rm_turbo_test.c +++ b/lib/src/phy/fec/test/rm_turbo_test.c @@ -197,6 +197,7 @@ int main(int argc, char **argv) { } } + srslte_rm_turbo_free_tables(); free(rm_bits); free(rm_bits2); free(rm_bits2_bytes); diff --git a/lib/src/phy/fec/test/viterbi_test.h b/lib/src/phy/fec/test/viterbi_test.h index 7d94e7c7e..38665305e 100644 --- a/lib/src/phy/fec/test/viterbi_test.h +++ b/lib/src/phy/fec/test/viterbi_test.h @@ -52,7 +52,24 @@ static expected_errors_t expected_errors[] = { {-1, -1, -1, true, -1.0, -1} }; -#else +#elif HAVE_NEON + +static expected_errors_t expected_errors[] = { + {1000, 1, 40, true, 0.0, 7282}, + {1000, 1, 40, true, 2.0, 725}, + {1000, 1, 40, true, 3.0, 176}, + {1000, 1, 40, true, 4.5, 24}, + + {100, 1, 1000, true, 0.0, 13208}, + {100, 1, 1000, true, 2.0, 939}, + {100, 1, 1000, true, 3.0, 110}, + {100, 1, 1000, true, 4.5, 5}, + + {-1, -1, -1, true, -1.0, -1} +}; + + +#else static expected_errors_t expected_errors[] = { {1000, 1, 40, true, 0.0, 5363}, diff --git a/lib/src/phy/fec/turbocoder.c b/lib/src/phy/fec/turbocoder.c index b7785980c..64f05b5e8 100644 --- a/lib/src/phy/fec/turbocoder.c +++ b/lib/src/phy/fec/turbocoder.c @@ -43,6 +43,7 @@ uint8_t tcod_lut_next_state[188][8][256]; uint8_t tcod_lut_output[188][8][256]; uint16_t tcod_per_fw[188][6144]; +static srslte_bit_interleaver_t tcod_interleavers[188]; static bool table_initiated = false; @@ -63,6 +64,9 @@ void srslte_tcod_free(srslte_tcod_t *h) { if (h->temp) { free(h->temp); } + for (int i = 0; i < 188; i++) { + srslte_bit_interleaver_free(&tcod_interleavers[i]); + } } /* Expects bits (1 byte = 1 bit) and produces bits. The systematic and parity bits are interlaced in the output */ @@ -198,8 +202,9 @@ int srslte_tcod_encode_lut(srslte_tcod_t *h, uint8_t *input, uint8_t *parity, ui } parity[long_cb/8] = 0; // will put tail here later - /* Interleave input */ - srslte_bit_interleave(input, h->temp, tcod_per_fw[cblen_idx], long_cb); + /* Interleave input */ + srslte_bit_interleaver_run(&tcod_interleavers[cblen_idx], input, h->temp, 0); + //srslte_bit_interleave(input, h->temp, tcod_per_fw[cblen_idx], long_cb); /* Parity bits for the 2nd constituent encoders */ uint8_t state1 = 0; @@ -297,6 +302,7 @@ void srslte_tcod_gentable() { for (uint32_t i=0;itdec_simd, input, long_cb); #else - srslte_vec_convert_if(input[0], h->input_conv, 0.01, 3*long_cb+12); + srslte_vec_convert_if(input[0], 0.01, h->input_conv, 3*long_cb+12); srslte_tdec_gen_iteration(&h->tdec_gen, h->input_conv, long_cb); #endif } @@ -156,7 +156,7 @@ int srslte_tdec_run_all_par(srslte_tdec_t * h, int16_t * input[SRSLTE_TDEC_MAX_N #ifdef LV_HAVE_SSE return srslte_tdec_simd_run_all(&h->tdec_simd, input, output, nof_iterations, long_cb); #else - srslte_vec_convert_if(input[0], h->input_conv, 0.01, 3*long_cb+12); + srslte_vec_convert_if(input[0], 0.01, h->input_conv, 3*long_cb+12); return srslte_tdec_gen_run_all(&h->tdec_gen, h->input_conv, output[0], nof_iterations, long_cb); #endif } diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index 6f3e43889..31ba2ca0a 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -33,20 +33,20 @@ #include "srslte/phy/mimo/precoding.h" #include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/mat.h" #ifdef LV_HAVE_SSE #include -int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); -int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_symbols); +int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate); +int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_symbols, float scaling); #endif #ifdef LV_HAVE_AVX #include -int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); +int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate); #endif #include "srslte/phy/utils/mat.h" - static srslte_mimo_decoder_t mimo_decoder = SRSLTE_MIMO_DECODER_MMSE; /************************************************ @@ -59,7 +59,7 @@ static srslte_mimo_decoder_t mimo_decoder = SRSLTE_MIMO_DECODER_MMSE; #define PROD(a,b) _mm_addsub_ps(_mm_mul_ps(a,_mm_moveldup_ps(b)),_mm_mul_ps(_mm_shuffle_ps(a,a,0xB1),_mm_movehdup_ps(b))) -int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { +int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate) { float *xPtr = (float*) x; const float *hPtr1 = (const float*) h[0]; @@ -122,7 +122,10 @@ int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ x1Val1 = _mm_div_ps(x1Val1, h1square); x2Val1 = _mm_div_ps(x2Val1, h2square); - + + x1Val1 = _mm_mul_ps(x1Val1, _mm_set1_ps(1/scaling)); + x2Val1 = _mm_mul_ps(x2Val1, _mm_set1_ps(1/scaling)); + _mm_store_ps(xPtr, x1Val1); xPtr+=4; _mm_store_ps(xPtr, x2Val1); xPtr+=4; @@ -134,7 +137,7 @@ int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ r += y[p][i]*conj(h[p][i]); hh += conj(h[p][i])*h[p][i]; } - x[i] = r/(hh+noise_estimate); + x[i] = scaling*r/(hh+noise_estimate); } return nof_symbols; } @@ -147,7 +150,7 @@ int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ -int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { +int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate) { float *xPtr = (float*) x; const float *hPtr1 = (const float*) h[0]; @@ -160,6 +163,8 @@ int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ __m256 noise = _mm256_set1_ps(noise_estimate); __m256 h1Val1, h2Val1, y1Val1, y2Val1, h12square, h1square, h2square, h1_p, h2_p, h1conj1, h2conj1, x1Val, x2Val; __m256 h1Val2, h2Val2, y1Val2, y2Val2, h1conj2, h2conj2; + __m256 avx_scaling = _mm256_set1_ps(1/scaling); + for (int i=0;i 32 && nof_rxant <= 2) { - return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, noise_estimate); + return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); } else { - return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); } #else #ifdef LV_HAVE_SSE if (nof_symbols > 32 && nof_rxant <= 2) { - return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, noise_estimate); + return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); } else { - return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); } #else - return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); #endif #endif } /* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/ -int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { +int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, + int nof_rxant, int nof_symbols, float scaling, float noise_estimate) { #ifdef LV_HAVE_AVX if (nof_symbols > 32) { - return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, noise_estimate); + return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); } else { - return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); } #else #ifdef LV_HAVE_SSE if (nof_symbols > 32) { - return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, noise_estimate); + return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); } else { - return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); } #else - return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); + return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); #endif #endif } @@ -296,7 +305,7 @@ int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MA /* C implementatino of the SFBC equalizer */ int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], - int nof_rxant, int nof_ports, int nof_symbols, int symbol_start) + int nof_rxant, int nof_ports, int nof_symbols, int symbol_start, float scaling) { int i; if (nof_ports == 2) { @@ -321,6 +330,7 @@ int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_ x0 += (conjf(h00) * r0 + h11 * conjf(r1)); x1 += (-h10 * conj(r0) + conj(h01) * r1); } + hh *= scaling; x[0][i] = x0 / hh * sqrt(2); x[1][i] = x1 / hh * sqrt(2); } @@ -351,6 +361,10 @@ int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_ x2 += (conjf(h1) * r2 + h3 * conjf(r3)); x3 += (-h3 * conjf(r2) + conjf(h1) * r3); } + + hh02 *= scaling; + hh13 *= scaling; + x[0][i] = x0 / hh02 * sqrt(2); x[1][i] = x1 / hh02 * sqrt(2); x[2][i] = x2 / hh13 * sqrt(2); @@ -365,15 +379,15 @@ int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_ int srslte_predecoding_diversity_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], - int nof_rxant, int nof_ports, int nof_symbols) { - return srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, nof_ports, nof_symbols, 0); + int nof_rxant, int nof_ports, int nof_symbols, float scaling) { + return srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, nof_ports, nof_symbols, 0, scaling); } /* SSE implementation of the 2-port SFBC equalizer */ #ifdef LV_HAVE_SSE int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], - int nof_rxant, int nof_symbols) + int nof_rxant, int nof_symbols, float scaling) { float *x0Ptr = (float*) x[0]; float *x1Ptr = (float*) x[1]; @@ -385,7 +399,7 @@ int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_ const float *yPtr1 = (const float*) y[1]; __m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f); - __m128 sqrt2 = _mm_setr_ps(sqrt(2), sqrt(2), sqrt(2), sqrt(2)); + __m128 sqrt2 = _mm_set1_ps(sqrtf(2)/scaling); __m128 h0Val_00, h0Val_10, h1Val_00, h1Val_10, h000, h00conj0, h010, h01conj0, h100, h110; __m128 h0Val_01, h0Val_11, h1Val_01, h1Val_11, h001, h00conj1, h011, h01conj1, h101, h111; @@ -474,13 +488,13 @@ int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_ _mm_store_ps(x1Ptr, x1); x1Ptr+=4; } // Compute remaining symbols using generic implementation - srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, 2, nof_symbols, 4*(nof_symbols/4)); + srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, 2, nof_symbols, 4*(nof_symbols/4), scaling); return nof_symbols; } #endif int srslte_predecoding_diversity(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], - int nof_ports, int nof_symbols) + int nof_ports, int nof_symbols, float scaling) { cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; cf_t *y[SRSLTE_MAX_PORTS]; @@ -493,47 +507,31 @@ int srslte_predecoding_diversity(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[S #ifdef LV_HAVE_SSE if (nof_symbols > 32 && nof_ports == 2) { - return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols); + return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols, scaling); } else { - return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); + return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling); } #else - return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); + return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling); #endif } int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], - int nof_rxant, int nof_ports, int nof_symbols) + int nof_rxant, int nof_ports, int nof_symbols, float scaling) { #ifdef LV_HAVE_SSE if (nof_symbols > 32 && nof_ports == 2) { - return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols); + return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols, scaling); } else { - return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); + return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling); } #else - return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); + return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling); #endif } - -int srslte_predecoding_type(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], - int nof_ports, int nof_layers, int nof_symbols, srslte_mimo_type_t type, float noise_estimate) -{ - cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - cf_t *y[SRSLTE_MAX_PORTS]; - uint32_t nof_rxant = 1; - - for (int i=0;i SRSLTE_MAX_PORTS) { fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, @@ -1437,10 +1438,10 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ if (nof_layers >= 2 && nof_layers <= 4) { switch (mimo_decoder) { case SRSLTE_MIMO_DECODER_ZF: - return srslte_predecoding_ccd_zf(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols); + return srslte_predecoding_ccd_zf(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, scaling); break; case SRSLTE_MIMO_DECODER_MMSE: - return srslte_predecoding_ccd_mmse(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, noise_estimate); + return srslte_predecoding_ccd_mmse(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, scaling, noise_estimate); break; } } else { @@ -1451,16 +1452,16 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ return -1; case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: if (nof_ports == 1 && nof_layers == 1) { - return srslte_predecoding_single_multi(y, h[0], x[0], nof_rxant, nof_symbols, noise_estimate); + return srslte_predecoding_single_multi(y, h[0], x[0], nof_rxant, nof_symbols, scaling, noise_estimate); } else { fprintf(stderr, - "Number of ports and layers must be 1 for transmission on single antenna ports\n"); + "Number of ports and layers must be 1 for transmission on single antenna ports (%d, %d)\n", nof_ports, nof_layers); return -1; } break; case SRSLTE_MIMO_TYPE_TX_DIVERSITY: if (nof_ports == nof_layers) { - return srslte_predecoding_diversity_multi(y, h, x, nof_rxant, nof_ports, nof_symbols); + return srslte_predecoding_diversity_multi(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling); } else { fprintf(stderr, "Error number of layers must equal number of ports in transmit diversity\n"); @@ -1469,7 +1470,7 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ break; case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: return srslte_predecoding_multiplex(y, h, x, nof_rxant, nof_ports, nof_layers, codebook_idx, nof_symbols, - noise_estimate); + scaling, noise_estimate); default: return SRSLTE_ERROR; } @@ -1487,12 +1488,16 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ * **************************************************/ -int srslte_precoding_single(cf_t *x, cf_t *y, int nof_symbols) { - memcpy(y, x, nof_symbols * sizeof(cf_t)); +int srslte_precoding_single(cf_t *x, cf_t *y, int nof_symbols, float scaling) { + if (scaling == 1.0f) { + memcpy(y, x, nof_symbols * sizeof(cf_t)); + } else { + srslte_vec_sc_prod_cfc(x, scaling, y, (uint32_t) nof_symbols); + } return nof_symbols; } int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_ports, - int nof_symbols) { + int nof_symbols, float scaling) { int i; if (nof_ports == 2) { for (i = 0; i < nof_symbols; i++) { @@ -1502,32 +1507,34 @@ int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO y[1][2 * i + 1] = conjf(x[0][i]); } // normalize - srslte_vec_sc_prod_cfc(y[0], 1.0/sqrtf(2), y[0], 2*nof_symbols); - srslte_vec_sc_prod_cfc(y[1], 1.0/sqrtf(2), y[1], 2*nof_symbols); + srslte_vec_sc_prod_cfc(y[0], scaling/sqrtf(2), y[0], 2*nof_symbols); + srslte_vec_sc_prod_cfc(y[1], scaling/sqrtf(2), y[1], 2*nof_symbols); return 2 * i; } else if (nof_ports == 4) { + scaling /= sqrtf(2); + //int m_ap = (nof_symbols%4)?(nof_symbols*4-2):nof_symbols*4; int m_ap = 4 * nof_symbols; for (i = 0; i < m_ap / 4; i++) { - y[0][4 * i] = x[0][i] / sqrtf(2); + y[0][4 * i] = x[0][i] * scaling; y[1][4 * i] = 0; - y[2][4 * i] = -conjf(x[1][i]) / sqrtf(2); + y[2][4 * i] = -conjf(x[1][i]) * scaling; y[3][4 * i] = 0; - y[0][4 * i + 1] = x[1][i] / sqrtf(2); + y[0][4 * i + 1] = x[1][i] * scaling; y[1][4 * i + 1] = 0; - y[2][4 * i + 1] = conjf(x[0][i]) / sqrtf(2); + y[2][4 * i + 1] = conjf(x[0][i]) * scaling; y[3][4 * i + 1] = 0; y[0][4 * i + 2] = 0; - y[1][4 * i + 2] = x[2][i] / sqrtf(2); + y[1][4 * i + 2] = x[2][i] * scaling; y[2][4 * i + 2] = 0; - y[3][4 * i + 2] = -conjf(x[3][i]) / sqrtf(2); + y[3][4 * i + 2] = -conjf(x[3][i]) * scaling; y[0][4 * i + 3] = 0; - y[1][4 * i + 3] = x[3][i] / sqrtf(2); + y[1][4 * i + 3] = x[3][i] * scaling; y[2][4 * i + 3] = 0; - y[3][4 * i + 3] = conjf(x[2][i]) / sqrtf(2); + y[3][4 * i + 3] = conjf(x[2][i]) * scaling; } return 4 * i; } else { @@ -1538,9 +1545,9 @@ int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO #ifdef LV_HAVE_AVX -int srslte_precoding_cdd_2x2_avx(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols) +int srslte_precoding_cdd_2x2_avx(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols, float scaling) { - __m256 norm_avx = _mm256_set1_ps(0.5f); + __m256 norm_avx = _mm256_set1_ps(0.5f * scaling); for (int i = 0; i < nof_symbols - 3; i += 4) { __m256 x0 = _mm256_load_ps((float*) &x[0][i]); __m256 x1 = _mm256_load_ps((float*) &x[1][i]); @@ -1563,9 +1570,9 @@ int srslte_precoding_cdd_2x2_avx(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_ #ifdef LV_HAVE_SSE -int srslte_precoding_cdd_2x2_sse(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols) +int srslte_precoding_cdd_2x2_sse(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols, float scaling) { - __m128 norm_sse = _mm_set1_ps(0.5f); + __m128 norm_sse = _mm_set1_ps(0.5f * scaling); for (int i = 0; i < nof_symbols - 1; i += 2) { __m128 x0 = _mm_load_ps((float*) &x[0][i]); __m128 x1 = _mm_load_ps((float*) &x[1][i]); @@ -1587,19 +1594,20 @@ int srslte_precoding_cdd_2x2_sse(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_ #endif /* LV_HAVE_SSE */ -int srslte_precoding_cdd_2x2_gen(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols) +int srslte_precoding_cdd_2x2_gen(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols, float scaling) { + scaling /= 2.0f; for (int i = 0; i < nof_symbols; i++) { - y[0][i] = (x[0][i]+x[1][i])/2.0f; - y[1][i] = (x[0][i]-x[1][i])/2.0f; + y[0][i] = (x[0][i]+x[1][i]) * scaling; + y[1][i] = (x[0][i]-x[1][i]) * scaling; i++; - y[0][i] = (x[0][i]+x[1][i])/2.0f; - y[1][i] = (-x[0][i]+x[1][i])/2.0f; + y[0][i] = (x[0][i]+x[1][i]) * scaling; + y[1][i] = (-x[0][i]+x[1][i]) * scaling; } return 2 * nof_symbols; } -int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols) +int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols, float scaling) { if (nof_ports == 2) { if (nof_layers != 2) { @@ -1607,12 +1615,12 @@ int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], return -1; } #ifdef LV_HAVE_AVX - return srslte_precoding_cdd_2x2_avx(x, y, nof_symbols); + return srslte_precoding_cdd_2x2_avx(x, y, nof_symbols, scaling); #else #ifdef LV_HAVE_SSE - return srslte_precoding_cdd_2x2_sse(x, y, nof_symbols); + return srslte_precoding_cdd_2x2_sse(x, y, nof_symbols, scaling); #else - return srslte_precoding_cdd_2x2_gen(x, y, nof_symbols); + return srslte_precoding_cdd_2x2_gen(x, y, nof_symbols, scaling); #endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_AVX */ } else if (nof_ports == 4) { @@ -1625,27 +1633,28 @@ int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], } int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, - int codebook_idx, uint32_t nof_symbols) + int codebook_idx, uint32_t nof_symbols, float scaling) { int i = 0; if (nof_ports == 2) { if (nof_layers == 1) { + scaling /= sqrtf(2.0f); switch(codebook_idx) { case 0: - srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); - srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[1], nof_symbols); + srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols); + srslte_vec_sc_prod_cfc(x[0], scaling, y[1], nof_symbols); break; case 1: - srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); - srslte_vec_sc_prod_cfc(x[0], -1.0f/sqrtf(2.0f), y[1], nof_symbols); + srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols); + srslte_vec_sc_prod_cfc(x[0], -scaling, y[1], nof_symbols); break; case 2: - srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); - srslte_vec_sc_prod_ccc(x[0], _Complex_I/sqrtf(2.0f), y[1], nof_symbols); + srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols); + srslte_vec_sc_prod_ccc(x[0], _Complex_I * scaling, y[1], nof_symbols); break; case 3: - srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); - srslte_vec_sc_prod_ccc(x[0], -_Complex_I/sqrtf(2.0f), y[1], nof_symbols); + srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols); + srslte_vec_sc_prod_ccc(x[0], -_Complex_I * scaling, y[1], nof_symbols); break; default: fprintf(stderr, "Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n", @@ -1655,49 +1664,52 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO } else if (nof_layers == 2) { switch(codebook_idx) { case 0: - srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); - srslte_vec_sc_prod_cfc(x[1], 1.0f/sqrtf(2.0f), y[1], nof_symbols); + scaling /= sqrtf(2.0f); + srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols); + srslte_vec_sc_prod_cfc(x[1], scaling, y[1], nof_symbols); break; case 1: + scaling /= 2.0f; #ifdef LV_HAVE_AVX for (; i < nof_symbols - 3; i += 4) { - __m256 x0 = _mm256_load_ps((float*)&x[0][i]); - __m256 x1 = _mm256_load_ps((float*)&x[1][i]); + __m256 x0 = _mm256_load_ps((float *) &x[0][i]); + __m256 x1 = _mm256_load_ps((float *) &x[1][i]); - __m256 y0 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_add_ps(x0, x1)); - __m256 y1 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_sub_ps(x0, x1)); + __m256 y0 = _mm256_mul_ps(_mm256_set1_ps(scaling), _mm256_add_ps(x0, x1)); + __m256 y1 = _mm256_mul_ps(_mm256_set1_ps(scaling), _mm256_sub_ps(x0, x1)); - _mm256_store_ps((float*)&y[0][i], y0); - _mm256_store_ps((float*)&y[1][i], y1); + _mm256_store_ps((float *) &y[0][i], y0); + _mm256_store_ps((float *) &y[1][i], y1); } #endif /* LV_HAVE_AVX */ #ifdef LV_HAVE_SSE for (; i < nof_symbols - 1; i += 2) { - __m128 x0 = _mm_load_ps((float*)&x[0][i]); - __m128 x1 = _mm_load_ps((float*)&x[1][i]); + __m128 x0 = _mm_load_ps((float *) &x[0][i]); + __m128 x1 = _mm_load_ps((float *) &x[1][i]); - __m128 y0 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_add_ps(x0, x1)); - __m128 y1 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_sub_ps(x0, x1)); + __m128 y0 = _mm_mul_ps(_mm_set1_ps(scaling), _mm_add_ps(x0, x1)); + __m128 y1 = _mm_mul_ps(_mm_set1_ps(scaling), _mm_sub_ps(x0, x1)); - _mm_store_ps((float*)&y[0][i], y0); - _mm_store_ps((float*)&y[1][i], y1); + _mm_store_ps((float *) &y[0][i], y0); + _mm_store_ps((float *) &y[1][i], y1); } #endif /* LV_HAVE_SSE */ for (; i < nof_symbols; i++) { - y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; - y[1][i] = 0.5f*x[0][i] - 0.5f*x[1][i]; + y[0][i] = (x[0][i] + x[1][i]) * scaling; + y[1][i] = (x[0][i] - x[1][i]) * scaling; } break; case 2: + scaling /= 2.0f; #ifdef LV_HAVE_AVX for (; i < nof_symbols - 3; i += 4) { __m256 x0 = _mm256_load_ps((float*)&x[0][i]); __m256 x1 = _mm256_load_ps((float*)&x[1][i]); - __m256 y0 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_add_ps(x0, x1)); - __m256 y1 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _MM256_MULJ_PS(_mm256_sub_ps(x0, x1))); + __m256 y0 = _mm256_mul_ps(_mm256_set1_ps(scaling), _mm256_add_ps(x0, x1)); + __m256 y1 = _mm256_mul_ps(_mm256_set1_ps(scaling), _MM256_MULJ_PS(_mm256_sub_ps(x0, x1))); _mm256_store_ps((float*)&y[0][i], y0); _mm256_store_ps((float*)&y[1][i], y1); @@ -1709,8 +1721,8 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO __m128 x0 = _mm_load_ps((float*)&x[0][i]); __m128 x1 = _mm_load_ps((float*)&x[1][i]); - __m128 y0 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_add_ps(x0, x1)); - __m128 y1 = _mm_mul_ps(_mm_set1_ps(0.5f), _MM_MULJ_PS(_mm_sub_ps(x0, x1))); + __m128 y0 = _mm_mul_ps(_mm_set1_ps(scaling), _mm_add_ps(x0, x1)); + __m128 y1 = _mm_mul_ps(_mm_set1_ps(scaling), _MM_MULJ_PS(_mm_sub_ps(x0, x1))); _mm_store_ps((float*)&y[0][i], y0); _mm_store_ps((float*)&y[1][i], y1); @@ -1718,8 +1730,8 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO #endif /* LV_HAVE_SSE */ for (; i < nof_symbols; i++) { - y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; - y[1][i] = 0.5f*_Complex_I*x[0][i] - 0.5f*_Complex_I*x[1][i]; + y[0][i] = (x[0][i] + x[1][i])*scaling; + y[1][i] = (_Complex_I*x[0][i] - _Complex_I*x[1][i])*scaling; } break; case 3: @@ -1739,7 +1751,7 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO /* 36.211 v10.3.0 Section 6.3.4 */ int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, - int nof_ports, int codebook_idx, int nof_symbols, srslte_mimo_type_t type) { + int nof_ports, int codebook_idx, int nof_symbols, float scaling, srslte_mimo_type_t type) { if (nof_ports > SRSLTE_MAX_PORTS) { fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, @@ -1754,10 +1766,10 @@ int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], switch (type) { case SRSLTE_MIMO_TYPE_CDD: - return srslte_precoding_cdd(x, y, nof_layers, nof_ports, nof_symbols); + return srslte_precoding_cdd(x, y, nof_layers, nof_ports, nof_symbols, scaling); case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: if (nof_ports == 1 && nof_layers == 1) { - return srslte_precoding_single(x[0], y[0], nof_symbols); + return srslte_precoding_single(x[0], y[0], nof_symbols, scaling); } else { fprintf(stderr, "Number of ports and layers must be 1 for transmission on single antenna ports\n"); @@ -1766,14 +1778,14 @@ int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], break; case SRSLTE_MIMO_TYPE_TX_DIVERSITY: if (nof_ports == nof_layers) { - return srslte_precoding_diversity(x, y, nof_ports, nof_symbols); + return srslte_precoding_diversity(x, y, nof_ports, nof_symbols, scaling); } else { fprintf(stderr, "Error number of layers must equal number of ports in transmit diversity\n"); return -1; } case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - return srslte_precoding_multiplex(x, y, nof_layers, nof_ports, codebook_idx, nof_symbols); + return srslte_precoding_multiplex(x, y, nof_layers, nof_ports, codebook_idx, (uint32_t) nof_symbols, scaling); default: return SRSLTE_ERROR; } diff --git a/lib/src/phy/mimo/test/precoder_test.c b/lib/src/phy/mimo/test/precoder_test.c index 1bbd9e3c0..589e3d51c 100644 --- a/lib/src/phy/mimo/test/precoder_test.c +++ b/lib/src/phy/mimo/test/precoder_test.c @@ -44,14 +44,16 @@ int nof_layers = 1, nof_tx_ports = 1, nof_rx_ports = 1, nof_re = 1; char *mimo_type_name = NULL; char decoder_type_name [16] = "zf"; float snr_db = 100.0f; +float scaling = 0.1f; void usage(char *prog) { printf( "Usage: %s -m [single|diversity|multiplex|cdd] -l [nof_layers] -p [nof_tx_ports]\n" - " -r [nof_rx_ports]\n", prog); + " -r [nof_rx_ports] -g [scaling]\n", prog); printf("\t-n num_symbols [Default %d]\n", nof_symbols); printf("\t-c codebook_idx [Default %d]\n", codebook_idx); printf("\t-s SNR in dB [Default %.1fdB]*\n", snr_db); + printf("\t-g Scaling [Default %.1f]*\n", scaling); printf("\t-d decoder type [zf|mmse] [Default %s]\n", decoder_type_name); printf("\n"); printf("* Performance test example:\n\t for snr in {0..20..1}; do ./precoding_test -m single -s $snr; done; \n\n", decoder_type_name); @@ -59,7 +61,7 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "mplnrcds")) != -1) { + while ((opt = getopt(argc, argv, "mplnrcdsg")) != -1) { switch (opt) { case 'n': nof_symbols = atoi(argv[optind]); @@ -85,6 +87,9 @@ void parse_args(int argc, char **argv) { case 's': snr_db = (float) atof(argv[optind]); break; + case 'g': + scaling = (float) atof(argv[optind]); + break; default: usage(argv[0]); exit(-1); @@ -149,7 +154,7 @@ void populate_channel(srslte_mimo_type_t type, cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_ static void awgn(cf_t *y[SRSLTE_MAX_PORTS], uint32_t n, float snr) { int i; - float std_dev = powf(10, - (snr + 3.0f) / 20.0f); + float std_dev = powf(10, - (snr + 3.0f) / 20.0f) * scaling; for (i = 0; i < nof_rx_ports; i++) { srslte_ch_awgn_c(y[i], y[i], std_dev, n); @@ -250,7 +255,7 @@ int main(int argc, char **argv) { } /* Execute Precoding (Tx) */ - if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, codebook_idx, nof_symbols, type) < 0) { + if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, codebook_idx, nof_symbols, scaling, type) < 0) { fprintf(stderr, "Error layer mapper encoder\n"); exit(-1); } @@ -285,8 +290,8 @@ int main(int argc, char **argv) { /* predecoding / equalization */ struct timeval t[3]; gettimeofday(&t[1], NULL); - srslte_predecoding_type_multi(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers, - codebook_idx, nof_re, type, powf(10, -snr_db/10)); + srslte_predecoding_type(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers, + codebook_idx, nof_re, type, scaling, powf(10, -snr_db / 10)); gettimeofday(&t[2], NULL); get_time_interval(t); diff --git a/lib/src/phy/modem/demod_hard.c b/lib/src/phy/modem/demod_hard.c index 76f54236d..899559ecc 100644 --- a/lib/src/phy/modem/demod_hard.c +++ b/lib/src/phy/modem/demod_hard.c @@ -44,6 +44,7 @@ int srslte_demod_hard_demodulate(srslte_demod_hard_t* q, cf_t* symbols, uint8_t int nbits=-1; switch(q->mod) { + case SRSLTE_MOD_LAST: case SRSLTE_MOD_BPSK: hard_bpsk_demod(symbols,bits,nsymbols); nbits=nsymbols; diff --git a/lib/src/phy/modem/demod_soft.c b/lib/src/phy/modem/demod_soft.c index 259a12271..0ea3ce938 100644 --- a/lib/src/phy/modem/demod_soft.c +++ b/lib/src/phy/modem/demod_soft.c @@ -57,11 +57,11 @@ void demod_bpsk_lte(const cf_t *symbols, float *llr, int nsymbols) { } void demod_qpsk_lte_s(const cf_t *symbols, short *llr, int nsymbols) { - srslte_vec_convert_fi((float*) symbols, llr, -SCALE_SHORT_CONV_QPSK*sqrt(2), nsymbols*2); + srslte_vec_convert_fi((const float*) symbols, -SCALE_SHORT_CONV_QPSK*sqrt(2), llr, nsymbols*2); } void demod_qpsk_lte(const cf_t *symbols, float *llr, int nsymbols) { - srslte_vec_sc_prod_fff((float*) symbols, -sqrt(2), llr, nsymbols*2); + srslte_vec_sc_prod_fff((const float*) symbols, -sqrt(2), llr, nsymbols*2); } void demod_16qam_lte(const cf_t *symbols, float *llr, int nsymbols) { diff --git a/lib/src/phy/modem/modem_table.c b/lib/src/phy/modem/modem_table.c index c19e52e77..3c4ad2417 100644 --- a/lib/src/phy/modem/modem_table.c +++ b/lib/src/phy/modem/modem_table.c @@ -82,6 +82,7 @@ int srslte_modem_table_set(srslte_modem_table_t* q, cf_t* table, uint32_t nsymbo int srslte_modem_table_lte(srslte_modem_table_t* q, srslte_mod_t modulation) { srslte_modem_table_init(q); switch(modulation) { + case SRSLTE_MOD_LAST: case SRSLTE_MOD_BPSK: q->nbits_x_symbol = 1; q->nsymbols = 2; diff --git a/lib/src/phy/phch/cqi.c b/lib/src/phy/phch/cqi.c index 0041c3fcb..8589ee51a 100644 --- a/lib/src/phy/phch/cqi.c +++ b/lib/src/phy/phch/cqi.c @@ -44,11 +44,38 @@ *******************************************************/ int srslte_cqi_hl_subband_pack(srslte_cqi_hl_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]) { - uint8_t *body_ptr = buff; - srslte_bit_unpack(msg->wideband_cqi, &body_ptr, 4); - srslte_bit_unpack(msg->subband_diff_cqi, &body_ptr, 2*msg->N); - - return 4+2*msg->N; + uint8_t *body_ptr = buff; + uint32_t bit_count = 0; + + /* Unpack codeword 0, common for 3GPP 36.212 Tables 5.2.2.6.2-1 and 5.2.2.6.2-2 */ + srslte_bit_unpack(msg->wideband_cqi_cw0, &body_ptr, 4); + srslte_bit_unpack(msg->subband_diff_cqi_cw0, &body_ptr, 2*msg->N); + bit_count += 4+2*msg->N; + + /* Unpack codeword 1, 3GPP 36.212 Table 5.2.2.6.2-2 */ + if (msg->rank_is_not_one) { + srslte_bit_unpack(msg->wideband_cqi_cw1, &body_ptr, 4); + srslte_bit_unpack(msg->subband_diff_cqi_cw1, &body_ptr, 2*msg->N); + bit_count += 4+2*msg->N; + } + + /* If PMI is present, unpack it */ + if (msg->pmi_present) { + if (msg->four_antenna_ports) { + srslte_bit_unpack(msg->pmi, &body_ptr, 4); + bit_count += 4; + } else { + if (msg->rank_is_not_one) { + srslte_bit_unpack(msg->pmi, &body_ptr, 1); + bit_count += 1; + } else { + srslte_bit_unpack(msg->pmi, &body_ptr, 2); + bit_count += 2; + } + } + } + + return bit_count; } int srslte_cqi_ue_subband_pack(srslte_cqi_ue_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]) @@ -98,11 +125,37 @@ int srslte_cqi_value_pack(srslte_cqi_value_t *value, uint8_t buff[SRSLTE_CQI_MAX int srslte_cqi_hl_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_hl_subband_t *msg) { - uint8_t *body_ptr = buff; - msg->wideband_cqi = srslte_bit_pack(&body_ptr, 4); - msg->subband_diff_cqi = srslte_bit_pack(&body_ptr, 2*msg->N); - - return 4+2*msg->N; + uint8_t *body_ptr = buff; + uint32_t bit_count = 0; + + msg->wideband_cqi_cw0 = (uint8_t) srslte_bit_pack(&body_ptr, 4); + msg->subband_diff_cqi_cw0 = srslte_bit_pack(&body_ptr, 2*msg->N); + bit_count += 4+2*msg->N; + + /* Unpack codeword 1, 3GPP 36.212 Table 5.2.2.6.2-2 */ + if (msg->rank_is_not_one) { + msg->wideband_cqi_cw1 = (uint8_t) srslte_bit_pack(&body_ptr, 4); + msg->subband_diff_cqi_cw1 = srslte_bit_pack(&body_ptr, 2*msg->N); + bit_count += 4+2*msg->N; + } + + /* If PMI is present, unpack it */ + if (msg->pmi_present) { + if (msg->four_antenna_ports) { + msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 4); + bit_count += 4; + } else { + if (msg->rank_is_not_one) { + msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 1); + bit_count += 1; + } else { + msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 2); + bit_count += 2; + } + } + } + + return bit_count; } int srslte_cqi_ue_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_ue_subband_t *msg) @@ -146,17 +199,44 @@ int srslte_cqi_value_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_value_ } int srslte_cqi_size(srslte_cqi_value_t *value) { + int size = 0; + switch(value->type) { case SRSLTE_CQI_TYPE_WIDEBAND: - return 4; + size = 4; + break; case SRSLTE_CQI_TYPE_SUBBAND: - return 4+(value->subband.subband_label_2_bits)?2:1; + size = 4 + (value->subband.subband_label_2_bits) ? 2 : 1; + break; case SRSLTE_CQI_TYPE_SUBBAND_UE: - return 4+2+value->subband_ue.L; + size = 4 + 2 + value->subband_ue.L; + break; case SRSLTE_CQI_TYPE_SUBBAND_HL: - return 4+2*value->subband_hl.N; + /* First codeword */ + size += 4 + 2 * value->subband_hl.N; + + /* Add Second codeword if required */ + if (value->subband_hl.rank_is_not_one && value->subband_hl.pmi_present) { + size += 4 + 2 * value->subband_hl.N; + } + + /* Add PMI if required*/ + if (value->subband_hl.pmi_present) { + if (value->subband_hl.four_antenna_ports) { + size += 4; + } else { + if (value->subband_hl.rank_is_not_one) { + size += 1; + } else { + size += 2; + } + } + } + break; + default: + size = SRSLTE_ERROR; } - return -1; + return size; } static bool srslte_cqi_get_N(uint32_t I_cqi_pmi, uint32_t *N_p, uint32_t *N_offset) { diff --git a/lib/src/phy/phch/dci.c b/lib/src/phy/phch/dci.c index 2daa7e10d..01ad7fb61 100644 --- a/lib/src/phy/phch/dci.c +++ b/lib/src/phy/phch/dci.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "srslte/phy/phch/dci.h" #include "srslte/phy/common/phy_common.h" @@ -111,7 +112,7 @@ int srslte_dci_rar_to_ul_grant(srslte_dci_rar_grant_t *rar, uint32_t nof_prb, srslte_ra_type2_from_riv(riv, &ul_dci->type2_alloc.L_crb, &ul_dci->type2_alloc.RB_start, nof_prb, nof_prb); - if (srslte_ra_ul_dci_to_grant(ul_dci, nof_prb, n_rb_ho, grant, 0)) { + if (srslte_ra_ul_dci_to_grant(ul_dci, nof_prb, n_rb_ho, grant)) { return SRSLTE_ERROR; } @@ -177,7 +178,7 @@ int srslte_dci_msg_to_ul_grant(srslte_dci_msg_t *msg, uint32_t nof_prb, return ret; } - if (srslte_ra_ul_dci_to_grant(ul_dci, nof_prb, n_rb_ho, grant, harq_pid)) { + if (srslte_ra_ul_dci_to_grant(ul_dci, nof_prb, n_rb_ho, grant)) { return ret; } @@ -359,6 +360,101 @@ uint32_t dci_format2B_sizeof(uint32_t nof_prb, uint32_t nof_ports) { } +uint32_t srslte_dci_dl_info(char *info_str, uint32_t len, srslte_ra_dl_dci_t *dci_msg, srslte_dci_format_t format) +{ + int n = 0; + + switch(dci_msg->alloc_type) { + case SRSLTE_RA_ALLOC_TYPE0: + n += snprintf(&info_str[n], len-n, "type0={rbg=0x%x}, ", dci_msg->type0_alloc.rbg_bitmask); + break; + case SRSLTE_RA_ALLOC_TYPE1: + n += snprintf(&info_str[n], len-n, "type1={vrb=0x%x, rbg_s=%d, sh=%d}, ", + dci_msg->type1_alloc.vrb_bitmask, dci_msg->type1_alloc.rbg_subset, dci_msg->type1_alloc.shift); + break; + case SRSLTE_RA_ALLOC_TYPE2: + n += snprintf(&info_str[n], len-n, "type2={riv=%d, rb=(%d,%d), mode=%s", + dci_msg->type2_alloc.riv, + dci_msg->type2_alloc.RB_start, dci_msg->type2_alloc.RB_start+dci_msg->type2_alloc.L_crb-1, + dci_msg->type2_alloc.mode==SRSLTE_RA_TYPE2_LOC?"local":"dist"); + if (dci_msg->type2_alloc.mode==SRSLTE_RA_TYPE2_LOC) { + n += snprintf(&info_str[n], len-n, ", ngap=%s, nprb1a=%d", + dci_msg->type2_alloc.n_gap==SRSLTE_RA_TYPE2_NG1?"ng1":"ng2", + dci_msg->type2_alloc.n_prb1a==SRSLTE_RA_TYPE2_NPRB1A_2?2:3); + } + n += snprintf(&info_str[n], len-n, "}, "); + break; + } + n += snprintf(&info_str[n], len-n, "pid=%d, ", dci_msg->harq_process); + + n += snprintf(&info_str[n], len-n, "mcs={"); + if (dci_msg->tb_en[0]) { + n += snprintf(&info_str[n], len-n, "%d", dci_msg->mcs_idx); + if (dci_msg->tb_en[1]) { + n += snprintf(&info_str[n], len-n, ","); + } else { + n += snprintf(&info_str[n], len-n, "}, "); + } + } + if (dci_msg->tb_en[1]) { + n += snprintf(&info_str[n], len - n, "%d}, ", dci_msg->mcs_idx_1); + } + n += snprintf(&info_str[n], len-n, "rv={"); + if (dci_msg->tb_en[0]) { + n += snprintf(&info_str[n], len-n, "%d", dci_msg->rv_idx); + if (dci_msg->tb_en[1]) { + n += snprintf(&info_str[n], len-n, ","); + } else { + n += snprintf(&info_str[n], len-n, "}, "); + } + } + if (dci_msg->tb_en[1]) { + n += snprintf(&info_str[n], len - n, "%d}, ", dci_msg->rv_idx_1); + } + n += snprintf(&info_str[n], len-n, "ndi={"); + if (dci_msg->tb_en[0]) { + n += snprintf(&info_str[n], len-n, "%d", dci_msg->ndi); + if (dci_msg->tb_en[1]) { + n += snprintf(&info_str[n], len-n, ","); + } else { + n += snprintf(&info_str[n], len-n, "}, "); + } + } + if (dci_msg->tb_en[1]) { + n += snprintf(&info_str[n], len - n, "%d}, ", dci_msg->ndi_1); + } + + if (format == SRSLTE_DCI_FORMAT1 || format == SRSLTE_DCI_FORMAT1A || format == SRSLTE_DCI_FORMAT1B) { + n += snprintf(&info_str[n], len-n, "tpc_pucch=%d, ", dci_msg->tpc_pucch); + } + if (format == SRSLTE_DCI_FORMAT2 || format == SRSLTE_DCI_FORMAT2A || format == SRSLTE_DCI_FORMAT2B) { + n += snprintf(&info_str[n], len-n, "tb_sw=%d, pinfo=%d, ", dci_msg->tb_cw_swap, dci_msg->pinfo); + } + return n; +} + +uint32_t srslte_dci_ul_info(char *info_str, uint32_t len, srslte_ra_ul_dci_t *dci_msg) +{ + int n = 0; + + n += snprintf(&info_str[n], len-n, "riv=%d, rb=(%d,%d), ", dci_msg->type2_alloc.riv, + dci_msg->type2_alloc.RB_start, dci_msg->type2_alloc.RB_start+dci_msg->type2_alloc.L_crb-1); + + switch(dci_msg->freq_hop_fl) { + case SRSLTE_RA_PUSCH_HOP_DISABLED: + n += snprintf(&info_str[n], len-n, "f_h=n/a, "); + break; + default: + n += snprintf(&info_str[n], len-n, "f_h=%d, ", dci_msg->freq_hop_fl); + break; + } + n += snprintf(&info_str[n], len-n, "mcs=%d, rv=%d, ndi=%d, ", dci_msg->mcs_idx, dci_msg->rv_idx, dci_msg->ndi); + n += snprintf(&info_str[n], len-n, "tpc_pusch=%d, dmrs_cs=%d, cqi=%s, ", + dci_msg->tpc_pusch, dci_msg->n_dmrs, dci_msg->cqi_request?"yes":"no"); + + return n; +} + uint32_t srslte_dci_format_sizeof(srslte_dci_format_t format, uint32_t nof_prb, uint32_t nof_ports) { switch (format) { case SRSLTE_DCI_FORMAT0: @@ -1159,7 +1255,32 @@ int dci_format2AB_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32 } else if (msg->format == SRSLTE_DCI_FORMAT2A) { data->pinfo = srslte_bit_pack(&y, precoding_bits_f2a(nof_ports)); } - + + // Table 5.3.3.1.5-1 + if (SRSLTE_RA_DL_GRANT_NOF_TB(data) == 2) { + if (data->tb_cw_swap) { + uint32_t tmp = data->rv_idx; + data->rv_idx = data->rv_idx_1; + data->rv_idx_1 = tmp; + + tmp = data->mcs_idx; + data->mcs_idx = data->mcs_idx_1; + data->mcs_idx_1 = tmp; + + bool tmp_ndi = data->ndi; + data->ndi = data->ndi_1; + data->ndi_1 = tmp_ndi; + } + } + + // Table 5.3.3.1.5-2 + if (!data->tb_en[0]) { + data->rv_idx = data->rv_idx_1; + data->mcs_idx = data->mcs_idx_1; + data->ndi = data->ndi_1; + + data->tb_en[1] = false; + } return SRSLTE_SUCCESS; } @@ -1276,6 +1397,32 @@ char* srslte_dci_format_string(srslte_dci_format_t format) { } } + +char* srslte_dci_format_string_short(srslte_dci_format_t format) { + switch (format) { + case SRSLTE_DCI_FORMAT0: + return "0"; + case SRSLTE_DCI_FORMAT1: + return "1"; + case SRSLTE_DCI_FORMAT1A: + return "1A"; + case SRSLTE_DCI_FORMAT1B: + return "1B"; + case SRSLTE_DCI_FORMAT1C: + return "1C"; + case SRSLTE_DCI_FORMAT1D: + return "1D"; + case SRSLTE_DCI_FORMAT2: + return "2"; + case SRSLTE_DCI_FORMAT2A: + return "2A"; + case SRSLTE_DCI_FORMAT2B: + return "2B"; + default: + return "N/A"; // fatal error + } +} + void srslte_dci_msg_type_fprint(FILE *f, srslte_dci_msg_type_t type) { switch (type.type) { case SRSLTE_DCI_MSG_TYPE_PUSCH_SCHED: diff --git a/lib/src/phy/phch/pbch.c b/lib/src/phy/phch/pbch.c index 2eaa20501..c72b12c60 100644 --- a/lib/src/phy/phch/pbch.c +++ b/lib/src/phy/phch/pbch.c @@ -497,10 +497,10 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS /* in control channels, only diversity is supported */ if (nant == 1) { /* no need for layer demapping */ - srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, noise_estimate); + srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, 1.0f, noise_estimate); } else { srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant, - q->nof_symbols); + q->nof_symbols, 1.0f); srslte_layerdemap_diversity(x, q->d, nant, q->nof_symbols / nant); } @@ -591,7 +591,7 @@ int srslte_pbch_encode(srslte_pbch_t *q, uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_ if (q->cell.nof_ports > 1) { srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols); srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, - q->nof_symbols / q->cell.nof_ports); + q->nof_symbols / q->cell.nof_ports, 1.0f); } else { memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); } diff --git a/lib/src/phy/phch/pcfich.c b/lib/src/phy/phch/pcfich.c index d960504fe..7269000a8 100644 --- a/lib/src/phy/phch/pcfich.c +++ b/lib/src/phy/phch/pcfich.c @@ -219,9 +219,9 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, q->nof_rx_antennas, q->nof_symbols, noise_estimate); + srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, q->nof_rx_antennas, q->nof_symbols, 1.0f, noise_estimate); } else { - srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols); + srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols, 1.0f); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); } @@ -278,7 +278,7 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR /* layer mapping & precoding */ if (q->cell.nof_ports > 1) { srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols); - srslte_precoding_diversity(x, q_symbols, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); + srslte_precoding_diversity(x, q_symbols, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports, 1.0f); } else { memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); } diff --git a/lib/src/phy/phch/pdcch.c b/lib/src/phy/phch/pdcch.c index 215324e6b..ca8480bc6 100644 --- a/lib/src/phy/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -218,13 +218,20 @@ uint32_t srslte_pdcch_ue_locations(srslte_pdcch_t *q, srslte_dci_location_t *c, return srslte_pdcch_ue_locations_ncce(q->nof_cce, c, max_candidates, nsubframe, rnti); } + +uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, srslte_dci_location_t *c, uint32_t max_candidates, + uint32_t nsubframe, uint16_t rnti) +{ + return srslte_pdcch_ue_locations_ncce_L(nof_cce, c, max_candidates, nsubframe, rnti, -1); +} + /** 36.213 v9.1.1 * Computes up to max_candidates UE-specific candidates for DCI messages and saves them * in the structure pointed by c. * Returns the number of candidates saved in the array c. */ -uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, srslte_dci_location_t *c, uint32_t max_candidates, - uint32_t nsubframe, uint16_t rnti) { +uint32_t srslte_pdcch_ue_locations_ncce_L(uint32_t nof_cce, srslte_dci_location_t *c, uint32_t max_candidates, + uint32_t nsubframe, uint16_t rnti, int Ls) { int l; // this must be int because of the for(;;--) loop uint32_t i, k, L, m; @@ -241,24 +248,26 @@ uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, srslte_dci_location_t // All aggregation levels from 8 to 1 for (l = 3; l >= 0; l--) { L = (1 << l); - // For all candidates as given in table 9.1.1-1 - for (i = 0; i < nof_candidates[l]; i++) { - if (nof_cce >= L) { - ncce = L * ((Yk + i) % (nof_cce / L)); - // Check if candidate fits in c vector and in CCE region - if (k < max_candidates && ncce + L <= nof_cce) - { - c[k].L = l; - c[k].ncce = ncce; - - DEBUG("UE-specific SS Candidate %d: nCCE: %d, L: %d\n", - k, c[k].ncce, c[k].L); + if (Ls<0 || Ls==L) { + // For all candidates as given in table 9.1.1-1 + for (i = 0; i < nof_candidates[l]; i++) { + if (nof_cce >= L) { + ncce = L * ((Yk + i) % (nof_cce / L)); + // Check if candidate fits in c vector and in CCE region + if (k < max_candidates && ncce + L <= nof_cce) + { + c[k].L = l; + c[k].ncce = ncce; - k++; - } + DEBUG("UE-specific SS Candidate %d: nCCE: %d, L: %d\n", + k, c[k].ncce, c[k].L); + + k++; + } + } } } - } + } DEBUG("Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x, nsubframe=%d, nof_cce=%d\n", k, rnti, nsubframe, nof_cce); @@ -485,9 +494,9 @@ int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MA /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, nof_symbols, noise_estimate/2); + srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, nof_symbols, 1.0f, noise_estimate/2); } else { - srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols); + srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols, 1.0f); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); } @@ -618,7 +627,7 @@ int srslte_pdcch_encode(srslte_pdcch_t *q, srslte_dci_msg_t *msg, srslte_dci_loc /* layer mapping & precoding */ if (q->cell.nof_ports > 1) { srslte_layermap_diversity(q->d, x, q->cell.nof_ports, nof_symbols); - srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); + srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports, 1.0f); } else { memcpy(q->symbols[0], q->d, nof_symbols * sizeof(cf_t)); } diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index b438a2957..70ef9d008 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -386,6 +386,12 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { return SRSLTE_SUCCESS; } +void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q, float rho_a) { + if (q) { + q->rho_a = rho_a; + } +} + void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) { uint32_t rnti_idx = q->is_ue?0:rnti; @@ -467,7 +473,7 @@ int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra for (int cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) { if (grant->tb_en[cw]) { if (srslte_cbsegm(&cfg->cb_segm[cw], (uint32_t) cfg->grant.mcs[cw].tbs)) { - fprintf(stderr, "Error computing Codeblock (1) segmentation for TBS=%d\n", cfg->grant.mcs[cw].tbs); + fprintf(stderr, "Error computing Codeword (%d) segmentation for TBS=%d\n", cw, cfg->grant.mcs[cw].tbs); return SRSLTE_ERROR; } } @@ -477,6 +483,7 @@ int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra cfg->sf_idx = sf_idx; memcpy(cfg->rv, rvidx, sizeof(uint32_t) * SRSLTE_MAX_CODEWORDS); cfg->mimo_type = mimo_type; + cfg->tb_cw_swap = grant->tb_cw_swap; /* Check and configure PDSCH transmission modes */ switch(mimo_type) { @@ -492,7 +499,7 @@ int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra ERROR("Wrong number of transport blocks (%d) for transmit diversity.", nof_tb); return SRSLTE_ERROR; } - cfg->nof_layers = 2; + cfg->nof_layers = cell.nof_ports; break; case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: if (nof_tb == 1) { @@ -543,19 +550,25 @@ static srslte_sequence_t *get_user_sequence(srslte_pdsch_t *q, uint16_t rnti, static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data, - uint32_t codeword_idx) { - srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx]; - srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx]; - uint32_t rv = cfg->rv[codeword_idx]; + uint32_t codeword_idx, uint32_t tb_idx) { + srslte_ra_nbits_t *nbits = &cfg->nbits[tb_idx]; + srslte_ra_mcs_t *mcs = &cfg->grant.mcs[tb_idx]; + uint32_t rv = cfg->rv[tb_idx]; + bool valid_inputs = true; - if (nbits->nof_bits) { - INFO("Encoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, + if (!softbuffer) { + ERROR("Error encoding (TB%d -> CW%d), softbuffer=NULL", tb_idx, codeword_idx); + valid_inputs = false; + } + + if (nbits->nof_bits && valid_inputs) { + INFO("Encoding PDSCH SF: %d (TB%d -> CW%d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + cfg->sf_idx, tb_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, nbits->nof_re, nbits->nof_bits, rv); /* Channel coding */ - if (srslte_dlsch_encode2(&q->dl_sch, cfg, softbuffer, data, q->e[codeword_idx], codeword_idx)) { - ERROR("Error encoding TB %d", codeword_idx); + if (srslte_dlsch_encode2(&q->dl_sch, cfg, softbuffer, data, q->e[codeword_idx], tb_idx)) { + ERROR("Error encoding (TB%d -> CW%d)", tb_idx, codeword_idx); return SRSLTE_ERROR; } @@ -570,6 +583,8 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c (uint8_t *) q->e[codeword_idx], q->d[codeword_idx], nbits->nof_bits); + } else { + return SRSLTE_ERROR_INVALID_INPUTS; } return SRSLTE_SUCCESS; @@ -577,15 +592,15 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint8_t *data, - uint32_t codeword_idx, bool *ack) { - srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx]; - srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx]; - uint32_t rv = cfg->rv[codeword_idx]; + uint32_t codeword_idx, uint32_t tb_idx, bool *ack) { + srslte_ra_nbits_t *nbits = &cfg->nbits[tb_idx]; + srslte_ra_mcs_t *mcs = &cfg->grant.mcs[tb_idx]; + uint32_t rv = cfg->rv[tb_idx]; int ret = SRSLTE_ERROR_INVALID_INPUTS; if (softbuffer && data && ack) { - INFO("Decoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, + INFO("Decoding PDSCH SF: %d (CW%d -> TB%d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + cfg->sf_idx, codeword_idx, tb_idx, srslte_mod_string(mcs->mod), mcs->tbs, nbits->nof_re, nbits->nof_bits, rv); /* demodulate symbols @@ -601,7 +616,7 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, nbits->nof_bits); /* Return */ - ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, codeword_idx); + ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, tb_idx); q->last_nof_iterations[codeword_idx] = srslte_sch_last_noi(&q->dl_sch); @@ -610,6 +625,9 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c } else if (ret == SRSLTE_ERROR) { *ack = false; ret = SRSLTE_SUCCESS; + } else if (ret == SRSLTE_ERROR_INVALID_INPUTS) { + *ack = false; + ret = SRSLTE_ERROR; } } else { ERROR("Detected NULL pointer in TB%d &softbuffer=%p &data=%p &ack=%p", codeword_idx, softbuffer, (void*)data, ack); @@ -676,25 +694,39 @@ int srslte_pdsch_decode(srslte_pdsch_t *q, memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); } + float pdsch_scaling = 1.0f; + if (q->rho_a != 0.0f) { + pdsch_scaling = q->rho_a; + } + // Pre-decoder - srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, - cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate); + if (srslte_predecoding_type(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, + cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, pdsch_scaling, noise_estimate)<0) { + printf("Error predecoding\n"); + return -1; + } // Layer demapping only if necessary if (cfg->nof_layers != nof_tb) { srslte_layerdemap_type(x, q->d, cfg->nof_layers, nof_tb, nof_symbols[0], nof_symbols, cfg->mimo_type); } - // Codeword decoding - for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb ++) { - /* Decode only if transport block is enabled and the default ACK is not true */ - if (cfg->grant.tb_en[tb] && !acks[tb]) { - int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb], rnti, data[tb], tb, &acks[tb]); - /* Check if there has been any execution error */ - if (ret) { - return ret; + /* Codeword decoding: Implementation of 3GPP 36.212 Table 5.3.3.1.5-1 and Table 5.3.3.1.5-2 */ + uint32_t cw_idx = (nof_tb == SRSLTE_MAX_TB && cfg->tb_cw_swap) ? 1 : 0; + for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) { + /* Decode only if transport block is enabled and the default ACK is not true */ + if (cfg->grant.tb_en[tb_idx]) { + if (!acks[tb_idx]) { + int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb_idx], rnti, data[tb_idx], cw_idx, tb_idx, &acks[tb_idx]); + + /* Check if there has been any execution error */ + if (ret) { + return ret; + } } + + cw_idx = (cw_idx + 1) % SRSLTE_MAX_CODEWORDS; } } @@ -767,20 +799,23 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, } /* If both transport block size is zero return error */ - if (cfg->grant.mcs[0].tbs == 0) { + if (!nof_tb) { return SRSLTE_ERROR_INVALID_INPUTS; } - if (cfg->nbits[0].nof_re > q->max_re) { + if (cfg->nbits[0].nof_re > q->max_re || cfg->nbits[1].nof_re > q->max_re) { fprintf(stderr, "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb); return SRSLTE_ERROR_INVALID_INPUTS; } - for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb ++) { - if (cfg->grant.tb_en[tb]) { - ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb], rnti, data[tb], tb); + /* Implementation of 3GPP 36.212 Table 5.3.3.1.5-1 and Table 5.3.3.1.5-2 */ + uint32_t cw_idx = (nof_tb == SRSLTE_MAX_TB && cfg->tb_cw_swap) ? 1 : 0; + for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) { + if (cfg->grant.tb_en[tb_idx]) { + ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb_idx], rnti, data[tb_idx], cw_idx, tb_idx); + cw_idx = (cw_idx + 1) % SRSLTE_MAX_CODEWORDS; } } @@ -807,7 +842,7 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, /* Precode */ srslte_precoding_type(x, q->symbols, cfg->nof_layers, q->cell.nof_ports, cfg->codebook_idx, - nof_symbols, cfg->mimo_type); + nof_symbols, 1.0f, cfg->mimo_type); } else { memcpy(q->symbols[0], q->d[0], cfg->nbits[0].nof_re * sizeof(cf_t)); } diff --git a/lib/src/phy/phch/phich.c b/lib/src/phy/phch/phich.c index 14a0d5426..37b8e1b7a 100644 --- a/lib/src/phy/phch/phich.c +++ b/lib/src/phy/phch/phich.c @@ -239,9 +239,9 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, noise_estimate); + srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, 1.0f, noise_estimate); } else { - srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB); + srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB, 1.0f); srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); } DEBUG("Recv!!: \n", 0); @@ -405,7 +405,7 @@ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_ if (q->cell.nof_ports > 1) { srslte_layermap_diversity(q->d0, x, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB); srslte_precoding_diversity(x, symbols_precoding, q->cell.nof_ports, - SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); + SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports, 1.0f); /**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */ } else { memcpy(q->sf_symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); diff --git a/lib/src/phy/phch/pmch.c b/lib/src/phy/phch/pmch.c index 99e40d50f..c1c322f34 100644 --- a/lib/src/phy/phch/pmch.c +++ b/lib/src/phy/phch/pmch.c @@ -378,14 +378,14 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q, } // No tx diversity in MBSFN - srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits[0].nof_re, noise_estimate); + srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits[0].nof_re, 1.0f, noise_estimate); if (SRSLTE_VERBOSE_ISDEBUG()) { - DEBUG("SAVED FILE subframe.dat: received subframe symbols\n",0); + DEBUG("SAVED FILE subframe.dat: received subframe symbols\n"); srslte_vec_save_file("subframe.dat", sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); - DEBUG("SAVED FILE hest0.dat: channel estimates for port 4\n",0); + DEBUG("SAVED FILE hest0.dat: channel estimates for port 4\n"); srslte_vec_save_file("hest0.dat", ce[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); - DEBUG("SAVED FILE pmch_symbols.dat: symbols after equalization\n",0); + DEBUG("SAVED FILE pmch_symbols.dat: symbols after equalization\n"); srslte_vec_save_file("pmch_symbols.bin", q->d, cfg->nbits[0].nof_re*sizeof(cf_t)); } @@ -393,16 +393,13 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q, * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, * thus we don't need tot set it in thde LLRs normalization */ - - - srslte_demod_soft_demodulate_s(cfg->grant.mcs[0].mod, q->d, q->e, cfg->nbits[0].nof_re); /* descramble */ srslte_scrambling_s_offset(&q->seqs[area_id]->seq[cfg->sf_idx], q->e, 0, cfg->nbits[0].nof_bits); if (SRSLTE_VERBOSE_ISDEBUG()) { - DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n",0); + DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n"); srslte_vec_save_file("llr.dat", q->e, cfg->nbits[0].nof_bits*sizeof(int16_t)); } return srslte_dlsch_decode(&q->dl_sch, cfg, softbuffer, q->e, data); diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index 498d34f3a..b1317de3e 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -173,7 +173,7 @@ srslte_pucch_format_t srslte_pucch_get_format(srslte_uci_data_t *uci_data, srslt { srslte_pucch_format_t format = SRSLTE_PUCCH_FORMAT_ERROR; // No CQI data - if (uci_data->uci_cqi_len == 0) { + if (uci_data->uci_cqi_len == 0 && uci_data->uci_ri_len == 0) { // 1-bit ACK + optional SR if (uci_data->uci_ack_len == 1) { format = SRSLTE_PUCCH_FORMAT_1A; @@ -750,7 +750,7 @@ float srslte_pucch_get_last_corr(srslte_pucch_t* q) /* Equalize, demodulate and decode PUCCH bits according to Section 5.4.1 of 36.211 */ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, uint32_t n_pucch, uint32_t sf_idx, uint16_t rnti, cf_t *sf_symbols, cf_t *ce, float noise_estimate, - uint8_t bits[SRSLTE_PUCCH_MAX_BITS]) + uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t nof_bits) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && @@ -787,11 +787,11 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, } // Equalization - srslte_predecoding_single(q->z_tmp, q->ce, q->z, nof_re, noise_estimate); + srslte_predecoding_single(q->z_tmp, q->ce, q->z, nof_re, 1.0f, noise_estimate); // Perform ML-decoding float corr=0, corr_max=-1e9; - int b_max = 0; // default bit value, eg. HI is NACK + uint8_t b_max = 0, b2_max = 0; // default bit value, eg. HI is NACK switch(format) { case SRSLTE_PUCCH_FORMAT_1: bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); @@ -808,7 +808,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, case SRSLTE_PUCCH_FORMAT_1A: bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); ret = 0; - for (int b=0;b<2;b++) { + for (uint8_t b=0;b<2;b++) { bits[0] = b; pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z_tmp); corr = srslte_vec_corr_ccc(q->z, q->z_tmp, nof_re); @@ -824,6 +824,30 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, q->last_corr = corr_max; bits[0] = b_max; break; + case SRSLTE_PUCCH_FORMAT_1B: + bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); + ret = 0; + for (uint8_t b=0;b<2;b++) { + for (uint8_t b2 = 0; b2 < 2; b2++) { + bits[0] = b; + bits[1] = b2; + pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z_tmp); + corr = srslte_vec_corr_ccc(q->z, q->z_tmp, nof_re); + if (corr > corr_max) { + corr_max = corr; + b_max = b; + b2_max = b2; + } + if (corr_max > q->threshold_format1) { // check with format1 in case ack+sr because ack only is binary + ret = 1; + } + DEBUG("format1b b=%d, corr=%f, nof_re=%d\n", b, corr, nof_re); + } + } + q->last_corr = corr_max; + bits[0] = b_max; + bits[1] = b2_max; + break; case SRSLTE_PUCCH_FORMAT_2: case SRSLTE_PUCCH_FORMAT_2A: case SRSLTE_PUCCH_FORMAT_2B: @@ -838,7 +862,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, } srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->z, llr_pucch2, SRSLTE_PUCCH2_NOF_BITS/2); srslte_scrambling_s(&q->users[rnti]->seq_f2[sf_idx], llr_pucch2); - q->last_corr = (float) srslte_uci_decode_cqi_pucch(&q->cqi, llr_pucch2, bits, 4)/2000; + q->last_corr = (float) srslte_uci_decode_cqi_pucch(&q->cqi, llr_pucch2, bits, nof_bits)/2000; ret = 1; } else { fprintf(stderr, "Decoding PUCCH2: rnti not set\n"); diff --git a/lib/src/phy/phch/pusch.c b/lib/src/phy/phch/pusch.c index f52bbbb42..7876a4f86 100644 --- a/lib/src/phy/phch/pusch.c +++ b/lib/src/phy/phch/pusch.c @@ -323,7 +323,7 @@ int srslte_pusch_set_cell(srslte_pusch_t *q, srslte_cell_t cell) { q->max_re = cell.nof_prb * MAX_PUSCH_RE(q->cell.cp); - INFO("PUSCH: Cell config PCI=5d, %d ports %d PRBs, max_symbols: %d\n", + INFO("PUSCH: Cell config PCI=%d, %d ports %d PRBs, max_symbols: %d\n", q->cell.id, q->cell.nof_ports, q->cell.nof_prb, q->max_re); if (q->cell.id != cell.id || q->cell.nof_prb == 0) { @@ -566,9 +566,9 @@ int srslte_pusch_decode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, cf_t *sf_symbols, cf_t *ce, float noise_estimate, uint16_t rnti, - uint8_t *data, srslte_uci_data_t *uci_data) + uint8_t *data, srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data) { - + int ret = SRSLTE_ERROR_INVALID_INPUTS; uint32_t n; if (q != NULL && @@ -596,7 +596,7 @@ int srslte_pusch_decode(srslte_pusch_t *q, } // Equalization - srslte_predecoding_single(q->d, q->ce, q->z, cfg->nbits.nof_re, noise_estimate); + srslte_predecoding_single(q->d, q->ce, q->z, cfg->nbits.nof_re, 1.0f, noise_estimate); // DFT predecoding srslte_dft_precoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb); @@ -607,19 +607,42 @@ int srslte_pusch_decode(srslte_pusch_t *q, // Generate scrambling sequence if not pre-generated srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits); + // Set CQI len assuming RI = 1 (3GPP 36.212 Clause 5.2.4.1. Uplink control information on PUSCH without UL-SCH data) + if (cqi_value) { + if (cqi_value->type == SRSLTE_CQI_TYPE_SUBBAND_HL) { + cqi_value->subband_hl.rank_is_not_one = false; + } + uci_data->uci_cqi_len = (uint32_t) srslte_cqi_size(cqi_value); + uci_data->uci_ri_len = (q->cell.nof_ports == 4) ? 2 : 1; + } + // Decode RI/HARQ bits before descrambling if (srslte_ulsch_uci_decode_ri_ack(&q->ul_sch, cfg, softbuffer, q->q, seq->c, uci_data)) { fprintf(stderr, "Error decoding RI/HARQ bits\n"); return SRSLTE_ERROR; } + + // Set CQI len with corresponding RI + if (cqi_value) { + if (cqi_value->type == SRSLTE_CQI_TYPE_SUBBAND_HL) { + cqi_value->subband_hl.rank_is_not_one = (uci_data->uci_ri != 0); + } + uci_data->uci_cqi_len = (uint32_t) srslte_cqi_size(cqi_value); + } // Descrambling srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits); - - return srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data); - } else { - return SRSLTE_ERROR_INVALID_INPUTS; + + // Decode + ret = srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data); + + // Unpack CQI value if available + if (cqi_value) { + srslte_cqi_value_unpack(uci_data->uci_cqi, cqi_value); + } } + + return ret; } uint32_t srslte_pusch_last_noi(srslte_pusch_t *q) { diff --git a/lib/src/phy/phch/ra.c b/lib/src/phy/phch/ra.c index be10c304c..e1eaa5de2 100644 --- a/lib/src/phy/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -185,108 +185,86 @@ int srslte_ra_ul_dci_to_grant_prb_allocation(srslte_ra_ul_dci_t *dci, srslte_ra_ } } -srslte_mod_t last_mod[8]; -uint32_t last_ul_tbs_idx[8]; -uint32_t last_dl_tbs[8]; -uint32_t last_dl_tbs2[8]; - -static int ul_dci_to_grant_mcs(srslte_ra_ul_dci_t *dci, srslte_ra_ul_grant_t *grant, uint32_t harq_pid) { - int tbs = -1; +static void ul_dci_to_grant_mcs(srslte_ra_ul_dci_t *dci, srslte_ra_ul_grant_t *grant) { // 8.6.2 First paragraph if (dci->mcs_idx <= 28) { /* Table 8.6.1-1 on 36.213 */ if (dci->mcs_idx < 11) { grant->mcs.mod = SRSLTE_MOD_QPSK; - tbs = srslte_ra_tbs_from_idx(dci->mcs_idx, grant->L_prb); - last_ul_tbs_idx[harq_pid%8] = dci->mcs_idx; + grant->mcs.tbs = srslte_ra_tbs_from_idx(dci->mcs_idx, grant->L_prb); } else if (dci->mcs_idx < 21) { grant->mcs.mod = SRSLTE_MOD_16QAM; - tbs = srslte_ra_tbs_from_idx(dci->mcs_idx-1, grant->L_prb); - last_ul_tbs_idx[harq_pid%8] = dci->mcs_idx-1; + grant->mcs.tbs = srslte_ra_tbs_from_idx(dci->mcs_idx-1, grant->L_prb); } else if (dci->mcs_idx < 29) { grant->mcs.mod = SRSLTE_MOD_64QAM; - tbs = srslte_ra_tbs_from_idx(dci->mcs_idx-2, grant->L_prb); - last_ul_tbs_idx[harq_pid%8] = dci->mcs_idx-2; + grant->mcs.tbs = srslte_ra_tbs_from_idx(dci->mcs_idx-2, grant->L_prb); } else { fprintf(stderr, "Invalid MCS index %d\n", dci->mcs_idx); } - last_mod[harq_pid%8] = grant->mcs.mod; } else if (dci->mcs_idx == 29 && dci->cqi_request && grant->L_prb <= 4) { // 8.6.1 and 8.6.2 36.213 second paragraph grant->mcs.mod = SRSLTE_MOD_QPSK; - tbs = srslte_ra_tbs_from_idx(last_ul_tbs_idx[harq_pid%8], grant->L_prb); - dci->rv_idx = 1; + grant->mcs.tbs = 0; + dci->rv_idx = 1; } else if (dci->mcs_idx >= 29) { - // Else use last TBS/Modulation and use mcs to obtain rv_idx - tbs = srslte_ra_tbs_from_idx(last_ul_tbs_idx[harq_pid%8], grant->L_prb); - grant->mcs.mod = last_mod[harq_pid%8]; + // Else use last TBS/Modulation and use mcs to obtain rv_idx + grant->mcs.tbs = -1; + grant->mcs.mod = SRSLTE_MOD_LAST; dci->rv_idx = dci->mcs_idx - 28; - DEBUG("TTI=%d, harq_pid=%d, mcs_idx=%d, tbs=%d, mod=%d, rv=%d\n", - harq_pid, harq_pid%8, dci->mcs_idx, tbs/8, grant->mcs.mod, dci->rv_idx); - } - if (tbs < 0) { - fprintf(stderr, "Error computing TBS\n"); - return SRSLTE_ERROR; - } else { - grant->mcs.tbs = (uint32_t) tbs; - return SRSLTE_SUCCESS; + DEBUG("mcs_idx=%d, tbs=%d, mod=%d, rv=%d\n", + dci->mcs_idx, grant->mcs.tbs/8, grant->mcs.mod, dci->rv_idx); } } -void srslte_ra_ul_grant_to_nbits(srslte_ra_ul_grant_t *grant, srslte_cp_t cp, uint32_t N_srs, srslte_ra_nbits_t *nbits) +void srslte_ra_ul_grant_to_nbits(srslte_ra_ul_grant_t *grant, srslte_cp_t cp, uint32_t N_srs, srslte_ra_nbits_t *nbits) { - nbits->nof_symb = 2*(SRSLTE_CP_NSYMB(cp)-1) - N_srs; + nbits->nof_symb = 2*(SRSLTE_CP_NSYMB(cp)-1) - N_srs; nbits->nof_re = nbits->nof_symb*grant->M_sc; nbits->nof_bits = nbits->nof_re * grant->Qm; } /** Compute PRB allocation for Uplink as defined in 8.1 and 8.4 of 36.213 */ -int srslte_ra_ul_dci_to_grant(srslte_ra_ul_dci_t *dci, uint32_t nof_prb, uint32_t n_rb_ho, srslte_ra_ul_grant_t *grant, - uint32_t harq_pid) +int srslte_ra_ul_dci_to_grant(srslte_ra_ul_dci_t *dci, uint32_t nof_prb, uint32_t n_rb_ho, srslte_ra_ul_grant_t *grant) { - - // Compute PRB allocation + + // Compute PRB allocation if (!srslte_ra_ul_dci_to_grant_prb_allocation(dci, grant, n_rb_ho, nof_prb)) { - - // Compute MCS - if (!ul_dci_to_grant_mcs(dci, grant, harq_pid)) { - - // Fill rest of grant structure - grant->mcs.idx = dci->mcs_idx; - grant->M_sc = grant->L_prb*SRSLTE_NRE; - grant->M_sc_init = grant->M_sc; // FIXME: What should M_sc_init be? - grant->Qm = srslte_mod_bits_x_symbol(grant->mcs.mod); - } else { - fprintf(stderr, "Error computing MCS\n"); - return SRSLTE_ERROR; - } + + // Compute MCS + ul_dci_to_grant_mcs(dci, grant); + + // Fill rest of grant structure + grant->mcs.idx = dci->mcs_idx; + grant->M_sc = grant->L_prb*SRSLTE_NRE; + grant->M_sc_init = grant->M_sc; // FIXME: What should M_sc_init be? + grant->Qm = srslte_mod_bits_x_symbol(grant->mcs.mod); + } else { - printf("Error computing UL PRB allocation\n"); - return SRSLTE_ERROR; + return SRSLTE_ERROR; } return SRSLTE_SUCCESS; } -uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell, uint32_t nof_prb, uint32_t nof_ctrl_symbols) +uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell, uint32_t nof_prb, uint32_t nof_ctrl_symbols) { - uint32_t nof_refs = 0; + uint32_t nof_refs = 0; uint32_t nof_symb = 2*SRSLTE_CP_NSYMB(cell.cp)-nof_ctrl_symbols; switch(cell.nof_ports) { - case 1: - nof_refs = 2*3; - break; - case 2: - nof_refs = 4*3; - break; - case 4: - nof_refs = 4*4; - break; + case 1: + nof_refs = 2*3; + break; + case 2: + nof_refs = 4*3; + break; + case 4: + nof_refs = 4*4; + break; } return nof_prb * (nof_symb*SRSLTE_NRE-nof_refs); } /* Computes the number of RE for each PRB in the prb_dist structure */ -uint32_t srslte_ra_dl_grant_nof_re(srslte_ra_dl_grant_t *grant, srslte_cell_t cell, +uint32_t srslte_ra_dl_grant_nof_re(srslte_ra_dl_grant_t *grant, srslte_cell_t cell, uint32_t sf_idx, uint32_t nof_ctrl_symbols) { uint32_t j, s; @@ -300,7 +278,7 @@ uint32_t srslte_ra_dl_grant_nof_re(srslte_ra_dl_grant_t *grant, srslte_cell_t ce } } } - return nof_re; + return nof_re; } @@ -315,7 +293,7 @@ int srslte_ra_dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, srslte_ra_ uint32_t bitmask; uint32_t P = srslte_ra_type0_P(nof_prb); uint32_t n_rb_rbg_subset, n_rb_type1; - + bzero(grant, sizeof(srslte_ra_dl_grant_t)); switch (dci->alloc_type) { case SRSLTE_RA_ALLOC_TYPE0: @@ -352,14 +330,14 @@ int srslte_ra_dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, srslte_ra_ * P * P + dci->type1_alloc.rbg_subset * P + (i + shift) % P] = true; grant->nof_prb++; } else { - return SRSLTE_ERROR; + return SRSLTE_ERROR; } } } memcpy(&grant->prb_idx[1], &grant->prb_idx[0], SRSLTE_MAX_PRB*sizeof(bool)); break; case SRSLTE_RA_ALLOC_TYPE2: - if (dci->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) { + if (dci->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) { for (i = 0; i < dci->type2_alloc.L_crb; i++) { grant->prb_idx[0][i + dci->type2_alloc.RB_start] = true; grant->nof_prb++; @@ -408,13 +386,13 @@ int srslte_ra_dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, srslte_ra_ if (n_tilde_prb_odd < nof_prb) { grant->prb_idx[0][n_tilde_prb_odd] = true; } else { - return SRSLTE_ERROR; + return SRSLTE_ERROR; } } else { if (n_tilde_prb_odd + N_gap - N_tilde_vrb / 2 < nof_prb) { grant->prb_idx[0][n_tilde_prb_odd + N_gap - N_tilde_vrb / 2] = true; } else { - return SRSLTE_ERROR; + return SRSLTE_ERROR; } } grant->nof_prb++; @@ -422,13 +400,13 @@ int srslte_ra_dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, srslte_ra_ if(n_tilde_prb_even < nof_prb) { grant->prb_idx[1][n_tilde_prb_even] = true; } else { - return SRSLTE_ERROR; + return SRSLTE_ERROR; } } else { if (n_tilde_prb_even + N_gap - N_tilde_vrb / 2 < nof_prb) { grant->prb_idx[1][n_tilde_prb_even + N_gap - N_tilde_vrb / 2] = true; } else { - return SRSLTE_ERROR; + return SRSLTE_ERROR; } } } @@ -442,8 +420,7 @@ int srslte_ra_dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, srslte_ra_ } int srslte_dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) { - uint32_t i_tbs = 0; - int tbs = -1; + int i_tbs = 0; if (mcs->idx < 10) { mcs->mod = SRSLTE_MOD_QPSK; i_tbs = mcs->idx; @@ -455,30 +432,26 @@ int srslte_dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) { i_tbs = mcs->idx-2; } else if (mcs->idx == 29) { mcs->mod = SRSLTE_MOD_QPSK; - tbs = 0; - i_tbs = 0; + i_tbs = -1; } else if (mcs->idx == 30) { mcs->mod = SRSLTE_MOD_16QAM; - tbs = 0; - i_tbs = 0; + i_tbs = -1; } else if (mcs->idx == 31) { mcs->mod = SRSLTE_MOD_64QAM; - tbs = 0; - i_tbs = 0; + i_tbs = -1; } - - if (tbs == -1) { + + int tbs = -1; + if (i_tbs >= 0) { tbs = srslte_ra_tbs_from_idx(i_tbs, nprb); - if (tbs >= 0) { - mcs->tbs = tbs; - } - } - return tbs; + mcs->tbs = tbs; + } + return tbs; } int srslte_dl_fill_ra_mcs_pmch(srslte_ra_mcs_t *mcs, uint32_t nprb) { - uint32_t i_tbs = 0; - int tbs = -1; + uint32_t i_tbs = 0; + int tbs = -1; if (mcs->idx < 5) { mcs->mod = SRSLTE_MOD_QPSK; i_tbs = mcs->idx*2; @@ -492,7 +465,7 @@ int srslte_dl_fill_ra_mcs_pmch(srslte_ra_mcs_t *mcs, uint32_t nprb) { mcs->mod = SRSLTE_MOD_64QAM; i_tbs = mcs->idx + 5; }else if (mcs->idx < 28) { - //mcs->mod = SRSLTE_MOD_256QAM; + //mcs->mod = SRSLTE_MOD_256QAM; i_tbs = mcs->idx + 5; }else if (mcs->idx == 28) { mcs->mod = SRSLTE_MOD_QPSK; @@ -511,15 +484,15 @@ int srslte_dl_fill_ra_mcs_pmch(srslte_ra_mcs_t *mcs, uint32_t nprb) { tbs = 0; i_tbs = 0; } - - + + if (tbs == -1) { tbs = srslte_ra_tbs_from_idx(i_tbs, nprb); if (tbs >= 0) { - mcs->tbs = tbs; + mcs->tbs = tbs; } - } - return tbs; + } + return tbs; } /* Modulation order and transport block size determination 7.1.7 in 36.213 @@ -530,9 +503,9 @@ int srslte_dl_fill_ra_mcs_pmch(srslte_ra_mcs_t *mcs, uint32_t nprb) { * */ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *grant, bool crc_is_crnti) { uint32_t n_prb=0; - int tbs = -1; - uint32_t i_tbs = 0; - + int tbs = -1; + uint32_t i_tbs = 0; + if (!crc_is_crnti) { if (dci->dci_is_1a) { n_prb = dci->type2_alloc.n_prb1a == SRSLTE_RA_TYPE2_NPRB1A_2 ? 2 : 3; @@ -546,35 +519,21 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr } } else { fprintf(stderr, "Error decoding DCI: P/SI/RA-RNTI supports Format1A/1C only\n"); - return SRSLTE_ERROR; + return SRSLTE_ERROR; } grant->mcs[0].mod = SRSLTE_MOD_QPSK; grant->mcs[0].tbs = (uint32_t) tbs; } else { n_prb = grant->nof_prb; - grant->nof_tb = 0; if (dci->tb_en[0]) { grant->mcs[0].idx = dci->mcs_idx; - tbs = srslte_dl_fill_ra_mcs(&grant->mcs[0], n_prb); - if (tbs) { - last_dl_tbs[dci->harq_process%8] = tbs; - } else { - // For mcs>=29, set last TBS received for this PID - grant->mcs[0].tbs = last_dl_tbs[dci->harq_process%8]; - } - grant->nof_tb++; + grant->mcs[0].tbs = srslte_dl_fill_ra_mcs(&grant->mcs[0], n_prb); } else { grant->mcs[0].tbs = 0; } if (dci->tb_en[1]) { grant->mcs[1].idx = dci->mcs_idx_1; - tbs = srslte_dl_fill_ra_mcs(&grant->mcs[1], n_prb); - if (tbs) { - last_dl_tbs2[dci->harq_process%8] = tbs; - } else { - // For mcs>=29, set last TBS received for this PID - grant->mcs[1].tbs = last_dl_tbs2[dci->harq_process%8]; - } + grant->mcs[1].tbs = srslte_dl_fill_ra_mcs(&grant->mcs[1], n_prb); } else { grant->mcs[1].tbs = 0; } @@ -586,8 +545,9 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr } } grant->pinfo = dci->pinfo; + grant->tb_cw_swap = dci->tb_cw_swap; - if (tbs < 0) { + if (grant->mcs[0].tbs < 0 || grant->mcs[1].tbs < 0) { return SRSLTE_ERROR; } else { return SRSLTE_SUCCESS; @@ -598,16 +558,16 @@ void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srsl srslte_ra_nbits_t nbits [SRSLTE_MAX_CODEWORDS]) { // Compute number of RE - for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + for (int i = 0; i < SRSLTE_MAX_TB; i++) { + /* Compute number of RE for first transport block */ + nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi); + nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi; + if (SRSLTE_SF_NORM == grant->sf_type) { + nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart; + } else if (SRSLTE_SF_MBSFN == grant->sf_type) { + nbits[i].nof_symb = 2 * SRSLTE_CP_EXT_NSYMB - nbits[0].lstart; + } if (grant->tb_en[i]) { - /* Compute number of RE for first transport block */ - nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi); - nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi; - if (SRSLTE_SF_NORM == grant->sf_type) { - nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart; - } else if (SRSLTE_SF_MBSFN == grant->sf_type) { - nbits[i].nof_symb = 2 * SRSLTE_CP_EXT_NSYMB - nbits[0].lstart; - } nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i]; } } @@ -622,16 +582,19 @@ int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci, if (msg_rnti >= SRSLTE_CRNTI_START && msg_rnti <= SRSLTE_CRNTI_END) { crc_is_crnti = true; } - // Compute PRB allocation - if (!srslte_ra_dl_dci_to_grant_prb_allocation(dci, grant, nof_prb)) { - // Compute MCS - if (!dl_dci_to_grant_mcs(dci, grant, crc_is_crnti)) { + // Compute PRB allocation + int ret =srslte_ra_dl_dci_to_grant_prb_allocation(dci, grant, nof_prb); + if (!ret) { + // Compute MCS + ret = dl_dci_to_grant_mcs(dci, grant, crc_is_crnti); + if (ret == SRSLTE_SUCCESS) { // Apply Section 7.1.7.3. If RA-RNTI and Format1C rv_idx=0 - if (msg_rnti >= SRSLTE_RARNTI_START && msg_rnti <= SRSLTE_RARNTI_END && - dci->dci_is_1c) - { - dci->rv_idx = 0; - } + if (dci->dci_is_1c) { + if ((msg_rnti >= SRSLTE_RARNTI_START && msg_rnti <= SRSLTE_RARNTI_END) || msg_rnti == SRSLTE_PRNTI) + { + dci->rv_idx = 0; + } + } } else { return SRSLTE_ERROR; } @@ -663,7 +626,7 @@ uint32_t srslte_ra_type1_N_rb(uint32_t nof_prb) { /* Convert Type2 scheduling L_crb and RB_start to RIV value */ uint32_t srslte_ra_type2_to_riv(uint32_t L_crb, uint32_t RB_start, uint32_t nof_prb) { uint32_t riv; - if (L_crb <= nof_prb / 2) { + if ((L_crb - 1) <= nof_prb / 2) { riv = nof_prb * (L_crb - 1) + RB_start; } else { riv = nof_prb * (nof_prb - L_crb + 1) + nof_prb - 1 - RB_start; @@ -907,4 +870,4 @@ void srslte_ra_prb_fprint(FILE *f, srslte_ra_dl_grant_t *grant) { } } -} \ No newline at end of file +} diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index e76fa6aef..b782725eb 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -147,6 +147,8 @@ clean: } void srslte_sch_free(srslte_sch_t *q) { + srslte_rm_turbo_free_tables(); + if (q->cb_in) { free(q->cb_in); } @@ -458,12 +460,12 @@ static int decode_tb(srslte_sch_t *q, if (cb_segm->F) { fprintf(stderr, "Error filler bits are not supported. Use standard TBS\n"); - return SRSLTE_ERROR; + return SRSLTE_ERROR_INVALID_INPUTS; } if (cb_segm->C > softbuffer->max_cb) { fprintf(stderr, "Error number of CB (%d) exceeds soft buffer size (%d CBs)\n", cb_segm->C, softbuffer->max_cb); - return SRSLTE_ERROR; + return SRSLTE_ERROR_INVALID_INPUTS; } bool crc_ok = true; @@ -491,11 +493,7 @@ static int decode_tb(srslte_sch_t *q, ((uint32_t) data[cb_segm->tbs/8+1])<<8 | ((uint32_t) data[cb_segm->tbs/8+2]); - if (!par_rx) { - INFO("Warning: Received all-zero transport block\n\n",0); - } - - if (par_rx == par_tx) { + if (par_rx == par_tx && par_rx) { INFO("TB decoded OK\n",0); return SRSLTE_SUCCESS; } else { @@ -517,15 +515,15 @@ int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuf int srslte_dlsch_decode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, - int16_t *e_bits, uint8_t *data, int codeword_idx) { + int16_t *e_bits, uint8_t *data, int tb_idx) { uint32_t Nl = 1; if (cfg->nof_layers != SRSLTE_RA_DL_GRANT_NOF_TB(&cfg->grant)) { Nl = 2; } - return decode_tb(q, softbuffer, &cfg->cb_segm[codeword_idx], - cfg->grant.Qm[codeword_idx] * Nl, cfg->rv[codeword_idx], cfg->nbits[codeword_idx].nof_bits, + return decode_tb(q, softbuffer, &cfg->cb_segm[tb_idx], + cfg->grant.Qm[tb_idx] * Nl, cfg->rv[tb_idx], cfg->nbits[tb_idx].nof_bits, e_bits, data); } @@ -546,15 +544,15 @@ int srslte_dlsch_encode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuf } int srslte_dlsch_encode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, uint8_t *e_bits, int codeword_idx) { + uint8_t *data, uint8_t *e_bits, int tb_idx) { uint32_t Nl = 1; if (cfg->nof_layers != SRSLTE_RA_DL_GRANT_NOF_TB(&cfg->grant)) { Nl = 2; } - return encode_tb(q, softbuffer, &cfg->cb_segm[codeword_idx], cfg->grant.Qm[codeword_idx]*Nl, cfg->rv[codeword_idx], - cfg->nbits[codeword_idx].nof_bits, data, e_bits); + return encode_tb(q, softbuffer, &cfg->cb_segm[tb_idx], cfg->grant.Qm[tb_idx]*Nl, cfg->rv[tb_idx], + cfg->nbits[tb_idx].nof_bits, data, e_bits); } /* Compute the interleaving function on-the-fly, because it depends on number of RI bits @@ -658,7 +656,7 @@ int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srs if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - ret = srslte_uci_decode_ack(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, acks, uci_data->uci_ack_len); + ret = srslte_uci_decode_ack_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, acks, uci_data->uci_ack_len, false); if (ret < 0) { return ret; } @@ -678,7 +676,7 @@ int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srs if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - ret = srslte_uci_decode_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ri); + ret = srslte_uci_decode_ack_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ri, uci_data->uci_ri_len, true); if (ret < 0) { return ret; } @@ -756,13 +754,18 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q, uint32_t nb_q = cfg->nbits.nof_bits; uint32_t Qm = cfg->grant.Qm; - // Encode RI - if (uci_data.uci_ri_len > 0) { + // Encode RI if CQI enabled + if (uci_data.uci_ri_len > 0 || uci_data.uci_cqi_len > 0) { + /* If no RI is reported set it to zero as specified in 3GPP 36.213 clause 7.2.1 */ + if (uci_data.uci_ri_len == 0) { + uci_data.uci_ri = 0; + } float beta = beta_ri_offset[cfg->uci_cfg.I_offset_ri]; if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - ret = srslte_uci_encode_ri(cfg, uci_data.uci_ri, uci_data.uci_cqi_len, beta, nb_q/Qm, q->ack_ri_bits); + uint8_t ri[2] = {uci_data.uci_ri, 0}; + ret = srslte_uci_encode_ack_ri(cfg, ri, uci_data.uci_ri_len, uci_data.uci_cqi_len, beta, nb_q/Qm, q->ack_ri_bits, true); if (ret < 0) { return ret; } @@ -809,8 +812,8 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q, if (cfg->cb_segm.tbs == 0) { beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; } - ret = srslte_uci_encode_ack(cfg, acks, uci_data.uci_ack_len, uci_data.uci_cqi_len, - beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm]); + ret = srslte_uci_encode_ack_ri(cfg, acks, uci_data.uci_ack_len, uci_data.uci_cqi_len, + beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm], false); if (ret < 0) { return ret; } diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 6e6b8c024..33f236061 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -119,6 +119,14 @@ add_test(pdsch_test_multiplex1cw_p0_50 pdsch_test -x multiplex -a 2 -p 0 -n 50) add_test(pdsch_test_multiplex1cw_p0_75 pdsch_test -x multiplex -a 2 -p 0 -n 75) add_test(pdsch_test_multiplex1cw_p0_100 pdsch_test -x multiplex -a 2 -p 0 -n 100) +# PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (1 codeword, swapped) +add_test(pdsch_test_multiplex1cw_p0_6_swap pdsch_test -x multiplex -a 2 -p 0 -m 0 -r 1 -M 28 -t 0 -n 6 -F 1) +add_test(pdsch_test_multiplex1cw_p0_15_swap pdsch_test -x multiplex -a 2 -p 0 -m 0 -r 1 -M 28 -t 0 -n 15) +add_test(pdsch_test_multiplex1cw_p0_25_swap pdsch_test -x multiplex -a 2 -p 0 -m 0 -r 1 -M 28 -t 0 -n 25) +add_test(pdsch_test_multiplex1cw_p0_50_swap pdsch_test -x multiplex -a 2 -p 0 -m 0 -r 1 -M 28 -t 0 -n 50) +add_test(pdsch_test_multiplex1cw_p0_75_swap pdsch_test -x multiplex -a 2 -p 0 -m 0 -r 1 -M 28 -t 0 -n 75) +add_test(pdsch_test_multiplex1cw_p0_100_swap pdsch_test -x multiplex -a 2 -p 0 -m 0 -r 1 -M 28 -t 0 -n 100) + # PDSCH test for Spatial Multiplex transmision mode with PMI = 1 (1 codeword) add_test(pdsch_test_multiplex1cw_p1_6 pdsch_test -x multiplex -a 2 -p 1 -n 6) add_test(pdsch_test_multiplex1cw_p1_12 pdsch_test -x multiplex -a 2 -p 1 -n 12) @@ -151,6 +159,14 @@ add_test(pdsch_test_multiplex2cw_p0_50 pdsch_test -x multiplex -a 2 -t 0 -p 0 - add_test(pdsch_test_multiplex2cw_p0_75 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 75) add_test(pdsch_test_multiplex2cw_p0_100 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 100) +# PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (2 codeword, swapped) +add_test(pdsch_test_multiplex2cw_p0_6_swap pdsch_test -x multiplex -a 2 -t 0 -p 0 -M 28 -n 6 -w -F 1) +add_test(pdsch_test_multiplex2cw_p0_12_swap pdsch_test -x multiplex -a 2 -t 0 -p 0 -m 28 -n 12 -w) +add_test(pdsch_test_multiplex2cw_p0_25_swap pdsch_test -x multiplex -a 2 -t 0 -p 0 -M 28 -n 25 -w) +add_test(pdsch_test_multiplex2cw_p0_50_swap pdsch_test -x multiplex -a 2 -t 0 -p 0 -m 28 -n 50 -w) +add_test(pdsch_test_multiplex2cw_p0_75_swap pdsch_test -x multiplex -a 2 -t 0 -p 0 -M 28 -n 75 -w) +add_test(pdsch_test_multiplex2cw_p0_100_swap pdsch_test -x multiplex -a 2 -t 0 -p 0 -m 28 -n 100 -w) + # PDSCH test for Spatial Multiplex transmision mode with PMI = 1 (2 codeword) add_test(pdsch_test_multiplex2cw_p1_6 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 6) add_test(pdsch_test_multiplex2cw_p1_12 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 12) @@ -218,6 +234,7 @@ add_executable(pucch_test pucch_test.c) target_link_libraries(pucch_test srslte_phy) add_test(pucch_test pucch_test) +add_test(pucch_test_uci_cqi_decoder pucch_test -q) ######################################################################## # PRACH TEST diff --git a/lib/src/phy/phch/test/pbch_file_test.c b/lib/src/phy/phch/test/pbch_file_test.c index 734640d55..2ca12e4c9 100644 --- a/lib/src/phy/phch/test/pbch_file_test.c +++ b/lib/src/phy/phch/test/pbch_file_test.c @@ -140,7 +140,7 @@ int base_init() { return -1; } - if (srslte_ofdm_init_(&fft, cell.cp, srslte_symbol_sz_power2(cell.nof_prb), cell.nof_prb, SRSLTE_DFT_FORWARD)) { + if (srslte_ofdm_init_(&fft, cell.cp, input_buffer, fft_buffer, srslte_symbol_sz_power2(cell.nof_prb), cell.nof_prb, SRSLTE_DFT_FORWARD)) { fprintf(stderr, "Error initializing FFT\n"); return -1; } @@ -203,7 +203,7 @@ int main(int argc, char **argv) { if (nread > 0) { // process 1st subframe only - srslte_ofdm_rx_sf(&fft, input_buffer, fft_buffer); + srslte_ofdm_rx_sf(&fft); /* Get channel estimates for each port */ srslte_chest_dl_estimate(&chest, fft_buffer, ce, 0); diff --git a/lib/src/phy/phch/test/pcfich_file_test.c b/lib/src/phy/phch/test/pcfich_file_test.c index dfb8d72e3..e92d6c7ba 100644 --- a/lib/src/phy/phch/test/pcfich_file_test.c +++ b/lib/src/phy/phch/test/pcfich_file_test.c @@ -120,15 +120,15 @@ int base_init() { fmatlab = NULL; } - flen = SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb)); + flen = SRSLTE_SF_LEN(srslte_symbol_sz_power2(cell.nof_prb)); - input_buffer = malloc(flen * sizeof(cf_t)); + input_buffer = srslte_vec_malloc(flen * sizeof(cf_t)); if (!input_buffer) { perror("malloc"); exit(-1); } - fft_buffer = malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); + fft_buffer = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); if (!fft_buffer) { perror("malloc"); return -1; @@ -151,7 +151,7 @@ int base_init() { return -1; } - if (srslte_ofdm_init_(&fft, cell.cp, srslte_symbol_sz_power2(cell.nof_prb), cell.nof_prb, SRSLTE_DFT_FORWARD)) { + if (srslte_ofdm_init_(&fft, cell.cp, input_buffer, fft_buffer, srslte_symbol_sz_power2(cell.nof_prb), cell.nof_prb, SRSLTE_DFT_FORWARD)) { fprintf(stderr, "Error initializing FFT\n"); return -1; } @@ -215,7 +215,7 @@ int main(int argc, char **argv) { n = srslte_filesource_read(&fsrc, input_buffer, flen); - srslte_ofdm_rx_sf(&fft, input_buffer, fft_buffer); + srslte_ofdm_rx_sf(&fft); if (fmatlab) { fprintf(fmatlab, "infft="); diff --git a/lib/src/phy/phch/test/pdcch_file_test.c b/lib/src/phy/phch/test/pdcch_file_test.c index d4ceed4b6..5482d9f98 100644 --- a/lib/src/phy/phch/test/pdcch_file_test.c +++ b/lib/src/phy/phch/test/pdcch_file_test.c @@ -126,7 +126,7 @@ int base_init() { exit(-1); } - flen = 2 * (SRSLTE_SLOT_LEN(srslte_symbol_sz(cell.nof_prb))); + flen = 2 * (SRSLTE_SLOT_LEN(srslte_symbol_sz_power2(cell.nof_prb))); input_buffer = malloc(flen * sizeof(cf_t)); if (!input_buffer) { @@ -157,7 +157,7 @@ int base_init() { return -1; } - if (srslte_ofdm_init_(&fft, cell.cp, srslte_symbol_sz_power2(cell.nof_prb), cell.nof_prb, SRSLTE_DFT_FORWARD)) { + if (srslte_ofdm_init_(&fft, cell.cp, input_buffer, fft_buffer, srslte_symbol_sz_power2(cell.nof_prb), cell.nof_prb, SRSLTE_DFT_FORWARD)) { fprintf(stderr, "Error initializing FFT\n"); return -1; } @@ -231,7 +231,7 @@ int main(int argc, char **argv) { INFO("Reading %d samples sub-frame %d\n", flen, frame_cnt); - srslte_ofdm_rx_sf(&fft, input_buffer, fft_buffer); + srslte_ofdm_rx_sf(&fft); /* Get channel estimates for each port */ srslte_chest_dl_estimate(&chest, fft_buffer, ce, frame_cnt %10); diff --git a/lib/src/phy/phch/test/pdsch_pdcch_file_test.c b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c index 90c0e1c17..ba662bc49 100644 --- a/lib/src/phy/phch/test/pdsch_pdcch_file_test.c +++ b/lib/src/phy/phch/test/pdsch_pdcch_file_test.c @@ -129,7 +129,7 @@ int base_init() { exit(-1); } - flen = 2 * (SRSLTE_SLOT_LEN(srslte_symbol_sz(cell.nof_prb))); + flen = SRSLTE_SF_LEN(srslte_symbol_sz_power2(cell.nof_prb)); input_buffer[0] = malloc(flen * sizeof(cf_t)); if (!input_buffer[0]) { @@ -137,7 +137,7 @@ int base_init() { exit(-1); } - if (srslte_ue_dl_init(&ue_dl, cell.nof_prb, 1)) { + if (srslte_ue_dl_init(&ue_dl, input_buffer, cell.nof_prb, 1)) { fprintf(stderr, "Error initializing UE DL\n"); return -1; } @@ -182,7 +182,7 @@ int main(int argc, char **argv) { srslte_filesource_read(&fsrc, input_buffer[0], flen); INFO("Reading %d samples sub-frame %d\n", flen, sf_idx); - ret = srslte_ue_dl_decode(&ue_dl, input_buffer, data, 0, sf_idx, acks); + ret = srslte_ue_dl_decode(&ue_dl, data, 0, sf_idx, acks); if(ret > 0) { printf("PDSCH Decoded OK!\n"); } else if (ret == 0) { diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index 0c98079b9..0b18d8b10 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -53,12 +53,13 @@ srslte_cell_t cell = { char mimo_type_str [32] = "single"; srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; -uint32_t cfi = 2; +uint32_t cfi = 1; uint32_t mcs[SRSLTE_MAX_CODEWORDS] = {0, 0}; uint32_t subframe = 1; int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1}; uint16_t rnti = 1234; uint32_t nof_rx_antennas = 1; +bool tb_cw_swap = false; uint32_t pmi = 0; char *input_file = NULL; @@ -77,12 +78,13 @@ void usage(char *prog) { printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb); printf("\t-a nof_rx_antennas [Default %d]\n", nof_rx_antennas); printf("\t-p pmi (multiplex only) [Default %d]\n", pmi); + printf("\t-w Swap Transport Blocks\n"); printf("\t-v [set srslte_verbose to debug, default none]\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "fmMcsrtRFpnavx")) != -1) { + while ((opt = getopt(argc, argv, "fmMcsrtRFpnawvx")) != -1) { switch(opt) { case 'f': input_file = argv[optind]; @@ -123,6 +125,9 @@ void parse_args(int argc, char **argv) { case 'a': nof_rx_antennas = (uint32_t) atoi(argv[optind]); break; + case 'w': + tb_cw_swap = true; + break; case 'v': srslte_verbose++; break; @@ -207,6 +212,11 @@ int main(int argc, char **argv) { dci.tb_en[1] = true; } + /* Enable swap */ + if (SRSLTE_RA_DL_GRANT_NOF_TB(&dci) == SRSLTE_MAX_TB && tb_cw_swap) { + dci.tb_cw_swap = tb_cw_swap; + } + /* Generate grant from DCI */ if (srslte_ra_dl_dci_to_grant(&dci, cell.nof_prb, rnti, &grant)) { fprintf(stderr, "Error computing resource allocation\n"); @@ -255,7 +265,7 @@ int main(int argc, char **argv) { } - for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + for (i = 0; i < SRSLTE_MAX_TB; i++) { if (grant.tb_en[i]) { data_tx[i] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs[i].tbs); if (!data_tx[i]) { @@ -271,6 +281,9 @@ int main(int argc, char **argv) { } bzero(data_rx[i], sizeof(uint8_t) * grant.mcs[i].tbs); + } else { + data_tx[i] = NULL; + data_rx[i] = NULL; } } @@ -483,7 +496,9 @@ int main(int argc, char **argv) { if (grant.tb_en[tb]) { for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) { if (data_tx[tb][byte] != data_rx[tb][byte]) { - ERROR("Found BYTE error in TB %d (%02X != %02X), quiting...", tb, data_tx[tb][byte], data_rx[tb][byte]); + ERROR("Found BYTE (%d) error in TB %d (%02X != %02X), quiting...", byte, tb, data_tx[tb][byte], data_rx[tb][byte]); + printf("Tx: "); srslte_vec_fprint_byte(stdout, data_tx[tb], grant.mcs[tb].tbs / 8); + printf("Rx: "); srslte_vec_fprint_byte(stdout, data_rx[tb], grant.mcs[tb].tbs / 8); ret = SRSLTE_ERROR; goto quit; } diff --git a/lib/src/phy/phch/test/phich_file_test.c b/lib/src/phy/phch/test/phich_file_test.c index 968aa5cbc..65f7ce9c0 100644 --- a/lib/src/phy/phch/test/phich_file_test.c +++ b/lib/src/phy/phch/test/phich_file_test.c @@ -144,7 +144,7 @@ int base_init() { fmatlab = NULL; } - flen = SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb)); + flen = SRSLTE_SF_LEN(srslte_symbol_sz_power2(cell.nof_prb)); input_buffer = malloc(flen * sizeof(cf_t)); if (!input_buffer) { @@ -175,7 +175,7 @@ int base_init() { return -1; } - if (srslte_ofdm_init_(&fft, cell.cp, srslte_symbol_sz_power2(cell.nof_prb), cell.nof_prb, SRSLTE_DFT_FORWARD)) { + if (srslte_ofdm_init_(&fft, cell.cp, input_buffer, fft_buffer, srslte_symbol_sz_power2(cell.nof_prb), cell.nof_prb, SRSLTE_DFT_FORWARD)) { fprintf(stderr, "Error initializing FFT\n"); return -1; } @@ -242,7 +242,7 @@ int main(int argc, char **argv) { n = srslte_filesource_read(&fsrc, input_buffer, flen); - srslte_ofdm_rx_sf(&fft, input_buffer, fft_buffer); + srslte_ofdm_rx_sf(&fft); if (fmatlab) { fprintf(fmatlab, "infft="); @@ -263,7 +263,11 @@ int main(int argc, char **argv) { for (ngroup=0;ngroup 0) { printf("PMCH Decoded OK!\n"); } else if (ret < 0) { diff --git a/lib/src/phy/phch/test/pmch_test.c b/lib/src/phy/phch/test/pmch_test.c index aea1b50c0..bf415e692 100644 --- a/lib/src/phy/phch/test/pmch_test.c +++ b/lib/src/phy/phch/test/pmch_test.c @@ -139,7 +139,7 @@ cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS]; cf_t *rx_slot_symbols[SRSLTE_MAX_PORTS]; srslte_pmch_t pmch_tx, pmch_rx; srslte_pdsch_cfg_t pmch_cfg; -srslte_ofdm_t ifft_mbsfn, fft_mbsfn; +srslte_ofdm_t ifft_mbsfn[SRSLTE_MAX_PORTS], fft_mbsfn[SRSLTE_MAX_PORTS]; int main(int argc, char **argv) { uint32_t i, j, k; @@ -167,12 +167,11 @@ int main(int argc, char **argv) { /* If transport block 0 is enabled */ grant.tb_en[0] = true; grant.tb_en[1] = false; - grant.nof_tb = 1; grant.mcs[0].idx = mcs_idx; - + grant.nof_prb = cell.nof_prb; grant.sf_type = SRSLTE_SF_MBSFN; - + srslte_dl_fill_ra_mcs(&grant.mcs[0], cell.nof_prb); grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod); for(int i = 0; i < 2; i++){ @@ -181,46 +180,11 @@ int main(int argc, char **argv) { } } - - -#ifdef DO_OFDM - - if (srslte_ofdm_tx_init_mbsfn(&ifft_mbsfn, SRSLTE_CP_EXT, cell.nof_prb)) { - fprintf(stderr, "Error creating iFFT object\n"); - exit(-1); - } - if (srslte_ofdm_rx_init_mbsfn(&fft_mbsfn, SRSLTE_CP_EXT, cell.nof_prb)) { - fprintf(stderr, "Error creating iFFT object\n"); - exit(-1); - } - - srslte_ofdm_set_non_mbsfn_region(&ifft_mbsfn, non_mbsfn_region); - srslte_ofdm_set_non_mbsfn_region(&fft_mbsfn, non_mbsfn_region); - srslte_ofdm_set_normalize(&ifft_mbsfn, true); - srslte_ofdm_set_normalize(&fft_mbsfn, true); - - - for (i = 0; i < cell.nof_ports; i++) { - tx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); - } - - for (i = 0; i < nof_rx_antennas; i++) { - rx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); - } -#endif /* DO_OFDM */ - - /* Configure PDSCH */ - - if (srslte_pmch_cfg(&pmch_cfg, cell, &grant, cfi, subframe)) { - fprintf(stderr, "Error configuring PMCH\n"); - exit(-1); - } - /* init memory */ for (i=0;icqi_table[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B*sizeof(int8_t)); - q->cqi_table_s[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B*sizeof(int16_t)); + uint8_t word[16]; + + uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH; + q->cqi_table = srslte_vec_malloc(nwords * sizeof(int8_t *)); + q->cqi_table_s = srslte_vec_malloc(nwords * sizeof(int16_t *)); + + for (uint32_t w = 0; w < nwords; w++) { + q->cqi_table[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B * sizeof(int8_t)); + q->cqi_table_s[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B * sizeof(int16_t)); uint8_t *ptr = word; - srslte_bit_unpack(w, &ptr, 4); - srslte_uci_encode_cqi_pucch(word, 4, q->cqi_table[w]); - for (int j=0;jcqi_table_s[w][j] = 2*q->cqi_table[w][j]-1; + srslte_bit_unpack(w, &ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH); + srslte_uci_encode_cqi_pucch(word, SRSLTE_UCI_MAX_CQI_LEN_PUCCH, q->cqi_table[w]); + for (int j = 0; j < SRSLTE_UCI_CQI_CODED_PUCCH_B; j++) { + q->cqi_table_s[w][j] = (int16_t)(2 * q->cqi_table[w][j] - 1); } } } void srslte_uci_cqi_pucch_free(srslte_uci_cqi_pucch_t *q) { - uint32_t nwords = 16; + uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH; for (uint32_t w=0;wcqi_table[w]) { free(q->cqi_table[w]); @@ -131,6 +134,8 @@ void srslte_uci_cqi_pucch_free(srslte_uci_cqi_pucch_t *q) { free(q->cqi_table_s[w]); } } + free(q->cqi_table); + free(q->cqi_table_s); } /* Encode UCI CQI/PMI as described in 5.2.3.3 of 36.212 @@ -151,17 +156,32 @@ int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_b } } +int srslte_uci_encode_cqi_pucch_from_table(srslte_uci_cqi_pucch_t *q, uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]) +{ + if (cqi_len <= SRSLTE_UCI_MAX_CQI_LEN_PUCCH) { + bzero(&cqi_data[cqi_len], SRSLTE_UCI_MAX_CQI_LEN_PUCCH - cqi_len); + uint8_t *ptr = cqi_data; + uint32_t packed = srslte_bit_pack(&ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH); + memcpy(b_bits, q->cqi_table[packed], SRSLTE_UCI_CQI_CODED_PUCCH_B); + + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + /* Decode UCI CQI/PMI over PUCCH */ int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32], uint8_t *cqi_data, uint32_t cqi_len) { - if (cqi_len == 4 && + if (cqi_len < SRSLTE_UCI_MAX_CQI_LEN_PUCCH && b_bits != NULL && cqi_data != NULL) { uint32_t max_w = 0; - int32_t max_corr = INT32_MIN; - for (uint32_t w=0;w<16;w++) { + int32_t max_corr = INT32_MIN; + uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH; + for (uint32_t w=0;wcqi_table_s[w], b_bits, SRSLTE_UCI_CQI_CODED_PUCCH_B); @@ -172,7 +192,7 @@ int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32 } // Convert word to bits again uint8_t *ptr = cqi_data; - srslte_bit_unpack(max_w, &ptr, cqi_len); + srslte_bit_unpack(max_w, &ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH); INFO("Decoded CQI: w=%d, corr=%d\n", max_w, max_corr); return max_corr; @@ -586,9 +606,7 @@ static uint32_t encode_ri_ack(uint8_t data[2], uint32_t data_len, srslte_uci_bit /* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 * Currently only supporting 1-bit HARQ */ -#ifndef MIMO_ENB - -static int32_t decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos) +static int32_t decode_ri_ack_1bit(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos) { uint32_t p0 = pos[0].position; uint32_t p1 = pos[1].position; @@ -598,33 +616,8 @@ static int32_t decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t * return -(q0+q1); } -int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, - float beta, uint32_t H_prime_total, - uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks) -{ - int32_t rx_ack = 0; - if (beta < 0) { - fprintf(stderr, "Error beta is reserved\n"); - return -1; - } - - uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); - - // Use the same interleaver function to get the HARQ bit position - for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); - rx_ack += (int32_t) decode_ri_ack(q_bits, c_seq, &ack_bits[cfg->grant.Qm*i]); - } - - if (acks) { - acks[0] = rx_ack>0; - } - return (int) Qprime; -} -#else - -static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3]) +static void decode_ri_ack_2bits(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3]) { uint32_t p0 = pos[Qm * 0 + 0].position; uint32_t p1 = pos[Qm * 0 + 1].position; @@ -645,118 +638,91 @@ static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos data[2] -= q2 + q5; } -int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, - float beta, uint32_t H_prime_total, - uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks) -{ - int32_t acks_sum[3] = {0, 0, 0}; - +/* Encode UCI ACK/RI bits as described in 5.2.2.6 of 36.212 + * Currently only supporting 1-bit RI + */ +int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg, + uint8_t *data, uint32_t data_len, + uint32_t O_cqi, float beta, uint32_t H_prime_total, + srslte_uci_bit_t *bits, bool ack_ri) { if (beta < 0) { fprintf(stderr, "Error beta is reserved\n"); - return -1; + return -1; } + uint32_t Qprime = Q_prime_ri_ack(cfg, data_len, O_cqi, beta); + srslte_uci_bit_type_t q_encoded_bits[18]; - uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta); + uint32_t nof_encoded_bits = encode_ri_ack(data, data_len, q_encoded_bits, cfg->grant.Qm); - // Use the same interleaver function to get the HARQ bit position for (uint32_t i = 0; i < Qprime; i++) { - uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); - if ((i % 3 == 0) && i > 0) { - decode_ri_ack(q_bits, &c_seq[0], &ack_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, acks_sum); + if (ack_ri) { + uci_ulsch_interleave_ri_gen(i, + cfg->grant.Qm, + H_prime_total, + cfg->nbits.nof_symb, + cfg->cp, + &bits[cfg->grant.Qm * i]); + } else { + uci_ulsch_interleave_ack_gen(i, + cfg->grant.Qm, + H_prime_total, + cfg->nbits.nof_symb, + cfg->cp, + &bits[cfg->grant.Qm * i]); } + uci_ulsch_interleave_put(&q_encoded_bits[(i * cfg->grant.Qm) % nof_encoded_bits], + cfg->grant.Qm, + &bits[cfg->grant.Qm * i]); } - if (acks) { - acks[0] = (uint8_t)(acks_sum[0] > 0); - acks[1] = (uint8_t)(acks_sum[1] > 0); - // TODO: Do something with acks_sum[2] - } - return (int) Qprime; -} -#endif - -/* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 - * Currently only supporting 1-bit HARQ - */ -int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint8_t acks[2], uint32_t nof_acks, - uint32_t O_cqi, float beta, uint32_t H_prime_total, - srslte_uci_bit_t *ack_bits) -{ - if (beta < 0) { - fprintf(stderr, "Error beta is reserved\n"); - return -1; - } - - uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta); - srslte_uci_bit_type_t q_encoded_bits[18]; - - uint32_t nof_encoded_bits = encode_ri_ack(acks, nof_acks, q_encoded_bits, cfg->grant.Qm); - - for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); - uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ack_bits[cfg->grant.Qm*i]); - } - return (int) Qprime; } -/* Encode UCI RI bits as described in 5.2.2.6 of 36.212 +/* Decode UCI ACK/RI bits as described in 5.2.2.6 of 36.212 * Currently only supporting 1-bit RI */ -int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, - float beta, uint32_t H_prime_total, - uint32_t O_cqi, srslte_uci_bit_t *ri_bits, uint8_t *data) +int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, + float beta, uint32_t H_prime_total, + uint32_t O_cqi, srslte_uci_bit_t *ack_ri_bits, uint8_t data[2], uint32_t nof_bits, bool is_ri) { - int32_t ri_sum[3] = {0, 0, 0}; - + int32_t sum[3] = {0, 0, 0}; + if (beta < 0) { fprintf(stderr, "Error beta is reserved\n"); - return -1; + return -1; } - uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); + uint32_t Qprime = Q_prime_ri_ack(cfg, nof_bits, O_cqi, beta); - // Use the same interleaver function to get the HARQ bit position - for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); - if ((i % 3 == 0) && i > 0) { - //decode_ri_ack(q_bits, &c_seq[0], &ri_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, ri_sum); + for (uint32_t i = 0; i < Qprime; i++) { + if (is_ri) { + uci_ulsch_interleave_ri_gen(i, + cfg->grant.Qm, + H_prime_total, + cfg->nbits.nof_symb, + cfg->cp, + &ack_ri_bits[cfg->grant.Qm * i]); + } else { + uci_ulsch_interleave_ack_gen(i, + cfg->grant.Qm, + H_prime_total, + cfg->nbits.nof_symb, + cfg->cp, + &ack_ri_bits[cfg->grant.Qm * i]); + + } + if (nof_bits == 2 && (i % 3 == 0) && i > 0) { + decode_ri_ack_2bits(q_bits, &c_seq[0], &ack_ri_bits[cfg->grant.Qm * (i - 3)], cfg->grant.Qm, sum); + } else if (nof_bits == 1) { + sum[0] += (int32_t) decode_ri_ack_1bit(q_bits, c_seq, &ack_ri_bits[cfg->grant.Qm * i]); } } - if (data) { - *data = (uint8_t) ((ri_sum[0] + ri_sum[1] + ri_sum[2]) > 0); + data[0] = (uint8_t) (sum[0] > 0); + if (nof_bits == 2) { + data[1] = (uint8_t) (sum[1] > 0); } - return (int) Qprime; -} - - -/* Encode UCI RI bits as described in 5.2.2.6 of 36.212 - * Currently only supporting 1-bit RI - */ -int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg, - uint8_t ri, - uint32_t O_cqi, float beta, uint32_t H_prime_total, - srslte_uci_bit_t *ri_bits) -{ - // FIXME: It supports RI of 1 bit only - uint8_t data[2] = {ri, 0}; - if (beta < 0) { - fprintf(stderr, "Error beta is reserved\n"); - return -1; - } - uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); - srslte_uci_bit_type_t q_encoded_bits[18]; - - uint32_t nof_encoded_bits = encode_ri_ack(data, 1, q_encoded_bits, cfg->grant.Qm); - - for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); - uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ri_bits[cfg->grant.Qm*i]); - } - return (int) Qprime; } - diff --git a/lib/src/phy/resampling/resample_arb.c b/lib/src/phy/resampling/resample_arb.c index 7bdb4deec..441e8c0dc 100644 --- a/lib/src/phy/resampling/resample_arb.c +++ b/lib/src/phy/resampling/resample_arb.c @@ -28,64 +28,104 @@ #include #include "srslte/phy/resampling/resample_arb.h" #include "srslte/phy/utils/debug.h" - -float srslte_resample_arb_polyfilt[SRSLTE_RESAMPLE_ARB_N][SRSLTE_RESAMPLE_ARB_M] = -{{0,0.002400347599485495,-0.006922416132556366,0.0179104136912176,0.99453086623794,-0.008521087756729117,0.0008598969867484128,0.0004992625165376107}, -{-0.001903604727400391,0.004479591950094871,-0.01525319260830623,0.04647449496926549,0.9910477342662829,-0.03275243420114668,0.008048813755373533,-0.001216900416836847}, -{-0.001750442300940216,0.006728826416921727,-0.02407540632178267,0.07708575473589654,0.9841056525667189,-0.05473739187922162,0.01460652754040275,-0.002745266140572769}, -{-0.001807302702047332,0.009130494591071001,-0.03332524241797466,0.1096377743266821,0.9737536341125557,-0.07444712408657775,0.0205085154280773,-0.004077596041064956}, -{-0.002005048395707184,0.01166717081713966,-0.04292591596219218,0.1440068251440274,0.9600641782991848,-0.09187282739868929,0.02573649090563353,-0.005218582609802016}, -{-0.002303606593778858,0.01431549924598744,-0.05279365431190471,0.1800496557331084,0.9431333663677619,-0.107022659158021,0.03028295984887362,-0.006178495199082676}, -{-0.002673824939871474,0.01705308556587308,-0.06283262272105428,0.2176066284621515,0.9230793648715676,-0.1199244901666642,0.03414559686566755,-0.006951034565279722}, -{-0.003099294850834212,0.01985022208215894,-0.07294100481214681,0.2564996326404178,0.9000412628278351,-0.1306207218667012,0.03733448898243594,-0.007554128492547957}, -{-0.003564415127592977,0.02267702927238637,-0.08300660359189582,0.2965368855416621,0.874178327911914,-0.1391710078036285,0.03986356581130199,-0.007992692892036229}, -{-0.004060222849803048,0.02549633298710617,-0.09291211362877161,0.3375102453232687,0.8456688916962831,-0.1456479420005528,0.04175429631970297,-0.00827816851803391}, -{-0.004574770330592958,0.02827133859849648,-0.1025308044303699,0.379200979038518,0.8147072909915275,-0.1501397816831265,0.04303284689167361,-0.008423951215857236}, -{-0.005100453570725489,0.0309593063669097,-0.1117325201826136,0.4213772298764557,0.7815036335229155,-0.1527444636485677,0.0437349357738538,-0.008441129184587313}, -{-0.005625340687997995,0.03351877124912608,-0.1203802123857154,0.463798444519773,0.7462810500374923,-0.1535722712206338,0.04389261707032224,-0.008345136869130621}, -{-0.006140888413286479,0.03590276234084221,-0.1283350405000867,0.5062161107254219,0.7092744343987509,-0.152741400055636,0.04355110899623683,-0.008147838953503964}, -{-0.006634012711933725,0.03806645580467819,-0.1354549138065051,0.5483763739419955,0.6707272107491931,-0.1503798528838644,0.0427502160096194,-0.007865132034489236}, -{-0.007094909626785393,0.03996043743797257,-0.1415969539549883,0.5900207719663111,0.6308907308946271,-0.1466186670140106,0.04153829696698895,-0.007508971112586246}, -{-0.007508971112586246,0.04153829696698895,-0.1466186670140106,0.6308907308946271,0.5900207719663111,-0.1415969539549883,0.03996043743797257,-0.007094909626785393}, -{-0.007865132034489236,0.0427502160096194,-0.1503798528838644,0.6707272107491931,0.5483763739419955,-0.1354549138065051,0.03806645580467819,-0.006634012711933725}, -{-0.008147838953503964,0.04355110899623683,-0.152741400055636,0.7092744343987509,0.5062161107254219,-0.1283350405000867,0.03590276234084221,-0.006140888413286479}, -{-0.008345136869130621,0.04389261707032224,-0.1535722712206338,0.7462810500374923,0.463798444519773,-0.1203802123857154,0.03351877124912608,-0.005625340687997995}, -{-0.008441129184587313,0.0437349357738538,-0.1527444636485677,0.7815036335229155,0.4213772298764557,-0.1117325201826136,0.0309593063669097,-0.005100453570725489}, -{-0.008423951215857236,0.04303284689167361,-0.1501397816831265,0.8147072909915275,0.379200979038518,-0.1025308044303699,0.02827133859849648,-0.004574770330592958}, -{-0.00827816851803391,0.04175429631970297,-0.1456479420005528,0.8456688916962831,0.3375102453232687,-0.09291211362877161,0.02549633298710617,-0.004060222849803048}, -{-0.007992692892036229,0.03986356581130199,-0.1391710078036285,0.874178327911914,0.2965368855416621,-0.08300660359189582,0.02267702927238637,-0.003564415127592977}, -{-0.007554128492547957,0.03733448898243594,-0.1306207218667012,0.9000412628278351,0.2564996326404178,-0.07294100481214681,0.01985022208215894,-0.003099294850834212}, -{-0.006951034565279722,0.03414559686566755,-0.1199244901666642,0.9230793648715676,0.2176066284621515,-0.06283262272105428,0.01705308556587308,-0.002673824939871474}, -{-0.006178495199082676,0.03028295984887362,-0.107022659158021,0.9431333663677619,0.1800496557331084,-0.05279365431190471,0.01431549924598744,-0.002303606593778858}, -{-0.005218582609802016,0.02573649090563353,-0.09187282739868929,0.9600641782991848,0.1440068251440274,-0.04292591596219218,0.01166717081713966,-0.002005048395707184}, -{-0.004077596041064956,0.0205085154280773,-0.07444712408657775,0.9737536341125557,0.1096377743266821,-0.03332524241797466,0.009130494591071001,-0.001807302702047332}, -{-0.002745266140572769,0.01460652754040275,-0.05473739187922162,0.9841056525667189,0.07708575473589654,-0.02407540632178267,0.006728826416921727,-0.001750442300940216}, -{-0.001216900416836847,0.008048813755373533,-0.03275243420114668,0.9910477342662829,0.04647449496926549,-0.01525319260830623,0.004479591950094871,-0.001903604727400391}, -{0.0004992625165376107,0.0008598969867484128,-0.008521087756729117,0.99453086623794,0.0179104136912176,-0.006922416132556366,0.002400347599485495,0}}; +#include "srslte/phy/utils/vector.h" -// TODO: use lte/utils/vector.h and Volk -cf_t srslte_resample_arb_dot_prod(cf_t* x, float *y, int len) -{ - cf_t res = 0+0*I; - for(int i=0;ireg[1], &q->reg[0], (SRSLTE_RESAMPLE_ARB_M-1)*sizeof(cf_t)); q->reg[0] = x; } // Initialize our struct -void srslte_resample_arb_init(srslte_resample_arb_t *q, float rate){ +void srslte_resample_arb_init(srslte_resample_arb_t *q, float rate, bool interpolate){ + memset(q->reg, 0, SRSLTE_RESAMPLE_ARB_M*sizeof(cf_t)); q->acc = 0.0; q->rate = rate; + q->interpolate = interpolate; q->step = (1/rate)*SRSLTE_RESAMPLE_ARB_N; } @@ -94,19 +134,48 @@ int srslte_resample_arb_compute(srslte_resample_arb_t *q, cf_t *input, cf_t *out int cnt = 0; int n_out = 0; int idx = 0; + cf_t res1,res2; + cf_t *filter_input; + float frac = 0; + memset(q->reg, 0, SRSLTE_RESAMPLE_ARB_M*sizeof(cf_t)); + + while (cnt < n_in) { + + if(cntreg[SRSLTE_RESAMPLE_ARB_M - cnt], input, (cnt)*sizeof(cf_t)); + filter_input = q->reg; + } else{ + filter_input = &input[cnt-SRSLTE_RESAMPLE_ARB_M]; + } + + res1 = srslte_resample_arb_dot_prod(filter_input, srslte_resample_arb_polyfilt[idx], SRSLTE_RESAMPLE_ARB_M); + if(q->interpolate){ + res2 = srslte_resample_arb_dot_prod(filter_input, srslte_resample_arb_polyfilt[(idx%SRSLTE_RESAMPLE_ARB_N)+1], SRSLTE_RESAMPLE_ARB_M); + } - while(cnt < n_in) - { - *output = srslte_resample_arb_dot_prod(q->reg, srslte_resample_arb_polyfilt[idx], SRSLTE_RESAMPLE_ARB_M); + if(idx == SRSLTE_RESAMPLE_ARB_N){ + *output = res1; + }else { + *output = (q->interpolate)?(res1 + (res2-res1)*frac):res1; + } + output++; n_out++; q->acc += q->step; - idx = (int)roundf(q->acc); + idx = (int)(q->acc); + while(idx >= SRSLTE_RESAMPLE_ARB_N){ q->acc -= SRSLTE_RESAMPLE_ARB_N; idx -= SRSLTE_RESAMPLE_ARB_N; - if(cnt < n_in) - srslte_resample_arb_push(q, input[cnt++]); + if(cnt < n_in){ + cnt++; + } + } + + if(q->interpolate){ + frac = q->acc - idx; + if(frac < 0) + frac = frac*(-1); } } return n_out; diff --git a/lib/src/phy/resampling/test/resample_arb_bench.c b/lib/src/phy/resampling/test/resample_arb_bench.c index 48879d036..e9ef3c442 100644 --- a/lib/src/phy/resampling/test/resample_arb_bench.c +++ b/lib/src/phy/resampling/test/resample_arb_bench.c @@ -35,9 +35,9 @@ #include "srslte/phy/resampling/resample_arb.h" - +#define ITERATIONS 10000 int main(int argc, char **argv) { - int N=10000000; + int N=9000; float rate = 24.0/25.0; cf_t *in = malloc(N*sizeof(cf_t)); cf_t *out = malloc(N*sizeof(cf_t)); @@ -46,12 +46,15 @@ int main(int argc, char **argv) { in[i] = sin(i*2*M_PI/100); srslte_resample_arb_t r; - srslte_resample_arb_init(&r, rate); + srslte_resample_arb_init(&r, rate, 0); clock_t start = clock(), diff; - //int n_out = srslte_resample_arb_compute(&r, in, out, N); + for(int xx = 0; xx diff && pre != post){ - printf("Interpolation failed at index %f", idx); + printf("Interpolation failed at index %f\n", idx); exit(-1); } } - free(in); free(out); } diff --git a/lib/src/phy/rf/rf_blade_imp.c b/lib/src/phy/rf/rf_blade_imp.c index d8996925f..4a8173f29 100644 --- a/lib/src/phy/rf/rf_blade_imp.c +++ b/lib/src/phy/rf/rf_blade_imp.c @@ -101,7 +101,7 @@ int rf_blade_start_tx_stream(void *h) return 0; } -int rf_blade_start_rx_stream(void *h) +int rf_blade_start_rx_stream(void *h, bool now) { int status; rf_blade_handler_t *handler = (rf_blade_handler_t*) h; @@ -464,7 +464,7 @@ int rf_blade_recv_with_time(void *h, } timestamp_to_secs(handler->rx_rate, meta.timestamp, secs, frac_secs); - srslte_vec_convert_if(handler->rx_buffer, data, 2048, 2*nsamples); + srslte_vec_convert_if(handler->rx_buffer, 2048, data, 2*nsamples); return nsamples; } @@ -506,7 +506,7 @@ int rf_blade_send_timed(void *h, return -1; } - srslte_vec_convert_fi(data, handler->tx_buffer, 2048, 2*nsamples); + srslte_vec_convert_fi(data, 2048, handler->tx_buffer, 2*nsamples); memset(&meta, 0, sizeof(meta)); if (is_start_of_burst) { diff --git a/lib/src/phy/rf/rf_blade_imp.h b/lib/src/phy/rf/rf_blade_imp.h index fbaeab1df..1a2cf1250 100644 --- a/lib/src/phy/rf/rf_blade_imp.h +++ b/lib/src/phy/rf/rf_blade_imp.h @@ -44,7 +44,7 @@ SRSLTE_API void rf_blade_set_tx_cal(void *h, srslte_rf_cal_t *cal); SRSLTE_API void rf_blade_set_rx_cal(void *h, srslte_rf_cal_t *cal); -SRSLTE_API int rf_blade_start_rx_stream(void *h); +SRSLTE_API int rf_blade_start_rx_stream(void *h, bool now); SRSLTE_API int rf_blade_start_rx_stream_nsamples(void *h, uint32_t nsamples); diff --git a/lib/src/phy/rf/rf_dev.h b/lib/src/phy/rf/rf_dev.h index d41adbeed..f800fb398 100644 --- a/lib/src/phy/rf/rf_dev.h +++ b/lib/src/phy/rf/rf_dev.h @@ -30,7 +30,7 @@ typedef struct { const char *name; char* (*srslte_rf_devname) (void *h); bool (*srslte_rf_rx_wait_lo_locked) (void *h); - int (*srslte_rf_start_rx_stream)(void *h); + int (*srslte_rf_start_rx_stream)(void *h, bool now); int (*srslte_rf_stop_rx_stream)(void *h); void (*srslte_rf_flush_buffer)(void *h); bool (*srslte_rf_has_rssi)(void *h); diff --git a/lib/src/phy/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c index c1074ebc5..1de66e066 100644 --- a/lib/src/phy/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -41,7 +41,7 @@ int rf_get_available_devices(char **devnames, int max_strlen) { double srslte_rf_set_rx_gain_th(srslte_rf_t *rf, double gain) { - if (gain > rf->new_rx_gain + 0.5 || gain < rf->new_rx_gain - 0.5) { + if (gain > rf->new_rx_gain + 2 || gain < rf->new_rx_gain - 2) { pthread_mutex_lock(&rf->mutex); rf->new_rx_gain = gain; pthread_cond_signal(&rf->cond); @@ -69,6 +69,7 @@ static void* thread_gain_fcn(void *h) { srslte_rf_set_rx_gain(h, rf->cur_rx_gain); } if (rf->tx_gain_same_rx) { + printf("setting also tx\n"); srslte_rf_set_tx_gain(h, rf->cur_rx_gain+rf->tx_rx_gain_offset); } pthread_mutex_unlock(&rf->mutex); @@ -98,11 +99,7 @@ const char* srslte_rf_get_devname(srslte_rf_t *rf) { return ((rf_dev_t*) rf->dev)->name; } -int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) { - return srslte_rf_open_devname_multi(rf, devname, args, 1); -} - -int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_channels) { +int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_channels) { /* Try to open the device if name is provided */ if (devname) { if (devname[0] != '\0') { @@ -149,9 +146,9 @@ bool srslte_rf_rx_wait_lo_locked(srslte_rf_t *rf) return ((rf_dev_t*) rf->dev)->srslte_rf_rx_wait_lo_locked(rf->handler); } -int srslte_rf_start_rx_stream(srslte_rf_t *rf) +int srslte_rf_start_rx_stream(srslte_rf_t *rf, bool now) { - return ((rf_dev_t*) rf->dev)->srslte_rf_start_rx_stream(rf->handler); + return ((rf_dev_t*) rf->dev)->srslte_rf_start_rx_stream(rf->handler, now); } int srslte_rf_stop_rx_stream(srslte_rf_t *rf) @@ -186,12 +183,12 @@ void srslte_rf_register_error_handler(srslte_rf_t *rf, srslte_rf_error_handler_t int srslte_rf_open(srslte_rf_t *h, char *args) { - return srslte_rf_open_devname_multi(h, NULL, args, 1); + return srslte_rf_open_devname(h, NULL, args, 1); } -int srslte_rf_open_multi(srslte_rf_t *h, char *args, uint32_t nof_rx_antennas) +int srslte_rf_open_multi(srslte_rf_t *h, char *args, uint32_t nof_channels) { - return srslte_rf_open_devname_multi(h, NULL, args, nof_rx_antennas); + return srslte_rf_open_devname(h, NULL, args, nof_channels); } int srslte_rf_close(srslte_rf_t *rf) diff --git a/lib/src/phy/rf/rf_soapy_imp.c b/lib/src/phy/rf/rf_soapy_imp.c index fef533ffc..83f5c3a23 100644 --- a/lib/src/phy/rf/rf_soapy_imp.c +++ b/lib/src/phy/rf/rf_soapy_imp.c @@ -38,6 +38,7 @@ #include typedef struct { + char *devname; SoapySDRKwargs args; SoapySDRDevice *device; SoapySDRRange *ranges; @@ -51,7 +52,6 @@ typedef struct { cf_t zero_mem[64*1024]; - int soapy_error(void *h) { return 0; @@ -90,7 +90,8 @@ void rf_soapy_register_error_handler(void *notused, srslte_rf_error_handler_t ne char* rf_soapy_devname(void* h) { - return "soapy"; + rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; + return handler->devname; } @@ -114,7 +115,7 @@ void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal) } -int rf_soapy_start_rx_stream(void *h) +int rf_soapy_start_rx_stream(void *h, bool now) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; if(handler->rx_stream_active == false){ @@ -196,11 +197,15 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas) printf("No Soapy devices found.\n"); return SRSLTE_ERROR; } - + char* devname; for (size_t i = 0; i < length; i++) { printf("Soapy has Found device #%d: ", (int)i); for (size_t j = 0; j < soapy_args[i].size; j++) { printf("%s=%s, ", soapy_args[i].keys[j], soapy_args[i].vals[j]); + if(!strcmp(soapy_args[i].keys[j],"name") && !strcmp(soapy_args[i].vals[j], "LimeSDR-USB")){ + devname = DEVNAME_LIME; + + } } printf("\n"); } @@ -218,7 +223,7 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas) handler->device = sdr; handler->tx_stream_active = false; handler->rx_stream_active = false; - + handler->devname = devname; if(SoapySDRDevice_getNumChannels(handler->device,SOAPY_SDR_RX) > 0){ printf("setting up RX stream\n"); if(SoapySDRDevice_setupStream(handler->device, &(handler->rxStream), SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) { @@ -234,6 +239,14 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas) return SRSLTE_ERROR; } } + size_t sensor_length; + char** sensors; + sensors = SoapySDRDevice_listSensors(handler->device, &sensor_length); + for(int i = 0; i < sensor_length;i++) + { + printf("available sensors are : \n"); + puts(sensors[i]); + } return SRSLTE_SUCCESS; } @@ -267,7 +280,7 @@ int rf_soapy_close(void *h) void rf_soapy_set_master_clock_rate(void *h, double rate) { // Allow the soapy to automatically set the appropriate clock rate - // TODO: implement this function + } @@ -285,12 +298,6 @@ double rf_soapy_set_rx_srate(void *h, double rate) printf("setSampleRate Rx fail: %s\n", SoapySDRDevice_lastError()); return SRSLTE_ERROR; } - - if (SoapySDRDevice_setBandwidth(handler->device, SOAPY_SDR_RX, 0, rate) != 0) { - printf("setBandwidth Rx failed: %s\n", SoapySDRDevice_lastError()); - return SRSLTE_ERROR; - } - return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_RX,0); } @@ -301,12 +308,6 @@ double rf_soapy_set_tx_srate(void *h, double rate) printf("setSampleRate Tx fail: %s\n", SoapySDRDevice_lastError()); return SRSLTE_ERROR; } - - if (SoapySDRDevice_setBandwidth(handler->device, SOAPY_SDR_TX, 0, rate) != 0) { - printf("setBandwidth Tx failed: %s\n", SoapySDRDevice_lastError()); - return SRSLTE_ERROR; - } - return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_TX,0); } diff --git a/lib/src/phy/rf/rf_soapy_imp.h b/lib/src/phy/rf/rf_soapy_imp.h index 19de4536c..4974157d1 100644 --- a/lib/src/phy/rf/rf_soapy_imp.h +++ b/lib/src/phy/rf/rf_soapy_imp.h @@ -28,7 +28,7 @@ #include #include "srslte/config.h" #include "srslte/phy/rf/rf.h" - +#define DEVNAME_LIME "lime" SRSLTE_API int rf_soapy_open(char *args, void **handler); @@ -45,7 +45,7 @@ SRSLTE_API void rf_soapy_set_tx_cal(void *h, srslte_rf_cal_t *cal); SRSLTE_API void rf_soapy_set_rx_cal(void *h, srslte_rf_cal_t *cal); -SRSLTE_API int rf_soapy_start_rx_stream(void *h); +SRSLTE_API int rf_soapy_start_rx_stream(void *h, bool now); SRSLTE_API int rf_soapy_stop_rx_stream(void *h); diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index 95287a628..0d289535e 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -50,12 +50,13 @@ typedef struct { double tx_rate; bool dynamic_rate; bool has_rssi; - uhd_sensor_value_handle rssi_value; uint32_t nof_rx_channels; int nof_tx_channels; srslte_rf_error_handler_t uhd_error_handler; - + + float current_master_clock; + bool async_thread_running; pthread_t async_thread; } rf_uhd_handler_t; @@ -219,21 +220,23 @@ void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal) } -int rf_uhd_start_rx_stream(void *h) +int rf_uhd_start_rx_stream(void *h, bool now) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; uhd_stream_cmd_t stream_cmd = { .stream_mode = UHD_STREAM_MODE_START_CONTINUOUS, - .stream_now = false + .stream_now = now }; - uhd_usrp_get_time_now(handler->usrp, 0, &stream_cmd.time_spec_full_secs, &stream_cmd.time_spec_frac_secs); - stream_cmd.time_spec_frac_secs += 0.1; - if (stream_cmd.time_spec_frac_secs > 1) { - stream_cmd.time_spec_frac_secs -= 1; - stream_cmd.time_spec_full_secs += 1; + if (!now) { + uhd_usrp_get_time_now(handler->usrp, 0, &stream_cmd.time_spec_full_secs, &stream_cmd.time_spec_frac_secs); + stream_cmd.time_spec_frac_secs += 0.2; + if (stream_cmd.time_spec_frac_secs > 1) { + stream_cmd.time_spec_frac_secs -= 1; + stream_cmd.time_spec_full_secs += 1; + } } - uhd_rx_streamer_issue_stream_cmd(handler->rx_stream, &stream_cmd); + uhd_rx_streamer_issue_stream_cmd(handler->rx_stream, &stream_cmd); return 0; } @@ -277,10 +280,15 @@ bool get_has_rssi(void *h) { float rf_uhd_get_rssi(void *h) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; if (handler->has_rssi) { - double val_out; - uhd_usrp_get_rx_sensor(handler->usrp, "rssi", 0, &handler->rssi_value); - uhd_sensor_value_to_realnum(handler->rssi_value, &val_out); - return val_out; + double val_out; + + uhd_sensor_value_handle rssi_value; + uhd_sensor_value_make_from_realnum(&rssi_value, "rssi", 0, "dBm", "%f"); + uhd_usrp_get_rx_sensor(handler->usrp, "rssi", 0, &rssi_value); + uhd_sensor_value_to_realnum(rssi_value, &val_out); + uhd_sensor_value_free(&rssi_value); + + return val_out; } else { return 0.0; } @@ -291,6 +299,13 @@ int rf_uhd_open(char *args, void **h) return rf_uhd_open_multi(args, h, 1); } +#define REMOVE_SUBSTRING_WITHCOMAS(S, TOREMOVE) \ + remove_substring(S, TOREMOVE ",");\ + remove_substring(S, TOREMOVE ", ");\ + remove_substring(S, "," TOREMOVE);\ + remove_substring(S, ", " TOREMOVE);\ + remove_substring(S, TOREMOVE) + static void remove_substring(char *s,const char *toremove) { while((s=strstr(s,toremove))) { @@ -298,6 +313,17 @@ static void remove_substring(char *s,const char *toremove) } } +static void copy_subdev_string(char *dst, char *src) { + int n = 0; + size_t len = strlen(src); + /* Copy until end of string or comma */ + while (n < len && src[n] != '\0' && src[n] != ',') { + dst[n] = src[n]; + n++; + } + dst[n] = '\0'; +} + int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) { if (h) { @@ -336,11 +362,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) // Check external clock argument enum {DEFAULT, EXTERNAL, GPSDO} clock_src; if (strstr(args, "clock=external")) { - remove_substring(args, "clock=external"); + REMOVE_SUBSTRING_WITHCOMAS(args, "clock=external"); clock_src = EXTERNAL; } else if (strstr(args, "clock=gpsdo")) { printf("Using GPSDO clock\n"); - remove_substring(args, "clock=gpsdo"); + REMOVE_SUBSTRING_WITHCOMAS(args, "clock=gpsdo"); clock_src = GPSDO; } else { clock_src = DEFAULT; @@ -349,36 +375,68 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) // Set over the wire format char *otw_format = "sc16"; if (strstr(args, "otw_format=sc12")) { + REMOVE_SUBSTRING_WITHCOMAS(args, "otw_format=sc12"); otw_format = "sc12"; } else if (strstr(args, "otw_format=sc16")) { + REMOVE_SUBSTRING_WITHCOMAS(args, "otw_format=sc16"); /* Do nothing */ } else if (strstr(args, "otw_format=")) { fprintf(stderr, "Wrong over the wire format. Valid formats: sc12, sc16\n"); return -1; } + // Set transmitter subdevice spec string + const char tx_subdev_arg[] = "tx_subdev_spec="; + char tx_subdev_str[64] = {0}; + char *tx_subdev_ptr = strstr(args, tx_subdev_arg); + if (tx_subdev_ptr) { + copy_subdev_string(tx_subdev_str, tx_subdev_ptr + strlen(tx_subdev_arg)); + } + + // Set receiver subdevice spec string + const char rx_subdev_arg[] = "rx_subdev_spec="; + char rx_subdev_str[64] = {0}; + char *rx_subdev_ptr = strstr(args, rx_subdev_arg); + if (rx_subdev_ptr) { + copy_subdev_string(rx_subdev_str, rx_subdev_ptr + strlen(rx_subdev_arg)); + } + + if (tx_subdev_ptr) { + remove_substring(args, tx_subdev_arg); + remove_substring(args, tx_subdev_str); + } + + if (rx_subdev_ptr) { + remove_substring(args, rx_subdev_arg); + remove_substring(args, rx_subdev_str); + } + /* If device type or name not given in args, choose a B200 */ if (args[0]=='\0') { if (find_string(devices_str, "type=b200") && !strstr(args, "recv_frame_size")) { // If B200 is available, use it args = "type=b200,master_clock_rate=30.72e6"; + handler->current_master_clock = 30720000; handler->devname = DEVNAME_B200; } else if (find_string(devices_str, "type=x300")) { // Else if X300 is available, set master clock rate now (can't be changed later) args = "type=x300,master_clock_rate=184.32e6"; - handler->dynamic_rate = false; + handler->current_master_clock = 184320000; + handler->dynamic_rate = false; handler->devname = DEVNAME_X300; } } else { // If args is set and x300 type is specified, make sure master_clock_rate is defined if (strstr(args, "type=x300") && !strstr(args, "master_clock_rate")) { sprintf(args2, "%s,master_clock_rate=184.32e6",args); - args = args2; - handler->dynamic_rate = false; + args = args2; + handler->current_master_clock = 184320000; + handler->dynamic_rate = false; handler->devname = DEVNAME_X300; - } else if (strstr(args, "type=b200")) { + } else { snprintf(args2, sizeof(args2), "%s,master_clock_rate=30.72e6", args); args = args2; + handler->current_master_clock = 30720000; handler->devname = DEVNAME_B200; } } @@ -386,17 +444,35 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) uhd_string_vector_free(&devices_str); /* Create UHD handler */ - if (strstr(args, "silent")) { - rf_uhd_suppress_stdout(NULL); - } else { - printf("Opening USRP with args: %s\n", args); - } + printf("Opening USRP with args: %s\n", args); uhd_error error = uhd_usrp_make(&handler->usrp, args); if (error) { fprintf(stderr, "Error opening UHD: code %d\n", error); return -1; } - + + /* Set transmitter subdev spec if specified */ + if (strlen(tx_subdev_str)) { + uhd_subdev_spec_handle subdev_spec_handle = {0}; + + printf("Setting tx_subdev_spec to '%s'\n", tx_subdev_str); + + uhd_subdev_spec_make(&subdev_spec_handle, tx_subdev_str); + uhd_usrp_set_tx_subdev_spec(handler->usrp, subdev_spec_handle, 0); + uhd_subdev_spec_free(&subdev_spec_handle); + } + + /* Set receiver subdev spec if specified */ + if (strlen(rx_subdev_str)) { + uhd_subdev_spec_handle subdev_spec_handle = {0}; + + printf("Setting rx_subdev_spec to '%s'\n", rx_subdev_str); + + uhd_subdev_spec_make(&subdev_spec_handle, rx_subdev_str); + uhd_usrp_set_rx_subdev_spec(handler->usrp, subdev_spec_handle, 0); + uhd_subdev_spec_free(&subdev_spec_handle); + } + if (!handler->devname) { char dev_str[1024]; uhd_usrp_get_mboard_name(handler->usrp, 0, dev_str, 1024); @@ -418,10 +494,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) } handler->has_rssi = get_has_rssi(handler); - if (handler->has_rssi) { - uhd_sensor_value_make_from_realnum(&handler->rssi_value, "rssi", 0, "dBm", "%f"); - } - + size_t channel[4] = {0, 1, 2, 3}; uhd_stream_args_t stream_args = { .cpu_format = "fc32", @@ -464,9 +537,17 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) uhd_rx_metadata_make(&handler->rx_md); uhd_rx_metadata_make(&handler->rx_md_first); uhd_tx_metadata_make(&handler->tx_md, false, 0, 0, false, false); - - - // Start low priority thread to receive async commands + + // Set starting gain to half maximum in case of using AGC + uhd_meta_range_handle gain_range; + uhd_meta_range_make(&gain_range); + uhd_usrp_get_rx_gain_range(handler->usrp, "", 0, gain_range); + double max_gain; + uhd_meta_range_stop(gain_range, &max_gain); + rf_uhd_set_rx_gain(handler, max_gain*0.7); + uhd_meta_range_free(&gain_range); + + // Start low priority thread to receive async commands handler->async_thread_running = true; if (pthread_create(&handler->async_thread, NULL, async_thread, handler)) { perror("pthread_create"); @@ -490,10 +571,7 @@ int rf_uhd_close(void *h) uhd_rx_metadata_free(&handler->rx_md_first); uhd_rx_metadata_free(&handler->rx_md); uhd_meta_range_free(&handler->rx_gain_range); - if (handler->has_rssi) { - uhd_sensor_value_free(&handler->rssi_value); - } - handler->async_thread_running = false; + handler->async_thread_running = false; pthread_join(handler->async_thread, NULL); uhd_tx_streamer_free(&handler->tx_stream); @@ -508,8 +586,11 @@ int rf_uhd_close(void *h) void rf_uhd_set_master_clock_rate(void *h, double rate) { rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - if (handler->dynamic_rate) { - uhd_usrp_set_master_clock_rate(handler->usrp, rate, 0); + if (rate != handler->current_master_clock) { + if (handler->dynamic_rate) { + uhd_usrp_set_master_clock_rate(handler->usrp, rate, 0); + } + handler->current_master_clock = rate; } } @@ -649,12 +730,14 @@ int rf_uhd_recv_with_time_multi(void *h, fprintf(stderr, "Error receiving from UHD: %d\n", error); return -1; } - md = &handler->rx_md; + + uhd_rx_metadata_error_code_t error_code = 0; + uhd_rx_metadata_error_code(*md, &error_code); + + md = &handler->rx_md; n += rxd_samples; trials++; - - uhd_rx_metadata_error_code_t error_code; - uhd_rx_metadata_error_code(*md, &error_code); + if (error_code == UHD_RX_METADATA_ERROR_CODE_OVERFLOW) { log_overflow(handler); } else if (error_code == UHD_RX_METADATA_ERROR_CODE_LATE_COMMAND) { @@ -718,7 +801,7 @@ int rf_uhd_send_timed_multi(void *h, int n = 0; cf_t *data_c[4]; for (int i = 0; i < 4; i++) { - data_c[i] = data[i]; + data_c[i] = data[i] ? data[i] : zero_mem; } do { size_t tx_samples = handler->tx_nof_samples; diff --git a/lib/src/phy/rf/rf_uhd_imp.h b/lib/src/phy/rf/rf_uhd_imp.h index 2be799333..e3555fab3 100644 --- a/lib/src/phy/rf/rf_uhd_imp.h +++ b/lib/src/phy/rf/rf_uhd_imp.h @@ -49,7 +49,8 @@ SRSLTE_API void rf_uhd_set_tx_cal(void *h, srslte_rf_cal_t *cal); SRSLTE_API void rf_uhd_set_rx_cal(void *h, srslte_rf_cal_t *cal); -SRSLTE_API int rf_uhd_start_rx_stream(void *h); +SRSLTE_API int rf_uhd_start_rx_stream(void *h, + bool now); SRSLTE_API int rf_uhd_start_rx_stream_nsamples(void *h, uint32_t nsamples); diff --git a/lib/src/phy/rf/rf_utils.c b/lib/src/phy/rf/rf_utils.c index ce288b5c5..ea016c721 100644 --- a/lib/src/phy/rf/rf_utils.c +++ b/lib/src/phy/rf/rf_utils.c @@ -60,7 +60,7 @@ int rf_rssi_scan(srslte_rf_t *rf, float *freqs, float *rssi, int nof_bands, doub srslte_rf_set_rx_freq(rf, f); srslte_rf_rx_wait_lo_locked(rf); usleep(10000); - srslte_rf_start_rx_stream(rf); + srslte_rf_start_rx_stream(rf, false); /* discard first samples */ for (j=0;j<2;j++) { @@ -113,23 +113,22 @@ int rf_mib_decoder(srslte_rf_t *rf, uint32_t nof_rx_antennas,cell_search_cfg_t * goto clean_exit; } - if (config->init_agc > 0) { - srslte_ue_sync_start_agc(&ue_mib.ue_sync, srslte_rf_set_rx_gain_th_wrapper, config->init_agc); - } - int srate = srslte_sampling_freq_hz(SRSLTE_UE_MIB_NOF_PRB); INFO("Setting sampling frequency %.2f MHz for PSS search\n", (float) srate/1000000); srslte_rf_set_rx_srate(rf, (float) srate); INFO("Starting receiver...\n", 0); - srslte_rf_start_rx_stream(rf); - - // Set CFO if available + srslte_rf_start_rx_stream(rf, false); + + // Copy CFO estimate if provided and disable CP estimation during find if (cfo) { - srslte_ue_sync_set_cfo(&ue_mib.ue_sync, *cfo); + ue_mib.ue_sync.cfo_current_value = *cfo/15000; + ue_mib.ue_sync.cfo_is_copied = true; + ue_mib.ue_sync.cfo_correct_enable_find = true; + srslte_sync_set_cfo_cp_enable(&ue_mib.ue_sync.sfind, false, 0); } - - /* Find and decody MIB */ + + /* Find and decode MIB */ ret = srslte_ue_mib_sync_decode(&ue_mib, config->max_frames_pbch, bch_payload, &cell->nof_ports, NULL); if (ret < 0) { fprintf(stderr, "Error decoding MIB\n"); @@ -138,12 +137,7 @@ int rf_mib_decoder(srslte_rf_t *rf, uint32_t nof_rx_antennas,cell_search_cfg_t * if (ret == 1) { srslte_pbch_mib_unpack(bch_payload, cell, NULL); } - - // Save AGC value - if (config->init_agc > 0) { - config->init_agc = srslte_agc_get_gain(&ue_mib.ue_sync.agc); - } - + // Save CFO if (cfo) { *cfo = srslte_ue_sync_get_cfo(&ue_mib.ue_sync); @@ -176,15 +170,12 @@ int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas, if (config->nof_valid_pss_frames) { srslte_ue_cellsearch_set_nof_valid_frames(&cs, config->nof_valid_pss_frames); } - if (config->init_agc > 0) { - srslte_ue_sync_start_agc(&cs.ue_sync, srslte_rf_set_rx_gain_th_wrapper, config->init_agc); - } - + INFO("Setting sampling frequency %.2f MHz for PSS search\n", SRSLTE_CS_SAMP_FREQ/1000000); srslte_rf_set_rx_srate(rf, SRSLTE_CS_SAMP_FREQ); INFO("Starting receiver...\n", 0); - srslte_rf_start_rx_stream(rf); + srslte_rf_start_rx_stream(rf, false); /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ uint32_t max_peak_cell = 0; @@ -222,12 +213,7 @@ int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas, // Save CFO if (cfo) { - *cfo = found_cells[max_peak_cell].cfo; - } - - // Save AGC value for MIB decoding - if (config->init_agc > 0) { - config->init_agc = srslte_agc_get_gain(&cs.ue_sync.agc); + *cfo = found_cells[max_peak_cell].cfo; } srslte_rf_stop_rx_stream(rf); diff --git a/lib/src/phy/scrambling/scrambling.c b/lib/src/phy/scrambling/scrambling.c index 42f16d1e8..ca0342905 100644 --- a/lib/src/phy/scrambling/scrambling.c +++ b/lib/src/phy/scrambling/scrambling.c @@ -60,10 +60,8 @@ void srslte_scrambling_c_offset(srslte_sequence_t *s, cf_t *data, int offset, in } void scrambling_b(uint8_t *c, uint8_t *data, int len) { - int i; - for (i = 0; i < len; i++) { - data[i] = (data[i] ^ c[i]); - } + + srslte_vec_xor_bbb((int8_t*)c,(int8_t*)data,(int8_t*)data,len); } void scrambling_b_word(uint8_t *c, uint8_t *data, int len) { diff --git a/lib/src/phy/sync/cfo.c b/lib/src/phy/sync/cfo.c index 34498ce58..806701a9a 100644 --- a/lib/src/phy/sync/cfo.c +++ b/lib/src/phy/sync/cfo.c @@ -45,7 +45,7 @@ int srslte_cfo_init(srslte_cfo_t *h, uint32_t nsamples) { if (!h->cur_cexp) { goto clean; } - h->tol = SRSLTE_CFO_TOLERANCE; + h->tol = 0; h->last_freq = 0; h->nsamples = nsamples; h->max_samples = nsamples; @@ -83,7 +83,7 @@ int srslte_cfo_resize(srslte_cfo_t *h, uint32_t samples) { return SRSLTE_SUCCESS; } -void srslte_cfo_correct(srslte_cfo_t *h, cf_t *input, cf_t *output, float freq) { +void srslte_cfo_correct(srslte_cfo_t *h, const cf_t *input, cf_t *output, float freq) { if (fabs(h->last_freq - freq) > h->tol) { h->last_freq = freq; srslte_cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, h->nsamples); diff --git a/lib/src/phy/sync/cp.c b/lib/src/phy/sync/cp.c index a282f6dfd..80d0a2179 100644 --- a/lib/src/phy/sync/cp.c +++ b/lib/src/phy/sync/cp.c @@ -63,14 +63,14 @@ int srslte_cp_synch_resize(srslte_cp_synch_t *q, uint32_t symbol_sz) } -uint32_t srslte_cp_synch(srslte_cp_synch_t *q, cf_t *input, uint32_t max_offset, uint32_t nof_symbols, uint32_t cp_len) +uint32_t srslte_cp_synch(srslte_cp_synch_t *q, const cf_t *input, uint32_t max_offset, uint32_t nof_symbols, uint32_t cp_len) { if (max_offset > q->symbol_sz) { max_offset = q->symbol_sz; } for (int i=0;icorr[i] = 0; - cf_t *inputPtr = input; + const cf_t *inputPtr = input; for (int n=0;ncorr[i] += srslte_vec_dot_prod_conj_ccc(&inputPtr[i], &inputPtr[i+q->symbol_sz], cplen)/nof_symbols; diff --git a/lib/src/phy/sync/find_sss.c b/lib/src/phy/sync/find_sss.c index 2afeced42..6695d70c2 100644 --- a/lib/src/phy/sync/find_sss.c +++ b/lib/src/phy/sync/find_sss.c @@ -68,16 +68,14 @@ static void corr_all_sz_partial(cf_t z[SRSLTE_SSS_N], float s[SRSLTE_SSS_N][SRSL } } -static void extract_pair_sss(srslte_sss_synch_t *q, cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) { +static void extract_pair_sss(srslte_sss_t *q, const cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) { cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; - float ce_mod[2*SRSLTE_SSS_N], z_real[2*SRSLTE_SSS_N], z_imag[2*SRSLTE_SSS_N]; - + srslte_dft_run_c(&q->dftp_input, input, input_fft); if (ce) { - srslte_vec_div_ccc(&input_fft[q->fft_size/2-SRSLTE_SSS_N], ce, ce_mod, - &input_fft[q->fft_size/2-SRSLTE_SSS_N], z_real, z_imag, - 2*SRSLTE_SSS_N); + srslte_vec_div_ccc(&input_fft[q->fft_size/2-SRSLTE_SSS_N], ce, + &input_fft[q->fft_size/2-SRSLTE_SSS_N], 2*SRSLTE_SSS_N); } for (int i = 0; i < SRSLTE_SSS_N; i++) { @@ -90,10 +88,10 @@ static void extract_pair_sss(srslte_sss_synch_t *q, cf_t *input, cf_t *ce, cf_t } -int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, cf_t *input, uint32_t *m0, float *m0_value, +int srslte_sss_m0m1_diff(srslte_sss_t *q, const cf_t *input, uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value) { - return srslte_sss_synch_m0m1_diff_coh(q, input, NULL, m0, m0_value, m1, m1_value); + return srslte_sss_m0m1_diff_coh(q, input, NULL, m0, m0_value, m1, m1_value); } /* Differential SSS estimation. @@ -104,7 +102,7 @@ int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, cf_t *input, uint32_t *m0, * */ -int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, +int srslte_sss_m0m1_diff_coh(srslte_sss_t *q, const cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value) { @@ -147,7 +145,7 @@ int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, cf_t *input, cf_t ce[2 * Jung-In Kim, Jung-Su Han, Hee-Jin Roh and Hyung-Jin Choi */ -int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, +int srslte_sss_m0m1_partial(srslte_sss_t *q, const cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value) { diff --git a/lib/src/phy/sync/pss.c b/lib/src/phy/sync/pss.c index f7b35071d..ac54264eb 100644 --- a/lib/src/phy/sync/pss.c +++ b/lib/src/phy/sync/pss.c @@ -30,16 +30,12 @@ #include #include #include -#include #include "srslte/phy/sync/pss.h" -#include "srslte/phy/dft/dft.h" -#include "srslte/phy/utils/vector.h" -#include "srslte/phy/utils/convolution.h" #include "srslte/phy/utils/debug.h" -int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time, +int srslte_pss_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time, uint32_t N_id_2, uint32_t fft_size, int cfo_i) { srslte_dft_plan_t plan; cf_t pss_signal_pad[2048]; @@ -69,7 +65,7 @@ int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time, srslte_vec_sc_prod_cfc(pss_signal_time, 1.0/SRSLTE_PSS_LEN, pss_signal_time, fft_size); srslte_dft_plan_free(&plan); - + ret = SRSLTE_SUCCESS; } return ret; @@ -77,16 +73,16 @@ int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time, /* Initializes the PSS synchronization object with fft_size=128 */ -int srslte_pss_synch_init(srslte_pss_synch_t *q, uint32_t frame_size) { - return srslte_pss_synch_init_fft(q, frame_size, 128); +int srslte_pss_init(srslte_pss_t *q, uint32_t frame_size) { + return srslte_pss_init_fft(q, frame_size, 128); } -int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) { - return srslte_pss_synch_init_fft_offset(q, frame_size, fft_size, 0); +int srslte_pss_init_fft(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size) { + return srslte_pss_init_fft_offset(q, frame_size, fft_size, 0); } -int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { - return srslte_pss_synch_init_fft_offset_decim(q, frame_size, fft_size, offset, 1); +int srslte_pss_init_fft_offset(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { + return srslte_pss_init_fft_offset_decim(q, frame_size, fft_size, offset, 1); } /* Initializes the PSS synchronization object. @@ -94,7 +90,7 @@ int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, * It correlates a signal of frame_size samples with the PSS sequence in the frequency * domain. The PSS sequence is transformed using fft_size samples. */ -int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, +int srslte_pss_init_fft_offset_decim(srslte_pss_t *q, uint32_t max_frame_size, uint32_t max_fft_size, int offset, int decimate) { @@ -106,7 +102,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, uint32_t N_id_2; uint32_t buffer_size; - bzero(q, sizeof(srslte_pss_synch_t)); + bzero(q, sizeof(srslte_pss_t)); q->N_id_2 = 10; q->ema_alpha = 0.2; @@ -123,6 +119,9 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, buffer_size = fft_size + frame_size + 1; + q->filter_pss_enable = false; + q->chest_on_filter = false; + if(q->decimate > 1) { int filter_order = 3; srslte_filt_decim_cc_init(&q->filter,q->decimate,filter_order); @@ -137,9 +136,19 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, } srslte_dft_plan_set_mirror(&q->dftp_input, true); srslte_dft_plan_set_dc(&q->dftp_input, true); - srslte_dft_plan_set_norm(&q->dftp_input, true); + srslte_dft_plan_set_norm(&q->dftp_input, false); - q->tmp_input = srslte_vec_malloc((buffer_size + frame_size*(q->decimate - 1)) * sizeof(cf_t)); + if (srslte_dft_plan(&q->idftp_input, fft_size, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) { + fprintf(stderr, "Error creating DFT plan \n"); + goto clean_and_exit; + } + srslte_dft_plan_set_mirror(&q->idftp_input, true); + srslte_dft_plan_set_dc(&q->idftp_input, true); + srslte_dft_plan_set_norm(&q->idftp_input, false); + + bzero(q->tmp_fft2, sizeof(cf_t)*SRSLTE_SYMBOL_SZ_MAX); + + q->tmp_input = srslte_vec_malloc((buffer_size + frame_size*(q->decimate - 1)) * sizeof(cf_t)); if (!q->tmp_input) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; @@ -167,7 +176,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, } bzero(q->conv_output_abs, sizeof(float) * buffer_size); #endif - + for (N_id_2=0;N_id_2<3;N_id_2++) { q->pss_signal_time[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); if (!q->pss_signal_time[N_id_2]) { @@ -175,36 +184,34 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, goto clean_and_exit; } /* The PSS is translated into the time domain for each N_id_2 */ - if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { + if (srslte_pss_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); goto clean_and_exit; - } + } bzero(&q->pss_signal_time[N_id_2][q->fft_size], q->frame_size * sizeof(cf_t)); - } + } #ifdef CONVOLUTION_FFT - for(N_id_2=0; N_id_2<3; N_id_2++) - q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); - if (srslte_conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) { fprintf(stderr, "Error initiating convolution FFT\n"); goto clean_and_exit; } - for(int i=0; i<3; i++) { - srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[i], q->pss_signal_freq_full[i]); + for(N_id_2=0; N_id_2<3; N_id_2++) { + q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); + srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[N_id_2], q->pss_signal_freq_full[N_id_2]); } - + #endif - - srslte_pss_synch_reset(q); - + + srslte_pss_reset(q); + ret = SRSLTE_SUCCESS; } -clean_and_exit: +clean_and_exit: if (ret == SRSLTE_ERROR) { - srslte_pss_synch_free(q); + srslte_pss_free(q); } return ret; @@ -216,7 +223,7 @@ clean_and_exit: * It correlates a signal of frame_size samples with the PSS sequence in the frequency * domain. The PSS sequence is transformed using fft_size samples. */ -int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { +int srslte_pss_resize(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -225,7 +232,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t ret = SRSLTE_ERROR; if (fft_size > q->max_fft_size || frame_size > q->max_frame_size) { - fprintf(stderr, "Error in pss_synch_config(): fft_size and frame_size must be lower than initialized\n"); + fprintf(stderr, "Error in pss_config(): fft_size and frame_size must be lower than initialized\n"); return SRSLTE_ERROR; } @@ -248,6 +255,13 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t return SRSLTE_ERROR; } + if (srslte_dft_replan(&q->idftp_input, fft_size)) { + fprintf(stderr, "Error creating DFT plan \n"); + return SRSLTE_ERROR; + } + + bzero(q->tmp_fft2, sizeof(cf_t)*SRSLTE_SYMBOL_SZ_MAX); + bzero(&q->tmp_input[q->frame_size], q->fft_size * sizeof(cf_t)); bzero(q->conv_output, sizeof(cf_t) * buffer_size); bzero(q->conv_output_avg, sizeof(float) * buffer_size); @@ -258,7 +272,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t // Generate PSS sequences for this FFT size for (N_id_2=0;N_id_2<3;N_id_2++) { - if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { + if (srslte_pss_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); return SRSLTE_ERROR; } @@ -276,7 +290,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t #endif - srslte_pss_synch_reset(q); + srslte_pss_reset(q); ret = SRSLTE_SUCCESS; } @@ -284,7 +298,7 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t } -void srslte_pss_synch_free(srslte_pss_synch_t *q) { +void srslte_pss_free(srslte_pss_t *q) { uint32_t i; if (q) { @@ -298,7 +312,7 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { } #ifdef CONVOLUTION_FFT srslte_conv_fft_cc_free(&q->conv_fft); - + #endif if (q->tmp_input) { free(q->tmp_input); @@ -312,9 +326,10 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { if (q->conv_output_avg) { free(q->conv_output_avg); } - + srslte_dft_plan_free(&q->dftp_input); - + srslte_dft_plan_free(&q->idftp_input); + if(q->decimate > 1) { srslte_filt_decim_cc_free(&q->filter); @@ -323,11 +338,11 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { } - bzero(q, sizeof(srslte_pss_synch_t)); + bzero(q, sizeof(srslte_pss_t)); } } -void srslte_pss_synch_reset(srslte_pss_synch_t *q) { +void srslte_pss_reset(srslte_pss_t *q) { uint32_t buffer_size = q->fft_size + q->frame_size + 1; bzero(q->conv_output_avg, sizeof(float) * buffer_size); } @@ -379,13 +394,13 @@ void srslte_pss_put_slot(cf_t *pss_signal, cf_t *slot, uint32_t nof_prb, srslte_ void srslte_pss_get_slot(cf_t *slot, cf_t *pss_signal, uint32_t nof_prb, srslte_cp_t cp) { int k; k = (SRSLTE_CP_NSYMB(cp) - 1) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 31; - memcpy(pss_signal, &slot[k], SRSLTE_PSS_LEN * sizeof(cf_t)); + memcpy(pss_signal, &slot[k], SRSLTE_PSS_LEN * sizeof(cf_t)); } /** Sets the current N_id_2 value. Returns -1 on error, 0 otherwise */ -int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, uint32_t N_id_2) { +int srslte_pss_set_N_id_2(srslte_pss_t *q, uint32_t N_id_2) { if (!srslte_N_id_2_isvalid((N_id_2))) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return -1; @@ -397,52 +412,80 @@ int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, uint32_t N_id_2) { /* Sets the weight factor alpha for the exponential moving average of the PSS correlation output */ -void srslte_pss_synch_set_ema_alpha(srslte_pss_synch_t *q, float alpha) { - q->ema_alpha = alpha; +void srslte_pss_set_ema_alpha(srslte_pss_t *q, float alpha) { + q->ema_alpha = alpha; } -/** Performs time-domain PSS correlation. +float compute_peak_sidelobe(srslte_pss_t *q, uint32_t corr_peak_pos, uint32_t conv_output_len) +{ + // Find end of peak lobe to the right + int pl_ub = corr_peak_pos+1; + while(q->conv_output_avg[pl_ub+1] <= q->conv_output_avg[pl_ub] && pl_ub < conv_output_len) { + pl_ub ++; + } + // Find end of peak lobe to the left + int pl_lb; + if (corr_peak_pos > 2) { + pl_lb = corr_peak_pos-1; + while(q->conv_output_avg[pl_lb-1] <= q->conv_output_avg[pl_lb] && pl_lb > 1) { + pl_lb --; + } + } else { + pl_lb = 0; + } + + int sl_distance_right = conv_output_len-1-pl_ub; + if (sl_distance_right < 0) { + sl_distance_right = 0; + } + int sl_distance_left = pl_lb; + + int sl_right = pl_ub+srslte_vec_max_fi(&q->conv_output_avg[pl_ub], sl_distance_right); + int sl_left = srslte_vec_max_fi(q->conv_output_avg, sl_distance_left); + float side_lobe_value = SRSLTE_MAX(q->conv_output_avg[sl_right], q->conv_output_avg[sl_left]); + + return q->conv_output_avg[corr_peak_pos]/side_lobe_value; +} + +/** Performs time-domain PSS correlation. * Returns the index of the PSS correlation peak in a subframe. * The frame starts at corr_peak_pos-subframe_size/2. * The value of the correlation is stored in corr_peak_value. * * Input buffer must be subframe_size long. */ -int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_peak_value) +int srslte_pss_find_pss(srslte_pss_t *q, const cf_t *input, float *corr_peak_value) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && + + if (q != NULL && input != NULL) { uint32_t corr_peak_pos; uint32_t conv_output_len; - + if (!srslte_N_id_2_isvalid(q->N_id_2)) { fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n"); return SRSLTE_ERROR; } /* Correlate input with PSS sequence - * + * * We do not reverse time-domain PSS signal because it's conjugate is symmetric. - * The conjugate operation on pss_signal_time has been done in srslte_pss_synch_init_N_id_2 + * The conjugate operation on pss_signal_time has been done in srslte_pss_init_N_id_2 * This is why we can use FFT-based convolution */ if (q->frame_size >= q->fft_size) { #ifdef CONVOLUTION_FFT - memcpy(q->tmp_input, input, (q->frame_size * q->decimate) * sizeof(cf_t)); - if(q->decimate > 1) - { - srslte_filt_decim_cc_execute(&(q->filter), q->tmp_input, q->filter.downsampled_input, q->filter.filter_output , (q->frame_size * q->decimate)); - conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->filter.filter_output,q->pss_signal_freq_full[q->N_id_2], q->conv_output); - } - else - { - conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->tmp_input, q->pss_signal_freq_full[q->N_id_2], q->conv_output); - } - + memcpy(q->tmp_input, input, (q->frame_size * q->decimate) * sizeof(cf_t)); + if(q->decimate > 1) { + srslte_filt_decim_cc_execute(&(q->filter), q->tmp_input, q->filter.downsampled_input, q->filter.filter_output , (q->frame_size * q->decimate)); + conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->filter.filter_output,q->pss_signal_freq_full[q->N_id_2], q->conv_output); + } else { + conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->tmp_input, q->pss_signal_freq_full[q->N_id_2], q->conv_output); + } + #else conv_output_len = srslte_conv_cc(input, q->pss_signal_time[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); #endif @@ -450,97 +493,61 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe for (int i=0;iframe_size;i++) { q->conv_output[i] = srslte_vec_dot_prod_ccc(q->pss_signal_time[q->N_id_2], &input[i], q->fft_size); } - conv_output_len = q->frame_size; + conv_output_len = q->frame_size; } - - #ifdef SRSLTE_PSS_ABS_SQUARE - srslte_vec_abs_square_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); - #else - srslte_vec_abs_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); - #endif - + // Compute modulus square + srslte_vec_abs_square_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); + + // If enabled, average the absolute value from previous calls if (q->ema_alpha < 1.0 && q->ema_alpha > 0.0) { - srslte_vec_sc_prod_fff(q->conv_output_abs, q->ema_alpha, q->conv_output_abs, conv_output_len-1); - srslte_vec_sc_prod_fff(q->conv_output_avg, 1-q->ema_alpha, q->conv_output_avg, conv_output_len-1); + srslte_vec_sc_prod_fff(q->conv_output_abs, q->ema_alpha, q->conv_output_abs, conv_output_len-1); + srslte_vec_sc_prod_fff(q->conv_output_avg, 1-q->ema_alpha, q->conv_output_avg, conv_output_len-1); srslte_vec_sum_fff(q->conv_output_abs, q->conv_output_avg, q->conv_output_avg, conv_output_len-1); } else { memcpy(q->conv_output_avg, q->conv_output_abs, sizeof(float)*(conv_output_len-1)); } + /* Find maximum of the absolute value of the correlation */ corr_peak_pos = srslte_vec_max_fi(q->conv_output_avg, conv_output_len-1); - - // save absolute value - q->peak_value = q->conv_output_avg[corr_peak_pos]; - -#ifdef SRSLTE_PSS_RETURN_PSR - // Find second side lobe - - // Find end of peak lobe to the right - int pl_ub = corr_peak_pos+1; - while(q->conv_output_avg[pl_ub+1] <= q->conv_output_avg[pl_ub] && pl_ub < conv_output_len) { - pl_ub ++; - } - // Find end of peak lobe to the left - int pl_lb; - if (corr_peak_pos > 2) { - pl_lb = corr_peak_pos-1; - while(q->conv_output_avg[pl_lb-1] <= q->conv_output_avg[pl_lb] && pl_lb > 1) { - pl_lb --; - } - } else { - pl_lb = 0; - } - int sl_distance_right = conv_output_len-1-pl_ub; - if (sl_distance_right < 0) { - sl_distance_right = 0; - } - int sl_distance_left = pl_lb; - - int sl_right = pl_ub+srslte_vec_max_fi(&q->conv_output_avg[pl_ub], sl_distance_right); - int sl_left = srslte_vec_max_fi(q->conv_output_avg, sl_distance_left); - float side_lobe_value = SRSLTE_MAX(q->conv_output_avg[sl_right], q->conv_output_avg[sl_left]); + // save absolute value + q->peak_value = q->conv_output_avg[corr_peak_pos]; + +#ifdef SRSLTE_PSS_RETURN_PSR if (corr_peak_value) { - *corr_peak_value = q->conv_output_avg[corr_peak_pos]/side_lobe_value; - - if (*corr_peak_value < 10) - DEBUG("peak_pos=%2d, pl_ub=%2d, pl_lb=%2d, sl_right: %2d, sl_left: %2d, PSR: %.2f/%.2f=%.2f\n", corr_peak_pos, pl_ub, pl_lb, - sl_right,sl_left, q->conv_output_avg[corr_peak_pos], side_lobe_value,*corr_peak_value); + *corr_peak_value = compute_peak_sidelobe(q, corr_peak_pos, conv_output_len); } #else if (corr_peak_value) { *corr_peak_value = q->conv_output_avg[corr_peak_pos]; } #endif - - if(q->decimate >1) - { - int decimation_correction = (q->filter.num_taps - 2); - corr_peak_pos = corr_peak_pos - decimation_correction; - corr_peak_pos = corr_peak_pos*q->decimate; + + if(q->decimate >1) { + int decimation_correction = (q->filter.num_taps - 2); + corr_peak_pos = corr_peak_pos - decimation_correction; + corr_peak_pos = corr_peak_pos*q->decimate; } - if (q->frame_size >= q->fft_size) { - ret = (int) corr_peak_pos; + ret = (int) corr_peak_pos; } else { ret = (int) corr_peak_pos + q->fft_size; } - } + } return ret; } -/* Computes frequency-domain channel estimation of the PSS symbol - * input signal is in the time-domain. - * ce is the returned frequency-domain channel estimates. +/* Computes frequency-domain channel estimation of the PSS symbol + * input signal is in the time-domain. + * ce is the returned frequency-domain channel estimates. */ -int srslte_pss_synch_chest(srslte_pss_synch_t *q, cf_t *input, cf_t ce[SRSLTE_PSS_LEN]) { +int srslte_pss_chest(srslte_pss_t *q, const cf_t *input, cf_t ce[SRSLTE_PSS_LEN]) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; - if (q != NULL && + if (q != NULL && input != NULL) { @@ -548,16 +555,55 @@ int srslte_pss_synch_chest(srslte_pss_synch_t *q, cf_t *input, cf_t ce[SRSLTE_PS fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n"); return SRSLTE_ERROR; } - + /* Transform to frequency-domain */ - srslte_dft_run_c(&q->dftp_input, input, input_fft); - + srslte_dft_run_c(&q->dftp_input, input, q->tmp_fft); + /* Compute channel estimate taking the PSS sequence as reference */ - srslte_vec_prod_conj_ccc(&input_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], ce, SRSLTE_PSS_LEN); - + srslte_vec_prod_conj_ccc(&q->tmp_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], ce, SRSLTE_PSS_LEN); + ret = SRSLTE_SUCCESS; } - return ret; + return ret; +} + +/* input points to beginning of last OFDM symbol of slot 0 of subframe 0 or 5 + * It must be called after calling srslte_pss_cfo_compute() with filter enabled + */ +void srslte_pss_sic(srslte_pss_t *q, cf_t *input) { + if (q->chest_on_filter) { + + bzero(q->tmp_fft, sizeof(cf_t)*q->fft_size); + + // Pass transmitted PSS sequence through the channel + srslte_vec_prod_ccc(q->pss_signal_freq[q->N_id_2], q->tmp_ce, &q->tmp_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], SRSLTE_PSS_LEN); + + // Get time-domain version of the received PSS + srslte_dft_run_c(&q->idftp_input, q->tmp_fft, q->tmp_fft2); + + // Substract received PSS from this N_id_2 from the input signal + srslte_vec_sc_prod_cfc(q->tmp_fft2, 1.0/q->fft_size, q->tmp_fft2, q->fft_size); + srslte_vec_sub_ccc(input, q->tmp_fft2, input, q->fft_size); + + } else { + fprintf(stderr, "Error calling srslte_pss_sic(): need to enable channel estimation on filtering\n"); + } +} + +// Frequency-domain filtering of the central 64 sub-carriers +void srslte_pss_filter(srslte_pss_t *q, const cf_t *input, cf_t *output) +{ + srslte_dft_run_c(&q->dftp_input, input, q->tmp_fft); + + memcpy(&q->tmp_fft2[q->fft_size/2-SRSLTE_PSS_LEN/2], + &q->tmp_fft[q->fft_size/2-SRSLTE_PSS_LEN/2], + sizeof(cf_t)*SRSLTE_PSS_LEN); + + if (q->chest_on_filter) { + srslte_vec_prod_conj_ccc(&q->tmp_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], q->tmp_ce, SRSLTE_PSS_LEN); + } + + srslte_dft_run_c(&q->idftp_input, q->tmp_fft2, output); } /* Returns the CFO estimation given a PSS received sequence @@ -565,14 +611,18 @@ int srslte_pss_synch_chest(srslte_pss_synch_t *q, cf_t *input, cf_t ce[SRSLTE_PS * Source: An Efficient CFO Estimation Algorithm for the Downlink of 3GPP-LTE * Feng Wang and Yu Zhu */ -float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, cf_t *pss_recv) { - cf_t y0, y1, yr; +float srslte_pss_cfo_compute(srslte_pss_t* q, const cf_t *pss_recv) { + cf_t y0, y1; - y0 = srslte_vec_dot_prod_ccc(q->pss_signal_time[q->N_id_2], pss_recv, q->fft_size/2); - y1 = srslte_vec_dot_prod_ccc(&q->pss_signal_time[q->N_id_2][q->fft_size/2], &pss_recv[q->fft_size/2], q->fft_size/2); - - yr = conjf(y0) * y1; + const cf_t *pss_ptr = pss_recv; - return atan2f(__imag__ yr, __real__ yr) / M_PI; + if (q->filter_pss_enable) { + srslte_pss_filter(q, pss_recv, q->tmp_fft); + pss_ptr = (const cf_t*) q->tmp_fft; + } + + y0 = srslte_vec_dot_prod_ccc(q->pss_signal_time[q->N_id_2], pss_ptr, q->fft_size/2); + y1 = srslte_vec_dot_prod_ccc(&q->pss_signal_time[q->N_id_2][q->fft_size/2], &pss_ptr[q->fft_size/2], q->fft_size/2); + return carg(conjf(y0) * y1)/M_PI; } diff --git a/lib/src/phy/sync/sss.c b/lib/src/phy/sync/sss.c index 4ed7b1d6c..31091bdb3 100644 --- a/lib/src/phy/sync/sss.c +++ b/lib/src/phy/sync/sss.c @@ -40,7 +40,7 @@ void generate_sss_all_tables(srslte_sss_tables_t *tables, uint32_t N_id_2); void convert_tables(srslte_sss_fc_tables_t *fc_tables, srslte_sss_tables_t *in); void generate_N_id_1_table(uint32_t table[30][30]); -int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) { +int srslte_sss_init(srslte_sss_t *q, uint32_t fft_size) { if (q != NULL && fft_size <= 2048) @@ -48,10 +48,10 @@ int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) { uint32_t N_id_2; srslte_sss_tables_t sss_tables; - bzero(q, sizeof(srslte_sss_synch_t)); + bzero(q, sizeof(srslte_sss_t)); if (srslte_dft_plan(&q->dftp_input, fft_size, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) { - srslte_sss_synch_free(q); + srslte_sss_free(q); return SRSLTE_ERROR; } srslte_dft_plan_set_mirror(&q->dftp_input, true); @@ -72,7 +72,7 @@ int srslte_sss_synch_init(srslte_sss_synch_t *q, uint32_t fft_size) { return SRSLTE_ERROR_INVALID_INPUTS; } -int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size) { +int srslte_sss_resize(srslte_sss_t *q, uint32_t fft_size) { if (q != NULL && fft_size <= 2048) { @@ -81,7 +81,7 @@ int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size) { return SRSLTE_ERROR; } if (srslte_dft_replan(&q->dftp_input, fft_size)) { - srslte_sss_synch_free(q); + srslte_sss_free(q); return SRSLTE_ERROR; } q->fft_size = fft_size; @@ -90,13 +90,13 @@ int srslte_sss_synch_resize(srslte_sss_synch_t *q, uint32_t fft_size) { return SRSLTE_ERROR_INVALID_INPUTS; } -void srslte_sss_synch_free(srslte_sss_synch_t *q) { +void srslte_sss_free(srslte_sss_t *q) { srslte_dft_plan_free(&q->dftp_input); - bzero(q, sizeof(srslte_sss_synch_t)); + bzero(q, sizeof(srslte_sss_t)); } /** Sets the N_id_2 to search for */ -int srslte_sss_synch_set_N_id_2(srslte_sss_synch_t *q, uint32_t N_id_2) { +int srslte_sss_set_N_id_2(srslte_sss_t *q, uint32_t N_id_2) { if (!srslte_N_id_2_isvalid(N_id_2)) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return SRSLTE_ERROR; @@ -124,12 +124,12 @@ void srslte_sss_put_slot(float *sss, cf_t *slot, uint32_t nof_prb, srslte_cp_t c } /** Sets the SSS correlation peak detection threshold */ -void srslte_sss_synch_set_threshold(srslte_sss_synch_t *q, float threshold) { +void srslte_sss_set_threshold(srslte_sss_t *q, float threshold) { q->corr_peak_threshold = threshold; } /** Returns the subframe index based on the m0 and m1 values */ -uint32_t srslte_sss_synch_subframe(uint32_t m0, uint32_t m1) { +uint32_t srslte_sss_subframe(uint32_t m0, uint32_t m1) { if (m1 > m0) { return 0; } else { @@ -138,7 +138,7 @@ uint32_t srslte_sss_synch_subframe(uint32_t m0, uint32_t m1) { } /** Returns the N_id_1 value based on the m0 and m1 values */ -int srslte_sss_synch_N_id_1(srslte_sss_synch_t *q, uint32_t m0, uint32_t m1) { +int srslte_sss_N_id_1(srslte_sss_t *q, uint32_t m0, uint32_t m1) { int N_id_1 = -1; if (m1 > m0) { if (m0 < 30 && m1 - 1 < 30) { diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index ee2ba76d1..bf86eef4d 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -37,11 +37,12 @@ #include "srslte/phy/utils/vector.h" #include "srslte/phy/sync/cfo.h" -#define MEANPEAK_EMA_ALPHA 0.1 -#define CFO_EMA_ALPHA 0.1 -#define CP_EMA_ALPHA 0.1 +#define CFO_EMA_ALPHA 0.1 +#define CP_EMA_ALPHA 0.1 -#define DEFAULT_CFO_TOL 50.0 // Hz +#define DEFAULT_CFO_TOL 0.0 // Hz + +#define MAX_CFO_PSS_OFFSET 7000 static bool fft_size_isvalid(uint32_t fft_size) { if (fft_size >= SRSLTE_SYNC_FFT_SZ_MIN && fft_size <= SRSLTE_SYNC_FFT_SZ_MAX && (fft_size%64) == 0) { @@ -51,47 +52,48 @@ static bool fft_size_isvalid(uint32_t fft_size) { } } - - int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size) { return srslte_sync_init_decim(q, frame_size, max_offset, fft_size, 1); } -int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size, int decimate) { +int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size, int decimate) +{ int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && - frame_size <= 307200 && fft_size_isvalid(fft_size)) { ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_sync_t)); - q->detect_cp = true; - q->sss_en = true; - q->mean_cfo = 0; - q->mean_cfo2 = 0; - q->N_id_2 = 1000; + + q->N_id_2 = 1000; q->N_id_1 = 1000; - q->cfo_i = 0; - q->find_cfo_i = false; - q->find_cfo_i_initiated = false; + q->cfo_ema_alpha = CFO_EMA_ALPHA; + q->sss_alg = SSS_FULL; + + q->detect_cp = true; + q->sss_en = true; + q->cfo_pss_enable = false; + q->cfo_cp_enable = false; + q->cfo_i_initiated = false; + q->pss_filtering_enabled = false; + + q->cfo_cp_nsymbols = 3; q->fft_size = fft_size; q->frame_size = frame_size; q->max_offset = max_offset; - q->sss_alg = SSS_FULL; q->max_frame_size = frame_size; - q->mean_cfo_isunset = true; - q->mean_cfo2_isunset = true; - q->enable_cfo_corr = true; - if (srslte_cfo_init(&q->cfocorr, q->frame_size)) { + srslte_sync_cfo_reset(q); + + if (srslte_cfo_init(&q->cfo_corr_frame, q->frame_size)) { fprintf(stderr, "Error initiating CFO\n"); goto clean_exit; } - if (srslte_cfo_init(&q->cfocorr2, q->frame_size)) { + if (srslte_cfo_init(&q->cfo_corr_symbol, q->fft_size)) { fprintf(stderr, "Error initiating CFO\n"); goto clean_exit; } @@ -119,11 +121,11 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o decimate = 1; } - if (srslte_pss_synch_init_fft_offset_decim(&q->pss, max_offset, fft_size, 0, decimate)) { + if (srslte_pss_init_fft_offset_decim(&q->pss, max_offset, fft_size, 0, decimate)) { fprintf(stderr, "Error initializing PSS object\n"); goto clean_exit; } - if (srslte_sss_synch_init(&q->sss, fft_size)) { + if (srslte_sss_init(&q->sss, fft_size)) { fprintf(stderr, "Error initializing SSS object\n"); goto clean_exit; } @@ -147,18 +149,23 @@ clean_exit: return ret; } -void srslte_sync_free(srslte_sync_t *q) { +void srslte_sync_free(srslte_sync_t *q) +{ if (q) { - srslte_pss_synch_free(&q->pss); - srslte_sss_synch_free(&q->sss); - srslte_cfo_free(&q->cfocorr); - srslte_cfo_free(&q->cfocorr2); + + srslte_pss_free(&q->pss); + srslte_sss_free(&q->sss); + srslte_cfo_free(&q->cfo_corr_frame); + srslte_cfo_free(&q->cfo_corr_symbol); srslte_cp_synch_free(&q->cp_synch); - for (int i=0;i<2;i++) { - if (q->cfo_i_corr[i]) { - free(q->cfo_i_corr[i]); + + if (q->cfo_i_initiated) { + for (int i=0;i<2;i++) { + if (q->cfo_i_corr[i]) { + free(q->cfo_i_corr[i]); + } + srslte_pss_free(&q->pss_i[i]); } - srslte_pss_synch_free(&q->pss_i[i]); } if (q->temp) { free(q->temp); @@ -174,53 +181,51 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse frame_size <= 307200 && fft_size_isvalid(fft_size)) { - ret = SRSLTE_ERROR; - if (frame_size > q->max_frame_size) { fprintf(stderr, "Error in sync_resize(): frame_size must be lower than initialized\n"); return SRSLTE_ERROR; } - q->detect_cp = true; - q->sss_en = true; - q->mean_cfo = 0; - q->mean_cfo2 = 0; - q->N_id_2 = 1000; - q->N_id_1 = 1000; - q->cfo_i = 0; - q->find_cfo_i = false; - q->find_cfo_i_initiated = false; - q->cfo_ema_alpha = CFO_EMA_ALPHA; - q->fft_size = fft_size; + + q->fft_size = fft_size; q->frame_size = frame_size; q->max_offset = max_offset; - q->sss_alg = SSS_FULL; - q->enable_cfo_corr = true; - - if (srslte_pss_synch_resize(&q->pss, max_offset, fft_size, 0)) { + if (srslte_pss_resize(&q->pss, q->max_offset, q->fft_size, 0)) { fprintf(stderr, "Error resizing PSS object\n"); return SRSLTE_ERROR; } - if (srslte_sss_synch_resize(&q->sss, fft_size)) { + if (srslte_sss_resize(&q->sss, q->fft_size)) { fprintf(stderr, "Error resizing SSS object\n"); return SRSLTE_ERROR; } - if (srslte_cp_synch_resize(&q->cp_synch, fft_size)) { + if (srslte_cp_synch_resize(&q->cp_synch, q->fft_size)) { fprintf(stderr, "Error resizing CFO\n"); return SRSLTE_ERROR; } - if (srslte_cfo_resize(&q->cfocorr, q->frame_size)) { + if (srslte_cfo_resize(&q->cfo_corr_frame, q->frame_size)) { fprintf(stderr, "Error resizing CFO\n"); return SRSLTE_ERROR; } - if (srslte_cfo_resize(&q->cfocorr2, q->frame_size)) { + if (srslte_cfo_resize(&q->cfo_corr_symbol, q->fft_size)) { fprintf(stderr, "Error resizing CFO\n"); return SRSLTE_ERROR; } + if (q->cfo_i_initiated) { + for (int i=0;i<2;i++) { + int offset=(i==0)?-1:1; + if (srslte_pss_resize(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { + fprintf(stderr, "Error initializing PSS object\n"); + } + for (int t=0;tframe_size;t++) { + q->cfo_i_corr[i][t] = cexpf(-2*_Complex_I*M_PI*offset*(float) t/q->fft_size); + } + } + } + // Update CFO tolerance srslte_sync_set_cfo_tol(q, q->current_cfo_tol); @@ -236,30 +241,14 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse void srslte_sync_set_cfo_tol(srslte_sync_t *q, float tol) { q->current_cfo_tol = tol; - srslte_cfo_set_tol(&q->cfocorr, tol/(15000.0*q->fft_size)); - srslte_cfo_set_tol(&q->cfocorr2, tol/(15000.0*q->fft_size)); + srslte_cfo_set_tol(&q->cfo_corr_frame, tol/(15000.0*q->fft_size)); + srslte_cfo_set_tol(&q->cfo_corr_symbol, tol/(15000.0*q->fft_size)); } void srslte_sync_set_threshold(srslte_sync_t *q, float threshold) { q->threshold = threshold; } -void srslte_sync_cfo_i_detec_en(srslte_sync_t *q, bool enabled) { - q->find_cfo_i = enabled; - if (enabled && !q->find_cfo_i_initiated) { - for (int i=0;i<2;i++) { - int offset=(i==0)?-1:1; - if (srslte_pss_synch_init_fft_offset(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { - fprintf(stderr, "Error initializing PSS object\n"); - } - for (int t=0;tframe_size;t++) { - q->cfo_i_corr[i][t] = cexpf(-2*_Complex_I*M_PI*offset*(float) t/q->fft_size); - } - } - q->find_cfo_i_initiated = true; - } -} - void srslte_sync_sss_en(srslte_sync_t *q, bool enabled) { q->sss_en = enabled; } @@ -291,32 +280,66 @@ uint32_t srslte_sync_get_sf_idx(srslte_sync_t *q) { } float srslte_sync_get_cfo(srslte_sync_t *q) { - return q->mean_cfo2 + q->cfo_i; + return q->cfo_cp_mean + q->cfo_pss_mean + q->cfo_i_value; } -void srslte_sync_set_cfo(srslte_sync_t *q, float cfo) { - q->mean_cfo = cfo; - q->mean_cfo2 = cfo; - q->mean_cfo2_isunset = false; - q->mean_cfo_isunset = false; +void srslte_sync_cfo_reset(srslte_sync_t *q) +{ + q->cfo_cp_mean = 0; + q->cfo_cp_is_set = false; + q->cfo_pss_mean = 0; + q->cfo_pss_is_set = false; } -void srslte_sync_set_cfo_i(srslte_sync_t *q, int cfo_i) { - q->cfo_i = cfo_i; +void srslte_sync_copy_cfo(srslte_sync_t *q, srslte_sync_t *src_obj) { + q->cfo_cp_mean = src_obj->cfo_cp_mean; + q->cfo_pss_mean = src_obj->cfo_pss_mean; + q->cfo_i_value = src_obj->cfo_i_value; + q->cfo_cp_is_set = false; + q->cfo_pss_is_set = false; } -void srslte_sync_set_cfo_enable(srslte_sync_t *q, bool enable) { - q->enable_cfo_corr = enable; +void srslte_sync_set_cfo_i_enable(srslte_sync_t *q, bool enable) { + q->cfo_i_enable = enable; + if (q->cfo_i_enable && !q->cfo_i_initiated) { + for (int i=0;i<2;i++) { + int offset=(i==0)?-1:1; + if (srslte_pss_init_fft_offset(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { + fprintf(stderr, "Error initializing PSS object\n"); + } + for (int t=0;tframe_size;t++) { + q->cfo_i_corr[i][t] = cexpf(-2*_Complex_I*M_PI*offset*(float) t/q->fft_size); + } + } + q->cfo_i_initiated = true; + } +} + +void srslte_sync_set_sss_eq_enable(srslte_sync_t *q, bool enable) { + q->sss_channel_equalize = enable; + if (enable) { + q->pss_filtering_enabled = true; + q->pss.chest_on_filter = true; + } +} + +void srslte_sync_set_pss_filt_enable(srslte_sync_t *q, bool enable) { + q->pss_filtering_enabled = enable; +} + +void srslte_sync_set_cfo_cp_enable(srslte_sync_t *q, bool enable, uint32_t nof_symbols) { + q->cfo_cp_enable = enable; + q->cfo_cp_nsymbols = nof_symbols; +} + +void srslte_sync_set_cfo_pss_enable(srslte_sync_t *q, bool enable) { + q->cfo_pss_enable = enable; } void srslte_sync_set_cfo_ema_alpha(srslte_sync_t *q, float alpha) { q->cfo_ema_alpha = alpha; } -float srslte_sync_get_last_peak_value(srslte_sync_t *q) { - return q->peak_value; -} - float srslte_sync_get_peak_value(srslte_sync_t *q) { return q->peak_value; } @@ -325,18 +348,17 @@ void srslte_sync_cp_en(srslte_sync_t *q, bool enabled) { q->detect_cp = enabled; } -bool srslte_sync_sss_is_en(srslte_sync_t *q) { - return q->sss_en; +void srslte_sync_set_em_alpha(srslte_sync_t *q, float alpha) +{ + srslte_pss_set_ema_alpha(&q->pss, alpha); } -void srslte_sync_set_em_alpha(srslte_sync_t *q, float alpha) { - srslte_pss_synch_set_ema_alpha(&q->pss, alpha); -} - -srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q) { +srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q) +{ return q->cp; } -void srslte_sync_set_cp(srslte_sync_t *q, srslte_cp_t cp) { +void srslte_sync_set_cp(srslte_sync_t *q, srslte_cp_t cp) +{ q->cp = cp; q->cp_len = SRSLTE_CP_ISNORM(q->cp)?SRSLTE_CP_LEN_NORM(1,q->fft_size):SRSLTE_CP_LEN_EXT(q->fft_size); if (q->frame_size < q->fft_size) { @@ -346,7 +368,8 @@ void srslte_sync_set_cp(srslte_sync_t *q, srslte_cp_t cp) { } } -void srslte_sync_set_sss_algorithm(srslte_sync_t *q, sss_alg_t alg) { +void srslte_sync_set_sss_algorithm(srslte_sync_t *q, sss_alg_t alg) +{ q->sss_alg = alg; } @@ -354,7 +377,7 @@ void srslte_sync_set_sss_algorithm(srslte_sync_t *q, sss_alg_t alg) { * "SSS Detection Method for Initial Cell Search in 3GPP LTE FDD/TDD Dual Mode Receiver" * by Jung-In Kim et al. */ -srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, cf_t *input, uint32_t peak_pos) +srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, const cf_t *input, uint32_t peak_pos) { float R_norm=0, R_ext=0, C_norm=0, C_ext=0; float M_norm=0, M_ext=0; @@ -370,8 +393,8 @@ srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, cf_t *input, uint32_t peak_p if (nof_symbols > 0) { - cf_t *input_cp_norm = &input[peak_pos-nof_symbols*(q->fft_size+cp_norm_len)]; - cf_t *input_cp_ext = &input[peak_pos-nof_symbols*(q->fft_size+cp_ext_len)]; + const cf_t *input_cp_norm = &input[peak_pos-nof_symbols*(q->fft_size+cp_norm_len)]; + const cf_t *input_cp_ext = &input[peak_pos-nof_symbols*(q->fft_size+cp_ext_len)]; for (int i=0;ifft_size], input_cp_norm, cp_norm_len)); @@ -414,33 +437,26 @@ srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, cf_t *input, uint32_t peak_p /* Returns 1 if the SSS is found, 0 if not and -1 if there is not enough space * to correlate */ -int sync_sss(srslte_sync_t *q, cf_t *input, uint32_t peak_pos, srslte_cp_t cp) { - int sss_idx, ret; +int sync_sss_symbol(srslte_sync_t *q, const cf_t *input) +{ + int ret; - srslte_sss_synch_set_N_id_2(&q->sss, q->N_id_2); + srslte_sss_set_N_id_2(&q->sss, q->N_id_2); - /* Make sure we have enough room to find SSS sequence */ - sss_idx = (int) peak_pos-2*q->fft_size-SRSLTE_CP_LEN(q->fft_size, (SRSLTE_CP_ISNORM(q->cp)?SRSLTE_CP_NORM_LEN:SRSLTE_CP_EXT_LEN)); - if (sss_idx < 0) { - DEBUG("Not enough room to decode SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx, peak_pos); - return SRSLTE_ERROR; - } - DEBUG("Searching SSS around sss_idx: %d, peak_pos: %d\n", sss_idx, peak_pos); - switch(q->sss_alg) { case SSS_DIFF: - srslte_sss_synch_m0m1_diff(&q->sss, &input[sss_idx], &q->m0, &q->m0_value, &q->m1, &q->m1_value); + srslte_sss_m0m1_diff(&q->sss, input, &q->m0, &q->m0_value, &q->m1, &q->m1_value); break; case SSS_PARTIAL_3: - srslte_sss_synch_m0m1_partial(&q->sss, &input[sss_idx], 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); + srslte_sss_m0m1_partial(&q->sss, input, 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); break; case SSS_FULL: - srslte_sss_synch_m0m1_partial(&q->sss, &input[sss_idx], 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); + srslte_sss_m0m1_partial(&q->sss, input, 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); break; } - q->sf_idx = srslte_sss_synch_subframe(q->m0, q->m1); - ret = srslte_sss_synch_N_id_1(&q->sss, q->m0, q->m1); + q->sf_idx = srslte_sss_subframe(q->m0, q->m1); + ret = srslte_sss_N_id_1(&q->sss, q->m0, q->m1); if (ret >= 0) { q->N_id_1 = (uint32_t) ret; DEBUG("SSS detected N_id_1=%d, sf_idx=%d, %s CP\n", @@ -452,27 +468,33 @@ int sync_sss(srslte_sync_t *q, cf_t *input, uint32_t peak_pos, srslte_cp_t cp) { } } -srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q) { - srslte_pss_synch_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; - return pss_obj[q->cfo_i+1]; +srslte_pss_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q) +{ + srslte_pss_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; + return pss_obj[q->cfo_i_value+1]; } -static float cfo_estimate(srslte_sync_t *q, cf_t *input) { +static float cfo_cp_estimate(srslte_sync_t *q, const cf_t *input) +{ uint32_t cp_offset = 0; - cp_offset = srslte_cp_synch(&q->cp_synch, input, q->max_offset, 2, SRSLTE_CP_LEN_NORM(1,q->fft_size)); + cp_offset = srslte_cp_synch(&q->cp_synch, input, q->max_offset, q->cfo_cp_nsymbols, SRSLTE_CP_LEN_NORM(1,q->fft_size)); cf_t cp_corr_max = srslte_cp_synch_corr_output(&q->cp_synch, cp_offset); float cfo = -carg(cp_corr_max) / M_PI / 2; return cfo; } -static int cfo_i_estimate(srslte_sync_t *q, cf_t *input, int find_offset, int *peak_pos) { +static int cfo_i_estimate(srslte_sync_t *q, const cf_t *input, int find_offset, int *peak_pos, int *cfo_i) +{ float peak_value; float max_peak_value = -99; int max_cfo_i = 0; - srslte_pss_synch_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; + srslte_pss_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; for (int cfo_i=0;cfo_i<3;cfo_i++) { - srslte_pss_synch_set_N_id_2(pss_obj[cfo_i], q->N_id_2); - int p = srslte_pss_synch_find_pss(pss_obj[cfo_i], &input[find_offset], &peak_value); + srslte_pss_set_N_id_2(pss_obj[cfo_i], q->N_id_2); + int p = srslte_pss_find_pss(pss_obj[cfo_i], &input[find_offset], &peak_value); + if (p < 0) { + return -1; + } if (peak_value > max_peak_value) { max_peak_value = peak_value; if (peak_pos) { @@ -481,125 +503,171 @@ static int cfo_i_estimate(srslte_sync_t *q, cf_t *input, int find_offset, int *p q->peak_value = peak_value; max_cfo_i = cfo_i-1; } - } - return max_cfo_i; -} - -float srslte_sync_cfo_estimate(srslte_sync_t *q, cf_t *input, int find_offset) { - float cfo_f = cfo_estimate(q, input); - - int cfo_i = 0; - if (q->find_cfo_i) { - cfo_i = cfo_i_estimate(q, input, find_offset, NULL); } - return (float) cfo_i + cfo_f; + if (cfo_i) { + *cfo_i = max_cfo_i; + } + return 0; } /** Finds the PSS sequence previously defined by a call to srslte_sync_set_N_id_2() - * around the position find_offset in the buffer input. + * around the position find_offset in the buffer input. + * * Returns 1 if the correlation peak exceeds the threshold set by srslte_sync_set_threshold() * or 0 otherwise. Returns a negative number on error (if N_id_2 has not been set) - * + * + * The input signal is not modified. Any CFO correction is done in internal buffers + * * The maximum of the correlation peak is always stored in *peak_position */ -srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_position) +srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uint32_t find_offset, uint32_t *peak_position) { - - srslte_sync_find_ret_t ret = SRSLTE_SYNC_ERROR; - + srslte_sync_find_ret_t ret = SRSLTE_SYNC_ERROR; + int peak_pos = 0; + if (!q) { return SRSLTE_ERROR_INVALID_INPUTS; } - if (input != NULL && + if (input != NULL && srslte_N_id_2_isvalid(q->N_id_2) && fft_size_isvalid(q->fft_size)) { - int peak_pos = 0; - - ret = SRSLTE_SUCCESS; - + if (peak_position) { *peak_position = 0; } - cf_t *input_cfo = input; + const cf_t *input_ptr = input; - if (q->enable_cfo_corr) { - float cfo = cfo_estimate(q, input); + /* First CFO estimation stage is integer. + * Finds max PSS correlation for shifted +1/0/-1 integer versions. + * This should only used once N_id_2 is set + */ + if (q->cfo_i_enable) { + if (cfo_i_estimate(q, input_ptr, find_offset, &peak_pos, &q->cfo_i_value) < 0) { + fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos); + return SRSLTE_ERROR; + } + // Correct it using precomputed signal and store in buffer (don't modify input signal) + if (q->cfo_i_value != 0) { + srslte_vec_prod_ccc((cf_t*) input_ptr, q->cfo_i_corr[q->cfo_i_value<0?0:1], q->temp, q->frame_size); + INFO("Compensating cfo_i=%d\n", q->cfo_i_value); + input_ptr = q->temp; + } + } - if (q->mean_cfo_isunset) { - q->mean_cfo = cfo; - q->mean_cfo_isunset = false; + /* Second stage is coarse fractional CFO estimation using CP. + * In case of multi-cell, this can lead to incorrect estimations if CFO from different cells is different + */ + if (q->cfo_cp_enable) { + float cfo_cp = cfo_cp_estimate(q, input_ptr); + + if (!q->cfo_cp_is_set) { + q->cfo_cp_mean = cfo_cp; + q->cfo_cp_is_set = true; } else { /* compute exponential moving average CFO */ - q->mean_cfo = SRSLTE_VEC_EMA(cfo, q->mean_cfo, q->cfo_ema_alpha); + q->cfo_cp_mean = SRSLTE_VEC_EMA(cfo_cp, q->cfo_cp_mean, q->cfo_ema_alpha); } + INFO("CP-CFO: estimated=%f, mean=%f\n", cfo_cp, q->cfo_cp_mean); + /* Correct CFO with the averaged CFO estimation */ - srslte_cfo_correct(&q->cfocorr2, input, q->temp, -q->mean_cfo / q->fft_size); - - input_cfo = q->temp; + srslte_cfo_correct(&q->cfo_corr_frame, input_ptr, q->temp, -q->cfo_cp_mean / q->fft_size); + input_ptr = q->temp; } - - /* If integer CFO is enabled, find max PSS correlation for shifted +1/0/-1 integer versions */ - if (q->find_cfo_i && q->enable_cfo_corr) { - q->cfo_i = cfo_i_estimate(q, input_cfo, find_offset, &peak_pos); - if (q->cfo_i != 0) { - srslte_vec_prod_ccc(input_cfo, q->cfo_i_corr[q->cfo_i<0?0:1], input_cfo, q->frame_size); - INFO("Compensating cfo_i=%d\n", q->cfo_i); - } - } else { - srslte_pss_synch_set_N_id_2(&q->pss, q->N_id_2); - peak_pos = srslte_pss_synch_find_pss(&q->pss, &input_cfo[find_offset], &q->peak_value); - // this compensates for the constant time shift caused by the low pass filter - if(q->decimate && peak_pos < 0) - { - peak_pos = 0 ;//peak_pos + q->decimate*(2);// replace 2 with q->filter_size -2; - } + + /* Find maximum of PSS correlation. If Integer CFO is enabled, correlation is already done + */ + if (!q->cfo_i_enable) { + srslte_pss_set_N_id_2(&q->pss, q->N_id_2); + peak_pos = srslte_pss_find_pss(&q->pss, &input_ptr[find_offset], q->threshold>0?&q->peak_value:NULL); if (peak_pos < 0) { fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos); - return SRSLTE_ERROR; - } + return SRSLTE_ERROR; + } } - + + INFO("PSS: id=%d, peak_pos=%d, peak_value=%f\n", q->N_id_2, peak_pos, q->peak_value); + + // Save peak position if (peak_position) { *peak_position = (uint32_t) peak_pos; } - - // Try to detect SSS - if (q->sss_en) { - // Set an invalid N_id_1 indicating SSS is yet to be detected - q->N_id_1 = 1000; - - if (sync_sss(q, input_cfo, find_offset + peak_pos, q->cp) < 0) { - DEBUG("No space for SSS processing. Frame starts at %d\n", peak_pos); - } + + // In case of decimation, this compensates for the constant time shift caused by the low pass filter + if(q->decimate && peak_pos < 0) { + peak_pos = 0 ;//peak_pos + q->decimate*(2);// replace 2 with q->filter_size -2; } - + /* If peak is over threshold, compute CFO and SSS */ - if (q->peak_value >= q->threshold) { - - if (q->detect_cp) { - if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { - srslte_sync_set_cp(q, srslte_sync_detect_cp(q, input_cfo, peak_pos + find_offset)); + if (q->peak_value >= q->threshold || q->threshold == 0) { + + if (q->cfo_pss_enable && peak_pos >= q->fft_size) { + + // Filter central bands before PSS-based CFO estimation + const cf_t *pss_ptr = &input_ptr[find_offset + peak_pos - q->fft_size]; + if (q->pss_filtering_enabled) { + srslte_pss_filter(&q->pss, pss_ptr, q->pss_filt); + pss_ptr = q->pss_filt; + } + + // PSS-based CFO estimation + q->cfo_pss = srslte_pss_cfo_compute(&q->pss, pss_ptr); + if (!q->cfo_pss_is_set) { + q->cfo_pss_mean = q->cfo_pss; + q->cfo_pss_is_set = true; + } else if (15000*fabsf(q->cfo_pss) < MAX_CFO_PSS_OFFSET) { + q->cfo_pss_mean = SRSLTE_VEC_EMA(q->cfo_pss, q->cfo_pss_mean, q->cfo_ema_alpha); + } + + INFO("PSS-CFO: filter=%s, estimated=%f, mean=%f\n", + q->pss_filtering_enabled?"yes":"no", q->cfo_pss, q->cfo_pss_mean); + + } + + // If there is enough space for CP and SSS estimation + if (peak_pos + find_offset >= 2 * (q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { + + // If SSS search is enabled, correlate SSS sequence + if (q->sss_en) { + + // Set an invalid N_id_1 indicating SSS is yet to be detected + q->N_id_1 = 1000; + + int sss_idx = find_offset + peak_pos - 2 * q->fft_size - + SRSLTE_CP_LEN(q->fft_size, (SRSLTE_CP_ISNORM(q->cp) ? SRSLTE_CP_NORM_LEN : SRSLTE_CP_EXT_LEN)); + + const cf_t *sss_ptr = &input_ptr[sss_idx]; + + // Correct CFO if detected in PSS + if (q->cfo_pss_enable) { + srslte_cfo_correct(&q->cfo_corr_symbol, sss_ptr, q->sss_filt, -q->cfo_pss_mean / q->fft_size); + // Equalize channel if estimated in PSS + if (q->sss_channel_equalize && q->pss.chest_on_filter && q->pss_filtering_enabled) { + srslte_vec_prod_ccc(&q->sss_filt[q->fft_size/2-SRSLTE_PSS_LEN/2], q->pss.tmp_ce, + &q->sss_filt[q->fft_size/2-SRSLTE_PSS_LEN/2], SRSLTE_PSS_LEN); + } + sss_ptr = q->sss_filt; + } + + if (sync_sss_symbol(q, sss_ptr) < 0) { + fprintf(stderr, "Error correlating SSS\n"); + return -1; + } + } + + // Detect CP length + if (q->detect_cp) { + srslte_sync_set_cp(q, srslte_sync_detect_cp(q, input_ptr, peak_pos + find_offset)); } else { DEBUG("Not enough room to detect CP length. Peak position: %d\n", peak_pos); } - } - - if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { - float cfo2 = srslte_pss_synch_cfo_compute(&q->pss, &input[find_offset + peak_pos - q->fft_size]); - if (q->mean_cfo2_isunset) { - q->mean_cfo2 = cfo2; - q->mean_cfo2_isunset = true; - } else { - q->mean_cfo2 = SRSLTE_VEC_EMA(cfo2, q->mean_cfo2, q->cfo_ema_alpha); - } ret = SRSLTE_SYNC_FOUND; } else { - ret = SRSLTE_SYNC_FOUND_NOSPACE; + ret = SRSLTE_SYNC_FOUND_NOSPACE; } } else { ret = SRSLTE_SYNC_NOFOUND; @@ -607,7 +675,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t DEBUG("SYNC ret=%d N_id_2=%d find_offset=%d frame_len=%d, pos=%d peak=%.2f threshold=%.2f sf_idx=%d, CFO=%.3f kHz\n", ret, q->N_id_2, find_offset, q->frame_size, peak_pos, q->peak_value, - q->threshold, q->sf_idx, 15*(q->cfo_i+q->mean_cfo)); + q->threshold, q->sf_idx, 15*(srslte_sync_get_cfo(q))); } else if (srslte_N_id_2_isvalid(q->N_id_2)) { fprintf(stderr, "Must call srslte_sync_set_N_id_2() first!\n"); @@ -619,5 +687,5 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t void srslte_sync_reset(srslte_sync_t *q) { q->M_ext_avg = 0; q->M_norm_avg = 0; - srslte_pss_synch_reset(&q->pss); + srslte_pss_reset(&q->pss); } diff --git a/lib/src/phy/sync/test/pss_file.c b/lib/src/phy/sync/test/pss_file.c index 7f70ad8ff..4087366ec 100644 --- a/lib/src/phy/sync/test/pss_file.c +++ b/lib/src/phy/sync/test/pss_file.c @@ -121,9 +121,9 @@ int main(int argc, char **argv) { srslte_filesource_t fsrc; cf_t *buffer; int frame_cnt, n; - srslte_pss_synch_t pss; + srslte_pss_t pss; srslte_cfo_t cfocorr, cfocorr64; - srslte_sss_synch_t sss; + srslte_sss_t sss; int32_t flen; int peak_idx, last_peak; float peak_value; @@ -152,12 +152,12 @@ int main(int argc, char **argv) { exit(-1); } - if (srslte_pss_synch_init_fft(&pss, flen, fft_size)) { + if (srslte_pss_init_fft(&pss, flen, fft_size)) { fprintf(stderr, "Error initiating PSS\n"); exit(-1); } - if (srslte_pss_synch_set_N_id_2(&pss, N_id_2_sync)) { + if (srslte_pss_set_N_id_2(&pss, N_id_2_sync)) { fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync); exit(-1); } @@ -165,12 +165,12 @@ int main(int argc, char **argv) { srslte_cfo_init(&cfocorr, flen); srslte_cfo_init(&cfocorr64, flen); - if (srslte_sss_synch_init(&sss, fft_size)) { + if (srslte_sss_init(&sss, fft_size)) { fprintf(stderr, "Error initializing SSS object\n"); return SRSLTE_ERROR; } - srslte_sss_synch_set_N_id_2(&sss, N_id_2); + srslte_sss_set_N_id_2(&sss, N_id_2); printf("Opening file...\n"); if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { @@ -210,7 +210,7 @@ int main(int argc, char **argv) { break; } - peak_idx = srslte_pss_synch_find_pss(&pss, buffer, &peak_value); + peak_idx = srslte_pss_find_pss(&pss, buffer, &peak_value); if (peak_idx < 0) { fprintf(stderr, "Error finding PSS peak\n"); exit(-1); @@ -224,14 +224,14 @@ int main(int argc, char **argv) { if (peak_idx >= fft_size) { // Estimate CFO - cfo = srslte_pss_synch_cfo_compute(&pss, &buffer[peak_idx-fft_size]); + cfo = srslte_pss_cfo_compute(&pss, &buffer[peak_idx-fft_size]); mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, frame_cnt); // Correct CFO srslte_cfo_correct(&cfocorr, buffer, buffer, -mean_cfo / fft_size); // Estimate channel - if (srslte_pss_synch_chest(&pss, &buffer[peak_idx-fft_size], ce)) { + if (srslte_pss_chest(&pss, &buffer[peak_idx-fft_size], ce)) { fprintf(stderr, "Error computing channel estimation\n"); exit(-1); } @@ -239,22 +239,22 @@ int main(int argc, char **argv) { // Find SSS int sss_idx = peak_idx-2*fft_size-(SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN):SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN)); if (sss_idx >= 0 && sss_idx < flen-fft_size) { - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error2++; } - INFO("sf_idx = %d\n", srslte_sss_synch_subframe(m0, m1)); - INFO("Partial N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + INFO("sf_idx = %d\n", srslte_sss_subframe(m0, m1)); + INFO("Partial N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); + srslte_sss_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error3++; } - INFO("Diff N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + INFO("Diff N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); + srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error1++; } - INFO("Full N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); + INFO("Full N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); } // Estimate CP @@ -269,7 +269,7 @@ int main(int argc, char **argv) { INFO("No space for CFO computation. Frame starts at \n",peak_idx); } - if(srslte_sss_synch_subframe(m0,m1) == 0) + if(srslte_sss_subframe(m0,m1) == 0) { #ifndef DISABLE_GRAPHICS if (!disable_plots) @@ -317,7 +317,7 @@ int main(int argc, char **argv) { } - srslte_pss_synch_free(&pss); + srslte_pss_free(&pss); free(buffer); srslte_filesource_free(&fsrc); #ifndef DISABLE_GRAPHICS diff --git a/lib/src/phy/sync/test/pss_mex.c b/lib/src/phy/sync/test/pss_mex.c index 77922a020..59cc0a897 100644 --- a/lib/src/phy/sync/test/pss_mex.c +++ b/lib/src/phy/sync/test/pss_mex.c @@ -47,7 +47,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { srslte_cell_t cell; - srslte_pss_synch_t pss; + srslte_pss_t pss; cf_t *input_symbols; int frame_len; @@ -74,17 +74,17 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) frame_len = (int) mxGetScalar(prhs[NOF_INPUTS]); } - if (srslte_pss_synch_init_fft(&pss, frame_len, srslte_symbol_sz(cell.nof_prb))) { + if (srslte_pss_init_fft(&pss, frame_len, srslte_symbol_sz(cell.nof_prb))) { fprintf(stderr, "Error initiating PSS\n"); exit(-1); } - if (srslte_pss_synch_set_N_id_2(&pss, cell.id%3)) { + if (srslte_pss_set_N_id_2(&pss, cell.id%3)) { fprintf(stderr, "Error setting N_id_2=%d\n",cell.id%3); exit(-1); } - srslte_pss_synch_set_ema_alpha(&pss, 1.0); + srslte_pss_set_ema_alpha(&pss, 1.0); - int peak_idx = srslte_pss_synch_find_pss(&pss, input_symbols, NULL); + int peak_idx = srslte_pss_find_pss(&pss, input_symbols, NULL); if (nlhs >= 1) { plhs[0] = mxCreateDoubleScalar(peak_idx); @@ -93,7 +93,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mexutils_write_cf(pss.conv_output, &plhs[1], frame_len, 1); } - srslte_pss_synch_free(&pss); + srslte_pss_free(&pss); free(input_symbols); return; diff --git a/lib/src/phy/sync/test/pss_usrp.c b/lib/src/phy/sync/test/pss_usrp.c index 8e8377b83..70881f15b 100644 --- a/lib/src/phy/sync/test/pss_usrp.c +++ b/lib/src/phy/sync/test/pss_usrp.c @@ -125,9 +125,9 @@ int main(int argc, char **argv) { cf_t *buffer; int frame_cnt, n; srslte_rf_t rf; - srslte_pss_synch_t pss; + srslte_pss_t pss; srslte_cfo_t cfocorr, cfocorr64; - srslte_sss_synch_t sss; + srslte_sss_t sss; int32_t flen; int peak_idx, last_peak; float peak_value; @@ -176,12 +176,12 @@ int main(int argc, char **argv) { exit(-1); } - if (srslte_pss_synch_init_fft(&pss, flen, fft_size)) { + if (srslte_pss_init_fft(&pss, flen, fft_size)) { fprintf(stderr, "Error initiating PSS\n"); exit(-1); } - if (srslte_pss_synch_set_N_id_2(&pss, N_id_2_sync)) { + if (srslte_pss_set_N_id_2(&pss, N_id_2_sync)) { fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync); exit(-1); } @@ -189,16 +189,16 @@ int main(int argc, char **argv) { srslte_cfo_init(&cfocorr, flen); srslte_cfo_init(&cfocorr64, flen); - if (srslte_sss_synch_init(&sss, fft_size)) { + if (srslte_sss_init(&sss, fft_size)) { fprintf(stderr, "Error initializing SSS object\n"); exit(-1); } - srslte_sss_synch_set_N_id_2(&sss, N_id_2); + srslte_sss_set_N_id_2(&sss, N_id_2); printf("N_id_2: %d\n", N_id_2); - srslte_rf_start_rx_stream(&rf); + srslte_rf_start_rx_stream(&rf, false); printf("Frame length %d samples\n", flen); printf("PSS detection threshold: %.2f\n", threshold); @@ -221,7 +221,9 @@ int main(int argc, char **argv) { uint32_t max_peak = 0; uint32_t max_peak_ = 0; uint32_t min_peak = fft_size; - uint32_t min_peak_ = fft_size; + uint32_t min_peak_ = fft_size; + + pss.filter_pss_enable = true; while(frame_cnt < nof_frames || nof_frames == -1) { n = srslte_rf_recv(&rf, buffer, flen - peak_offset, 1); @@ -230,7 +232,7 @@ int main(int argc, char **argv) { exit(-1); } - peak_idx = srslte_pss_synch_find_pss(&pss, buffer, &peak_value); + peak_idx = srslte_pss_find_pss(&pss, buffer, &peak_value); if (peak_idx < 0) { fprintf(stderr, "Error finding PSS peak\n"); exit(-1); @@ -243,36 +245,40 @@ int main(int argc, char **argv) { if (peak_idx >= fft_size) { - // Estimate CFO - cfo = srslte_pss_synch_cfo_compute(&pss, &buffer[peak_idx-fft_size]); + // Estimate CFO + cfo = srslte_pss_cfo_compute(&pss, &buffer[peak_idx-fft_size]); mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, frame_cnt); // Correct CFO srslte_cfo_correct(&cfocorr, buffer, buffer, -mean_cfo / fft_size); // Estimate channel - if (srslte_pss_synch_chest(&pss, &buffer[peak_idx-fft_size], ce)) { + if (srslte_pss_chest(&pss, &buffer[peak_idx-fft_size], ce)) { fprintf(stderr, "Error computing channel estimation\n"); exit(-1); } - - // Find SSS + + // Find SSS int sss_idx = peak_idx-2*fft_size-(SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN):SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN)); if (sss_idx >= 0 && sss_idx < flen-fft_size) { - INFO("Full N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, ce, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + + // Filter SSS + srslte_pss_filter(&pss, &buffer[sss_idx], &buffer[sss_idx]); + + INFO("Full N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); + srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, ce, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error2++; } - INFO("Partial N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); - srslte_sss_synch_m0m1_diff_coh(&sss, &buffer[sss_idx], ce, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + INFO("Partial N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); + srslte_sss_m0m1_diff_coh(&sss, &buffer[sss_idx], ce, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error3++; } - INFO("Diff N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); + INFO("Diff N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1)); } - srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); - if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { + srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); + if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) { sss_error1++; } @@ -288,7 +294,7 @@ int main(int argc, char **argv) { INFO("No space for CFO computation. Frame starts at \n",peak_idx); } - if(srslte_sss_synch_subframe(m0,m1) == 0) + if(srslte_sss_subframe(m0,m1) == 0) { #ifndef DISABLE_GRAPHICS if (!disable_plots) @@ -301,12 +307,12 @@ int main(int argc, char **argv) { } printf("[%5d]: Pos: %5d (%d-%d), PSR: %4.1f (~%4.1f) Pdet: %4.2f, " - "FA: %4.2f, CFO: %+4.1f kHz, SFO: %+.2f Hz SSSmiss: %4.2f/%4.2f/%4.2f CPNorm: %.0f%%\r", + "FA: %4.2f, CFO: %+7.1f Hz, SFO: %+.2f Hz SSSmiss: %4.2f/%4.2f/%4.2f CPNorm: %.0f%%\r", frame_cnt, peak_idx, min_peak_, max_peak_, peak_value, mean_peak, (float) nof_det/frame_cnt, - (float) nof_nopeakdet/frame_cnt, mean_cfo*15, sfo, + (float) nof_nopeakdet/frame_cnt, mean_cfo*15000, sfo, (float) sss_error1/nof_det,(float) sss_error2/nof_det,(float) sss_error3/nof_det, (float) cp_is_norm/nof_det * 100); @@ -352,8 +358,8 @@ int main(int argc, char **argv) { } - srslte_sss_synch_free(&sss); - srslte_pss_synch_free(&pss); + srslte_sss_free(&sss); + srslte_pss_free(&pss); free(buffer); srslte_rf_close(&rf); diff --git a/lib/src/phy/sync/test/sss_mex.c b/lib/src/phy/sync/test/sss_mex.c index 4c92d81ec..56165fe3d 100644 --- a/lib/src/phy/sync/test/sss_mex.c +++ b/lib/src/phy/sync/test/sss_mex.c @@ -50,7 +50,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { srslte_cell_t cell; - srslte_sss_synch_t sss; + srslte_sss_t sss; cf_t *input_symbols; int frame_len; uint32_t m0, m1; @@ -80,12 +80,12 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) return; } - if (srslte_sss_synch_init(&sss, srslte_symbol_sz(cell.nof_prb))) { + if (srslte_sss_init(&sss, srslte_symbol_sz(cell.nof_prb))) { mexErrMsgTxt("Error initializing SSS object\n"); return; } - srslte_sss_synch_set_N_id_2(&sss, cell.id%3); + srslte_sss_set_N_id_2(&sss, cell.id%3); // Find SSS uint32_t sss_idx = SRSLTE_SLOT_IDX_CPNORM(5,srslte_symbol_sz(cell.nof_prb)); @@ -95,23 +95,23 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } //mexPrintf("SSS begins at %d/%d. Running algorithm %s\n", sss_idx, frame_len, alg); if (!strcmp(alg, "partial")) { - srslte_sss_synch_m0m1_partial(&sss, &input_symbols[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); + srslte_sss_m0m1_partial(&sss, &input_symbols[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); } else if (!strcmp(alg, "diff")) { - srslte_sss_synch_m0m1_diff(&sss, &input_symbols[sss_idx], &m0, &m0_value, &m1, &m1_value); + srslte_sss_m0m1_diff(&sss, &input_symbols[sss_idx], &m0, &m0_value, &m1, &m1_value); } else if (!strcmp(alg, "full")) { - srslte_sss_synch_m0m1_partial(&sss, &input_symbols[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); + srslte_sss_m0m1_partial(&sss, &input_symbols[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); } else { mexErrMsgTxt("Unsupported algorithm type\n"); return; } - //mexPrintf("m0: %d, m1: %d, N_id_1: %d\n", m0, m1, srslte_sss_synch_N_id_1(&sss, m0, m1)); + //mexPrintf("m0: %d, m1: %d, N_id_1: %d\n", m0, m1, srslte_sss_N_id_1(&sss, m0, m1)); if (nlhs >= 1) { - plhs[0] = mxCreateDoubleScalar(srslte_sss_synch_N_id_1(&sss, m0, m1)); + plhs[0] = mxCreateDoubleScalar(srslte_sss_N_id_1(&sss, m0, m1)); } if (nlhs >= 2) { - plhs[1] = mxCreateDoubleScalar(srslte_sss_synch_subframe(m0, m1)); + plhs[1] = mxCreateDoubleScalar(srslte_sss_subframe(m0, m1)); } if (nlhs >= 3) { mexutils_write_f(sss.corr_output_m0, &plhs[2], SRSLTE_SSS_N, 1); @@ -119,7 +119,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) if (nlhs >= 4) { mexutils_write_f(sss.corr_output_m1, &plhs[3], SRSLTE_SSS_N, 1); } - srslte_sss_synch_free(&sss); + srslte_sss_free(&sss); free(input_symbols); return; diff --git a/lib/src/phy/sync/test/sync_test.c b/lib/src/phy/sync/test/sync_test.c index 8715b316e..9016c1baa 100644 --- a/lib/src/phy/sync/test/sync_test.c +++ b/lib/src/phy/sync/test/sync_test.c @@ -108,8 +108,8 @@ int main(int argc, char **argv) { perror("malloc"); exit(-1); } - - if (srslte_ofdm_tx_init(&ifft, cp, nof_prb)) { + + if (srslte_ofdm_tx_init(&ifft, cp, buffer, fft_buffer, nof_prb)) { fprintf(stderr, "Error creating iFFT object\n"); exit(-1); } @@ -124,8 +124,7 @@ int main(int argc, char **argv) { /* Set a very high threshold to make sure the correlation is ok */ srslte_sync_set_threshold(&syncobj, 5.0); srslte_sync_set_sss_algorithm(&syncobj, SSS_PARTIAL_3); - srslte_sync_set_cfo_enable(&syncobj, false); - + if (cell_id == -1) { cid = 0; max_cid = 49; @@ -150,8 +149,14 @@ int main(int argc, char **argv) { /* Transform to OFDM symbols */ memset(fft_buffer, 0, sizeof(cf_t) * FLEN); - srslte_ofdm_tx_sf(&ifft, buffer, &fft_buffer[offset]); + srslte_ofdm_tx_sf(&ifft); + /* Apply sample offset */ + for (int i = 0; i < FLEN; i++) { + fft_buffer[FLEN - i - 1 + offset] = fft_buffer[FLEN - i - 1]; + } + bzero(fft_buffer, sizeof(cf_t) * offset); + if (srslte_sync_find(&syncobj, fft_buffer, 0, &find_idx) < 0) { fprintf(stderr, "Error running srslte_sync_find\n"); exit(-1); diff --git a/lib/src/phy/ue/ue_cell_search.c b/lib/src/phy/ue/ue_cell_search.c index dc35fb48c..133aad144 100644 --- a/lib/src/phy/ue/ue_cell_search.c +++ b/lib/src/phy/ue/ue_cell_search.c @@ -116,7 +116,7 @@ int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t * q, uint32_t max_fra goto clean_exit; } if (srslte_ue_sync_set_cell(&q->ue_sync, cell)) { - fprintf(stderr, "Error initiating ue_sync\n"); + fprintf(stderr, "Error setting cell in ue_sync\n"); goto clean_exit; } @@ -292,6 +292,8 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q, srslte_ue_sync_set_N_id_2(&q->ue_sync, N_id_2); srslte_ue_sync_reset(&q->ue_sync); + srslte_ue_sync_cfo_reset(&q->ue_sync); + do { ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index c4e2d3f6c..348d0bdb6 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -53,6 +53,7 @@ static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FO const uint32_t nof_common_formats = 2; int srslte_ue_dl_init(srslte_ue_dl_t *q, + cf_t *in_buffer[SRSLTE_MAX_PORTS], uint32_t max_prb, uint32_t nof_rx_antennas) { @@ -73,12 +74,35 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, q->sample_offset = 0; q->nof_rx_antennas = nof_rx_antennas; - if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, max_prb)) { - fprintf(stderr, "Error initiating FFT\n"); - goto clean_exit; + for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { + q->sf_symbols_m[j] = srslte_vec_malloc(MAX_SFLEN_RE * sizeof(cf_t)); + if (!q->sf_symbols_m[j]) { + perror("malloc"); + goto clean_exit; + } + for (uint32_t i=0;ice_m[i][j] = srslte_vec_malloc(MAX_SFLEN_RE * sizeof(cf_t)); + if (!q->ce_m[i][j]) { + perror("malloc"); + goto clean_exit; + } + bzero(q->ce_m[i][j], MAX_SFLEN_RE * sizeof(cf_t)); + } } - - if (srslte_ofdm_rx_init_mbsfn(&q->fft_mbsfn, SRSLTE_CP_EXT, max_prb)) { + + q->sf_symbols = q->sf_symbols_m[0]; + for (int i=0;ice[i] = q->ce_m[i][0]; + } + + for (int i = 0; i < nof_rx_antennas; i++) { + if (srslte_ofdm_rx_init(&q->fft[i], SRSLTE_CP_NORM, in_buffer[i], q->sf_symbols_m[i], max_prb)) { + fprintf(stderr, "Error initiating FFT\n"); + goto clean_exit; + } + } + + if (srslte_ofdm_rx_init_mbsfn(&q->fft_mbsfn, SRSLTE_CP_EXT, in_buffer[0], q->sf_symbols_m[0], max_prb)) { fprintf(stderr, "Error initiating FFT for MBSFN subframes \n"); goto clean_exit; } @@ -127,28 +151,7 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, fprintf(stderr, "Error initiating SFO correct\n"); goto clean_exit; } - srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft.symbol_sz); - - for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { - q->sf_symbols_m[j] = srslte_vec_malloc(MAX_SFLEN_RE * sizeof(cf_t)); - if (!q->sf_symbols_m[j]) { - perror("malloc"); - goto clean_exit; - } - for (uint32_t i=0;ice_m[i][j] = srslte_vec_malloc(MAX_SFLEN_RE * sizeof(cf_t)); - if (!q->ce_m[i][j]) { - perror("malloc"); - goto clean_exit; - } - bzero(q->ce_m[i][j], MAX_SFLEN_RE * sizeof(cf_t)); - } - } - - q->sf_symbols = q->sf_symbols_m[0]; - for (int i=0;ice[i] = q->ce_m[i][0]; - } + srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft[0].symbol_sz); ret = SRSLTE_SUCCESS; } else { @@ -164,7 +167,9 @@ clean_exit: void srslte_ue_dl_free(srslte_ue_dl_t *q) { if (q) { - srslte_ofdm_rx_free(&q->fft); + for (int port = 0; port < SRSLTE_MAX_PORTS; port++) { + srslte_ofdm_rx_free(&q->fft[port]); + } srslte_ofdm_rx_free(&q->fft_mbsfn); srslte_chest_dl_free(&q->chest); srslte_regs_free(&q->regs); @@ -219,10 +224,12 @@ int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell) fprintf(stderr, "Error resizing SFO correct\n"); return SRSLTE_ERROR; } - srslte_cfo_set_tol(&q->sfo_correct, 1e-5/q->fft.symbol_sz); - if (srslte_ofdm_rx_set_prb(&q->fft, q->cell.cp, q->cell.nof_prb)) { - fprintf(stderr, "Error resizing FFT\n"); - return SRSLTE_ERROR; + srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft[0].symbol_sz); + for (int port = 0; port < q->nof_rx_antennas; port++) { + if (srslte_ofdm_rx_set_prb(&q->fft[port], q->cell.cp, q->cell.nof_prb)) { + fprintf(stderr, "Error resizing FFT\n"); + return SRSLTE_ERROR; + } } if (srslte_chest_dl_set_cell(&q->chest, q->cell)) { fprintf(stderr, "Error resizing channel estimator\n"); @@ -250,7 +257,7 @@ int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell) } ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", + fprintf(stderr, "Invalid cell properties ue_dl: Id=%d, Ports=%d, PRBs=%d\n", cell.id, cell.nof_ports, cell.nof_prb); } return ret; @@ -301,7 +308,38 @@ void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q, srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, non_mbsfn_region_length); } +void srslte_ue_dl_set_power_alloc(srslte_ue_dl_t *q, float rho_a, float rho_b) { + if (q) { + srslte_pdsch_set_power_allocation(&q->pdsch, rho_a); + q->rho_b = rho_b; + uint32_t nof_symbols_slot = SRSLTE_CP_NSYMB(q->cell.cp); + uint32_t nof_re_symbol = SRSLTE_NRE * q->cell.nof_prb; + + /* Apply rho_b if required according to 3GPP 36.213 Table 5.2-2 */ + if (rho_b != 0.0f && rho_b != 1.0f) { + float scaling = 1.0f / rho_b; + for (uint32_t i = 0; i < q->nof_rx_antennas; i++) { + for (uint32_t j = 0; j < 2; j++) { + cf_t *ptr; + ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 0); + srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); + if (q->cell.cp == SRSLTE_CP_NORM) { + ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 4); + srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); + } else { + ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 3); + srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); + } + if (q->cell.nof_ports == 4) { + ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 1); + srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); + } + } + } + } + } +} void srslte_ue_dl_reset(srslte_ue_dl_t *q) { for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){ @@ -321,27 +359,27 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) { * - PDCCH decoding: Find DCI for RNTI given by previous call to srslte_ue_dl_set_rnti() * - PDSCH decoding: Decode TB scrambling with RNTI given by srslte_ue_dl_set_rnti() */ -int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], +int srslte_ue_dl_decode(srslte_ue_dl_t *q, uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) { - return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks); + return srslte_ue_dl_decode_rnti(q, data, tm, tti, q->current_rnti, acks); } -int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi){ +int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi){ - return srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, cfi, SRSLTE_SF_NORM); + return srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); } -int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) +int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) { - if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { + if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Run FFT for all subframe data */ for (int j=0;jnof_rx_antennas;j++) { if(sf_type == SRSLTE_SF_MBSFN ) { - srslte_ofdm_rx_sf(&q->fft_mbsfn, input[j], q->sf_symbols_m[j]); + srslte_ofdm_rx_sf(&q->fft_mbsfn); }else{ - srslte_ofdm_rx_sf(&q->fft, input[j], q->sf_symbols_m[j]); + srslte_ofdm_rx_sf(&q->fft[j]); } /* Correct SFO multiplying by complex exponential in the time domain */ @@ -351,7 +389,7 @@ int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE srslte_cfo_correct(&q->sfo_correct, &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], - q->sample_offset / q->fft.symbol_sz); + q->sample_offset / q->fft[j].symbol_sz); } } } @@ -360,6 +398,32 @@ int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE return SRSLTE_ERROR_INVALID_INPUTS; } } + +int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi) +{ + if (input && q && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { + + /* Run FFT for all subframe data */ + for (int j=0;jnof_rx_antennas;j++) { + srslte_ofdm_rx_sf_ng(&q->fft[j], input[j], q->sf_symbols_m[j]); + + /* Correct SFO multiplying by complex exponential in the time domain */ + if (q->sample_offset) { + int nsym = SRSLTE_CP_NSYMB(q->cell.cp); + for (int i=0;i<2*nsym;i++) { + srslte_cfo_correct(&q->sfo_correct, + &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], + &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], + q->sample_offset / q->fft[j].symbol_sz); + } + } + } + return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi) { return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); @@ -430,7 +494,7 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3 } } -int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], +int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, uint16_t rnti, bool acks[SRSLTE_MAX_CODEWORDS]) { srslte_mimo_type_t mimo_type; @@ -441,7 +505,7 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t cfi; uint32_t sf_idx = tti%10; - if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_NORM)) < 0) { + if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, &cfi, SRSLTE_SF_NORM)) < 0) { return ret; } @@ -583,16 +647,15 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, - cf_t *input[SRSLTE_MAX_PORTS], - uint8_t *data, - uint32_t tti) + uint8_t *data, + uint32_t tti) { srslte_ra_dl_grant_t grant; int ret = SRSLTE_ERROR; uint32_t cfi; uint32_t sf_idx = tti%10; - if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_MBSFN)) < 0) { + if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, &cfi, SRSLTE_SF_MBSFN)) < 0) { return ret; } @@ -601,9 +664,9 @@ int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, //float noise_estimate = 0; grant.sf_type = SRSLTE_SF_MBSFN; - grant.nof_tb = 1; grant.mcs[0].idx = 2; - + grant.tb_en[0] = true; + grant.tb_en[1] = false; grant.nof_prb = q->pmch.cell.nof_prb; srslte_dl_fill_ra_mcs(&grant.mcs[0], grant.nof_prb); srslte_softbuffer_rx_reset_tbs(q->softbuffers[0], (uint32_t) grant.mcs[0].tbs); @@ -662,7 +725,8 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */ for (uint32_t nof_layers = 1; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++) { float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers * nof_layers; - if (_sinr > best_sinr + 0.1) { + /* Find best SINR, force maximum number of layers if SNR is higher than 30 dB */ + if (_sinr > best_sinr + 0.1 || _sinr > 1.0e+3) { best_sinr = _sinr; best_pmi = (uint8_t) q->pmi[nof_layers - 1]; best_ri = (uint8_t) (nof_layers - 1); @@ -677,6 +741,7 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo } /* Set RI */ + q->ri = best_ri; if (ri != NULL) { *ri = best_ri; } @@ -712,9 +777,10 @@ int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, uint8_t *ri, float *cn) { *cn = _cn; } + q->ri = (uint8_t)((_cn < 17.0f)? 1:0); /* Set rank indicator */ if (!ret && ri) { - *ri = (uint8_t)((_cn < 17.0f)? 1:0); + *ri = (uint8_t) q->ri; } return ret; @@ -907,6 +973,7 @@ bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_pr srslte_phich_ngroups(&q->phich), srslte_phich_nsf(&q->phich)); if (!srslte_phich_decode(&q->phich, q->sf_symbols_m, q->ce_m, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) { + q->last_phich_corr = distance; INFO("Decoded PHICH %d with distance %f\n", ack_bit, distance); } else { fprintf(stderr, "Error decoding PHICH\n"); diff --git a/lib/src/phy/ue/ue_mib.c b/lib/src/phy/ue/ue_mib.c index 23fec7f6e..c003a2ba3 100644 --- a/lib/src/phy/ue/ue_mib.c +++ b/lib/src/phy/ue/ue_mib.c @@ -35,7 +35,8 @@ #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" -int srslte_ue_mib_init(srslte_ue_mib_t * q, +int srslte_ue_mib_init(srslte_ue_mib_t * q, + cf_t *in_buffer[SRSLTE_MAX_PORTS], uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -65,7 +66,7 @@ int srslte_ue_mib_init(srslte_ue_mib_t * q, } } - if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, max_prb)) { + if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, in_buffer[0], q->sf_symbols, max_prb)) { fprintf(stderr, "Error initializing FFT\n"); goto clean_exit; } @@ -143,14 +144,14 @@ void srslte_ue_mib_reset(srslte_ue_mib_t * q) srslte_pbch_decode_reset(&q->pbch); } -int srslte_ue_mib_decode(srslte_ue_mib_t * q, cf_t *input, +int srslte_ue_mib_decode(srslte_ue_mib_t * q, uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, int *sfn_offset) { int ret = SRSLTE_SUCCESS; cf_t *ce_slot1[SRSLTE_MAX_PORTS]; /* Run FFT for the slot symbols */ - srslte_ofdm_rx_sf(&q->fft, input, q->sf_symbols); + srslte_ofdm_rx_sf(&q->fft); /* Get channel estimates of sf idx #0 for each port */ ret = srslte_chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, 0); @@ -198,7 +199,7 @@ int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q, } q->nof_rx_antennas = nof_rx_antennas; - if (srslte_ue_mib_init(&q->ue_mib, SRSLTE_UE_MIB_NOF_PRB)) { + if (srslte_ue_mib_init(&q->ue_mib, q->sf_buffer, SRSLTE_UE_MIB_NOF_PRB)) { fprintf(stderr, "Error initiating ue_mib\n"); return SRSLTE_ERROR; } @@ -261,11 +262,11 @@ int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q, uint32_t nof_frames = 0; int mib_ret = SRSLTE_UE_MIB_NOTFOUND; - srslte_ue_mib_sync_reset(q); - - if (q != NULL) + if (q != NULL) { - ret = SRSLTE_SUCCESS; + srslte_ue_mib_sync_reset(q); + + ret = SRSLTE_SUCCESS; do { mib_ret = SRSLTE_UE_MIB_NOTFOUND; ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); @@ -274,7 +275,7 @@ int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q, return -1; } else if (srslte_ue_sync_get_sfidx(&q->ue_sync) == 0) { if (ret == 1) { - mib_ret = srslte_ue_mib_decode(&q->ue_mib, q->sf_buffer[0], bch_payload, nof_tx_ports, sfn_offset); + mib_ret = srslte_ue_mib_decode(&q->ue_mib, bch_payload, nof_tx_ports, sfn_offset); } else { DEBUG("Resetting PBCH decoder after %d frames\n", q->ue_mib.frame_cnt); srslte_ue_mib_reset(&q->ue_mib); diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index f121c5bac..f3360dda7 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include "srslte/srslte.h" #include "srslte/phy/ue/ue_sync.h" @@ -47,6 +47,7 @@ #define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0 #define DEFAULT_SFO_EMA_COEFF 0.1 + cf_t dummy_buffer0[15*2048/2]; cf_t dummy_buffer1[15*2048/2]; @@ -70,10 +71,12 @@ int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q, uint32_t nof_prb, char * q->file_mode = true; q->sf_len = SRSLTE_SF_LEN(srslte_symbol_sz(nof_prb)); q->file_cfo = -offset_freq; - q->correct_cfo = true; q->fft_size = srslte_symbol_sz(nof_prb); q->nof_rx_antennas = nof_rx_ant; - + + q->cfo_correct_enable_find = false; + q->cfo_correct_enable_track = true; + if (srslte_cfo_init(&q->file_cfo_correct, 2*q->sf_len)) { fprintf(stderr, "Error initiating CFO\n"); goto clean_exit; @@ -96,6 +99,7 @@ int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q, uint32_t nof_prb, char * free(file_offset_buffer); } + srslte_ue_sync_cfo_reset(q); srslte_ue_sync_reset(q); ret = SRSLTE_SUCCESS; @@ -107,6 +111,33 @@ clean_exit: return ret; } +void srslte_ue_sync_cfo_reset(srslte_ue_sync_t *q) +{ + q->cfo_is_copied = false; + q->cfo_current_value = 0; + srslte_sync_cfo_reset(&q->strack); + srslte_sync_cfo_reset(&q->sfind); +} + +void srslte_ue_sync_reset(srslte_ue_sync_t *q) { + + if (!q->file_mode) { + srslte_sync_reset(&q->sfind); + srslte_sync_reset(&q->strack); + } else { + q->sf_idx = 9; + } + q->pss_stable_timeout = false; + q->state = SF_FIND; + q->frame_ok_cnt = 0; + q->frame_no_cnt = 0; + q->frame_total_cnt = 0; + q->mean_sample_offset = 0.0; + q->next_rf_sample_offset = 0; + q->frame_find_cnt = 0; +} + + int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, double (set_gain_callback)(void*, double), float init_gain_value) { uint32_t nframes; if (q->nof_recv_sf == 1) { @@ -118,6 +149,8 @@ int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, double (set_gain_callback)(voi q->do_agc = n==0?true:false; if (q->do_agc) { srslte_agc_set_gain(&q->agc, init_gain_value); + srslte_agc_set_target(&q->agc, 0.3); + srslte_agc_set_bandwidth(&q->agc, 0.8); } return n; } @@ -177,13 +210,24 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, q->fft_size = srslte_symbol_sz(max_prb); q->sf_len = SRSLTE_SF_LEN(q->fft_size); q->file_mode = false; - q->correct_cfo = true; - q->agc_period = 0; + q->agc_period = 0; q->sample_offset_correct_period = DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD; q->sfo_ema = DEFAULT_SFO_EMA_COEFF; q->max_prb = max_prb; + q->cfo_ref_max = DEFAULT_CFO_REF_MAX; + q->cfo_ref_min = DEFAULT_CFO_REF_MIN; + q->cfo_pss_min = DEFAULT_CFO_PSS_MIN; + q->cfo_loop_bw_pss = DEFAULT_CFO_BW_PSS; + q->cfo_loop_bw_ref = DEFAULT_CFO_BW_REF; + + q->cfo_correct_enable_find = false; + q->cfo_correct_enable_track = true; + + q->pss_stable_cnt = 0; + q->pss_stable_timeout = DEFAULT_PSS_STABLE_TIMEOUT; + if (search_cell) { /* If the cell is unkown, we search PSS/SSS in 5 ms */ @@ -218,6 +262,25 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, } } + // Configure FIND and TRACK sync objects behaviour (this configuration is always the same) + srslte_sync_set_cfo_i_enable(&q->sfind, false); + srslte_sync_set_cfo_pss_enable(&q->sfind, true); + srslte_sync_set_pss_filt_enable(&q->sfind, true); + srslte_sync_set_sss_eq_enable(&q->sfind, false); + + // During track, we do CFO correction outside the sync object + srslte_sync_set_cfo_i_enable(&q->strack, false); + srslte_sync_set_cfo_pss_enable(&q->strack, true); + srslte_sync_set_pss_filt_enable(&q->strack, true); + srslte_sync_set_sss_eq_enable(&q->strack, false); + + // FIXME: CP detection not working very well. Not supporting Extended CP right now + srslte_sync_cp_en(&q->strack, false); + srslte_sync_cp_en(&q->sfind, false); + + srslte_sync_sss_en(&q->strack, true); + q->decode_sss_on_track = true; + ret = SRSLTE_SUCCESS; } @@ -253,8 +316,6 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) if (q != NULL && srslte_nofprb_isvalid(cell.nof_prb)) { - ret = SRSLTE_ERROR; - if (cell.nof_prb > q->max_prb) { fprintf(stderr, "Error in ue_sync_set_cell(): cell.nof_prb must be lower than initialized\n"); return SRSLTE_ERROR; @@ -269,15 +330,10 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) /* If the cell is unkown, we search PSS/SSS in 5 ms */ q->nof_recv_sf = 5; - - q->decode_sss_on_track = true; - } else { /* If the cell is known, we work on a 1ms basis */ q->nof_recv_sf = 1; - - q->decode_sss_on_track = true; } q->frame_len = q->nof_recv_sf*q->sf_len; @@ -287,61 +343,61 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) } if(srslte_sync_resize(&q->sfind, q->frame_len, q->frame_len, q->fft_size)) { - fprintf(stderr, "Error initiating sync find\n"); + fprintf(stderr, "Error setting cell sync find\n"); return SRSLTE_ERROR; } if (cell.id == 1000) { if(srslte_sync_resize(&q->strack, q->frame_len, TRACK_FRAME_SIZE, q->fft_size)) { - fprintf(stderr, "Error initiating sync track\n"); + fprintf(stderr, "Error setting cell sync track\n"); return SRSLTE_ERROR; } } else { if(srslte_sync_resize(&q->strack, q->frame_len, SRSLTE_CP_LEN_NORM(1,q->fft_size), q->fft_size)) { - fprintf(stderr, "Error initiating sync track\n"); + fprintf(stderr, "Error setting cell sync track\n"); return SRSLTE_ERROR; } } if (cell.id == 1000) { - /* If the cell id is unknown, enable CP detection on find */ - // FIXME: CP detection not working very well. Not supporting Extended CP right now - srslte_sync_cp_en(&q->sfind, false); - srslte_sync_cp_en(&q->strack, false); + q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES; - srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.8); + srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.8); srslte_sync_set_cfo_ema_alpha(&q->strack, 0.1); - srslte_sync_cfo_i_detec_en(&q->sfind, false); + srslte_sync_set_em_alpha(&q->sfind, 1); - q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES; - srslte_sync_set_threshold(&q->sfind, 2.0); + srslte_sync_set_threshold(&q->sfind, 2.0); srslte_sync_set_threshold(&q->strack, 1.2); - } else { - srslte_sync_set_N_id_2(&q->sfind, cell.id%3); - srslte_sync_set_N_id_2(&q->strack, cell.id%3); - q->sfind.cp = cell.cp; - q->strack.cp = cell.cp; - srslte_sync_cp_en(&q->sfind, false); - srslte_sync_cp_en(&q->strack, false); - - srslte_sync_cfo_i_detec_en(&q->sfind, false); - - srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.1); + srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.1); srslte_sync_set_cfo_ema_alpha(&q->strack, 0.1); + } else { + q->sfind.cp = cell.cp; + q->strack.cp = cell.cp; + + srslte_sync_set_N_id_2(&q->sfind, cell.id%3); + srslte_sync_set_N_id_2(&q->strack, cell.id%3); + + srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.1); + srslte_sync_set_cfo_ema_alpha(&q->strack, DEFAULT_CFO_EMA_TRACK); + /* In find phase and if the cell is known, do not average pss correlation * because we only capture 1 subframe and do not know where the peak is. */ q->nof_avg_find_frames = 1; - srslte_sync_set_em_alpha(&q->sfind, 1); - srslte_sync_set_threshold(&q->sfind, 3.0); + srslte_sync_set_em_alpha(&q->sfind, 1); + srslte_sync_set_threshold(&q->sfind, 3.0); - srslte_sync_set_em_alpha(&q->strack, 0.2); + srslte_sync_set_em_alpha(&q->strack, 0.2); srslte_sync_set_threshold(&q->strack, 1.2); } + // When cell is unknown, do CP CFO correction + srslte_sync_set_cfo_cp_enable(&q->sfind, true, q->frame_len<10000?14:3); + q->cfo_correct_enable_find = false; + srslte_ue_sync_reset(q); ret = SRSLTE_SUCCESS; @@ -355,32 +411,60 @@ void srslte_ue_sync_get_last_timestamp(srslte_ue_sync_t *q, srslte_timestamp_t * memcpy(timestamp, &q->last_timestamp, sizeof(srslte_timestamp_t)); } -uint32_t srslte_ue_sync_peak_idx(srslte_ue_sync_t *q) { - return q->peak_idx; +void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q, float bw_pss, float bw_ref, + float pss_tol, float ref_tol, float ref_max, + uint32_t pss_stable_conv_time) { + q->cfo_loop_bw_pss = bw_pss; + q->cfo_loop_bw_ref = bw_ref; + q->cfo_pss_min = pss_tol; + q->cfo_ref_min = ref_tol; + q->cfo_ref_max = ref_max; + q->pss_stable_timeout = pss_stable_conv_time; } -srslte_ue_sync_state_t srslte_ue_sync_get_state(srslte_ue_sync_t *q) { - return q->state; +void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float ema) { + srslte_sync_set_cfo_ema_alpha(&q->strack, ema); } + +void srslte_ue_sync_set_cfo_ref(srslte_ue_sync_t *q, float ref_cfo) +{ + // Accept REF-based CFO adjustments only after PSS CFO is stable + if (q->pss_is_stable) { + if (fabsf(ref_cfo)*15000 > q->cfo_ref_min) { + if (fabsf(ref_cfo)*15000 > q->cfo_ref_max) { + ref_cfo = (ref_cfo>0?q->cfo_ref_max:-q->cfo_ref_max)/15000; + } + q->cfo_current_value += ref_cfo*q->cfo_loop_bw_ref; + } + } +} + uint32_t srslte_ue_sync_get_sfidx(srslte_ue_sync_t *q) { return q->sf_idx; } -void srslte_ue_sync_cfo_i_detec_en(srslte_ue_sync_t *q, bool enable) { - srslte_sync_cfo_i_detec_en(&q->strack, enable); - srslte_sync_cfo_i_detec_en(&q->sfind, enable); +void srslte_ue_sync_set_cfo_i_enable(srslte_ue_sync_t *q, bool enable) { + printf("Warning: Setting integer CFO detection/correction. This is experimental!\n"); + srslte_sync_set_cfo_i_enable(&q->strack, enable); + srslte_sync_set_cfo_i_enable(&q->sfind, enable); } float srslte_ue_sync_get_cfo(srslte_ue_sync_t *q) { - return 15000 * srslte_sync_get_cfo(&q->strack); + return 15000 * q->cfo_current_value; } -void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q, float cfo) { - srslte_sync_set_cfo(&q->sfind, cfo/15000); - srslte_sync_set_cfo(&q->strack, cfo/15000); +void srslte_ue_sync_copy_cfo(srslte_ue_sync_t *q, srslte_ue_sync_t *src_obj) { + // Copy find object internal CFO averages + srslte_sync_copy_cfo(&q->sfind, &src_obj->sfind); + // Current CFO is tracking-phase CFO of previous object + q->cfo_current_value = src_obj->cfo_current_value; + q->cfo_is_copied = true; } -void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t *q, float cfo_tol) {} +void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t *q, float cfo_tol) { + srslte_sync_set_cfo_tol(&q->strack, cfo_tol); + srslte_sync_set_cfo_tol(&q->sfind, cfo_tol); +} float srslte_ue_sync_get_sfo(srslte_ue_sync_t *q) { return q->mean_sfo/5e-3; @@ -399,7 +483,8 @@ void srslte_ue_sync_set_sfo_ema(srslte_ue_sync_t *q, float ema_coefficient) { } void srslte_ue_sync_decode_sss_on_track(srslte_ue_sync_t *q, bool enabled) { - q->decode_sss_on_track = enabled; + q->decode_sss_on_track = enabled; + srslte_sync_sss_en(&q->strack, q->decode_sss_on_track); } void srslte_ue_sync_set_N_id_2(srslte_ue_sync_t *q, uint32_t N_id_2) { @@ -427,7 +512,7 @@ static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS q->frame_find_cnt++; DEBUG("Found peak %d at %d, value %.3f, Cell_id: %d CP: %s\n", q->frame_find_cnt, q->peak_idx, - srslte_sync_get_last_peak_value(&q->sfind), q->cell.id, srslte_cp_string(q->cell.cp)); + srslte_sync_get_peak_value(&q->sfind), q->cell.id, srslte_cp_string(q->cell.cp)); if (q->frame_find_cnt >= q->nof_avg_find_frames || q->peak_idx < 2*q->fft_size) { INFO("Realigning frame, reading %d samples\n", q->peak_idx+q->sf_len/2); @@ -444,11 +529,13 @@ static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS q->mean_sample_offset = 0; /* Goto Tracking state */ - q->state = SF_TRACK; - - /* Initialize track state CFO */ - q->strack.mean_cfo = q->sfind.mean_cfo; - q->strack.cfo_i = q->sfind.cfo_i; + q->state = SF_TRACK; + + /* Set CFO values. Since we correct before track, the initial track state is CFO=0 Hz */ + if (!q->cfo_is_copied) { + q->cfo_current_value = srslte_sync_get_cfo(&q->sfind); + } + srslte_sync_cfo_reset(&q->strack); } return 0; @@ -484,6 +571,23 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) { q->mean_sample_offset = q->last_sample_offset; } + /* Adjust current CFO estimation with PSS + * Since sync track has enabled only PSS-based correlation, get_cfo() returns that value only, already filtered. + */ + INFO("TRACK: cfo_current=%f, cfo_strack=%f\n", 15000*q->cfo_current_value, 15000*srslte_sync_get_cfo(&q->strack)); + if (15000*fabsf(srslte_sync_get_cfo(&q->strack)) > q->cfo_pss_min) { + q->cfo_current_value += srslte_sync_get_cfo(&q->strack)*q->cfo_loop_bw_pss; + q->pss_stable_cnt = 0; + q->pss_is_stable = false; + } else { + if (!q->pss_is_stable) { + q->pss_stable_cnt++; + if (q->pss_stable_cnt >= q->pss_stable_timeout) { + q->pss_is_stable = true; + } + } + } + // Compute cumulative moving average time offset */ if (!frame_idx) { // Adjust RF sampling time based on the mean sampling offset @@ -536,13 +640,7 @@ static int track_peak_no(srslte_ue_sync_t *q) { return 0; } else { INFO("Tracking peak not found. Peak %.3f, %d lost\n", - srslte_sync_get_last_peak_value(&q->strack), (int) q->frame_no_cnt); - /* - printf("Saving files: pss_corr (%d), input (%d)\n", q->strack.pss.frame_size, SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); - srslte_vec_save_file("pss_corr", q->strack.pss.conv_output_avg, q->strack.pss.frame_size*sizeof(float)); - srslte_vec_save_file("input", q->input_buffer, SRSLTE_SF_LEN_PRB(q->cell.nof_prb)*sizeof(cf_t)); - exit(-1); - */ + srslte_sync_get_peak_value(&q->strack), (int) q->frame_no_cnt); return 1; } @@ -571,12 +669,10 @@ static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PO return SRSLTE_SUCCESS; } -bool first_track = true; - int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { - cf_t *_input_buffer[SRSLTE_MAX_PORTS]; - _input_buffer[0] = input_buffer; - return srslte_ue_sync_zerocopy_multi(q, _input_buffer); + cf_t *_input_buffer[SRSLTE_MAX_PORTS]; + _input_buffer[0] = input_buffer; + return srslte_ue_sync_zerocopy_multi(q, _input_buffer); } /* Returns 1 if the subframe is synchronized in time, 0 otherwise */ @@ -603,7 +699,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE return SRSLTE_ERROR; } } - if (q->correct_cfo) { + if (q->cfo_correct_enable_track) { for (int i = 0; i < q->nof_rx_antennas; i++) { srslte_cfo_correct(&q->file_cfo_correct, input_buffer[i], @@ -618,19 +714,30 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE INFO("Reading %d samples. sf_idx = %d\n", q->sf_len, q->sf_idx); ret = 1; } else { + if (receive_samples(q, input_buffer)) { fprintf(stderr, "Error receiving samples\n"); return SRSLTE_ERROR; } - + int n; switch (q->state) { - case SF_FIND: - switch(srslte_sync_find(&q->sfind, input_buffer[0], 0, &q->peak_idx)) { + case SF_FIND: + // Correct CFO before PSS/SSS find using the sync object corrector (initialized for 1 ms) + if (q->cfo_correct_enable_find) { + for (int i=0;inof_rx_antennas;i++) { + srslte_cfo_correct(&q->strack.cfo_corr_frame, + input_buffer[i], + input_buffer[i], + -q->cfo_current_value/q->fft_size); + } + } + n = srslte_sync_find(&q->sfind, input_buffer[0], 0, &q->peak_idx); + switch(n) { case SRSLTE_SYNC_ERROR: ret = SRSLTE_ERROR; fprintf(stderr, "Error finding correlation peak (%d)\n", ret); return SRSLTE_ERROR; - case SRSLTE_SYNC_FOUND: + case SRSLTE_SYNC_FOUND: ret = find_peak_ok(q, input_buffer); break; case SRSLTE_SYNC_FOUND_NOSPACE: @@ -652,37 +759,39 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE case SF_TRACK: ret = 1; - - srslte_sync_sss_en(&q->strack, q->decode_sss_on_track); - + + // Increase subframe counter q->sf_idx = (q->sf_idx + q->nof_recv_sf) % 10; - /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ - if (q->sf_idx == 0 || q->sf_idx == 5) { + // Correct CFO before PSS/SSS tracking using the sync object corrector (initialized for 1 ms) + if (q->cfo_correct_enable_track) { + for (int i=0;inof_rx_antennas;i++) { + srslte_cfo_correct(&q->strack.cfo_corr_frame, + input_buffer[i], + input_buffer[i], + -q->cfo_current_value/q->fft_size); + } + } + /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ + if (q->sf_idx == 0 || q->sf_idx == 5) + { + // Process AGC every period if (q->do_agc && (q->agc_period == 0 || (q->agc_period && (q->frame_total_cnt%q->agc_period) == 0))) { srslte_agc_process(&q->agc, input_buffer[0], q->sf_len); } - #ifdef MEASURE_EXEC_TIME - struct timeval t[3]; - gettimeofday(&t[1], NULL); - #endif - - track_idx = 0; - - /* Track PSS/SSS around the expected PSS position + /* Track PSS/SSS around the expected PSS position * In tracking phase, the subframe carrying the PSS is always the last one of the frame */ - - switch(srslte_sync_find(&q->strack, input_buffer[0], - q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2, - &track_idx)) + n = srslte_sync_find(&q->strack, input_buffer[0], + q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2, + &track_idx); + switch(n) { case SRSLTE_SYNC_ERROR: - ret = SRSLTE_ERROR; fprintf(stderr, "Error tracking correlation peak\n"); return SRSLTE_ERROR; case SRSLTE_SYNC_FOUND: @@ -692,60 +801,26 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE // It's very very unlikely that we fall here because this event should happen at FIND phase only ret = 0; q->state = SF_FIND; - printf("Warning: No space for SSS/CP while in tracking phase\n"); + INFO("Warning: No space for SSS/CP while in tracking phase\n"); break; case SRSLTE_SYNC_NOFOUND: ret = track_peak_no(q); break; } - #ifdef MEASURE_EXEC_TIME - gettimeofday(&t[2], NULL); - get_time_interval(t); - q->mean_exec_time = (float) SRSLTE_VEC_CMA((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt); - #endif - if (ret == SRSLTE_ERROR) { fprintf(stderr, "Error processing tracking peak\n"); q->state = SF_FIND; return SRSLTE_SUCCESS; - } - - q->frame_total_cnt++; - } - if (q->correct_cfo) { - for (int i=0;inof_rx_antennas;i++) { - srslte_cfo_correct(&q->strack.cfocorr, - input_buffer[i], - input_buffer[i], - -srslte_sync_get_cfo(&q->strack) / q->fft_size); } - } + + q->frame_total_cnt++; + } break; } - } } return ret; } -void srslte_ue_sync_reset(srslte_ue_sync_t *q) { - - if (!q->file_mode) { - srslte_sync_reset(&q->sfind); - srslte_sync_reset(&q->strack); - } else { - q->sf_idx = 9; - } - q->state = SF_FIND; - q->frame_ok_cnt = 0; - q->frame_no_cnt = 0; - q->frame_total_cnt = 0; - q->mean_sample_offset = 0.0; - q->next_rf_sample_offset = 0; - q->frame_find_cnt = 0; - #ifdef MEASURE_EXEC_TIME - q->mean_exec_time = 0; - #endif -} diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index 37dfecd93..63411fb25 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -38,9 +38,10 @@ #define MAX_SFLEN SRSLTE_SF_LEN(srslte_symbol_sz(max_prb)) -#define DEFAULT_CFO_TOL 50.0 // Hz +#define DEFAULT_CFO_TOL 1.0 // Hz int srslte_ue_ul_init(srslte_ue_ul_t *q, + cf_t *out_buffer, uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -50,8 +51,14 @@ int srslte_ue_ul_init(srslte_ue_ul_t *q, ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_ue_ul_t)); - - if (srslte_ofdm_tx_init(&q->fft, SRSLTE_CP_NORM, max_prb)) { + + q->sf_symbols = srslte_vec_malloc(SRSLTE_SF_LEN_PRB(max_prb) * sizeof(cf_t)); + if (!q->sf_symbols) { + perror("malloc"); + goto clean_exit; + } + + if (srslte_ofdm_tx_init(&q->fft, SRSLTE_CP_NORM, q->sf_symbols, out_buffer, max_prb)) { fprintf(stderr, "Error initiating FFT\n"); goto clean_exit; } @@ -83,11 +90,6 @@ int srslte_ue_ul_init(srslte_ue_ul_t *q, fprintf(stderr, "Error initiating srslte_refsignal_ul\n"); goto clean_exit; } - q->sf_symbols = srslte_vec_malloc(SRSLTE_SF_LEN_PRB(max_prb) * sizeof(cf_t)); - if (!q->sf_symbols) { - perror("malloc"); - goto clean_exit; - } q->refsignal = srslte_vec_malloc(2 * SRSLTE_NRE * max_prb * sizeof(cf_t)); if (!q->refsignal) { perror("malloc"); @@ -176,7 +178,7 @@ int srslte_ue_ul_set_cell(srslte_ue_ul_t *q, } ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", + fprintf(stderr, "Invalid cell properties ue_ul: Id=%d, Ports=%d, PRBs=%d\n", cell.id, cell.nof_ports, cell.nof_prb); } return ret; @@ -271,21 +273,33 @@ int srslte_ue_ul_cfg_grant(srslte_ue_ul_t *q, srslte_ra_ul_grant_t *grant, void pucch_encode_bits(srslte_uci_data_t *uci_data, srslte_pucch_format_t format, uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS], uint8_t pucch2_bits[SRSLTE_PUCCH_MAX_BITS]) -{ +{ + uint8_t uci_buffer[SRSLTE_CQI_MAX_BITS]; + uint8_t uci_buffer_len = 0; + if (format == SRSLTE_PUCCH_FORMAT_1A || format == SRSLTE_PUCCH_FORMAT_1B) { pucch_bits[0] = uci_data->uci_ack; pucch_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 1a } if (format >= SRSLTE_PUCCH_FORMAT_2) { - /* Append Differential CQI */ - memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len); - uci_data->uci_cqi_len += uci_data->uci_dif_cqi_len; + /* Put RI (goes alone) */ + if (uci_data->ri_periodic_report) { + uci_buffer[0] = uci_data->uci_ri; // It assumes only 1 bit of RI + uci_buffer_len += uci_data->uci_ri_len; + } else { + /* Append CQI */ + memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_cqi, uci_data->uci_cqi_len); + uci_buffer_len += uci_data->uci_cqi_len; - /* Append PMI */ - memcpy(&uci_data->uci_cqi[uci_data->uci_cqi_len], uci_data->uci_pmi, uci_data->uci_pmi_len); - uci_data->uci_cqi_len += uci_data->uci_pmi_len; + /* Append Differential CQI */ + memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_dif_cqi, uci_data->uci_dif_cqi_len); + uci_buffer_len += uci_data->uci_dif_cqi_len; - srslte_uci_encode_cqi_pucch(uci_data->uci_cqi, uci_data->uci_cqi_len, pucch_bits); + /* Append PMI */ + memcpy(&uci_buffer[uci_buffer_len], uci_data->uci_pmi, uci_data->uci_pmi_len); + uci_buffer_len += uci_data->uci_pmi_len; + } + srslte_uci_encode_cqi_pucch(uci_buffer, uci_buffer_len, pucch_bits); if (format > SRSLTE_PUCCH_FORMAT_2) { pucch2_bits[0] = uci_data->uci_ack; pucch2_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 2a @@ -347,7 +361,7 @@ int srslte_ue_ul_pucch_encode(srslte_ue_ul_t *q, srslte_uci_data_t uci_data, q->last_pucch_format = format; - srslte_ofdm_tx_sf(&q->fft, q->sf_symbols, output_signal); + srslte_ofdm_tx_sf(&q->fft); if (q->cfo_en) { srslte_cfo_correct(&q->cfo, output_signal, output_signal, q->current_cfo / srslte_symbol_sz(q->cell.nof_prb)); @@ -417,7 +431,7 @@ int srslte_ue_ul_srs_encode(srslte_ue_ul_t *q, uint32_t tti, cf_t *output_signal } } - srslte_ofdm_tx_sf(&q->fft, q->sf_symbols, output_signal); + srslte_ofdm_tx_sf(&q->fft); if (q->cfo_en) { srslte_cfo_correct(&q->cfo, output_signal, output_signal, q->current_cfo / srslte_symbol_sz(q->cell.nof_prb)); @@ -451,7 +465,7 @@ int srslte_ue_ul_pusch_encode_rnti_softbuffer(srslte_ue_ul_t *q, if (srslte_pusch_encode(&q->pusch, &q->pusch_cfg, softbuffer, data, uci_data, rnti, q->sf_symbols)) { fprintf(stderr, "Error encoding TB\n"); - return ret; + return SRSLTE_ERROR; } if (q->signals_pregenerated) { @@ -486,7 +500,7 @@ int srslte_ue_ul_pusch_encode_rnti_softbuffer(srslte_ue_ul_t *q, } } - srslte_ofdm_tx_sf(&q->fft, q->sf_symbols, output_signal); + srslte_ofdm_tx_sf(&q->fft); if (q->cfo_en) { srslte_cfo_correct(&q->cfo, output_signal, output_signal, q->current_cfo / srslte_symbol_sz(q->cell.nof_prb)); diff --git a/lib/src/phy/utils/bit.c b/lib/src/phy/utils/bit.c index 9ef53c35a..809d4c392 100644 --- a/lib/src/phy/utils/bit.c +++ b/lib/src/phy/utils/bit.c @@ -30,8 +30,181 @@ #include #include #include +#include + +#ifdef LV_HAVE_SSE + +#include + +#endif /* LV_HAVE_SSE */ #include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" + +void srslte_bit_interleaver_init(srslte_bit_interleaver_t *q, + uint16_t *interleaver, + uint32_t nof_bits) { + static const uint8_t mask[] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }; + + bzero(q, sizeof(srslte_bit_interleaver_t)); + + q->interleaver = srslte_vec_malloc(sizeof(uint16_t)*nof_bits); + q->byte_idx = srslte_vec_malloc(sizeof(uint16_t)*nof_bits); + q->bit_mask = srslte_vec_malloc(sizeof(uint8_t)*nof_bits); + q->nof_bits = nof_bits; + + for (int i = 0; i < nof_bits; i++) { + uint16_t i_px = interleaver[i]; + q->interleaver[i] = i_px; + q->byte_idx[i] = (uint16_t) (interleaver[i] / 8); + q->bit_mask[i] = (uint8_t) (mask[i_px%8]); + } +} + +void srslte_bit_interleaver_free(srslte_bit_interleaver_t *q) { + if (q->interleaver) { + free(q->interleaver); + } + + if (q->byte_idx) { + free(q->byte_idx); + } + + if (q->bit_mask) { + free(q->bit_mask); + } + + bzero(q, sizeof(srslte_bit_interleaver_t)); +} + +void srslte_bit_interleaver_run(srslte_bit_interleaver_t *q, uint8_t *input, uint8_t *output, uint16_t w_offset) { + static const uint8_t mask[] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }; + uint16_t *byte_idx = q->byte_idx; + uint8_t *bit_mask = q->bit_mask; + uint8_t *output_ptr = output; + + uint32_t st=0, w_offset_p=0; + + if (w_offset < 8 && w_offset > 0) { + st=1; + for (uint32_t j=0;j<8-w_offset;j++) { + uint16_t i_p = q->interleaver[j]; + if (input[i_p/8] & mask[i_p%8]) { + output[0] |= mask[j+w_offset]; + } else { + output[0] &= ~(mask[j+w_offset]); + } + } + w_offset_p=8-w_offset; + } + + uint32_t i = st * 8; + + byte_idx += i - w_offset_p; + bit_mask += i - w_offset_p; + output_ptr += st; + +#ifdef LV_HAVE_SSE + for(; i < q->nof_bits - 15; i += 16) { + __m128i in128; + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x7); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x6); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x5); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x4); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x3); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x2); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x1); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x0); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xF); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xE); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xD); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xC); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xB); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0xA); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x9); + in128 = _mm_insert_epi8(in128, input[*(byte_idx++)], 0x8); + + __m128i mask128 = _mm_loadu_si128((__m128i *) bit_mask); + mask128 = _mm_shuffle_epi8(mask128, _mm_set_epi8(0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7)); + + __m128i cmp128 = _mm_cmpeq_epi8(_mm_and_si128(in128, mask128), mask128); + *((uint16_t *) (output_ptr)) = (uint16_t) _mm_movemask_epi8(cmp128); + + bit_mask += 16; + output_ptr += 2; + } + +#endif /* LV_HAVE_SSE */ + + for(; i < q->nof_bits; i += 8) { + uint8_t out0 = (input[*(byte_idx++)] & *(bit_mask++))?mask[0]:(uint8_t)0; + uint8_t out1 = (input[*(byte_idx++)] & *(bit_mask++))?mask[1]:(uint8_t)0; + uint8_t out2 = (input[*(byte_idx++)] & *(bit_mask++))?mask[2]:(uint8_t)0; + uint8_t out3 = (input[*(byte_idx++)] & *(bit_mask++))?mask[3]:(uint8_t)0; + uint8_t out4 = (input[*(byte_idx++)] & *(bit_mask++))?mask[4]:(uint8_t)0; + uint8_t out5 = (input[*(byte_idx++)] & *(bit_mask++))?mask[5]:(uint8_t)0; + uint8_t out6 = (input[*(byte_idx++)] & *(bit_mask++))?mask[6]:(uint8_t)0; + uint8_t out7 = (input[*(byte_idx++)] & *(bit_mask++))?mask[7]:(uint8_t)0; + + *output_ptr = out0 | out1 | out2 | out3 | out4 | out5 | out6 | out7; + output_ptr++; + } + + for (uint32_t j=0;jnof_bits%8;j++) { + uint16_t i_p = q->interleaver[(q->nof_bits/8)*8+j-w_offset]; + if (input[i_p/8] & mask[i_p%8]) { + output[q->nof_bits/8] |= mask[j]; + } else { + output[q->nof_bits/8] &= ~(mask[j]); + } + } + for (uint32_t j=0;jinterleaver[(q->nof_bits/8)*8+j-w_offset]; + if (input[i_p/8] & (1<<(7-i_p%8))) { + output[q->nof_bits/8] |= mask[j]; + } else { + output[q->nof_bits/8] &= ~(mask[j]); + } + } + +#if 0 + /* THIS PIECE OF CODE IS FOR CHECKING SIMD BEHAVIOUR. DO NOT ENABLE. */ + uint8_t *output2 = malloc(q->nof_bits/8); + for (i=st;inof_bits/8;i++) { + + uint16_t i_p0 = q->interleaver[i*8+0-w_offset_p]; + uint16_t i_p1 = q->interleaver[i*8+1-w_offset_p]; + uint16_t i_p2 = q->interleaver[i*8+2-w_offset_p]; + uint16_t i_p3 = q->interleaver[i*8+3-w_offset_p]; + uint16_t i_p4 = q->interleaver[i*8+4-w_offset_p]; + uint16_t i_p5 = q->interleaver[i*8+5-w_offset_p]; + uint16_t i_p6 = q->interleaver[i*8+6-w_offset_p]; + uint16_t i_p7 = q->interleaver[i*8+7-w_offset_p]; + + uint8_t out0 = (input[i_p0/8] & mask[i_p0%8])?mask[0]:(uint8_t)0; + uint8_t out1 = (input[i_p1/8] & mask[i_p1%8])?mask[1]:(uint8_t)0; + uint8_t out2 = (input[i_p2/8] & mask[i_p2%8])?mask[2]:(uint8_t)0; + uint8_t out3 = (input[i_p3/8] & mask[i_p3%8])?mask[3]:(uint8_t)0; + uint8_t out4 = (input[i_p4/8] & mask[i_p4%8])?mask[4]:(uint8_t)0; + uint8_t out5 = (input[i_p5/8] & mask[i_p5%8])?mask[5]:(uint8_t)0; + uint8_t out6 = (input[i_p6/8] & mask[i_p6%8])?mask[6]:(uint8_t)0; + uint8_t out7 = (input[i_p7/8] & mask[i_p7%8])?mask[7]:(uint8_t)0; + + output2[i] = out0 | out1 | out2 | out3 | out4 | out5 | out6 | out7; + } + + for(i = st; i < q->nof_bits/8; i++) { + if (true || output[i] != output2[i]) { + printf("%05d/%05d %02X %02X\n", i, q->nof_bits/8, output[i], output2[i]); + } + //output[i] = output2[i]; + } + free(output2); +#endif +} + + void srslte_bit_interleave(uint8_t *input, uint8_t *output, uint16_t *interleaver, uint32_t nof_bits) { srslte_bit_interleave_w_offset(input, output, interleaver, nof_bits, 0); @@ -53,6 +226,129 @@ void srslte_bit_interleave_w_offset(uint8_t *input, uint8_t *output, uint16_t *i } w_offset_p=8-w_offset; } +#ifdef LV_HAVE_SSE + __m64 m64mask = _mm_setr_pi8((uint8_t) 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1); + __m128i m128mask = _mm_set1_epi64(m64mask); + + union { + uint8_t v[8]; + __m64 m64; + } a, b, c; + + union { + __m128i m128; + uint16_t u16[8]; + uint8_t u8[16]; + struct { + __m64 reg_a; + __m64 reg_b; + } m64; + struct { + uint16_t i0, i1, i2, i3, i4, i5, i6, i7; + } v; + } ipx, epx, ipx2, epx2, b128, a128, c128; + + uint32_t i = st; + for (; i < (nof_bits / 8 - 1); i += 2) { + ipx.m128 = _mm_loadu_si128((__m128i *) (interleaver + (i * 8) - w_offset_p)); + epx.m128 = _mm_shuffle_epi8(ipx.m128, _mm_set_epi8(0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E)); + ipx2.m128 = _mm_loadu_si128((__m128i *) (interleaver + ((i + 1) * 8) - w_offset_p)); + epx2.m128 = _mm_shuffle_epi8(ipx2.m128, _mm_set_epi8(0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E)); + + epx.m128 = _mm_blendv_epi8(epx.m128, epx2.m128, _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, + (uint8_t) 0xFF, (uint8_t) 0xFF, + (uint8_t) 0xFF, (uint8_t) 0xFF, + (uint8_t) 0xFF, (uint8_t) 0xFF, + (uint8_t) 0xFF, (uint8_t) 0xFF)); + + b128.m128 = _mm_and_si128(epx.m128, _mm_set1_epi8(0x7)); + b128.m128 = _mm_shuffle_epi8(m128mask, b128.m128); + + ipx.m128 = _mm_srli_epi16(ipx.m128, 3); + ipx2.m128 = _mm_srli_epi16(ipx2.m128, 3); + + a128.m128 = _mm_set_epi8(input[ipx2.v.i0], + input[ipx2.v.i1], + input[ipx2.v.i2], + input[ipx2.v.i3], + input[ipx2.v.i4], + input[ipx2.v.i5], + input[ipx2.v.i6], + input[ipx2.v.i7], + input[ipx.v.i0], + input[ipx.v.i1], + input[ipx.v.i2], + input[ipx.v.i3], + input[ipx.v.i4], + input[ipx.v.i5], + input[ipx.v.i6], + input[ipx.v.i7]); + + c128.m128 = _mm_cmpeq_epi8(_mm_and_si128(a128.m128, b128.m128), b128.m128); + uint16_t o = (uint16_t) _mm_movemask_epi8(c128.m128); + *((uint16_t *) (output + i)) = o; + } + + for (; i < nof_bits / 8; i++) { + ipx.m128 = _mm_loadu_si128((__m128i *) (interleaver + i * 8 - w_offset_p)); + epx.m128 = _mm_shuffle_epi8(ipx.m128, _mm_set_epi8(0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E)); + b.m64 = _mm_and_si64(epx.m64.reg_a, _mm_set1_pi8(0x7)); + b.m64 = _mm_shuffle_pi8(m64mask, b.m64); + + ipx.m128 = _mm_srli_epi16(ipx.m128, 3); + + a.m64 = _mm_set_pi8(input[ipx.v.i0], + input[ipx.v.i1], + input[ipx.v.i2], + input[ipx.v.i3], + input[ipx.v.i4], + input[ipx.v.i5], + input[ipx.v.i6], + input[ipx.v.i7]); + + c.m64 = _mm_cmpeq_pi8(_mm_and_si64(a.m64, b.m64), b.m64); + output[i] = (uint8_t) _mm_movemask_pi8(c.m64); + } + +#if 0 + /* THIS PIECE OF CODE IS FOR CHECKING SIMD BEHAVIOUR. DO NOT ENABLE. */ + uint8_t *output2 = malloc(nof_bits/8); + for (i=st;iinput_plan, input, q->input_fft); srslte_vec_prod_ccc(q->input_fft, filter_freq, q->output_fft, q->output_len); @@ -125,7 +125,7 @@ uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q, cf_t *input, cf_t * } -uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, cf_t *input, cf_t *filter, cf_t *output) { +uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, const cf_t *input, const cf_t *filter, cf_t *output) { srslte_dft_run_c(&q->filter_plan, filter, q->filter_fft); @@ -133,7 +133,7 @@ uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, cf_t *input, cf_t *filt } -uint32_t srslte_conv_cc(cf_t *input, cf_t *filter, cf_t *output, uint32_t input_len, uint32_t filter_len) { +uint32_t srslte_conv_cc(const cf_t *input, const cf_t *filter, cf_t *output, uint32_t input_len, uint32_t filter_len) { uint32_t i; uint32_t M = filter_len; uint32_t N = input_len; diff --git a/lib/src/phy/utils/debug.c b/lib/src/phy/utils/debug.c index 423abee6c..4b65e8d6d 100644 --- a/lib/src/phy/utils/debug.c +++ b/lib/src/phy/utils/debug.c @@ -24,9 +24,17 @@ * */ +#include +#include +#include +#include +#include + #include "srslte/phy/utils/debug.h" +#include "srslte/version.h" int srslte_verbose = 0; +int handler_registered = 0; void get_time_interval(struct timeval * tdata) { @@ -37,3 +45,57 @@ void get_time_interval(struct timeval * tdata) { tdata[0].tv_usec += 1000000; } } + +const static char crash_file_name[] = "./srsLTE.backtrace.crash"; +static int bt_argc; +static char **bt_argv; + +static void crash_handler(int sig) { + void *array[128]; + int size; + + /* Get all stack traces */ + size = backtrace(array, 128); + + FILE *f = fopen(crash_file_name, "a"); + if (!f) { + printf("srsLTE crashed... we could not save backtrace in '%s'...\n", crash_file_name); + } else { + char **symbols = backtrace_symbols(array, size); + + time_t lnTime; + struct tm *stTime; + char strdate[32]; + + time(&lnTime); + stTime = localtime(&lnTime); + + strftime(strdate, 32, "%d/%m/%Y %H:%M:%S", stTime); + + fprintf(f, "--- command='"); + for (int i = 0; i < bt_argc; i++) { + fprintf(f, "%s%s", (i == 0) ? "" : " ", bt_argv[i]); + } + fprintf(f, "' version=%s signal=%d date='%s' ---\n", SRSLTE_VERSION_STRING, sig, strdate); + + for (int i = 0; i < size; i++) { + fprintf(f, "\t%s\n", symbols[i]); + } + fprintf(f, "\n"); + + printf("srsLTE crashed... backtrace saved in '%s'...\n", crash_file_name); + fclose(f); + } + printf("--- exiting ---\n"); + exit(1); +} + +void srslte_debug_handle_crash(int argc, char **argv) { + bt_argc = argc; + bt_argv = argv; + + signal(SIGSEGV, crash_handler); + signal(SIGABRT, crash_handler); + signal(SIGILL, crash_handler); + signal(SIGFPE, crash_handler); +} diff --git a/lib/src/phy/utils/mat.c b/lib/src/phy/utils/mat.c index 439daa2ce..bbfc38135 100644 --- a/lib/src/phy/utils/mat.c +++ b/lib/src/phy/utils/mat.c @@ -27,6 +27,7 @@ #include #include +#include #include "srslte/phy/utils/mat.h" diff --git a/lib/src/phy/utils/ringbuffer.c b/lib/src/phy/utils/ringbuffer.c index 86578b3ea..400f80360 100644 --- a/lib/src/phy/utils/ringbuffer.c +++ b/lib/src/phy/utils/ringbuffer.c @@ -11,10 +11,9 @@ int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity) if (!q->buffer) { return -1; } - q->capacity = capacity; - q->count = 0; - q->wpm = 0; - q->rpm = 0; + + q->capacity = capacity; + srslte_ringbuffer_reset(q); pthread_mutex_init(&q->mutex, NULL); pthread_cond_init(&q->cvar, NULL); @@ -22,7 +21,7 @@ int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity) return 0; } -void srslte_ringbuffer_free(srslte_ringbuffer_t *q, int capacity) +void srslte_ringbuffer_free(srslte_ringbuffer_t *q) { if (q) { if (q->buffer) { @@ -34,11 +33,26 @@ void srslte_ringbuffer_free(srslte_ringbuffer_t *q, int capacity) } } -int srslte_ringbuffer_write(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes) -{ +void srslte_ringbuffer_reset(srslte_ringbuffer_t *q) +{ + pthread_mutex_lock(&q->mutex); + q->count = 0; + q->wpm = 0; + q->rpm = 0; + pthread_mutex_unlock(&q->mutex); +} + +int srslte_ringbuffer_status(srslte_ringbuffer_t *q) +{ + return q->count; +} + +int srslte_ringbuffer_write(srslte_ringbuffer_t *q, void *p, int nof_bytes) +{ + uint8_t *ptr = (uint8_t*) p; int w_bytes = nof_bytes; pthread_mutex_lock(&q->mutex); - if (q->count + w_bytes >= q->capacity) { + if (q->count + w_bytes > q->capacity) { w_bytes = q->capacity - q->count; fprintf(stderr, "Buffer overrun: lost %d bytes\n", nof_bytes - w_bytes); } @@ -59,8 +73,9 @@ int srslte_ringbuffer_write(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes) return w_bytes; } -int srslte_ringbuffer_read(srslte_ringbuffer_t *q, uint8_t *ptr, int nof_bytes) +int srslte_ringbuffer_read(srslte_ringbuffer_t *q, void *p, int nof_bytes) { + uint8_t *ptr = (uint8_t*) p; pthread_mutex_lock(&q->mutex); while(q->count < nof_bytes) { pthread_cond_wait(&q->cvar, &q->mutex); diff --git a/lib/src/phy/utils/test/CMakeLists.txt b/lib/src/phy/utils/test/CMakeLists.txt index 4dccbf2a0..1f5c66827 100644 --- a/lib/src/phy/utils/test/CMakeLists.txt +++ b/lib/src/phy/utils/test/CMakeLists.txt @@ -42,3 +42,7 @@ target_link_libraries(algebra_test srslte_phy) add_test(algebra_2x2_zf_solver_test algebra_test -z) add_test(algebra_2x2_mmse_solver_test algebra_test -m) + +add_executable(vector_test vector_test.c) +target_link_libraries(vector_test srslte_phy) +add_test(vector_test vector_test) diff --git a/lib/src/phy/utils/test/mat_test.c b/lib/src/phy/utils/test/mat_test.c index 49be5c9ae..0bfb482a9 100644 --- a/lib/src/phy/utils/test/mat_test.c +++ b/lib/src/phy/utils/test/mat_test.c @@ -29,16 +29,21 @@ #include #include #include -#include #include #include "srslte/phy/utils/mat.h" +#include "srslte/phy/utils/simd.h" +#include "srslte/phy/utils/vector.h" bool zf_solver = false; bool mmse_solver = false; bool verbose = false; +#define RANDOM_F() ((float)rand())/((float)RAND_MAX) +#define RANDOM_S() ((int16_t)(rand() && 0x800F)) +#define RANDOM_CF() (RANDOM_F() + _Complex_I*RANDOM_F()) + double elapsed_us(struct timeval *ts_start, struct timeval *ts_end) { if (ts_end->tv_usec > ts_start->tv_usec) { return ((double) ts_end->tv_sec - (double) ts_start->tv_sec) * 1000000 + @@ -49,16 +54,16 @@ double elapsed_us(struct timeval *ts_start, struct timeval *ts_end) { } } -#define NOF_REPETITIONS 1000 +#define BLOCK_SIZE 1000 #define RUN_TEST(FUNCTION) /*TYPE NAME (void)*/ { \ int i;\ struct timeval start, end;\ gettimeofday(&start, NULL); \ bool ret = true; \ - for (i = 0; i < NOF_REPETITIONS; i++) {ret &= FUNCTION ();}\ + for (i = 0; i < BLOCK_SIZE; i++) {ret &= FUNCTION ();}\ gettimeofday(&end, NULL);\ if (verbose) printf("%32s: %s ... %6.2f us/call\n", #FUNCTION, (ret)?"Pass":"Fail", \ - elapsed_us(&start, &end)/NOF_REPETITIONS);\ + elapsed_us(&start, &end)/BLOCK_SIZE);\ passed &= ret;\ } @@ -373,6 +378,24 @@ bool test_mmse_solver_avx(void) { #endif /* LV_HAVE_AVX */ +bool test_vec_dot_prod_ccc(void) { + __attribute__((aligned(256))) cf_t a[14]; + __attribute__((aligned(256))) cf_t b[14]; + cf_t res = 0, gold = 0; + + for (int i = 0; i < 14; i++) { + a[i] = RANDOM_CF(); + b[i] = RANDOM_CF(); + } + + res = srslte_vec_dot_prod_ccc(a, b, 14); + + for (int i=0;i<14;i++) { + gold += a[i]*b[i]; + } + + return (cabsf(res - gold) < 1e-3); +} int main(int argc, char **argv) { bool passed = true; @@ -405,6 +428,8 @@ int main(int argc, char **argv) { #endif /* LV_HAVE_AVX */ } + RUN_TEST(test_vec_dot_prod_ccc); + printf("%s!\n", (passed) ? "Ok" : "Failed"); if (!passed) { diff --git a/lib/src/phy/utils/test/vector_test.c b/lib/src/phy/utils/test/vector_test.c new file mode 100644 index 000000000..cb7eff480 --- /dev/null +++ b/lib/src/phy/utils/test/vector_test.c @@ -0,0 +1,853 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "srslte/phy/utils/mat.h" +#include "srslte/phy/utils/simd.h" +#include "srslte/phy/utils/vector.h" + + +bool zf_solver = false; +bool mmse_solver = false; +bool verbose = false; + +#define MAX_MSE (1e-3) +#define NOF_REPETITIONS (1024) +#define MAX_FUNCTIONS (64) +#define MAX_BLOCKS (16) + + +#define RANDOM_F() ((float)rand())/((float)RAND_MAX) +#define RANDOM_S() ((int16_t)(rand() && 0x800F)) +#define RANDOM_B() ((int8_t)(rand() && 0x8008)) +#define RANDOM_CF() (RANDOM_F() + _Complex_I*RANDOM_F()) + +#define TEST_CALL(TEST_CODE) gettimeofday(&start, NULL);\ + for (int i = 0; i < NOF_REPETITIONS; i++){TEST_CODE;}\ + gettimeofday(&end, NULL); \ + *timing = elapsed_us(&start, &end); + +#define TEST(X, CODE) static bool test_##X (char *func_name, double *timing, uint32_t block_size) {\ + struct timeval start, end;\ + float mse = 0.0f;\ + bool passed;\ + strncpy(func_name, #X, 32);\ + CODE;\ + passed = (mse < MAX_MSE);\ + printf("%32s (%5d) ... %7.1f MSamp/s ... %3s Passed (%.6f)\n", func_name, block_size, \ + (double) block_size*NOF_REPETITIONS/ *timing, passed?"":"Not", mse);\ + return passed;\ +} + +#define MALLOC(TYPE, NAME) TYPE *NAME = srslte_vec_malloc(sizeof(TYPE)*block_size) + + +static double elapsed_us(struct timeval *ts_start, struct timeval *ts_end) { + if (ts_end->tv_usec > ts_start->tv_usec) { + return ((double) ts_end->tv_sec - (double) ts_start->tv_sec) * 1000000 + + (double) ts_end->tv_usec - (double) ts_start->tv_usec; + } else { + return ((double) ts_end->tv_sec - (double) ts_start->tv_sec - 1) * 1000000 + + ((double) ts_end->tv_usec + 1000000) - (double) ts_start->tv_usec; + } +} + +float squared_error (cf_t a, cf_t b) { + float diff_re = __real__ a - __real__ b; + float diff_im = __imag__ a - __imag__ b; + return diff_re*diff_re + diff_im*diff_im; +} + + TEST(srslte_vec_xor_bbb, + MALLOC(int8_t, x); + MALLOC(int8_t, y); + MALLOC(int8_t, z); + + cf_t gold = 0.0f; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_B(); + y[i] = RANDOM_B(); + } + + TEST_CALL(srslte_vec_xor_bbb(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] ^ y[i]; + mse += cabsf(gold - z[i]); + } + + free(x); + free(y); + free(z); +) + +TEST(srslte_vec_acc_ff, + MALLOC(float, x); + float z; + + cf_t gold = 0.0f; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_F(); + } + + TEST_CALL(z = srslte_vec_acc_ff(x, block_size)) + + for (int i = 0; i < block_size; i++) { + gold += x[i]; + } + + mse += fabs(gold - z) / gold; + + free(x); +) + +TEST(srslte_vec_dot_prod_sss, + MALLOC(int16_t, x); + MALLOC(int16_t, y); + int16_t z; + + cf_t gold = 0.0f; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_S(); + y[i] = RANDOM_S(); + } + + TEST_CALL(z = srslte_vec_dot_prod_sss(x, y, block_size)) + + for (int i = 0; i < block_size; i++) { + gold += x[i] * y[i]; + } + + mse += cabsf(gold - z) / cabsf(gold); + + free(x); + free(y); +) + +TEST(srslte_vec_sum_sss, + MALLOC(int16_t, x); + MALLOC(int16_t, y); + MALLOC(int16_t, z); + + cf_t gold = 0.0f; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_S(); + y[i] = RANDOM_S(); + } + + TEST_CALL(srslte_vec_sum_sss(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] + y[i]; + mse += cabsf(gold - z[i]); + } + + free(x); + free(y); + free(z); +) + +TEST(srslte_vec_sub_sss, + MALLOC(int16_t, x); + MALLOC(int16_t, y); + MALLOC(int16_t, z); + + cf_t gold = 0.0f; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_S(); + y[i] = RANDOM_S(); + } + + TEST_CALL(srslte_vec_sub_sss(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] - y[i]; + mse += cabsf(gold - z[i]); + } + + free(x); + free(y); + free(z); +) + +TEST(srslte_vec_prod_sss, + MALLOC(int16_t, x); + MALLOC(int16_t, y); + MALLOC(int16_t, z); + + cf_t gold = 0.0f; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_S(); + y[i] = RANDOM_S(); + } + + TEST_CALL(srslte_vec_prod_sss(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] * y[i]; + mse += cabsf(gold - z[i]); + } + + free(x); + free(y); + free(z); +) + +TEST(srslte_vec_acc_cc, + MALLOC(cf_t, x); + cf_t z; + + cf_t gold = 0.0f; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_F(); + } + + TEST_CALL(z = srslte_vec_acc_cc(x, block_size)) + + for (int i = 0; i < block_size; i++) { + gold += x[i]; + } + + mse += cabsf(gold - z)/cabsf(gold); + + free(x); +) + + +TEST(srslte_vec_sum_fff, + MALLOC(float, x); + MALLOC(float, y); + MALLOC(float, z); + + cf_t gold = 0.0f; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_F(); + y[i] = RANDOM_F(); + } + + TEST_CALL(srslte_vec_sum_fff(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] + y[i]; + mse += cabsf(gold - z[i]); + } + + free(x); + free(y); +) + +TEST(srslte_vec_sub_fff, + MALLOC(float, x); + MALLOC(float, y); + MALLOC(float, z); + + cf_t gold = 0.0f; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_F(); + y[i] = RANDOM_F(); + } + + TEST_CALL(srslte_vec_sub_fff(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] - y[i]; + mse += cabsf(gold - z[i]); + } + + free(x); + free(y); +) + +TEST(srslte_vec_dot_prod_ccc, + MALLOC(cf_t, x); + MALLOC(cf_t, y); + cf_t z; + + cf_t gold = 0.0f; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + y[i] = RANDOM_CF(); + } + + TEST_CALL(z = srslte_vec_dot_prod_ccc(x, y, block_size)) + + for (int i = 0; i < block_size; i++) { + gold += x[i] * y[i]; + } + + mse = cabsf(gold - z) / cabsf(gold); + + free(x); + free(y); +) + +TEST(srslte_vec_dot_prod_conj_ccc, + MALLOC(cf_t, x); + MALLOC(cf_t, y); + cf_t z; + + cf_t gold = 0.0f; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + y[i] = RANDOM_CF(); + } + + TEST_CALL(z = srslte_vec_dot_prod_conj_ccc(x, y, block_size)) + + for (int i = 0; i < block_size; i++) { + gold += x[i] * conjf(y[i]); + } + + mse = cabsf(gold - z) / cabsf(gold); + + free(x); + free(y); +) + +TEST(srslte_vec_prod_ccc, + MALLOC(cf_t, x); + MALLOC(cf_t, y); + MALLOC(cf_t, z); + + cf_t gold; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + y[i] = RANDOM_CF(); + } + + TEST_CALL(srslte_vec_prod_ccc(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] * y[i]; + mse += cabsf(gold - z[i]); + } + + free(x); + free(z); +) + +TEST(srslte_vec_prod_ccc_split, + MALLOC(float, x_re); + MALLOC(float, x_im); + MALLOC(float, y_re); + MALLOC(float, y_im); + MALLOC(float, z_re); + MALLOC(float, z_im); + + cf_t gold; + for (int i = 0; i < block_size; i++) { + x_re[i] = RANDOM_F(); + x_im[i] = RANDOM_F(); + y_re[i] = RANDOM_F(); + y_im[i] = RANDOM_F(); + } + + TEST_CALL(srslte_vec_prod_ccc_split(x_re, x_im, y_re, y_im, z_re, z_im, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = (x_re[i] + I * x_im[i]) * (y_re[i] + I * y_im[i]); + mse += cabsf(gold - (z_re[i] + I*z_im[i])); + } + + free(x_re); + free(x_im); + free(y_re); + free(y_im); + free(z_re); + free(z_im); +) + +TEST(srslte_vec_prod_conj_ccc, + MALLOC(cf_t, x); + MALLOC(cf_t, y); + MALLOC(cf_t, z); + + cf_t gold; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + y[i] = RANDOM_CF(); + } + + TEST_CALL(srslte_vec_prod_conj_ccc(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] * conjf(y[i]); + mse += cabsf(gold - z[i]); + } + + free(x); + free(z); +) + +TEST(srslte_vec_sc_prod_ccc, + MALLOC(cf_t, x); + MALLOC(cf_t, z); + cf_t y = RANDOM_CF(); + + cf_t gold; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + } + + TEST_CALL(srslte_vec_sc_prod_ccc(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] * y; + mse += cabsf(gold - z[i]); + } + + free(x); + free(z); +) + +TEST(srslte_vec_convert_fi, + MALLOC(float, x); + MALLOC(short, z); + float scale = 1000.0f; + + short gold; + for (int i = 0; i < block_size; i++) { + x[i] = (float) RANDOM_F(); + } + + TEST_CALL(srslte_vec_convert_fi(x, scale, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = (short) ((x[i] * scale)); + mse += cabsf((float)gold - (float) z[i]); + } + + free(x); + free(z); +) + +TEST(srslte_vec_prod_fff, + MALLOC(float, x); + MALLOC(float, y); + MALLOC(float, z); + + cf_t gold; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + y[i] = RANDOM_CF(); + } + + TEST_CALL(srslte_vec_prod_fff(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] * y[i]; + mse += cabsf(gold - z[i]); + } + + free(x); + free(y); + free(z); +) + +TEST(srslte_vec_prod_cfc, + MALLOC(cf_t, x); + MALLOC(float, y); + MALLOC(cf_t, z); + + cf_t gold; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + y[i] = RANDOM_F(); + } + + TEST_CALL(srslte_vec_prod_cfc(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] * y[i]; + mse += cabsf(gold - z[i]); + } + + free(x); + free(y); + free(z); +) + +TEST(srslte_vec_sc_prod_fff, + MALLOC(float, x); + MALLOC(float, z); + float y = RANDOM_F(); + + float gold; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + } + + TEST_CALL(srslte_vec_sc_prod_fff(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] * y; + mse += cabsf(gold - z[i]); + } + + free(x); + free(z); +) + +TEST(srslte_vec_abs_cf, + MALLOC(cf_t, x); + MALLOC(float, z); + float gold; + + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + } + x[0] = 0.0f; + + TEST_CALL(srslte_vec_abs_cf(x, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = sqrtf(crealf(x[i]) * crealf(x[i]) + cimagf(x[i])*cimagf(x[i])); + mse += cabsf(gold - z[i])/block_size; + } + + free(x); + free(z); +) + +TEST(srslte_vec_abs_square_cf, + MALLOC(cf_t, x); + MALLOC(float, z); + float gold; + + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + } + + TEST_CALL(srslte_vec_abs_square_cf(x, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = crealf(x[i]) * crealf(x[i]) + cimagf(x[i])*cimagf(x[i]); + mse += cabsf(gold - z[i]); + } + + free(x); + free(z); +) + +TEST(srslte_vec_sc_prod_cfc, + MALLOC(cf_t, x); + MALLOC(cf_t, z); + cf_t gold; + float h = RANDOM_F(); + + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + } + + TEST_CALL(srslte_vec_sc_prod_cfc(x, h, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] * h; + mse += cabsf(gold - z[i]); + } + + free(x); + free(z); +) + +TEST(srslte_vec_div_ccc, + MALLOC(cf_t, x); + MALLOC(cf_t, y); + MALLOC(cf_t, z); + + cf_t gold; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + y[i] = RANDOM_CF(); + } + + TEST_CALL(srslte_vec_div_ccc(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] / y[i]; + mse += cabsf(gold - z[i]); + } + mse /= block_size; + + free(x); + free(y); + free(z); +) + + +TEST(srslte_vec_div_cfc, + MALLOC(cf_t, x); + MALLOC(float, y); + MALLOC(cf_t, z); + + cf_t gold; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + y[i] = RANDOM_F(); + } + + TEST_CALL(srslte_vec_div_cfc(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] / y[i]; + mse += cabsf(gold - z[i])/cabsf(gold); + } + mse /= block_size; + + free(x); + free(y); + free(z); +) + + +TEST(srslte_vec_div_fff, + MALLOC(float, x); + MALLOC(float, y); + MALLOC(float, z); + + cf_t gold; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_F() + 0.0001; + y[i] = RANDOM_F()+ 0.0001; + } + + TEST_CALL(srslte_vec_div_fff(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] / y[i]; + mse += cabsf(gold - z[i]); + } + mse /= block_size; + + free(x); + free(y); + free(z); +) + +TEST(srslte_vec_max_fi, + MALLOC(float, x); + + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_F(); + } + + uint32_t max_index = 0; + TEST_CALL(max_index = srslte_vec_max_fi(x, block_size);) + + float gold_value = -INFINITY; + uint32_t gold_index = 0; + for (int i = 0; i < block_size; i++) { + if (gold_value < x[i]) { + gold_value = x[i]; + gold_index = i; + } + } + mse = (gold_index != max_index) ? 1:0; + + free(x); +) + +TEST(srslte_vec_max_abs_ci, + MALLOC(cf_t, x); + + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_CF(); + } + + uint32_t max_index = 0; + TEST_CALL(max_index = srslte_vec_max_abs_ci(x, block_size);) + + float gold_value = -INFINITY; + uint32_t gold_index = 0; + for (int i = 0; i < block_size; i++) { + cf_t a = x[i]; + float abs2 = __real__ a * __real__ a + __imag__ a * __imag__ a; + if (abs2 > gold_value) { + gold_value = abs2; + gold_index = (uint32_t)i; + } + } + mse = (gold_index != max_index) ? 1:0; + + free(x); +) + +int main(int argc, char **argv) { + char func_names[MAX_FUNCTIONS][32]; + double timmings[MAX_FUNCTIONS][MAX_BLOCKS]; + uint32_t sizes[32]; + uint32_t size_count = 0; + uint32_t func_count = 0; + bool passed[MAX_FUNCTIONS][MAX_BLOCKS]; + bool all_passed = true; + + for (uint32_t block_size = 1; block_size <= 1024*8; block_size *= 2) { + func_count = 0; + + + passed[func_count][size_count] = test_srslte_vec_xor_bbb(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + + passed[func_count][size_count] = test_srslte_vec_acc_ff(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_dot_prod_sss(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_sum_sss(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_sub_sss(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_prod_sss(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_acc_cc(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_sum_fff(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_sub_fff(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_dot_prod_ccc(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_dot_prod_conj_ccc(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_convert_fi(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_prod_fff(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_prod_cfc(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_prod_ccc(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_prod_ccc_split(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_prod_conj_ccc(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_sc_prod_ccc(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_sc_prod_fff(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_abs_cf(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_abs_square_cf(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_sc_prod_cfc(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_div_ccc(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_div_cfc(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_div_fff(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_max_fi(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_max_abs_ci(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + sizes[size_count] = block_size; + size_count++; + } + + char fname[68]; + FILE *f = NULL; + void * p = popen("(date +%g%m%d && hostname) | tr '\\r\\n' '__'", "r"); + if (p) { + fgets(fname, 64, p); + strncpy(fname + strnlen(fname, 64) - 1, ".tsv", 4); + f = fopen(fname, "w"); + if (f) printf("Saving benchmark results in '%s'\n", fname); + } + pclose(p); + + + printf("\n"); + printf("%32s |", "Subroutine/MSps"); + if (f) fprintf(f, "Subroutine/MSps Vs Vector size\t"); + for (int i = 0; i < size_count; i++) { + printf(" %7d", sizes[i]); + if (f) fprintf(f, "%d\t", sizes[i]); + } + printf(" |\n"); + if (f) fprintf(f, "\n"); + + for (int j = 0; j < 32; j++) { + printf("-"); + } + printf("-+-"); + for (int j = 0; j < size_count; j++) { + printf("--------"); + } + printf("-|\n"); + + for (int i = 0; i < func_count; i++) { + printf("%32s | ", func_names[i]); + if (f) fprintf(f, "%s\t", func_names[i]); + + for (int j = 0; j < size_count; j++) { + printf(" %s%7.1f\x1b[0m", (passed[i][j])?"":"\x1B[31m", (double) NOF_REPETITIONS*(double)sizes[j]/timmings[i][j]); + if (f) fprintf(f, "%.1f\t", (double) NOF_REPETITIONS*(double)sizes[j]/timmings[i][j]); + + all_passed &= passed[i][j]; + } + printf(" |\n"); + if (f) fprintf(f, "\n"); + } + + if (f) fclose(f); + + return (all_passed)?SRSLTE_SUCCESS:SRSLTE_ERROR; +} diff --git a/lib/src/phy/utils/vector.c b/lib/src/phy/utils/vector.c index d78f5d707..35457fcb5 100644 --- a/lib/src/phy/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -36,333 +36,80 @@ #include "srslte/phy/utils/bit.h" -#ifdef LV_HAVE_SSE -#include -#endif -#ifdef LV_HAVE_AVX -#include -#endif - - -#ifdef HAVE_VOLK -#include "volk/volk.h" -#endif - -#ifdef DEBUG_MODE -#warning FIXME: Disabling SSE/AVX vector code -#undef LV_HAVE_SSE -#undef LV_HAVE_AVX -#endif - - -int srslte_vec_acc_ii(int *x, uint32_t len) { - int i; - int z=0; - for (i=0;im) { - m=x[i]; - p=i; - } - } - return p; -#endif -#endif +uint32_t srslte_vec_max_fi(const float *x, const uint32_t len) { + return srslte_vec_max_fi_simd(x, len); } -int16_t srslte_vec_max_star_si(int16_t *x, uint32_t len) { -#ifdef HAVE_VOLK_MAX_STAR_S_FUNCTION - int16_t target=0; - volk_16i_max_star_16i(&target,x,len); - return target; - -#else - uint32_t i; - int16_t m=-INT16_MIN; - for (i=0;im) { - m=x[i]; - } - } - return m; -#endif +// CP autocorr +uint32_t srslte_vec_max_abs_ci(const cf_t *x, const uint32_t len) { + return srslte_vec_max_ci_simd(x, len); } -int16_t srslte_vec_max_abs_star_si(int16_t *x, uint32_t len) { - uint32_t i; - int16_t m=-INT16_MIN; - for (i=0;im) { - m=abs(x[i]); - } - } - return m; -} - -void srslte_vec_max_fff(float *x, float *y, float *z, uint32_t len) { -#ifdef HAVE_VOLK_MAX_VEC_FUNCTION - volk_32f_x2_max_32f(z,x,y,len); -#else - uint32_t i; - for (i=0;i y[i]) { - z[i] = x[i]; - } else { - z[i] = y[i]; - } - } -#endif -} - - -uint32_t srslte_vec_max_abs_ci(cf_t *x, uint32_t len) { -#ifdef HAVE_VOLK_MAX_ABS_FUNCTION_32 - uint32_t target=0; - volk_32fc_index_max_32u(&target,x,len); - return target; -#else -#ifdef HAVE_VOLK_MAX_ABS_FUNCTION_16 - uint32_t target=0; - volk_32fc_index_max_16u(&target,x,len); - return target; -#else - uint32_t i; - float m=-FLT_MAX; - uint32_t p=0; - float tmp; - for (i=0;im) { - m=tmp; - p=i; - } - } - return p; -#endif -#endif -} - -void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, float clip, uint32_t len) { +void srslte_vec_quant_fuc(const float *in, uint8_t *out, const float gain, const float offset, const float clip, const uint32_t len) { int i; int tmp; @@ -848,7 +377,7 @@ void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, flo } } -void srslte_vec_quant_suc(int16_t *in, uint8_t *out, float gain, int16_t offset, int16_t clip, uint32_t len) { +void srslte_vec_quant_suc(const int16_t *in, uint8_t *out, const float gain, const int16_t offset, const int16_t clip, const uint32_t len) { int i; int16_t tmp; @@ -862,24 +391,6 @@ void srslte_vec_quant_suc(int16_t *in, uint8_t *out, float gain, int16_t offset, } } -void srs_vec_cf_cpy(cf_t *dst, cf_t *src, int len) { - int i = 0; - -#ifdef LV_HAVE_AVX - for (; i < len - 3; i += 4) { - _mm256_store_ps((float *) &dst[i], _mm256_load_ps((float *) &src[i])); - } -#endif /* LV_HAVE_AVX */ -#ifdef LV_HAVE_SSE - for (; i < len - 1; i += 2) { - _mm_store_ps((float *) &dst[i], _mm_load_ps((float *) &src[i])); - } - for (; i < len; i++) { - ((__m64*) dst)[i] = ((__m64*) src)[i]; - } -#else - for (; i < len; i++) { - dst[i] = src[i]; - } -#endif /* LV_HAVE_SSE */ +void srs_vec_cf_cpy(const cf_t *dst, cf_t *src, int len) { + srslte_vec_cp_simd(dst, src, len); } diff --git a/lib/src/phy/utils/vector_simd.c b/lib/src/phy/utils/vector_simd.c index 7be4afc44..78286a81a 100644 --- a/lib/src/phy/utils/vector_simd.c +++ b/lib/src/phy/utils/vector_simd.c @@ -25,475 +25,1109 @@ */ -#include #include #include #include #include - -#include "srslte/phy/utils/vector_simd.h" - #include #include -#ifdef LV_HAVE_SSE -#include -#endif - -#ifdef LV_HAVE_AVX -#include -#endif +#include +#include "srslte/phy/utils/vector_simd.h" +#include "srslte/phy/utils/simd.h" -int srslte_vec_dot_prod_sss_sse(short *x, short *y, uint32_t len) -{ - int result = 0; -#ifdef LV_HAVE_SSE - unsigned int number = 0; - const unsigned int points = len / 8; +void srslte_vec_xor_bbb_simd(const int8_t *x, const int8_t *y, int8_t *z, const int len) { + int i = 0; +#if SRSLTE_SIMD_B_SIZE + if (SRSLTE_IS_ALIGNED(x) && SRSLTE_IS_ALIGNED(y) && SRSLTE_IS_ALIGNED(z)) { + for (; i < len - SRSLTE_SIMD_B_SIZE + 1; i += SRSLTE_SIMD_B_SIZE) { + simd_b_t a = srslte_simd_b_load(&x[i]); + simd_b_t b = srslte_simd_b_load(&y[i]); - const __m128i* xPtr = (const __m128i*) x; - const __m128i* yPtr = (const __m128i*) y; - - __m128i dotProdVal = _mm_setzero_si128(); + simd_b_t r = srslte_simd_b_xor(a, b); - __m128i xVal, yVal, zVal; - for(;number < points; number++){ + srslte_simd_b_store(&z[i], r); + } + } else { + for (; i < len - SRSLTE_SIMD_B_SIZE + 1; i += SRSLTE_SIMD_B_SIZE) { + simd_b_t a = srslte_simd_b_loadu(&x[i]); + simd_b_t b = srslte_simd_b_loadu(&y[i]); - xVal = _mm_load_si128(xPtr); - yVal = _mm_loadu_si128(yPtr); + simd_s_t r = srslte_simd_b_xor(a, b); - zVal = _mm_mullo_epi16(xVal, yVal); - - dotProdVal = _mm_add_epi16(dotProdVal, zVal); - - xPtr ++; - yPtr ++; + srslte_simd_b_storeu(&z[i], r); + } } +#endif /* SRSLTE_SIMD_B_SIZE */ - short dotProdVector[8]; - _mm_store_si128((__m128i*) dotProdVector, dotProdVal); - for (int i=0;i<8;i++) { - result += dotProdVector[i]; + for(; i < len; i++){ + z[i] = x[i] ^ y[i]; + } +} + +int srslte_vec_dot_prod_sss_simd(const int16_t *x, const int16_t *y, const int len) { + int i = 0; + int result = 0; +#if SRSLTE_SIMD_S_SIZE + simd_s_t simd_dotProdVal = srslte_simd_s_zero(); + if (SRSLTE_IS_ALIGNED(x) && SRSLTE_IS_ALIGNED(y)) { + for (; i < len - SRSLTE_SIMD_S_SIZE + 1; i += SRSLTE_SIMD_S_SIZE) { + simd_s_t a = srslte_simd_s_load(&x[i]); + simd_s_t b = srslte_simd_s_load(&y[i]); + + simd_s_t z = srslte_simd_s_mul(a, b); + + simd_dotProdVal = srslte_simd_s_add(simd_dotProdVal, z); + } + } else { + for (; i < len - SRSLTE_SIMD_S_SIZE + 1; i += SRSLTE_SIMD_S_SIZE) { + simd_s_t a = srslte_simd_s_loadu(&x[i]); + simd_s_t b = srslte_simd_s_loadu(&y[i]); + + simd_s_t z = srslte_simd_s_mul(a, b); + + simd_dotProdVal = srslte_simd_s_add(simd_dotProdVal, z); + } + } + __attribute__ ((aligned (SRSLTE_SIMD_S_SIZE*2))) short dotProdVector[SRSLTE_SIMD_S_SIZE]; + srslte_simd_s_store(dotProdVector, simd_dotProdVal); + for (int k = 0; k < SRSLTE_SIMD_S_SIZE; k++) { + result += dotProdVector[k]; + } +#endif /* SRSLTE_SIMD_S_SIZE */ + + for(; i < len; i++){ + result += (x[i] * y[i]); } - number = points * 8; - for(;number < len; number++){ - result += (x[number] * y[number]); - } - -#endif return result; } +void srslte_vec_sum_sss_simd(const int16_t *x, const int16_t *y, int16_t *z, const int len) { + int i = 0; +#if SRSLTE_SIMD_S_SIZE + if (SRSLTE_IS_ALIGNED(x) && SRSLTE_IS_ALIGNED(y) && SRSLTE_IS_ALIGNED(z)) { + for (; i < len - SRSLTE_SIMD_S_SIZE + 1; i += SRSLTE_SIMD_S_SIZE) { + simd_s_t a = srslte_simd_s_load(&x[i]); + simd_s_t b = srslte_simd_s_load(&y[i]); -int srslte_vec_dot_prod_sss_avx2(short *x, short *y, uint32_t len) -{ - int result = 0; -#ifdef LV_HAVE_AVX2 - unsigned int number = 0; - const unsigned int points = len / 16; + simd_s_t r = srslte_simd_s_add(a, b); - const __m256i* xPtr = (const __m256i*) x; - const __m256i* yPtr = (const __m256i*) y; - - __m256i dotProdVal = _mm256_setzero_si256(); + srslte_simd_s_store(&z[i], r); + } + } else { + for (; i < len - SRSLTE_SIMD_S_SIZE + 1; i += SRSLTE_SIMD_S_SIZE) { + simd_s_t a = srslte_simd_s_loadu(&x[i]); + simd_s_t b = srslte_simd_s_loadu(&y[i]); - __m256i xVal, yVal, zVal; - for(;number < points; number++){ + simd_s_t r = srslte_simd_s_add(a, b); - xVal = _mm256_load_si256(xPtr); - yVal = _mm256_loadu_si256(yPtr); - zVal = _mm256_mullo_epi16(xVal, yVal); - dotProdVal = _mm256_add_epi16(dotProdVal, zVal); - xPtr ++; - yPtr ++; - } - - __attribute__ ((aligned (256))) short dotProdVector[16]; - _mm256_store_si256((__m256i*) dotProdVector, dotProdVal); - for (int i=0;i<16;i++) { - result += dotProdVector[i]; + srslte_simd_s_storeu(&z[i], r); + } } +#endif /* SRSLTE_SIMD_S_SIZE */ - number = points * 16; - for(;number < len; number++){ - result += (x[number] * y[number]); + for(; i < len; i++){ + z[i] = x[i] + y[i]; } - -#endif - return result; } +void srslte_vec_sub_sss_simd(const int16_t *x, const int16_t *y, int16_t *z, const int len) { + int i = 0; +#if SRSLTE_SIMD_S_SIZE + if (SRSLTE_IS_ALIGNED(x) && SRSLTE_IS_ALIGNED(y) && SRSLTE_IS_ALIGNED(z)) { + for (; i < len - SRSLTE_SIMD_S_SIZE + 1; i += SRSLTE_SIMD_S_SIZE) { + simd_s_t a = srslte_simd_s_load(&x[i]); + simd_s_t b = srslte_simd_s_load(&y[i]); + simd_s_t r = srslte_simd_s_sub(a, b); -void srslte_vec_sum_sss_sse(short *x, short *y, short *z, uint32_t len) -{ -#ifdef LV_HAVE_SSE - unsigned int number = 0; - const unsigned int points = len / 8; + srslte_simd_s_store(&z[i], r); + } + } else { + for (; i < len - SRSLTE_SIMD_S_SIZE + 1; i += SRSLTE_SIMD_S_SIZE) { + simd_s_t a = srslte_simd_s_loadu(&x[i]); + simd_s_t b = srslte_simd_s_loadu(&y[i]); - const __m128i* xPtr = (const __m128i*) x; - const __m128i* yPtr = (const __m128i*) y; - __m128i* zPtr = (__m128i*) z; + simd_s_t r = srslte_simd_s_sub(a, b); - __m128i xVal, yVal, zVal; - for(;number < points; number++){ - - xVal = _mm_load_si128(xPtr); - yVal = _mm_load_si128(yPtr); - - zVal = _mm_add_epi16(xVal, yVal); - - _mm_store_si128(zPtr, zVal); - - xPtr ++; - yPtr ++; - zPtr ++; + srslte_simd_s_storeu(&z[i], r); + } } +#endif /* SRSLTE_SIMD_S_SIZE */ - number = points * 8; - for(;number < len; number++){ - z[number] = x[number] + y[number]; + for(; i < len; i++){ + z[i] = x[i] - y[i]; } -#endif - } -void srslte_vec_sum_sss_avx2(short *x, short *y, short *z, uint32_t len) -{ -#ifdef LV_HAVE_AVX2 - unsigned int number = 0; - const unsigned int points = len / 16; +void srslte_vec_prod_sss_simd(const int16_t *x, const int16_t *y, int16_t *z, const int len) { + int i = 0; +#if SRSLTE_SIMD_S_SIZE + if (SRSLTE_IS_ALIGNED(x) && SRSLTE_IS_ALIGNED(y) && SRSLTE_IS_ALIGNED(z)) { + for (; i < len - SRSLTE_SIMD_S_SIZE + 1; i += SRSLTE_SIMD_S_SIZE) { + simd_s_t a = srslte_simd_s_load(&x[i]); + simd_s_t b = srslte_simd_s_load(&y[i]); - const __m256i* xPtr = (const __m256i*) x; - const __m256i* yPtr = (const __m256i*) y; - __m256i* zPtr = (__m256i*) z; + simd_s_t r = srslte_simd_s_mul(a, b); - __m256i xVal, yVal, zVal; - for(;number < points; number++){ + srslte_simd_s_store(&z[i], r); + } + } else { + for (; i < len - SRSLTE_SIMD_S_SIZE + 1; i += SRSLTE_SIMD_S_SIZE) { + simd_s_t a = srslte_simd_s_loadu(&x[i]); + simd_s_t b = srslte_simd_s_loadu(&y[i]); - xVal = _mm256_load_si256(xPtr); - yVal = _mm256_loadu_si256(yPtr); + simd_s_t r = srslte_simd_s_mul(a, b); - zVal = _mm256_add_epi16(xVal, yVal); - _mm256_store_si256(zPtr, zVal); - - xPtr ++; - yPtr ++; - zPtr ++; + srslte_simd_s_storeu(&z[i], r); + } } +#endif /* SRSLTE_SIMD_S_SIZE */ - number = points * 16; - for(;number < len; number++){ - z[number] = x[number] + y[number]; + for(; i < len; i++){ + z[i] = x[i] * y[i]; } -#endif - } - -void srslte_vec_sub_sss_sse(short *x, short *y, short *z, uint32_t len) -{ -#ifdef LV_HAVE_SSE - unsigned int number = 0; - const unsigned int points = len / 8; - - const __m128i* xPtr = (const __m128i*) x; - const __m128i* yPtr = (const __m128i*) y; - __m128i* zPtr = (__m128i*) z; - - __m128i xVal, yVal, zVal; - for(;number < points; number++){ - - xVal = _mm_load_si128(xPtr); - yVal = _mm_load_si128(yPtr); - - zVal = _mm_sub_epi16(xVal, yVal); - - _mm_store_si128(zPtr, zVal); - - xPtr ++; - yPtr ++; - zPtr ++; - } - - number = points * 8; - for(;number < len; number++){ - z[number] = x[number] - y[number]; - } -#endif -} - -void srslte_vec_sub_sss_avx2(short *x, short *y, short *z, uint32_t len) -{ -#ifdef LV_HAVE_AVX2 - unsigned int number = 0; - const unsigned int points = len / 16; - - const __m256i* xPtr = (const __m256i*) x; - const __m256i* yPtr = (const __m256i*) y; - __m256i* zPtr = (__m256i*) z; - - __m256i xVal, yVal, zVal; - for(;number < points; number++){ - - xVal = _mm256_load_si256(xPtr); - yVal = _mm256_loadu_si256(yPtr); - - zVal = _mm256_sub_epi16(xVal, yVal); - - _mm256_store_si256(zPtr, zVal); - - xPtr ++; - yPtr ++; - zPtr ++; - } - - number = points * 16; - for(;number < len; number++){ - z[number] = x[number] - y[number]; - } - #endif -} - - - - -void srslte_vec_prod_sss_sse(short *x, short *y, short *z, uint32_t len) -{ -#ifdef LV_HAVE_SSE - unsigned int number = 0; - const unsigned int points = len / 8; - - const __m128i* xPtr = (const __m128i*) x; - const __m128i* yPtr = (const __m128i*) y; - __m128i* zPtr = (__m128i*) z; - - __m128i xVal, yVal, zVal; - for(;number < points; number++){ - - xVal = _mm_load_si128(xPtr); - yVal = _mm_load_si128(yPtr); - - zVal = _mm_mullo_epi16(xVal, yVal); - - _mm_store_si128(zPtr, zVal); - - xPtr ++; - yPtr ++; - zPtr ++; - } - - number = points * 8; - for(;number < len; number++){ - z[number] = x[number] * y[number]; - } -#endif -} - -void srslte_vec_prod_sss_avx2(short *x, short *y, short *z, uint32_t len) -{ -#ifdef LV_HAVE_AVX2 - unsigned int number = 0; - const unsigned int points = len / 16; - - const __m256i* xPtr = (const __m256i*) x; - const __m256i* yPtr = (const __m256i*) y; - __m256i* zPtr = (__m256i*) z; - - __m256i xVal, yVal, zVal; - for(;number < points; number++){ - - xVal = _mm256_loadu_si256(xPtr); - yVal = _mm256_loadu_si256(yPtr); - - zVal = _mm256_mullo_epi16(xVal, yVal); - - _mm256_storeu_si256(zPtr, zVal); - - xPtr ++; - yPtr ++; - zPtr ++; - } - - number = points * 16; - for(;number < len; number++){ - z[number] = x[number] * y[number]; - } -#endif -} - - - - - - -void srslte_vec_sc_div2_sss_sse(short *x, int k, short *z, uint32_t len) -{ -#ifdef LV_HAVE_SSE - unsigned int number = 0; - const unsigned int points = len / 8; - - const __m128i* xPtr = (const __m128i*) x; - __m128i* zPtr = (__m128i*) z; - - __m128i xVal, zVal; - for(;number < points; number++){ - - xVal = _mm_load_si128(xPtr); - - zVal = _mm_srai_epi16(xVal, k); - - _mm_store_si128(zPtr, zVal); - - xPtr ++; - zPtr ++; - } - - number = points * 8; - short divn = (1< max_value) { + max_value = values_buffer[k]; + max_index = (uint32_t) indexes_buffer[k]; + } + } +#endif /* SRSLTE_SIMD_I_SIZE */ + + for (; i < len; i++) { + if (x[i] > max_value) { + max_value = x[i]; + max_index = (uint32_t)i; + } + } + + return max_index; +} + +uint32_t srslte_vec_max_ci_simd(const cf_t *x, const int len) { + int i = 0; + + float max_value = -INFINITY; + uint32_t max_index = 0; + +#if SRSLTE_SIMD_I_SIZE + __attribute__ ((aligned (SRSLTE_SIMD_I_SIZE*sizeof(int)))) int indexes_buffer[SRSLTE_SIMD_I_SIZE] = {0}; + __attribute__ ((aligned (SRSLTE_SIMD_I_SIZE*sizeof(float)))) float values_buffer[SRSLTE_SIMD_I_SIZE] = {0}; + + for (int k = 0; k < SRSLTE_SIMD_I_SIZE; k++) indexes_buffer[k] = k; + simd_i_t simd_inc = srslte_simd_i_set1(SRSLTE_SIMD_I_SIZE); + simd_i_t simd_indexes = srslte_simd_i_load(indexes_buffer); + simd_i_t simd_max_indexes = srslte_simd_i_set1(0); + + simd_f_t simd_max_values = srslte_simd_f_set1(-INFINITY); + + if (SRSLTE_IS_ALIGNED(x)) { + for (; i < len - SRSLTE_SIMD_I_SIZE + 1; i += SRSLTE_SIMD_I_SIZE) { + simd_f_t x1 = srslte_simd_f_load((float *) &x[i]); + simd_f_t x2 = srslte_simd_f_load((float *) &x[i + SRSLTE_SIMD_F_SIZE / 2]); + + simd_f_t mul1 = srslte_simd_f_mul(x1, x1); + simd_f_t mul2 = srslte_simd_f_mul(x2, x2); + + simd_f_t z1 = srslte_simd_f_hadd(mul1, mul2); + + simd_sel_t res = srslte_simd_f_max(z1, simd_max_values); + + simd_max_indexes = srslte_simd_i_select(simd_max_indexes, simd_indexes, res); + simd_max_values = (simd_f_t) srslte_simd_i_select((simd_i_t) simd_max_values, (simd_i_t) z1, res); + simd_indexes = srslte_simd_i_add(simd_indexes, simd_inc); + } + } else { + for (; i < len - SRSLTE_SIMD_I_SIZE + 1; i += SRSLTE_SIMD_I_SIZE) { + simd_f_t x1 = srslte_simd_f_loadu((float *) &x[i]); + simd_f_t x2 = srslte_simd_f_loadu((float *) &x[i + SRSLTE_SIMD_F_SIZE / 2]); + + simd_f_t mul1 = srslte_simd_f_mul(x1, x1); + simd_f_t mul2 = srslte_simd_f_mul(x2, x2); + + simd_f_t z1 = srslte_simd_f_hadd(mul1, mul2); + + simd_sel_t res = srslte_simd_f_max(z1, simd_max_values); + + simd_max_indexes = srslte_simd_i_select(simd_max_indexes, simd_indexes, res); + simd_max_values = (simd_f_t) srslte_simd_i_select((simd_i_t) simd_max_values, (simd_i_t) z1, res); + simd_indexes = srslte_simd_i_add(simd_indexes, simd_inc); + } + } + + srslte_simd_i_store(indexes_buffer, simd_max_indexes); + srslte_simd_f_store(values_buffer, simd_max_values); + + for (int k = 0; k < SRSLTE_SIMD_I_SIZE; k++) { + if (values_buffer[k] > max_value) { + max_value = values_buffer[k]; + max_index = (uint32_t) indexes_buffer[k]; + } + } +#endif /* SRSLTE_SIMD_I_SIZE */ + + for (; i < len; i++) { + cf_t a = x[i]; + float abs2 = __real__ a * __real__ a + __imag__ a * __imag__ a; + if (abs2 > max_value) { + max_value = abs2; + max_index = (uint32_t)i; + } + } + + return max_index; } diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index b393a3ff4..f592db71f 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -34,9 +34,9 @@ extern "C" { namespace srslte { -bool radio::init(char *args, char *devname) +bool radio::init(char *args, char *devname, uint32_t nof_channels) { - if (srslte_rf_open_devname(&rf_device, devname, args)) { + if (srslte_rf_open_devname(&rf_device, devname, args, nof_channels)) { fprintf(stderr, "Error opening RF device\n"); return false; } @@ -59,15 +59,17 @@ bool radio::init(char *args, char *devname) } else if (strstr(srslte_rf_name(&rf_device), "bladerf")) { burst_preamble_sec = blade_default_burst_preamble_sec; } else { + burst_preamble_sec = 0; printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); } if (args) { - strncpy(saved_args, args, 128); + strncpy(saved_args, args, 127); } if (devname) { - strncpy(saved_devname, devname, 128); + strncpy(saved_devname, devname, 127); } + saved_nof_channels = nof_channels; return true; } @@ -82,7 +84,7 @@ void radio::reset() printf("Resetting Radio...\n"); srslte_rf_close(&rf_device); sleep(3); - if (srslte_rf_open_devname(&rf_device, saved_devname, saved_args)) { + if (srslte_rf_open_devname(&rf_device, saved_devname, saved_args, saved_nof_channels)) { fprintf(stderr, "Error opening RF device\n"); } } @@ -137,9 +139,9 @@ bool radio::rx_at(void* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time return false; } -bool radio::rx_now(void* buffer, uint32_t nof_samples, srslte_timestamp_t* rxd_time) +bool radio::rx_now(void* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time) { - if (srslte_rf_recv_with_time(&rf_device, buffer, nof_samples, true, + if (srslte_rf_recv_with_time_multi(&rf_device, buffer, nof_samples, true, rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) { return true; } else { @@ -186,10 +188,18 @@ bool radio::is_first_of_burst() { #define BLOCKING_TX true -bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) -{ - void *iq_samples[4] = {(void *) zeros, (void *) zeros, (void *) zeros, (void *) zeros}; +bool radio::tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) { + void *_buffer[SRSLTE_MAX_PORTS]; + _buffer[0] = buffer; + for (int p = 1; p < SRSLTE_MAX_PORTS; p++) { + _buffer[p] = zeros; + } + + return this->tx(_buffer, nof_samples, tx_time); +} + +bool radio::tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time) { if (!tx_adv_negative) { srslte_timestamp_sub(&tx_time, 0, tx_adv_sec); } else { @@ -202,7 +212,7 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) srslte_timestamp_copy(&tx_time_pad, &tx_time); srslte_timestamp_sub(&tx_time_pad, 0, burst_preamble_time_rounded); save_trace(1, &tx_time_pad); - srslte_rf_send_timed_multi(&rf_device, iq_samples, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, true, false); + srslte_rf_send_timed_multi(&rf_device, buffer, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, true, false); is_start_of_burst = false; } } @@ -212,8 +222,7 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) srslte_timestamp_add(&end_of_burst_time, 0, (double) nof_samples/cur_tx_srate); save_trace(0, &tx_time); - iq_samples[0] = buffer; - int ret = srslte_rf_send_timed_multi(&rf_device, (void**) iq_samples, nof_samples, + int ret = srslte_rf_send_timed_multi(&rf_device, buffer, nof_samples, tx_time.full_secs, tx_time.frac_secs, BLOCKING_TX, is_start_of_burst, false); is_start_of_burst = false; @@ -329,11 +338,10 @@ void radio::set_tx_srate(double srate) } burst_preamble_time_rounded = (double) burst_preamble_samples/cur_tx_srate; - int nsamples=0; /* Set time advance for each known device if in auto mode */ if (tx_adv_auto) { - + /* This values have been calibrated using the prach_test_usrp tool in srsLTE */ if (!strcmp(srslte_rf_name(&rf_device), "uhd_b200")) { @@ -355,7 +363,48 @@ void radio::set_tx_srate(double srate) /* Interpolate from known values */ printf("\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", cur_tx_srate); nsamples = cur_tx_srate*(uhd_default_tx_adv_samples * (1/cur_tx_srate) + uhd_default_tx_adv_offset_sec); - } + } + + }else if(!strcmp(srslte_rf_name(&rf_device), "uhd_usrp2")) { + double srate_khz = round(cur_tx_srate/1e3); + if (srate_khz == 1.92e3) { + nsamples = 14;// estimated + } else if (srate_khz == 3.84e3) { + nsamples = 32; + } else if (srate_khz == 5.76e3) { + nsamples = 43; + } else if (srate_khz == 11.52e3) { + nsamples = 54; + } else if (srate_khz == 15.36e3) { + nsamples = 65;// to calc + } else if (srate_khz == 23.04e3) { + nsamples = 80; // to calc + } else { + /* Interpolate from known values */ + printf("\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", cur_tx_srate); + nsamples = cur_tx_srate*(uhd_default_tx_adv_samples * (1/cur_tx_srate) + uhd_default_tx_adv_offset_sec); + } + + } else if(!strcmp(srslte_rf_name(&rf_device), "lime")) { + double srate_khz = round(cur_tx_srate/1e3); + if (srate_khz == 1.92e3) { + nsamples = 70;// estimated + } else if (srate_khz == 3.84e3) { + nsamples = 76;//estimated + } else if (srate_khz == 5.76e3) { + nsamples = 76; + } else if (srate_khz == 11.52e3) { + nsamples = 76; + } else if (srate_khz == 15.36e3) { + nsamples = 73; + } else if (srate_khz == 23.04e3) { + nsamples = 87; + } else { + /* Interpolate from known values */ + printf("\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", cur_tx_srate); + nsamples = cur_tx_srate*(uhd_default_tx_adv_samples * (1/cur_tx_srate) + uhd_default_tx_adv_offset_sec); + } + } else if (!strcmp(srslte_rf_name(&rf_device), "uhd_x300")) { // In X300 TX/RX offset is independent of sampling rate @@ -392,9 +441,9 @@ void radio::set_tx_srate(double srate) tx_adv_sec = nsamples/cur_tx_srate; } -void radio::start_rx() +void radio::start_rx(bool now) { - srslte_rf_start_rx_stream(&rf_device); + srslte_rf_start_rx_stream(&rf_device, now); } void radio::stop_rx() diff --git a/lib/src/radio/radio_multi.cc b/lib/src/radio/radio_multi.cc index 018a675ac..664458c75 100644 --- a/lib/src/radio/radio_multi.cc +++ b/lib/src/radio/radio_multi.cc @@ -4,7 +4,7 @@ namespace srslte { bool radio_multi::init_multi(uint32_t nof_rx_antennas, char* args, char* devname) { - if (srslte_rf_open_devname_multi(&rf_device, devname, args, nof_rx_antennas)) { + if (srslte_rf_open_devname(&rf_device, devname, args, nof_rx_antennas)) { fprintf(stderr, "Error opening RF device\n"); return false; } @@ -31,10 +31,10 @@ bool radio_multi::init_multi(uint32_t nof_rx_antennas, char* args, char* devname } if (args) { - strncpy(saved_args, args, 128); + strncpy(saved_args, args, 127); } if (devname) { - strncpy(saved_devname, devname, 128); + strncpy(saved_devname, devname, 127); } return true; diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index 0acc7f6bd..5d3b4d061 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -51,7 +51,19 @@ void pdcp::init(srsue::rlc_interface_pdcp *rlc_, srsue::rrc_interface_pdcp *rrc_ } void pdcp::stop() -{} +{ + for(uint32_t i=0;iinfo("Added bearer %s\n", rrc->get_rb_name(lcid).c_str()); + pdcp_log->info("Added bearer %s\n", get_rb_name(lcid)); } else { - pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", rrc->get_rb_name(lcid).c_str()); + pdcp_log->warning("Bearer %s already configured. Reconfiguration not supported\n", get_rb_name(lcid)); } } void pdcp::config_security(uint32_t lcid, - uint8_t *k_rrc_enc, - uint8_t *k_rrc_int, + uint8_t *k_enc, + uint8_t *k_int, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { if(valid_lcid(lcid)) - pdcp_array[lcid].config_security(k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + pdcp_array[lcid].config_security(k_enc, k_int, cipher_algo, integ_algo); +} + +void pdcp::config_security_all(uint8_t *k_enc, + uint8_t *k_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo) +{ + for(uint32_t i=0;idebug("Init %s\n", rrc->get_rb_name(lcid).c_str()); + log->debug("Init %s\n", get_rb_name(lcid)); +} + +void pdcp_entity::stop() +{ + if(running) { + running = false; + thread_cancel(); + wait_thread_finish(); + } +} + +// Reestablishment procedure: 36.323 5.2 +void pdcp_entity::reestablish() { + // For SRBs + if (cfg.is_control) { + tx_count = 0; + rx_count = 0; + } else { + if (rlc->rb_is_um(lcid)) { + tx_count = 0; + rx_count = 0; + } + } } void pdcp_entity::reset() { active = false; if(log) - log->debug("Reset %s\n", rrc->get_rb_name(lcid).c_str()); + log->debug("Reset %s\n", get_rb_name(lcid)); } bool pdcp_entity::is_active() @@ -74,107 +105,93 @@ bool pdcp_entity::is_active() // RRC interface void pdcp_entity::write_sdu(byte_buffer_t *sdu) { - log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU, do_security = %s", rrc->get_rb_name(lcid).c_str(), (cfg.do_security)?"true":"false"); + log->info_hex(sdu->msg, sdu->N_bytes, + "TX %s SDU, SN: %d, do_integrity = %s, do_encryption = %s", + get_rb_name(lcid), tx_count, + (do_integrity) ? "true" : "false", (do_encryption) ? "true" : "false"); if (cfg.is_control) { pdcp_pack_control_pdu(tx_count, sdu); - if(cfg.do_security) - { - integrity_generate(&k_rrc_int[16], - tx_count, - lcid-1, - cfg.direction, - sdu->msg, + if(do_integrity) { + integrity_generate(sdu->msg, sdu->N_bytes-4, &sdu->msg[sdu->N_bytes-4]); } - tx_count++; } if (cfg.is_data) { if(12 == cfg.sn_len) { - pdcp_pack_data_pdu_long_sn(tx_count++, sdu); + pdcp_pack_data_pdu_long_sn(tx_count, sdu); } else { - pdcp_pack_data_pdu_short_sn(tx_count++, sdu); + pdcp_pack_data_pdu_short_sn(tx_count, sdu); } } + if(do_encryption) { + cipher_encrypt(&sdu->msg[sn_len_bytes], + sdu->N_bytes-sn_len_bytes, + &sdu->msg[sn_len_bytes]); + log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU (encrypted)", get_rb_name(lcid)); + } + tx_count++; + rlc->write_sdu(lcid, sdu); } -void pdcp_entity::config_security(uint8_t *k_rrc_enc_, - uint8_t *k_rrc_int_, +void pdcp_entity::config_security(uint8_t *k_enc_, + uint8_t *k_int_, CIPHERING_ALGORITHM_ID_ENUM cipher_algo_, INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) { - cfg.do_security = true; for(int i=0; i<32; i++) { - k_rrc_enc[i] = k_rrc_enc_[i]; - k_rrc_int[i] = k_rrc_int_[i]; + k_enc[i] = k_enc_[i]; + k_int[i] = k_int_[i]; } cipher_algo = cipher_algo_; integ_algo = integ_algo_; } +void pdcp_entity::enable_integrity() +{ + do_integrity = true; +} + +void pdcp_entity::enable_encryption() +{ + do_encryption = true; +} + // RLC interface void pdcp_entity::write_pdu(byte_buffer_t *pdu) { - - - - - - if (cfg.is_data) { - uint32_t sn; - if(12 == cfg.sn_len) - { - pdcp_unpack_data_pdu_long_sn(pdu, &sn); - } else { - pdcp_unpack_data_pdu_short_sn(pdu, &sn); - } - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU: %d", rrc->get_rb_name(lcid).c_str(), sn); - gw->write_pdu(lcid, pdu); - } else { - if (cfg.is_control) { - uint32_t sn; - pdcp_unpack_control_pdu(pdu, &sn); - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s SDU SN: %d", - rrc->get_rb_name(lcid).c_str(), sn); - } else { - log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", rrc->get_rb_name(lcid).c_str()); - } - // pass to RRC - rrc->write_pdu(lcid, pdu); - } + rx_pdu_queue.write(pdu); } -void pdcp_entity::integrity_generate( uint8_t *key_128, - uint32_t count, - uint8_t rb_id, - uint8_t direction, - uint8_t *msg, +void pdcp_entity::integrity_generate( uint8_t *msg, uint32_t msg_len, uint8_t *mac) { + uint8_t bearer; + switch(integ_algo) { case INTEGRITY_ALGORITHM_ID_EIA0: break; case INTEGRITY_ALGORITHM_ID_128_EIA1: - security_128_eia1(key_128, - count, - rb_id, - direction, + security_128_eia1(&k_int[16], + tx_count, + get_bearer_id(lcid), + cfg.direction, msg, msg_len, mac); break; case INTEGRITY_ALGORITHM_ID_128_EIA2: - security_128_eia2(key_128, - count, - rb_id, - direction, + security_128_eia2(&k_int[16], + tx_count, + get_bearer_id(lcid), + cfg.direction, msg, msg_len, mac); @@ -184,6 +201,213 @@ void pdcp_entity::integrity_generate( uint8_t *key_128, } } +bool pdcp_entity::integrity_verify(uint8_t *msg, + uint32_t count, + uint32_t msg_len, + uint8_t *mac) +{ + uint8_t mac_exp[4] = {0x00}; + uint8_t i = 0; + bool isValid = true; + + switch(integ_algo) + { + case INTEGRITY_ALGORITHM_ID_EIA0: + break; + case INTEGRITY_ALGORITHM_ID_128_EIA1: + security_128_eia1(&k_int[16], + count, + get_bearer_id(lcid), + (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + msg, + msg_len, + mac_exp); + break; + case INTEGRITY_ALGORITHM_ID_128_EIA2: + security_128_eia2(&k_int[16], + count, + get_bearer_id(lcid), + (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + msg, + msg_len, + mac_exp); + break; + default: + break; + } + + switch(integ_algo) + { + case INTEGRITY_ALGORITHM_ID_EIA0: + break; + case INTEGRITY_ALGORITHM_ID_128_EIA1: // Intentional fall-through + case INTEGRITY_ALGORITHM_ID_128_EIA2: + for(i=0; i<4; i++){ + if(mac[i] != mac_exp[i]){ + log->error_hex(mac_exp, 4, "MAC mismatch (expected)"); + log->error_hex(mac, 4, "MAC mismatch (found)"); + isValid = false; + break; + } + } + if (isValid){ + log->info_hex(mac_exp, 4, "MAC match (expected)"); + log->info_hex(mac, 4, "MAC match (found)"); + } + break; + default: + break; + } + + return isValid; +} + +void pdcp_entity::cipher_encrypt(uint8_t *msg, + uint32_t msg_len, + uint8_t *ct) +{ + byte_buffer_t ct_tmp; + switch(cipher_algo) + { + case CIPHERING_ALGORITHM_ID_EEA0: + break; + case CIPHERING_ALGORITHM_ID_128_EEA1: + security_128_eea1(&(k_enc[16]), + tx_count, + get_bearer_id(lcid), + cfg.direction, + msg, + msg_len, + ct_tmp.msg); + memcpy(ct, ct_tmp.msg, msg_len); + break; + case CIPHERING_ALGORITHM_ID_128_EEA2: + security_128_eea2(&(k_enc[16]), + tx_count, + get_bearer_id(lcid), + cfg.direction, + msg, + msg_len, + ct_tmp.msg); + memcpy(ct, ct_tmp.msg, msg_len); + break; + default: + break; + } +} + +void pdcp_entity::cipher_decrypt(uint8_t *ct, + uint32_t count, + uint32_t ct_len, + uint8_t *msg) +{ + byte_buffer_t msg_tmp; + switch(cipher_algo) + { + case CIPHERING_ALGORITHM_ID_EEA0: + break; + case CIPHERING_ALGORITHM_ID_128_EEA1: + security_128_eea1(&(k_enc[16]), + count, + get_bearer_id(lcid), + (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + ct, + ct_len, + msg_tmp.msg); + memcpy(msg, msg_tmp.msg, ct_len); + break; + case CIPHERING_ALGORITHM_ID_128_EEA2: + security_128_eea2(&(k_enc[16]), + count, + get_bearer_id(lcid), + (cfg.direction == SECURITY_DIRECTION_DOWNLINK) ? (SECURITY_DIRECTION_UPLINK) : (SECURITY_DIRECTION_DOWNLINK), + ct, + ct_len, + msg_tmp.msg); + memcpy(msg, msg_tmp.msg, ct_len); + break; + default: + break; + } +} + + +void pdcp_entity::run_thread() +{ + byte_buffer_t *pdu; + running = true; + + while(running) { + rx_pdu_queue.read(&pdu); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU, do_integrity = %s, do_encryption = %s", + get_rb_name(lcid), (do_integrity) ? "true" : "false", (do_encryption) ? "true" : "false"); + + // Handle SRB messages + switch(lcid) + { + case RB_ID_SRB0: + // Simply pass on to RRC + rrc->write_pdu(RB_ID_SRB0, pdu); + break; + case RB_ID_SRB1: // Intentional fall-through + case RB_ID_SRB2: + uint32_t sn; + if (do_encryption) { + cipher_decrypt(&(pdu->msg[sn_len_bytes]), + rx_count, + pdu->N_bytes - sn_len_bytes, + &(pdu->msg[sn_len_bytes])); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU (decrypted)", get_rb_name(lcid)); + } + + if (do_integrity) { + integrity_verify(pdu->msg, + rx_count, + pdu->N_bytes - 4, + &(pdu->msg[pdu->N_bytes - 4])); + } + + pdcp_unpack_control_pdu(pdu, &sn); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU SN: %d", get_rb_name(lcid), sn); + rrc->write_pdu(lcid, pdu); + break; + } + + // Handle DRB messages + if(lcid >= RB_ID_DRB1) + { + uint32_t sn; + if (do_encryption) { + cipher_decrypt(&(pdu->msg[sn_len_bytes]), + rx_count, + pdu->N_bytes - sn_len_bytes, + &(pdu->msg[sn_len_bytes])); + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU (decrypted)", get_rb_name(lcid)); + } + if(12 == cfg.sn_len) + { + pdcp_unpack_data_pdu_long_sn(pdu, &sn); + } else { + pdcp_unpack_data_pdu_short_sn(pdu, &sn); + } + log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU SN: %d", get_rb_name(lcid), sn); + gw->write_pdu(lcid, pdu); + } + + rx_count++; + } +} + +uint8_t pdcp_entity::get_bearer_id(uint8_t lcid) +{ + if(lcid <= RB_ID_SRB2) { + return lcid - 1; + } else { + return lcid - RB_ID_SRB2 - 1; + } +} + + /**************************************************************************** * Pack/Unpack helper functions * Ref: 3GPP TS 36.323 v10.1.0 diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index f506ebc63..16319c268 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -95,6 +95,14 @@ void rlc::get_metrics(rlc_metrics_t &m) reset_metrics(); } +void rlc::reestablish() { + for(uint32_t i=0; iget_rb_name(lcid); +bool rlc::rb_is_um(uint32_t lcid) { + return rlc_array[lcid].get_mode()==RLC_MODE_UM; } /******************************************************************************* @@ -217,11 +224,10 @@ void rlc::add_bearer(uint32_t lcid) cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS0; add_bearer(lcid, srslte_rlc_config_t(&cnfg)); } else { - rlc_log->warning("Bearer %s already configured. Reconfiguration not supported\n", get_rb_name(lcid).c_str()); + rlc_log->warning("Bearer %s already configured. Reconfiguration not supported\n", get_rb_name(lcid)); } }else{ - rlc_log->error("Radio bearer %s does not support default RLC configuration.\n", - get_rb_name(lcid).c_str()); + rlc_log->error("Radio bearer %s does not support default RLC configuration.\n", get_rb_name(lcid)); } } @@ -234,7 +240,7 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg) if (!rlc_array[lcid].active()) { rlc_log->info("Adding radio bearer %s with mode %s\n", - get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg.rlc_mode]); + get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg.rlc_mode]); switch(cnfg.rlc_mode) { case LIBLTE_RRC_RLC_MODE_AM: @@ -254,7 +260,7 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg) return; } } else { - rlc_log->warning("Bearer %s already created.\n", get_rb_name(lcid).c_str()); + rlc_log->warning("Bearer %s already created.\n", get_rb_name(lcid)); } rlc_array[lcid].configure(cnfg); diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index b62a7e88e..c048133d6 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -79,7 +79,7 @@ void rlc_am::configure(srslte_rlc_config_t cfg_) cfg = cfg_.am; log->info("%s configured: t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, " "t_reordering=%d, t_status_prohibit=%d\n", - rrc->get_rb_name(lcid).c_str(), cfg.t_poll_retx, cfg.poll_pdu, cfg.poll_byte, cfg.max_retx_thresh, + get_rb_name(lcid), cfg.t_poll_retx, cfg.poll_pdu, cfg.poll_byte, cfg.max_retx_thresh, cfg.t_reordering, cfg.t_status_prohibit); } @@ -175,7 +175,7 @@ uint32_t rlc_am::get_bearer() void rlc_am::write_sdu(byte_buffer_t *sdu) { - log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", get_rb_name(lcid)); tx_sdu_queue.write(sdu); } @@ -201,8 +201,14 @@ uint32_t rlc_am::get_total_buffer_state() rlc_amd_retx_t retx = retx_queue.front(); log->debug("Buffer state - retx - SN: %d, Segment: %s, %d:%d\n", retx.sn, retx.is_segment ? "true" : "false", retx.so_start, retx.so_end); if(tx_window.end() != tx_window.find(retx.sn)) { - n_bytes += required_buffer_size(retx); + int req_bytes = required_buffer_size(retx); + if (req_bytes < 0) { + log->error("In get_total_buffer_state(): Removing retx.sn=%d from queue\n", retx.sn); + retx_queue.pop_front(); + } else { + n_bytes += req_bytes; log->debug("Buffer state - retx: %d bytes\n", n_bytes); + } } } @@ -250,7 +256,13 @@ uint32_t rlc_am::get_buffer_state() rlc_amd_retx_t retx = retx_queue.front(); log->debug("Buffer state - retx - SN: %d, Segment: %s, %d:%d\n", retx.sn, retx.is_segment ? "true" : "false", retx.so_start, retx.so_end); if(tx_window.end() != tx_window.find(retx.sn)) { - n_bytes = required_buffer_size(retx); + int req_bytes = required_buffer_size(retx); + if (req_bytes < 0) { + log->error("In get_buffer_state(): Removing retx.sn=%d from queue\n", retx.sn); + retx_queue.pop_front(); + goto unlock_and_return; + } + n_bytes = (uint32_t) req_bytes; log->debug("Buffer state - retx: %d bytes\n", n_bytes); goto unlock_and_return; } @@ -296,8 +308,9 @@ int rlc_am::read_pdu(uint8_t *payload, uint32_t nof_bytes) } // RETX if required if(retx_queue.size() > 0) { + int ret = build_retx_pdu(payload, nof_bytes); pthread_mutex_unlock(&mutex); - return build_retx_pdu(payload, nof_bytes); + return ret; } // Build a PDU from SDUs @@ -346,7 +359,7 @@ void rlc_am::check_reordering_timeout() if(reordering_timeout.is_running() && reordering_timeout.expired()) { reordering_timeout.reset(); - log->debug("%s reordering timeout expiry - updating vr_ms\n", rrc->get_rb_name(lcid).c_str()); + log->debug("%s reordering timeout expiry - updating vr_ms\n", get_rb_name(lcid)); // 36.322 v10 Section 5.1.3.2.4 vr_ms = vr_x; @@ -381,6 +394,18 @@ bool rlc_am::poll_required() return true; if(poll_retx()) return true; + + if(tx_sdu_queue.size() == 0 && retx_queue.size() == 0) + return true; + + /* According to 5.2.2.1 in 36.322 v13.3.0 a poll should be requested if + * the entire AM window is unacknowledged, i.e. no new PDU can be transmitted. + * However, it seems more appropiate to request more often if polling + * is disabled otherwise, e.g. every N PDUs. + */ + if (cfg.poll_pdu == 0 && cfg.poll_byte == 0 && vt_s % poll_periodicity == 0) + return true; + return false; } @@ -408,7 +433,7 @@ int rlc_am::build_status_pdu(uint8_t *payload, uint32_t nof_bytes) if(pdu_len > 0 && nof_bytes >= (uint32_t)pdu_len) { log->info("%s Tx status PDU - %s\n", - rrc->get_rb_name(lcid).c_str(), rlc_am_to_string(&status).c_str()); + get_rb_name(lcid), rlc_am_to_string(&status).c_str()); do_status = false; poll_received = false; @@ -419,24 +444,41 @@ int rlc_am::build_status_pdu(uint8_t *payload, uint32_t nof_bytes) return rlc_am_write_status_pdu(&status, payload); }else{ log->warning("%s Cannot tx status PDU - %d bytes available, %d bytes required\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, pdu_len); + get_rb_name(lcid), nof_bytes, pdu_len); return 0; } } int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) { + // Check there is at least 1 element before calling front() + if (retx_queue.empty()) { + log->error("In build_retx_pdu(): retx_queue is empty\n"); + return -1; + } + rlc_amd_retx_t retx = retx_queue.front(); // Sanity check - drop any retx SNs not present in tx_window while(tx_window.end() == tx_window.find(retx.sn)) { retx_queue.pop_front(); - retx = retx_queue.front(); + if (!retx_queue.empty()) { + retx = retx_queue.front(); + } else { + log->error("In build_retx_pdu(): retx_queue is empty during sanity check\n"); + return -1; + } } // Is resegmentation needed? - if(retx.is_segment || required_buffer_size(retx) > (int)nof_bytes) { - log->debug("%s build_retx_pdu - resegmentation required\n", rrc->get_rb_name(lcid).c_str()); + int req_size = required_buffer_size(retx); + if (req_size < 0) { + log->error("In build_retx_pdu(): Removing retx.sn=%d from queue\n", retx.sn); + retx_queue.pop_front(); + return -1; + } + if(retx.is_segment || req_size > (int)nof_bytes) { + log->debug("%s build_retx_pdu - resegmentation required\n", get_rb_name(lcid)); return build_segment(payload, nof_bytes, retx); } @@ -461,7 +503,7 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_window[retx.sn].retx_count >= cfg.max_retx_thresh) rrc->max_retx_attempted(); log->info("%s Retx PDU scheduled for tx. SN: %d, retx count: %d\n", - rrc->get_rb_name(lcid).c_str(), retx.sn, tx_window[retx.sn].retx_count); + get_rb_name(lcid), retx.sn, tx_window[retx.sn].retx_count); debug_state(); return (ptr-payload) + tx_window[retx.sn].buf->N_bytes; @@ -469,6 +511,10 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx) { + if (!tx_window[retx.sn].buf) { + log->error("In build_segment: retx.sn=%d has null buffer\n", retx.sn); + return 0; + } if(!retx.is_segment){ retx.so_start = 0; retx.so_end = tx_window[retx.sn].buf->N_bytes; @@ -494,7 +540,7 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r if(nof_bytes <= head_len) { log->warning("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); + get_rb_name(lcid), nof_bytes, head_len); return 0; } pdu_space = nof_bytes-head_len; @@ -560,15 +606,15 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r memcpy(ptr, data, len); log->info("%s Retx PDU segment scheduled for tx. SN: %d, SO: %d\n", - rrc->get_rb_name(lcid).c_str(), retx.sn, retx.so_start); + get_rb_name(lcid), retx.sn, retx.so_start); debug_state(); int pdu_len = (ptr-payload) + len; if(pdu_len > (int)nof_bytes) { log->error("%s Retx PDU segment length error. Available: %d, Used: %d\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, pdu_len); + get_rb_name(lcid), nof_bytes, pdu_len); log->debug("%s Retx PDU segment length error. Header len: %d, Payload len: %d, N_li: %d\n", - rrc->get_rb_name(lcid).c_str(), (ptr-payload), len, new_header.N_li); + get_rb_name(lcid), (ptr-payload), len, new_header.N_li); } return pdu_len; @@ -613,16 +659,16 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t pdu_space = nof_bytes; uint8_t *pdu_ptr = pdu->msg; - if(pdu_space <= head_len) + if(pdu_space <= head_len + 1) { log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); + get_rb_name(lcid), nof_bytes, head_len); pool->deallocate(pdu); return 0; } log->debug("%s Building PDU - pdu_space: %d, head_len: %d \n", - rrc->get_rb_name(lcid).c_str(), pdu_space, head_len); + get_rb_name(lcid), pdu_space, head_len); // Check for SDU segment if(tx_sdu) @@ -637,7 +683,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + get_rb_name(lcid), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -648,11 +694,11 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", - rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len); + get_rb_name(lcid), to_move, pdu_space, head_len); } // Pull SDUs from queue - while(pdu_space > head_len && tx_sdu_queue.size() > 0) + while(pdu_space > head_len + 1 && tx_sdu_queue.size() > 0) { if(last_li > 0) header.li[header.N_li++] = last_li; @@ -672,7 +718,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + get_rb_name(lcid), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -682,7 +728,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) pdu_space = 0; log->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d \n", - rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len); + get_rb_name(lcid), to_move, pdu_space, head_len); } if(tx_sdu) @@ -691,11 +737,11 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) // Set Poll bit pdu_without_poll++; byte_without_poll += (pdu->N_bytes + head_len); - log->debug("%s pdu_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), pdu_without_poll); - log->debug("%s byte_without_poll: %d\n", rrc->get_rb_name(lcid).c_str(), byte_without_poll); + log->debug("%s pdu_without_poll: %d\n", get_rb_name(lcid), pdu_without_poll); + log->debug("%s byte_without_poll: %d\n", get_rb_name(lcid), byte_without_poll); if(poll_required()) { - log->debug("%s setting poll bit to request status\n", rrc->get_rb_name(lcid).c_str()); + log->debug("%s setting poll bit to request status\n", get_rb_name(lcid)); header.p = 1; poll_sn = vt_s; pdu_without_poll = 0; @@ -706,7 +752,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) // Set SN header.sn = vt_s; vt_s = (vt_s + 1)%MOD; - log->info("%s PDU scheduled for tx. SN: %d\n", rrc->get_rb_name(lcid).c_str(), header.sn); + log->info("%s PDU scheduled for tx. SN: %d\n", get_rb_name(lcid), header.sn); // Place PDU in tx_window, write header and TX tx_window[header.sn].buf = pdu; @@ -727,26 +773,26 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h std::map::iterator it; log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d", - rrc->get_rb_name(lcid).c_str(), header.sn); + get_rb_name(lcid), header.sn); if(!inside_rx_window(header.sn)) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); do_status = true; } log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - rrc->get_rb_name(lcid).c_str(), header.sn, vr_r, vr_mr); + get_rb_name(lcid), header.sn, vr_r, vr_mr); return; } it = rx_window.find(header.sn); if(rx_window.end() != it) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); do_status = true; } log->info("%s Discarding duplicate SN: %d\n", - rrc->get_rb_name(lcid).c_str(), header.sn); + get_rb_name(lcid), header.sn); return; } @@ -779,7 +825,7 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h // Check poll bit if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); poll_received = true; // 36.322 v10 Section 5.2.3 @@ -824,16 +870,16 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a std::map::iterator it; log->info_hex(payload, nof_bytes, "%s Rx data PDU segment. SN: %d, SO: %d", - rrc->get_rb_name(lcid).c_str(), header.sn, header.so); + get_rb_name(lcid), header.sn, header.so); // Check inside rx window if(!inside_rx_window(header.sn)) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); do_status = true; } log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - rrc->get_rb_name(lcid).c_str(), header.sn, vr_r, vr_mr); + get_rb_name(lcid), header.sn, vr_r, vr_mr); return; } @@ -852,7 +898,7 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a if(rx_segments.end() != it) { if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); do_status = true; } @@ -882,7 +928,7 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a // Check poll bit if(header.p) { - log->info("%s Status packet requested through polling bit\n", rrc->get_rb_name(lcid).c_str()); + log->info("%s Status packet requested through polling bit\n", get_rb_name(lcid)); poll_received = true; // 36.322 v10 Section 5.2.3 @@ -900,12 +946,12 @@ void rlc_am::handle_data_pdu_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) { - log->info_hex(payload, nof_bytes, "%s Rx control PDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(payload, nof_bytes, "%s Rx control PDU", get_rb_name(lcid)); rlc_status_pdu_t status; rlc_am_read_status_pdu(payload, nof_bytes, &status); - log->info("%s Rx Status PDU: %s\n", rrc->get_rb_name(lcid).c_str(), rlc_am_to_string(&status).c_str()); + log->info("%s Rx Status PDU: %s\n", get_rb_name(lcid), rlc_am_to_string(&status).c_str()); poll_retx_timeout.reset(); @@ -943,7 +989,7 @@ void rlc_am::handle_control_pdu(uint8_t *payload, uint32_t nof_bytes) } } else { log->warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d\n", - rrc->get_rb_name(lcid).c_str(), i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes); + get_rb_name(lcid), i, status.nacks[j].so_start, status.nacks[j].so_end, it->second.buf->N_bytes); } } @@ -997,7 +1043,7 @@ void rlc_am::reassemble_rx_sdus() rx_sdu->N_bytes += len; rx_window[vr_r].buf->msg += len; rx_window[vr_r].buf->N_bytes -= len; - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", get_rb_name(lcid)); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -1013,7 +1059,7 @@ void rlc_am::reassemble_rx_sdus() rx_sdu->N_bytes += rx_window[vr_r].buf->N_bytes; if(rlc_am_end_aligned(rx_window[vr_r].header.fi)) { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", get_rb_name(lcid)); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -1057,7 +1103,7 @@ void rlc_am::debug_state() { log->debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d " "vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d\n", - rrc->get_rb_name(lcid).c_str(), vt_a, vt_ms, vt_s, poll_sn, + get_rb_name(lcid), vt_a, vt_ms, vt_s, poll_sn, vr_r, vr_mr, vr_x, vr_ms, vr_h); } @@ -1135,7 +1181,17 @@ bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pd int rlc_am::required_buffer_size(rlc_amd_retx_t retx) { if(!retx.is_segment){ - return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; + if (tx_window.count(retx.sn)) { + if (tx_window[retx.sn].buf) { + return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; + } else { + log->warning("retx.sn=%d has null ptr in required_buffer_size()\n", retx.sn); + return -1; + } + } else { + log->warning("retx.sn=%d does not exist in required_buffer_size()\n", retx.sn); + return -1; + } } // Construct new header diff --git a/lib/src/upper/rlc_entity.cc b/lib/src/upper/rlc_entity.cc index 5a351162a..81692889c 100644 --- a/lib/src/upper/rlc_entity.cc +++ b/lib/src/upper/rlc_entity.cc @@ -70,6 +70,10 @@ void rlc_entity::configure(srslte_rlc_config_t cnfg) rlc->configure(cnfg); } +void rlc_entity::reestablish() { + rlc->reset(); +} + void rlc_entity::reset() { rlc->reset(); diff --git a/lib/src/upper/rlc_tm.cc b/lib/src/upper/rlc_tm.cc index 627752494..4559dd07b 100644 --- a/lib/src/upper/rlc_tm.cc +++ b/lib/src/upper/rlc_tm.cc @@ -84,7 +84,7 @@ uint32_t rlc_tm::get_bearer() // PDCP interface void rlc_tm::write_sdu(byte_buffer_t *sdu) { - log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", get_rb_name(lcid)); ul_queue.write(sdu); } @@ -104,7 +104,7 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t pdu_size = ul_queue.size_tail_bytes(); if(pdu_size > nof_bytes) { - log->error("TX %s PDU size larger than MAC opportunity\n", rrc->get_rb_name(lcid).c_str()); + log->error("TX %s PDU size larger than MAC opportunity\n", get_rb_name(lcid)); return 0; } byte_buffer_t *buf; @@ -112,9 +112,9 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes) pdu_size = buf->N_bytes; memcpy(payload, buf->msg, buf->N_bytes); log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), buf->get_latency_us()); + get_rb_name(lcid), buf->get_latency_us()); pool->deallocate(buf); - log->info_hex(payload, pdu_size, "TX %s, %s PDU", rrc->get_rb_name(lcid).c_str(), rlc_mode_text[RLC_MODE_TM]); + log->info_hex(payload, pdu_size, "TX %s, %s PDU", get_rb_name(lcid), rlc_mode_text[RLC_MODE_TM]); return pdu_size; } diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc index b2697178c..5b395228f 100644 --- a/lib/src/upper/rlc_um.cc +++ b/lib/src/upper/rlc_um.cc @@ -75,18 +75,18 @@ void rlc_um::configure(srslte_rlc_config_t cnfg_) case LIBLTE_RRC_RLC_MODE_UM_BI: log->info("%s configured in %s mode: " "t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n", - rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], + get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]); break; case LIBLTE_RRC_RLC_MODE_UM_UNI_UL: log->info("%s configured in %s mode: tx_sn_field_length=%u bits\n", - rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], + get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], rlc_umd_sn_size_num[cfg.rx_sn_field_length]); break; case LIBLTE_RRC_RLC_MODE_UM_UNI_DL: log->info("%s configured in %s mode: " "t_reordering=%d ms, rx_sn_field_length=%u bits\n", - rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], + get_rb_name(lcid), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode], cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]); break; default: @@ -153,7 +153,7 @@ uint32_t rlc_um::get_bearer() void rlc_um::write_sdu(byte_buffer_t *sdu) { - log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", rrc->get_rb_name(lcid).c_str()); + log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU", get_rb_name(lcid)); tx_sdu_queue.write(sdu); } @@ -216,7 +216,7 @@ void rlc_um::timer_expired(uint32_t timeout_id) // 36.322 v10 Section 5.1.2.2.4 log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n", - rrc->get_rb_name(lcid).c_str()); + get_rb_name(lcid)); log->warning("Lost PDU SN: %d\n", vr_ur); pdu_lost = true; @@ -277,10 +277,11 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) int head_len = rlc_um_packed_length(&header); int pdu_space = nof_bytes; - if(pdu_space <= head_len) + if(pdu_space <= head_len + 1) { + pool->deallocate(pdu); log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n", - rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len); + get_rb_name(lcid), nof_bytes, head_len); return 0; } @@ -290,7 +291,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t space = pdu_space-head_len; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n", - rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes); + get_rb_name(lcid), to_move, tx_sdu->N_bytes); memcpy(pdu_ptr, tx_sdu->msg, to_move); last_li = to_move; pdu_ptr += to_move; @@ -300,7 +301,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + get_rb_name(lcid), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -309,7 +310,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) } // Pull SDUs from queue - while(pdu_space > head_len && tx_sdu_queue.size() > 0) + while(pdu_space > head_len + 1 && tx_sdu_queue.size() > 0) { log->debug("pdu_space=%d, head_len=%d\n", pdu_space, head_len); if(last_li > 0) @@ -319,7 +320,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t space = pdu_space-head_len; to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space; log->debug("%s adding new SDU segment - %d bytes of %d remaining\n", - rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes); + get_rb_name(lcid), to_move, tx_sdu->N_bytes); memcpy(pdu_ptr, tx_sdu->msg, to_move); last_li = to_move; pdu_ptr += to_move; @@ -329,7 +330,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) if(tx_sdu->N_bytes == 0) { log->info("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", - rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us()); + get_rb_name(lcid), tx_sdu->get_latency_us()); pool->deallocate(tx_sdu); tx_sdu = NULL; } @@ -344,11 +345,11 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) vt_us = (vt_us + 1)%cfg.tx_mod; // Add header and TX - log->debug("%s packing PDU with length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes); + log->debug("%s packing PDU with length %d\n", get_rb_name(lcid), pdu->N_bytes); rlc_um_write_data_pdu_header(&header, pdu); memcpy(payload, pdu->msg, pdu->N_bytes); uint32_t ret = pdu->N_bytes; - log->debug("%sreturning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes); + log->debug("%s returning length %d\n", get_rb_name(lcid), pdu->N_bytes); pool->deallocate(pdu); debug_state(); @@ -362,20 +363,20 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes) rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header); log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d", - rrc->get_rb_name(lcid).c_str(), header.sn); + get_rb_name(lcid), header.sn); if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) && RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur)) { log->info("%s SN: %d outside rx window [%d:%d] - discarding\n", - rrc->get_rb_name(lcid).c_str(), header.sn, vr_ur, vr_uh); + get_rb_name(lcid), header.sn, vr_ur, vr_uh); return; } it = rx_window.find(header.sn); if(rx_window.end() != it) { log->info("%s Discarding duplicate SN: %d\n", - rrc->get_rb_name(lcid).c_str(), header.sn); + get_rb_name(lcid), header.sn); return; } @@ -450,7 +451,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", get_rb_name(lcid), vr_ur, i); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -470,7 +471,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (lower edge last segments)\n"); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (lower edge last segments)", get_rb_name(lcid), vr_ur); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -504,7 +505,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", get_rb_name(lcid), vr_ur, i); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -533,7 +534,7 @@ void rlc_um::reassemble_rx_sdus() log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n"); rx_sdu->reset(); } else { - log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur); + log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", get_rb_name(lcid), vr_ur); rx_sdu->set_timestamp(); pdcp->write_pdu(lcid, rx_sdu); rx_sdu = pool_allocate; @@ -563,7 +564,7 @@ bool rlc_um::inside_reordering_window(uint16_t sn) void rlc_um::debug_state() { log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n", - rrc->get_rb_name(lcid).c_str(), vt_us, vr_ur, vr_ux, vr_uh); + get_rb_name(lcid), vt_us, vr_ur, vr_ux, vr_uh); } diff --git a/lib/test/CMakeLists.txt b/lib/test/CMakeLists.txt index a1af8153c..72e9e9100 100644 --- a/lib/test/CMakeLists.txt +++ b/lib/test/CMakeLists.txt @@ -18,5 +18,6 @@ # and at http://www.gnu.org/licenses/. # +add_subdirectory(asn1) add_subdirectory(common) add_subdirectory(upper) diff --git a/lib/test/asn1/CMakeLists.txt b/lib/test/asn1/CMakeLists.txt new file mode 100644 index 000000000..6c52d1972 --- /dev/null +++ b/lib/test/asn1/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Copyright 2013-2017 Software Radio Systems Limited +# +# This file is part of srsLTE +# +# srsLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsLTE 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +add_executable(rrc_meas_test rrc_meas_test.cc) +target_link_libraries(rrc_meas_test srslte_common srslte_phy srslte_asn1) +add_test(rrc_meas_test rrc_meas_test) diff --git a/lib/test/asn1/rrc_meas_test.cc b/lib/test/asn1/rrc_meas_test.cc new file mode 100644 index 000000000..63a4d61b6 --- /dev/null +++ b/lib/test/asn1/rrc_meas_test.cc @@ -0,0 +1,91 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include "srslte/common/log_filter.h" +#include "srslte/asn1/liblte_rrc.h" + + +void basic_test() { + srslte::log_filter log1("RRC"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(128); + + LIBLTE_BIT_MSG_STRUCT bit_buf; + LIBLTE_BIT_MSG_STRUCT bit_buf2; + LIBLTE_BYTE_MSG_STRUCT byte_buf; + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + uint32_t rrc_message_len = 18; + uint8_t rrc_message[] = {0x08, 0x10, 0x49, 0x3C, 0x0D, 0x97, 0x89, 0x83, + 0xC0, 0x84, 0x20, 0x82, 0x08, 0x21, 0x00, 0x01, + 0xBC, 0x48}; + + srslte_bit_unpack_vector(rrc_message, bit_buf.msg, rrc_message_len*8); + bit_buf.N_bits = rrc_message_len*8; + liblte_rrc_unpack_ul_dcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &ul_dcch_msg); + + assert(ul_dcch_msg.msg_type == LIBLTE_RRC_UL_DCCH_MSG_TYPE_MEASUREMENT_REPORT); + LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *rep = &ul_dcch_msg.msg.measurement_report; + assert(rep->meas_id == 1); + assert(rep->pcell_rsrp_result == 73); + assert(rep->pcell_rsrq_result == 15); + assert(rep->have_meas_result_neigh_cells); + assert(rep->meas_result_neigh_cells_choice == LIBLTE_RRC_MEAS_RESULT_LIST_EUTRA); + LIBLTE_RRC_MEAS_RESULT_LIST_EUTRA_STRUCT *eutra = &rep->meas_result_neigh_cells.eutra; + assert(eutra->n_result == 1); + assert(eutra->result_eutra_list[0].phys_cell_id == 357); + assert(eutra->result_eutra_list[0].have_cgi_info); + assert(eutra->result_eutra_list[0].cgi_info.have_plmn_identity_list); + assert(eutra->result_eutra_list[0].cgi_info.cell_global_id.plmn_id.mcc == 0xF898); + assert(eutra->result_eutra_list[0].cgi_info.cell_global_id.plmn_id.mnc == 0xFF78); + assert(eutra->result_eutra_list[0].cgi_info.cell_global_id.cell_id == 0x1084104); + assert(eutra->result_eutra_list[0].cgi_info.tracking_area_code == 0x1042); + assert(eutra->result_eutra_list[0].cgi_info.have_plmn_identity_list); + assert(eutra->result_eutra_list[0].cgi_info.n_plmn_identity_list == 1); + assert(eutra->result_eutra_list[0].cgi_info.plmn_identity_list[0].mcc == 0xFFFF); + assert(eutra->result_eutra_list[0].cgi_info.plmn_identity_list[0].mnc == 0xFF00); + assert(eutra->result_eutra_list[0].meas_result.have_rsrp); + assert(eutra->result_eutra_list[0].meas_result.rsrp_result == 60); + assert(eutra->result_eutra_list[0].meas_result.have_rsrp); + assert(eutra->result_eutra_list[0].meas_result.rsrq_result == 18); + + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT*)&bit_buf2); + srslte_bit_pack_vector(bit_buf2.msg, byte_buf.msg, bit_buf2.N_bits); + byte_buf.N_bytes = (bit_buf2.N_bits+7)/8; + log1.info_hex(byte_buf.msg, byte_buf.N_bytes, "UL_DCCH Packed message\n"); + + for(uint32_t i=0; i +#include +#include + +#include "srslte/common/liblte_security.h" + +/* + * Prototypes + */ + +int32 arrcmp(uint8_t const * const a, uint8_t const * const b, uint32 len) { + uint32 i = 0; + + for (i = 0; i < len; i++) { + if (a[i] != b[i]) { + return a[i] - b[i]; + } + } + return 0; +} + +/* + * Tests + * + * Document Reference: 33.401 V13.1.0 Annex C.3 + * Specification of the 3GPP Confidentiality and + * Integrity Algorithms UEA2 & UIA2 D4 v1.0 + */ + +void test_set_1() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 253, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0x5d, 0x5b, 0xfe, 0x75, 0xeb, 0x04, 0xf6, + 0x8c, 0xe0, 0xa1, 0x23, 0x77, 0xea, 0x00, 0xb3, 0x7d, + 0x47, 0xc6, 0xa0, 0xba, 0x06, 0x30, 0x91, 0x55, 0x08, + 0x6a, 0x85, 0x9c, 0x43, 0x41, 0xb3, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_2() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x2b, 0xd6, 0x45, 0x9f, 0x82, 0xc4, 0x40, + 0xe0, 0x95, 0x2c, 0x49, 0x10, 0x48, 0x05, 0xff, 0x48 }; + uint32_t count = 0xc675a64b; + uint8_t bearer = 0x0c; + uint8_t direction = 1; + uint32_t len_bits = 798, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x7e, 0xc6, 0x12, 0x72, 0x74, 0x3b, 0xf1, + 0x61, 0x47, 0x26, 0x44, 0x6a, 0x6c, 0x38, 0xce, 0xd1, + 0x66, 0xf6, 0xca, 0x76, 0xeb, 0x54, 0x30, 0x04, 0x42, + 0x86, 0x34, 0x6c, 0xef, 0x13, 0x0f, 0x92, 0x92, 0x2b, + 0x03, 0x45, 0x0d, 0x3a, 0x99, 0x75, 0xe5, 0xbd, 0x2e, + 0xa0, 0xeb, 0x55, 0xad, 0x8e, 0x1b, 0x19, 0x9e, 0x3e, + 0xc4, 0x31, 0x60, 0x20, 0xe9, 0xa1, 0xb2, 0x85, 0xe7, + 0x62, 0x79, 0x53, 0x59, 0xb7, 0xbd, 0xfd, 0x39, 0xbe, + 0xf4, 0xb2, 0x48, 0x45, 0x83, 0xd5, 0xaf, 0xe0, 0x82, + 0xae, 0xe6, 0x38, 0xbf, 0x5f, 0xd5, 0xa6, 0x06, 0x19, + 0x39, 0x01, 0xa0, 0x8f, 0x4a, 0xb4, 0x1a, 0xab, 0x9b, + 0x13, 0x48, 0x80 }; + uint8_t ct[] = { 0x3f, 0x67, 0x85, 0x07, 0x14, 0xb8, 0xda, + 0x69, 0xef, 0xb7, 0x27, 0xed, 0x7a, 0x6c, 0x0c, 0x50, + 0x71, 0x4a, 0xd7, 0x36, 0xc4, 0xf5, 0x60, 0x00, 0x06, + 0xe3, 0x52, 0x5b, 0xe8, 0x07, 0xc4, 0x67, 0xc6, 0x77, + 0xff, 0x86, 0x4a, 0xf4, 0x5f, 0xba, 0x09, 0xc2, 0x7c, + 0xde, 0x38, 0xf8, 0x7a, 0x1f, 0x84, 0xd5, 0x9a, 0xb2, + 0x55, 0x40, 0x8f, 0x2c, 0x7b, 0x82, 0xf9, 0xea, 0xd4, + 0x1a, 0x1f, 0xe6, 0x5e, 0xab, 0xeb, 0xfb, 0xc1, 0xf3, + 0xa4, 0xc5, 0x6c, 0x9a, 0x26, 0xfc, 0xf7, 0xb3, 0xd6, + 0x6d, 0x02, 0x20, 0xee, 0x47, 0x75, 0xbc, 0x58, 0x17, + 0x0a, 0x2b, 0x12, 0xf3, 0x43, 0x1d, 0x11, 0xb3, 0x44, + 0xd6, 0xe3, 0x6c }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_3() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x0a, 0x8b, 0x6b, 0xd8, 0xd9, 0xb0, 0x8b, + 0x08, 0xd6, 0x4e, 0x32, 0xd1, 0x81, 0x77, 0x77, 0xfb }; + uint32_t count = 0x544d49cd; + uint8_t bearer = 0x04; + uint8_t direction = 0; + uint32_t len_bits = 310, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0xfd, 0x40, 0xa4, 0x1d, 0x37, 0x0a, 0x1f, + 0x65, 0x74, 0x50, 0x95, 0x68, 0x7d, 0x47, 0xba, 0x1d, + 0x36, 0xd2, 0x34, 0x9e, 0x23, 0xf6, 0x44, 0x39, 0x2c, + 0x8e, 0xa9, 0xc4, 0x9d, 0x40, 0xc1, 0x32, 0x71, 0xaf, + 0xf2, 0x64, 0xd0, 0xf2, 0x48, 0x00 }; + uint8_t ct[] = { 0x48, 0x14, 0x8e, 0x54, 0x52, 0xa2, 0x10, + 0xc0, 0x5f, 0x46, 0xbc, 0x80, 0xdc, 0x6f, 0x73, 0x49, + 0x5b, 0x02, 0x04, 0x8c, 0x1b, 0x95, 0x8b, 0x02, 0x61, + 0x02, 0xca, 0x97, 0x28, 0x02, 0x79, 0xa4, 0xc1, 0x8d, + 0x2e, 0xe3, 0x08, 0x92, 0x1c }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_4() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xaa, 0x1f, 0x95, 0xae, 0xa5, 0x33, 0xbc, + 0xb3, 0x2e, 0xb6, 0x3b, 0xf5, 0x2d, 0x8f, 0x83, 0x1a }; + uint32_t count = 0x72d8c671; + uint8_t bearer = 0x10; + uint8_t direction = 1; + uint32_t len_bits = 1022, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0xfb, 0x1b, 0x96, 0xc5, 0xc8, 0xba, 0xdf, + 0xb2, 0xe8, 0xe8, 0xed, 0xfd, 0xe7, 0x8e, 0x57, 0xf2, + 0xad, 0x81, 0xe7, 0x41, 0x03, 0xfc, 0x43, 0x0a, 0x53, + 0x4d, 0xcc, 0x37, 0xaf, 0xce, 0xc7, 0x0e, 0x15, 0x17, + 0xbb, 0x06, 0xf2, 0x72, 0x19, 0xda, 0xe4, 0x90, 0x22, + 0xdd, 0xc4, 0x7a, 0x06, 0x8d, 0xe4, 0xc9, 0x49, 0x6a, + 0x95, 0x1a, 0x6b, 0x09, 0xed, 0xbd, 0xc8, 0x64, 0xc7, + 0xad, 0xbd, 0x74, 0x0a, 0xc5, 0x0c, 0x02, 0x2f, 0x30, + 0x82, 0xba, 0xfd, 0x22, 0xd7, 0x81, 0x97, 0xc5, 0xd5, + 0x08, 0xb9, 0x77, 0xbc, 0xa1, 0x3f, 0x32, 0xe6, 0x52, + 0xe7, 0x4b, 0xa7, 0x28, 0x57, 0x60, 0x77, 0xce, 0x62, + 0x8c, 0x53, 0x5e, 0x87, 0xdc, 0x60, 0x77, 0xba, 0x07, + 0xd2, 0x90, 0x68, 0x59, 0x0c, 0x8c, 0xb5, 0xf1, 0x08, + 0x8e, 0x08, 0x2c, 0xfa, 0x0e, 0xc9, 0x61, 0x30, 0x2d, + 0x69, 0xcf, 0x3d, 0x44 }; + uint8_t ct[] = { 0xff, 0xcf, 0xc2, 0xfe, 0xad, 0x6c, 0x09, + 0x4e, 0x96, 0xc5, 0x89, 0xd0, 0xf6, 0x77, 0x9b, 0x67, + 0x84, 0x24, 0x6c, 0x3c, 0x4d, 0x1c, 0xea, 0x20, 0x3d, + 0xb3, 0x90, 0x1f, 0x40, 0xad, 0x4f, 0xd7, 0x13, 0x8b, + 0xc6, 0xd7, 0x7e, 0x83, 0x20, 0xcb, 0x10, 0x2f, 0x49, + 0x7f, 0xdd, 0x44, 0xa2, 0x69, 0xa9, 0x6e, 0xcb, 0x28, + 0x61, 0x77, 0x00, 0xe3, 0x32, 0xeb, 0x2f, 0x73, 0x6b, + 0x34, 0xf4, 0xf2, 0x69, 0x30, 0x94, 0xe2, 0x2f, 0xf9, + 0x4f, 0x9b, 0xe4, 0x72, 0x3d, 0xa4, 0x0c, 0x40, 0xdf, + 0xd3, 0x93, 0x1c, 0xc1, 0xac, 0x97, 0x23, 0xf6, 0xb4, + 0xa9, 0x91, 0x3e, 0x96, 0xb6, 0xdb, 0x7a, 0xbc, 0xac, + 0xe4, 0x15, 0x17, 0x7c, 0x1d, 0x01, 0x15, 0xc5, 0xf0, + 0x9b, 0x5f, 0xde, 0xa0, 0xb3, 0xad, 0xb8, 0xf9, 0xda, + 0x6e, 0x9f, 0x9a, 0x04, 0xc5, 0x43, 0x39, 0x7b, 0x9d, + 0x43, 0xf8, 0x73, 0x30 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_5() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x96, 0x18, 0xae, 0x46, 0x89, 0x1f, 0x86, + 0x57, 0x8e, 0xeb, 0xe9, 0x0e, 0xf7, 0xa1, 0x20, 0x2e }; + uint32_t count = 0xc675a64b; + uint8_t bearer = 0x0c; + uint8_t direction = 1; + uint32_t len_bits = 1245, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x8d, 0xaa, 0x17, 0xb1, 0xae, 0x05, 0x05, + 0x29, 0xc6, 0x82, 0x7f, 0x28, 0xc0, 0xef, 0x6a, 0x12, + 0x42, 0xe9, 0x3f, 0x8b, 0x31, 0x4f, 0xb1, 0x8a, 0x77, + 0xf7, 0x90, 0xae, 0x04, 0x9f, 0xed, 0xd6, 0x12, 0x26, + 0x7f, 0xec, 0xae, 0xfc, 0x45, 0x01, 0x74, 0xd7, 0x6d, + 0x9f, 0x9a, 0xa7, 0x75, 0x5a, 0x30, 0xcd, 0x90, 0xa9, + 0xa5, 0x87, 0x4b, 0xf4, 0x8e, 0xaf, 0x70, 0xee, 0xa3, + 0xa6, 0x2a, 0x25, 0x0a, 0x8b, 0x6b, 0xd8, 0xd9, 0xb0, + 0x8b, 0x08, 0xd6, 0x4e, 0x32, 0xd1, 0x81, 0x77, 0x77, + 0xfb, 0x54, 0x4d, 0x49, 0xcd, 0x49, 0x72, 0x0e, 0x21, + 0x9d, 0xbf, 0x8b, 0xbe, 0xd3, 0x39, 0x04, 0xe1, 0xfd, + 0x40, 0xa4, 0x1d, 0x37, 0x0a, 0x1f, 0x65, 0x74, 0x50, + 0x95, 0x68, 0x7d, 0x47, 0xba, 0x1d, 0x36, 0xd2, 0x34, + 0x9e, 0x23, 0xf6, 0x44, 0x39, 0x2c, 0x8e, 0xa9, 0xc4, + 0x9d, 0x40, 0xc1, 0x32, 0x71, 0xaf, 0xf2, 0x64, 0xd0, + 0xf2, 0x48, 0x41, 0xd6, 0x46, 0x5f, 0x09, 0x96, 0xff, + 0x84, 0xe6, 0x5f, 0xc5, 0x17, 0xc5, 0x3e, 0xfc, 0x33, + 0x63, 0xc3, 0x84, 0x92, 0xa8 }; + uint8_t ct[] = { 0x6c, 0xdb, 0x18, 0xa7, 0xca, 0x82, 0x18, + 0xe8, 0x6e, 0x4b, 0x4b, 0x71, 0x6a, 0x4d, 0x04, 0x37, + 0x1f, 0xbe, 0xc2, 0x62, 0xfc, 0x5a, 0xd0, 0xb3, 0x81, + 0x9b, 0x18, 0x7b, 0x97, 0xe5, 0x5b, 0x1a, 0x4d, 0x7c, + 0x19, 0xee, 0x24, 0xc8, 0xb4, 0xd7, 0x72, 0x3c, 0xfe, + 0xdf, 0x04, 0x5b, 0x8a, 0xca, 0xe4, 0x86, 0x95, 0x17, + 0xd8, 0x0e, 0x50, 0x61, 0x5d, 0x90, 0x35, 0xd5, 0xd9, + 0xc5, 0xa4, 0x0a, 0xf6, 0x02, 0x28, 0x0b, 0x54, 0x25, + 0x97, 0xb0, 0xcb, 0x18, 0x61, 0x9e, 0xeb, 0x35, 0x92, + 0x57, 0x59, 0xd1, 0x95, 0xe1, 0x00, 0xe8, 0xe4, 0xaa, + 0x0c, 0x38, 0xa3, 0xc2, 0xab, 0xe0, 0xf3, 0xd8, 0xff, + 0x04, 0xf3, 0xc3, 0x3c, 0x29, 0x50, 0x69, 0xc2, 0x36, + 0x94, 0xb5, 0xbb, 0xea, 0xcd, 0xd5, 0x42, 0xe2, 0x8e, + 0x8a, 0x94, 0xed, 0xb9, 0x11, 0x9f, 0x41, 0x2d, 0x05, + 0x4b, 0xe1, 0xfa, 0x72, 0x72, 0xb5, 0xff, 0xb2, 0xb2, + 0x57, 0x0f, 0x4f, 0x7c, 0xea, 0xf3, 0x83, 0xa8, 0xa9, + 0xd9, 0x35, 0x72, 0xf0, 0x4d, 0x6e, 0x3a, 0x6e, 0x29, + 0x37, 0x26, 0xec, 0x62, 0xc8 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_6() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x54, 0xf4, 0xe2, 0xe0, 0x4c, 0x83, 0x78, + 0x6e, 0xec, 0x8f, 0xb5, 0xab, 0xe8, 0xe3, 0x65, 0x66 }; + uint32_t count = 0xaca4f50f; + uint8_t bearer = 0x0b; + uint8_t direction = 0; + uint32_t len_bits = 3861, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x40, 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, + 0xfb, 0x42, 0x86, 0xb2, 0x99, 0x78, 0x3d, 0xaf, 0x44, + 0x2c, 0x09, 0x9f, 0x7a, 0xb0, 0xf5, 0x8d, 0x5c, 0x8e, + 0x46, 0xb1, 0x04, 0xf0, 0x8f, 0x01, 0xb4, 0x1a, 0xb4, + 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x36, 0xbd, 0x1a, + 0x3d, 0x90, 0xdc, 0x3a, 0x41, 0xb4, 0x6d, 0x51, 0x67, + 0x2a, 0xc4, 0xc9, 0x66, 0x3a, 0x2b, 0xe0, 0x63, 0xda, + 0x4b, 0xc8, 0xd2, 0x80, 0x8c, 0xe3, 0x3e, 0x2c, 0xcc, + 0xbf, 0xc6, 0x34, 0xe1, 0xb2, 0x59, 0x06, 0x08, 0x76, + 0xa0, 0xfb, 0xb5, 0xa4, 0x37, 0xeb, 0xcc, 0x8d, 0x31, + 0xc1, 0x9e, 0x44, 0x54, 0x31, 0x87, 0x45, 0xe3, 0xfa, + 0x16, 0xbb, 0x11, 0xad, 0xae, 0x24, 0x88, 0x79, 0xfe, + 0x52, 0xdb, 0x25, 0x43, 0xe5, 0x3c, 0xf4, 0x45, 0xd3, + 0xd8, 0x28, 0xce, 0x0b, 0xf5, 0xc5, 0x60, 0x59, 0x3d, + 0x97, 0x27, 0x8a, 0x59, 0x76, 0x2d, 0xd0, 0xc2, 0xc9, + 0xcd, 0x68, 0xd4, 0x49, 0x6a, 0x79, 0x25, 0x08, 0x61, + 0x40, 0x14, 0xb1, 0x3b, 0x6a, 0xa5, 0x11, 0x28, 0xc1, + 0x8c, 0xd6, 0xa9, 0x0b, 0x87, 0x97, 0x8c, 0x2f, 0xf1, + 0xca, 0xbe, 0x7d, 0x9f, 0x89, 0x8a, 0x41, 0x1b, 0xfd, + 0xb8, 0x4f, 0x68, 0xf6, 0x72, 0x7b, 0x14, 0x99, 0xcd, + 0xd3, 0x0d, 0xf0, 0x44, 0x3a, 0xb4, 0xa6, 0x66, 0x53, + 0x33, 0x0b, 0xcb, 0xa1, 0x10, 0x5e, 0x4c, 0xec, 0x03, + 0x4c, 0x73, 0xe6, 0x05, 0xb4, 0x31, 0x0e, 0xaa, 0xad, + 0xcf, 0xd5, 0xb0, 0xca, 0x27, 0xff, 0xd8, 0x9d, 0x14, + 0x4d, 0xf4, 0x79, 0x27, 0x59, 0x42, 0x7c, 0x9c, 0xc1, + 0xf8, 0xcd, 0x8c, 0x87, 0x20, 0x23, 0x64, 0xb8, 0xa6, + 0x87, 0x95, 0x4c, 0xb0, 0x5a, 0x8d, 0x4e, 0x2d, 0x99, + 0xe7, 0x3d, 0xb1, 0x60, 0xde, 0xb1, 0x80, 0xad, 0x08, + 0x41, 0xe9, 0x67, 0x41, 0xa5, 0xd5, 0x9f, 0xe4, 0x18, + 0x9f, 0x15, 0x42, 0x00, 0x26, 0xfe, 0x4c, 0xd1, 0x21, + 0x04, 0x93, 0x2f, 0xb3, 0x8f, 0x73, 0x53, 0x40, 0x43, + 0x8a, 0xaf, 0x7e, 0xca, 0x6f, 0xd5, 0xcf, 0xd3, 0xa1, + 0x95, 0xce, 0x5a, 0xbe, 0x65, 0x27, 0x2a, 0xf6, 0x07, + 0xad, 0xa1, 0xbe, 0x65, 0xa6, 0xb4, 0xc9, 0xc0, 0x69, + 0x32, 0x34, 0x09, 0x2c, 0x4d, 0x01, 0x8f, 0x17, 0x56, + 0xc6, 0xdb, 0x9d, 0xc8, 0xa6, 0xd8, 0x0b, 0x88, 0x81, + 0x38, 0x61, 0x6b, 0x68, 0x12, 0x62, 0xf9, 0x54, 0xd0, + 0xe7, 0x71, 0x17, 0x48, 0x78, 0x0d, 0x92, 0x29, 0x1d, + 0x86, 0x29, 0x99, 0x72, 0xdb, 0x74, 0x1c, 0xfa, 0x4f, + 0x37, 0xb8, 0xb5, 0x6c, 0xdb, 0x18, 0xa7, 0xca, 0x82, + 0x18, 0xe8, 0x6e, 0x4b, 0x4b, 0x71, 0x6a, 0x4d, 0x04, + 0x37, 0x1f, 0xbe, 0xc2, 0x62, 0xfc, 0x5a, 0xd0, 0xb3, + 0x81, 0x9b, 0x18, 0x7b, 0x97, 0xe5, 0x5b, 0x1a, 0x4d, + 0x7c, 0x19, 0xee, 0x24, 0xc8, 0xb4, 0xd7, 0x72, 0x3c, + 0xfe, 0xdf, 0x04, 0x5b, 0x8a, 0xca, 0xe4, 0x86, 0x95, + 0x17, 0xd8, 0x0e, 0x50, 0x61, 0x5d, 0x90, 0x35, 0xd5, + 0xd9, 0xc5, 0xa4, 0x0a, 0xf6, 0x02, 0x28, 0x0b, 0x54, + 0x25, 0x97, 0xb0, 0xcb, 0x18, 0x61, 0x9e, 0xeb, 0x35, + 0x92, 0x57, 0x59, 0xd1, 0x95, 0xe1, 0x00, 0xe8, 0xe4, + 0xaa, 0x0c, 0x38, 0xa3, 0xc2, 0xab, 0xe0, 0xf3, 0xd8, + 0xff, 0x04, 0xf3, 0xc3, 0x3c, 0x29, 0x50, 0x69, 0xc2, + 0x36, 0x94, 0xb5, 0xbb, 0xea, 0xcd, 0xd5, 0x42, 0xe2, + 0x8e, 0x8a, 0x94, 0xed, 0xb9, 0x11, 0x9f, 0x41, 0x2d, + 0x05, 0x4b, 0xe1, 0xfa, 0x72, 0xb0, 0x95, 0x50 }; + uint8_t ct[] = { 0x35, 0x1e, 0x30, 0xd4, 0xd9, 0x10, 0xc5, + 0xdd, 0x5a, 0xd7, 0x83, 0x4c, 0x42, 0x6e, 0x6c, 0x0c, + 0xab, 0x64, 0x86, 0xda, 0x7b, 0x0f, 0xda, 0x4c, 0xd8, + 0x3a, 0xf1, 0xb9, 0x64, 0x71, 0x37, 0xf1, 0xac, 0x43, + 0xb4, 0x34, 0x22, 0x3b, 0x19, 0xbe, 0x07, 0xbd, 0x89, + 0xd1, 0xcc, 0x30, 0x69, 0x44, 0xd3, 0x36, 0x1e, 0xa1, + 0xa2, 0xf8, 0xcd, 0xbd, 0x32, 0x16, 0x55, 0x97, 0x63, + 0x50, 0xd0, 0x0b, 0x80, 0xdd, 0x83, 0x81, 0x20, 0xa7, + 0x75, 0x5c, 0x6d, 0xea, 0x2a, 0xb2, 0xb0, 0xc9, 0x9a, + 0x91, 0x3f, 0x47, 0xda, 0xe2, 0xb8, 0xde, 0xb9, 0xa8, + 0x29, 0xe5, 0x46, 0x9f, 0xf2, 0xe1, 0x87, 0x77, 0x6f, + 0x6f, 0xd0, 0x81, 0xe3, 0x87, 0x1d, 0x11, 0x9a, 0x76, + 0xe2, 0x4c, 0x91, 0x7e, 0xa6, 0x26, 0x48, 0xe0, 0x2e, + 0x90, 0x36, 0x75, 0x64, 0xde, 0x72, 0xae, 0x7e, 0x4f, + 0x0a, 0x42, 0x49, 0xa9, 0xa5, 0xb0, 0xe4, 0x65, 0xa2, + 0xd6, 0xd9, 0xdc, 0x87, 0x84, 0x3b, 0x1b, 0x87, 0x5c, + 0xc9, 0xa3, 0xbe, 0x93, 0xd8, 0xda, 0x8f, 0x56, 0xec, + 0xaf, 0x59, 0x81, 0xfe, 0x93, 0xc2, 0x84, 0x31, 0x8b, + 0x0d, 0xec, 0x7a, 0x3b, 0xa1, 0x08, 0xe2, 0xcb, 0x1a, + 0x61, 0xe9, 0x66, 0xfa, 0x7a, 0xfa, 0x7a, 0xc7, 0xf6, + 0x7f, 0x65, 0xbc, 0x4a, 0x2d, 0xf0, 0x70, 0xd4, 0xe4, + 0x34, 0x84, 0x5f, 0x10, 0x9a, 0xb2, 0xb6, 0x8a, 0xde, + 0x3d, 0xc3, 0x16, 0xca, 0x63, 0x32, 0xa6, 0x28, 0x93, + 0xe0, 0xa7, 0xec, 0x0b, 0x4f, 0xc2, 0x51, 0x91, 0xbf, + 0x2f, 0xf1, 0xb9, 0xf9, 0x81, 0x5e, 0x4b, 0xa8, 0xa9, + 0x9c, 0x64, 0x3b, 0x52, 0x18, 0x04, 0xf7, 0xd5, 0x85, + 0x0d, 0xde, 0x39, 0x52, 0x20, 0x6e, 0xc6, 0xcc, 0xf3, + 0x40, 0xf9, 0xb3, 0x22, 0x0b, 0x30, 0x23, 0xbd, 0xd0, + 0x63, 0x95, 0x6e, 0xa8, 0x33, 0x39, 0x20, 0xfd, 0xe9, + 0x9e, 0x06, 0x75, 0x41, 0x0e, 0x49, 0xef, 0x3b, 0x4d, + 0x3f, 0xb3, 0xdf, 0x51, 0x92, 0xf9, 0x9c, 0xa8, 0x3d, + 0x3b, 0x00, 0x32, 0xde, 0x08, 0xc2, 0x20, 0x77, 0x6a, + 0x58, 0x65, 0xb0, 0xe4, 0xb3, 0xb0, 0xc7, 0x5d, 0xef, + 0xe7, 0x76, 0x2d, 0xff, 0x01, 0x8e, 0xa7, 0xf5, 0xbe, + 0x2b, 0x2f, 0x97, 0x2b, 0x2a, 0x8b, 0xa5, 0x97, 0x0e, + 0x43, 0xbd, 0x6f, 0xdd, 0x63, 0xda, 0xe6, 0x29, 0x78, + 0x4e, 0xc4, 0x8d, 0x61, 0x00, 0x54, 0xee, 0x4e, 0x4b, + 0x5d, 0xbb, 0xf1, 0xfc, 0x2f, 0xa0, 0xb8, 0x30, 0xe9, + 0x4d, 0xcb, 0xb7, 0x01, 0x4e, 0x8a, 0xb4, 0x29, 0xab, + 0x10, 0x0f, 0xc4, 0x8f, 0x83, 0x17, 0x1d, 0x99, 0xfc, + 0x25, 0x8b, 0x7c, 0x2b, 0xa7, 0xc1, 0x76, 0xea, 0xea, + 0xad, 0x37, 0xf8, 0x60, 0xd5, 0x97, 0xa3, 0x1c, 0xe7, + 0x9b, 0x59, 0x47, 0x33, 0xc7, 0x14, 0x1d, 0xf7, 0x91, + 0x51, 0xfc, 0xa9, 0x0c, 0x08, 0x47, 0x8a, 0x5c, 0x6c, + 0x2c, 0xc4, 0x81, 0xd5, 0x1f, 0xfe, 0xce, 0x3c, 0xd7, + 0xd2, 0x58, 0x13, 0x48, 0x82, 0x7a, 0x71, 0xf0, 0x91, + 0x42, 0x8e, 0xbe, 0x38, 0xc9, 0x5a, 0x3f, 0x5c, 0x63, + 0xe0, 0x56, 0xdf, 0xb7, 0xcc, 0x45, 0xa9, 0xb7, 0xc0, + 0x7d, 0x83, 0x4e, 0x7b, 0x20, 0xb9, 0x9e, 0xd2, 0x02, + 0x42, 0x9c, 0x14, 0xbb, 0x85, 0xff, 0xa4, 0x3b, 0x7c, + 0xb6, 0x84, 0x95, 0xcd, 0x75, 0xab, 0x66, 0xd9, 0x64, + 0xd4, 0xca, 0xfe, 0x64, 0xdd, 0x94, 0x04, 0xda, 0xe2, + 0xdc, 0x51, 0x10, 0x61, 0x7f, 0x19, 0x4f, 0xc3, 0xc1, + 0x84, 0xf5, 0x83, 0xcd, 0x0d, 0xef, 0x6d, 0x00 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +// set len_bitsgth to multiple of 8 respectively 128 +void test_set_1_block_size() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 256, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0x5d, 0x5b, 0xfe, 0x75, 0xeb, 0x04, 0xf6, + 0x8c, 0xe0, 0xa1, 0x23, 0x77, 0xea, 0x00, 0xb3, 0x7d, + 0x47, 0xc6, 0xa0, 0xba, 0x06, 0x30, 0x91, 0x55, 0x08, + 0x6a, 0x85, 0x9c, 0x43, 0x41, 0xb3, 0x7c }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +// inserted bit flip in msg[0] +void test_set_1_invalid() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 253, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x99, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0x5d, 0x5b, 0xfe, 0x75, 0xeb, 0x04, 0xf6, + 0x8c, 0xe0, 0xa1, 0x23, 0x77, 0xea, 0x00, 0xb3, 0x7d, + 0x47, 0xc6, 0xa0, 0xba, 0x06, 0x30, 0x91, 0x55, 0x08, + 0x6a, 0x85, 0x9c, 0x43, 0x41, 0xb3, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea1(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp != 0); + + // decryption + err_lte = liblte_security_decryption_eea1(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp != 0); + + free(out); +} + +/* + * Functions + */ + +int main(int argc, char * argv[]) { + test_set_1(); + test_set_2(); + test_set_3(); + test_set_4(); + test_set_5(); + test_set_6(); + test_set_1_block_size(); + test_set_1_invalid(); +} diff --git a/lib/test/common/test_eea2.cc b/lib/test/common/test_eea2.cc new file mode 100644 index 000000000..fccaefe70 --- /dev/null +++ b/lib/test/common/test_eea2.cc @@ -0,0 +1,567 @@ +/* + * Includes + */ + +#include +#include +#include + +#include "srslte/common/liblte_security.h" + +/* + * Prototypes + */ + +int32 arrcmp(uint8_t const * const a, uint8_t const * const b, uint32 len) { + uint32 i = 0; + + for (i = 0; i < len; i++) { + if (a[i] != b[i]) { + return a[i] - b[i]; + } + } + return 0; +} + +/* + * Tests + * + * Document Reference: 33.401 V13.1.0 Annex C.1 + */ + +void test_set_1() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 253, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0xe9, 0xfe, 0xd8, 0xa6, 0x3d, 0x15, 0x53, + 0x04, 0xd7, 0x1d, 0xf2, 0x0b, 0xf3, 0xe8, 0x22, 0x14, + 0xb2, 0x0e, 0xd7, 0xda, 0xd2, 0xf2, 0x33, 0xdc, 0x3c, + 0x22, 0xd7, 0xbd, 0xee, 0xed, 0x8e, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_2() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x2b, 0xd6, 0x45, 0x9f, 0x82, 0xc4, 0x40, + 0xe0, 0x95, 0x2c, 0x49, 0x10, 0x48, 0x05, 0xff, 0x48 }; + uint32_t count = 0xc675a64b; + uint8_t bearer = 0x0c; + uint8_t direction = 1; + uint32_t len_bits = 798, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x7e, 0xc6, 0x12, 0x72, 0x74, 0x3b, 0xf1, + 0x61, 0x47, 0x26, 0x44, 0x6a, 0x6c, 0x38, 0xce, 0xd1, + 0x66, 0xf6, 0xca, 0x76, 0xeb, 0x54, 0x30, 0x04, 0x42, + 0x86, 0x34, 0x6c, 0xef, 0x13, 0x0f, 0x92, 0x92, 0x2b, + 0x03, 0x45, 0x0d, 0x3a, 0x99, 0x75, 0xe5, 0xbd, 0x2e, + 0xa0, 0xeb, 0x55, 0xad, 0x8e, 0x1b, 0x19, 0x9e, 0x3e, + 0xc4, 0x31, 0x60, 0x20, 0xe9, 0xa1, 0xb2, 0x85, 0xe7, + 0x62, 0x79, 0x53, 0x59, 0xb7, 0xbd, 0xfd, 0x39, 0xbe, + 0xf4, 0xb2, 0x48, 0x45, 0x83, 0xd5, 0xaf, 0xe0, 0x82, + 0xae, 0xe6, 0x38, 0xbf, 0x5f, 0xd5, 0xa6, 0x06, 0x19, + 0x39, 0x01, 0xa0, 0x8f, 0x4a, 0xb4, 0x1a, 0xab, 0x9b, + 0x13, 0x48, 0x80 }; + uint8_t ct[] = { 0x59, 0x61, 0x60, 0x53, 0x53, 0xc6, 0x4b, + 0xdc, 0xa1, 0x5b, 0x19, 0x5e, 0x28, 0x85, 0x53, 0xa9, + 0x10, 0x63, 0x25, 0x06, 0xd6, 0x20, 0x0a, 0xa7, 0x90, + 0xc4, 0xc8, 0x06, 0xc9, 0x99, 0x04, 0xcf, 0x24, 0x45, + 0xcc, 0x50, 0xbb, 0x1c, 0xf1, 0x68, 0xa4, 0x96, 0x73, + 0x73, 0x4e, 0x08, 0x1b, 0x57, 0xe3, 0x24, 0xce, 0x52, + 0x59, 0xc0, 0xe7, 0x8d, 0x4c, 0xd9, 0x7b, 0x87, 0x09, + 0x76, 0x50, 0x3c, 0x09, 0x43, 0xf2, 0xcb, 0x5a, 0xe8, + 0xf0, 0x52, 0xc7, 0xb7, 0xd3, 0x92, 0x23, 0x95, 0x87, + 0xb8, 0x95, 0x60, 0x86, 0xbc, 0xab, 0x18, 0x83, 0x60, + 0x42, 0xe2, 0xe6, 0xce, 0x42, 0x43, 0x2a, 0x17, 0x10, + 0x5c, 0x53, 0xd0 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_3() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x0a, 0x8b, 0x6b, 0xd8, 0xd9, 0xb0, 0x8b, + 0x08, 0xd6, 0x4e, 0x32, 0xd1, 0x81, 0x77, 0x77, 0xfb }; + uint32_t count = 0x544d49cd; + uint8_t bearer = 0x04; + uint8_t direction = 0; + uint32_t len_bits = 310, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0xfd, 0x40, 0xa4, 0x1d, 0x37, 0x0a, 0x1f, + 0x65, 0x74, 0x50, 0x95, 0x68, 0x7d, 0x47, 0xba, 0x1d, + 0x36, 0xd2, 0x34, 0x9e, 0x23, 0xf6, 0x44, 0x39, 0x2c, + 0x8e, 0xa9, 0xc4, 0x9d, 0x40, 0xc1, 0x32, 0x71, 0xaf, + 0xf2, 0x64, 0xd0, 0xf2, 0x48, 0x00 }; + uint8_t ct[] = { 0x75, 0x75, 0x0d, 0x37, 0xb4, 0xbb, 0xa2, + 0xa4, 0xde, 0xdb, 0x34, 0x23, 0x5b, 0xd6, 0x8c, 0x66, + 0x45, 0xac, 0xda, 0xac, 0xa4, 0x81, 0x38, 0xa3, 0xb0, + 0xc4, 0x71, 0xe2, 0xa7, 0x04, 0x1a, 0x57, 0x64, 0x23, + 0xd2, 0x92, 0x72, 0x87, 0xf0, 0x00 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_4() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xaa, 0x1f, 0x95, 0xae, 0xa5, 0x33, 0xbc, + 0xb3, 0x2e, 0xb6, 0x3b, 0xf5, 0x2d, 0x8f, 0x83, 0x1a }; + uint32_t count = 0x72d8c671; + uint8_t bearer = 0x10; + uint8_t direction = 1; + uint32_t len_bits = 1022, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0xfb, 0x1b, 0x96, 0xc5, 0xc8, 0xba, 0xdf, + 0xb2, 0xe8, 0xe8, 0xed, 0xfd, 0xe7, 0x8e, 0x57, 0xf2, + 0xad, 0x81, 0xe7, 0x41, 0x03, 0xfc, 0x43, 0x0a, 0x53, + 0x4d, 0xcc, 0x37, 0xaf, 0xce, 0xc7, 0x0e, 0x15, 0x17, + 0xbb, 0x06, 0xf2, 0x72, 0x19, 0xda, 0xe4, 0x90, 0x22, + 0xdd, 0xc4, 0x7a, 0x06, 0x8d, 0xe4, 0xc9, 0x49, 0x6a, + 0x95, 0x1a, 0x6b, 0x09, 0xed, 0xbd, 0xc8, 0x64, 0xc7, + 0xad, 0xbd, 0x74, 0x0a, 0xc5, 0x0c, 0x02, 0x2f, 0x30, + 0x82, 0xba, 0xfd, 0x22, 0xd7, 0x81, 0x97, 0xc5, 0xd5, + 0x08, 0xb9, 0x77, 0xbc, 0xa1, 0x3f, 0x32, 0xe6, 0x52, + 0xe7, 0x4b, 0xa7, 0x28, 0x57, 0x60, 0x77, 0xce, 0x62, + 0x8c, 0x53, 0x5e, 0x87, 0xdc, 0x60, 0x77, 0xba, 0x07, + 0xd2, 0x90, 0x68, 0x59, 0x0c, 0x8c, 0xb5, 0xf1, 0x08, + 0x8e, 0x08, 0x2c, 0xfa, 0x0e, 0xc9, 0x61, 0x30, 0x2d, + 0x69, 0xcf, 0x3d, 0x44 }; + uint8_t ct[] = { 0xdf, 0xb4, 0x40, 0xac, 0xb3, 0x77, 0x35, + 0x49, 0xef, 0xc0, 0x46, 0x28, 0xae, 0xb8, 0xd8, 0x15, + 0x62, 0x75, 0x23, 0x0b, 0xdc, 0x69, 0x0d, 0x94, 0xb0, + 0x0d, 0x8d, 0x95, 0xf2, 0x8c, 0x4b, 0x56, 0x30, 0x7f, + 0x60, 0xf4, 0xca, 0x55, 0xeb, 0xa6, 0x61, 0xeb, 0xba, + 0x72, 0xac, 0x80, 0x8f, 0xa8, 0xc4, 0x9e, 0x26, 0x78, + 0x8e, 0xd0, 0x4a, 0x5d, 0x60, 0x6c, 0xb4, 0x18, 0xde, + 0x74, 0x87, 0x8b, 0x9a, 0x22, 0xf8, 0xef, 0x29, 0x59, + 0x0b, 0xc4, 0xeb, 0x57, 0xc9, 0xfa, 0xf7, 0xc4, 0x15, + 0x24, 0xa8, 0x85, 0xb8, 0x97, 0x9c, 0x42, 0x3f, 0x2f, + 0x8f, 0x8e, 0x05, 0x92, 0xa9, 0x87, 0x92, 0x01, 0xbe, + 0x7f, 0xf9, 0x77, 0x7a, 0x16, 0x2a, 0xb8, 0x10, 0xfe, + 0xb3, 0x24, 0xba, 0x74, 0xc4, 0xc1, 0x56, 0xe0, 0x4d, + 0x39, 0x09, 0x72, 0x09, 0x65, 0x3a, 0xc3, 0x3e, 0x5a, + 0x5f, 0x2d, 0x88, 0x64 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_5() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x96, 0x18, 0xae, 0x46, 0x89, 0x1f, 0x86, + 0x57, 0x8e, 0xeb, 0xe9, 0x0e, 0xf7, 0xa1, 0x20, 0x2e }; + uint32_t count = 0xc675a64b; + uint8_t bearer = 0x0c; + uint8_t direction = 1; + uint32_t len_bits = 1245, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x8d, 0xaa, 0x17, 0xb1, 0xae, 0x05, 0x05, + 0x29, 0xc6, 0x82, 0x7f, 0x28, 0xc0, 0xef, 0x6a, 0x12, + 0x42, 0xe9, 0x3f, 0x8b, 0x31, 0x4f, 0xb1, 0x8a, 0x77, + 0xf7, 0x90, 0xae, 0x04, 0x9f, 0xed, 0xd6, 0x12, 0x26, + 0x7f, 0xec, 0xae, 0xfc, 0x45, 0x01, 0x74, 0xd7, 0x6d, + 0x9f, 0x9a, 0xa7, 0x75, 0x5a, 0x30, 0xcd, 0x90, 0xa9, + 0xa5, 0x87, 0x4b, 0xf4, 0x8e, 0xaf, 0x70, 0xee, 0xa3, + 0xa6, 0x2a, 0x25, 0x0a, 0x8b, 0x6b, 0xd8, 0xd9, 0xb0, + 0x8b, 0x08, 0xd6, 0x4e, 0x32, 0xd1, 0x81, 0x77, 0x77, + 0xfb, 0x54, 0x4d, 0x49, 0xcd, 0x49, 0x72, 0x0e, 0x21, + 0x9d, 0xbf, 0x8b, 0xbe, 0xd3, 0x39, 0x04, 0xe1, 0xfd, + 0x40, 0xa4, 0x1d, 0x37, 0x0a, 0x1f, 0x65, 0x74, 0x50, + 0x95, 0x68, 0x7d, 0x47, 0xba, 0x1d, 0x36, 0xd2, 0x34, + 0x9e, 0x23, 0xf6, 0x44, 0x39, 0x2c, 0x8e, 0xa9, 0xc4, + 0x9d, 0x40, 0xc1, 0x32, 0x71, 0xaf, 0xf2, 0x64, 0xd0, + 0xf2, 0x48, 0x41, 0xd6, 0x46, 0x5f, 0x09, 0x96, 0xff, + 0x84, 0xe6, 0x5f, 0xc5, 0x17, 0xc5, 0x3e, 0xfc, 0x33, + 0x63, 0xc3, 0x84, 0x92, 0xa8 }; + uint8_t ct[] = { 0x91, 0x9c, 0x8c, 0x33, 0xd6, 0x67, 0x89, + 0x70, 0x3d, 0x05, 0xa0, 0xd7, 0xce, 0x82, 0xa2, 0xae, + 0xac, 0x4e, 0xe7, 0x6c, 0x0f, 0x4d, 0xa0, 0x50, 0x33, + 0x5e, 0x8a, 0x84, 0xe7, 0x89, 0x7b, 0xa5, 0xdf, 0x2f, + 0x36, 0xbd, 0x51, 0x3e, 0x3d, 0x0c, 0x85, 0x78, 0xc7, + 0xa0, 0xfc, 0xf0, 0x43, 0xe0, 0x3a, 0xa3, 0xa3, 0x9f, + 0xba, 0xad, 0x7d, 0x15, 0xbe, 0x07, 0x4f, 0xaa, 0x5d, + 0x90, 0x29, 0xf7, 0x1f, 0xb4, 0x57, 0xb6, 0x47, 0x83, + 0x47, 0x14, 0xb0, 0xe1, 0x8f, 0x11, 0x7f, 0xca, 0x10, + 0x67, 0x79, 0x45, 0x09, 0x6c, 0x8c, 0x5f, 0x32, 0x6b, + 0xa8, 0xd6, 0x09, 0x5e, 0xb2, 0x9c, 0x3e, 0x36, 0xcf, + 0x24, 0x5d, 0x16, 0x22, 0xaa, 0xfe, 0x92, 0x1f, 0x75, + 0x66, 0xc4, 0xf5, 0xd6, 0x44, 0xf2, 0xf1, 0xfc, 0x0e, + 0xc6, 0x84, 0xdd, 0xb2, 0x13, 0x49, 0x74, 0x76, 0x22, + 0xe2, 0x09, 0x29, 0x5d, 0x27, 0xff, 0x3f, 0x95, 0x62, + 0x33, 0x71, 0xd4, 0x9b, 0x14, 0x7c, 0x0a, 0xf4, 0x86, + 0x17, 0x1f, 0x22, 0xcd, 0x04, 0xb1, 0xcb, 0xeb, 0x26, + 0x58, 0x22, 0x3e, 0x69, 0x38 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +void test_set_6() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0x54, 0xf4, 0xe2, 0xe0, 0x4c, 0x83, 0x78, + 0x6e, 0xec, 0x8f, 0xb5, 0xab, 0xe8, 0xe3, 0x65, 0x66 }; + uint32_t count = 0xaca4f50f; + uint8_t bearer = 0x0b; + uint8_t direction = 0; + uint32_t len_bits = 3861, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x40, 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, + 0xfb, 0x42, 0x86, 0xb2, 0x99, 0x78, 0x3d, 0xaf, 0x44, + 0x2c, 0x09, 0x9f, 0x7a, 0xb0, 0xf5, 0x8d, 0x5c, 0x8e, + 0x46, 0xb1, 0x04, 0xf0, 0x8f, 0x01, 0xb4, 0x1a, 0xb4, + 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x36, 0xbd, 0x1a, + 0x3d, 0x90, 0xdc, 0x3a, 0x41, 0xb4, 0x6d, 0x51, 0x67, + 0x2a, 0xc4, 0xc9, 0x66, 0x3a, 0x2b, 0xe0, 0x63, 0xda, + 0x4b, 0xc8, 0xd2, 0x80, 0x8c, 0xe3, 0x3e, 0x2c, 0xcc, + 0xbf, 0xc6, 0x34, 0xe1, 0xb2, 0x59, 0x06, 0x08, 0x76, + 0xa0, 0xfb, 0xb5, 0xa4, 0x37, 0xeb, 0xcc, 0x8d, 0x31, + 0xc1, 0x9e, 0x44, 0x54, 0x31, 0x87, 0x45, 0xe3, 0xfa, + 0x16, 0xbb, 0x11, 0xad, 0xae, 0x24, 0x88, 0x79, 0xfe, + 0x52, 0xdb, 0x25, 0x43, 0xe5, 0x3c, 0xf4, 0x45, 0xd3, + 0xd8, 0x28, 0xce, 0x0b, 0xf5, 0xc5, 0x60, 0x59, 0x3d, + 0x97, 0x27, 0x8a, 0x59, 0x76, 0x2d, 0xd0, 0xc2, 0xc9, + 0xcd, 0x68, 0xd4, 0x49, 0x6a, 0x79, 0x25, 0x08, 0x61, + 0x40, 0x14, 0xb1, 0x3b, 0x6a, 0xa5, 0x11, 0x28, 0xc1, + 0x8c, 0xd6, 0xa9, 0x0b, 0x87, 0x97, 0x8c, 0x2f, 0xf1, + 0xca, 0xbe, 0x7d, 0x9f, 0x89, 0x8a, 0x41, 0x1b, 0xfd, + 0xb8, 0x4f, 0x68, 0xf6, 0x72, 0x7b, 0x14, 0x99, 0xcd, + 0xd3, 0x0d, 0xf0, 0x44, 0x3a, 0xb4, 0xa6, 0x66, 0x53, + 0x33, 0x0b, 0xcb, 0xa1, 0x10, 0x5e, 0x4c, 0xec, 0x03, + 0x4c, 0x73, 0xe6, 0x05, 0xb4, 0x31, 0x0e, 0xaa, 0xad, + 0xcf, 0xd5, 0xb0, 0xca, 0x27, 0xff, 0xd8, 0x9d, 0x14, + 0x4d, 0xf4, 0x79, 0x27, 0x59, 0x42, 0x7c, 0x9c, 0xc1, + 0xf8, 0xcd, 0x8c, 0x87, 0x20, 0x23, 0x64, 0xb8, 0xa6, + 0x87, 0x95, 0x4c, 0xb0, 0x5a, 0x8d, 0x4e, 0x2d, 0x99, + 0xe7, 0x3d, 0xb1, 0x60, 0xde, 0xb1, 0x80, 0xad, 0x08, + 0x41, 0xe9, 0x67, 0x41, 0xa5, 0xd5, 0x9f, 0xe4, 0x18, + 0x9f, 0x15, 0x42, 0x00, 0x26, 0xfe, 0x4c, 0xd1, 0x21, + 0x04, 0x93, 0x2f, 0xb3, 0x8f, 0x73, 0x53, 0x40, 0x43, + 0x8a, 0xaf, 0x7e, 0xca, 0x6f, 0xd5, 0xcf, 0xd3, 0xa1, + 0x95, 0xce, 0x5a, 0xbe, 0x65, 0x27, 0x2a, 0xf6, 0x07, + 0xad, 0xa1, 0xbe, 0x65, 0xa6, 0xb4, 0xc9, 0xc0, 0x69, + 0x32, 0x34, 0x09, 0x2c, 0x4d, 0x01, 0x8f, 0x17, 0x56, + 0xc6, 0xdb, 0x9d, 0xc8, 0xa6, 0xd8, 0x0b, 0x88, 0x81, + 0x38, 0x61, 0x6b, 0x68, 0x12, 0x62, 0xf9, 0x54, 0xd0, + 0xe7, 0x71, 0x17, 0x48, 0x78, 0x0d, 0x92, 0x29, 0x1d, + 0x86, 0x29, 0x99, 0x72, 0xdb, 0x74, 0x1c, 0xfa, 0x4f, + 0x37, 0xb8, 0xb5, 0x6c, 0xdb, 0x18, 0xa7, 0xca, 0x82, + 0x18, 0xe8, 0x6e, 0x4b, 0x4b, 0x71, 0x6a, 0x4d, 0x04, + 0x37, 0x1f, 0xbe, 0xc2, 0x62, 0xfc, 0x5a, 0xd0, 0xb3, + 0x81, 0x9b, 0x18, 0x7b, 0x97, 0xe5, 0x5b, 0x1a, 0x4d, + 0x7c, 0x19, 0xee, 0x24, 0xc8, 0xb4, 0xd7, 0x72, 0x3c, + 0xfe, 0xdf, 0x04, 0x5b, 0x8a, 0xca, 0xe4, 0x86, 0x95, + 0x17, 0xd8, 0x0e, 0x50, 0x61, 0x5d, 0x90, 0x35, 0xd5, + 0xd9, 0xc5, 0xa4, 0x0a, 0xf6, 0x02, 0x28, 0x0b, 0x54, + 0x25, 0x97, 0xb0, 0xcb, 0x18, 0x61, 0x9e, 0xeb, 0x35, + 0x92, 0x57, 0x59, 0xd1, 0x95, 0xe1, 0x00, 0xe8, 0xe4, + 0xaa, 0x0c, 0x38, 0xa3, 0xc2, 0xab, 0xe0, 0xf3, 0xd8, + 0xff, 0x04, 0xf3, 0xc3, 0x3c, 0x29, 0x50, 0x69, 0xc2, + 0x36, 0x94, 0xb5, 0xbb, 0xea, 0xcd, 0xd5, 0x42, 0xe2, + 0x8e, 0x8a, 0x94, 0xed, 0xb9, 0x11, 0x9f, 0x41, 0x2d, + 0x05, 0x4b, 0xe1, 0xfa, 0x72, 0x00, 0xb0, 0x90, 0x00 }; + uint8_t ct[] = { 0x5c, 0xb7, 0x2c, 0x6e, 0xdc, 0x87, 0x8f, + 0x15, 0x66, 0xe1, 0x02, 0x53, 0xaf, 0xc3, 0x64, 0xc9, + 0xfa, 0x54, 0x0d, 0x91, 0x4d, 0xb9, 0x4c, 0xbe, 0xe2, + 0x75, 0xd0, 0x91, 0x7c, 0xa6, 0xaf, 0x0d, 0x77, 0xac, + 0xb4, 0xef, 0x3b, 0xbe, 0x1a, 0x72, 0x2b, 0x2e, 0xf5, + 0xbd, 0x1d, 0x4b, 0x8e, 0x2a, 0xa5, 0x02, 0x4e, 0xc1, + 0x38, 0x8a, 0x20, 0x1e, 0x7b, 0xce, 0x79, 0x20, 0xae, + 0xc6, 0x15, 0x89, 0x5f, 0x76, 0x3a, 0x55, 0x64, 0xdc, + 0xc4, 0xc4, 0x82, 0xa2, 0xee, 0x1d, 0x8b, 0xfe, 0xcc, + 0x44, 0x98, 0xec, 0xa8, 0x3f, 0xbb, 0x75, 0xf9, 0xab, + 0x53, 0x0e, 0x0d, 0xaf, 0xbe, 0xde, 0x2f, 0xa5, 0x89, + 0x5b, 0x82, 0x99, 0x1b, 0x62, 0x77, 0xc5, 0x29, 0xe0, + 0xf2, 0x52, 0x9d, 0x7f, 0x79, 0x60, 0x6b, 0xe9, 0x67, + 0x06, 0x29, 0x6d, 0xed, 0xfa, 0x9d, 0x74, 0x12, 0xb6, + 0x16, 0x95, 0x8c, 0xb5, 0x63, 0xc6, 0x78, 0xc0, 0x28, + 0x25, 0xc3, 0x0d, 0x0a, 0xee, 0x77, 0xc4, 0xc1, 0x46, + 0xd2, 0x76, 0x54, 0x12, 0x42, 0x1a, 0x80, 0x8d, 0x13, + 0xce, 0xc8, 0x19, 0x69, 0x4c, 0x75, 0xad, 0x57, 0x2e, + 0x9b, 0x97, 0x3d, 0x94, 0x8b, 0x81, 0xa9, 0x33, 0x7c, + 0x3b, 0x2a, 0x17, 0x19, 0x2e, 0x22, 0xc2, 0x06, 0x9f, + 0x7e, 0xd1, 0x16, 0x2a, 0xf4, 0x4c, 0xde, 0xa8, 0x17, + 0x60, 0x36, 0x65, 0xe8, 0x07, 0xce, 0x40, 0xc8, 0xe0, + 0xdd, 0x9d, 0x63, 0x94, 0xdc, 0x6e, 0x31, 0x15, 0x3f, + 0xe1, 0x95, 0x5c, 0x47, 0xaf, 0xb5, 0x1f, 0x26, 0x17, + 0xee, 0x0c, 0x5e, 0x3b, 0x8e, 0xf1, 0xad, 0x75, 0x74, + 0xed, 0x34, 0x3e, 0xdc, 0x27, 0x43, 0xcc, 0x94, 0xc9, + 0x90, 0xe1, 0xf1, 0xfd, 0x26, 0x42, 0x53, 0xc1, 0x78, + 0xde, 0xa7, 0x39, 0xc0, 0xbe, 0xfe, 0xeb, 0xcd, 0x9f, + 0x9b, 0x76, 0xd4, 0x9c, 0x10, 0x15, 0xc9, 0xfe, 0xcf, + 0x50, 0xe5, 0x3b, 0x8b, 0x52, 0x04, 0xdb, 0xcd, 0x3e, + 0xed, 0x86, 0x38, 0x55, 0xda, 0xbc, 0xdc, 0xc9, 0x4b, + 0x31, 0xe3, 0x18, 0x02, 0x15, 0x68, 0x85, 0x5c, 0x8b, + 0x9e, 0x52, 0xa9, 0x81, 0x95, 0x7a, 0x11, 0x28, 0x27, + 0xf9, 0x78, 0xba, 0x96, 0x0f, 0x14, 0x47, 0x91, 0x1b, + 0x31, 0x7b, 0x55, 0x11, 0xfb, 0xcc, 0x7f, 0xb1, 0x3a, + 0xc1, 0x53, 0xdb, 0x74, 0x25, 0x11, 0x17, 0xe4, 0x86, + 0x1e, 0xb9, 0xe8, 0x3b, 0xff, 0xff, 0xc4, 0xeb, 0x77, + 0x55, 0x57, 0x90, 0x38, 0xe5, 0x79, 0x24, 0xb1, 0xf7, + 0x8b, 0x3e, 0x1a, 0xd9, 0x0b, 0xab, 0x2a, 0x07, 0x87, + 0x1b, 0x72, 0xdb, 0x5e, 0xef, 0x96, 0xc3, 0x34, 0x04, + 0x49, 0x66, 0xdb, 0x0c, 0x37, 0xca, 0xfd, 0x1a, 0x89, + 0xe5, 0x64, 0x6a, 0x35, 0x80, 0xeb, 0x64, 0x65, 0xf1, + 0x21, 0xdc, 0xe9, 0xcb, 0x88, 0xd8, 0x5b, 0x96, 0xcf, + 0x23, 0xcc, 0xcc, 0xd4, 0x28, 0x07, 0x67, 0xbe, 0xe8, + 0xee, 0xb2, 0x3d, 0x86, 0x52, 0x46, 0x1d, 0xb6, 0x49, + 0x31, 0x03, 0x00, 0x3b, 0xaf, 0x89, 0xf5, 0xe1, 0x82, + 0x61, 0xea, 0x43, 0xc8, 0x4a, 0x92, 0xeb, 0xff, 0xff, + 0xe4, 0x90, 0x9d, 0xc4, 0x6c, 0x51, 0x92, 0xf8, 0x25, + 0xf7, 0x70, 0x60, 0x0b, 0x96, 0x02, 0xc5, 0x57, 0xb5, + 0xf8, 0xb4, 0x31, 0xa7, 0x9d, 0x45, 0x97, 0x7d, 0xd9, + 0xc4, 0x1b, 0x86, 0x3d, 0xa9, 0xe1, 0x42, 0xe9, 0x00, + 0x20, 0xcf, 0xd0, 0x74, 0xd6, 0x92, 0x7b, 0x7a, 0xb3, + 0xb6, 0x72, 0x5d, 0x1a, 0x6f, 0x3f, 0x98, 0xb9, 0xc9, + 0xda, 0xa8, 0x98, 0x2a, 0xff, 0x06, 0x78, 0x28, 0x00 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +// set len_bitsgth to multiple of 8 respectively 128 +void test_set_1_block_size() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 256, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x98, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0xe9, 0xfe, 0xd8, 0xa6, 0x3d, 0x15, 0x53, + 0x04, 0xd7, 0x1d, 0xf2, 0x0b, 0xf3, 0xe8, 0x22, 0x14, + 0xb2, 0x0e, 0xd7, 0xda, 0xd2, 0xf2, 0x33, 0xdc, 0x3c, + 0x22, 0xd7, 0xbd, 0xee, 0xed, 0x8e, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp == 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp == 0); + + free(out); +} + +// inserted bit flip in msg[0] +void test_set_1_invalid() +{ + LIBLTE_ERROR_ENUM err_lte = LIBLTE_ERROR_INVALID_INPUTS; + int32 err_cmp = 0; + + uint8_t key[] = { 0xd3, 0xc5, 0xd5, 0x92, 0x32, 0x7f, 0xb1, + 0x1c, 0x40, 0x35, 0xc6, 0x68, 0x0a, 0xf8, 0xc6, 0xd1 }; + uint32_t count = 0x398a59b4; + uint8_t bearer = 0x15; + uint8_t direction = 1; + uint32_t len_bits = 253, len_bytes = (len_bits + 7) / 8; + uint8_t msg[] = { 0x99, 0x1b, 0xa6, 0x82, 0x4c, 0x1b, 0xfb, + 0x1a, 0xb4, 0x85, 0x47, 0x20, 0x29, 0xb7, 0x1d, 0x80, + 0x8c, 0xe3, 0x3e, 0x2c, 0xc3, 0xc0, 0xb5, 0xfc, 0x1f, + 0x3d, 0xe8, 0xa6, 0xdc, 0x66, 0xb1, 0xf0 }; + uint8_t ct[] = { 0xe9, 0xfe, 0xd8, 0xa6, 0x3d, 0x15, 0x53, + 0x04, 0xd7, 0x1d, 0xf2, 0x0b, 0xf3, 0xe8, 0x22, 0x14, + 0xb2, 0x0e, 0xd7, 0xda, 0xd2, 0xf2, 0x33, 0xdc, 0x3c, + 0x22, 0xd7, 0xbd, 0xee, 0xed, 0x8e, 0x78 }; + + uint8_t * out = (uint8_t *) calloc(len_bytes, + sizeof(uint8_t)); + + // encryption + err_lte = liblte_security_encryption_eea2(key, count, bearer, + direction, msg, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(ct, out, len_bytes); + assert(err_cmp != 0); + + // decryption + err_lte = liblte_security_decryption_eea2(key, count, bearer, + direction, ct, len_bits, out); + assert(err_lte == LIBLTE_SUCCESS); + + // compare cipher text + err_cmp = arrcmp(msg, out, len_bytes); + assert(err_cmp != 0); + + free(out); +} + +/* + * Functions + */ + +int main(int argc, char * argv[]) { + test_set_1(); + test_set_2(); + test_set_3(); + test_set_4(); + test_set_5(); + test_set_6(); + test_set_1_block_size(); + test_set_1_invalid(); +} diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index 7a37d0d5d..9ada2ba42 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -123,7 +123,7 @@ void basic_test() byte_buffer_t pdu_bufs[NBUFS]; for(int i=0;i pending_ack; void ack_add_rnti(uint16_t rnti); void ack_rem_rnti(uint16_t rnti); void ack_clear(uint32_t sf_idx); - void ack_set_pending(uint32_t sf_idx, uint16_t rnti, uint32_t n_pdcch); - bool ack_is_pending(uint32_t sf_idx, uint16_t rnti, uint32_t *last_n_pdcch = NULL); + void ack_set_pending(uint32_t sf_idx, uint16_t rnti, uint32_t tb_idx, uint32_t n_pdcch); + bool ack_is_pending(uint32_t sf_idx, uint16_t rnti, uint32_t tb_idx, uint32_t *last_n_pdcch = NULL); private: std::vector tx_mutex; diff --git a/srsenb/hdr/phy/phch_worker.h b/srsenb/hdr/phy/phch_worker.h index 906e8b9d0..383c9d583 100644 --- a/srsenb/hdr/phy/phch_worker.h +++ b/srsenb/hdr/phy/phch_worker.h @@ -45,7 +45,7 @@ public: void stop(); void reset(); - cf_t *get_buffer_rx(); + cf_t *get_buffer_rx(uint32_t antenna_idx); void set_time(uint32_t tti, uint32_t tx_mutex_cnt, srslte_timestamp_t tx_time); int add_rnti(uint16_t rnti); @@ -56,13 +56,15 @@ public: int read_ce_abs(float *ce_abs); int read_pusch_d(cf_t *pusch_d); void start_plot(); - + + void set_conf_dedicated_ack(uint16_t rnti, + bool rrc_completed); void set_config_dedicated(uint16_t rnti, srslte_uci_cfg_t *uci_cfg, srslte_pucch_sched_t *pucch_sched, srslte_refsignal_srs_cfg_t *srs_cfg, - uint32_t I_sr, bool pucch_cqi, uint32_t pmi_idx, bool pucch_cqi_ack); + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated); uint32_t get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]); @@ -73,12 +75,12 @@ private: void work_imp(); - int encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants, uint32_t sf_idx); - int decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch, uint32_t tti_rx); - int encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks, uint32_t sf_idx); - int encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants, uint32_t sf_idx); - int encode_pdcch_ul(srslte_enb_ul_pusch_t *grants, uint32_t nof_grants, uint32_t sf_idx); - int decode_pucch(uint32_t tti_rx); + int encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants); + int decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch); + int encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks); + int encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants); + int encode_pdcch_ul(srslte_enb_ul_pusch_t *grants, uint32_t nof_grants); + int decode_pucch(); /* Common objects */ @@ -87,30 +89,41 @@ private: bool initiated; bool running; - cf_t *signal_buffer_rx; - cf_t *signal_buffer_tx; - uint32_t tti_rx, tti_tx, tti_sched_ul, sf_rx, sf_tx, sf_sched_ul, tx_mutex_cnt; - + cf_t *signal_buffer_rx[SRSLTE_MAX_PORTS]; + cf_t *signal_buffer_tx[SRSLTE_MAX_PORTS]; + uint32_t tti_rx, tti_tx_dl, tti_tx_ul; + uint32_t sf_rx, sf_tx, tx_mutex_cnt; + uint32_t t_rx, t_tx_dl, t_tx_ul; srslte_enb_dl_t enb_dl; srslte_enb_ul_t enb_ul; - srslte_timestamp_t tx_time; + srslte_timestamp_t tx_time; // Class to store user information class ue { public: - ue() : I_sr(0), I_sr_en(false), cqi_en(false), pucch_cqi_ack(false), pmi_idx(0), has_grant_tti(0) {bzero(&metrics, sizeof(phy_metrics_t));} + ue() : I_sr(0), I_sr_en(false), cqi_en(false), pucch_cqi_ack(false), pmi_idx(0), has_grant_tti(0), + dedicated_ack(false) {bzero(&metrics, sizeof(phy_metrics_t));} uint32_t I_sr; uint32_t pmi_idx; + uint32_t ri_idx; bool I_sr_en; bool cqi_en; + bool ri_en; bool pucch_cqi_ack; int has_grant_tti; + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated; + bool dedicated_ack; uint32_t rnti; srslte_enb_ul_phich_info_t phich_info; void metrics_read(phy_metrics_t *metrics); void metrics_dl(uint32_t mcs); void metrics_ul(uint32_t mcs, float rssi, float sinr, uint32_t turbo_iters); + + int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS]; + int last_ul_tbs[2*HARQ_DELAY_MS]; + srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS]; + private: phy_metrics_t metrics; }; diff --git a/srsenb/hdr/phy/phy.h b/srsenb/hdr/phy/phy.h index 9ab1efd74..a1616c268 100644 --- a/srsenb/hdr/phy/phy.h +++ b/srsenb/hdr/phy/phy.h @@ -66,6 +66,7 @@ public: static uint32_t tti_to_subf(uint32_t tti); void start_plot(); + void set_conf_dedicated_ack(uint16_t rnti, bool dedicated_ack); void set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated); void get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]); diff --git a/srsenb/hdr/upper/pdcp.h b/srsenb/hdr/upper/pdcp.h index 228490312..8c5b05275 100644 --- a/srsenb/hdr/upper/pdcp.h +++ b/srsenb/hdr/upper/pdcp.h @@ -67,8 +67,9 @@ private: uint16_t rnti; srsenb::rlc_interface_pdcp *rlc; // rlc_interface_pdcp - void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu); - }; + void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu); + bool rb_is_um(uint32_t lcid); + }; class user_interface_gtpu : public srsue::gw_interface_pdcp { diff --git a/srsenb/hdr/upper/rlc.h b/srsenb/hdr/upper/rlc.h index abbf99516..b937cd216 100644 --- a/srsenb/hdr/upper/rlc.h +++ b/srsenb/hdr/upper/rlc.h @@ -54,6 +54,7 @@ public: // rlc_interface_pdcp void write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *sdu); + bool rb_is_um(uint16_t rnti, uint32_t lcid); std::string get_rb_name(uint32_t lcid); // rlc_interface_mac diff --git a/srsenb/hdr/upper/rrc.h b/srsenb/hdr/upper/rrc.h index e0b9dd158..8b402fa86 100644 --- a/srsenb/hdr/upper/rrc.h +++ b/srsenb/hdr/upper/rrc.h @@ -79,6 +79,7 @@ typedef struct { LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_STRUCT sibs[LIBLTE_RRC_MAX_SIB]; LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT mac_cnfg; LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT pusch_cfg; + LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT antenna_info; rrc_cfg_sr_t sr_cfg; rrc_cfg_cqi_t cqi_cfg; rrc_cfg_qci_t qci_cfg[MAX_NOF_QCI]; @@ -264,7 +265,7 @@ public: uint32_t cqi_idx; bool cqi_allocated; int cqi_sched_sf_idx; - bool cqi_sched_prb_idx; + int cqi_sched_prb_idx; int get_drbid_config(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb, int drbid); }; diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index 82b4e8145..fad7e1528 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -136,7 +136,7 @@ bool enb::init(all_args_t *args_) dev_args = (char*) args->rf.device_args.c_str(); } - if(!radio.init(dev_args, dev_name)) + if(!radio.init(dev_args, dev_name, args->enb.nof_ports)) { printf("Failed to find device %s with args %s\n", args->rf.device_name.c_str(), args->rf.device_args.c_str()); diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 3beb85a65..dea3866a7 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -37,7 +37,7 @@ namespace srsenb { int enb::parse_cell_cfg(all_args_t *args, srslte_cell_t *cell) { cell->id = args->enb.pci; cell->cp = SRSLTE_CP_NORM; - cell->nof_ports = 1; + cell->nof_ports = args->enb.nof_ports; cell->nof_prb = args->enb.n_prb; LIBLTE_RRC_PHICH_CONFIG_STRUCT phichcfg; @@ -749,7 +749,7 @@ int enb::parse_sibs(all_args_t *args, rrc_cfg_t *rrc_cfg, phy_cfg_t *phy_config_ } // Fill rest of data from enb config - sib1->cell_id = args->enb.s1ap.enb_id; + sib1->cell_id = (args->enb.s1ap.enb_id << 8) + args->enb.s1ap.cell_id; sib1->tracking_area_code = args->enb.s1ap.tac; sib1->freq_band_indicator = srslte_band_get_band(args->rf.dl_earfcn); sib1->N_plmn_ids = 1; @@ -842,6 +842,30 @@ bool enb::sib_is_present(LIBLTE_RRC_SCHEDULING_INFO_STRUCT *sched_info, uint32_t int enb::parse_rr(all_args_t* args, rrc_cfg_t* rrc_cfg) { + + /* Transmission mode config section */ + if (args->enb.transmission_mode < 0 || args->enb.transmission_mode > LIBLTE_RRC_TRANSMISSION_MODE_N_ITEMS) { + ERROR("Invalid transmission mode (%d). Only indexes 1-4 are implemented.\n", args->enb.transmission_mode); + return SRSLTE_ERROR; + } + + bzero(&rrc_cfg->antenna_info, sizeof(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT)); + rrc_cfg->antenna_info.tx_mode = (LIBLTE_RRC_TRANSMISSION_MODE_ENUM) (args->enb.transmission_mode - 1); + + if (rrc_cfg->antenna_info.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) { + rrc_cfg->antenna_info.ue_tx_antenna_selection_setup = LIBLTE_RRC_UE_TX_ANTENNA_SELECTION_OPEN_LOOP; + rrc_cfg->antenna_info.ue_tx_antenna_selection_setup_present = true; + + rrc_cfg->antenna_info.codebook_subset_restriction_choice = LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM3; + } else if (rrc_cfg->antenna_info.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { + rrc_cfg->antenna_info.ue_tx_antenna_selection_setup = LIBLTE_RRC_UE_TX_ANTENNA_SELECTION_CLOSED_LOOP; + rrc_cfg->antenna_info.ue_tx_antenna_selection_setup_present = true; + + rrc_cfg->antenna_info.codebook_subset_restriction_choice = LIBLTE_RRC_CODEBOOK_SUBSET_RESTRICTION_N2_TM4; + rrc_cfg->antenna_info.codebook_subset_restriction = 0b111111; + rrc_cfg->antenna_info.codebook_subset_restriction_present = true; + } + /* MAC config section */ parser::section mac_cnfg("mac_cnfg"); diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc index 6c8458540..4e706cfc7 100644 --- a/srsenb/src/mac/mac.cc +++ b/srsenb/src/mac/mac.cc @@ -24,10 +24,10 @@ * */ -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #include #include @@ -262,10 +262,10 @@ void mac::rl_ok(uint16_t rnti) } } -int mac::ack_info(uint32_t tti, uint16_t rnti, bool ack) +int mac::ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack) { log_h->step(tti); - uint32_t nof_bytes = scheduler.dl_ack_info(tti, rnti, ack); + uint32_t nof_bytes = scheduler.dl_ack_info(tti, rnti, tb_idx, ack); ue_db[rnti]->metrics_tx(ack, nof_bytes); if (ack) { @@ -305,11 +305,51 @@ int mac::crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc) } } -int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) +int mac::set_dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dl_ant_info) { + log_h->step(tti); + + if (ue_db.count(rnti)) { + scheduler.dl_ant_info(rnti, dl_ant_info); + } else { + Error("User rnti=0x%x not found\n", rnti); + return -1; + } + return 0; +} + +int mac::ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value) { log_h->step(tti); if (ue_db.count(rnti)) { + scheduler.dl_ri_info(tti, rnti, ri_value); + ue_db[rnti]->metrics_dl_ri(ri_value); + } else { + Error("User rnti=0x%x not found\n", rnti); + return -1; + } + return 0; +} + +int mac::pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) +{ + log_h->step(tti); + + if (ue_db.count(rnti)) { + scheduler.dl_pmi_info(tti, rnti, pmi_value); + ue_db[rnti]->metrics_dl_pmi(pmi_value); + } else { + Error("User rnti=0x%x not found\n", rnti); + return -1; + } + return 0; +} + +int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) +{ + log_h->step(tti); + + if (ue_db.count(rnti)) { scheduler.dl_cqi_info(tti, rnti, cqi_value); ue_db[rnti]->metrics_dl_cqi(cqi_value); } else { @@ -406,7 +446,7 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) log_h->step(tti); if (!started) { - return 0; + return 0; } if (!dl_sched_res) { @@ -431,43 +471,54 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) // Copy grant info dl_sched_res->sched_grants[n].rnti = rnti; + dl_sched_res->sched_grants[n].dci_format = sched_result.data[i].dci_format; memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.data[i].dci, sizeof(srslte_ra_dl_dci_t)); memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.data[i].dci_location, sizeof(srslte_dci_location_t)); - - dl_sched_res->sched_grants[n].softbuffer = ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.harq_process); - - // Get PDU if it's a new transmission - if (sched_result.data[i].nof_pdu_elems > 0) { - dl_sched_res->sched_grants[n].data = ue_db[rnti]->generate_pdu(sched_result.data[i].pdu, - sched_result.data[i].nof_pdu_elems, - sched_result.data[i].tbs); - if (pcap) { - pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data, sched_result.data[i].tbs, rnti, true, tti); + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + dl_sched_res->sched_grants[n].softbuffers[tb] = + ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.harq_process, tb); + + if (sched_result.data[i].nof_pdu_elems[tb] > 0) { + /* Get PDU if it's a new transmission */ + dl_sched_res->sched_grants[n].data[tb] = ue_db[rnti]->generate_pdu(sched_result.data[i].pdu[tb], + sched_result.data[i].nof_pdu_elems[tb], + sched_result.data[i].tbs[tb]); + + if (!dl_sched_res->sched_grants[n].data[tb]) { + Error("Error! PDU was not generated (rnti=0x%04x, tb=%d)\n", rnti, tb); + sched_result.data[i].dci.tb_en[tb] = false; + } + + if (pcap) { + pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti); + } + + } else { + /* TB not enabled OR no data to send: set pointers to NULL */ + dl_sched_res->sched_grants[n].data[tb] = NULL; } - - } else { - dl_sched_res->sched_grants[n].data = NULL; } n++; } - + // Copy RAR grants for (uint32_t i=0;isched_grants[n].rnti = sched_result.rar[i].rarnti; + dl_sched_res->sched_grants[n].rnti = sched_result.rar[i].rarnti; + dl_sched_res->sched_grants[n].dci_format = SRSLTE_DCI_FORMAT1A; // Force Format 1A memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.rar[i].dci, sizeof(srslte_ra_dl_dci_t)); memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.rar[i].dci_location, sizeof(srslte_dci_location_t)); // Set softbuffer (there are no retx in RAR but a softbuffer is required) - dl_sched_res->sched_grants[n].softbuffer = &rar_softbuffer_tx; + dl_sched_res->sched_grants[n].softbuffers[0] = &rar_softbuffer_tx; // Assemble PDU - dl_sched_res->sched_grants[n].data = assemble_rar(sched_result.rar[i].grants, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs); + dl_sched_res->sched_grants[n].data[0] = assemble_rar(sched_result.rar[i].grants, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs); if (pcap) { - pcap->write_dl_ranti(dl_sched_res->sched_grants[n].data, sched_result.data[i].tbs, dl_sched_res->sched_grants[n].rnti, true, tti); + pcap->write_dl_ranti(dl_sched_res->sched_grants[n].data[0], sched_result.data[i].tbs[0], dl_sched_res->sched_grants[n].rnti, true, tti); } n++; @@ -476,26 +527,27 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) // Copy SI and Paging grants for (uint32_t i=0;isched_grants[n].rnti = (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH ) ? SRSLTE_SIRNTI : SRSLTE_PRNTI; + dl_sched_res->sched_grants[n].rnti = (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH ) ? SRSLTE_SIRNTI : SRSLTE_PRNTI; + dl_sched_res->sched_grants[n].dci_format = SRSLTE_DCI_FORMAT1A; // Force Format 1A memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.bc[i].dci, sizeof(srslte_ra_dl_dci_t)); memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.bc[i].dci_location, sizeof(srslte_dci_location_t)); // Set softbuffer if (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH) { - dl_sched_res->sched_grants[n].softbuffer = &bcch_softbuffer_tx[sched_result.bc[i].index]; - dl_sched_res->sched_grants[n].data = assemble_si(sched_result.bc[i].index); + dl_sched_res->sched_grants[n].softbuffers[0] = &bcch_softbuffer_tx[sched_result.bc[i].index]; + dl_sched_res->sched_grants[n].data[0] = assemble_si(sched_result.bc[i].index); #ifdef WRITE_SIB_PCAP if (pcap) { pcap->write_dl_sirnti(dl_sched_res->sched_grants[n].data, sched_result.bc[i].tbs, true, tti); } #endif } else { - dl_sched_res->sched_grants[n].softbuffer = &pcch_softbuffer_tx; - dl_sched_res->sched_grants[n].data = pcch_payload_buffer; + dl_sched_res->sched_grants[n].softbuffers[0] = &pcch_softbuffer_tx; + dl_sched_res->sched_grants[n].data[0] = pcch_payload_buffer; rlc_h->read_pdu_pcch(pcch_payload_buffer, pcch_payload_buffer_len); if (pcap) { - pcap->write_dl_pch(dl_sched_res->sched_grants[n].data, sched_result.bc[i].tbs, true, tti); + pcap->write_dl_pch(dl_sched_res->sched_grants[n].data[0], sched_result.bc[i].tbs, true, tti); } } @@ -601,7 +653,7 @@ int mac::get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res) ul_sched_res->nof_phich = sched_result.nof_phich_elems; return SRSLTE_SUCCESS; } - + void mac::tti_clock() { timers_thread.tti_clock(); diff --git a/srsenb/src/mac/scheduler.cc b/srsenb/src/mac/scheduler.cc index 801b68d38..5a0da1015 100644 --- a/srsenb/src/mac/scheduler.cc +++ b/srsenb/src/mac/scheduler.cc @@ -5,10 +5,10 @@ #include "srslte/common/pdu.h" #include "mac/scheduler.h" -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) namespace srsenb { @@ -238,12 +238,25 @@ int sched::dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code) return ret; } -int sched::dl_ack_info(uint32_t tti, uint16_t rnti, bool ack) +int sched::dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dl_ant_info) { + pthread_mutex_lock(&mutex); + int ret = 0; + if (ue_db.count(rnti)) { + ue_db[rnti].set_dl_ant_info(dl_ant_info); + } else { + Error("User rnti=0x%x not found\n", rnti); + ret = -1; + } + pthread_mutex_unlock(&mutex); + return ret; +} + +int sched::dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack) { pthread_mutex_lock(&mutex); int ret = 0; if (ue_db.count(rnti)) { - ret = ue_db[rnti].set_ack_info(tti, ack); + ret = ue_db[rnti].set_ack_info(tti, tb_idx, ack); } else { Error("User rnti=0x%x not found\n", rnti); ret = -1; @@ -266,12 +279,12 @@ int sched::ul_crc_info(uint32_t tti, uint16_t rnti, bool crc) return ret; } -int sched::dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) +int sched::dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) { pthread_mutex_lock(&mutex); int ret = 0; if (ue_db.count(rnti)) { - ue_db[rnti].set_dl_cqi(tti, cqi_value); + ue_db[rnti].set_dl_ri(tti, cqi_value); } else { Error("User rnti=0x%x not found\n", rnti); ret = -1; @@ -280,6 +293,34 @@ int sched::dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) return ret; } +int sched::dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) +{ + pthread_mutex_lock(&mutex); + int ret = 0; + if (ue_db.count(rnti)) { + ue_db[rnti].set_dl_pmi(tti, pmi_value); + } else { + Error("User rnti=0x%x not found\n", rnti); + ret = -1; + } + pthread_mutex_unlock(&mutex); + return ret; +} + +int sched::dl_cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) +{ + pthread_mutex_lock(&mutex); + int ret = 0; + if (ue_db.count(rnti)) { + ue_db[rnti].set_dl_cqi(tti, cqi_value); + } else { + Error("User rnti=0x%x not found\n", rnti); + ret = -1; + } + pthread_mutex_unlock(&mutex); + return ret; +} + int sched::dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size) { for (int i=0;ifirst; dl_harq_proc *h = dl_metric->get_user_allocation(user); - + srslte_dci_format_t dci_format = user->get_dci_format(); + data[nof_data_elems].dci_format = dci_format; + + uint32_t aggr_level = user->get_aggr_level(srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, cfg.cell.nof_prb, cfg.cell.nof_ports)); if (h) { // Try to schedule DCI first if (generate_dci(&data[nof_data_elems].dci_location, - user->get_locations(current_cfi, sf_idx), - user->get_aggr_level(srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, cfg.cell.nof_prb, cfg.cell.nof_ports)), user)) + user->get_locations(current_cfi, sf_idx), + aggr_level, user)) { - bool is_newtx = h->is_empty(); - int tbs = user->generate_format1(h, &data[nof_data_elems], current_tti, current_cfi); + bool is_newtx = h->is_empty(0); + int tbs = 0; + switch(dci_format) { + case SRSLTE_DCI_FORMAT1: + tbs = user->generate_format1(h, &data[nof_data_elems], current_tti, current_cfi); + break; + case SRSLTE_DCI_FORMAT2: + tbs = user->generate_format2(h, &data[nof_data_elems], current_tti, current_cfi); + break; + case SRSLTE_DCI_FORMAT2A: + tbs = user->generate_format2a(h, &data[nof_data_elems], current_tti, current_cfi); + break; + default: + Error("DCI format (%d) not implemented\n", dci_format); + } if (tbs >= 0) { - log_h->info("SCHED: DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, n_rtx=%d, tbs=%d, buffer=%d\n", + log_h->info("SCHED: DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, n_rtx=%d, tbs=%d, buffer=%d, tb_en={%s,%s}\n", !is_newtx?"retx":"tx", rnti, h->get_id(), h->get_rbgmask(), - data[nof_data_elems].dci_location.L, data[nof_data_elems].dci_location.ncce, h->nof_retx(), - tbs, user->get_pending_dl_new_data(current_tti)); + data[nof_data_elems].dci_location.L, data[nof_data_elems].dci_location.ncce, h->nof_retx(0) + h->nof_retx(1), + tbs, user->get_pending_dl_new_data(current_tti), data[nof_data_elems].dci.tb_en[0]?"y":"n", + data[nof_data_elems].dci.tb_en[1]?"y":"n"); nof_data_elems++; } else { log_h->warning("SCHED: Error DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, tbs=%d, buffer=%d\n", @@ -619,7 +677,9 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST]) tbs, user->get_pending_dl_new_data(current_tti)); } } else { - h->reset(); + for(uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + h->reset(tb); + } Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d\n", rnti, h->get_id()); } } @@ -678,17 +738,17 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched pthread_mutex_lock(&mutex); /* If dl_sched() not yet called this tti (this tti is +4ms advanced), reset CCE state */ - if ((current_tti+4)%10240 != tti) { + if (TTI_TX(current_tti) != tti) { bzero(used_cce, MAX_CCE*sizeof(bool)); } /* Initialize variables */ current_tti = tti; sfn = tti/10; - if (tti > 4) { - sf_idx = (tti-4)%10; + if (tti > HARQ_DELAY_MS) { + sf_idx = (tti-HARQ_DELAY_MS)%10; } else { - sf_idx = (tti+10240-4)%10; + sf_idx = (tti+10240-HARQ_DELAY_MS)%10; } int nof_dci_elems = 0; int nof_phich_elems = 0; @@ -707,7 +767,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched /* Indicate PHICH acknowledgment if needed */ if (h->has_pending_ack()) { - sched_result->phich[nof_phich_elems].phich = h->get_ack()?ul_sched_phich_t::ACK:ul_sched_phich_t::NACK; + sched_result->phich[nof_phich_elems].phich = h->get_ack(0)?ul_sched_phich_t::ACK:ul_sched_phich_t::NACK; sched_result->phich[nof_phich_elems].rnti = rnti; nof_phich_elems++; } @@ -764,7 +824,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched if (h) { ul_harq_proc::ul_alloc_t alloc = h->get_alloc(); - bool is_newtx = h->is_empty(); + bool is_newtx = h->is_empty(0); bool needs_pdcch = !h->is_adaptive_retx() && !is_rar; // Set number of retx @@ -783,7 +843,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched user->get_locations(current_cfi, sf_idx), aggr_level)) { - h->reset(); + h->reset(0); log_h->warning("SCHED: Could not schedule UL DCI rnti=0x%x, pid=%d, L=%d\n", rnti, h->get_id(), aggr_level); sched_result->pusch[nof_dci_elems].needs_pdcch = false; @@ -810,7 +870,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched is_newtx?"tx":"retx", rnti, h->get_id(), sched_result->pusch[nof_dci_elems].dci_location.L, sched_result->pusch[nof_dci_elems].dci_location.ncce, - alloc.RB_start, alloc.RB_start+alloc.L, h->nof_retx(), sched_result->pusch[nof_dci_elems].tbs, + alloc.RB_start, alloc.RB_start+alloc.L, h->nof_retx(0), sched_result->pusch[nof_dci_elems].tbs, user->get_pending_ul_new_data(current_tti),pending_data_before, user->get_pending_ul_old_data()); nof_dci_elems++; diff --git a/srsenb/src/mac/scheduler_harq.cc b/srsenb/src/mac/scheduler_harq.cc index a6ae70d19..a10fb562f 100644 --- a/srsenb/src/mac/scheduler_harq.cc +++ b/srsenb/src/mac/scheduler_harq.cc @@ -25,16 +25,15 @@ */ #include -#include #include "srslte/srslte.h" #include "srslte/common/pdu.h" #include "mac/scheduler.h" -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) namespace srsenb { @@ -50,7 +49,9 @@ void harq_proc::config(uint32_t id_, uint32_t max_retx_, srslte::log* log_h_) log_h = log_h_; id = id_; max_retx = max_retx_; - ndi = false; + for (int i = 0; i < SRSLTE_MAX_TB; i++) { + ndi[i] = false; + } } void harq_proc::set_max_retx(uint32_t max_retx_) { @@ -63,101 +64,101 @@ uint32_t harq_proc::get_id() return id; } -void harq_proc::reset() +void harq_proc::reset(uint32_t tb_idx) { - active = false; - ack = true; - ack_received = false; - n_rtx = 0; + active[tb_idx] = false; + ack[tb_idx] = true; + ack_received[tb_idx] = false; + n_rtx[tb_idx] = 0; tti = 0; - last_mcs = -1; - last_tbs = -1; - tx_cnt = 0; + last_mcs[tb_idx] = -1; + last_tbs[tb_idx] = -1; + tx_cnt[tb_idx] = 0; } -bool harq_proc::is_empty() +bool harq_proc::is_empty(uint32_t tb_idx) { - return !active || (active && ack && ack_received); + return !active[tb_idx] || (active[tb_idx] && ack[tb_idx] && ack_received[tb_idx]); } -bool harq_proc::has_pending_retx_common() +bool harq_proc::has_pending_retx_common(uint32_t tb_idx) { - return !ack && n_rtx < max_retx; + return !ack[tb_idx] && n_rtx[tb_idx] < max_retx; } uint32_t harq_proc::get_tti() { - return tti; + return (uint32_t) tti; } -bool harq_proc::get_ack() +bool harq_proc::get_ack(uint32_t tb_idx) { - return ack; + return ack[tb_idx]; } -void harq_proc::set_ack(bool ack_) +void harq_proc::set_ack(uint32_t tb_idx, bool ack_) { - ack = ack_; - ack_received = true; - log_h->debug("ACK=%d received pid=%d, n_rtx=%d, max_retx=%d\n", ack_, id, n_rtx, max_retx); - if (n_rtx + 1 >= max_retx) { - Warning("SCHED: discarting TB pid=%d, tti=%d, maximum number of retx exceeded (%d)\n", id, tti, max_retx); - active = false; + ack[tb_idx] = ack_; + ack_received[tb_idx] = true; + log_h->debug("ACK=%d received pid=%d, tb_idx=%d, n_rtx=%d, max_retx=%d\n", ack_, id, tb_idx, n_rtx[tb_idx], max_retx); + if (n_rtx[tb_idx] + 1 >= max_retx) { + Warning("SCHED: discarting TB %d pid=%d, tti=%d, maximum number of retx exceeded (%d)\n", tb_idx, id, tti, max_retx); + active[tb_idx] = false; } } -void harq_proc::new_tx_common(uint32_t tti_, int mcs, int tbs) +void harq_proc::new_tx_common(uint32_t tb_idx, uint32_t tti_, int mcs, int tbs) { - reset(); - ndi = !ndi; + reset(tb_idx); + ndi[tb_idx] = !ndi[tb_idx]; tti = tti_; - tx_cnt++; - last_mcs = mcs; - last_tbs = tbs; + tx_cnt[tb_idx]++; + last_mcs[tb_idx] = mcs; + last_tbs[tb_idx] = tbs; if (max_retx) { - active = true; + active[tb_idx] = true; } else { - active = false; // Can reuse this process if no retx are allowed + active[tb_idx] = false; // Can reuse this process if no retx are allowed } } -void harq_proc::new_retx(uint32_t tti_, int *mcs, int *tbs) +void harq_proc::new_retx(uint32_t tb_idx, uint32_t tti_, int *mcs, int *tbs) { - ack_received = false; + ack_received[tb_idx] = false; tti = tti_; - n_rtx++; + n_rtx[tb_idx]++; if (mcs) { - *mcs = last_mcs; + *mcs = last_mcs[tb_idx]; } if (tbs) { - *tbs = last_tbs; + *tbs = last_tbs[tb_idx]; } } -uint32_t harq_proc::nof_tx() +uint32_t harq_proc::nof_tx(uint32_t tb_idx) { - return tx_cnt; + return tx_cnt[tb_idx]; } -uint32_t harq_proc::nof_retx() +uint32_t harq_proc::nof_retx(uint32_t tb_idx) { - return n_rtx; + return n_rtx[tb_idx]; } -bool harq_proc::get_ndi() +bool harq_proc::get_ndi(uint32_t tb_idx) { - return ndi; + return ndi[tb_idx]; } /****************************************************** * UE::DL HARQ class * ******************************************************/ -void dl_harq_proc::new_tx(uint32_t tti, int mcs, int tbs, uint32_t n_cce_) +void dl_harq_proc::new_tx(uint32_t tb_idx, uint32_t tti, int mcs, int tbs, uint32_t n_cce_) { n_cce = n_cce_; - new_tx_common(tti, mcs, tbs); + new_tx_common(tb_idx, tti, mcs, tbs); } uint32_t dl_harq_proc::get_n_cce() @@ -175,14 +176,14 @@ void dl_harq_proc::set_rbgmask(uint32_t new_mask) rbgmask = new_mask; } -bool dl_harq_proc::has_pending_retx(uint32_t current_tti) +bool dl_harq_proc::has_pending_retx(uint32_t tb_idx, uint32_t current_tti) { - return srslte_tti_interval(current_tti, tti) >= 8 && has_pending_retx_common(); + return srslte_tti_interval(current_tti, tti) >= (2*HARQ_DELAY_MS) && has_pending_retx_common(tb_idx); } -int dl_harq_proc::get_tbs() +int dl_harq_proc::get_tbs(uint32_t tb_idx) { - return last_tbs; + return last_tbs[tb_idx]; } @@ -215,7 +216,7 @@ bool ul_harq_proc::is_adaptive_retx() void ul_harq_proc::new_tx(uint32_t tti_, int mcs, int tbs) { need_ack = true; - new_tx_common(tti_, mcs, tbs); + new_tx_common(0, tti_, mcs, tbs); pending_data = tbs; } @@ -225,10 +226,10 @@ bool ul_harq_proc::has_pending_ack() bool ret = need_ack; // Reset if already received a positive ACK - if (active && ack) { - active = false; + if (active[0] && ack[0]) { + active[0] = false; } - if (!active) { + if (!active[0]) { need_ack = false; } return ret; @@ -238,15 +239,15 @@ bool ul_harq_proc::has_pending_ack() void ul_harq_proc::reset_pending_data() { - if (!active) { + if (!active[0]) { pending_data = 0; } } - uint32_t ul_harq_proc::get_pending_data() +uint32_t ul_harq_proc::get_pending_data() { - return pending_data; + return (uint32_t) pending_data; } void ul_harq_proc::set_rar_mcs(uint32_t mcs) diff --git a/srsenb/src/mac/scheduler_metric.cc b/srsenb/src/mac/scheduler_metric.cc index 708ab2dd8..60a299c04 100644 --- a/srsenb/src/mac/scheduler_metric.cc +++ b/srsenb/src/mac/scheduler_metric.cc @@ -28,10 +28,10 @@ #include "mac/scheduler_harq.h" #include "mac/scheduler_metric.h" -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) namespace srsenb { @@ -142,8 +142,12 @@ dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user) dl_harq_proc *h = user->get_pending_dl_harq(current_tti); // Time-domain RR scheduling +#if ASYNC_DL_SCHED if (pending_data || h) { - if (nof_users_with_data) { +#else + if (pending_data || (h && !h->is_empty())) { +#endif + if (nof_users_with_data) { if (nof_users_with_data == 2) { } if ((current_tti%nof_users_with_data) != user->ue_idx) { @@ -153,7 +157,11 @@ dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user) } // Schedule retx if we have space +#if ASYNC_DL_SCHED if (h) { +#else + if (h && !h->is_empty()) { +#endif uint32_t retx_mask = h->get_rbgmask(); // If can schedule the same mask, do it if (!allocation_is_valid(retx_mask)) { @@ -170,10 +178,14 @@ dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user) } } } - // If could not schedule the reTx, or there wasn't any pending retx, find an empty PID + // If could not schedule the reTx, or there wasn't any pending retx, find an empty PID +#if ASYNC_DL_SCHED h = user->get_empty_dl_harq(); if (h) { - // Allocate resources based on pending data +#else + if (h && h->is_empty()) { +#endif + // Allocate resources based on pending data if (pending_data) { uint32_t pending_rb = user->get_required_prb_dl(pending_data, nof_ctrl_symbols); uint32_t newtx_mask = 0; @@ -212,7 +224,7 @@ void ul_metric_rr::new_tti(std::map &ue_db, uint32_t nof_rb_, nof_users_with_data = 0; for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { sched_ue *user = (sched_ue*) &iter->second; - if (user->get_pending_ul_new_data(current_tti) || !user->get_ul_harq(current_tti)->is_empty()) { + if (user->get_pending_ul_new_data(current_tti) || !user->get_ul_harq(current_tti)->is_empty(0)) { user->ue_idx = nof_users_with_data; nof_users_with_data++; } @@ -284,7 +296,7 @@ ul_harq_proc* ul_metric_rr::get_user_allocation(sched_ue *user) uint32_t pending_data = user->get_pending_ul_new_data(current_tti); ul_harq_proc *h = user->get_ul_harq(current_tti); - if (pending_data || !h->is_empty()) { + if (pending_data || !h->is_empty(0)) { if (nof_users_with_data) { if ((current_tti%nof_users_with_data) != user->ue_idx) { return NULL; @@ -294,7 +306,7 @@ ul_harq_proc* ul_metric_rr::get_user_allocation(sched_ue *user) // Schedule retx if we have space - if (!h->is_empty()) { + if (!h->is_empty(0)) { ul_harq_proc::ul_alloc_t alloc = h->get_alloc(); @@ -313,7 +325,7 @@ ul_harq_proc* ul_metric_rr::get_user_allocation(sched_ue *user) } } // If could not schedule the reTx, or there wasn't any pending retx, find an empty PID - if (h->is_empty()) { + if (h->is_empty(0)) { // Allocate resources based on pending data if (pending_data) { uint32_t pending_rb = user->get_required_prb_ul(pending_data); diff --git a/srsenb/src/mac/scheduler_ue.cc b/srsenb/src/mac/scheduler_ue.cc index 38058415f..5adee6e43 100644 --- a/srsenb/src/mac/scheduler_ue.cc +++ b/srsenb/src/mac/scheduler_ue.cc @@ -25,21 +25,16 @@ */ #include -#include -#include -#include -#include -#include #include "srslte/srslte.h" #include "srslte/common/pdu.h" #include "mac/scheduler_ue.h" #include "mac/scheduler.h" -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) /****************************************************** * UE class * @@ -109,8 +104,10 @@ void sched_ue::reset() ul_cqi_tti = 0; cqi_request_tti = 0; for (int i=0;iset_ack(crc_res); + get_ul_harq(tti)->set_ack(0, crc_res); +} + +void sched_ue::set_dl_ri(uint32_t tti, uint32_t ri) +{ + dl_ri = ri; + dl_ri_tti = tti; +} + +void sched_ue::set_dl_pmi(uint32_t tti, uint32_t pmi) +{ + dl_pmi = pmi; + dl_pmi_tti = tti; } void sched_ue::set_dl_cqi(uint32_t tti, uint32_t cqi) { - dl_cqi = cqi; - dl_cqi_tti = tti; + dl_cqi = cqi; + dl_cqi_tti = tti; +} + +void sched_ue::set_dl_ant_info(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *d) +{ + memcpy(&dl_ant_info, d, sizeof(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT)); } void sched_ue::set_ul_cqi(uint32_t tti, uint32_t cqi, uint32_t ul_ch_code) @@ -357,10 +371,10 @@ void sched_ue::tpc_dec() { // Generates a Format1 grant -int sched_ue::generate_format1(dl_harq_proc *h, - sched_interface::dl_sched_data_t *data, - uint32_t tti, - uint32_t cfi) +int sched_ue::generate_format1(dl_harq_proc *h, + sched_interface::dl_sched_data_t *data, + uint32_t tti, + uint32_t cfi) { srslte_ra_dl_dci_t *dci = &data->dci; bzero(dci, sizeof(srslte_ra_dl_dci_t)); @@ -379,7 +393,7 @@ int sched_ue::generate_format1(dl_harq_proc *h, if (is_first_dl_tx()) { need_conres_ce = true; } - if (h->is_empty()) { + if (h->is_empty(0)) { uint32_t req_bytes = get_pending_dl_new_data(tti); @@ -395,49 +409,181 @@ int sched_ue::generate_format1(dl_harq_proc *h, mcs = fixed_mcs_dl; } - h->new_tx(tti, mcs, tbs, data->dci_location.ncce); - + h->new_tx(0, tti, mcs, tbs, data->dci_location.ncce); + + // Allocate MAC ConRes CE + if (need_conres_ce) { + data->pdu[0][0].lcid = srslte::sch_subh::CON_RES_ID; + data->nof_pdu_elems[0]++; + Info("SCHED: Added MAC Contention Resolution CE for rnti=0x%x\n", rnti); + } + + int rem_tbs = tbs; + int x = 0; + do { + x = alloc_pdu(rem_tbs, &data->pdu[0][data->nof_pdu_elems[0]]); + rem_tbs -= x; + if (x) { + data->nof_pdu_elems[0]++; + } + } while(rem_tbs > 0 && x > 0); + Debug("SCHED: Alloc format1 new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes); } else { - h->new_retx(tti, &mcs, &tbs); + h->new_retx(0, tti, &mcs, &tbs); Debug("SCHED: Alloc format1 previous mcs=%d, tbs=%d\n", mcs, tbs); } - - // Allocate MAC ConRes CE - if (need_conres_ce) { - data->pdu[0].lcid = srslte::sch_subh::CON_RES_ID; - data->nof_pdu_elems++; - Info("SCHED: Added MAC Contention Resolution CE for rnti=0x%x\n", rnti); - } - - int rem_tbs = tbs; - int x = 0; - do { - x = alloc_pdu(rem_tbs, &data->pdu[data->nof_pdu_elems]); - rem_tbs -= x; - if (x) { - data->nof_pdu_elems++; - } - } while(rem_tbs > 0 && x > 0); - - data->rnti = rnti; + + data->rnti = rnti; if (tbs > 0) { dci->harq_process = h->get_id(); - dci->mcs_idx = mcs; - dci->rv_idx = sched::get_rvidx(h->nof_retx()); - dci->ndi = h->get_ndi(); - dci->tpc_pucch = next_tpc_pucch; + dci->mcs_idx = (uint32_t) mcs; + dci->rv_idx = sched::get_rvidx(h->nof_retx(0)); + dci->ndi = h->get_ndi(0); + dci->tpc_pucch = (uint8_t) next_tpc_pucch; next_tpc_pucch = 1; - data->tbs = tbs; - dci->tb_en[0] = true; + data->tbs[0] = (uint32_t) tbs; + data->tbs[1] = 0; + dci->tb_en[0] = true; dci->tb_en[1] = false; } return tbs; } +// Generates a Format2a grant +int sched_ue::generate_format2a(dl_harq_proc *h, + sched_interface::dl_sched_data_t *data, + uint32_t tti, + uint32_t cfi) +{ + bool tb_en[SRSLTE_MAX_TB] = {false}; + srslte_ra_dl_dci_t *dci = &data->dci; + bzero(dci, sizeof(srslte_ra_dl_dci_t)); -int sched_ue::generate_format0(ul_harq_proc *h, + uint32_t sf_idx = tti%10; + + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci->type0_alloc.rbg_bitmask = h->get_rbgmask(); + + uint32_t nof_prb = format1_count_prb(h->get_rbgmask(), cell.nof_prb); + uint32_t nof_ctrl_symbols = cfi + (cell.nof_prb < 10 ? 1 : 0); + srslte_ra_dl_grant_t grant; + srslte_ra_dl_dci_to_grant_prb_allocation(dci, &grant, cell.nof_prb); + uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols); + uint32_t req_bytes = get_pending_dl_new_data(tti); + + if (dl_ri == 0) { + if (h->is_empty(1)) { + /* One layer, tb1 buffer is empty, send tb0 only */ + tb_en[0] = true; + } else { + /* One layer, tb1 buffer is not empty, send tb1 only */ + tb_en[1] = true; + } + } else { + /* Two layers, retransmit what TBs that have not been Acknowledged */ + bool no_retx = true; + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + if (!h->is_empty(tb)) { + tb_en[tb] = true; + no_retx = false; + } + } + /* Two layers, no retransmissions... */ + if (no_retx) { + tb_en[0] = true; + tb_en[1] = true; + } + } + + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + int mcs = 0; + int tbs = 0; + + if (tb_en[tb]) { + if (h->is_empty(tb)) { + if (fixed_mcs_dl < 0) { + tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs); + } else { + tbs = srslte_ra_tbs_from_idx((uint32_t) srslte_ra_tbs_idx_from_mcs((uint32_t) fixed_mcs_dl), nof_prb) / 8; + mcs = fixed_mcs_dl; + } + + h->new_tx(tb, tti, mcs, tbs, data->dci_location.ncce); + + int rem_tbs = tbs; + int x = 0; + do { + x = alloc_pdu(rem_tbs, &data->pdu[tb][data->nof_pdu_elems[tb]]); + rem_tbs -= x; + if (x) { + data->nof_pdu_elems[tb]++; + } + } while (rem_tbs > 0 && x > 0); + + Debug("SCHED: Alloc format2/2a new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes); + } else { + h->new_retx(tb, tti, &mcs, &tbs); + Debug("SCHED: Alloc format2/2a previous mcs=%d, tbs=%d\n", mcs, tbs); + } + } + + /* Fill DCI TB dedicated fields */ + if (tbs > 0) { + if (tb == 0) { + dci->mcs_idx = (uint32_t) mcs; + dci->rv_idx = sched::get_rvidx(h->nof_retx(tb)); + dci->ndi = h->get_ndi(tb); + } else { + dci->mcs_idx_1 = (uint32_t) mcs; + dci->rv_idx_1 = sched::get_rvidx(h->nof_retx(tb)); + dci->ndi_1 = h->get_ndi(tb); + } + data->tbs[tb] = (uint32_t) tbs; + dci->tb_en[tb] = true; + } else { + data->tbs[tb] = 0; + dci->tb_en[tb] = false; + } + + if ( req_bytes > (uint32_t) tbs) { + req_bytes -= tbs; + } else { + req_bytes = 0; + } + } + + /* Fill common fields */ + data->rnti = rnti; + dci->harq_process = h->get_id(); + dci->tpc_pucch = (uint8_t) next_tpc_pucch; + next_tpc_pucch = 1; + + return data->tbs[0] + data->tbs[1]; +} + +// Generates a Format2 grant +int sched_ue::generate_format2(dl_harq_proc *h, + sched_interface::dl_sched_data_t *data, + uint32_t tti, + uint32_t cfi) +{ + /* Call Format 2a (common) */ + int ret = generate_format2a(h, data, tti, cfi); + + /* Compute precoding information */ + if (SRSLTE_RA_DL_GRANT_NOF_TB(&data->dci) == 1) { + data->dci.pinfo = (uint8_t) (dl_pmi + 1) % (uint8_t) 5; + } else { + data->dci.pinfo = (uint8_t) (dl_pmi & 1); + } + + return ret; +} + + +int sched_ue::generate_format0(ul_harq_proc *h, sched_interface::ul_sched_data_t *data, uint32_t tti, bool cqi_request) @@ -453,7 +599,7 @@ int sched_ue::generate_format0(ul_harq_proc *h, if (h->get_rar_mcs(&mcs)) { tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8; h->new_tx(tti, mcs, tbs); - } else if (h->is_empty()) { + } else if (h->is_empty(0)) { uint32_t req_bytes = get_pending_ul_new_data(tti); @@ -469,7 +615,7 @@ int sched_ue::generate_format0(ul_harq_proc *h, h->new_tx(tti, mcs, tbs); } else { - h->new_retx(tti, &mcs, NULL); + h->new_retx(0, tti, &mcs, NULL); tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8; } @@ -480,8 +626,8 @@ int sched_ue::generate_format0(ul_harq_proc *h, dci->type2_alloc.L_crb = allocation.L; dci->type2_alloc.RB_start = allocation.RB_start; dci->mcs_idx = mcs; - dci->rv_idx = sched::get_rvidx(h->nof_retx()); - dci->ndi = h->get_ndi(); + dci->rv_idx = sched::get_rvidx(h->nof_retx(0)); + dci->ndi = h->get_ndi(0); dci->cqi_request = cqi_request; dci->freq_hop_fl = srslte_ra_ul_dci_t::SRSLTE_RA_PUSCH_HOP_DISABLED; dci->tpc_pusch = next_tpc_pusch; @@ -512,7 +658,7 @@ uint32_t sched_ue::get_max_retx() { bool sched_ue::is_first_dl_tx() { for (int i=0;i 0) { + if (dl_harq[i].nof_tx(0) > 0) { return false; } } @@ -657,10 +803,11 @@ bool sched_ue::is_sr_triggered() /* Gets HARQ process with oldest pending retx */ dl_harq_proc* sched_ue::get_pending_dl_harq(uint32_t tti) { +#if ASYNC_DL_SCHED int oldest_idx=-1; uint32_t oldest_tti = 0; for (int i=0;i oldest_tti) { oldest_idx = i; @@ -672,17 +819,20 @@ dl_harq_proc* sched_ue::get_pending_dl_harq(uint32_t tti) return &dl_harq[oldest_idx]; } else { return NULL; - } + } +#else + return &dl_harq[tti%SCHED_MAX_HARQ_PROC]; +#endif } dl_harq_proc* sched_ue::get_empty_dl_harq() { for (int i=0;ierror_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) namespace srsenb { @@ -107,9 +107,9 @@ srslte_softbuffer_rx_t* ue::get_rx_softbuffer(uint32_t tti) return &softbuffer_rx[tti%NOF_HARQ_PROCESSES]; } -srslte_softbuffer_tx_t* ue::get_tx_softbuffer(uint32_t harq_process) +srslte_softbuffer_tx_t* ue::get_tx_softbuffer(uint32_t harq_process, uint32_t tb_idx) { - return &softbuffer_tx[harq_process%NOF_HARQ_PROCESSES]; + return &softbuffer_tx[(harq_process * SRSLTE_MAX_TB + tb_idx )%NOF_HARQ_PROCESSES]; } uint8_t* ue::request_buffer(uint32_t tti, uint32_t len) @@ -407,6 +407,16 @@ void ue::metrics_phr(float phr) { phr_counter++; } +void ue::metrics_dl_ri(uint32_t dl_ri) { + metrics.dl_ri = SRSLTE_VEC_EMA((float) dl_ri, metrics.dl_ri, 0.5f); + dl_ri_counter++; +} + +void ue::metrics_dl_pmi(uint32_t dl_ri) { + metrics.dl_pmi = SRSLTE_VEC_CMA((float) dl_ri, metrics.dl_pmi, dl_pmi_counter); + dl_pmi_counter++; +} + void ue::metrics_dl_cqi(uint32_t dl_cqi) { metrics.dl_cqi = SRSLTE_VEC_CMA((float) dl_cqi, metrics.dl_cqi, dl_cqi_counter); dl_cqi_counter++; diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 528878388..c2b08307b 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -75,9 +75,11 @@ void parse_args(all_args_t *args, int argc, char* argv[]) { ("enb.mnc", bpo::value(&mnc)->default_value("01"), "Mobile Network Code") ("enb.mme_addr", bpo::value(&args->enb.s1ap.mme_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connnection") ("enb.gtp_bind_addr", bpo::value(&args->enb.s1ap.gtp_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for GTP connection") - ("enb.phy_cell_id", bpo::value(&args->enb.pci)->default_value(0), "Physical Cell Identity (PCI)") + ("enb.phy_cell_id", bpo::value(&args->enb.pci)->default_value(0), "Physical Cell Identity (PCI)") ("enb.n_prb", bpo::value(&args->enb.n_prb)->default_value(25), "Number of PRB") - + ("enb.nof_ports", bpo::value(&args->enb.nof_ports)->default_value(1), "Number of ports") + ("enb.tm", bpo::value(&args->enb.transmission_mode)->default_value(1), "Transmission mode (1-8)") + ("enb_files.sib_config", bpo::value(&args->enb_files.sib_config)->default_value("sib.conf"), "SIB configuration files") ("enb_files.rr_config", bpo::value(&args->enb_files.rr_config)->default_value("rr.conf"), "RR configuration files") ("enb_files.drb_config", bpo::value(&args->enb_files.drb_config)->default_value("drb.conf"), "DRB configuration files") @@ -316,12 +318,18 @@ void parse_args(all_args_t *args, int argc, char* argv[]) { } } +static int sigcnt = 0; static bool running = true; static bool do_metrics = false; void sig_int_handler(int signo) { + sigcnt++; running = false; + printf("Stopping srsENB... Press Ctrl+C %d more times to force stop\n", 10-sigcnt); + if (sigcnt >= 10) { + exit(-1); + } } void *input_loop(void *m) @@ -350,6 +358,8 @@ int main(int argc, char *argv[]) metrics_stdout metrics; enb *enb = enb::get_instance(); + srslte_debug_handle_crash(argc, argv); + cout << "--- Software Radio Systems LTE eNodeB ---" << endl << endl; parse_args(&args, argc, argv); diff --git a/srsenb/src/metrics_stdout.cc b/srsenb/src/metrics_stdout.cc index ec55b0dcf..efea243f1 100644 --- a/srsenb/src/metrics_stdout.cc +++ b/srsenb/src/metrics_stdout.cc @@ -108,8 +108,8 @@ void metrics_stdout::print_metrics() { n_reports = 0; cout << endl; - cout << "------DL-------------------------UL-------------------------------" << endl; - cout << "rnti cqi mcs brate bler snr phr mcs brate bler bsr" << endl; + cout << "------DL-------------------------------UL--------------------------------" << endl; + cout << "rnti cqi ri mcs brate bler snr phr mcs brate bler bsr" << endl; } if (metrics.rrc.n_ues > 0) { @@ -123,6 +123,7 @@ void metrics_stdout::print_metrics() cout << std::hex << metrics.mac[i].rnti << " "; cout << float_to_string(metrics.mac[i].dl_cqi, 2); + cout << float_to_string(metrics.mac[i].dl_ri + 1, 3); cout << float_to_string(metrics.phy[i].dl.mcs, 2); if (metrics.mac[i].tx_brate > 0 && metrics_report_period) { cout << float_to_eng_string((float) metrics.mac[i].tx_brate/metrics_report_period, 2); diff --git a/srsenb/src/phy/phch_common.cc b/srsenb/src/phy/phch_common.cc index e4d91581e..c732f76dc 100644 --- a/srsenb/src/phy/phch_common.cc +++ b/srsenb/src/phy/phch_common.cc @@ -30,12 +30,11 @@ #include "phy/txrx.h" #include -#include -#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) using namespace std; @@ -48,8 +47,8 @@ void phch_common::set_nof_mutex(uint32_t nof_mutex_) { } void phch_common::reset() { - bzero(ul_grants, sizeof(mac_interface_phy::ul_sched_t)*10); - bzero(dl_grants, sizeof(mac_interface_phy::dl_sched_t)*10); + bzero(ul_grants, sizeof(mac_interface_phy::ul_sched_t)*TTIMOD_SZ); + bzero(dl_grants, sizeof(mac_interface_phy::dl_sched_t)*TTIMOD_SZ); } bool phch_common::init(srslte_cell_t *cell_, srslte::radio* radio_h_, mac_interface_phy *mac_) @@ -74,7 +73,7 @@ void phch_common::stop() { } } -void phch_common::worker_end(uint32_t tx_mutex_cnt, cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) +void phch_common::worker_end(uint32_t tx_mutex_cnt, cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time) { // Wait previous TTIs to be transmitted @@ -84,8 +83,8 @@ void phch_common::worker_end(uint32_t tx_mutex_cnt, cf_t* buffer, uint32_t nof_s pthread_mutex_lock(&tx_mutex[tx_mutex_cnt%nof_mutex]); } - radio->set_tti(tx_mutex_cnt); - radio->tx(buffer, nof_samples, tx_time); + radio->set_tti(tx_mutex_cnt); + radio->tx((void **) buffer, nof_samples, tx_time); // Trigger next transmission pthread_mutex_unlock(&tx_mutex[(tx_mutex_cnt+1)%nof_mutex]); @@ -98,14 +97,18 @@ void phch_common::ack_clear(uint32_t sf_idx) { for(std::map::iterator iter=pending_ack.begin(); iter!=pending_ack.end(); ++iter) { pending_ack_t *p = (pending_ack_t*) &iter->second; - p->is_pending[sf_idx] = false; + for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) { + p->is_pending[sf_idx][tb_idx] = false; + } } } void phch_common::ack_add_rnti(uint16_t rnti) { - for (int sf_idx=0;sf_idx<10;sf_idx++) { - pending_ack[rnti].is_pending[sf_idx] = false; + for (int sf_idx=0;sf_idxerror_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) using namespace std; @@ -88,17 +88,21 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_) pthread_mutex_init(&mutex, NULL); // Init cell here - signal_buffer_rx = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t)); - if (!signal_buffer_rx) { - fprintf(stderr, "Error allocating memory\n"); - return; + for(int p = 0; p < SRSLTE_MAX_PORTS; p++) { + signal_buffer_rx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); + if (!signal_buffer_rx[p]) { + fprintf(stderr, "Error allocating memory\n"); + return; + } + bzero(signal_buffer_rx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); + signal_buffer_tx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); + if (!signal_buffer_tx[p]) { + fprintf(stderr, "Error allocating memory\n"); + return; + } + bzero(signal_buffer_tx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); } - signal_buffer_tx = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t)); - if (!signal_buffer_tx) { - fprintf(stderr, "Error allocating memory\n"); - return; - } - if (srslte_enb_dl_init(&enb_dl, phy->cell.nof_prb)) { + if (srslte_enb_dl_init(&enb_dl, signal_buffer_tx, phy->cell.nof_prb)) { fprintf(stderr, "Error initiating ENB DL\n"); return; } @@ -106,7 +110,7 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_) fprintf(stderr, "Error initiating ENB DL\n"); return; } - if (srslte_enb_ul_init(&enb_ul, phy->cell.nof_prb)) { + if (srslte_enb_ul_init(&enb_ul, signal_buffer_rx[0], phy->cell.nof_prb)) { fprintf(stderr, "Error initiating ENB UL\n"); return; } @@ -153,11 +157,13 @@ void phch_worker::stop() srslte_enb_dl_free(&enb_dl); srslte_enb_ul_free(&enb_ul); - if (signal_buffer_rx) { - free(signal_buffer_rx); - } - if (signal_buffer_tx) { - free(signal_buffer_tx); + for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { + if (signal_buffer_rx[p]) { + free(signal_buffer_rx[p]); + } + if (signal_buffer_tx[p]) { + free(signal_buffer_tx[p]); + } } pthread_mutex_unlock(&mutex); pthread_mutex_destroy(&mutex); @@ -168,19 +174,24 @@ void phch_worker::reset() ue_db.clear(); } -cf_t* phch_worker::get_buffer_rx() +cf_t* phch_worker::get_buffer_rx(uint32_t antenna_idx) { - return signal_buffer_rx; + return signal_buffer_rx[antenna_idx]; } void phch_worker::set_time(uint32_t tti_, uint32_t tx_mutex_cnt_, srslte_timestamp_t tx_time_) { tti_rx = tti_; - tti_tx = (tti_ + 4)%10240; - tti_sched_ul = (tti_ + 8)%10240; + tti_tx_dl = TTI_TX(tti_rx); + tti_tx_ul = TTI_RX_ACK(tti_rx); + sf_rx = tti_rx%10; - sf_tx = tti_tx%10; - sf_sched_ul = tti_sched_ul%10; + sf_tx = tti_tx_dl%10; + + t_tx_dl = TTIMOD(tti_tx_dl); + t_rx = TTIMOD(tti_rx); + t_tx_ul = TTIMOD(tti_tx_ul); + tx_mutex_cnt = tx_mutex_cnt_; memcpy(&tx_time, &tx_time_, sizeof(srslte_timestamp_t)); } @@ -189,16 +200,16 @@ int phch_worker::add_rnti(uint16_t rnti) { if (srslte_enb_dl_add_rnti(&enb_dl, rnti)) { - return -1; + return -1; } if (srslte_enb_ul_add_rnti(&enb_ul, rnti)) { - return -1; + return -1; } - // Create user - ue_db[rnti].rnti = rnti; - - return SRSLTE_SUCCESS; + // Create user + ue_db[rnti].rnti = rnti; + + return SRSLTE_SUCCESS; } @@ -206,67 +217,92 @@ uint32_t phch_worker::get_nof_rnti() { return ue_db.size(); } -void phch_worker::set_config_dedicated(uint16_t rnti, - srslte_uci_cfg_t *uci_cfg, +void phch_worker::set_conf_dedicated_ack(uint16_t rnti, bool ack){ + pthread_mutex_lock(&mutex); + if (ue_db.count(rnti)) { + ue_db[rnti].dedicated_ack = ack; + } else { + Error("Setting dedicated ack: rnti=0x%x does not exist\n"); + } + pthread_mutex_unlock(&mutex); +} + +void phch_worker::set_config_dedicated(uint16_t rnti, + srslte_uci_cfg_t *uci_cfg, srslte_pucch_sched_t *pucch_sched, srslte_refsignal_srs_cfg_t *srs_cfg, - uint32_t I_sr, bool pucch_cqi, uint32_t pmi_idx, bool pucch_cqi_ack) + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) { - pthread_mutex_lock(&mutex); + uint32_t I_sr = dedicated->sched_request_cnfg.sr_cnfg_idx; + bool pucch_cqi = dedicated->cqi_report_cnfg.report_periodic_setup_present; + uint32_t pmi_idx = dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx; + bool pucch_cqi_ack = dedicated->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi; + bool pucch_ri = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present; + uint32_t ri_idx = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx; + + pthread_mutex_lock(&mutex); if (ue_db.count(rnti)) { pucch_sched->N_pucch_1 = phy->pucch_cfg.n1_pucch_an; srslte_enb_ul_cfg_ue(&enb_ul, rnti, uci_cfg, pucch_sched, srs_cfg); - - ue_db[rnti].I_sr = I_sr; + + ue_db[rnti].I_sr = I_sr; ue_db[rnti].I_sr_en = true; if (pucch_cqi) { - ue_db[rnti].pmi_idx = pmi_idx; - ue_db[rnti].cqi_en = true; - ue_db[rnti].pucch_cqi_ack = pucch_cqi_ack; + ue_db[rnti].pmi_idx = pmi_idx; + ue_db[rnti].cqi_en = true; + ue_db[rnti].pucch_cqi_ack = pucch_cqi_ack; } else { - ue_db[rnti].pmi_idx = 0; - ue_db[rnti].cqi_en = false; + ue_db[rnti].pmi_idx = 0; + ue_db[rnti].cqi_en = false; } - + + if (pucch_ri) { + ue_db[rnti].ri_idx = ri_idx; + ue_db[rnti].ri_en = true; + } else { + ue_db[rnti].ri_idx = 0; + ue_db[rnti].ri_en = false; + } + + /* Copy all dedicated RRC configuration to UE */ + memcpy(&ue_db[rnti].dedicated, dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT)); } else { Error("Setting config dedicated: rnti=0x%x does not exist\n"); } - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&mutex); } void phch_worker::rem_rnti(uint16_t rnti) { - pthread_mutex_lock(&mutex); + pthread_mutex_lock(&mutex); if (ue_db.count(rnti)) { ue_db.erase(rnti); - - srslte_enb_dl_rem_rnti(&enb_dl, rnti); + + srslte_enb_dl_rem_rnti(&enb_dl, rnti); srslte_enb_ul_rem_rnti(&enb_ul, rnti); - - // remove any pending grant for each subframe - for (uint32_t i=0;i<10;i++) { + + // remove any pending grant for each subframe + for (uint32_t i=0;iul_grants[i].nof_grants;j++) { if (phy->ul_grants[i].sched_grants[j].rnti == rnti) { - phy->ul_grants[i].sched_grants[j].rnti = 0; + phy->ul_grants[i].sched_grants[j].rnti = 0; } } for (uint32_t j=0;jdl_grants[i].nof_grants;j++) { if (phy->dl_grants[i].sched_grants[j].rnti == rnti) { - phy->dl_grants[i].sched_grants[j].rnti = 0; + phy->dl_grants[i].sched_grants[j].rnti = 0; } } } } else { Error("Removing user: rnti=0x%x does not exist\n", rnti); } - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&mutex); } void phch_worker::work_imp() { - uint32_t sf_ack; - if (!running) { return; } @@ -274,69 +310,75 @@ void phch_worker::work_imp() pthread_mutex_lock(&mutex); mac_interface_phy::ul_sched_t *ul_grants = phy->ul_grants; - mac_interface_phy::dl_sched_t *dl_grants = phy->dl_grants; - mac_interface_phy *mac = phy->mac; - + mac_interface_phy::dl_sched_t *dl_grants = phy->dl_grants; + mac_interface_phy *mac = phy->mac; + log_h->step(tti_rx); - + Debug("Worker %d running\n", get_id()); - + for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { uint16_t rnti = (uint16_t) iter->first; - ue_db[rnti].has_grant_tti = -1; + ue_db[rnti].has_grant_tti = -1; } // Process UL signal - srslte_enb_ul_fft(&enb_ul, signal_buffer_rx); + srslte_enb_ul_fft(&enb_ul); // Decode pending UL grants for the tti they were scheduled - decode_pusch(ul_grants[sf_rx].sched_grants, ul_grants[sf_rx].nof_grants, sf_rx); - + decode_pusch(ul_grants[t_rx].sched_grants, ul_grants[t_rx].nof_grants); + // Decode remaining PUCCH ACKs not associated with PUSCH transmission and SR signals - decode_pucch(tti_rx); - + decode_pucch(); + // Get DL scheduling for the TX TTI from MAC - if (mac->get_dl_sched(tti_tx, &dl_grants[sf_tx]) < 0) { + if (mac->get_dl_sched(tti_tx_dl, &dl_grants[t_tx_dl]) < 0) { Error("Getting DL scheduling from MAC\n"); goto unlock; - } - - if (dl_grants[sf_tx].cfi < 1 || dl_grants[sf_tx].cfi > 3) { - Error("Invalid CFI=%d\n", dl_grants[sf_tx].cfi); + } + + if (dl_grants[t_tx_dl].cfi < 1 || dl_grants[t_tx_dl].cfi > 3) { + Error("Invalid CFI=%d\n", dl_grants[t_tx_dl].cfi); goto unlock; } - + // Get UL scheduling for the TX TTI from MAC - if (mac->get_ul_sched(tti_sched_ul, &ul_grants[sf_sched_ul]) < 0) { + if (mac->get_ul_sched(tti_tx_ul, &ul_grants[t_tx_ul]) < 0) { Error("Getting UL scheduling from MAC\n"); goto unlock; - } - + } + // Put base signals (references, PBCH, PCFICH and PSS/SSS) into the resource grid srslte_enb_dl_clear_sf(&enb_dl); - srslte_enb_dl_set_cfi(&enb_dl, dl_grants[sf_tx].cfi); - srslte_enb_dl_put_base(&enb_dl, tti_tx); + srslte_enb_dl_set_cfi(&enb_dl, dl_grants[t_tx_dl].cfi); + srslte_enb_dl_put_base(&enb_dl, tti_tx_dl); + + // Put UL/DL grants to resource grid. PDSCH data will be encoded as well. + encode_pdcch_dl(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants); + encode_pdcch_ul(ul_grants[t_tx_ul].sched_grants, ul_grants[t_tx_ul].nof_grants); + encode_pdsch(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants); - // Put UL/DL grants to resource grid. PDSCH data will be encoded as well. - encode_pdcch_dl(dl_grants[sf_tx].sched_grants, dl_grants[sf_tx].nof_grants, sf_tx); - encode_pdcch_ul(ul_grants[sf_sched_ul].sched_grants, ul_grants[sf_sched_ul].nof_grants, sf_tx); - encode_pdsch(dl_grants[sf_tx].sched_grants, dl_grants[sf_tx].nof_grants, sf_tx); - // Put pending PHICH HARQ ACK/NACK indications into subframe - encode_phich(ul_grants[sf_sched_ul].phich, ul_grants[sf_sched_ul].nof_phich, sf_tx); - - // Prepare for receive ACK for DL grants in sf_tx+4 - sf_ack = (sf_tx+4)%10; - phy->ack_clear(sf_ack); - for (uint32_t i=0;iack_clear(TTIMOD(TTI_TX(t_tx_dl))); + for (uint32_t i=0;i= SRSLTE_CRNTI_START && dl_grants[sf_tx].sched_grants[i].rnti <= SRSLTE_CRNTI_END) { - phy->ack_set_pending(sf_ack, dl_grants[sf_tx].sched_grants[i].rnti, dl_grants[sf_tx].sched_grants[i].location.ncce); + uint16_t rnti = dl_grants[t_tx_dl].sched_grants[i].rnti; + if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) { + /* For each TB */ + for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) { + /* If TB enabled, set pending ACK */ + if (dl_grants[t_tx_dl].sched_grants[i].grant.tb_en[tb_idx]) { + phy->ack_set_pending(TTIMOD(TTI_TX(t_tx_dl)), rnti, tb_idx, dl_grants[t_tx_dl].sched_grants[i].location.ncce); + } + } } } - + // Generate signal and transmit - srslte_enb_dl_gen_signal(&enb_dl, signal_buffer_tx); + srslte_enb_dl_gen_signal(&enb_dl); Debug("Sending to radio\n"); phy->worker_end(tx_mutex_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time); @@ -345,35 +387,35 @@ void phch_worker::work_imp() #endif #ifdef DEBUG_WRITE_FILE - if (tti_tx == 10) { + if (tti_tx_dl == 10) { fclose(f); exit(-1); } -#endif - +#endif + /* Tell the plotting thread to draw the plots */ #ifdef ENABLE_GUI if ((int) get_id() == plot_worker_id) { - sem_post(&plot_sem); + sem_post(&plot_sem); } #endif unlock: - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&mutex); } -int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch, uint32_t tti) +int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) { - srslte_uci_data_t uci_data; + srslte_uci_data_t uci_data; bzero(&uci_data, sizeof(srslte_uci_data_t)); - - uint32_t wideband_cqi_value = 0; - - uint32_t n_rb_ho = 0; + + uint32_t wideband_cqi_value = 0; + + uint32_t n_rb_ho = 0; for (uint32_t i=0;iack_is_pending(sf_rx, rnti)) { - uci_data.uci_ack_len = 1; + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + acks_pending[tb] = phy->ack_is_pending(t_rx, rnti, tb); + if (acks_pending[tb]) { + uci_data.uci_ack_len++; + } } - // Configure PUSCH CQI channel - srslte_cqi_value_t cqi_value; - bool cqi_enabled = false; - if (ue_db[rnti].cqi_en && srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { + + // Configure PUSCH CQI channel + srslte_cqi_value_t cqi_value = {0}; + bool cqi_enabled = false; +#if 0 + if (ue_db[rnti].cqi_en && ue_db[rnti].ri_en && srslte_ri_send(ue_db[rnti].pmi_idx, ue_db[rnti].ri_idx, tti_rx) ) { + uci_data.uci_ri_len = 1; /* Asumes only 1 bit for RI */ + ri_enabled = true; + } else if (ue_db[rnti].cqi_en && srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; - cqi_enabled = true; - } else if (grants[i].grant.cqi_request) { + cqi_enabled = true; + if (ue_db[rnti].dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { + //uci_data.uci_dif_cqi_len = 3; + uci_data.uci_pmi_len = 2; + } + } else +#endif + if (grants[i].grant.cqi_request) { cqi_value.type = SRSLTE_CQI_TYPE_SUBBAND_HL; cqi_value.subband_hl.N = (phy->cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(phy->cell.nof_prb) : 0; - cqi_enabled = true; + cqi_value.subband_hl.four_antenna_ports = (phy->cell.nof_ports == 4); + cqi_value.subband_hl.pmi_present = (ue_db[rnti].dedicated.cqi_report_cnfg.report_mode_aperiodic == LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31); + cqi_enabled = true; } - if (cqi_enabled) { - uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value); - } - - // mark this tti as having an ul grant to avoid pucch - ue_db[rnti].has_grant_tti = tti_rx; - - srslte_ra_ul_grant_t phy_grant; + + // mark this tti as having an ul grant to avoid pucch + ue_db[rnti].has_grant_tti = tti_rx; + + srslte_ra_ul_grant_t phy_grant; int res = -1; - if (!srslte_ra_ul_dci_to_grant(&grants[i].grant, enb_ul.cell.nof_prb, n_rb_ho, &phy_grant, tti%8)) { + if (!srslte_ra_ul_dci_to_grant(&grants[i].grant, enb_ul.cell.nof_prb, n_rb_ho, &phy_grant)) { + + // Handle Format0 adaptive retx + // Use last TBS for this TB in case of mcs>28 + if (phy_grant.mcs.idx > 28) { + phy_grant.mcs.tbs = ue_db[rnti].last_ul_tbs[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)]; + Info("RETX: mcs=%d, old_tbs=%d pid=%d\n", phy_grant.mcs.idx, phy_grant.mcs.tbs, TTI_TX(tti_rx)%(2*HARQ_DELAY_MS)); + } + ue_db[rnti].last_ul_tbs[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)] = phy_grant.mcs.tbs; + + if (phy_grant.mcs.mod == SRSLTE_MOD_LAST) { + phy_grant.mcs.mod = ue_db[rnti].last_ul_mod[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)]; + phy_grant.Qm = srslte_mod_bits_x_symbol(phy_grant.mcs.mod); + } + ue_db[rnti].last_ul_mod[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)] = phy_grant.mcs.mod; + + if (phy_grant.mcs.mod == SRSLTE_MOD_64QAM) { phy_grant.mcs.mod = SRSLTE_MOD_16QAM; } phy_grant.Qm = SRSLTE_MIN(phy_grant.Qm, 4); res = srslte_enb_ul_get_pusch(&enb_ul, &phy_grant, grants[i].softbuffer, - rnti, grants[i].rv_idx, - grants[i].current_tx_nb, - grants[i].data, - &uci_data, - tti); + rnti, grants[i].rv_idx, + grants[i].current_tx_nb, + grants[i].data, + (cqi_enabled) ? &cqi_value : NULL, + &uci_data, + sf_rx); } else { Error("Computing PUSCH grant\n"); - return SRSLTE_ERROR; + return SRSLTE_ERROR; } - + #ifdef LOG_EXECTIME gettimeofday(&t[2], NULL); get_time_interval(t); snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec); #endif - - bool crc_res = (res == 0); - + + bool crc_res = (res == 0); + // Save PHICH scheduling for this user. Each user can have just 1 PUSCH grant per TTI - ue_db[rnti].phich_info.n_prb_lowest = enb_ul.pusch_cfg.grant.n_prb_tilde[0]; - ue_db[rnti].phich_info.n_dmrs = phy_grant.ncs_dmrs; + ue_db[rnti].phich_info.n_prb_lowest = enb_ul.pusch_cfg.grant.n_prb_tilde[0]; + ue_db[rnti].phich_info.n_dmrs = phy_grant.ncs_dmrs; char cqi_str[64]; if (cqi_enabled) { - srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); if (ue_db[rnti].cqi_en) { wideband_cqi_value = cqi_value.wideband.wideband_cqi; } else if (grants[i].grant.cqi_request) { - wideband_cqi_value = cqi_value.subband_hl.wideband_cqi; + wideband_cqi_value = cqi_value.subband_hl.wideband_cqi_cw0; + if (cqi_value.subband_hl.pmi_present) { + if (cqi_value.subband_hl.rank_is_not_one) { + Info("PUSCH: Aperiodic ri~1, CQI=%02d/%02d, pmi=%d for %d subbands\n", + cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.wideband_cqi_cw1, + cqi_value.subband_hl.pmi, cqi_value.subband_hl.N); + } else { + Info("PUSCH: Aperiodic ri=1, CQI=%02d, pmi=%d for %d subbands\n", + cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.pmi, cqi_value.subband_hl.N); + } + } else { + Info("PUSCH: Aperiodic ri%s, CQI=%02d for %d subbands\n", + cqi_value.subband_hl.rank_is_not_one?"~1":"=1", + cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.N); + } } snprintf(cqi_str, 64, ", cqi=%d", wideband_cqi_value); } - - float snr_db = 10*log10(srslte_chest_ul_get_snr(&enb_ul.chest)); + + float snr_db = 10*log10(srslte_chest_ul_get_snr(&enb_ul.chest)); /* if (!crc_res && enb_ul.pusch_cfg.grant.L_prb == 1 && enb_ul.pusch_cfg.grant.n_prb[0] == 0 && snr_db > 5) { @@ -454,256 +541,346 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch, srslte_vec_save_file("d", enb_ul.pusch.d, sizeof(cf_t)*enb_ul.pusch_cfg.nbits.nof_re); srslte_vec_save_file("ce2", enb_ul.pusch.ce, sizeof(cf_t)*enb_ul.pusch_cfg.nbits.nof_re); srslte_vec_save_file("z", enb_ul.pusch.z, sizeof(cf_t)*enb_ul.pusch_cfg.nbits.nof_re); - printf("saved sf_idx=%d, mcs=%d, tbs=%d, rnti=%d, rv=%d, snr=%.1f\n", tti%10, - grants[i].grant.mcs_idx, enb_ul.pusch_cfg.cb_segm.tbs, rnti, grants[i].rv_idx, snr_db); + printf("saved sf_idx=%d, mcs=%d, tbs=%d, rnti=%d, rv=%d, snr=%.1f\n", tti%10, + grants[i].grant.mcs_idx, enb_ul.pusch_cfg.cb_segm.tbs, rnti, grants[i].rv_idx, snr_db); exit(-1); } */ log_h->info_hex(grants[i].data, phy_grant.mcs.tbs/8, - "PUSCH: rnti=0x%x, prb=(%d,%d), tbs=%d, mcs=%d, rv=%d, snr=%.1f dB, n_iter=%d, crc=%s%s%s%s\n", + "PUSCH: rnti=0x%x, prb=(%d,%d), tbs=%d, mcs=%d, rv=%d, snr=%.1f dB, n_iter=%d, crc=%s%s%s%s%s\n", rnti, phy_grant.n_prb[0], phy_grant.n_prb[0]+phy_grant.L_prb, phy_grant.mcs.tbs/8, phy_grant.mcs.idx, grants[i].grant.rv_idx, - snr_db, + snr_db, srslte_pusch_last_noi(&enb_ul.pusch), crc_res?"OK":"KO", - uci_data.uci_ack_len>0?(uci_data.uci_ack?", ack=1":", ack=0"):"", - uci_data.uci_cqi_len>0?cqi_str:"", - timestr); - - // Notify MAC of RL status + (uci_data.uci_ack_len)?(uci_data.uci_ack?"1":"0"):"", + (uci_data.uci_ack_len > 1)?(uci_data.uci_ack_2?"1":"0"):"", + uci_data.uci_cqi_len>0?cqi_str:"", + uci_data.uci_ri_len>0?(uci_data.uci_ri?", ri=0":", ri=1"):"", + timestr); + + // Notify MAC of RL status if (grants[i].grant.rv_idx == 0) { if (res && snr_db < PUSCH_RL_SNR_DB_TH) { Debug("PUSCH: Radio-Link failure snr=%.1f dB\n", snr_db); phy->mac->rl_failure(rnti); } else { phy->mac->rl_ok(rnti); - } + } } - + // Notify MAC new received data and HARQ Indication value - phy->mac->crc_info(tti_rx, rnti, phy_grant.mcs.tbs/8, crc_res); - if (uci_data.uci_ack_len) { - phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (crc_res || snr_db > PUSCH_RL_SNR_DB_TH)); + phy->mac->crc_info(tti_rx, rnti, phy_grant.mcs.tbs/8, crc_res); + uint32_t ack_idx = 0; + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + if (acks_pending[tb]) { + bool ack = ((ack_idx++ == 0) ? uci_data.uci_ack : uci_data.uci_ack_2); + bool valid = (crc_res || snr_db > PUSCH_RL_SNR_DB_TH); + phy->mac->ack_info(tti_rx, rnti, tb, ack && valid); + } } - - // Notify MAC of UL SNR and DL CQI + + // Notify MAC of UL SNR, DL CQI and DL RI if (snr_db >= PUSCH_RL_SNR_DB_TH) { phy->mac->snr_info(tti_rx, rnti, snr_db); } if (uci_data.uci_cqi_len>0 && crc_res) { phy->mac->cqi_info(tti_rx, rnti, wideband_cqi_value); } - - // Save metrics stats + if (uci_data.uci_ri_len > 0 && crc_res) { + phy->mac->ri_info(tti_rx, rnti, uci_data.uci_ri); + } + if (cqi_value.subband_hl.pmi_present && crc_res) { + phy->mac->pmi_info(tti_rx, rnti, cqi_value.subband_hl.pmi); + } + + // Save metrics stats ue_db[rnti].metrics_ul(phy_grant.mcs.idx, 0, snr_db, srslte_pusch_last_noi(&enb_ul.pusch)); - } - } - return SRSLTE_SUCCESS; -} - - -int phch_worker::decode_pucch(uint32_t tti_rx) -{ - uint32_t sf_rx = tti_rx%10; - srslte_uci_data_t uci_data; - - for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { - uint16_t rnti = (uint16_t) iter->first; - - if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END && ue_db[rnti].has_grant_tti != (int) tti_rx) { - // Check if user needs to receive PUCCH - bool needs_pucch = false, needs_ack=false, needs_sr=false, needs_cqi=false; - uint32_t last_n_pdcch = 0; - bzero(&uci_data, sizeof(srslte_uci_data_t)); - - if (ue_db[rnti].I_sr_en) { - if (srslte_ue_ul_sr_send_tti(ue_db[rnti].I_sr, tti_rx)) { - needs_pucch = true; - needs_sr = true; - uci_data.scheduling_request = true; - } - } - if (phy->ack_is_pending(sf_rx, rnti, &last_n_pdcch)) { - needs_pucch = true; - needs_ack = true; - uci_data.uci_ack_len = 1; - } - srslte_cqi_value_t cqi_value; - if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack)) { - if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { - needs_pucch = true; - needs_cqi = true; - cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; - uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value); - } - } - - if (needs_pucch) { - if (srslte_enb_ul_get_pucch(&enb_ul, rnti, last_n_pdcch, sf_rx, &uci_data)) { - fprintf(stderr, "Error getting PUCCH\n"); - return SRSLTE_ERROR; - } - if (uci_data.uci_ack_len > 0) { - phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (srslte_pucch_get_last_corr(&enb_ul.pucch) >= PUCCH_RL_CORR_TH)); - } - if (uci_data.scheduling_request) { - phy->mac->sr_detected(tti_rx, rnti); - } - - char cqi_str[64]; - if (uci_data.uci_cqi_len) { - srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); - phy->mac->cqi_info(tti_rx, rnti, cqi_value.wideband.wideband_cqi); - sprintf(cqi_str, ", cqi=%d", cqi_value.wideband.wideband_cqi); - } - log_h->info("PUCCH: rnti=0x%x, corr=%.2f, n_pucch=%d, n_prb=%d%s%s%s\n", - rnti, - srslte_pucch_get_last_corr(&enb_ul.pucch), - enb_ul.pucch.last_n_pucch, enb_ul.pucch.last_n_prb, - needs_ack?(uci_data.uci_ack?", ack=1":", ack=0"):"", - needs_sr?(uci_data.scheduling_request?", sr=yes":", sr=no"):"", - needs_cqi?cqi_str:""); - - - // Notify MAC of RL status - if (!needs_sr) { - if (srslte_pucch_get_last_corr(&enb_ul.pucch) < PUCCH_RL_CORR_TH) { - Debug("PUCCH: Radio-Link failure corr=%.1f\n", srslte_pucch_get_last_corr(&enb_ul.pucch)); - phy->mac->rl_failure(rnti); - } else { - phy->mac->rl_ok(rnti); - } - } - } - } - } - return 0; -} - - -int phch_worker::encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks, uint32_t sf_idx) -{ - for (uint32_t i=0;i::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + uint16_t rnti = (uint16_t) iter->first; + + if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END && ue_db[rnti].has_grant_tti != (int) tti_rx) { + // Check if user needs to receive PUCCH + bool needs_pucch = false, needs_ack[SRSLTE_MAX_TB] = {false}, needs_sr = false, needs_cqi = false, + needs_ri = false; + uint32_t last_n_pdcch = 0; + bzero(&uci_data, sizeof(srslte_uci_data_t)); + + if (ue_db[rnti].I_sr_en) { + if (srslte_ue_ul_sr_send_tti(ue_db[rnti].I_sr, tti_rx)) { + needs_pucch = true; + needs_sr = true; + uci_data.scheduling_request = true; + } + } + + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + needs_ack[tb] = phy->ack_is_pending(t_rx, rnti, tb, &last_n_pdcch); + if (needs_ack[tb]) { + needs_pucch = true; + uci_data.uci_ack_len++; + } + } + srslte_cqi_value_t cqi_value; + LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated = &ue_db[rnti].dedicated; + LIBLTE_RRC_TRANSMISSION_MODE_ENUM tx_mode = dedicated->antenna_info_explicit_value.tx_mode; + + if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack[0] || !needs_ack[1])) { + if (ue_db[rnti].ri_en && srslte_ri_send(ue_db[rnti].pmi_idx, ue_db[rnti].ri_idx, tti_rx)) { + needs_pucch = true; + needs_ri = true; + uci_data.uci_ri_len = 1; + uci_data.ri_periodic_report = true; + } else if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { + needs_pucch = true; + needs_cqi = true; + cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; + uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value); + if (tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { + //uci_data.uci_dif_cqi_len = 3; + uci_data.uci_pmi_len = 2; + } + } + } + + if (needs_pucch) { + if (srslte_enb_ul_get_pucch(&enb_ul, rnti, last_n_pdcch, sf_rx, &uci_data)) { + fprintf(stderr, "Error getting PUCCH\n"); + return SRSLTE_ERROR; + } + /* If only one ACK is required, it can be for TB0 or TB1 */ + uint32_t ack_idx = 0; + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + if (needs_ack[tb]) { + bool ack = ((ack_idx++ == 0) ? uci_data.uci_ack : uci_data.uci_ack_2); + bool valid = srslte_pucch_get_last_corr(&enb_ul.pucch) >= PUCCH_RL_CORR_TH; + phy->mac->ack_info(tti_rx, rnti, tb, ack && valid); + } + } + if (uci_data.scheduling_request) { + phy->mac->sr_detected(tti_rx, rnti); + } + + char cqi_ri_str[64]; + if (srslte_pucch_get_last_corr(&enb_ul.pucch) > PUCCH_RL_CORR_TH) { + if (uci_data.uci_ri_len && needs_ri) { + phy->mac->ri_info(tti_rx, rnti, uci_data.uci_ri); + sprintf(cqi_ri_str, ", ri=%d", uci_data.uci_ri); + } else if (uci_data.uci_cqi_len && needs_cqi) { + srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); + phy->mac->cqi_info(tti_rx, rnti, cqi_value.wideband.wideband_cqi); + sprintf(cqi_ri_str, ", cqi=%d", cqi_value.wideband.wideband_cqi); + + if (uci_data.uci_pmi_len) { + uint32_t packed_pmi = uci_data.uci_pmi[0]; + if (uci_data.uci_pmi_len > 1) { + packed_pmi = (packed_pmi << 1) + uci_data.uci_pmi[1]; + } + phy->mac->pmi_info(tti_rx, rnti, packed_pmi); + sprintf(cqi_ri_str, "%s, pmi=%c", cqi_ri_str, packed_pmi + 0x30); + } + + } + } + log_h->info("PUCCH: rnti=0x%x, corr=%.2f, n_pucch=%d, n_prb=%d%s%s%s%s\n", + rnti, + srslte_pucch_get_last_corr(&enb_ul.pucch), + enb_ul.pucch.last_n_pucch, enb_ul.pucch.last_n_prb, + (uci_data.uci_ack_len)?(uci_data.uci_ack?", ack=1":", ack=0"):"", + (uci_data.uci_ack_len > 1)?(uci_data.uci_ack_2?"1":"0"):"", + needs_sr?(uci_data.scheduling_request?", sr=yes":", sr=no"):"", + (needs_cqi || needs_ri)?cqi_ri_str:""); + + + // Notify MAC of RL status + if (!needs_sr) { + if (srslte_pucch_get_last_corr(&enb_ul.pucch) < PUCCH_RL_CORR_TH) { + Debug("PUCCH: Radio-Link failure corr=%.1f\n", srslte_pucch_get_last_corr(&enb_ul.pucch)); + phy->mac->rl_failure(rnti); + } else { + phy->mac->rl_ok(rnti); + } + } + } + } + } + return 0; +} + + +int phch_worker::encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks) +{ + for (uint32_t i=0;irnti; if (rnti) { - srslte_dci_format_t format = SRSLTE_DCI_FORMAT1; - switch(grants[i].grant.alloc_type) { - case SRSLTE_RA_ALLOC_TYPE0: - case SRSLTE_RA_ALLOC_TYPE1: - format = SRSLTE_DCI_FORMAT1; - break; - case SRSLTE_RA_ALLOC_TYPE2: - format = SRSLTE_DCI_FORMAT1A; - break; - } - if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, format, grants[i].location, rnti, sf_idx)) { + if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, grant->dci_format, grants[i].location, rnti, sf_tx)) { fprintf(stderr, "Error putting PDCCH %d\n",i); - return SRSLTE_ERROR; - } - + return SRSLTE_ERROR; + } + if (LOG_THIS(rnti)) { - Info("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti_tx=%d\n", srslte_dci_format_string(format), - rnti, grants[i].location.ncce, (1<dci_format), + rnti, grants[i].location.ncce, (1<info_hex(ptr, len, - "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx=%d\n", - rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, - phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx); + "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tti_tx_dl=%d, tx_scheme=%s%s%s%s\n", + rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, tti_tx_dl, + srslte_mimotype2str(mimo_type), pinfo_str, tbstr[0], tbstr[1]); } - srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL}; - uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL}; - int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, 0}; + int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, grants[i].grant.rv_idx_1}; - - if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, rv, sf_idx, d, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0)) - { - fprintf(stderr, "Error putting PDSCH %d\n",i); - return SRSLTE_ERROR; + if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffers, rnti, rv, sf_tx, grants[i].data, mimo_type)) { + fprintf(stderr, "Error putting PDSCH %d\n", i); + return SRSLTE_ERROR; } - // Save metrics stats + // Save metrics stats ue_db[rnti].metrics_dl(phy_grant.mcs[0].idx); } } - return SRSLTE_SUCCESS; + return SRSLTE_SUCCESS; } diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index c0d0a73c9..7aa965291 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -36,10 +36,10 @@ #include "srslte/common/log.h" #include "phy/phy.h" -#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) using namespace std; @@ -207,6 +207,13 @@ void phy::get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]) /***** RRC->PHY interface **********/ +void phy::set_conf_dedicated_ack(uint16_t rnti, bool ack) +{ + for (uint32_t i = 0; i < nof_workers; i++) { + workers[i].set_conf_dedicated_ack(rnti, ack); + } +} + void phy::set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) { // Parse RRC config @@ -225,11 +232,7 @@ void phy::set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICAT pucch_sched.n_pucch_sr = dedicated->sched_request_cnfg.sr_pucch_resource_idx; for (uint32_t i=0;isched_request_cnfg.sr_cnfg_idx, - dedicated->cqi_report_cnfg.report_periodic_setup_present, - dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx, - dedicated->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi); + workers[i].set_config_dedicated(rnti, &uci_cfg, &pucch_sched, NULL, dedicated); } } diff --git a/srsenb/src/phy/txrx.cc b/srsenb/src/phy/txrx.cc index 9427e3459..396069b45 100644 --- a/srsenb/src/phy/txrx.cc +++ b/srsenb/src/phy/txrx.cc @@ -32,10 +32,10 @@ #include "phy/txrx.h" #include "phy/phch_worker.h" -#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) using namespace std; @@ -77,7 +77,7 @@ void txrx::stop() void txrx::run_thread() { phch_worker *worker = NULL; - cf_t *buffer = NULL; + cf_t *buffer[SRSLTE_MAX_PORTS] = {NULL}; srslte_timestamp_t rx_time, tx_time; uint32_t sf_len = SRSLTE_SF_LEN_PRB(worker_com->cell.nof_prb); @@ -108,14 +108,16 @@ void txrx::run_thread() while (running) { tti = (tti+1)%10240; worker = (phch_worker*) workers_pool->wait_worker(tti); - if (worker) { - buffer = worker->get_buffer_rx(); + if (worker) { + for (int p = 0; p < SRSLTE_MAX_PORTS; p++){ + buffer[p] = worker->get_buffer_rx(p); + } - radio_h->rx_now(buffer, sf_len, &rx_time); + radio_h->rx_now((void **) buffer, sf_len, &rx_time); /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ srslte_timestamp_copy(&tx_time, &rx_time); - srslte_timestamp_add(&tx_time, 0, 4e-3); + srslte_timestamp_add(&tx_time, 0, HARQ_DELAY_MS*1e-3); Debug("Settting TTI=%d, tx_mutex=%d, tx_time=%d:%f to worker %d\n", tti, tx_mutex_cnt, @@ -129,7 +131,7 @@ void txrx::run_thread() workers_pool->start_worker(worker); // Trigger prach worker execution - prach->new_tti(tti, buffer); + prach->new_tti(tti, buffer[0]); } else { // wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here diff --git a/srsenb/src/upper/gtpu.cc b/srsenb/src/upper/gtpu.cc index d8f53d662..5d64cb4e5 100644 --- a/srsenb/src/upper/gtpu.cc +++ b/srsenb/src/upper/gtpu.cc @@ -82,6 +82,7 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_ #endif struct sockaddr_in bindaddr; + bzero(&bindaddr, sizeof(struct sockaddr_in)); bindaddr.sin_family = AF_INET; bindaddr.sin_addr.s_addr = inet_addr(gtp_bind_addr.c_str()); bindaddr.sin_port = htons(GTPU_PORT); @@ -137,7 +138,10 @@ void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* pdu) servaddr.sin_port = htons(GTPU_PORT); gtpu_write_header(&header, pdu); - sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in)); + if (sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in))<0) { + perror("sendto"); + } + pool->deallocate(pdu); } diff --git a/srsenb/src/upper/pdcp.cc b/srsenb/src/upper/pdcp.cc index 027f04909..afd41976f 100644 --- a/srsenb/src/upper/pdcp.cc +++ b/srsenb/src/upper/pdcp.cc @@ -124,6 +124,10 @@ void pdcp::user_interface_rlc::write_sdu(uint32_t lcid, srslte::byte_buffer_t* s rlc->write_sdu(rnti, lcid, sdu); } +bool pdcp::user_interface_rlc::rb_is_um(uint32_t lcid) { + return rlc->rb_is_um(rnti, lcid); +} + void pdcp::user_interface_rrc::write_pdu(uint32_t lcid, srslte::byte_buffer_t* pdu) { rrc->write_pdu(rnti, lcid, pdu); diff --git a/srsenb/src/upper/rlc.cc b/srsenb/src/upper/rlc.cc index 6147597e3..fff674112 100644 --- a/srsenb/src/upper/rlc.cc +++ b/srsenb/src/upper/rlc.cc @@ -160,6 +160,14 @@ void rlc::write_sdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* sdu) } } +bool rlc::rb_is_um(uint16_t rnti, uint32_t lcid) { + if (users.count(rnti)) { + return users[rnti].rlc->rb_is_um(lcid); + } else { + return false; + } +} + void rlc::user_interface::max_retx_attempted() { rrc->max_retx_attempted(rnti); diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 4a432b394..223a0d6ed 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -223,9 +223,13 @@ void rrc::rem_user(uint16_t rnti) if (users.count(rnti) == 1) { rrc_log->console("Disconnecting rnti=0x%x.\n", rnti); rrc_log->info("Disconnecting rnti=0x%x.\n", rnti); - /* **Caution** order of removal here is imporant: from bottom to top */ + /* **Caution** order of removal here is important: from bottom to top */ mac->ue_rem(rnti); // MAC handles PHY + + pthread_mutex_unlock(&user_mutex); usleep(50000); + pthread_mutex_lock(&user_mutex); + rlc->rem_user(rnti); pdcp->rem_user(rnti); gtpu->rem_user(rnti); @@ -695,10 +699,19 @@ rrc::ue::ue() { parent = NULL; set_activity(); - sr_allocated = false; has_tmsi = false; connect_notified = false; transaction_id = 0; + sr_allocated = false; + sr_sched_sf_idx = 0; + sr_sched_prb_idx = 0; + sr_N_pucch = 0; + sr_I = 0; + cqi_allocated = false; + cqi_pucch = 0; + cqi_idx = 0; + cqi_sched_sf_idx = 0; + cqi_sched_prb_idx = 0; state = RRC_STATE_IDLE; } @@ -764,9 +777,9 @@ bool rrc::ue::is_timeout() } if (deadline_str) { - uint64_t deadline = deadline_s*1e6 + deadline_us; - uint64_t elapsed = t[0].tv_sec*1e6 + t[0].tv_usec; - if (elapsed > deadline) { + int64_t deadline = deadline_s*1e6 + deadline_us; + int64_t elapsed = t[0].tv_sec*1e6 + t[0].tv_usec; + if (elapsed > deadline && elapsed > 0) { parent->rrc_log->warning("User rnti=0x%x expired %s deadline: %d:%d>%d:%d us\n", rnti, deadline_str, t[0].tv_sec, t[0].tv_usec, @@ -862,6 +875,10 @@ void rrc::ue::handle_rrc_con_setup_complete(LIBLTE_RRC_CONNECTION_SETUP_COMPLETE memcpy(pdu->msg, msg->dedicated_info_nas.msg, msg->dedicated_info_nas.N_bytes); pdu->N_bytes = msg->dedicated_info_nas.N_bytes; + // Acknowledge Dedicated Configuration + parent->phy->set_conf_dedicated_ack(rnti, true); + parent->mac->phy_config_enabled(rnti, true); + if(has_tmsi) { parent->s1ap->initial_ue(rnti, pdu, m_tmsi, mmec); } else { @@ -1106,14 +1123,21 @@ void rrc::ue::send_connection_setup(bool is_setup) mac_cfg->time_alignment_timer = parent->cfg.mac_cnfg.time_alignment_timer; // physicalConfigDedicated - rr_cfg->phy_cnfg_ded_present = true; + rr_cfg->phy_cnfg_ded_present = true; LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cfg = &rr_cfg->phy_cnfg_ded; bzero(phy_cfg, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT)); phy_cfg->pusch_cnfg_ded_present = true; memcpy(&phy_cfg->pusch_cnfg_ded, &parent->cfg.pusch_cfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_DEDICATED_STRUCT)); phy_cfg->sched_request_cnfg_present = true; phy_cfg->sched_request_cnfg.setup_present = true; - phy_cfg->sched_request_cnfg.dsr_trans_max = parent->cfg.sr_cfg.dsr_max; + phy_cfg->sched_request_cnfg.dsr_trans_max = parent->cfg.sr_cfg.dsr_max; + + if (parent->cfg.antenna_info.tx_mode > LIBLTE_RRC_TRANSMISSION_MODE_1) { + memcpy(&phy_cfg->antenna_info_explicit_value, &parent->cfg.antenna_info, + sizeof(LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT)); + phy_cfg->antenna_info_present = true; + phy_cfg->antenna_info_default_value = false; + } if (is_setup) { if (sr_allocate(parent->cfg.sr_cfg.period, &phy_cfg->sched_request_cnfg.sr_cnfg_idx, &phy_cfg->sched_request_cnfg.sr_pucch_resource_idx)) { @@ -1138,13 +1162,23 @@ void rrc::ue::send_connection_setup(bool is_setup) phy_cfg->cqi_report_cnfg_present = true; if(parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) { phy_cfg->cqi_report_cnfg.report_mode_aperiodic_present = true; - phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30; + if (phy_cfg->antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { + phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31; + } else { + phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30; + } } else { phy_cfg->cqi_report_cnfg.report_periodic_present = true; phy_cfg->cqi_report_cnfg.report_periodic_setup_present = true; phy_cfg->cqi_report_cnfg.report_periodic.format_ind_periodic = LIBLTE_RRC_CQI_FORMAT_INDICATOR_PERIODIC_WIDEBAND_CQI; - phy_cfg->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi = parent->cfg.cqi_cfg.simultaneousAckCQI; - phy_cfg->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present = false; + phy_cfg->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi = parent->cfg.cqi_cfg.simultaneousAckCQI; + if (phy_cfg->antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3 || + phy_cfg->antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { + phy_cfg->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present = true; + phy_cfg->cqi_report_cnfg.report_periodic.ri_cnfg_idx = 483; + } else { + phy_cfg->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present = false; + } if (is_setup) { if (cqi_allocate(parent->cfg.cqi_cfg.period, &phy_cfg->cqi_report_cnfg.report_periodic.pmi_cnfg_idx, @@ -1194,7 +1228,9 @@ void rrc::ue::send_connection_setup(bool is_setup) // Configure PHY layer parent->phy->set_config_dedicated(rnti, phy_cfg); - parent->mac->phy_config_enabled(rnti, true); + parent->phy->set_conf_dedicated_ack(rnti, false); + parent->mac->set_dl_ant_info(rnti, &phy_cfg->antenna_info_explicit_value); + parent->mac->phy_config_enabled(rnti, false); rr_cfg->drb_to_add_mod_list_size = 0; rr_cfg->drb_to_release_list_size = 0; diff --git a/srsue/hdr/mac/demux.h b/srsue/hdr/mac/demux.h index 8b722e8c9..fb38990ec 100644 --- a/srsue/hdr/mac/demux.h +++ b/srsue/hdr/mac/demux.h @@ -41,14 +41,16 @@ namespace srsue { class demux : public srslte::pdu_queue::process_callback { public: - demux(uint8_t nof_harq_proc_); + demux(); void init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc, srslte::log* log_h_, srslte::timers::timer* time_alignment_timer); bool process_pdus(); - uint8_t* request_buffer(uint32_t pid, uint32_t len); + uint8_t* request_buffer(uint32_t len); + uint8_t* request_buffer_bcch(uint32_t len); void deallocate(uint8_t* payload_buffer_ptr); - void push_pdu(uint32_t pid, uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp); + void push_pdu(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp); + void push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp); void push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes); void set_uecrid_callback(bool (*callback)(void*, uint64_t), void *arg); @@ -59,7 +61,8 @@ public: private: const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps const static int NOF_BUFFER_PDUS = 64; // Number of PDU buffers per HARQ pid - uint8_t bcch_buffer[1024]; // BCCH PID has a dedicated buffer + const static int MAX_BCCH_PDU_LEN = 1024; + uint8_t bcch_buffer[MAX_BCCH_PDU_LEN]; // BCCH PID has a dedicated buffer bool (*uecrid_callback) (void*, uint64_t); void *uecrid_callback_arg; @@ -76,8 +79,7 @@ private: srslte::log *log_h; srslte::timers::timer *time_alignment_timer; rlc_interface_mac *rlc; - uint8_t nof_harq_proc; - + // Buffer of PDUs srslte::pdu_queue pdus; }; diff --git a/srsue/hdr/mac/dl_harq.h b/srsue/hdr/mac/dl_harq.h index ee925596f..9a7f66f47 100644 --- a/srsue/hdr/mac/dl_harq.h +++ b/srsue/hdr/mac/dl_harq.h @@ -27,10 +27,10 @@ #ifndef DL_HARQ_H #define DL_HARQ_H -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #include "srslte/common/log.h" #include "srslte/common/timers.h" @@ -262,10 +262,13 @@ private: if (!ack) { // Instruct the PHY To combine the received data and attempt to decode it - payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid * SRSLTE_MAX_TB + tid, - cur_grant.n_bytes[tid]); + if (pid == HARQ_BCCH_PID) { + payload_buffer_ptr = harq_entity->demux_unit->request_buffer_bcch(cur_grant.n_bytes[tid]); + } else { + payload_buffer_ptr = harq_entity->demux_unit->request_buffer(cur_grant.n_bytes[tid]); + } action->payload_ptr[tid] = payload_buffer_ptr; - if (!action->payload_ptr) { + if (!action->payload_ptr[tid]) { action->decode_enabled[tid] = false; Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes[tid]); return; @@ -305,8 +308,7 @@ private: harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes[tid], ack, cur_grant.tti); } Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes[tid]); - harq_entity->demux_unit->push_pdu(pid * SRSLTE_MAX_TB + tid, payload_buffer_ptr, cur_grant.n_bytes[tid], - cur_grant.tti); + harq_entity->demux_unit->push_pdu_bcch(payload_buffer_ptr, cur_grant.n_bytes[tid], cur_grant.tti); } else { if (harq_entity->pcap) { harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes[tid], cur_grant.rnti, ack, @@ -318,8 +320,7 @@ private: harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes[tid]); } else { Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes[tid]); - harq_entity->demux_unit->push_pdu(pid * SRSLTE_MAX_TB + tid, payload_buffer_ptr, cur_grant.n_bytes[tid], - cur_grant.tti); + harq_entity->demux_unit->push_pdu(payload_buffer_ptr, cur_grant.n_bytes[tid], cur_grant.tti); // Compute average number of retransmissions per packet harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, @@ -346,9 +347,10 @@ private: // Determine if it's a new transmission 5.3.2.2 bool calc_is_new_transmission(Tgrant grant) { - if ((grant.ndi[tid] != cur_grant.ndi[tid]) || // 1st condition (NDI has changed) - (pid == HARQ_BCCH_PID && grant.rv[tid] == 0) || // 2nd condition (Broadcast and 1st transmission) - is_first_tb) // 3rd condition (first TB) + if (grant.phy_grant.dl.mcs[tid].idx <= 28 && // mcs 29,30,31 always retx regardless of rest + ((grant.ndi[tid] != cur_grant.ndi[tid]) || // 1st condition (NDI has changed) + (pid == HARQ_BCCH_PID && grant.rv[tid] == 0) || // 2nd condition (Broadcast and 1st transmission) + is_first_tb)) { is_first_tb = false; is_new_transmission = true; diff --git a/srsue/hdr/mac/mac.h b/srsue/hdr/mac/mac.h index a306af187..b1b649de7 100644 --- a/srsue/hdr/mac/mac.h +++ b/srsue/hdr/mac/mac.h @@ -79,7 +79,8 @@ public: void pcch_stop_rx(); void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD); void reconfiguration(); - void reset(); + void reset(); + void wait_uplink(); /******** set/get MAC configuration ****************/ void set_config(mac_cfg_t *mac_cfg); @@ -88,8 +89,12 @@ public: void set_config_rach(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT *rach_cfg, uint32_t prach_config_index); void set_config_sr(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT *sr_cfg); void set_contention_id(uint64_t uecri); - + + void start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask); + void start_cont_ho(); + void get_rntis(ue_rnti_t *rntis); + void set_ho_rnti(uint16_t crnti, uint16_t target_pci); void start_pcap(srslte::mac_pcap* pcap); @@ -109,7 +114,7 @@ private: static const int MAC_MAIN_THREAD_PRIO = 5; static const int MAC_PDU_THREAD_PRIO = 6; - static const int MAC_NOF_HARQ_PROC = 8; + static const int MAC_NOF_HARQ_PROC = 2*HARQ_DELAY_MS; // Interaction with PHY srslte::tti_sync_cv ttisync; diff --git a/srsue/hdr/mac/mux.h b/srsue/hdr/mac/mux.h index 1167af752..ebc61b5c6 100644 --- a/srsue/hdr/mac/mux.h +++ b/srsue/hdr/mac/mux.h @@ -82,8 +82,7 @@ private: const static int MIN_RLC_SDU_LEN = 0; const static int MAX_NOF_SUBHEADERS = 20; - const static int MAX_HARQ_PROC = 8; - + std::vector lch; // Keep track of the PIDs that transmitted BSR reports @@ -100,7 +99,7 @@ private: uint8_t nof_harq_proc; /* Msg3 Buffer */ - static const uint32_t MSG3_BUFF_SZ = 128; + static const uint32_t MSG3_BUFF_SZ = 1024; uint8_t msg3_buff[MSG3_BUFF_SZ]; /* PDU Buffer */ diff --git a/srsue/hdr/mac/proc_ra.h b/srsue/hdr/mac/proc_ra.h index 2bd2dd807..de8a0671d 100644 --- a/srsue/hdr/mac/proc_ra.h +++ b/srsue/hdr/mac/proc_ra.h @@ -43,164 +43,175 @@ namespace srsue { class ra_proc : public srslte::timer_callback { - public: - ra_proc() : rar_pdu_msg(20) { - bzero(&softbuffer_rar, sizeof(srslte_softbuffer_rx_t)); - pcap = NULL; - backoff_interval_start = 0; - backoff_inteval = 0; - received_target_power_dbm = 0; - ra_rnti = 0; - current_ta = 0; - state = IDLE; - last_msg3_group = RA_GROUP_A; - msg3_transmitted = false; - first_rar_received = false; - phy_h = NULL; - log_h = NULL; - mac_cfg = NULL; - mux_unit = NULL; - demux_unit = NULL; - rrc = NULL; - transmitted_contention_id = 0; - transmitted_crnti = 0; - pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; - started_by_pdcch = false; - rar_grant_nbytes = 0; - rar_grant_tti = 0; - msg3_flushed = false; +public: + ra_proc() : rar_pdu_msg(20) { + bzero(&softbuffer_rar, sizeof(srslte_softbuffer_rx_t)); + pcap = NULL; + backoff_interval_start = 0; + backoff_inteval = 0; + received_target_power_dbm = 0; + ra_rnti = 0; + current_ta = 0; + state = IDLE; + last_msg3_group = RA_GROUP_A; + msg3_transmitted = false; + first_rar_received = false; + phy_h = NULL; + log_h = NULL; + mac_cfg = NULL; + mux_unit = NULL; + demux_unit = NULL; + rrc = NULL; + transmitted_contention_id = 0; + transmitted_crnti = 0; + pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; + started_by_pdcch = false; + rar_grant_nbytes = 0; + rar_grant_tti = 0; + msg3_flushed = false; - time_alignment_timer = NULL; - contention_resolution_timer = NULL; - }; + noncontention_enabled = false; + next_preamble_idx = 0; + next_prach_mask = 0; - ~ra_proc(); + time_alignment_timer = NULL; + contention_resolution_timer = NULL; + }; - void init(phy_interface_mac *phy_h, - rrc_interface_mac *rrc_, - srslte::log *log_h, - mac_interface_rrc::ue_rnti_t *rntis, - mac_interface_rrc::mac_cfg_t *mac_cfg, - srslte::timers::timer* time_alignment_timer_, - srslte::timers::timer* contention_resolution_timer_, - mux *mux_unit, - demux *demux_unit); - void reset(); - void start_pdcch_order(); - void start_mac_order(uint32_t msg_len_bits = 56); - void step(uint32_t tti); - bool is_successful(); - bool is_response_error(); - bool is_contention_resolution(); - void harq_retx(); - bool is_error(); - bool in_progress(); - void pdcch_to_crnti(bool contains_uplink_grant); - void timer_expired(uint32_t timer_id); - - void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action); - void tb_decoded_ok(); - - void start_pcap(srslte::mac_pcap* pcap); + ~ra_proc(); + + void init(phy_interface_mac *phy_h, + rrc_interface_mac *rrc_, + srslte::log *log_h, + mac_interface_rrc::ue_rnti_t *rntis, + mac_interface_rrc::mac_cfg_t *mac_cfg, + srslte::timers::timer* time_alignment_timer_, + srslte::timers::timer* contention_resolution_timer_, + mux *mux_unit, + demux *demux_unit); + void reset(); + void start_pdcch_order(); + void start_mac_order(uint32_t msg_len_bits = 56, bool is_ho = false); + void step(uint32_t tti); + bool is_successful(); + bool is_response_error(); + bool is_contention_resolution(); + void harq_retx(); + bool is_error(); + bool in_progress(); + void pdcch_to_crnti(bool contains_uplink_grant); + void timer_expired(uint32_t timer_id); + + void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action); + void tb_decoded_ok(); + + void start_noncont(uint32_t preamble_index, uint32_t prach_mask); + + void start_pcap(srslte::mac_pcap* pcap); private: - static bool uecrid_callback(void *arg, uint64_t uecri); + static bool uecrid_callback(void *arg, uint64_t uecri); - bool contention_resolution_id_received(uint64_t uecri); - void process_timeadv_cmd(uint32_t ta_cmd); - void step_initialization(); - void step_resource_selection(); - void step_preamble_transmission(); - void step_pdcch_setup(); - void step_response_reception(); - void step_response_error(); - void step_backoff_wait(); - void step_contention_resolution(); - void step_completition(); + bool contention_resolution_id_received(uint64_t uecri); + void process_timeadv_cmd(uint32_t ta_cmd); + void step_initialization(); + void step_resource_selection(); + void step_preamble_transmission(); + void step_pdcch_setup(); + void step_response_reception(); + void step_response_error(); + void step_backoff_wait(); + void step_contention_resolution(); + void step_completition(); - // Buffer to receive RAR PDU - static const uint32_t MAX_RAR_PDU_LEN = 2048; - uint8_t rar_pdu_buffer[MAX_RAR_PDU_LEN]; - srslte::rar_pdu rar_pdu_msg; + // Buffer to receive RAR PDU + static const uint32_t MAX_RAR_PDU_LEN = 2048; + uint8_t rar_pdu_buffer[MAX_RAR_PDU_LEN]; + srslte::rar_pdu rar_pdu_msg; - // Random Access parameters provided by higher layers defined in 5.1.1 - uint32_t configIndex; - uint32_t nof_preambles; - uint32_t nof_groupA_preambles; - uint32_t nof_groupB_preambles; - uint32_t messagePowerOffsetGroupB; - uint32_t messageSizeGroupA; - uint32_t responseWindowSize; - uint32_t powerRampingStep; - uint32_t preambleTransMax; - uint32_t iniReceivedTargetPower; - int delta_preamble_db; - uint32_t contentionResolutionTimer; - uint32_t maskIndex; - int preambleIndex; - uint32_t new_ra_msg_len; + // Random Access parameters provided by higher layers defined in 5.1.1 + uint32_t configIndex; + uint32_t nof_preambles; + uint32_t nof_groupA_preambles; + uint32_t nof_groupB_preambles; + uint32_t messagePowerOffsetGroupB; + uint32_t messageSizeGroupA; + uint32_t responseWindowSize; + uint32_t powerRampingStep; + uint32_t preambleTransMax; + uint32_t iniReceivedTargetPower; + int delta_preamble_db; + uint32_t contentionResolutionTimer; + uint32_t maskIndex; + int preambleIndex; + uint32_t new_ra_msg_len; - // Internal variables - uint32_t preambleTransmissionCounter; - uint32_t backoff_param_ms; - uint32_t sel_maskIndex; - uint32_t sel_preamble; - uint32_t backoff_interval_start; - uint32_t backoff_inteval; - int received_target_power_dbm; - uint32_t ra_rnti; - uint32_t current_ta; + bool noncontention_enabled; + uint32_t next_preamble_idx; + uint32_t next_prach_mask; - srslte_softbuffer_rx_t softbuffer_rar; + // Internal variables + uint32_t preambleTransmissionCounter; + uint32_t backoff_param_ms; + uint32_t sel_maskIndex; + uint32_t sel_preamble; + uint32_t backoff_interval_start; + uint32_t backoff_inteval; + int received_target_power_dbm; + uint32_t ra_rnti; + uint32_t current_ta; - enum { - IDLE = 0, - INITIALIZATION, // Section 5.1.1 - RESOURCE_SELECTION, // Section 5.1.2 - PREAMBLE_TRANSMISSION, // Section 5.1.3 - PDCCH_SETUP, - RESPONSE_RECEPTION, // Section 5.1.4 - RESPONSE_ERROR, - BACKOFF_WAIT, - CONTENTION_RESOLUTION, // Section 5.1.5 - COMPLETION, // Section 5.1.6 - COMPLETION_DONE, - RA_PROBLEM // Section 5.1.5 last part - } state; + srslte_softbuffer_rx_t softbuffer_rar; - typedef enum {RA_GROUP_A, RA_GROUP_B} ra_group_t; + enum { + IDLE = 0, + INITIALIZATION, // Section 5.1.1 + RESOURCE_SELECTION, // Section 5.1.2 + PREAMBLE_TRANSMISSION, // Section 5.1.3 + PDCCH_SETUP, + RESPONSE_RECEPTION, // Section 5.1.4 + RESPONSE_ERROR, + BACKOFF_WAIT, + CONTENTION_RESOLUTION, // Section 5.1.5 + COMPLETION, // Section 5.1.6 + COMPLETION_DONE, + RA_PROBLEM // Section 5.1.5 last part + } state; - ra_group_t last_msg3_group; - bool msg3_transmitted; - bool first_rar_received; - void read_params(); + typedef enum {RA_GROUP_A, RA_GROUP_B} ra_group_t; - phy_interface_mac *phy_h; - srslte::log *log_h; - mux *mux_unit; - demux *demux_unit; - srslte::mac_pcap *pcap; - rrc_interface_mac *rrc; + ra_group_t last_msg3_group; + bool msg3_transmitted; + bool first_rar_received; + void read_params(); - srslte::timers::timer *time_alignment_timer; - srslte::timers::timer *contention_resolution_timer; + phy_interface_mac *phy_h; + srslte::log *log_h; + mux *mux_unit; + demux *demux_unit; + srslte::mac_pcap *pcap; + rrc_interface_mac *rrc; - mac_interface_rrc::ue_rnti_t *rntis; - mac_interface_rrc::mac_cfg_t *mac_cfg; + srslte::timers::timer *time_alignment_timer; + srslte::timers::timer *contention_resolution_timer; - uint64_t transmitted_contention_id; - uint16_t transmitted_crnti; + mac_interface_rrc::ue_rnti_t *rntis; + mac_interface_rrc::mac_cfg_t *mac_cfg; - enum { - PDCCH_CRNTI_NOT_RECEIVED = 0, - PDCCH_CRNTI_UL_GRANT, - PDCCH_CRNTI_DL_GRANT - } pdcch_to_crnti_received; + uint64_t transmitted_contention_id; + uint16_t transmitted_crnti; - bool started_by_pdcch; - uint32_t rar_grant_nbytes; - uint32_t rar_grant_tti; - bool msg3_flushed; - bool rar_received; + enum { + PDCCH_CRNTI_NOT_RECEIVED = 0, + PDCCH_CRNTI_UL_GRANT, + PDCCH_CRNTI_DL_GRANT + } pdcch_to_crnti_received; + + bool ra_is_ho; + bool started_by_pdcch; + uint32_t rar_grant_nbytes; + uint32_t rar_grant_tti; + bool msg3_flushed; + bool rar_received; }; } // namespace srsue diff --git a/srsue/hdr/mac/ul_harq.h b/srsue/hdr/mac/ul_harq.h index 4749971b6..5b33be1ec 100644 --- a/srsue/hdr/mac/ul_harq.h +++ b/srsue/hdr/mac/ul_harq.h @@ -27,10 +27,10 @@ #ifndef ULHARQ_H #define ULHARQ_H -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/log.h" @@ -44,39 +44,35 @@ namespace srsue { template -class ul_harq_entity -{ +class ul_harq_entity { public: - static uint32_t pidof(uint32_t tti) - { - return (uint32_t) tti%N; + static uint32_t pidof(uint32_t tti) { + return (uint32_t) tti % N; } - - ul_harq_entity() : proc(N) - { + + ul_harq_entity() : proc(N) { contention_timer = NULL; - pcap = NULL; - mux_unit = NULL; - log_h = NULL; - params = NULL; - rntis = NULL; - average_retx = 0; - nof_pkts = 0; + pcap = NULL; + mux_unit = NULL; + log_h = NULL; + params = NULL; + rntis = NULL; + average_retx = 0; + nof_pkts = 0; } - bool init(srslte::log *log_h_, + bool init(srslte::log *log_h_, mac_interface_rrc_common::ue_rnti_t *rntis_, mac_interface_rrc_common::ul_harq_params_t *params_, - srslte::timers::timer* contention_timer_, - mux *mux_unit_) - { - log_h = log_h_; - mux_unit = mux_unit_; - params = params_; - rntis = rntis_; + srslte::timers::timer *contention_timer_, + mux *mux_unit_) { + log_h = log_h_; + mux_unit = mux_unit_; + params = params_; + rntis = rntis_; contention_timer = contention_timer_; - for (uint32_t i=0;iMAC interface for UL processes **************************/ - void new_grant_ul(Tgrant grant, Taction *action) + void new_grant_ul(Tgrant grant, Taction *action) { + new_grant_ul_ack(grant, NULL, action); + } + void new_grant_ul_ack(Tgrant grant, bool *ack, Taction *action) { if (grant.rnti_type == SRSLTE_RNTI_USER || grant.rnti_type == SRSLTE_RNTI_TEMP || @@ -115,27 +111,20 @@ public: if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) { grant.ndi[0] = true; } - run_tti(grant.tti, &grant, action); + run_tti(grant.tti, &grant, ack, action); } else if (grant.rnti_type == SRSLTE_RNTI_SPS) { if (grant.ndi[0]) { grant.ndi[0] = proc[pidof(grant.tti)].get_ndi(); - run_tti(grant.tti, &grant, action); + run_tti(grant.tti, &grant, ack, action); } else { Info("Not implemented\n"); } } } - void new_grant_ul_ack(Tgrant grant, bool ack, Taction *action) - { - set_ack(grant.tti, ack, action); - new_grant_ul(grant, action); - } - void harq_recv(uint32_t tti, bool ack, Taction *action) { - set_ack(tti, ack, action); - run_tti(tti, NULL, action); + run_tti(tti, NULL, &ack, action); } int get_current_tbs(uint32_t tti) @@ -206,24 +195,36 @@ private: bzero(&cur_grant, sizeof(Tgrant)); } - void reset_ndi() { ndi = false; } - - void run_tti(uint32_t tti_tx, Tgrant *grant, Taction* action) + void reset_ndi() { cur_grant.ndi[0] = false; } + + void run_tti(uint32_t tti_tx, Tgrant *grant, bool *ack, Taction* action) { - uint32_t max_retx; - if (is_msg3) { - max_retx = harq_entity->params->max_harq_msg3_tx; - } else { - max_retx = harq_entity->params->max_harq_tx; + if (ack) { + if (grant) { + if (grant->ndi[0] == get_ndi()) { + *ack = false; + } + } + harq_feedback = *ack; + } + + // Reset HARQ process if TB has changed + if (harq_feedback && has_grant() && grant) { + if (grant->n_bytes[0] != cur_grant.n_bytes[0] && cur_grant.n_bytes[0] > 0) { + Debug("UL %d: Reset due to change of grant size last_grant=%d, new_grant=%d\n", + pid, cur_grant.n_bytes[0], grant->n_bytes[0]); + reset(); + } } // Receive and route HARQ feedbacks if (grant) { - if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi()) || - (grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) || - grant->is_from_rar) + if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi() && harq_feedback) || + (grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) || + grant->is_from_rar) { // New transmission + reset(); // Uplink grant in a RAR if (grant->is_from_rar) { @@ -245,25 +246,15 @@ private: Warning("Uplink grant but no MAC PDU in Multiplex Unit buffer\n"); } } - } else { + } else if (has_grant()) { // Adaptive Re-TX - if (current_tx_nb >= max_retx) { - Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); - reset(); - action->expect_ack = false; - } else { - generate_retx(tti_tx, grant, action); - } + generate_retx(tti_tx, grant, action); + } else { + Warning("UL %d: Received retransmission but no previous grant available for this PID.\n", pid); } } else if (has_grant()) { // Non-Adaptive Re-Tx - if (current_tx_nb >= max_retx) { - Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); - reset(); - action->expect_ack = false; - } else { - generate_retx(tti_tx, action); - } + generate_retx(tti_tx, action); } if (harq_entity->pcap && grant) { if (grant->is_from_rar) { @@ -273,18 +264,6 @@ private: } } - void set_harq_feedback(bool ack) - { - harq_feedback = ack; - // UL packet successfully delivered - if (ack) { - Info("UL %d: HARQ = ACK for UL transmission. Discarting TB.\n", pid); - reset(); - } else { - Info("UL %d: HARQ = NACK for UL transmission\n", pid); - } - } - uint32_t get_rv() { int rv_of_irv[4] = {0, 2, 3, 1}; @@ -292,9 +271,8 @@ private: } bool has_grant() { return is_grant_configured; } - bool get_ndi() { return ndi; } + bool get_ndi() { return cur_grant.ndi[0]; } bool is_sps() { return false; } - uint32_t last_tx_tti() { return tti_last_tx; } uint32_t get_nof_retx() { return current_tx_nb; } int get_current_tbs() { return cur_grant.n_bytes[0]*8; } @@ -305,7 +283,6 @@ private: uint32_t current_tx_nb; uint32_t current_irv; bool harq_feedback; - bool ndi; srslte::log *log_h; ul_harq_entity *harq_entity; bool is_grant_configured; @@ -328,24 +305,43 @@ private: void generate_retx(uint32_t tti_tx, Tgrant *grant, Taction *action) { + uint32_t max_retx; + if (is_msg3) { + max_retx = harq_entity->params->max_harq_msg3_tx; + } else { + max_retx = harq_entity->params->max_harq_tx; + } + + if (current_tx_nb >= max_retx) { + Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); + reset(); + action->expect_ack = false; + return; + } + int irv_of_rv[4] = {0, 3, 1, 2}; + + // HARQ entity requests an adaptive transmission if (grant) { - // HARQ entity requests an adaptive transmission if (grant->rv) { current_irv = irv_of_rv[grant->rv[0]%4]; } + + Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d, HI=%s, ndi=%d, prev_ndi=%d\n", + pid, current_tx_nb, get_rv(), grant->n_bytes[0], harq_feedback?"ACK":"NACK", grant->ndi[0], cur_grant.ndi[0]); + memcpy(&cur_grant, grant, sizeof(Tgrant)); harq_feedback = false; - Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d\n", - pid, current_tx_nb, get_rv(), grant->n_bytes[0]); + + generate_tx(tti_tx, action); + + // HARQ entity requests a non-adaptive transmission + } else if (!harq_feedback) { + // Non-adaptive retx are only sent if HI=NACK. If HI=ACK but no grant was received do not reset PID + Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d, HI=%s\n", + pid, current_tx_nb, get_rv(), cur_grant.n_bytes[0], harq_feedback?"ACK":"NACK"); + generate_tx(tti_tx, action); - } else { - Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d\n", - pid, current_tx_nb, get_rv(), cur_grant.n_bytes[0]); - // HARQ entity requests a non-adaptive transmission - if (!harq_feedback) { - generate_tx(tti_tx, action); - } } // On every Msg3 retransmission, restart mac-ContentionResolutionTimer as defined in Section 5.1.5 @@ -396,24 +392,12 @@ private: // Implements Section 5.4.2.1 // Called with UL grant - void run_tti(uint32_t tti, Tgrant *grant, Taction* action) + void run_tti(uint32_t tti, Tgrant *grant, bool *ack, Taction* action) { uint32_t tti_tx = (tti+action->tti_offset)%10240; - proc[pidof(tti_tx)].run_tti(tti_tx, grant, action); + proc[pidof(tti_tx)].run_tti(tti_tx, grant, ack, action); } - void set_ack(uint32_t tti, bool ack, Taction *action) - { - int tti_harq = (int) tti - action->tti_offset; - if (tti_harq < 0) { - tti_harq += 10240; - } - uint32_t pid_harq = pidof(tti_harq); - if (proc[pid_harq].has_grant() && (proc[pid_harq].last_tx_tti() <= (uint32_t)tti_harq)) { - proc[pid_harq].set_harq_feedback(ack); - } - } - ul_sps ul_sps_assig; srslte::timers::timer *contention_timer; diff --git a/srsue/hdr/metrics_csv.h b/srsue/hdr/metrics_csv.h index a897265d2..f0b3e48c4 100644 --- a/srsue/hdr/metrics_csv.h +++ b/srsue/hdr/metrics_csv.h @@ -48,12 +48,14 @@ class metrics_csv : public srslte::metrics_listener public: metrics_csv(std::string filename); - void set_metrics(ue_metrics_t &m, float report_period_secs); + void set_periodicity(float metrics_report_period_sec); + void set_metrics(ue_metrics_t &m); void set_ue_handle(ue_metrics_interface *ue_); private: std::string float_to_string(float f, int digits, bool add_semicolon = true); + float metrics_report_period; std::ofstream file; ue_metrics_interface* ue; uint32_t n_reports; diff --git a/srsue/hdr/metrics_stdout.h b/srsue/hdr/metrics_stdout.h index 8ae33b24e..87a67cb2e 100644 --- a/srsue/hdr/metrics_stdout.h +++ b/srsue/hdr/metrics_stdout.h @@ -46,8 +46,9 @@ class metrics_stdout : public srslte::metrics_listener public: metrics_stdout(); + void set_periodicity(float metrics_report_period_sec); void toggle_print(bool b); - void set_metrics(ue_metrics_t &m, float report_period_secs); + void set_metrics(ue_metrics_t &m); void set_ue_handle(ue_metrics_interface *ue_); private: @@ -55,6 +56,7 @@ private: std::string float_to_eng_string(float f, int digits); std::string int_to_eng_string(int f, int digits); + float metrics_report_period; bool do_print; uint8_t n_reports; ue_metrics_interface* ue; diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h index aa64fe9ea..fd73d9421 100644 --- a/srsue/hdr/phy/phch_common.h +++ b/srsue/hdr/phy/phch_common.h @@ -42,122 +42,142 @@ namespace srsue { + +class chest_feedback_itf +{ +public: + virtual void out_of_sync() = 0; + virtual void set_cfo(float cfo) = 0; +}; + /* Subclass that manages variables common to all workers */ - class phch_common { - public: - - /* Common variables used by all phy workers */ - phy_interface_rrc::phy_cfg_t *config; - phy_args_t *args; - rrc_interface_phy *rrc; - mac_interface_phy *mac; - srslte_ue_ul_t ue_ul; - - /* Power control variables */ - float pathloss; - float cur_pathloss; - float p0_preamble; - float cur_radio_power; - float cur_pusch_power; - float avg_rsrp_db; - float avg_rsrq_db; - float rx_gain_offset; - float avg_snr_db; - float avg_noise; - float avg_rsrp; - - phch_common(uint32_t max_mutex = 3); - void init(phy_interface_rrc::phy_cfg_t *config, - phy_args_t *args, - srslte::log *_log, - srslte::radio *_radio, - rrc_interface_phy *rrc, - mac_interface_phy *_mac); - - /* For RNTI searches, -1 means now or forever */ - void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); - uint16_t get_ul_rnti(uint32_t tti); - srslte_rnti_type_t get_ul_rnti_type(); +class phch_common { +public: - void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); - uint16_t get_dl_rnti(uint32_t tti); - srslte_rnti_type_t get_dl_rnti_type(); - - void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]); - bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant = NULL); - - void reset_pending_ack(uint32_t tti); - void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs); - bool get_pending_ack(uint32_t tti); - bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs); - - void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); - - void set_nof_mutex(uint32_t nof_mutex); - - bool sr_enabled; - int sr_last_tx_tti; - - srslte::radio* get_radio(); + /* Common variables used by all phy workers */ + phy_interface_rrc::phy_cfg_t *config; + phy_args_t *args; + rrc_interface_phy *rrc; + mac_interface_phy *mac; - void set_cell(const srslte_cell_t &c); - uint32_t get_nof_prb(); - void set_dl_metrics(const dl_metrics_t &m); - void get_dl_metrics(dl_metrics_t &m); - void set_ul_metrics(const ul_metrics_t &m); - void get_ul_metrics(ul_metrics_t &m); - void set_sync_metrics(const sync_metrics_t &m); - void get_sync_metrics(sync_metrics_t &m); + /* Power control variables */ + float pathloss; + float cur_pathloss; + float p0_preamble; + float cur_radio_power; + float cur_pusch_power; + float avg_rsrp; + float avg_rsrp_dbm; + float avg_rsrq_db; + float rx_gain_offset; + float avg_snr_db; + float avg_noise; - void reset_ul(); - - private: - - std::vector tx_mutex; - - bool is_first_of_burst; - srslte::radio *radio_h; - float cfo; - srslte::log *log_h; + bool pcell_meas_enabled; + uint32_t pcell_report_period; - - bool ul_rnti_active(uint32_t tti); - bool dl_rnti_active(uint32_t tti); - uint16_t ul_rnti, dl_rnti; - srslte_rnti_type_t ul_rnti_type, dl_rnti_type; - int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end; - - float time_adv_sec; - - srslte_dci_rar_grant_t rar_grant; - bool rar_grant_pending; - uint32_t rar_grant_tti; - - typedef struct { - bool enabled; - uint32_t I_lowest; - uint32_t n_dmrs; - } pending_ack_t; - pending_ack_t pending_ack[10]; - - bool is_first_tx; + // Save last TBS for mcs>28 cases + int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS]; + uint32_t last_dl_tti[2*HARQ_DELAY_MS]; - uint32_t nof_workers; - uint32_t nof_mutex; - uint32_t max_mutex; + int last_ul_tbs[2*HARQ_DELAY_MS]; + uint32_t last_ul_tti[2*HARQ_DELAY_MS]; + srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS]; - srslte_cell_t cell; + phch_common(uint32_t max_mutex = 3); + void init(phy_interface_rrc::phy_cfg_t *config, + phy_args_t *args, + srslte::log *_log, + srslte::radio *_radio, + rrc_interface_phy *rrc, + mac_interface_phy *_mac); - dl_metrics_t dl_metrics; - uint32_t dl_metrics_count; - bool dl_metrics_read; - ul_metrics_t ul_metrics; - uint32_t ul_metrics_count; - bool ul_metrics_read; - sync_metrics_t sync_metrics; - uint32_t sync_metrics_count; - bool sync_metrics_read; - }; + /* For RNTI searches, -1 means now or forever */ + void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); + uint16_t get_ul_rnti(uint32_t tti); + srslte_rnti_type_t get_ul_rnti_type(); + + void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); + uint16_t get_dl_rnti(uint32_t tti); + srslte_rnti_type_t get_dl_rnti_type(); + + void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]); + bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant = NULL); + + void reset_pending_ack(uint32_t tti); + void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs); + bool get_pending_ack(uint32_t tti); + bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs); + bool is_any_pending_ack(); + + void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); + + void set_nof_mutex(uint32_t nof_mutex); + + bool sr_enabled; + int sr_last_tx_tti; + + srslte::radio* get_radio(); + + void set_cell(const srslte_cell_t &c); + uint32_t get_nof_prb(); + void set_dl_metrics(const dl_metrics_t &m); + void get_dl_metrics(dl_metrics_t &m); + void set_ul_metrics(const ul_metrics_t &m); + void get_ul_metrics(ul_metrics_t &m); + void set_sync_metrics(const sync_metrics_t &m); + void get_sync_metrics(sync_metrics_t &m); + + void reset_ul(); + void reset(); + +private: + + std::vector tx_mutex; + + bool is_first_of_burst; + srslte::radio *radio_h; + float cfo; + srslte::log *log_h; + + + bool ul_rnti_active(uint32_t tti); + bool dl_rnti_active(uint32_t tti); + uint16_t ul_rnti, dl_rnti; + srslte_rnti_type_t ul_rnti_type, dl_rnti_type; + int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end; + + float time_adv_sec; + + srslte_dci_rar_grant_t rar_grant; + bool rar_grant_pending; + uint32_t rar_grant_tti; + + typedef struct { + bool enabled; + uint32_t I_lowest; + uint32_t n_dmrs; + } pending_ack_t; + pending_ack_t pending_ack[TTIMOD_SZ]; + + bool is_first_tx; + + uint32_t nof_workers; + uint32_t nof_mutex; + uint32_t max_mutex; + + srslte_cell_t cell; + + dl_metrics_t dl_metrics; + uint32_t dl_metrics_count; + bool dl_metrics_read; + ul_metrics_t ul_metrics; + uint32_t ul_metrics_count; + bool ul_metrics_read; + sync_metrics_t sync_metrics; + uint32_t sync_metrics_count; + bool sync_metrics_read; +}; } // namespace srsue diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index 044960760..ed4bd706a 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -27,10 +27,13 @@ #ifndef UEPHYRECV_H #define UEPHYRECV_H +#include + #include "srslte/srslte.h" #include "srslte/common/log.h" #include "srslte/common/threads.h" #include "srslte/common/thread_pool.h" +#include "srslte/common/tti_sync_cv.h" #include "srslte/radio/radio_multi.h" #include "phy/prach.h" #include "phy/phch_worker.h" @@ -39,41 +42,51 @@ namespace srsue { -typedef _Complex float cf_t; +typedef _Complex float cf_t; -class phch_recv : public thread + +class phch_recv : public thread, public chest_feedback_itf { public: phch_recv(); ~phch_recv(); void init(srslte::radio_multi* radio_handler, mac_interface_phy *mac,rrc_interface_phy *rrc, prach *prach_buffer, srslte::thread_pool *_workers_pool, - phch_common *_worker_com, srslte::log* _log_h, uint32_t nof_rx_antennas, uint32_t prio, int sync_cpu_affinity = -1); + phch_common *_worker_com, srslte::log* _log_h, srslte::log *_log_phy_lib_h, uint32_t nof_rx_antennas, uint32_t prio, int sync_cpu_affinity = -1); void stop(); void set_agc_enable(bool enable); void set_earfcn(std::vector earfcn); - + void force_freq(float dl_freq, float ul_freq); + void reset_sync(); void cell_search_start(); void cell_search_stop(); void cell_search_next(bool reset = false); bool cell_select(uint32_t earfcn, srslte_cell_t cell); + bool cell_handover(srslte_cell_t cell); + + void meas_reset(); + int meas_start(uint32_t earfcn, int pci); + int meas_stop(uint32_t earfcn, int pci); uint32_t get_current_tti(); bool status_is_sync(); + // from chest_feedback_itf + void out_of_sync(); + void set_cfo(float cfo); + void set_time_adv_sec(float time_adv_sec); - void get_current_cell(srslte_cell_t *cell); - + void get_current_cell(srslte_cell_t *cell, uint32_t *earfcn = NULL); + + const static int MUTEX_X_WORKER = 4; - // public variables needed by callback function - uint32_t current_sflen; - srslte::radio_multi *radio_h; - int next_offset; - + double set_rx_gain(double gain); + int radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); + int scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); private: @@ -82,49 +95,202 @@ private: void reset(); void radio_error(); bool wait_radio_reset(); - void set_ue_sync_opts(srslte_ue_sync_t *q); + void set_ue_sync_opts(srslte_ue_sync_t *q, float cfo); void run_thread(); void set_sampling_rate(); bool set_frequency(); - void resync_sfn(bool is_connected = false); - bool stop_sync(); + bool set_cell(); void cell_search_inc(); - - bool init_cell(); - void free_cell(); + void resync_sfn(bool is_connected = false, bool rx_now = false); + bool stop_sync(); void stop_rx(); - void start_rx(); + void start_rx(bool now = false); bool radio_is_rx; bool radio_is_resetting; + bool running; - bool running; - + // Class to run cell search + class search { + public: + typedef enum {CELL_NOT_FOUND, CELL_FOUND, ERROR, TIMEOUT} ret_code; + + ~search(); + void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent); + void reset(); + float get_last_gain(); + float get_last_cfo(); + void set_N_id_2(int N_id_2); + ret_code run(srslte_cell_t *cell); + + private: + phch_recv *p; + srslte::log *log_h; + cf_t *buffer[SRSLTE_MAX_PORTS]; + srslte_ue_cellsearch_t cs; + srslte_ue_mib_sync_t ue_mib_sync; + int force_N_id_2; + }; + + // Class to synchronize system frame number + class sfn_sync { + public: + typedef enum {IDLE, SFN_FOUND, SFX0_FOUND, ERROR, TIMEOUT} ret_code; + + ~sfn_sync(); + void init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t timeout = SYNC_SFN_TIMEOUT); + void reset(); + bool set_cell(srslte_cell_t cell); + ret_code run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt, bool sfidx_only = false); + + private: + srslte::log *log_h; + srslte_ue_sync_t *ue_sync; + cf_t *buffer[SRSLTE_MAX_PORTS]; + srslte_ue_mib_t ue_mib; + uint32_t cnt; + uint32_t timeout; + const static uint32_t SYNC_SFN_TIMEOUT = 200; + }; + + // Class to perform cell measurements + class measure { + + // TODO: This class could early stop once the variance between the last N measurements is below 3GPP requirements + + public: + typedef enum {IDLE, MEASURE_OK, ERROR} ret_code; + + ~measure(); + void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, + uint32_t nof_rx_antennas, uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES); + void reset(); + void set_cell(srslte_cell_t cell); + ret_code run_subframe(uint32_t sf_idx); + ret_code run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx); + ret_code run_multiple_subframes(cf_t *buffer, uint32_t offset, uint32_t sf_idx, uint32_t nof_sf); + float rsrp(); + float rsrq(); + float snr(); + uint32_t frame_st_idx(); + void set_rx_gain_offset(float rx_gain_offset); + private: + srslte::log *log_h; + srslte_ue_dl_t ue_dl; + cf_t *buffer[SRSLTE_MAX_PORTS]; + uint32_t cnt; + uint32_t nof_subframes; + uint32_t current_prb; + float rx_gain_offset; + float mean_rsrp, mean_rsrq, mean_snr; + uint32_t final_offset; + const static int RSRP_MEASURE_NOF_FRAMES = 5; + }; + + // Class to receive secondary cell + class scell_recv { + public: + const static int MAX_CELLS = 8; + typedef struct { + uint32_t pci; + float rsrp; + float rsrq; + uint32_t offset; + } cell_info_t; + void init(srslte::log *log_h, bool sic_pss_enabled); + void reset(); + int find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t current_cell, uint32_t nof_sf, cell_info_t found_cells[MAX_CELLS]); + private: + + const static int DEFAULT_MEASUREMENT_LEN = 10; + + cf_t *input_cfo_corrected; + cf_t *sf_buffer[SRSLTE_MAX_PORTS]; + srslte::log *log_h; + srslte_sync_t sync_find; + + bool sic_pss_enabled; + uint32_t current_fft_sz; + measure measure_p; + }; + + /* TODO: Intra-freq measurements can be improved by capturing 200 ms length signal and run cell search + + * measurements offline using sync object and finding multiple cells for each N_id_2 + */ + + // Class to perform intra-frequency measurements + class intra_measure : public thread { + public: + void init(phch_common *common, rrc_interface_phy *rrc, srslte::log *log_h); + void stop(); + void add_cell(int pci); + void rem_cell(int pci); + void set_primay_cell(uint32_t earfcn, srslte_cell_t cell); + void clear_cells(); + int get_offset(uint32_t pci); + void write(uint32_t tti, cf_t *data, uint32_t nsamples); + private: + void run_thread(); + const static int CAPTURE_LEN_SF = 15; + const static int INTRA_FREQ_MEAS_PERIOD_MS = 200; + scell_recv scell; + rrc_interface_phy *rrc; + srslte::log *log_h; + phch_common *common; + uint32_t current_earfcn; + uint32_t current_sflen; + srslte_cell_t primary_cell; + std::vector active_pci; + + srslte::tti_sync_cv tti_sync; + + cf_t *search_buffer; + + scell_recv::cell_info_t info[scell_recv::MAX_CELLS]; + + bool running; + bool receive_enabled; + bool receiving; + uint32_t measure_tti; + uint32_t receive_cnt; + srslte_ringbuffer_t ring_buffer; + }; + + + + // Objects for internal use + measure measure_p; + search search_p; + sfn_sync sfn_p; + intra_measure intra_freq_meas; + + uint32_t current_sflen; + int next_offset; + uint32_t nof_rx_antennas; + + // Pointers to other classes mac_interface_phy *mac; rrc_interface_phy *rrc; srslte::log *log_h; + srslte::log *log_phy_lib_h; srslte::thread_pool *workers_pool; + srslte::radio_multi *radio_h; phch_common *worker_com; prach *prach_buffer; - // Structures for Cell Camp - srslte_ue_sync_t ue_sync; - srslte_ue_mib_t ue_mib; + // Object for synchronization of the primary cell + srslte_ue_sync_t ue_sync; - // Structures for Cell Search - srslte_ue_cellsearch_t cs; - srslte_ue_mib_sync_t ue_mib_sync; - - uint32_t nof_rx_antennas; - - cf_t *sf_buffer[SRSLTE_MAX_PORTS]; + // Buffer for primary cell samples + cf_t *sf_buffer[SRSLTE_MAX_PORTS]; // Sync metrics - sync_metrics_t metrics; + sync_metrics_t metrics; + // State for primary cell enum { IDLE = 0, CELL_SEARCH, @@ -136,41 +302,34 @@ private: bool is_in_idle; + // Sampling rate mode (find is 1.96 MHz, camp is the full cell BW) enum { SRATE_NONE=0, SRATE_FIND, SRATE_CAMP } srate_mode; float current_srate; + // This is the primary cell srslte_cell_t cell; bool cell_is_set; - bool is_sfn_synched; - bool started; + bool started; float time_adv_sec; uint32_t tti; bool do_agc; - float last_gain; - float cellsearch_cfo; uint32_t nof_tx_mutex; uint32_t tx_mutex_cnt; + float ul_dl_factor; uint32_t current_earfcn; + int cur_earfcn_index; + bool cell_search_in_progress; - uint32_t sync_sfn_cnt; - const static uint32_t SYNC_SFN_TIMEOUT = 200; - float ul_dl_factor; - int cur_earfcn_index; - bool cell_search_in_progress; - uint32_t measure_cnt; - float measure_rsrp; - srslte_ue_dl_t ue_dl_measure; + uint32_t out_of_sync_cnt; + uint32_t out_of_sync2_cnt; - const static int RSRP_MEASURE_NOF_FRAMES = 5; + float dl_freq; + float ul_freq; - int cell_sync_sfn(); - int cell_meas_rsrp(); - int cell_search(int force_N_id_2 = -1); - bool set_cell(); }; } // namespace srsue diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index 0811723e0..e1d943880 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -45,7 +45,7 @@ public: ~phch_worker(); void reset(); void set_common(phch_common *phy); - bool init(uint32_t max_prb, srslte::log *log); + bool init(uint32_t max_prb, srslte::log *log, srslte::log *log_phy_lib_h, chest_feedback_itf *chest_loop); bool set_cell(srslte_cell_t cell); @@ -66,15 +66,18 @@ public: int read_ce_abs(float *ce_abs); int read_pdsch_d(cf_t *pdsch_d); void start_plot(); - -private: + + float get_ref_cfo(); + +private: /* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */ void work_imp(); /* Internal methods */ bool extract_fft_and_pdcch_llr(); - + void compute_ri(); + /* ... for DL */ bool decode_pdcch_ul(mac_interface_phy::mac_grant_t *grant); bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant); @@ -114,6 +117,8 @@ private: /* Common objects */ phch_common *phy; srslte::log *log_h; + srslte::log *log_phy_lib_h; + chest_feedback_itf *chest_loop; srslte_cell_t cell; bool mem_initiated; bool cell_initiated; @@ -146,10 +151,11 @@ private: srslte_uci_cfg_t uci_cfg; srslte_cqi_periodic_cfg_t period_cqi; srslte_ue_ul_powerctrl_t power_ctrl; - uint32_t I_sr; + uint32_t I_sr; + bool sr_configured; float cfo; bool rar_cqi_request; - + // Metrics dl_metrics_t dl_metrics; ul_metrics_t ul_metrics; diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index 0c77360b2..5a1ac14a7 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -40,8 +40,8 @@ #include "srslte/interfaces/ue_interfaces.h" namespace srsue { - -typedef _Complex float cf_t; + +typedef _Complex float cf_t; class phy : public phy_interface_mac @@ -64,7 +64,7 @@ public: void set_agc_enable(bool enabled); void get_metrics(phy_metrics_t &m); - + void srslte_phy_logger(phy_logger_level_t log_level, char *str); static uint32_t tti_to_SFN(uint32_t tti); @@ -76,6 +76,8 @@ public: void write_trace(std::string filename); void set_earfcn(std::vector earfcns); + void force_freq(float dl_freq, float ul_freq); + /********** RRC INTERFACE ********************/ void reset(); @@ -85,6 +87,11 @@ public: void cell_search_stop(); void cell_search_next(); bool cell_select(uint32_t earfcn, srslte_cell_t phy_cell); + bool cell_handover(srslte_cell_t cell); + + void meas_reset(); + int meas_start(uint32_t earfcn, int pci); + int meas_stop(uint32_t earfcn, int pci); /********** MAC INTERFACE ********************/ /* Functions to synchronize with a cell */ @@ -130,7 +137,10 @@ public: float get_pathloss_db(); uint32_t get_current_tti(); - void get_current_cell(srslte_cell_t *cell); + + void get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn = NULL); + uint32_t get_current_earfcn(); + uint32_t get_current_pci(); void start_plot(); @@ -150,6 +160,7 @@ private: srslte::radio_multi *radio_handler; std::vector log_vec; srslte::log *log_h; + srslte::log *log_phy_lib_h; srsue::mac_interface_phy *mac; srsue::rrc_interface_phy *rrc; @@ -167,7 +178,7 @@ private: /* Current time advance */ uint32_t n_ta; - + bool init_(srslte::radio *radio_handler, mac_interface_phy *mac, srslte::log *log_h, bool do_agc, uint32_t nof_workers); void set_default_args(phy_args_t *args); bool check_args(phy_args_t *args); diff --git a/srsue/hdr/phy/prach.h b/srsue/hdr/phy/prach.h index 67ccc0c94..8218ca644 100644 --- a/srsue/hdr/phy/prach.h +++ b/srsue/hdr/phy/prach.h @@ -45,11 +45,11 @@ namespace srsue { args = NULL; config = NULL; - signal_buffer = NULL; transmitted_tti = 0; target_power_dbm = 0; mem_initiated = false; cell_initiated = false; + signal_buffer = NULL; } ~prach(); void init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config, uint32_t max_prb, phy_args_t *args, srslte::log *log_h); diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h index 4e48f6b6d..b008b2fd5 100644 --- a/srsue/hdr/ue.h +++ b/srsue/hdr/ue.h @@ -80,7 +80,6 @@ public: void pregenerate_signals(bool enable); - private: virtual ~ue(); @@ -88,6 +87,7 @@ private: srsue::phy phy; srsue::mac mac; srslte::mac_pcap mac_pcap; + srslte::nas_pcap nas_pcap; srslte::rlc rlc; srslte::pdcp pdcp; srsue::rrc rrc; diff --git a/srsue/hdr/ue_base.h b/srsue/hdr/ue_base.h index 411896f70..0b28dfeb6 100644 --- a/srsue/hdr/ue_base.h +++ b/srsue/hdr/ue_base.h @@ -38,6 +38,7 @@ #include "srslte/radio/radio_multi.h" #include "phy/phy.h" #include "upper/usim.h" +#include "upper/rrc.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/logger.h" @@ -68,6 +69,8 @@ typedef struct { typedef struct { bool enable; std::string filename; + bool nas_enable; + std::string nas_filename; }pcap_args_t; typedef struct { @@ -78,6 +81,7 @@ typedef struct { typedef struct { std::string phy_level; + std::string phy_lib_level; std::string mac_level; std::string rlc_level; std::string pdcp_level; @@ -103,12 +107,12 @@ typedef struct { }gui_args_t; typedef struct { - phy_args_t phy; - float metrics_period_secs; - bool pregenerate_signals; - std::string ue_cateogry; - bool metrics_csv_enable; - std::string metrics_csv_filename; + std::string ip_netmask; + phy_args_t phy; + float metrics_period_secs; + bool pregenerate_signals; + bool metrics_csv_enable; + std::string metrics_csv_filename; }expert_args_t; typedef struct { @@ -119,6 +123,8 @@ typedef struct { log_args_t log; gui_args_t gui; usim_args_t usim; + rrc_args_t rrc; + std::string ue_category_str; expert_args_t expert; }all_args_t; @@ -160,6 +166,10 @@ public: srslte::log_filter rf_log; rf_metrics_t rf_metrics; srslte::LOG_LEVEL_ENUM level(std::string l); + + std::string get_build_mode(); + std::string get_build_info(); + std::string get_build_string(); }; } // namespace srsue diff --git a/srsue/hdr/upper/gw.h b/srsue/hdr/upper/gw.h index 800b31624..b97ceb6c5 100644 --- a/srsue/hdr/upper/gw.h +++ b/srsue/hdr/upper/gw.h @@ -57,8 +57,13 @@ public: // NAS interface srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str); + void set_netmask(std::string netmask); + private: + bool default_netmask; + std::string netmask; + static const int GW_THREAD_PRIO = 7; pdcp_interface_gw *pdcp; diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index e743165fb..6038993e0 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -33,6 +33,7 @@ #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/security.h" #include "srslte/asn1/liblte_mme.h" +#include "srslte/common/nas_pcap.h" using srslte::byte_buffer_t; @@ -57,6 +58,9 @@ static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL", "DEREGISTERED INITIATED", "TRACKING AREA UPDATE INITIATED"}; +static const bool eia_caps[8] = {false, true, true, false, false, false, false, false}; +static const bool eea_caps[8] = {true, true, true, false, false, false, false, false}; + typedef enum { PLMN_NOT_SELECTED = 0, PLMN_SELECTED @@ -80,16 +84,12 @@ public: // RRC interface void notify_connection_setup(); - void write_pdu(uint32_t lcid, byte_buffer_t *pdu); - uint32_t get_ul_count(); - bool is_attached(); bool is_attaching(); - bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi); - + bool get_k_asme(uint8_t *k_asme_, uint32_t n); void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code); void plmn_search_end(); @@ -97,6 +97,9 @@ public: void attach_request(); void deattach_request(); + // PCAP + void start_pcap(srslte::nas_pcap *pcap_); + private: srslte::byte_buffer_pool *pool; srslte::log *nas_log; @@ -115,72 +118,102 @@ private: std::vector known_plmns; - // Save short MAC + LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT emm_info; - // Identifiers - LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti; - bool is_guti_set; + // Security context + struct nas_sec_ctxt{ + uint8_t ksi; + uint8_t k_asme[32]; + uint32_t tx_count; + uint32_t rx_count; + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; + LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti; + }; + + bool have_guti; + bool have_ctxt; + nas_sec_ctxt ctxt; uint32_t ip_addr; uint8_t eps_bearer_id; uint8_t transaction_id; - // NAS counters - incremented for each security-protected message recvd/sent - uint32_t count_ul; - uint32_t count_dl; - // Security - uint8_t ksi; uint8_t k_nas_enc[32]; uint8_t k_nas_int[32]; - srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; - srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; + // PCAP + srslte::nas_pcap *pcap = NULL; void integrity_generate(uint8_t *key_128, uint32_t count, - uint8_t rb_id, uint8_t direction, uint8_t *msg, uint32_t msg_len, uint8_t *mac); + bool integrity_check(byte_buffer_t *pdu); + void cipher_encrypt(byte_buffer_t *pdu); + void cipher_decrypt(byte_buffer_t *pdu); - void integrity_check(); - - void cipher_encrypt(); - - void cipher_decrypt(); + bool check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps); // Parsers void parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu); - void parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu); - void parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu); - void parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu); - void parse_identity_request(uint32_t lcid, byte_buffer_t *pdu); - void parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu); - void parse_service_reject(uint32_t lcid, byte_buffer_t *pdu); - void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu); - void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu); // Senders void send_attach_request(); - void send_identity_response(); - void send_service_request(); - void send_esm_information_response(); - void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg); + void send_security_mode_reject(uint8_t cause); + + // security context persistence file + bool read_ctxt_file(nas_sec_ctxt *ctxt); + bool write_ctxt_file(nas_sec_ctxt ctxt); + + // ctxt file helpers + std::string hex_to_string(uint8_t *hex, int size); + bool string_to_hex(std::string hex_str, uint8_t *hex, uint32_t len); + std::string emm_info_str(LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT *info); + + template + bool readvar(std::istream &file, const char *key, T *var) + { + std::string line; + size_t len = strlen(key); + std::getline(file, line); + if(line.substr(0,len).compare(key)) { + return false; + } + *var = (T)atoi(line.substr(len).c_str()); + return true; + } + + bool readvar(std::istream &file, const char *key, uint8_t *var, int varlen) + { + std::string line; + size_t len = strlen(key); + std::getline(file, line); + if(line.substr(0,len).compare(key)) { + return false; + } + std::string tmp = line.substr(len); + if(!string_to_hex(tmp, var, varlen)) { + return false; + } + return true; + } }; } // namespace srsue diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 3643f76c3..b5df0900a 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -38,15 +38,25 @@ #include "srslte/common/threads.h" #include +#include + +typedef struct { + uint32_t ue_category; + uint32_t feature_group; + uint8_t supported_bands[LIBLTE_RRC_BAND_N_ITEMS]; + uint32_t nof_supported_bands; +}rrc_args_t; using srslte::byte_buffer_t; -namespace srsue { static std::string rb_id_str[] = {"SRB0", "SRB1", "SRB2", - "DRB1","DRB2","DRB3", - "DRB4","DRB5","DRB6", - "DRB7","DRB8"}; + "DRB1","DRB2","DRB3", + "DRB4","DRB5","DRB6", + "DRB7","DRB8"}; + + +namespace srsue { class rrc :public rrc_interface_nas @@ -73,13 +83,54 @@ public: rrc_state_t get_state(); - void set_ue_category(int category); + void set_args(rrc_args_t *args); // Timeout callback interface void timer_expired(uint32_t timeout_id); void liblte_rrc_log(char *str); + + // NAS interface + void write_sdu(uint32_t lcid, byte_buffer_t *sdu); + + uint16_t get_mcc(); + + uint16_t get_mnc(); + + void enable_capabilities(); + void plmn_search(); + void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); + + // PHY interface + void in_sync(); + void out_of_sync(); + void earfcn_end(); + void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp); + void new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn, uint32_t pci); + + // MAC interface + void ho_ra_completed(bool ra_successful); + void release_pucch_srs(); + void run_tti(uint32_t tti); + + void ra_problem(); + + // GW interface + bool is_connected(); + + bool have_drb(); + + // PDCP interface + void write_pdu(uint32_t lcid, byte_buffer_t *pdu); + + void write_pdu_bcch_bch(byte_buffer_t *pdu); + + void write_pdu_bcch_dlsch(byte_buffer_t *pdu); + + void write_pdu_pcch(byte_buffer_t *pdu); + + private: srslte::byte_buffer_pool *pool; srslte::log *rrc_log; @@ -90,7 +141,15 @@ private: nas_interface_rrc *nas; usim_interface_rrc *usim; - srslte::bit_buffer_t bit_buf; + LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; + LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + + byte_buffer_t* byte_align_and_pack(byte_buffer_t *pdu = NULL); + void send_ul_ccch_msg(byte_buffer_t *pdu = NULL); + void send_ul_dcch_msg(byte_buffer_t *pdu = NULL); + srslte::bit_buffer_t bit_buf; pthread_mutex_t mutex; @@ -98,6 +157,16 @@ private: uint8_t transaction_id; bool drb_up; + rrc_args_t args; + bool first_stimsi_attempt; + + uint16_t ho_src_rnti; + int ho_src_cell_idx; + phy_interface_rrc::phy_cfg_t ho_src_phy_cfg; + mac_interface_rrc::mac_cfg_t ho_src_mac_cfg; + bool pending_mob_reconf; + LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT mob_reconf; + // timeouts in ms uint32_t connecting_timeout; @@ -120,15 +189,11 @@ private: std::map srbs; std::map drbs; - LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; - LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; - // RRC constants and timers srslte::mac_interface_timers *mac_timers; uint32_t n310_cnt, N310; uint32_t n311_cnt, N311; - uint32_t t301, t310, t311; - int ue_category; + uint32_t t301, t310, t311, t304; typedef struct { uint32_t earfcn; @@ -136,14 +201,22 @@ private: float rsrp; bool has_valid_sib1; bool has_valid_sib2; + bool has_valid_sib3; + bool has_valid_sib13; bool in_sync; - LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; - LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT sib3; + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT sib13; } cell_t; - std::vector known_cells; + const static int MAX_KNOWN_CELLS = 64; + cell_t known_cells[MAX_KNOWN_CELLS]; cell_t *current_cell; + int find_cell_idx(uint32_t earfcn, uint32_t pci); + cell_t* add_new_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp); + uint32_t find_best_cell(uint32_t earfcn, srslte_cell_t *cell); typedef enum { SI_ACQUIRE_IDLE = 0, @@ -153,8 +226,9 @@ private: si_acquire_state_t si_acquire_state; void run_si_acquisition_procedure(); - uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x); + uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf); uint32_t nof_sib1_trials; + uint16_t sysinfo_index; uint32_t last_win_start; void select_next_cell_in_plmn(); @@ -164,78 +238,134 @@ private: bool thread_running; void run_thread(); - // NAS interface - void write_sdu(uint32_t lcid, byte_buffer_t *sdu); + // Measurements sub-class + class rrc_meas { + public: + void init(rrc *parent); + void reset(); + void parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *meas_config); + void new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, float rsrq, uint32_t tti); + void run_tti(uint32_t tti); + bool timer_expired(uint32_t timer_id); + void ho_finish(); + private: - uint16_t get_mcc(); + const static int NOF_MEASUREMENTS = 3; - uint16_t get_mnc(); + typedef enum {RSRP = 0, RSRQ = 1, BOTH = 2} quantity_t; - void enable_capabilities(); - void plmn_search(); - void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); + typedef struct { + uint32_t pci; + float q_offset; + } meas_cell_t; - // PHY interface - void in_sync(); - void out_of_sync(); - void earfcn_end(); - void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp); + typedef struct { + uint32_t earfcn; + float q_offset; + std::map cells; + } meas_obj_t; - // MAC interface - void release_pucch_srs(); + typedef struct { + uint32_t interval; + uint32_t max_cell; + uint32_t amount; + quantity_t trigger_quantity; + quantity_t report_quantity; + LIBLTE_RRC_EVENT_EUTRA_STRUCT event; + enum {EVENT, PERIODIC} trigger_type; + } report_cfg_t; - void ra_problem(); + typedef struct { + float ms[NOF_MEASUREMENTS]; + bool triggered; + bool timer_enter_triggered; + bool timer_exit_triggered; + uint32_t enter_tti; + uint32_t exit_tti; + } meas_value_t; - // GW interface - bool is_connected(); + typedef struct { + uint32_t nof_reports_sent; + uint32_t report_id; + uint32_t object_id; + bool triggered; + uint32_t periodic_timer; + std::map cell_values; // Value for each PCI in this object + } meas_t; - bool have_drb(); + std::map objects; + std::map reports_cfg; + std::map active; - // PDCP interface - void write_pdu(uint32_t lcid, byte_buffer_t *pdu); + rrc *parent; + srslte::log *log_h; + phy_interface_rrc *phy; + srslte::mac_interface_timers *mac_timers; - void write_pdu_bcch_bch(byte_buffer_t *pdu); + uint32_t filter_k_rsrp, filter_k_rsrq; + float filter_a[NOF_MEASUREMENTS]; - void write_pdu_bcch_dlsch(byte_buffer_t *pdu); + meas_value_t pcell_measurement; - void write_pdu_pcch(byte_buffer_t *pdu); + bool s_measure_enabled; + float s_measure_value; - // Radio bearers - typedef enum{ - RB_ID_SRB0 = 0, - RB_ID_SRB1, - RB_ID_SRB2, - RB_ID_DRB1, - RB_ID_DRB2, - RB_ID_DRB3, - RB_ID_DRB4, - RB_ID_DRB5, - RB_ID_DRB6, - RB_ID_DRB7, - RB_ID_DRB8, - RB_ID_MAX - } rb_id_t; + void stop_reports(meas_t *m); + void stop_reports_object(uint32_t object_id); + void remove_meas_object(uint32_t object_id); + void remove_meas_report(uint32_t report_id); + void remove_meas_id(uint32_t measId); + void remove_meas_id(std::map::iterator it); + void calculate_triggers(uint32_t tti); + void update_phy(); + void L3_filter(meas_value_t *value, float rsrp[NOF_MEASUREMENTS]); + bool find_earfcn_cell(uint32_t earfcn, uint32_t pci, meas_obj_t **object, int *cell_idx); + float range_to_value(quantity_t quant, uint8_t range); + uint8_t value_to_range(quantity_t quant, float value); + bool process_event(LIBLTE_RRC_EVENT_EUTRA_STRUCT *event, uint32_t tti, + bool enter_condition, bool exit_condition, + meas_t *m, meas_value_t *cell); - std::string get_rb_name(uint32_t lcid) { - if (lcid < RB_ID_MAX) { - return rb_id_str[lcid]; - } else { - return std::string("INVALID_RB"); - } - } + void generate_report(uint32_t meas_id); + }; + + rrc_meas measurements; + + + // Cell selection/reselection functions/variables + typedef struct { + float Qrxlevmin; + float Qrxlevminoffset; + float Qqualmin; + float Qqualminoffset; + float s_intrasearchP; + float q_hyst; + float threshservinglow; + + } cell_resel_cfg_t; + + cell_resel_cfg_t cell_resel_cfg; + + float get_srxlev(float Qrxlevmeas); + float get_squal(float Qqualmeas); + void cell_reselection_eval(float rsrp, float rsrq); + bool cell_selection_eval(float rsrp, float rsrq = 0); + + bool connection_requested; + void plmn_select_rrc(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); // RLC interface void max_retx_attempted(); // Senders void send_con_request(); - void send_con_restablish_request(); + void send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause, uint16_t crnti); void send_con_restablish_complete(); void send_con_setup_complete(byte_buffer_t *nas_msg); void send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu); void send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu); - void send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu); - void send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu); + void send_rrc_con_reconfig_complete(byte_buffer_t *pdu); + void send_rrc_ue_cap_info(byte_buffer_t *pdu); // Parsers void parse_dl_ccch(byte_buffer_t *pdu); @@ -243,10 +373,22 @@ private: void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu); // Helpers + void ho_failed(); + bool ho_prepare(); + void add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp); void rrc_connection_release(); - void radio_link_failure(); + void con_restablish_cell_reselected(); + void radio_link_failure(); + static void* start_sib_thread(void *rrc_); void sib_search(); + void apply_rr_config_common_dl(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config); + void apply_rr_config_common_ul(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config); + void handle_sib1(); + void handle_sib2(); + void handle_sib3(); + void handle_sib13(); + void apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2); void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup); void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup); @@ -264,7 +406,6 @@ private: void set_mac_default(); void set_rrc_default(); void set_bearers(); - }; } // namespace srsue diff --git a/srsue/hdr/upper/rrc_common.h b/srsue/hdr/upper/rrc_common.h index 95b909620..6d1186812 100644 --- a/srsue/hdr/upper/rrc_common.h +++ b/srsue/hdr/upper/rrc_common.h @@ -38,6 +38,8 @@ typedef enum { RRC_STATE_CELL_SELECTED, RRC_STATE_CONNECTING, RRC_STATE_CONNECTED, + RRC_STATE_HO_PREPARE, + RRC_STATE_HO_PROCESS, RRC_STATE_LEAVE_CONNECTED, RRC_STATE_N_ITEMS, } rrc_state_t; diff --git a/srsue/hdr/upper/usim.h b/srsue/hdr/upper/usim.h index fea15ba68..cf5a4c820 100644 --- a/srsue/hdr/upper/usim.h +++ b/srsue/hdr/upper/usim.h @@ -1,4 +1,4 @@ -/** +/** * * \section COPYRIGHT * @@ -59,24 +59,30 @@ public: void stop(); // NAS interface - void get_imsi_vec(uint8_t* imsi_, uint32_t n); - void get_imei_vec(uint8_t* imei_, uint32_t n); - int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id); + std::string get_imsi_str(); + std::string get_imei_str(); + + bool get_imsi_vec(uint8_t* imsi_, uint32_t n); + bool get_imei_vec(uint8_t* imei_, uint32_t n); + bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id); void generate_authentication_response(uint8_t *rand, uint8_t *autn_enb, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res); + uint8_t *res, + uint8_t *k_asme); - void generate_nas_keys(uint8_t *k_nas_enc, + void generate_nas_keys(uint8_t *k_asme, + uint8_t *k_nas_enc, uint8_t *k_nas_int, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); // RRC interface - void generate_as_keys(uint32_t count_ul, + void generate_as_keys(uint8_t *k_asme, + uint32_t count_ul, uint8_t *k_rrc_enc, uint8_t *k_rrc_int, uint8_t *k_up_enc, @@ -84,6 +90,16 @@ public: srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + void generate_as_keys_ho(uint32_t pci, + uint32_t earfcn, + int ncc, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); + private: void gen_auth_res_milenage( uint8_t *rand, @@ -91,13 +107,15 @@ private: uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res); + uint8_t *res, + uint8_t *k_asme); void gen_auth_res_xor( uint8_t *rand, uint8_t *autn_enb, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res); + uint8_t *res, + uint8_t *k_asme); void str_to_hex(std::string str, uint8_t *hex); srslte::log *usim_log; @@ -110,6 +128,9 @@ private: uint64_t imei; uint8_t k[16]; + std::string imsi_str; + std::string imei_str; + // Security variables uint8_t rand[16]; uint8_t ck[16]; @@ -118,7 +139,11 @@ private: uint8_t mac[8]; uint8_t autn[16]; uint8_t k_asme[32]; + uint8_t nh[32]; uint8_t k_enb[32]; + uint8_t k_enb_star[32]; + + uint32_t current_ncc; bool initiated; diff --git a/srsue/src/mac/demux.cc b/srsue/src/mac/demux.cc index 75bafd1b4..71be1ffc1 100644 --- a/srsue/src/mac/demux.cc +++ b/srsue/src/mac/demux.cc @@ -25,10 +25,10 @@ */ -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #include "mac/mac.h" #include "mac/demux.h" @@ -36,7 +36,7 @@ namespace srsue { -demux::demux(uint8_t nof_harq_proc_) : mac_msg(20), pending_mac_msg(20), nof_harq_proc(nof_harq_proc_) +demux::demux() : mac_msg(20), pending_mac_msg(20), rlc(NULL) { } @@ -64,18 +64,18 @@ void demux::deallocate(uint8_t* payload_buffer_ptr) pdus.deallocate(payload_buffer_ptr); } } - -uint8_t* demux::request_buffer(uint32_t pid, uint32_t len) -{ - uint8_t *buff = NULL; - if (pid < nof_harq_proc) { - return pdus.request(len); - } else if (pid == nof_harq_proc) { - buff = bcch_buffer; +uint8_t* demux::request_buffer_bcch(uint32_t len) +{ + if (len < MAX_BCCH_PDU_LEN) { + return bcch_buffer; } else { - Error("Requested buffer for invalid PID=%d\n", pid); + return NULL; } - return buff; +} + +uint8_t* demux::request_buffer(uint32_t len) +{ + return pdus.request(len); } /* Demultiplexing of MAC PDU associated with a Temporal C-RNTI. The PDU will @@ -117,21 +117,17 @@ void demux::push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes) * This function enqueues the packet and returns quicly because ACK * deadline is important here. */ -void demux::push_pdu(uint32_t pid, uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) -{ - if (pid < nof_harq_proc) { - return pdus.push(buff, nof_bytes, tstamp); - } else if (pid == nof_harq_proc) { - /* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through - * the MAC in transparent mode. - * Warning: In this case function sends the message to RLC now, since SI blocks do not - * require ACK feedback to be transmitted quickly. - */ - Debug("Pushed BCCH MAC PDU in transparent mode\n"); - rlc->write_pdu_bcch_dlsch(buff, nof_bytes); - } else { - Error("Pushed buffer for invalid PID=%d\n", pid); - } +void demux::push_pdu(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) { + return pdus.push(buff, nof_bytes, tstamp); +} + +/* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through +* the MAC in transparent mode. +* Warning: In this case function sends the message to RLC now, since SI blocks do not +* require ACK feedback to be transmitted quickly. +*/ +void demux::push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) { + rlc->write_pdu_bcch_dlsch(buff, nof_bytes); } bool demux::process_pdus() diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index b54ea5be6..daa82d1cb 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -24,10 +24,10 @@ * */ -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #include #include @@ -44,7 +44,6 @@ namespace srsue { mac::mac() : ttisync(10240), timers(64), mux_unit(MAC_NOF_HARQ_PROC), - demux_unit(SRSLTE_MAX_TB*MAC_NOF_HARQ_PROC), pdu_process_thread(&demux_unit) { started = false; @@ -111,6 +110,15 @@ void mac::reconfiguration() } +void mac::wait_uplink() { + int cnt=0; + Info("Waiting to uplink...\n"); + while(mux_unit.is_pending_any_sdu() && cnt<20) { + usleep(1000); + cnt++; + } +} + // Implement Section 5.9 void mac::reset() { @@ -118,7 +126,8 @@ void mac::reset() Info("Resetting MAC\n"); - timers.stop_all(); + timers.get(timer_alignment)->stop(); + timers.get(contention_resolution_timer)->stop(); ul_harq.reset_ndi(); @@ -153,8 +162,7 @@ void mac::run_thread() { while(started) { /* Warning: Here order of invocation of procedures is important!! */ - ttisync.wait(); - tti = phy_h->get_current_tti(); + tti = ttisync.wait(); log_h->step(tti); timers.step_all(); @@ -180,6 +188,8 @@ void mac::run_thread() { ra_procedure.start_mac_order(); } ra_procedure.step(tti); + + rrc_h->run_tti(tti); } } @@ -218,7 +228,7 @@ void mac::pcch_stop_rx() void mac::tti_clock(uint32_t tti) { - ttisync.increase(); + ttisync.increase(tti); } void mac::bch_decoded_ok(uint8_t* payload, uint32_t len) @@ -268,6 +278,7 @@ void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); action->generate_ack = false; action->decode_enabled[0] = true; + action->decode_enabled[1] = false; srslte_softbuffer_rx_reset_cb(&pch_softbuffer, 1); action->payload_ptr[0] = pch_payload_buffer; action->softbuffers[0] = &pch_softbuffer; @@ -308,7 +319,7 @@ void mac::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: void mac::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t* action) { int tbs = ul_harq.get_current_tbs(tti); - ul_harq.new_grant_ul_ack(grant, ack, action); + ul_harq.new_grant_ul_ack(grant, &ack, action); if (!ack) { metrics.tx_errors++; } else { @@ -369,11 +380,30 @@ void mac::get_rntis(ue_rnti_t* rntis) memcpy(rntis, &uernti, sizeof(ue_rnti_t)); } +void mac::set_ho_rnti(uint16_t crnti, uint16_t target_pci) { + phy_h->pdcch_dl_search_reset(); + phy_h->pdcch_ul_search_reset(); + uernti.crnti = crnti; + if (pcap) { + pcap->set_ue_id(target_pci); + } +} + void mac::set_contention_id(uint64_t uecri) { uernti.contention_id = uecri; } +void mac::start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask) +{ + ra_procedure.start_noncont(preamble_index, prach_mask); +} + +void mac::start_cont_ho() +{ + ra_procedure.start_mac_order(56, true); +} + void mac::get_config(mac_cfg_t* mac_cfg) { memcpy(mac_cfg, &config, sizeof(mac_cfg_t)); @@ -417,7 +447,7 @@ void mac::get_metrics(mac_metrics_t &m) metrics.rx_pkts?((float) 100*metrics.rx_errors/metrics.rx_pkts):0.0, dl_harq.get_average_retx(), metrics.tx_pkts?((float) 100*metrics.tx_errors/metrics.tx_pkts):0.0, - dl_harq.get_average_retx()); + ul_harq.get_average_retx()); metrics.ul_buffer = (int) bsr_procedure.get_buffer_state(); m = metrics; diff --git a/srsue/src/mac/mux.cc b/srsue/src/mac/mux.cc index 5ab58fb50..ba2b45209 100644 --- a/srsue/src/mac/mux.cc +++ b/srsue/src/mac/mux.cc @@ -24,10 +24,10 @@ * */ -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #include "mac/mux.h" #include "mac/mac.h" @@ -62,7 +62,9 @@ void mux::init(rlc_interface_mac *rlc_, srslte::log *log_h_, bsr_interface_mux * void mux::reset() { - lch.clear(); + for (uint32_t i=0;iset_c_rnti(pending_crnti_ce)) { Warning("Pending C-RNTI CE could not be inserted in MAC PDU\n"); } } } + } else { + is_rar = true; } pending_crnti_ce = 0; @@ -200,44 +207,44 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32 } } - // Update buffer states for all logical channels - int sdu_space = pdu_msg.get_sdu_space(); - for (uint32_t i=0;iget_buffer_state(lch[i].id); - lch[i].sched_len = 0; - } - - // data from any Logical Channel, except data from UL-CCCH; - // first only those with positive Bj - for (uint32_t i=0;i= 0) { - lch[i].Bj -= lch[i].sched_len; - } + if (!is_rar) { + // Update buffer states for all logical channels + int sdu_space = pdu_msg.get_sdu_space(); + for (uint32_t i=0;iget_buffer_state(lch[i].id); + lch[i].sched_len = 0; } - } - // If resources remain, allocate regardless of their Bj value - for (uint32_t i=0;i 0) { - for (int i=(int)lch.size()-1;i>=0;i--) { - if (lch[i].sched_len > 0) { - lch[i].sched_len = -1; - break; + // data from any Logical Channel, except data from UL-CCCH; + // first only those with positive Bj + for (uint32_t i=0;i= 0) { + lch[i].Bj -= lch[i].sched_len; + } } } - } - // Now allocate the SDUs from the RLC - for (uint32_t i=0;iinfo("Allocating scheduled lch=%d len=%d\n", lch[i].id, lch[i].sched_len); - allocate_sdu(lch[i].id, &pdu_msg, lch[i].sched_len); + + // If resources remain, allocate regardless of their Bj value + for (uint32_t i=0;i 0) { + for (int i=(int)lch.size()-1;i>=0;i--) { + if (lch[i].sched_len > 0) { + lch[i].sched_len = -1; + break; + } + } + } + for (uint32_t i=0;iinfo("SDU: scheduled lcid=%d, rlc_buffer=%d, allocated=%d/%d\n", - ch->id, ch->buffer_len, sched_len, *sdu_space); + log_h->debug("SDU: scheduled lcid=%d, rlc_buffer=%d, allocated=%d/%d\n", + ch->id, ch->buffer_len, sched_len, sdu_space?*sdu_space:0); *sdu_space -= sched_len; ch->buffer_len -= sched_len; @@ -309,16 +316,15 @@ bool mux::allocate_sdu(uint32_t lcid, srslte::sch_pdu* pdu_msg, int max_sdu_sz) sdu_len = max_sdu_sz; } int sdu_space = pdu_msg->get_sdu_space(); - if (sdu_len > sdu_space) { + if (sdu_len > sdu_space || max_sdu_sz < 0) { sdu_len = sdu_space; - } + } if (sdu_len > MIN_RLC_SDU_LEN) { if (pdu_msg->new_subh()) { // there is space for a new subheader - int sdu_len2 = sdu_len; sdu_len = pdu_msg->get()->set_sdu(lcid, sdu_len, rlc); if (sdu_len > 0) { // new SDU could be added - Info("SDU: allocated lcid=%d, rlc_buffer=%d, allocated=%d/%d, max_sdu_sz=%d, remaining=%d\n", + Debug("SDU: allocated lcid=%d, rlc_buffer=%d, allocated=%d/%d, max_sdu_sz=%d, remaining=%d\n", lcid, buffer_state, sdu_len, sdu_space, max_sdu_sz, pdu_msg->rem_size()); return true; } else { @@ -349,14 +355,19 @@ bool mux::msg3_is_transmitted() /* Returns a pointer to the Msg3 buffer */ uint8_t* mux::msg3_get(uint8_t *payload, uint32_t pdu_sz) { - uint8_t* msg3_buff_start_pdu = pdu_get(msg3_buff, pdu_sz, 0, 0); - if (!msg3_buff_start_pdu) { - Error("Moving PDU from Mux unit to Msg3 buffer\n"); + if (pdu_sz < MSG3_BUFF_SZ - 32) { + uint8_t* msg3_buff_start_pdu = pdu_get(msg3_buff, pdu_sz, 0, 0); + if (!msg3_buff_start_pdu) { + Error("Moving PDU from Mux unit to Msg3 buffer\n"); + return NULL; + } + memcpy(payload, msg3_buff_start_pdu, sizeof(uint8_t)*pdu_sz); + msg3_has_been_transmitted = true; + return payload; + } else { + Error("Msg3 size (%d) is longer than internal msg3_buff size=%d, (see mux.h)\n", pdu_sz, MSG3_BUFF_SZ-32); return NULL; - } - memcpy(payload, msg3_buff_start_pdu, sizeof(uint8_t)*pdu_sz); - msg3_has_been_transmitted = true; - return payload; + } } diff --git a/srsue/src/mac/proc_bsr.cc b/srsue/src/mac/proc_bsr.cc index 898943ab9..f68b6eee8 100644 --- a/srsue/src/mac/proc_bsr.cc +++ b/srsue/src/mac/proc_bsr.cc @@ -24,10 +24,10 @@ * */ -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #include "mac/proc_bsr.h" #include "mac/mac.h" @@ -368,7 +368,7 @@ bool bsr_proc::need_to_reset_sr() { bool bsr_proc::need_to_send_sr(uint32_t tti) { if (!sr_is_sent && triggered_bsr_type == REGULAR) { - if (srslte_tti_interval(tti,next_tx_tti)>0 && srslte_tti_interval(tti,next_tx_tti) < 10240-4) { + if (srslte_tti_interval(tti,next_tx_tti)>0 && srslte_tti_interval(tti,next_tx_tti) < 10240-HARQ_DELAY_MS) { reset_sr = false; sr_is_sent = true; Debug("BSR: Need to send sr: sr_is_sent=true, reset_sr=false, tti=%d, next_tx_tti=%d\n", tti, next_tx_tti); diff --git a/srsue/src/mac/proc_phr.cc b/srsue/src/mac/proc_phr.cc index ead0bf153..54c1ec1ce 100644 --- a/srsue/src/mac/proc_phr.cc +++ b/srsue/src/mac/proc_phr.cc @@ -24,10 +24,10 @@ * */ -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #include "mac/proc_phr.h" #include "mac/mac.h" diff --git a/srsue/src/mac/proc_ra.cc b/srsue/src/mac/proc_ra.cc index 4bceef2a5..d9a3e0d4d 100644 --- a/srsue/src/mac/proc_ra.cc +++ b/srsue/src/mac/proc_ra.cc @@ -24,10 +24,10 @@ * */ -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #include #include @@ -96,9 +96,15 @@ void ra_proc::read_params() { // Read initialization parameters configIndex = mac_cfg->prach_config_index; - preambleIndex = 0; // pass when called from higher layers for non-contention based RA - maskIndex = 0; // same - nof_preambles = liblte_rrc_number_of_ra_preambles_num[mac_cfg->rach.num_ra_preambles]; + if (noncontention_enabled) { + preambleIndex = next_preamble_idx; + maskIndex = next_prach_mask; + noncontention_enabled = false; + } else { + preambleIndex = 0; // pass when called from higher layers for non-contention based RA + maskIndex = 0; // same + } + nof_preambles = liblte_rrc_number_of_ra_preambles_num[mac_cfg->rach.num_ra_preambles]; if (mac_cfg->rach.preambles_group_a_cnfg.present) { nof_groupA_preambles = liblte_rrc_size_of_ra_preambles_group_a_num[mac_cfg->rach.preambles_group_a_cnfg.size_of_ra]; } else { @@ -386,13 +392,16 @@ void ra_proc::step_response_reception() { } } -void ra_proc::step_response_error() { - +void ra_proc::step_response_error() +{ preambleTransmissionCounter++; if (preambleTransmissionCounter >= preambleTransMax + 1) { rError("Maximum number of transmissions reached (%d)\n", preambleTransMax); rrc->ra_problem(); state = RA_PROBLEM; + if (ra_is_ho) { + rrc->ho_ra_completed(false); + } } else { backoff_interval_start = phy_h->get_current_tti(); if (backoff_param_ms) { @@ -495,8 +504,11 @@ void ra_proc::step_completition() { phy_h->set_crnti(rntis->crnti); - msg3_transmitted = false; + msg3_transmitted = false; state = COMPLETION_DONE; + if (ra_is_ho) { + rrc->ho_ra_completed(true); + } } void ra_proc::step(uint32_t tti_) @@ -536,9 +548,17 @@ void ra_proc::step(uint32_t tti_) } } -void ra_proc::start_mac_order(uint32_t msg_len_bits) +void ra_proc::start_noncont(uint32_t preamble_index, uint32_t prach_mask) { + next_preamble_idx = preamble_index; + next_prach_mask = prach_mask; + noncontention_enabled = true; + start_mac_order(56, true); +} + +void ra_proc::start_mac_order(uint32_t msg_len_bits, bool is_ho) { if (state == IDLE || state == COMPLETION_DONE || state == RA_PROBLEM) { + ra_is_ho = is_ho; started_by_pdcch = false; new_ra_msg_len = msg_len_bits; state = INITIALIZATION; diff --git a/srsue/src/mac/proc_sr.cc b/srsue/src/mac/proc_sr.cc index afd2b7b5a..cb31a1c6d 100644 --- a/srsue/src/mac/proc_sr.cc +++ b/srsue/src/mac/proc_sr.cc @@ -24,10 +24,10 @@ * */ -#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #include "mac/proc_sr.h" diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 569083998..aae389f70 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -37,6 +37,7 @@ #include #include "ue.h" +#include "srslte/srslte.h" #include "metrics_stdout.h" #include "metrics_csv.h" #include "srslte/common/metrics_hub.h" @@ -65,6 +66,8 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { common.add_options() ("rf.dl_earfcn", bpo::value(&args->rf.dl_earfcn)->default_value(3400), "Downlink EARFCN") ("rf.freq_offset", bpo::value(&args->rf.freq_offset)->default_value(0), "(optional) Frequency offset") + ("rf.dl_freq", bpo::value(&args->rf.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)") + ("rf.ul_freq", bpo::value(&args->rf.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)") ("rf.rx_gain", bpo::value(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain") ("rf.tx_gain", bpo::value(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain") ("rf.nof_rx_ant", bpo::value(&args->rf.nof_rx_ant)->default_value(1), "Number of RX antennas") @@ -73,12 +76,18 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { ("rf.device_args", bpo::value(&args->rf.device_args)->default_value("auto"), "Front-end device arguments") ("rf.time_adv_nsamples", bpo::value(&args->rf.time_adv_nsamples)->default_value("auto"), "Transmission time advance") - ("rf.burst_preamble_us", bpo::value(&args->rf.burst_preamble)->default_value("auto"), - "Transmission time advance") + ("rf.burst_preamble_us", bpo::value(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance") - ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), - "Enable MAC packet captures for wireshark") + ("rrc.feature_group", bpo::value(&args->rrc.feature_group)->default_value(0xe6041c00), "Hex value of the featureGroupIndicators field in the" + "UECapabilityInformation message. Default 0xe6041c00") + ("rrc.ue_category", bpo::value(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)") + + + ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") ("pcap.filename", bpo::value(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") + ("pcap.nas_enable", bpo::value(&args->pcap.nas_enable)->default_value(false), "Enable NAS packet captures for wireshark") + ("pcap.nas_filename", bpo::value(&args->pcap.nas_filename)->default_value("ue_nas.pcap"), "NAS layer capture filename (useful when NAS encryption is enabled)") + ("trace.enable", bpo::value(&args->trace.enable)->default_value(false), "Enable PHY and radio timing traces") ("trace.phy_filename", bpo::value(&args->trace.phy_filename)->default_value("ue.phy_trace"), @@ -89,6 +98,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { ("gui.enable", bpo::value(&args->gui.enable)->default_value(false), "Enable GUI plots") ("log.phy_level", bpo::value(&args->log.phy_level), "PHY log level") + ("log.phy_lib_level", bpo::value(&args->log.phy_lib_level), "PHY lib log level") ("log.phy_hex_limit", bpo::value(&args->log.phy_hex_limit), "PHY log hex dump limit") ("log.mac_level", bpo::value(&args->log.mac_level), "MAC log level") ("log.mac_hex_limit", bpo::value(&args->log.mac_hex_limit), "MAC log hex dump limit") @@ -120,6 +130,10 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { /* Expert section */ + ("expert.ip_netmask", + bpo::value(&args->expert.ip_netmask)->default_value("255.255.255.0"), + "Netmask of the tun_srsue device") + ("expert.phy.worker_cpu_mask", bpo::value(&args->expert.phy.worker_cpu_mask)->default_value(-1), "cpu bit mask (eg 255 = 1111 1111)") @@ -128,10 +142,6 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { bpo::value(&args->expert.phy.sync_cpu_affinity)->default_value(-1), "index of the core used by the sync thread") - ("expert.ue_category", - bpo::value(&args->expert.ue_cateogry)->default_value("4"), - "UE Category (1 to 5)") - ("expert.metrics_period_secs", bpo::value(&args->expert.metrics_period_secs)->default_value(1.0), "Periodicity for metrics in seconds") @@ -193,8 +203,51 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { "Enables integer CFO estimation and correction.") ("expert.cfo_correct_tol_hz", - bpo::value(&args->expert.phy.cfo_correct_tol_hz)->default_value(50.0), - "Tolerance (in Hz) for digial CFO compensation.") + bpo::value(&args->expert.phy.cfo_correct_tol_hz)->default_value(1.0), + "Tolerance (in Hz) for digital CFO compensation (needs to be low if average_subframe_enabled=true.") + + ("expert.cfo_pss_ema", + bpo::value(&args->expert.phy.cfo_pss_ema)->default_value(DEFAULT_CFO_EMA_TRACK), + "CFO Exponential Moving Average coefficient for PSS estimation during TRACK.") + + /* REF EMA is currently not used + ("expert.cfo_ref_ema", + bpo::value(&args->expert.phy.cfo_ref_ema)->default_value(0.01), + "CFO Exponential Moving Average coefficient for RS estimation after PSS acquisition") + */ + + ("expert.cfo_ref_mask", + bpo::value(&args->expert.phy.cfo_ref_mask)->default_value(1023), + "Bitmask for subframes on which to run RS estimation (set to 0 to disable, default all sf)") + + ("expert.cfo_loop_bw_pss", + bpo::value(&args->expert.phy.cfo_loop_bw_pss)->default_value(DEFAULT_CFO_BW_PSS), + "CFO feedback loop bandwidth for samples from PSS") + + ("expert.cfo_loop_bw_ref", + bpo::value(&args->expert.phy.cfo_loop_bw_ref)->default_value(DEFAULT_CFO_BW_REF), + "CFO feedback loop bandwidth for samples from RS") + + ("expert.cfo_loop_pss_tol", + bpo::value(&args->expert.phy.cfo_loop_pss_tol)->default_value(DEFAULT_CFO_PSS_MIN), + "Tolerance (in Hz) of the PSS estimation method. Below this value, PSS estimation does not feeds back the loop" + "and RS estimations are used instead (when available)") + + ("expert.cfo_loop_ref_min", + bpo::value(&args->expert.phy.cfo_loop_ref_min)->default_value(DEFAULT_CFO_REF_MIN), + "Tolerance (in Hz) of the RS estimation method. Below this value, RS estimation does not feeds back the loop") + + ("expert.cfo_loop_pss_conv", + bpo::value(&args->expert.phy.cfo_loop_pss_conv)->default_value(DEFAULT_PSS_STABLE_TIMEOUT), + "After the PSS estimation is below cfo_loop_pss_tol for cfo_loop_pss_timeout times consecutively, RS adjustments are allowed.") + + ("expert.sic_pss_enabled", + bpo::value(&args->expert.phy.sic_pss_enabled)->default_value(true), + "Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells. Must be disabled if cells have identical channel and timing.") + + ("expert.average_subframe_enabled", + bpo::value(&args->expert.phy.average_subframe_enabled)->default_value(false), + "Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.") ("expert.time_correct_period", bpo::value(&args->expert.phy.time_correct_period)->default_value(5), @@ -275,6 +328,9 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { if (!vm.count("log.phy_level")) { args->log.phy_level = args->log.all_level; } + if (!vm.count("log.phy_lib_level")) { + args->log.phy_lib_level = args->log.all_level; + } if (!vm.count("log.mac_level")) { args->log.mac_level = args->log.all_level; } @@ -328,12 +384,18 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { } } +static int sigcnt = 0; static bool running = true; static bool do_metrics = false; metrics_stdout metrics_screen; void sig_int_handler(int signo) { + sigcnt++; running = false; + printf("Stopping srsUE... Press Ctrl+C %d more times to force stop\n", 10-sigcnt); + if (sigcnt >= 10) { + exit(-1); + } } void *input_loop(void *m) { @@ -358,6 +420,9 @@ int main(int argc, char *argv[]) srslte::metrics_hub metricshub; signal(SIGINT, sig_int_handler); all_args_t args; + + srslte_debug_handle_crash(argc, argv); + parse_args(&args, argc, argv); srsue_instance_type_t type = LTE; @@ -375,11 +440,13 @@ int main(int argc, char *argv[]) metricshub.init(ue, args.expert.metrics_period_secs); metricshub.add_listener(&metrics_screen); metrics_screen.set_ue_handle(ue); + metrics_screen.set_periodicity(args.expert.metrics_period_secs); metrics_csv metrics_file(args.expert.metrics_csv_filename); if (args.expert.metrics_csv_enable) { metricshub.add_listener(&metrics_file); metrics_file.set_ue_handle(ue); + metrics_file.set_periodicity(args.expert.metrics_period_secs); } pthread_t input; @@ -387,6 +454,7 @@ int main(int argc, char *argv[]) bool plot_started = false; bool signals_pregenerated = false; + while (running) { if (ue->is_attached()) { if (!signals_pregenerated && args.expert.pregenerate_signals) { diff --git a/srsue/src/metrics_csv.cc b/srsue/src/metrics_csv.cc index f9bdce213..7c84659b5 100644 --- a/srsue/src/metrics_csv.cc +++ b/srsue/src/metrics_csv.cc @@ -43,6 +43,7 @@ namespace srsue{ metrics_csv::metrics_csv(std::string filename) :n_reports(0) + ,metrics_report_period(1.0) ,ue(NULL) { file.open(filename.c_str()); @@ -53,7 +54,11 @@ void metrics_csv::set_ue_handle(ue_metrics_interface *ue_) ue = ue_; } -void metrics_csv::set_metrics(ue_metrics_t &metrics, float metrics_report_period) +void metrics_csv::set_periodicity(float metrics_report_period_sec) { + this->metrics_report_period = metrics_report_period_sec; +} + +void metrics_csv::set_metrics(ue_metrics_t &metrics) { if (file.is_open() && ue != NULL) { if(n_reports == 0) { @@ -75,7 +80,7 @@ void metrics_csv::set_metrics(ue_metrics_t &metrics, float metrics_report_period file << float_to_string(metrics.phy.ul.mcs, 2); file << float_to_string((float) metrics.mac.ul_buffer, 2); file << float_to_string((float) metrics.mac.tx_brate/metrics_report_period, 2); - if (metrics.mac.tx_pkts > 0) { + if (metrics.mac.tx_pkts > 0) { file << float_to_string((float) 100*metrics.mac.tx_errors/metrics.mac.tx_pkts, 1); } else { file << float_to_string(0, 2); diff --git a/srsue/src/metrics_stdout.cc b/srsue/src/metrics_stdout.cc index 048532c8f..9f413b65f 100644 --- a/srsue/src/metrics_stdout.cc +++ b/srsue/src/metrics_stdout.cc @@ -50,6 +50,7 @@ char const * const prefixes[2][9] = metrics_stdout::metrics_stdout() :do_print(false) ,n_reports(10) + ,metrics_report_period(1.0) ,ue(NULL) { } @@ -64,8 +65,11 @@ void metrics_stdout::toggle_print(bool b) do_print = b; } +void metrics_stdout::set_periodicity(float metrics_report_period_sec) { + this->metrics_report_period = metrics_report_period_sec; +} -void metrics_stdout::set_metrics(ue_metrics_t &metrics, float metrics_report_period) +void metrics_stdout::set_metrics(ue_metrics_t &metrics) { if(!do_print || ue == NULL) return; diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc index d49b1ced2..b9138100b 100644 --- a/srsue/src/phy/phch_common.cc +++ b/srsue/src/phy/phch_common.cc @@ -29,10 +29,10 @@ #include "srslte/srslte.h" #include "phy/phch_common.h" -#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) namespace srsue { @@ -47,24 +47,7 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) mac = NULL; max_mutex = max_mutex_; nof_mutex = 0; - sr_enabled = false; - is_first_of_burst = true; - is_first_tx = true; - rar_grant_pending = false; - pathloss = 0; - cur_pathloss = 0; - cur_pusch_power = 0; - p0_preamble = 0; - cur_radio_power = 0; - rx_gain_offset = 0; - sr_last_tx_tti = -1; - cur_pusch_power = 0; - bzero(zeros, 50000*sizeof(cf_t)); - // FIXME: This is an ungly fix to avoid the TX filters to empty - for (int i=0;i<50000;i++) { - zeros[i] = 0.01*cexpf(((float) i/50000)*0.1*_Complex_I); - } bzero(&dl_metrics, sizeof(dl_metrics_t)); dl_metrics_read = true; dl_metrics_count = 0; @@ -74,6 +57,16 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) bzero(&sync_metrics, sizeof(sync_metrics_t)); sync_metrics_read = true; sync_metrics_count = 0; + + bzero(zeros, 50000*sizeof(cf_t)); + + // FIXME: This is an ugly fix to avoid the TX filters to empty + for (int i=0;i<50000;i++) { + zeros[i] = 0.01*cexpf(((float) i/50000)*0.1*_Complex_I); + } + + reset(); + } void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, rrc_interface_phy *_rrc, mac_interface_phy *_mac) @@ -136,12 +129,14 @@ srslte::radio* phch_common::get_radio() void phch_common::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]) { srslte_dci_rar_grant_unpack(&rar_grant, grant_payload); - rar_grant_pending = true; - // PUSCH is at n+6 or n+7 and phch_worker assumes default delay of 4 ttis + rar_grant_pending = true; + if (MSG3_DELAY_MS < 0) { + fprintf(stderr, "Error MSG3_DELAY_MS can't be negative\n"); + } if (rar_grant.ul_delay) { - rar_grant_tti = (tti + 3) % 10240; + rar_grant_tti = (tti + MSG3_DELAY_MS + 1) % 10240; } else { - rar_grant_tti = (tti + 2) % 10240; + rar_grant_tti = (tti + MSG3_DELAY_MS) % 10240; } } @@ -195,13 +190,13 @@ void phch_common::set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int } void phch_common::reset_pending_ack(uint32_t tti) { - pending_ack[tti%10].enabled = false; + pending_ack[TTIMOD(tti)].enabled = false; } void phch_common::set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs) { - pending_ack[tti%10].enabled = true; - pending_ack[tti%10].I_lowest = I_lowest; - pending_ack[tti%10].n_dmrs = n_dmrs; + pending_ack[TTIMOD(tti)].enabled = true; + pending_ack[TTIMOD(tti)].I_lowest = I_lowest; + pending_ack[TTIMOD(tti)].n_dmrs = n_dmrs; Debug("Set pending ACK for tti=%d I_lowest=%d, n_dmrs=%d\n", tti, I_lowest, n_dmrs); } @@ -211,12 +206,21 @@ bool phch_common::get_pending_ack(uint32_t tti) { bool phch_common::get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs) { if (I_lowest) { - *I_lowest = pending_ack[tti%10].I_lowest; + *I_lowest = pending_ack[TTIMOD(tti)].I_lowest; } if (n_dmrs) { - *n_dmrs = pending_ack[tti%10].n_dmrs; + *n_dmrs = pending_ack[TTIMOD(tti)].n_dmrs; } - return pending_ack[tti%10].enabled; + return pending_ack[TTIMOD(tti)].enabled; +} + +bool phch_common::is_any_pending_ack() { + for (int i=0;iset_tti(tti); if (tx_enable) { - radio_h->tx(buffer, nof_samples, tx_time); + radio_h->tx_single(buffer, nof_samples, tx_time); is_first_of_burst = false; } else { if (TX_MODE_CONTINUOUS) { if (!is_first_of_burst) { - radio_h->tx(zeros, nof_samples, tx_time); + radio_h->tx_single(zeros, nof_samples, tx_time); } } else { if (!is_first_of_burst) { @@ -253,10 +257,6 @@ void phch_common::worker_end(uint32_t tti, bool tx_enable, } // Trigger next transmission pthread_mutex_unlock(&tx_mutex[(tti+1)%nof_mutex]); - - // Trigger MAC clock - mac->tti_clock(tti); - } @@ -326,14 +326,36 @@ void phch_common::get_sync_metrics(sync_metrics_t &m) { sync_metrics_read = true; } +void phch_common::reset() { + sr_enabled = false; + is_first_of_burst = true; + is_first_tx = true; + rar_grant_pending = false; + pathloss = 0; + cur_pathloss = 0; + cur_pusch_power = 0; + p0_preamble = 0; + cur_radio_power = 0; + rx_gain_offset = 0; + sr_last_tx_tti = -1; + cur_pusch_power = 0; + + pcell_meas_enabled = false; + pcell_report_period = 20; + + bzero(pending_ack, sizeof(pending_ack_t)*TTIMOD_SZ); + +} + void phch_common::reset_ul() { - is_first_tx = true; + is_first_tx = true; is_first_of_burst = true; for (uint32_t i=0;itx_end(); } } diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index c14141257..4ae969273 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -25,105 +25,79 @@ */ #include -#include +#include #include "srslte/srslte.h" #include "srslte/common/log.h" #include "phy/phch_worker.h" -#include "phy/phch_common.h" #include "phy/phch_recv.h" -#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) namespace srsue { -int radio_recv_wrapper_cs(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { - phch_recv *h = (phch_recv*) obj; - srslte::radio_multi *radio_h = h->radio_h; - - if (radio_h->rx_now(data, nsamples, rx_time)) { - int offset = nsamples - h->current_sflen; - if (abs(offset) < 10 && offset != 0) { - h->next_offset = offset; - } else if (nsamples < 10) { - h->next_offset = nsamples; - } - return nsamples; - } else { - return -1; - } +int radio_recv_callback(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { + return ((phch_recv*) obj)->radio_recv_fnc(data, nsamples, rx_time); } double callback_set_rx_gain(void *h, double gain) { - srslte::radio_multi *radio_handler = (srslte::radio_multi *) h; - return radio_handler->set_rx_gain_th(gain); + return ((phch_recv*) h)->set_rx_gain(gain); } + phch_recv::phch_recv() { + dl_freq = -1; + ul_freq = -1; bzero(&cell, sizeof(srslte_cell_t)); running = false; + worker_com = NULL; } -void phch_recv:: init(srslte::radio_multi *_radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc, +void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc, prach *_prach_buffer, srslte::thread_pool *_workers_pool, - phch_common *_worker_com, srslte::log *_log_h, uint32_t nof_rx_antennas_, uint32_t prio, - int sync_cpu_affinity) { + phch_common *_worker_com, srslte::log *_log_h, srslte::log *_log_phy_lib_h, uint32_t nof_rx_antennas_, uint32_t prio, + int sync_cpu_affinity) +{ radio_h = _radio_handler; - log_h = _log_h; - mac = _mac; - rrc = _rrc; - workers_pool = _workers_pool; - worker_com = _worker_com; - prach_buffer = _prach_buffer; + log_h = _log_h; + log_phy_lib_h = _log_phy_lib_h; + mac = _mac; + rrc = _rrc; + workers_pool = _workers_pool; + worker_com = _worker_com; + prach_buffer = _prach_buffer; nof_rx_antennas = nof_rx_antennas_; - reset(); - for (uint32_t i = 0; i < nof_rx_antennas; i++) { sf_buffer[i] = (cf_t *) srslte_vec_malloc(sizeof(cf_t) * 3 * SRSLTE_SF_LEN_PRB(100)); } - - if (srslte_ue_cellsearch_init_multi(&cs, 5, radio_recv_wrapper_cs, nof_rx_antennas, - this)) { - Error("SYNC: Initiating UE cell search\n"); - return; - } - - srslte_ue_cellsearch_set_nof_valid_frames(&cs, 2); - - // Set options defined in expert section - set_ue_sync_opts(&cs.ue_sync); - - if (do_agc) { - srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, last_gain); - } - - if (srslte_ue_dl_init(&ue_dl_measure, SRSLTE_MAX_PRB, nof_rx_antennas)) { - Error("SYNC: Initiating ue_dl_measure\n"); - return; - } - - if (srslte_ue_mib_init(&ue_mib, SRSLTE_MAX_PRB)) { - Error("SYNC: Initiating UE MIB decoder\n"); - return; - } - - if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_wrapper_cs, nof_rx_antennas, this)) { + if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_callback, nof_rx_antennas, this)) { Error("SYNC: Initiating ue_sync\n"); return; } - if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_wrapper_cs, nof_rx_antennas, this)) { - Error("SYNC: Initiating UE MIB synchronization\n"); - return; - } - nof_tx_mutex = MUTEX_X_WORKER * workers_pool->get_nof_workers(); worker_com->set_nof_mutex(nof_tx_mutex); + + // Initialize cell searcher + search_p.init(sf_buffer, log_h, nof_rx_antennas, this); + + // Initialize SFN synchronizer + sfn_p.init(&ue_sync, sf_buffer, log_h); + + // Initialize measurement class for the primary cell + measure_p.init(sf_buffer, log_h, nof_rx_antennas); + + // Start intra-frequency measurement + intra_freq_meas.init(worker_com, rrc, log_h); + + reset(); + + // Start main thread if (sync_cpu_affinity < 0) { start(prio); } else { @@ -138,33 +112,35 @@ phch_recv::~phch_recv() { } } srslte_ue_sync_free(&ue_sync); - srslte_ue_dl_free(&ue_dl_measure); - srslte_ue_mib_free(&ue_mib); - srslte_ue_mib_sync_free(&ue_mib_sync); - srslte_ue_cellsearch_free(&cs); } -void phch_recv::stop() { - +void phch_recv::stop() +{ + intra_freq_meas.stop(); running = false; wait_thread_finish(); } -void phch_recv::reset() { +void phch_recv::reset() +{ tx_mutex_cnt = 0; running = true; phy_state = IDLE; time_adv_sec = 0; next_offset = 0; cell_is_set = false; - sync_sfn_cnt = 0; srate_mode = SRATE_NONE; cell_search_in_progress = false; current_earfcn = 0; radio_is_resetting = false; + sfn_p.reset(); + measure_p.reset(); + search_p.reset(); + } -void phch_recv::radio_error() { +void phch_recv::radio_error() +{ log_h->error("SYNC: Receiving from radio.\n"); phy_state = IDLE; radio_is_resetting=true; @@ -180,6 +156,10 @@ void phch_recv::radio_error() { radio_is_resetting=false; } +void phch_recv::set_cfo(float cfo) { + srslte_ue_sync_set_cfo_ref(&ue_sync, cfo); +} + bool phch_recv::wait_radio_reset() { int cnt=0; while(cnt < 20 && radio_is_resetting) { @@ -189,11 +169,13 @@ bool phch_recv::wait_radio_reset() { return radio_is_resetting; } -void phch_recv::set_agc_enable(bool enable) { +void phch_recv::set_agc_enable(bool enable) +{ do_agc = enable; } -void phch_recv::set_time_adv_sec(float _time_adv_sec) { +void phch_recv::set_time_adv_sec(float _time_adv_sec) +{ if (TX_MODE_CONTINUOUS && !radio_h->is_first_of_burst()) { int nsamples = ceil(current_srate*_time_adv_sec); next_offset = -nsamples; @@ -202,12 +184,29 @@ void phch_recv::set_time_adv_sec(float _time_adv_sec) { } } -void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) { +void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q, float cfo) +{ if (worker_com->args->cfo_integer_enabled) { - srslte_ue_sync_cfo_i_detec_en(q, true); + srslte_ue_sync_set_cfo_i_enable(q, true); } + srslte_ue_sync_set_cfo_ema(q, worker_com->args->cfo_pss_ema); srslte_ue_sync_set_cfo_tol(q, worker_com->args->cfo_correct_tol_hz); + srslte_ue_sync_set_cfo_loop_bw(q, worker_com->args->cfo_loop_bw_pss, worker_com->args->cfo_loop_bw_ref, + worker_com->args->cfo_loop_pss_tol, + worker_com->args->cfo_loop_ref_min, + worker_com->args->cfo_loop_pss_tol, + worker_com->args->cfo_loop_pss_conv); + + q->strack.pss.chest_on_filter = worker_com->args->sic_pss_enabled; + + // Disable CP based CFO estimation during find + if (cfo != 0) { + q->cfo_current_value = cfo/15000; + q->cfo_is_copied = true; + q->cfo_correct_enable_find = true; + srslte_sync_set_cfo_cp_enable(&q->sfind, false, 0); + } int time_correct_period = worker_com->args->time_correct_period; if (time_correct_period > 0) { @@ -230,24 +229,16 @@ void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) { bool phch_recv::set_cell() { cell_is_set = false; - if (srslte_ue_mib_set_cell(&ue_mib, cell)) { - Error("SYNC: Setting cell: initiating ue_mib\n"); - return false; - } + + // Set cell in all objects if (srslte_ue_sync_set_cell(&ue_sync, cell)) { Error("SYNC: Setting cell: initiating ue_sync"); return false; } - - // Set options defined in expert section - set_ue_sync_opts(&ue_sync); - - if (srslte_ue_dl_set_cell(&ue_dl_measure, cell)) { - Error("SYNC: Setting cell: initiating ue_dl_measure\n"); - return false; - } - + measure_p.set_cell(cell); + sfn_p.set_cell(cell); worker_com->set_cell(cell); + intra_freq_meas.set_primay_cell(current_earfcn, cell); for (uint32_t i = 0; i < workers_pool->get_nof_workers(); i++) { if (!((phch_worker *) workers_pool->get_worker(i))->set_cell(cell)) { @@ -255,189 +246,28 @@ bool phch_recv::set_cell() { return false; } } - if (do_agc) { - srslte_ue_sync_start_agc(&ue_sync, callback_set_rx_gain, last_gain); - } + + // Set options defined in expert section + set_ue_sync_opts(&ue_sync, search_p.get_last_cfo()); + + // Reset ue_sync and set CFO/gain from search procedure + srslte_ue_sync_reset(&ue_sync); + cell_is_set = true; return cell_is_set; } -int phch_recv::cell_search(int force_N_id_2) { - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; +void phch_recv::resync_sfn(bool is_connected, bool now) { - srslte_ue_cellsearch_result_t found_cells[3]; - - bzero(&cell, sizeof(srslte_cell_t)); - bzero(found_cells, 3 * sizeof(srslte_ue_cellsearch_result_t)); - - if (srate_mode != SRATE_FIND) { - srate_mode = SRATE_FIND; - radio_h->set_rx_srate(1.92e6); - } - start_rx(); - - /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ - uint32_t max_peak_cell = 0; - int ret = SRSLTE_ERROR; - - Info("SYNC: Searching for cell...\n"); - printf("."); fflush(stdout); - - if (force_N_id_2 >= 0 && force_N_id_2 < 3) { - ret = srslte_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]); - max_peak_cell = force_N_id_2; - } else { - ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell); - } - - last_gain = srslte_agc_get_gain(&cs.ue_sync.agc); - - if (ret < 0) { - Error("SYNC: Error decoding MIB: Error searching PSS\n"); - return -1; - } else if (ret == 0) { + if (!now) { + wait_radio_reset(); stop_rx(); - Info("SYNC: Could not find any cell in this frequency\n"); - return 0; } - // Save result - cell.id = found_cells[max_peak_cell].cell_id; - cell.cp = found_cells[max_peak_cell].cp; - cellsearch_cfo = found_cells[max_peak_cell].cfo; - - printf("\n"); - Info("SYNC: PSS/SSS detected: PCI=%d, CFO=%.1f KHz, CP=%s\n", - cell.id, cellsearch_cfo/1000, srslte_cp_string(cell.cp)); - - if (srslte_ue_mib_sync_set_cell(&ue_mib_sync, cell.id, cell.cp)) { - Error("SYNC: Setting UE MIB cell\n"); - return false; - } - - // Set options defined in expert section - set_ue_sync_opts(&ue_mib_sync.ue_sync); - - if (do_agc) { - srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, last_gain); - } - - srslte_ue_sync_reset(&ue_mib_sync.ue_sync); - srslte_ue_sync_set_cfo(&ue_mib_sync.ue_sync, cellsearch_cfo); - - /* Find and decode MIB */ - int sfn_offset; - ret = srslte_ue_mib_sync_decode(&ue_mib_sync, - 40, - bch_payload, &cell.nof_ports, &sfn_offset); - stop_rx(); - last_gain = srslte_agc_get_gain(&ue_mib_sync.ue_sync.agc); - cellsearch_cfo = srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync); - - srslte_ue_sync_reset(&ue_sync); - srslte_ue_sync_set_cfo(&ue_sync, cellsearch_cfo); - - if (ret == 1) { - srslte_pbch_mib_unpack(bch_payload, &cell, NULL); - - fprintf(stdout, "Found Cell: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", - cell.id, cell.nof_prb, cell.nof_ports, cellsearch_cfo/1000); - - Info("SYNC: MIB Decoded: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", - cell.id, cell.nof_prb, cell.nof_ports, cellsearch_cfo/1000); - - return true; - } else if (ret == 0) { - Warning("SYNC: Found PSS but could not decode PBCH\n"); - return 0; - } else { - Error("SYNC: Receiving MIB\n"); - return -1; - } -} - - -int phch_recv::cell_sync_sfn(void) { - - int ret = SRSLTE_ERROR; - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; - - srslte_ue_sync_decode_sss_on_track(&ue_sync, true); - ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer); - if (ret < 0) { - Error("SYNC: Error calling ue_sync_get_buffer"); - return -1; - } - - if (ret == 1) { - if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) { - int sfn_offset = 0; - Info("SYNC: Trying to decode MIB... SNR=%.1f dB\n", - 10*log10(srslte_chest_dl_get_snr(&ue_mib.chest))); - int n = srslte_ue_mib_decode(&ue_mib, sf_buffer[0], bch_payload, NULL, &sfn_offset); - if (n < 0) { - Error("SYNC: Error decoding MIB while synchronising SFN"); - return -1; - } else if (n == SRSLTE_UE_MIB_FOUND) { - uint32_t sfn; - srslte_pbch_mib_unpack(bch_payload, &cell, &sfn); - - sfn = (sfn+sfn_offset)%1024; - tti = sfn * 10; - - srslte_ue_sync_decode_sss_on_track(&ue_sync, true); - Info("SYNC: DONE, TTI=%d, sfn_offset=%d\n", tti, sfn_offset); - srslte_ue_mib_reset(&ue_mib); - return 1; - } - } - } else { - Debug("SYNC: PSS/SSS not found...\n"); - } - return 0; -} - -int phch_recv::cell_meas_rsrp() { - - uint32_t cfi = 0; - - tti = (tti+1) % 10240; - log_h->step(tti); - - uint32_t sf_idx = tti%10; - - int sync_res = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer); - if (sync_res == 1) { - if (srslte_ue_dl_decode_fft_estimate(&ue_dl_measure, sf_buffer, sf_idx, &cfi)) { - log_h->error("SYNC: Measuring RSRP: Estimating channel\n"); - return -1; - } - float rsrp = srslte_chest_dl_get_rsrp(&ue_dl_measure.chest); - float snr = srslte_chest_dl_get_snr(&ue_dl_measure.chest); - measure_rsrp = SRSLTE_VEC_CMA(rsrp, measure_rsrp, measure_cnt); - measure_cnt++; - log_h->info("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", - measure_cnt, RSRP_MEASURE_NOF_FRAMES, sf_idx, 10 * log10(rsrp / 1000), 10*log10(snr)); - if (measure_cnt >= RSRP_MEASURE_NOF_FRAMES) { - return 1; - } - } else { - log_h->error("SYNC: Measuring RSRP: Sync error\n"); - return -1; - } - - return 0; -} - -void phch_recv::resync_sfn(bool is_connected) { - - wait_radio_reset(); - - stop_rx(); - start_rx(); - srslte_ue_mib_reset(&ue_mib); + start_rx(now); + sfn_p.reset(); Info("SYNC: Starting SFN synchronization\n"); - sync_sfn_cnt = 0; + phy_state = is_connected?CELL_RESELECT:CELL_SELECT; } @@ -445,6 +275,11 @@ void phch_recv::set_earfcn(std::vector earfcn) { this->earfcn = earfcn; } +void phch_recv::force_freq(float dl_freq, float ul_freq) { + this->dl_freq = dl_freq; + this->ul_freq = ul_freq; +} + bool phch_recv::stop_sync() { wait_radio_reset(); @@ -468,25 +303,26 @@ void phch_recv::reset_sync() { wait_radio_reset(); Warning("SYNC: Resetting sync, cell_search_in_progress=%s\n", cell_search_in_progress?"yes":"no"); - srslte_ue_sync_reset(&ue_mib_sync.ue_sync); + search_p.reset(); srslte_ue_sync_reset(&ue_sync); - resync_sfn(true); + resync_sfn(true, true); } void phch_recv::cell_search_inc() { cur_earfcn_index++; if (cur_earfcn_index >= 0) { - if (cur_earfcn_index >= (int) earfcn.size() - 1) { + if (cur_earfcn_index >= (int) earfcn.size()) { cur_earfcn_index = 0; rrc->earfcn_end(); + } else { + Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size()); + if (current_earfcn != earfcn[cur_earfcn_index]) { + current_earfcn = earfcn[cur_earfcn_index]; + set_frequency(); + } } } - Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size()); - if (current_earfcn != earfcn[cur_earfcn_index]) { - current_earfcn = earfcn[cur_earfcn_index]; - set_frequency(); - } } void phch_recv::cell_search_next(bool reset) { @@ -505,12 +341,16 @@ void phch_recv::cell_search_next(bool reset) { } void phch_recv::cell_search_start() { - if (earfcn.size() > 0) { - Info("SYNC: Starting Cell Search procedure in %d EARFCNs...\n", earfcn.size()); - cell_search_next(true); + if (phy_state == CELL_CAMP) { + Warning("SYNC: Can't start cell search procedure while camping on cell\n"); } else { - Info("SYNC: Empty EARFCN list. Stopping cell search...\n"); - log_h->console("Empty EARFCN list. Stopping cell search...\n"); + if (earfcn.size() > 0) { + Info("SYNC: Starting Cell Search procedure in %d EARFCNs...\n", earfcn.size()); + cell_search_next(true); + } else { + Info("SYNC: Empty EARFCN list. Stopping cell search...\n"); + log_h->console("Empty EARFCN list. Stopping cell search...\n"); + } } } @@ -522,6 +362,32 @@ void phch_recv::cell_search_stop() { cell_search_in_progress = false; } +bool phch_recv::cell_handover(srslte_cell_t cell) +{ + int cnt = 0; + while(worker_com->is_any_pending_ack() && cnt < 10) { + usleep(1000); + cnt++; + log_h->info("Cell HO: Waiting pending PHICH\n"); + } + + bool ret; + this->cell = cell; + Info("Cell HO: Stopping sync with current cell\n"); + worker_com->reset_ul(); + stop_sync(); + Info("Cell HO: Reconfiguring cell\n"); + if (set_cell()) { + Info("Cell HO: Synchronizing with new cell\n"); + resync_sfn(true, true); + ret = true; + } else { + log_h->error("Cell HO: Configuring cell PCI=%d\n", cell.id); + ret = false; + } + return ret; +} + bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { // Check if we are already camping in this cell @@ -543,24 +409,24 @@ bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { log_h->warning("Still not in idle\n"); } - current_earfcn = earfcn; - - printf("cell select called set frequency\n"); - - if (set_frequency()) { - this->cell = cell; - log_h->info("Cell Select: Configuring cell...\n"); - - if (set_cell()) { - log_h->info("Cell Select: Synchronizing on cell...\n"); - - resync_sfn(); - - usleep(500000); // Time offset we set start_rx to start receveing samples - return true; - } else { + if (earfcn != current_earfcn) { + if (set_frequency()) { log_h->error("Cell Select: Configuring cell in EARFCN=%d, PCI=%d\n", earfcn, cell.id); + return false; } + current_earfcn = earfcn; + } + + this->cell = cell; + log_h->info("Cell Select: Configuring cell...\n"); + + if (set_cell()) { + log_h->info("Cell Select: Synchronizing on cell...\n"); + + resync_sfn(); + + usleep(500000); // Time offset we set start_rx to start receiving samples + return true; } return false; } @@ -568,17 +434,25 @@ bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { bool phch_recv::set_frequency() { - double dl_freq = 1e6*srslte_band_fd(current_earfcn); - double ul_freq = 1e6*srslte_band_fu(srslte_band_ul_earfcn(current_earfcn)); - if (dl_freq > 0 && ul_freq > 0) { + double set_dl_freq = 0; + double set_ul_freq = 0; + + if (this->dl_freq > 0 && this->ul_freq > 0) { + set_dl_freq = this->dl_freq; + set_ul_freq = this->ul_freq; + } else { + set_dl_freq = 1e6*srslte_band_fd(current_earfcn); + set_ul_freq = 1e6*srslte_band_fu(srslte_band_ul_earfcn(current_earfcn)); + } + if (set_dl_freq > 0 && set_ul_freq > 0) { log_h->info("SYNC: Set DL EARFCN=%d, f_dl=%.1f MHz, f_ul=%.1f MHz\n", - current_earfcn, dl_freq / 1e6, ul_freq / 1e6); + current_earfcn, set_dl_freq / 1e6, set_ul_freq / 1e6); log_h->console("Searching cell in DL EARFCN=%d, f_dl=%.1f MHz, f_ul=%.1f MHz\n", - current_earfcn, dl_freq / 1e6, ul_freq / 1e6); + current_earfcn, set_dl_freq / 1e6, set_ul_freq / 1e6); - radio_h->set_rx_freq(dl_freq); - radio_h->set_tx_freq(ul_freq); + radio_h->set_rx_freq(set_dl_freq); + radio_h->set_tx_freq(set_ul_freq); ul_dl_factor = radio_h->get_tx_freq()/radio_h->get_rx_freq(); srslte_ue_sync_reset(&ue_sync); @@ -610,22 +484,96 @@ void phch_recv::set_sampling_rate() } } -void phch_recv::run_thread() { +void phch_recv::stop_rx() { + if (radio_is_rx) { + Info("SYNC: Stopping RX streaming\n"); + radio_h->stop_rx(); + } + radio_is_rx = false; +} + +void phch_recv::start_rx(bool now) { + if (!radio_is_rx) { + Info("SYNC: Starting RX streaming\n"); + radio_h->start_rx(now); + } + radio_is_rx = true; +} + +uint32_t phch_recv::get_current_tti() { + return tti; +} + +bool phch_recv::status_is_sync() { + return phy_state == CELL_CAMP; +} + +void phch_recv::get_current_cell(srslte_cell_t *cell_, uint32_t *earfcn) { + if (cell_) { + memcpy(cell_, &cell, sizeof(srslte_cell_t)); + } + if (earfcn) { + *earfcn = current_earfcn; + } +} + +int phch_recv::radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) +{ + if (radio_h->rx_now(data, nsamples, rx_time)) { + int offset = nsamples - current_sflen; + if (abs(offset) < 10 && offset != 0) { + next_offset = offset; + } else if (nsamples < 10) { + next_offset = nsamples; + } + + log_h->debug("SYNC: received %d samples from radio\n", nsamples); + + return nsamples; + } else { + return -1; + } +} + +double phch_recv::set_rx_gain(double gain) { + return radio_h->set_rx_gain_th(gain); +} + + + + +/** + * MAIN THREAD + */ + +void phch_recv::run_thread() +{ phch_worker *worker = NULL; - cf_t *buffer[SRSLTE_MAX_PORTS]; + phch_worker *last_worker = NULL; + cf_t *buffer[SRSLTE_MAX_PORTS] = {NULL}; + uint32_t sf_idx = 0; phy_state = IDLE; is_in_idle = true; - while (running) { + while (running) + { if (phy_state != IDLE) { is_in_idle = false; Debug("SYNC: state=%d\n", phy_state); } + + log_h->step(tti); + log_phy_lib_h->step(tti); + + sf_idx = tti%10; + switch (phy_state) { case CELL_SEARCH: - if (cell_search_in_progress) { - switch(cell_search()) { - case 1: + if (cell_search_in_progress) + { + switch(search_p.run(&cell)) + { + case search::CELL_FOUND: if (!srslte_cell_isvalid(&cell)) { Error("SYNC: Detected invalid cell\n"); phy_state = IDLE; @@ -636,7 +584,7 @@ void phch_recv::run_thread() { resync_sfn(); } break; - case 0: + case search::CELL_NOT_FOUND: if (cell_search_in_progress) { cell_search_inc(); } @@ -649,46 +597,42 @@ void phch_recv::run_thread() { break; case CELL_RESELECT: case CELL_SELECT: - - srslte_ue_sync_decode_sss_on_track(&ue_sync, true); - - switch (cell_sync_sfn()) { - case 1: - srslte_ue_sync_set_agc_period(&ue_sync, 20); + switch (sfn_p.run_subframe(&cell, &tti)) + { + case sfn_sync::SFN_FOUND: if (!cell_search_in_progress) { - phy_state = CELL_CAMP; log_h->info("Sync OK. Camping on cell PCI=%d...\n", cell.id); + phy_state = CELL_CAMP; } else { - measure_cnt = 0; - measure_rsrp = 0; - phy_state = CELL_MEASURE; + measure_p.reset(); + phy_state = CELL_MEASURE; } break; - case 0: + case sfn_sync::TIMEOUT: + if (cell_search_in_progress) { + log_h->warning("SYNC: Timeout while synchronizing SFN. Going back to cell search\n"); + phy_state = CELL_SEARCH; + } else { + log_h->warning("SYNC: Timeout while synchronizing SFN. Reselecting cell\n"); + resync_sfn(true, true); + } + break; + case sfn_sync::IDLE: break; default: radio_error(); break; } - sync_sfn_cnt++; - if (sync_sfn_cnt >= SYNC_SFN_TIMEOUT) { - sync_sfn_cnt = 0; - log_h->warning("SYNC: Timeout while synchronizing SFN\n"); - if (phy_state == CELL_SELECT) { - phy_state = CELL_SEARCH; - } else { - phy_state = IDLE; - } - } break; case CELL_MEASURE: - switch(cell_meas_rsrp()) { - case 1: + switch(measure_p.run_subframe_sync(&ue_sync, sf_idx)) + { + case measure::MEASURE_OK: log_h->info("SYNC: Measured OK. Camping on cell PCI=%d...\n", cell.id); phy_state = CELL_CAMP; - rrc->cell_found(earfcn[cur_earfcn_index], cell, 10*log10(measure_rsrp/1000)); + rrc->cell_found(earfcn[cur_earfcn_index], cell, measure_p.rsrp()); break; - case 0: + case measure::IDLE: break; default: radio_error(); @@ -696,17 +640,24 @@ void phch_recv::run_thread() { } break; case CELL_CAMP: - tti = (tti+1) % 10240; + worker = (phch_worker *) workers_pool->wait_worker(tti); if (worker) { - for (uint32_t i = 0; i < nof_rx_antennas; i++) { + for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) { buffer[i] = worker->get_buffer(i); } switch(srslte_ue_sync_zerocopy_multi(&ue_sync, buffer)) { case 1: - log_h->step(tti); + if (last_worker) { + Debug("SF: cfo_tot=%7.1f Hz, ref=%f Hz, pss=%f Hz\n", + srslte_ue_sync_get_cfo(&ue_sync), + 15000*last_worker->get_ref_cfo(), + 15000*ue_sync.strack.cfo_pss_mean); + } + + last_worker = worker; Debug("SYNC: Worker %d synchronized\n", worker->get_id()); @@ -717,11 +668,11 @@ void phch_recv::run_thread() { worker->set_sample_offset(srslte_ue_sync_get_sfo(&ue_sync)/1000); - /* Compute TX time: Any transmission happens in TTI4 thus advance 4 ms the reception time */ + /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ srslte_timestamp_t rx_time, tx_time, tx_time_prach; srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time); srslte_timestamp_copy(&tx_time, &rx_time); - srslte_timestamp_add(&tx_time, 0, 4e-3 - time_adv_sec); + srslte_timestamp_add(&tx_time, 0, HARQ_DELAY_MS*1e-3 - time_adv_sec); worker->set_tx_time(tx_time, next_offset); next_offset = 0; @@ -738,15 +689,28 @@ void phch_recv::run_thread() { worker_com->p0_preamble = prach_buffer->get_p0_preamble(); worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss+worker_com->p0_preamble); } + workers_pool->start_worker(worker); + + if ((tti%5) == 0 && worker_com->args->sic_pss_enabled) { + srslte_pss_sic(&ue_sync.strack.pss, &buffer[0][SRSLTE_SF_LEN_PRB(cell.nof_prb)/2-ue_sync.strack.fft_size]); + } + intra_freq_meas.write(tti, buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)); + out_of_sync_cnt = 0; break; case 0: - log_h->error("SYNC: Sync error. Sending out-of-sync to RRC\n"); - // Notify RRC of out-of-sync frame - rrc->out_of_sync(); + // Signal every 5 errors only (PSS is every 5) + if (out_of_sync_cnt == 0) { + // Notify RRC of out-of-sync frame + log_h->error("SYNC: Sync error. Sending out-of-sync to RRC\n"); + rrc->out_of_sync(); + } worker->release(); worker_com->reset_ul(); - mac->tti_clock(tti); + out_of_sync_cnt++; + if (out_of_sync_cnt >= 5) { + out_of_sync_cnt = 0; + } break; default: radio_error(); @@ -763,41 +727,778 @@ void phch_recv::run_thread() { } is_in_idle = true; usleep(1000); - // Keep running MAC timer from system clock - tti = (tti+1) % 10240; - mac->tti_clock(tti); break; } + + // Increase TTI counter and trigger MAC clock (lower priority) + mac->tti_clock(tti); + tti = (tti+1) % 10240; + } +} + +void phch_recv::out_of_sync() { + out_of_sync2_cnt++; + Info("SYNC: Received out_of_sync from channel estimator (%d)\n", out_of_sync2_cnt); + if (out_of_sync2_cnt >= 2) { + out_of_sync2_cnt = 0; + Info("SYNC: Trying to resync signal\n"); + resync_sfn(true, true); + } +} + + + + + + + + + + + + +/********* + * Cell search class + */ +phch_recv::search::~search() +{ + srslte_ue_mib_sync_free(&ue_mib_sync); + srslte_ue_cellsearch_free(&cs); +} + +void phch_recv::search::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent) +{ + this->log_h = log_h; + this->p = parent; + + for (int i=0;ibuffer[i] = buffer[i]; + } + + if (srslte_ue_cellsearch_init_multi(&cs, 5, radio_recv_callback, nof_rx_antennas, parent)) { + Error("SYNC: Initiating UE cell search\n"); + } + + if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_callback, nof_rx_antennas, parent)) { + Error("SYNC: Initiating UE MIB synchronization\n"); + } + + srslte_ue_cellsearch_set_nof_valid_frames(&cs, 2); + + // Set options defined in expert section + p->set_ue_sync_opts(&cs.ue_sync, 0); + + force_N_id_2 = -1; +} + +void phch_recv::search::set_N_id_2(int N_id_2) { + force_N_id_2 = N_id_2; +} + +void phch_recv::search::reset() +{ + srslte_ue_sync_reset(&ue_mib_sync.ue_sync); +} + +float phch_recv::search::get_last_gain() +{ + return srslte_agc_get_gain(&ue_mib_sync.ue_sync.agc); +} + +float phch_recv::search::get_last_cfo() +{ + return srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync); +} + +phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell) +{ + + if (!cell) { + return ERROR; + } + + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + + srslte_ue_cellsearch_result_t found_cells[3]; + + bzero(cell, sizeof(srslte_cell_t)); + bzero(found_cells, 3 * sizeof(srslte_ue_cellsearch_result_t)); + + if (p->srate_mode != SRATE_FIND) { + p->srate_mode = SRATE_FIND; + p->radio_h->set_rx_srate(1.92e6); + } + p->start_rx(); + + /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ + uint32_t max_peak_cell = 0; + int ret = SRSLTE_ERROR; + + Info("SYNC: Searching for cell...\n"); + printf("."); fflush(stdout); + + if (force_N_id_2 >= 0 && force_N_id_2 < 3) { + ret = srslte_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]); + max_peak_cell = force_N_id_2; + } else { + ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell); + } + + if (ret < 0) { + Error("SYNC: Error decoding MIB: Error searching PSS\n"); + return ERROR; + } else if (ret == 0) { + p->stop_rx(); + Info("SYNC: Could not find any cell in this frequency\n"); + return CELL_NOT_FOUND; + } + // Save result + cell->id = found_cells[max_peak_cell].cell_id; + cell->cp = found_cells[max_peak_cell].cp; + float cfo = found_cells[max_peak_cell].cfo; + + printf("\n"); + Info("SYNC: PSS/SSS detected: PCI=%d, CFO=%.1f KHz, CP=%s\n", + cell->id, cfo/1000, srslte_cp_string(cell->cp)); + + if (srslte_ue_mib_sync_set_cell(&ue_mib_sync, cell->id, cell->cp)) { + Error("SYNC: Setting UE MIB cell\n"); + return ERROR; + } + + // Set options defined in expert section + p->set_ue_sync_opts(&ue_mib_sync.ue_sync, cfo); + + // Start AGC after initial cell search + if (p->do_agc) { + srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, p->radio_h->get_rx_gain()); + } + + srslte_ue_sync_reset(&ue_mib_sync.ue_sync); + + /* Find and decode MIB */ + int sfn_offset; + ret = srslte_ue_mib_sync_decode(&ue_mib_sync, + 40, + bch_payload, &cell->nof_ports, &sfn_offset); + p->stop_rx(); + + if (ret == 1) { + srslte_pbch_mib_unpack(bch_payload, cell, NULL); + + fprintf(stdout, "Found Cell: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", + cell->id, cell->nof_prb, cell->nof_ports, cfo/1000); + + Info("SYNC: MIB Decoded: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", + cell->id, cell->nof_prb, cell->nof_ports, cfo/1000); + + return CELL_FOUND; + } else if (ret == 0) { + Warning("SYNC: Found PSS but could not decode PBCH\n"); + return CELL_NOT_FOUND; + } else { + Error("SYNC: Receiving MIB\n"); + return ERROR; + } +} + + + + + + + + +/********* + * SFN synchronizer class + */ + +phch_recv::sfn_sync::~sfn_sync() +{ + srslte_ue_mib_free(&ue_mib); +} + +void phch_recv::sfn_sync::init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t timeout) +{ + this->log_h = log_h; + this->ue_sync = ue_sync; + this->timeout = timeout; + + for (int i=0;ibuffer[i] = buffer[i]; + } + + if (srslte_ue_mib_init(&ue_mib, this->buffer, SRSLTE_MAX_PRB)) { + Error("SYNC: Initiating UE MIB decoder\n"); + } +} + +bool phch_recv::sfn_sync::set_cell(srslte_cell_t cell) +{ + if (srslte_ue_mib_set_cell(&ue_mib, cell)) { + Error("SYNC: Setting cell: initiating ue_mib\n"); + return false; + } + reset(); + return true; +} + +void phch_recv::sfn_sync::reset() +{ + srslte_ue_mib_reset(&ue_mib); + cnt = 0; +} + +phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt, bool sfidx_only) +{ + + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + + srslte_ue_sync_decode_sss_on_track(ue_sync, true); + int ret = srslte_ue_sync_zerocopy_multi(ue_sync, buffer); + if (ret < 0) { + Error("SYNC: Error calling ue_sync_get_buffer"); + return ERROR; + } + + if (ret == 1) { + if (srslte_ue_sync_get_sfidx(ue_sync) == 0) { + + // Skip MIB decoding if we are only interested in subframe 0 + if (sfidx_only) { + if (tti_cnt) { + *tti_cnt = 0; + } + return SFX0_FOUND; + } + + int sfn_offset = 0; + Info("SYNC: Trying to decode MIB... SNR=%.1f dB\n", 10*log10(srslte_chest_dl_get_snr(&ue_mib.chest))); + + int n = srslte_ue_mib_decode(&ue_mib, bch_payload, NULL, &sfn_offset); + if (n < 0) { + Error("SYNC: Error decoding MIB while synchronising SFN"); + return ERROR; + } else if (n == SRSLTE_UE_MIB_FOUND) { + uint32_t sfn; + srslte_pbch_mib_unpack(bch_payload, cell, &sfn); + + sfn = (sfn+sfn_offset)%1024; + if (tti_cnt) { + *tti_cnt = 10*sfn; + Info("SYNC: DONE, TTI=%d, sfn_offset=%d\n", *tti_cnt, sfn_offset); + } + + srslte_ue_sync_set_agc_period(ue_sync, 20); + srslte_ue_sync_decode_sss_on_track(ue_sync, true); + reset(); + return SFN_FOUND; + } + } + } else { + Debug("SYNC: PSS/SSS not found...\n"); + } + + cnt++; + if (cnt >= timeout) { + cnt = 0; + return TIMEOUT; + } + + return IDLE; +} + + + + + + +/********* + * Measurement class + */ +void phch_recv::measure::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t nof_subframes) +{ + this->log_h = log_h; + this->nof_subframes = nof_subframes; + for (int i=0;ibuffer[i] = buffer[i]; + } + + if (srslte_ue_dl_init(&ue_dl, this->buffer, SRSLTE_MAX_PRB, nof_rx_antennas)) { + Error("SYNC: Initiating ue_dl_measure\n"); + return; + } + reset(); +} + +phch_recv::measure::~measure() { + srslte_ue_dl_free(&ue_dl); +} + +void phch_recv::measure::reset() { + cnt = 0; + mean_rsrp = 0; + mean_rsrq = 0; + mean_snr = 0; +} + +void phch_recv::measure::set_cell(srslte_cell_t cell) +{ + current_prb = cell.nof_prb; + if (srslte_ue_dl_set_cell(&ue_dl, cell)) { + Error("SYNC: Setting cell: initiating ue_dl_measure\n"); + } + reset(); +} + +float phch_recv::measure::rsrp() { + return mean_rsrp; +} + +float phch_recv::measure::rsrq() { + return mean_rsrq; +} + +float phch_recv::measure::snr() { + return mean_snr; +} + +uint32_t phch_recv::measure::frame_st_idx() { + return final_offset; +} + +void phch_recv::measure::set_rx_gain_offset(float rx_gain_offset) { + this->rx_gain_offset = rx_gain_offset; +} + +phch_recv::measure::ret_code phch_recv::measure::run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx) +{ + int sync_res = srslte_ue_sync_zerocopy_multi(ue_sync, buffer); + if (sync_res == 1) { + log_h->info("SYNC: CFO=%.1f KHz\n", srslte_ue_sync_get_cfo(ue_sync)); + return run_subframe(sf_idx); + } else { + log_h->error("SYNC: Measuring RSRP: Sync error\n"); + return ERROR; + } + + return IDLE; +} + +phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *input_buffer, + uint32_t offset, + uint32_t sf_idx, + uint32_t max_sf) +{ + uint32_t sf_len = SRSLTE_SF_LEN_PRB(current_prb); + + ret_code ret = IDLE; + + offset = offset-sf_len/2; + if (offset < 0) { + offset += sf_len; + sf_idx ++; + } + + float max_rsrp = -99; + int best_test_offset = 0; + int test_offset = 0; + bool found_best = false; + + // Fine-tune offset using RS + for (uint32_t n=0;n<5;n++) { + + test_offset = offset-2+n; + if (test_offset >= 0) { + + cf_t *buf_m[SRSLTE_MAX_PORTS]; + buf_m[0] = &input_buffer[test_offset]; + + uint32_t cfi; + if (srslte_ue_dl_decode_fft_estimate_noguru(&ue_dl, buf_m, sf_idx, &cfi)) { + Error("MEAS: Measuring RSRP: Estimating channel\n"); + return ERROR; + } + + float rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest); + if (rsrp > max_rsrp) { + max_rsrp = rsrp; + best_test_offset = test_offset; + found_best = true; + } + } + } + + offset = found_best?best_test_offset:offset; + if (offset >= 0 && offset < sf_len*max_sf) { + uint32_t nof_sf = (sf_len*max_sf - offset)/sf_len; + + Debug("INTRA: fine-tuning offset: %d, found_best=%d, rem_sf=%d\n", offset, found_best, nof_sf); + + final_offset = offset; + + for (uint32_t i=0;ierror("SYNC: Measuring RSRP: Estimating channel\n"); + return ERROR; + } + + float rsrp = 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest)) + 30 - rx_gain_offset; + float rsrq = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest)); + float snr = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)); + + if (cnt == 0) { + mean_rsrp = rsrp; + mean_rsrq = rsrq; + mean_snr = snr; + } else { + mean_rsrp = SRSLTE_VEC_CMA(rsrp, mean_rsrp, cnt); + mean_rsrq = SRSLTE_VEC_CMA(rsrq, mean_rsrq, cnt); + mean_snr = SRSLTE_VEC_CMA(snr, mean_snr, cnt); + + } + cnt++; + + log_h->debug("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", + cnt, nof_subframes, sf_idx, rsrp, snr); + + if (cnt >= nof_subframes) { + return MEASURE_OK; + } else { + return IDLE; + } +} + + + + + + +/********** + * Secondary cell receiver + */ + +void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled) +{ + this->log_h = log_h; + this->sic_pss_enabled = sic_pss_enabled; + + // and a separate ue_sync instance + + uint32_t max_fft_sz = srslte_symbol_sz(100); + uint32_t max_sf_size = SRSLTE_SF_LEN(max_fft_sz); + + sf_buffer[0] = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*max_sf_size); + input_cfo_corrected = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*15*max_sf_size); + + measure_p.init(sf_buffer, log_h, 1, DEFAULT_MEASUREMENT_LEN); + + //do this different we don't need all this search window. + if(srslte_sync_init(&sync_find, 50*max_sf_size, 5*max_sf_size, max_fft_sz)) { + fprintf(stderr, "Error initiating sync_find\n"); + return; + } + srslte_sync_cp_en(&sync_find, false); + srslte_sync_set_threshold(&sync_find, 1.2); + srslte_sync_set_em_alpha(&sync_find, 0.0); + + // Configure FIND object behaviour (this configuration is always the same) + srslte_sync_set_cfo_ema_alpha(&sync_find, 1.0); + srslte_sync_set_cfo_i_enable(&sync_find, false); + srslte_sync_set_cfo_pss_enable(&sync_find, true); + srslte_sync_set_pss_filt_enable(&sync_find, true); + srslte_sync_set_sss_eq_enable(&sync_find, true); + + sync_find.pss.chest_on_filter = true; + + if (!sic_pss_enabled) { + sync_find.sss_channel_equalize = false; + } + + reset(); +} + +void phch_recv::scell_recv::reset() +{ + current_fft_sz = 0; + measure_p.reset(); +} + +int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t cell, uint32_t nof_sf, cell_info_t cells[MAX_CELLS]) +{ + uint32_t fft_sz = srslte_symbol_sz(cell.nof_prb); + uint32_t sf_len = SRSLTE_SF_LEN(fft_sz); + + if (fft_sz != current_fft_sz) { + if (srslte_sync_resize(&sync_find, nof_sf*sf_len, 5*sf_len, fft_sz)) { + fprintf(stderr, "Error resizing sync nof_sf=%d, sf_len=%d, fft_sz=%d\n", nof_sf, sf_len, fft_sz); + return SRSLTE_ERROR; + } + current_fft_sz = fft_sz; + } + + int nof_cells = 0; + uint32_t peak_idx = 0; + uint32_t sf_idx = 0; + int cell_id = 0; + + srslte_cell_t found_cell; + memcpy(&found_cell, &cell, sizeof(srslte_cell_t)); + found_cell.id = 10000; + + measure_p.set_rx_gain_offset(rx_gain_offset); + + for (uint32_t n_id_2=0;n_id_2<3;n_id_2++) { + + if (n_id_2 != (cell.id%3) || sic_pss_enabled) { + srslte_sync_set_N_id_2(&sync_find, n_id_2); + + srslte_sync_find_ret_t sync_res; + + do { + srslte_sync_reset(&sync_find); + srslte_sync_cfo_reset(&sync_find); + + uint32_t sf5_cnt=0; + do { + sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt*5*sf_len, &peak_idx); + } while(sync_res != SRSLTE_SYNC_FOUND && sf5_cnt < nof_sf/5); + + switch(sync_res) { + case SRSLTE_SYNC_ERROR: + return SRSLTE_ERROR; + fprintf(stderr, "Error finding correlation peak\n"); + return SRSLTE_ERROR; + case SRSLTE_SYNC_FOUND: + sf_idx = srslte_sync_get_sf_idx(&sync_find); + cell_id = srslte_sync_get_cell_id(&sync_find); + + if (cell_id >= 0) { + // We found the same cell as before, look another N_id_2 + if ((uint32_t) cell_id == found_cell.id || (uint32_t) cell_id == cell.id) { + sync_res = SRSLTE_SYNC_NOFOUND; + } else { + // We found a new cell ID + found_cell.id = cell_id; + found_cell.nof_ports = 1; // Use port 0 only for measurement + measure_p.set_cell(found_cell); + + // Correct CFO + srslte_cfo_correct(&sync_find.cfo_corr_frame, + input_buffer, + input_cfo_corrected, + -srslte_sync_get_cfo(&sync_find)/sync_find.fft_size); + + + switch(measure_p.run_multiple_subframes(input_cfo_corrected, peak_idx, sf_idx, nof_sf)) { + case measure::MEASURE_OK: + cells[nof_cells].pci = found_cell.id; + cells[nof_cells].rsrp = measure_p.rsrp(); + cells[nof_cells].rsrq = measure_p.rsrq(); + cells[nof_cells].offset = measure_p.frame_st_idx(); + + Info("INTRA: Found neighbour cell %d: PCI=%03d, RSRP=%5.1f dBm, peak_idx=%5d, peak_value=%3.2f n_id_2=%d, CFO=%6.1f Hz\n", + nof_cells, cell_id, measure_p.rsrp(), measure_p.frame_st_idx(), sync_find.peak_value, n_id_2, 15000*srslte_sync_get_cfo(&sync_find)); + + nof_cells++; + + if (sic_pss_enabled) { + srslte_pss_sic(&sync_find.pss, &input_buffer[sf_len/2-fft_sz]); + } + + break; + case measure::ERROR: + Error("Measuring neighbour cell\n"); + return SRSLTE_ERROR; + default: + break; + } + } + } else { + sync_res = SRSLTE_SYNC_NOFOUND; + } + break; + case SRSLTE_SYNC_FOUND_NOSPACE: + /* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */ + break; + default: + break; + } + } while (sync_res == SRSLTE_SYNC_FOUND && sic_pss_enabled); + } + } + return nof_cells; +} + + + +/********** + * PHY measurements + * + */ + +void phch_recv::meas_reset() { + // Stop all measurements + intra_freq_meas.clear_cells(); + if (worker_com) { + worker_com->pcell_meas_enabled = false; + } +} + +int phch_recv::meas_start(uint32_t earfcn, int pci) { + if (earfcn == current_earfcn) { + worker_com->pcell_meas_enabled = true; + if (pci != (int) cell.id) { + intra_freq_meas.add_cell(pci); + } + return 0; + } else { + Warning("INTRA: Inter-frequency measurements not supported (current EARFCN=%d, requested measurement for %d)\n", + current_earfcn, earfcn); + return -1; + } +} + +int phch_recv::meas_stop(uint32_t earfcn, int pci) { + if (earfcn == current_earfcn) { + intra_freq_meas.rem_cell(pci); + return 0; + } else { + Warning("INTRA: Inter-frequency measurements not supported (current EARFCN=%d, requested stop measurement for %d)\n", + current_earfcn, earfcn); + } + return -1; +} + +void phch_recv::intra_measure::init(phch_common *common, rrc_interface_phy *rrc, srslte::log *log_h) { + this->rrc = rrc; + this->log_h = log_h; + this->common = common; + receive_enabled = false; + + // Start scell + scell.init(log_h, common->args->sic_pss_enabled); + + search_buffer = (cf_t*) srslte_vec_malloc(CAPTURE_LEN_SF*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB)*sizeof(cf_t)); + + if (srslte_ringbuffer_init(&ring_buffer, sizeof(cf_t)*100*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB))) { + return; + } + + running = true; + start(); +} + +void phch_recv::intra_measure::stop() { + running = false; + tti_sync.increase(); + wait_thread_finish(); +} + +void phch_recv::intra_measure::set_primay_cell(uint32_t earfcn, srslte_cell_t cell) { + this->current_earfcn = earfcn; + current_sflen = SRSLTE_SF_LEN_PRB(cell.nof_prb); + memcpy(&this->primary_cell, &cell, sizeof(srslte_cell_t)); +} + +void phch_recv::intra_measure::clear_cells() { + active_pci.clear(); + receive_enabled = false; + receiving = false; + receive_cnt = 0; + srslte_ringbuffer_reset(&ring_buffer); +} + +void phch_recv::intra_measure::add_cell(int pci) { + if (std::find(active_pci.begin(), active_pci.end(), pci) == active_pci.end()) { + active_pci.push_back(pci); + receive_enabled = true; + Info("INTRA: Starting intra-frequency measurement for pci=%d\n", pci); + } else { + Debug("INTRA: Requested to start already existing intra-frequency measurement for PCI=%d\n", pci); + } +} + +int phch_recv::intra_measure::get_offset(uint32_t pci) { + for (int i=0;i::iterator newEnd = std::remove(active_pci.begin(), active_pci.end(), pci); + + if (newEnd != active_pci.end()) { + active_pci.erase(newEnd, active_pci.end()); + if (active_pci.size() == 0) { + receive_enabled = false; + } + Info("INTRA: Stopping intra-frequency measurement for pci=%d. Number of cells: %d\n", pci, active_pci.size()); + } else { + Warning("INTRA: Requested to stop non-existing intra-frequency measurement for PCI=%d\n", pci); + } +} + +void phch_recv::intra_measure::write(uint32_t tti, cf_t *data, uint32_t nsamples) { + if (receive_enabled) { + if ((tti%INTRA_FREQ_MEAS_PERIOD_MS) == 0) { + receiving = true; + receive_cnt = 0; + measure_tti = tti; + srslte_ringbuffer_reset(&ring_buffer); + } + if (receiving == true) { + if (srslte_ringbuffer_write(&ring_buffer, data, nsamples*sizeof(cf_t)) < (int) (nsamples*sizeof(cf_t))) { + Warning("Error writing to ringbuffer\n"); + receiving = false; + } else { + receive_cnt++; + if (receive_cnt == CAPTURE_LEN_SF) { + tti_sync.increase(); + } + } + } + + } +} + +void phch_recv::intra_measure::run_thread() +{ + while(running) { + if (running) { + tti_sync.wait(); + } + + if (running) { + // Read 15 ms data from buffer + srslte_ringbuffer_read(&ring_buffer, search_buffer, CAPTURE_LEN_SF*current_sflen*sizeof(cf_t)); + int found_cells = scell.find_cells(search_buffer, common->rx_gain_offset, primary_cell, CAPTURE_LEN_SF, info); + receiving = false; + + for (int i=0;inew_phy_meas(info[i].rsrp, info[i].rsrq, measure_tti, current_earfcn, info[i].pci); + } + // Look for other cells not found automatically + } } } -void phch_recv::stop_rx() { - if (radio_is_rx) { - Info("SYNC: Stopping RX streaming\n"); - radio_h->stop_rx(); - } - radio_is_rx = false; -} - -void phch_recv::start_rx() { - if (!radio_is_rx) { - Info("SYNC: Starting RX streaming\n"); - radio_h->start_rx(); - } - radio_is_rx = true; -} - -uint32_t phch_recv::get_current_tti() { - return tti; -} - -bool phch_recv::status_is_sync() { - return phy_state == CELL_CAMP; -} - -void phch_recv::get_current_cell(srslte_cell_t *cell_) { - if (cell_) { - memcpy(cell_, &cell, sizeof(srslte_cell_t)); - } -} } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index c0fec2ba2..1024c1209 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -27,21 +27,20 @@ #include #include #include "phy/phch_worker.h" +#include "srslte/srslte.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/asn1/liblte_rrc.h" -#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) /* This is to visualize the channel response */ #ifdef ENABLE_GUI #include "srsgui/srsgui.h" #include -#include "srslte/srslte.h" -#include "srslte/interfaces/ue_interfaces.h" void init_plots(srsue::phch_worker *worker); pthread_t plot_thread; @@ -58,15 +57,16 @@ namespace srsue { phch_worker::phch_worker() : tr_exec(10240) { - phy = NULL; + phy = NULL; + chest_loop = NULL; + bzero(signal_buffer, sizeof(cf_t*)*SRSLTE_MAX_PORTS); mem_initiated = false; cell_initiated = false; pregen_enabled = false; trace_enabled = false; - - reset(); + reset(); } @@ -95,10 +95,11 @@ void phch_worker::reset() bzero(&pucch_sched, sizeof(srslte_pucch_sched_t)); bzero(&srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); bzero(&period_cqi, sizeof(srslte_cqi_periodic_cfg_t)); - I_sr = 0; + sr_configured = false; rnti_is_set = false; - rar_cqi_request = false; - cfi = 0; + rar_cqi_request = false; + I_sr = 0; + cfi = 0; } void phch_worker::set_common(phch_common* phy_) @@ -106,9 +107,12 @@ void phch_worker::set_common(phch_common* phy_) phy = phy_; } -bool phch_worker::init(uint32_t max_prb, srslte::log *log_h) +bool phch_worker::init(uint32_t max_prb, srslte::log *log_h, srslte::log *log_phy_lib_h , chest_feedback_itf *chest_loop) { this->log_h = log_h; + this->log_phy_lib_h = log_phy_lib_h; + this->chest_loop = chest_loop; + // ue_sync in phy.cc requires a buffer for 3 subframes for (uint32_t i=0;iargs->nof_rx_ant;i++) { signal_buffer[i] = (cf_t*) srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(max_prb)); @@ -118,16 +122,18 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h) } } - if (srslte_ue_dl_init(&ue_dl, max_prb, phy->args->nof_rx_ant)) { + if (srslte_ue_dl_init(&ue_dl, signal_buffer, max_prb, phy->args->nof_rx_ant)) { Error("Initiating UE DL\n"); return false; } - if (srslte_ue_ul_init(&ue_ul, max_prb)) { + if (srslte_ue_ul_init(&ue_ul, signal_buffer[0], max_prb)) { Error("Initiating UE UL\n"); return false; } + srslte_chest_dl_average_subframe(&ue_dl.chest, phy->args->average_subframe_enabled); + srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, phy->args->cfo_ref_mask!=0, phy->args->cfo_ref_mask); srslte_ue_ul_set_normalization(&ue_ul, true); srslte_ue_ul_set_cfo_enable(&ue_ul, true); @@ -168,6 +174,9 @@ void phch_worker::set_tti(uint32_t tti_, uint32_t tx_tti_) tti = tti_; tx_tti = tx_tti_; log_h->step(tti); + log_phy_lib_h->step(tti); + + } void phch_worker::set_cfo(float cfo_) @@ -190,6 +199,11 @@ void phch_worker::set_crnti(uint16_t rnti) rnti_is_set = true; } +float phch_worker::get_ref_cfo() +{ + return srslte_chest_dl_get_cfo(&ue_dl.chest); +} + void phch_worker::work_imp() { if (!cell_initiated) { @@ -221,9 +235,15 @@ void phch_worker::work_imp() /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ bool chest_ok = extract_fft_and_pdcch_llr(); - bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>1.0; + bool snr_th_err = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))<-20.0; + bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>-15.0; - if (chest_ok && snr_th_ok) { + // Call feedback loop for chest + if (chest_loop && ((1<<(tti%10)) & phy->args->cfo_ref_mask)) { + chest_loop->set_cfo(srslte_chest_dl_get_cfo(&ue_dl.chest)); + } + + if (chest_ok && !snr_th_err) { /***** Downlink Processing *******/ @@ -257,41 +277,15 @@ void phch_worker::work_imp() if (dl_action.generate_ack) { set_uci_ack(dl_ack, dl_mac_grant.tb_en); } - - /* Select Rank Indicator by computing Condition Number */ - if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) { - if (ue_dl.nof_rx_antennas > 1) { - /* If 2 ort more receiving antennas, select RI */ - float cn = 0.0f; - srslte_ue_dl_ri_select(&ue_dl, &uci_data.uci_ri, &cn); - uci_data.uci_ri_len = 1; - } else { - /* If only one receiving antenna, force RI for 1 layer */ - uci_data.uci_ri = 0; - uci_data.uci_ri_len = 1; - Warning("Only one receiving antenna with TM3. Forcing RI=1 layer.\n"); - } - } else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4){ - float sinr = 0.0f; - uint8 packed_pmi = 0; - srslte_ue_dl_ri_pmi_select(&ue_dl, &uci_data.uci_ri, &packed_pmi, &sinr); - srslte_bit_unpack_vector(&packed_pmi, uci_data.uci_pmi, 2); - uci_data.uci_ri_len = 1; - if (uci_data.uci_ri == 0) { - uci_data.uci_pmi_len = 2; - uci_data.uci_dif_cqi_len = 0; - } else { - uci_data.uci_pmi_len = 1; - uci_data.uci_dif_cqi_len = 3; - } - - /* If only one antenna in TM4 print limitation warning */ - if (ue_dl.nof_rx_antennas < 2) { - Warning("Only one receiving antenna with TM4. Forcing RI=1 layer (PMI=%d).\n", packed_pmi); - } - } } } + + // Process RAR before UL to enable zero-delay Msg3 + bool rar_delivered = false; + if (HARQ_DELAY_MS == MSG3_DELAY_MS && dl_mac_grant.rnti_type == SRSLTE_RNTI_RAR) { + rar_delivered = true; + phy->mac->tb_decoded(dl_ack[0], 0, dl_mac_grant.rnti_type, dl_mac_grant.pid); + } // Decode PHICH bool ul_ack = false; @@ -313,11 +307,11 @@ void phch_worker::work_imp() set_uci_periodic_cqi(); } - /* TTI offset for UL is always 4 for LTE */ - ul_action.tti_offset = 4; + /* TTI offset for UL */ + ul_action.tti_offset = HARQ_DELAY_MS; /* Send UL grant or HARQ information (from PHICH) to MAC */ - if (ul_grant_available && ul_ack_available) { + if (ul_grant_available && ul_ack_available) { phy->mac->new_grant_ul_ack(ul_mac_grant, ul_ack, &ul_action); } else if (ul_grant_available && !ul_ack_available) { phy->mac->new_grant_ul(ul_mac_grant, &ul_action); @@ -335,10 +329,10 @@ void phch_worker::work_imp() &ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar); signal_ready = true; if (ul_action.expect_ack) { - phy->set_pending_ack(tti + 8, ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs); + phy->set_pending_ack(TTI_RX_ACK(tti), ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs); } - } else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0) { + } else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0 || uci_data.uci_ri_len > 0) { encode_pucch(); signal_ready = true; } else if (srs_is_ready_to_send()) { @@ -357,7 +351,7 @@ void phch_worker::work_imp() if (!dl_action.generate_ack_callback) { if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH && dl_action.decode_enabled[0]) { phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]); - } else { + } else if (!rar_delivered) { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { if (dl_action.decode_enabled[tb]) { phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); @@ -372,9 +366,10 @@ void phch_worker::work_imp() if (snr_th_ok) { phy->rrc->in_sync(); log_h->debug("SYNC: Sending in-sync to RRC\n"); - } else { + } else if (snr_th_err) { + chest_loop->out_of_sync(); phy->rrc->out_of_sync(); - log_h->debug("SNR=%.1f dB under threshold. Sending out-of-sync to RRC\n", + log_h->info("SNR=%.1f dB under threshold. Sending out-of-sync to RRC\n", 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))); } } @@ -387,13 +382,46 @@ void phch_worker::work_imp() #endif } +void phch_worker::compute_ri() { + if (uci_data.uci_ri_len > 0) { + /* Do nothing */ + } else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) { + if (ue_dl.nof_rx_antennas > 1) { + /* If 2 ort more receiving antennas, select RI */ + float cn = 0.0f; + srslte_ue_dl_ri_select(&ue_dl, &uci_data.uci_ri, &cn); + Info("RI select %d layers, κ=%fdB\n", uci_data.uci_ri + 1, cn); + } else { + /* If only one receiving antenna, force RI for 1 layer */ + uci_data.uci_ri = 0; + Warning("Only one receiving antenna with TM3. Forcing RI=1 layer.\n"); + } + uci_data.uci_ri_len = 1; + } else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { + float sinr = 0.0f; + uint8 packed_pmi = 0; + srslte_ue_dl_ri_pmi_select(&ue_dl, &uci_data.uci_ri, &packed_pmi, &sinr); + if (uci_data.uci_ri == 0) { + uci_data.uci_pmi_len = 2; + uci_data.uci_dif_cqi_len = 0; + } else { + uci_data.uci_pmi_len = 1; + uci_data.uci_dif_cqi_len = 3; + } + srslte_bit_unpack_vector(&packed_pmi, uci_data.uci_pmi, uci_data.uci_pmi_len); + Info("ri=%d; pmi=%d; SINR=%.1fdB\n", ue_dl.ri, ue_dl.pmi[ue_dl.ri], 10*log10f(ue_dl.sinr[ue_dl.ri][ue_dl.pmi[ue_dl.ri]])); + + /* If only one antenna in TM4 print limitation warning */ + if (ue_dl.nof_rx_antennas < 2) { + Warning("Only one receiving antenna with TM4. Forcing RI=1 layer (PMI=%d).\n", packed_pmi); + } + uci_data.uci_ri_len = 1; + } +} bool phch_worker::extract_fft_and_pdcch_llr() { - bool decode_pdcch = false; - if (phy->get_ul_rnti(tti) || phy->get_dl_rnti(tti) || phy->get_pending_rar(tti)) { - decode_pdcch = true; - } - + bool decode_pdcch = true; + /* Without a grant, we might need to do fft processing if need to decode PHICH */ if (phy->get_pending_ack(tti) || decode_pdcch) { @@ -413,7 +441,7 @@ bool phch_worker::extract_fft_and_pdcch_llr() { srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS); } - if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) { Error("Getting PDCCH FFT estimate\n"); return false; } @@ -472,10 +500,24 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) return false; } + grant->pid = ASYNC_DL_SCHED?dci_unpacked.harq_process:(UL_PIDOF(TTI_TX(tti))); + + // Set last TBS for this TB (pid) in case of mcs>28 (7.1.7.2 of 36.213) + for (int i=0;iphy_grant.dl.mcs[i].idx > 28) { + grant->phy_grant.dl.mcs[i].tbs = phy->last_dl_tbs[grant->pid][i]; + } + if(grant->phy_grant.dl.mcs[i].tbs < 0) { + Info("Invalid TBS size for PDSCH grant\n"); + grant->phy_grant.dl.mcs[i].tbs = 0; + } + // save it + phy->last_dl_tbs[grant->pid][i] = grant->phy_grant.dl.mcs[i].tbs; + } + /* Fill MAC grant structure */ grant->ndi[0] = dci_unpacked.ndi; grant->ndi[1] = dci_unpacked.ndi_1; - grant->pid = dci_unpacked.harq_process; grant->n_bytes[0] = grant->phy_grant.dl.mcs[0].tbs / (uint32_t) 8; grant->n_bytes[1] = grant->phy_grant.dl.mcs[1].tbs / (uint32_t) 8; grant->tti = tti; @@ -488,11 +530,6 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) grant->tb_en[1] = dci_unpacked.tb_en[1]; grant->tb_cw_swap = dci_unpacked.tb_cw_swap; // FIXME: tb_cw_swap not supported - if (grant->tb_cw_swap) { - Info("tb_cw_swap = true\n"); - printf("tb_cw_swap = true\n"); - } - last_dl_pdcch_ncce = srslte_ue_dl_get_ncce(&ue_dl); char hexstr[16]; @@ -524,14 +561,19 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { if (grant->tb_en[tb] && (rv[tb] < 0 || rv[tb] > 3)) { valid_config = false; - Error("Wrong RV (%d) for TB index %d", rv[tb], tb); + Error("Wrong RV (%d) for TB index %d\n", rv[tb], tb); } } + uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(grant); switch(phy->config->dedicated.antenna_info_explicit_value.tx_mode) { /* Implemented Tx Modes */ case LIBLTE_RRC_TRANSMISSION_MODE_1: mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + if (nof_tb != 1) { + Error("Wrong number of transport blocks (%d) for single antenna.", nof_tb); + valid_config = false; + } break; case LIBLTE_RRC_TRANSMISSION_MODE_2: if (cell.nof_ports > 1) { @@ -539,26 +581,30 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL } else { mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; } + if (nof_tb != 1) { + Error("Wrong number of transport blocks (%d) for transmit diversity.", nof_tb); + valid_config = false; + } break; case LIBLTE_RRC_TRANSMISSION_MODE_3: - if (SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 1) { + if (nof_tb == 1) { mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else if (ue_dl.nof_rx_antennas > 1 && SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 2) { + } else if (ue_dl.nof_rx_antennas > 1 && nof_tb == 2) { mimo_type = SRSLTE_MIMO_TYPE_CDD; } else { Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM3\n", ue_dl.nof_rx_antennas, - SRSLTE_RA_DL_GRANT_NOF_TB(grant)); + nof_tb); valid_config = false; } break; case LIBLTE_RRC_TRANSMISSION_MODE_4: - if (SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 1) { + if (nof_tb == 1) { mimo_type = (grant->pinfo == 0) ? SRSLTE_MIMO_TYPE_TX_DIVERSITY : SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - } else if (ue_dl.nof_rx_antennas > 1 && SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 2) { + } else if (ue_dl.nof_rx_antennas > 1 && nof_tb == 2) { mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; } else { Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM3\n", ue_dl.nof_rx_antennas, - SRSLTE_RA_DL_GRANT_NOF_TB(grant)); + nof_tb); valid_config = false; } break; @@ -578,12 +624,26 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL valid_config = false; } + /* Set power allocation according to 3GPP 36.213 clause 5.2 Downlink power allocation */ + float rho_a = 1.0f, rho_b = 1.0f; + if (phy->config->dedicated.pdsch_cnfg_ded < LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS) { + float rho_a_db = liblte_rrc_pdsch_config_p_a_num[(int) phy->config->dedicated.pdsch_cnfg_ded]; + rho_a = powf(10.0f, rho_a_db / 20.0f) * ((cell.nof_ports == 1) ? 1.0f : sqrtf(2.0f)); + } + if (phy->config->common.pdsch_cnfg.p_b < 4) { + uint32_t idx0 = (cell.nof_ports == 1) ? 0 : 1; + float cell_specific_ratio = pdsch_cfg_cell_specific_ratio_table[idx0][phy->config->common.pdsch_cnfg.p_b]; + rho_b = sqrtf(cell_specific_ratio); + } + srslte_ue_dl_set_power_alloc(&ue_dl, rho_a, rho_b); + Debug("DL Buffer TTI %d: Decoding PDSCH\n", tti); /* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */ if (valid_config) { if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, rv, mimo_type)) { - if (ue_dl.pdsch_cfg.grant.mcs[0].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[0].tbs >= 0) { + if ((ue_dl.pdsch_cfg.grant.mcs[0].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[0].tbs >= 0) || + (ue_dl.pdsch_cfg.grant.mcs[1].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[1].tbs >= 0)) { float noise_estimate = srslte_chest_dl_get_noise_estimate(&ue_dl.chest); @@ -612,12 +672,17 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec); #endif - snprintf(commonstr, 128, "PDSCH: l_crb=%2d, harq=%d, snr=%.1f dB", grant->nof_prb, harq_pid, - 10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest))); + char pinfo_str[16] = {0}; + if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { + snprintf(pinfo_str, 15, ", pinfo=%x", grant->pinfo); + } + + snprintf(commonstr, 128, "PDSCH: l_crb=%2d, harq=%d, snr=%.1f dB, tx_scheme=%s%s", grant->nof_prb, harq_pid, + 10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest)), srslte_mimotype2str(mimo_type), pinfo_str); for (int i=0;itb_en[i]) { - snprintf(tbstr[i], 128, ", TB%d: tbs=%d, mcs=%d, rv=%d, crc=%s, it=%d", + snprintf(tbstr[i], 128, ", CW%d: tbs=%d, mcs=%d, rv=%d, crc=%s, it=%d", i, grant->mcs[i].tbs/8, grant->mcs[i].idx, rv[i], acks[i] ? "OK" : "KO", srslte_pdsch_last_noi_cw(&ue_dl.pdsch, i)); } @@ -634,6 +699,9 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL Error("Error configuring DL grant\n"); ret = SRSLTE_ERROR; } + } else { + Error("Error invalid DL config\n"); + ret = SRSLTE_ERROR; } return ret; } @@ -663,7 +731,7 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant) char timestr[64]; timestr[0]='\0'; - phy->reset_pending_ack(tti + 8); + phy->reset_pending_ack(TTI_RX_ACK(tti)); srslte_dci_msg_t dci_msg; srslte_ra_ul_dci_t dci_unpacked; @@ -712,19 +780,35 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant) ue_dl.last_location_ul.ncce, (1<phy_grant.ul.mcs.tbs==0) { - srslte_vec_fprint_hex(stdout, dci_msg.data, dci_msg.nof_bits); + Info("Received PUSCH grant with empty data\n"); } } } - - /* Limit UL modulation if not supported by the UE or disabled by higher layers */ - if (!phy->config->enable_64qam) { - if (grant->phy_grant.ul.mcs.mod == SRSLTE_MOD_64QAM) { - grant->phy_grant.ul.mcs.mod = SRSLTE_MOD_16QAM; - grant->phy_grant.ul.Qm = 4; + + + // Handle Format0 adaptive retx + if (ret) { + // Use last TBS for this TB in case of mcs>28 + if (grant->phy_grant.ul.mcs.idx > 28) { + // Make sure we received a grant in the previous TTI for this PID + grant->phy_grant.ul.mcs.tbs = phy->last_ul_tbs[UL_PIDOF(TTI_TX(tti))]; + grant->phy_grant.ul.mcs.mod = phy->last_ul_mod[UL_PIDOF(TTI_TX(tti))]; + grant->phy_grant.ul.Qm = srslte_mod_bits_x_symbol(grant->phy_grant.ul.mcs.mod); } } - + if (ret) { + phy->last_ul_tbs[UL_PIDOF(TTI_TX(tti))] = grant->phy_grant.ul.mcs.tbs; + phy->last_ul_mod[UL_PIDOF(TTI_TX(tti))] = grant->phy_grant.ul.mcs.mod; + phy->last_ul_tti[UL_PIDOF(TTI_TX(tti))] = TTI_RX_ACK(tti); + /* Limit UL modulation if not supported by the UE or disabled by higher layers */ + if (!phy->config->enable_64qam) { + if (grant->phy_grant.ul.mcs.mod >= SRSLTE_MOD_64QAM) { + grant->phy_grant.ul.mcs.mod = SRSLTE_MOD_16QAM; + grant->phy_grant.ul.Qm = 4; + } + } + } + /* Make sure the grant is valid */ if (ret && !srslte_dft_precoding_valid_prb(grant->phy_grant.ul.L_prb) && grant->phy_grant.ul.L_prb <= cell.nof_prb) { Warning("Received invalid UL grant. L=%d\n", grant->phy_grant.ul.L_prb); @@ -741,11 +825,9 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant) if (SRSLTE_VERBOSE_ISINFO()) { srslte_ra_pusch_fprint(stdout, &dci_unpacked, cell.nof_prb); } - - return true; - } else { - return false; - } + } + + return ret; } void phch_worker::reset_uci() @@ -755,28 +837,22 @@ void phch_worker::reset_uci() void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_MAX_CODEWORDS]) { - uint32_t nof_tb = 0; - if (tb_en[0]) { - uci_data.uci_ack = (uint8_t) ((ack[0]) ? 1 : 0); - nof_tb = 1; - } else { - uci_data.uci_ack = 1; + /* Map ACK according to 3GPP 36.212 clause 5.2.3.1 */ + uint32_t nof_ack = 0; + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (tb_en[tb]) { + ((nof_ack == 0)?uci_data.uci_ack:uci_data.uci_ack_2) = (uint8_t)(ack[tb]?1:0); + nof_ack++; + } } - - if (tb_en[1]) { - uci_data.uci_ack_2 = (uint8_t) ((ack[1]) ? 1 : 0); - nof_tb = 2; - } - - uci_data.uci_ack_len = nof_tb; - + uci_data.uci_ack_len = nof_ack; } void phch_worker::set_uci_sr() { uci_data.scheduling_request = false; - if (phy->sr_enabled) { - uint32_t sr_tx_tti = (tti+4)%10240; + if (phy->sr_enabled && sr_configured) { + uint32_t sr_tx_tti = TTI_TX(tti); // Get I_sr parameter if (srslte_ue_ul_sr_send_tti(I_sr, sr_tx_tti)) { Info("PUCCH: SR transmission at TTI=%d, I_sr=%d\n", sr_tx_tti, I_sr); @@ -793,16 +869,13 @@ void phch_worker::set_uci_periodic_cqi() int cqi_max = phy->args->cqi_max; if (period_cqi.configured && rnti_is_set) { - if (period_cqi.ri_idx_present && srslte_ri_send(period_cqi.pmi_idx, period_cqi.ri_idx, (tti+4)%10240)) { - if (uci_data.uci_ri_len) { - uci_data.uci_cqi[0] = uci_data.uci_ri; - uci_data.uci_cqi_len = uci_data.uci_ri_len; - uci_data.uci_ri_len = 0; - uci_data.uci_dif_cqi_len = 0; - uci_data.uci_pmi_len = 0; - Info("PUCCH: Periodic RI=%d\n", uci_data.uci_cqi[0]); - } - } else if (srslte_cqi_send(period_cqi.pmi_idx, (tti+4)%10240)) { + if (period_cqi.ri_idx_present && srslte_ri_send(period_cqi.pmi_idx, period_cqi.ri_idx, TTI_TX(tti))) { + /* Compute RI, PMI and SINR */ + compute_ri(); + + uci_data.ri_periodic_report = true; + Info("PUCCH: Periodic RI=%d\n", uci_data.uci_ri); + } else if (srslte_cqi_send(period_cqi.pmi_idx, TTI_TX(tti))) { srslte_cqi_value_t cqi_report; if (period_cqi.format_is_subband) { // TODO: Implement subband periodic reports @@ -823,6 +896,16 @@ void phch_worker::set_uci_periodic_cqi() } Info("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db); } + if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { + if (ue_dl.ri == 0) { + uci_data.uci_pmi_len = 2; + } else { + uci_data.uci_pmi_len = 1; + uci_data.uci_dif_cqi_len = 3; + } + uint8_t *ptr = uci_data.uci_pmi; + srslte_bit_unpack(ue_dl.pmi[ue_dl.ri], &ptr, uci_data.uci_pmi_len); + } uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); rar_cqi_request = false; } @@ -832,6 +915,9 @@ void phch_worker::set_uci_periodic_cqi() void phch_worker::set_uci_aperiodic_cqi() { if (phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic_present) { + /* Compute RI, PMI and SINR */ + compute_ri(); + switch(phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic) { case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30: /* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1 @@ -844,18 +930,68 @@ void phch_worker::set_uci_aperiodic_cqi() reported RI. For other transmission modes they are reported conditioned on rank 1. */ if (rnti_is_set) { - srslte_cqi_value_t cqi_report; + srslte_cqi_value_t cqi_report = {0}; cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL; - cqi_report.subband_hl.wideband_cqi = srslte_cqi_from_snr(phy->avg_snr_db); + cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(phy->avg_snr_db); // TODO: implement subband CQI properly - cqi_report.subband_hl.subband_diff_cqi = 0; // Always report zero offset on all subbands + cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands cqi_report.subband_hl.N = (cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(cell.nof_prb) : 0; Info("PUSCH: Aperiodic CQI=%d, SNR=%.1f dB, for %d subbands\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db, cqi_report.subband_hl.N); uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); } break; + case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31: + /* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1 + - A single precoding matrix is selected from the codebook subset assuming transmission on set S subbands + - A UE shall report one subband CQI value per codeword for each set S subband which are calculated assuming + the use of the single precoding matrix in all subbands and assuming transmission in the corresponding + subband. + - A UE shall report a wideband CQI value per codeword which is calculated assuming the use of the single + precoding matrix in all subbands and transmission on set S subbands + - The UE shall report the single selected precoding matrix indicator. + - For transmission mode 4 the reported PMI and CQI values are calculated conditioned on the reported RI. For + other transmission modes they are reported conditioned on rank 1. + */ + if (rnti_is_set) { + /* Select RI, PMI and SINR */ + uint32_t ri = ue_dl.ri; // Select RI (0: 1 layer, 1: 2 layer, otherwise: not implemented) + uint32_t pmi = ue_dl.pmi[ri]; // Select PMI + float sinr_db = 10 * log10(ue_dl.sinr[ri][pmi]); + + /* Fill CQI Report */ + srslte_cqi_value_t cqi_report = {0}; + cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL; + + cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(sinr_db); + cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands + + if (ri > 0) { + cqi_report.subband_hl.rank_is_not_one = true; + cqi_report.subband_hl.wideband_cqi_cw1 = srslte_cqi_from_snr(sinr_db); + cqi_report.subband_hl.subband_diff_cqi_cw1 = 0; // Always report zero offset on all subbands + } + + cqi_report.subband_hl.pmi = pmi; + cqi_report.subband_hl.pmi_present = true; + cqi_report.subband_hl.four_antenna_ports = (cell.nof_ports == 4); + + // TODO: implement subband CQI properly + cqi_report.subband_hl.N = (uint32_t) ((cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(cell.nof_prb) : 0); + + if (cqi_report.subband_hl.rank_is_not_one) { + Info("PUSCH: Aperiodic ri~1, CQI=%02d/%02d, SINR=%2.1f/%2.1fdB, pmi=%d for %d subbands\n", + cqi_report.subband_hl.wideband_cqi_cw0, cqi_report.subband_hl.wideband_cqi_cw1, + sinr_db, sinr_db, pmi, cqi_report.subband_hl.N); + } else { + Info("PUSCH: Aperiodic ri=1, CQI=%02d, SINR=%2.1f, pmi=%d for %d subbands\n", + cqi_report.subband_hl.wideband_cqi_cw0, + sinr_db, pmi, cqi_report.subband_hl.N); + } + uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); + } + break; default: Warning("Received CQI request but mode %s is not supported\n", liblte_rrc_cqi_report_mode_aperiodic_text[phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic]); @@ -868,8 +1004,8 @@ void phch_worker::set_uci_aperiodic_cqi() bool phch_worker::srs_is_ready_to_send() { if (srs_cfg.configured) { - if (srslte_refsignal_srs_send_cs(srs_cfg.subframe_config, (tti+4)%10) == 1 && - srslte_refsignal_srs_send_ue(srs_cfg.I_srs, (tti+4)%10240) == 1) + if (srslte_refsignal_srs_send_cs(srs_cfg.subframe_config, TTI_TX(tti)%10) == 1 && + srslte_refsignal_srs_send_ue(srs_cfg.I_srs, TTI_TX(tti)) == 1) { return true; } @@ -889,10 +1025,10 @@ void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, ui char timestr[64]; timestr[0]='\0'; - if (srslte_ue_ul_cfg_grant(&ue_ul, grant, (tti+4)%10240, rv, current_tx_nb)) { + if (srslte_ue_ul_cfg_grant(&ue_ul, grant, TTI_TX(tti), rv, current_tx_nb)) { Error("Configuring UL grant\n"); } - + if (srslte_ue_ul_pusch_encode_rnti_softbuffer(&ue_ul, payload, uci_data, softbuffer, @@ -918,13 +1054,14 @@ void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, ui snprintf(timestr, 64, ", tot_time=%4d us", (int) logtime_start[0].tv_usec); #endif - Info("PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d, ack=%s, ri=%s, cfo=%.1f KHz%s\n", - (tti+4)%10240, - grant->n_prb[0], grant->n_prb[0]+grant->L_prb, - grant->mcs.tbs/8, grant->mcs.idx, rv, - uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no", - uci_data.uci_ri_len>0?(uci_data.uci_ri?"1":"0"):"no", - cfo*15, timestr); + uint8_t dummy[2] = {0,0}; + log_h->info("PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d, ack=%s, ri=%s, cfo=%.1f KHz%s\n", + (tti+HARQ_DELAY_MS)%10240, + grant->n_prb[0], grant->n_prb[0]+grant->L_prb, + grant->mcs.tbs/8, grant->mcs.idx, rv, + uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no", + uci_data.uci_ri_len>0?(uci_data.uci_ri?"1":"0"):"no", + cfo*15, timestr); // Store metrics ul_metrics.mcs = grant->mcs.idx; @@ -937,7 +1074,7 @@ void phch_worker::encode_pucch() char timestr[64]; timestr[0]='\0'; - if (uci_data.scheduling_request || uci_data.uci_ack_len > 0 || uci_data.uci_cqi_len > 0) + if (uci_data.scheduling_request || uci_data.uci_ack_len > 0 || uci_data.uci_cqi_len > 0 || uci_data.uci_ri_len > 0) { // Drop CQI if there is collision with ACK @@ -950,7 +1087,7 @@ void phch_worker::encode_pucch() gettimeofday(&t[1], NULL); #endif - if (srslte_ue_ul_pucch_encode(&ue_ul, uci_data, last_dl_pdcch_ncce, (tti+4)%10240, signal_buffer[0])) { + if (srslte_ue_ul_pucch_encode(&ue_ul, uci_data, last_dl_pdcch_ncce, TTI_TX(tti), signal_buffer[0])) { Error("Encoding PUCCH\n"); } @@ -975,7 +1112,7 @@ void phch_worker::encode_pucch() uci_data.uci_pmi_len>0?(uci_data.uci_pmi[0]?"1":"0"):"", uci_data.scheduling_request?"yes":"no", cfo*15, timestr); - } + } if (uci_data.scheduling_request) { phy->sr_enabled = false; @@ -987,7 +1124,7 @@ void phch_worker::encode_srs() char timestr[64]; timestr[0]='\0'; - if (srslte_ue_ul_srs_encode(&ue_ul, (tti+4)%10240, signal_buffer[0])) + if (srslte_ue_ul_srs_encode(&ue_ul, TTI_TX(tti), signal_buffer[0])) { Error("Encoding SRS\n"); } @@ -1002,7 +1139,7 @@ void phch_worker::encode_srs() float gain = set_power(tx_power); uint32_t fi = srslte_vec_max_fi((float*) signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb)); float *f = (float*) signal_buffer; - Info("SRS: power=%.2f dBm, tti_tx=%d%s\n", tx_power, (tti+4)%10240, timestr); + Info("SRS: power=%.2f dBm, tti_tx=%d%s\n", tx_power, TTI_TX(tti), timestr); } @@ -1118,7 +1255,7 @@ void phch_worker::set_ul_params(bool pregen_disabled) /* SR configuration */ I_sr = dedicated->sched_request_cnfg.sr_cnfg_idx; - + sr_configured = true; if (pregen_enabled && !pregen_disabled) { Info("Pre-generating UL signals worker=%d\n", get_id()); @@ -1184,55 +1321,53 @@ void phch_worker::update_measurements() { float snr_ema_coeff = phy->args->snr_ema_coeff; if (chest_done) { - /* Compute ADC/RX gain offset every 20 ms */ - if ((tti%20) == 0 || phy->rx_gain_offset == 0) { + /* Compute ADC/RX gain offset every ~10s */ + if (tti== 0 || phy->rx_gain_offset == 0) { float rx_gain_offset = 0; if (phy->get_radio()->has_rssi() && phy->args->rssi_sensor_enabled) { - float rssi_all_signal = srslte_chest_dl_get_rssi(&ue_dl.chest); - if (rssi_all_signal) { - rx_gain_offset = 10*log10(rssi_all_signal)-phy->get_radio()->get_rssi(); - } else { - rx_gain_offset = 0; - } + float rssi_all_signal = 30+10*log10(srslte_vec_avg_power_cf(signal_buffer[0],SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb)))); + rx_gain_offset = 30+rssi_all_signal-phy->get_radio()->get_rssi(); } else { rx_gain_offset = phy->get_radio()->get_rx_gain(); } if (phy->rx_gain_offset) { - phy->rx_gain_offset = SRSLTE_VEC_EMA(phy->rx_gain_offset, rx_gain_offset, 0.1); + phy->rx_gain_offset = SRSLTE_VEC_EMA(rx_gain_offset, phy->rx_gain_offset, 0.5); } else { phy->rx_gain_offset = rx_gain_offset; } } // Average RSRQ - float cur_rsrq = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest)); - if (isnormal(cur_rsrq)) { - phy->avg_rsrq_db = SRSLTE_VEC_EMA(phy->avg_rsrq_db, cur_rsrq, snr_ema_coeff); + float rsrq_db = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest)); + if (isnormal(rsrq_db)) { + phy->avg_rsrq_db = SRSLTE_VEC_EMA(rsrq_db, phy->avg_rsrq_db, snr_ema_coeff); } - + // Average RSRP - float cur_rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest); - if (isnormal(cur_rsrp)) { - phy->avg_rsrp = SRSLTE_VEC_EMA(phy->avg_rsrp, cur_rsrp, snr_ema_coeff); + float rsrp_lin = srslte_chest_dl_get_rsrp(&ue_dl.chest); + if (isnormal(rsrp_lin)) { + phy->avg_rsrp = SRSLTE_VEC_EMA(rsrp_lin, phy->avg_rsrp, snr_ema_coeff); } /* Correct absolute power measurements by RX gain offset */ - float rsrp = 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest)) + 30 - phy->rx_gain_offset; - float rssi = 10*log10(srslte_chest_dl_get_rssi(&ue_dl.chest)) + 30 - phy->rx_gain_offset; - - // TODO: Send UE measurements to RRC where filtering is done. Now do filtering here - if (isnormal(rsrp)) { - if (!phy->avg_rsrp_db) { - phy->avg_rsrp_db = rsrp; + float rsrp_dbm = 10*log10(rsrp_lin) + 30 - phy->rx_gain_offset; + float rssi_db = 10*log10(srslte_chest_dl_get_rssi(&ue_dl.chest)) + 30 - phy->rx_gain_offset; + + // Serving cell measurements are averaged over DEFAULT_MEAS_PERIOD_MS then sent to RRC + if (isnormal(rsrp_dbm)) { + if (!phy->avg_rsrp_dbm) { + phy->avg_rsrp_dbm= rsrp_dbm; } else { - uint32_t k = 4; // Set by RRC reconfiguration message - float coeff = pow(0.5,(float) k/4); - phy->avg_rsrp_db = SRSLTE_VEC_EMA(phy->avg_rsrp_db, rsrp, coeff); - } + phy->avg_rsrp_dbm = SRSLTE_VEC_EMA(rsrp_dbm, phy->avg_rsrp_dbm, snr_ema_coeff); + } + if ((tti%phy->pcell_report_period) == 0 && phy->pcell_meas_enabled) { + phy->rrc->new_phy_meas(phy->avg_rsrp_dbm, phy->avg_rsrq_db, tti); + } } + // Compute PL float tx_crs_power = phy->config->common.pdsch_cnfg.rs_power; - phy->pathloss = tx_crs_power - phy->avg_rsrp_db; + phy->pathloss = tx_crs_power - phy->avg_rsrp_dbm; // Average noise float cur_noise = srslte_chest_dl_get_noise_estimate(&ue_dl.chest); @@ -1240,18 +1375,18 @@ void phch_worker::update_measurements() if (!phy->avg_noise) { phy->avg_noise = cur_noise; } else { - phy->avg_noise = SRSLTE_VEC_EMA(phy->avg_noise, cur_noise, snr_ema_coeff); + phy->avg_noise = SRSLTE_VEC_EMA(cur_noise, phy->avg_noise, snr_ema_coeff); } } // Compute SNR - phy->avg_snr_db = 10*log10(phy->avg_rsrp/phy->avg_noise); + phy->avg_snr_db = 10*log10(phy->avg_rsrp/phy->avg_noise); // Store metrics dl_metrics.n = phy->avg_noise; - dl_metrics.rsrp = phy->avg_rsrp_db; + dl_metrics.rsrp = phy->avg_rsrp_dbm; dl_metrics.rsrq = phy->avg_rsrq_db; - dl_metrics.rssi = rssi; + dl_metrics.rssi = rssi_db; dl_metrics.pathloss = phy->pathloss; dl_metrics.sinr = phy->avg_snr_db; dl_metrics.turbo_iters = srslte_pdsch_last_noi(&ue_dl.pdsch); diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index e74107661..0763b09cb 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -37,12 +37,11 @@ #include "srslte/common/threads.h" #include "srslte/common/log.h" #include "phy/phy.h" -#include "phy/phch_worker.h" -#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) @@ -57,6 +56,31 @@ phy::phy() : workers_pool(MAX_WORKERS), { } +static void srslte_phy_handler(phy_logger_level_t log_level, void *ctx, char *str) { + phy *r = (phy *) ctx; + r->srslte_phy_logger(log_level, str); +} + +void phy::srslte_phy_logger(phy_logger_level_t log_level, char *str) { + if (log_phy_lib_h) { + switch(log_level){ + case LOG_LEVEL_INFO: + log_phy_lib_h->info(" %s", str); + break; + case LOG_LEVEL_DEBUG: + log_phy_lib_h->debug(" %s", str); + break; + case LOG_LEVEL_ERROR: + log_phy_lib_h->error(" %s", str); + break; + default: + break; + } + } else { + printf("[PHY_LIB]: %s\n", str); + } +} + void phy::set_default_args(phy_args_t *args) { args->nof_rx_ant = 1; @@ -106,7 +130,7 @@ bool phy::init(srslte::radio_multi* radio_handler, mac_interface_phy *mac, rrc_i this->radio_handler = radio_handler; this->mac = mac; this->rrc = rrc; - + if (!phy_args) { args = &default_args; set_default_args(args); @@ -119,7 +143,9 @@ bool phy::init(srslte::radio_multi* radio_handler, mac_interface_phy *mac, rrc_i } nof_workers = args->nof_phy_threads; - + this->log_phy_lib_h = (srslte::log*) log_vec[nof_workers]; + srslte_phy_log_register_handler(this, srslte_phy_handler); + initiated = false; start(); return true; @@ -134,12 +160,12 @@ void phy::run_thread() { // Add workers to workers pool and start threads for (uint32_t i=0;iworker_cpu_mask); } // Warning this must be initialized after all workers have been added to the pool - sf_recv.init(radio_handler, mac, rrc, &prach_buffer, &workers_pool, &workers_common, log_h, args->nof_rx_ant, SF_RECV_THREAD_PRIO, args->sync_cpu_affinity); + sf_recv.init(radio_handler, mac, rrc, &prach_buffer, &workers_pool, &workers_common, log_h, log_phy_lib_h, args->nof_rx_ant, SF_RECV_THREAD_PRIO, args->sync_cpu_affinity); // Disable UL signal pregeneration until the attachment enable_pregen_signals(false); @@ -199,22 +225,19 @@ void phy::set_timeadv_rar(uint32_t ta_cmd) { } void phy::set_timeadv(uint32_t ta_cmd) { - n_ta = srslte_N_ta_new(n_ta, ta_cmd); - //sf_recv.set_time_adv_sec(((float) n_ta)*SRSLTE_LTE_TS); - Warning("Not supported: Set TA: ta_cmd: %d, n_ta: %d, ta_usec: %.1f\n", ta_cmd, n_ta, ((float) n_ta)*SRSLTE_LTE_TS*1e6); + uint32_t new_nta = srslte_N_ta_new(n_ta, ta_cmd); + sf_recv.set_time_adv_sec(((float) (new_nta - n_ta))*SRSLTE_LTE_TS); + Info("PHY: Set TA: ta_cmd: %d, n_ta: %d, old_n_ta: %d, ta_usec: %.1f\n", ta_cmd, new_nta, n_ta, ((float) new_nta)*SRSLTE_LTE_TS*1e6); + n_ta = new_nta; } void phy::configure_prach_params() { - if (sf_recv.status_is_sync()) { - Debug("Configuring PRACH parameters\n"); - srslte_cell_t cell; - sf_recv.get_current_cell(&cell); - if (!prach_buffer.set_cell(cell)) { - Error("Configuring PRACH parameters\n"); - } - } else { - Error("Cell is not synchronized\n"); + Debug("Configuring PRACH parameters\n"); + srslte_cell_t cell; + sf_recv.get_current_cell(&cell); + if (!prach_buffer.set_cell(cell)) { + Error("Configuring PRACH parameters\n"); } } @@ -247,11 +270,27 @@ void phy::sync_reset() { sf_recv.reset_sync(); } +void phy::meas_reset() { + sf_recv.meas_reset(); +} + +int phy::meas_start(uint32_t earfcn, int pci) { + return sf_recv.meas_start(earfcn, pci); +} + +int phy::meas_stop(uint32_t earfcn, int pci) { + return sf_recv.meas_stop(earfcn, pci); +} + bool phy::cell_select(uint32_t earfcn, srslte_cell_t phy_cell) { return sf_recv.cell_select(earfcn, phy_cell); } +bool phy::cell_handover(srslte_cell_t cell) { + return sf_recv.cell_handover(cell); +} + float phy::get_phr() { float phr = radio_handler->get_max_tx_power() - workers_common.cur_pusch_power; @@ -283,9 +322,21 @@ void phy::pdcch_ul_search_reset() workers_common.set_ul_rnti(SRSLTE_RNTI_USER, 0); } -void phy::get_current_cell(srslte_cell_t *cell) +void phy::get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn) { - sf_recv.get_current_cell(cell); + sf_recv.get_current_cell(cell, current_earfcn); +} + +uint32_t phy::get_current_pci() { + srslte_cell_t cell; + sf_recv.get_current_cell(&cell); + return cell.id; +} + +uint32_t phy::get_current_earfcn() { + uint32_t earfcn; + sf_recv.get_current_cell(NULL, &earfcn); + return earfcn; } void phy::prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) @@ -308,7 +359,10 @@ void phy::reset() pdcch_dl_search_reset(); for(uint32_t i=0;i earfcns) sf_recv.set_earfcn(earfcns); } +void phy::force_freq(float dl_freq, float ul_freq) +{ + sf_recv.force_freq(dl_freq, ul_freq); +} + bool phy::sync_status() { return sf_recv.status_is_sync(); diff --git a/srsue/src/phy/prach.cc b/srsue/src/phy/prach.cc index 7c693fe7a..498ea1c6a 100644 --- a/srsue/src/phy/prach.cc +++ b/srsue/src/phy/prach.cc @@ -34,10 +34,10 @@ #include "phy/phy.h" #include "srslte/interfaces/ue_interfaces.h" -#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) namespace srsue { @@ -75,7 +75,7 @@ void prach::init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config_, uint32_t max_prb, return; } srslte_cfo_set_tol(&cfo_h, 0); - signal_buffer = (cf_t*) srslte_vec_malloc(SRSLTE_PRACH_MAX_LEN*sizeof(cf_t)); + signal_buffer = (cf_t *) srslte_vec_malloc(SRSLTE_PRACH_MAX_LEN * sizeof(cf_t)); if (!signal_buffer) { perror("malloc"); return; @@ -181,8 +181,8 @@ void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte // Get current TX gain float old_gain = radio_handler->get_tx_gain(); - // Correct CFO before transmission - srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb)); + // Correct CFO before transmission FIXME: UL SISO Only + srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb)); // If power control is enabled, choose amplitude and power if (args->ul_pwr_ctrl_en) { @@ -207,8 +207,9 @@ void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte } Debug("TX PRACH: Power control for PRACH is disabled, setting gain to %.0f dB\n", prach_gain); } - - radio_handler->tx(signal_buffer, len, tx_time); + + void *tmp_buffer[SRSLTE_MAX_PORTS] = {signal_buffer, NULL, NULL, NULL}; + radio_handler->tx(tmp_buffer, len, tx_time); radio_handler->tx_end(); Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, tx_time=%f\n", diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 92adaf8dd..8f10a5bfc 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -32,7 +32,6 @@ #include #include #include -#include using namespace srslte; @@ -58,6 +57,7 @@ bool ue::init(all_args_t *args_) } else { logger_file.init(args->log.filename); logger_file.log("\n\n"); + logger_file.log(get_build_string().c_str()); logger = &logger_file; } @@ -84,6 +84,16 @@ bool ue::init(all_args_t *args_) for (int i=0;iexpert.phy.nof_phy_threads;i++) { ((srslte::log_filter*) phy_log[i])->set_level(level(args->log.phy_level)); } + + /* here we add a log layer to handle logging from the phy library*/ + srslte::log_filter *lib_log = new srslte::log_filter; + char tmp[16]; + sprintf(tmp, "PHY_LIB"); + lib_log->init(tmp, logger, true); + phy_log.push_back((void*) lib_log); + ((srslte::log_filter*) phy_log[args->expert.phy.nof_phy_threads])->set_level(level(args->log.phy_lib_level)); + + mac_log.set_level(level(args->log.mac_level)); rlc_log.set_level(level(args->log.rlc_level)); pdcp_log.set_level(level(args->log.pdcp_level)); @@ -92,7 +102,7 @@ bool ue::init(all_args_t *args_) gw_log.set_level(level(args->log.gw_level)); usim_log.set_level(level(args->log.usim_level)); - for (int i=0;iexpert.phy.nof_phy_threads;i++) { + for (int i=0;iexpert.phy.nof_phy_threads + 1;i++) { ((srslte::log_filter*) phy_log[i])->set_hex_limit(args->log.phy_hex_limit); } mac_log.set_hex_limit(args->log.mac_hex_limit); @@ -104,20 +114,26 @@ bool ue::init(all_args_t *args_) usim_log.set_hex_limit(args->log.usim_hex_limit); // Set up pcap and trace - if(args->pcap.enable) - { + if(args->pcap.enable) { mac_pcap.open(args->pcap.filename.c_str()); mac.start_pcap(&mac_pcap); } - if(args->trace.enable) - { + if(args->pcap.nas_enable) { + nas_pcap.open(args->pcap.nas_filename.c_str()); + nas.start_pcap(&nas_pcap); + } + if(args->trace.enable) { phy.start_trace(); radio.start_trace(); } // Init layers - // PHY initis in background, start before radio + if (args->rf.rx_gain < 0) { + phy.set_agc_enable(true); + } + + // PHY initis in background, start before radio args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant; phy.init(&radio, &mac, &rrc, phy_log, &args->expert.phy); @@ -133,8 +149,7 @@ bool ue::init(all_args_t *args_) } printf("Opening RF device with %d RX antennas...\n", args->rf.nof_rx_ant); - if(!radio.init_multi(args->rf.nof_rx_ant, dev_args, dev_name)) - { + if(!radio.init_multi(args->rf.nof_rx_ant, dev_args, dev_name)) { printf("Failed to find device %s with args %s\n", args->rf.device_name.c_str(), args->rf.device_args.c_str()); return false; @@ -160,8 +175,6 @@ bool ue::init(all_args_t *args_) if (args->rf.rx_gain < 0) { radio.start_agc(false); - radio.set_tx_rx_gain_offset(10); - phy.set_agc_enable(true); } else { radio.set_rx_gain(args->rf.rx_gain); } @@ -185,14 +198,25 @@ bool ue::init(all_args_t *args_) nas.init(&usim, &rrc, &gw, &nas_log, 1 /* RB_ID_SRB1 */); gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */); + gw.set_netmask(args->expert.ip_netmask); + rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log); - rrc.set_ue_category(atoi(args->expert.ue_cateogry.c_str())); + + // Get current band from provided EARFCN + args->rrc.supported_bands[0] = srslte_band_get_band(args->rf.dl_earfcn); + args->rrc.nof_supported_bands = 1; + args->rrc.ue_category = atoi(args->ue_category_str.c_str()); + rrc.set_args(&args->rrc); // Currently EARFCN list is set to only one frequency as indicated in ue.conf std::vector earfcn_list; earfcn_list.push_back(args->rf.dl_earfcn); phy.set_earfcn(earfcn_list); + if (args->rf.dl_freq > 0 && args->rf.ul_freq > 0) { + phy.force_freq(args->rf.dl_freq, args->rf.ul_freq); + } + printf("Waiting PHY to initialize...\n"); phy.wait_initialize(); phy.configure_ul_params(); @@ -231,12 +255,13 @@ void ue::stop() radio.stop(); usleep(1e5); - if(args->pcap.enable) - { + if(args->pcap.enable) { mac_pcap.close(); } - if(args->trace.enable) - { + if(args->pcap.nas_enable) { + nas_pcap.close(); + } + if(args->trace.enable) { phy.write_trace(args->trace.phy_filename); radio.write_trace(args->trace.radio_filename); } diff --git a/srsue/src/ue_base.cc b/srsue/src/ue_base.cc index 94b9b5155..4b2c372ae 100644 --- a/srsue/src/ue_base.cc +++ b/srsue/src/ue_base.cc @@ -24,13 +24,14 @@ * */ - #include "ue_base.h" #include "ue.h" #include "srslte/srslte.h" +#include "srslte/build_info.h" #include #include #include +#include #include #include @@ -58,6 +59,9 @@ ue_base* ue_base::get_instance(srsue_instance_type_t type) } ue_base::ue_base() { + // print build info + std::cout << std::endl << get_build_string() << std::endl; + // load FFTW wisdom srslte_dft_load(); } @@ -116,4 +120,21 @@ srslte::LOG_LEVEL_ENUM ue_base::level(std::string l) } } +std::string ue_base::get_build_mode() +{ + return std::string(srslte_get_build_mode()); +} + +std::string ue_base::get_build_info() +{ + return std::string(srslte_get_build_info()); +} + +std::string ue_base::get_build_string() +{ + std::stringstream ss; + ss << "Built in " << get_build_mode() << " mode using " << get_build_info() << "." << std::endl; + return ss.str(); +} + } // namespace srsue diff --git a/srsue/src/upper/gw.cc b/srsue/src/upper/gw.cc index 07ac36989..1e3e81999 100644 --- a/srsue/src/upper/gw.cc +++ b/srsue/src/upper/gw.cc @@ -44,6 +44,7 @@ gw::gw() :if_up(false) { current_ip_addr = 0; + default_netmask = true; } void gw::init(pdcp_interface_gw *pdcp_, nas_interface_gw *nas_, srslte::log *gw_log_, uint32_t lcid_) @@ -104,6 +105,12 @@ void gw::get_metrics(gw_metrics_t &m) ul_tput_bytes = 0; } +void gw::set_netmask(std::string netmask) { + default_netmask = false; + this->netmask = netmask; +} + + /******************************************************************************* PDCP interface *******************************************************************************/ @@ -152,7 +159,11 @@ srslte::error_t gw::setup_if_addr(uint32_t ip_addr, char *err_str) return(srslte::ERROR_CANT_START); } ifr.ifr_netmask.sa_family = AF_INET; - ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0"); + const char *mask = "255.255.255.0"; + if (!default_netmask) { + mask = netmask.c_str(); + } + ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr(mask); if(0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) { err_str = strerror(errno); diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index f0fd8cf54..1fb26c177 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -25,17 +25,31 @@ */ +#include +#include +#include +#include +#include #include "srslte/asn1/liblte_rrc.h" #include "upper/nas.h" +#include "srslte/common/security.h" #include "srslte/common/bcd_helpers.h" using namespace srslte; namespace srsue { + +/********************************************************************* + * NAS + ********************************************************************/ + nas::nas() - : state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), is_guti_set(false), ip_addr(0), eps_bearer_id(0), - count_ul(0), count_dl(0) {} + : state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), have_guti(false), have_ctxt(false), ip_addr(0), eps_bearer_id(0) +{ + ctxt.rx_count = 0; + ctxt.tx_count = 0; +} void nas::init(usim_interface_nas *usim_, rrc_interface_nas *rrc_, @@ -51,23 +65,34 @@ void nas::init(usim_interface_nas *usim_, state = EMM_STATE_DEREGISTERED; plmn_selection = PLMN_NOT_SELECTED; - if (usim->get_home_plmn_id(&home_plmn)) { + if (!usim->get_home_plmn_id(&home_plmn)) { nas_log->error("Getting Home PLMN Id from USIM. Defaulting to 001-01\n"); home_plmn.mcc = 61441; // This is 001 home_plmn.mnc = 65281; // This is 01 } cfg = cfg_; + + if((read_ctxt_file(&ctxt))) { + usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, + ctxt.cipher_algo, ctxt.integ_algo); + nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc"); + nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int"); + have_guti = true; + have_ctxt = true; + } } -void nas::stop() {} +void nas::stop() { + write_ctxt_file(ctxt); +} emm_state_t nas::get_state() { return state; } /******************************************************************************* -UE interface -*******************************************************************************/ + * UE interface + ******************************************************************************/ void nas::attach_request() { nas_log->info("Attach Request\n"); @@ -84,7 +109,6 @@ void nas::attach_request() { } else if (state == EMM_STATE_REGISTERED) { nas_log->info("NAS state is registered, connecting to same PLMN\n"); rrc->plmn_select(current_plmn); - selecting_plmn = current_plmn; } else { nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]); } @@ -96,11 +120,16 @@ void nas::deattach_request() { } /******************************************************************************* -RRC interface -*******************************************************************************/ + * RRC interface + ******************************************************************************/ void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) { + // Do not process new PLMN if already selected + if (plmn_selection == PLMN_SELECTED) { + return; + } + // Check if already registered for (uint32_t i=0;iinfo_hex(pdu->msg, pdu->N_bytes, "DL %s PDU", rrc->get_rb_name(lcid).c_str()); + nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s PDU", get_rb_name(lcid)); - // Parse the message + // Parse the message security header + liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*)pdu, &pd, &sec_hdr_type); + switch(sec_hdr_type) + { + case LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS: + case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT: + case LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST: + case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY: + break; + case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED: + mac_valid = integrity_check(pdu); + cipher_decrypt(pdu); + break; + case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT: + break; + default: + nas_log->error("Not handling NAS message with SEC_HDR_TYPE=%02X\n",msg_type); + pool->deallocate(pdu); + break; + } + + // Write NAS pcap + if(pcap != NULL) { + pcap->write_nas(pdu->msg, pdu->N_bytes); + } + + // Parse the message header liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT *) pdu, &pd, &msg_type); + nas_log->info_hex(pdu->msg, pdu->N_bytes, "DL %s Decrypted PDU", get_rb_name(lcid)); + // TODO: Check if message type requieres specical security header type and if it isvalid + switch (msg_type) { case LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT: parse_attach_accept(lcid, pdu); @@ -207,37 +267,59 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { } uint32_t nas::get_ul_count() { - return count_ul; + return ctxt.tx_count; } bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) { - if (is_guti_set) { - s_tmsi->mmec = guti.mme_code; - s_tmsi->m_tmsi = guti.m_tmsi; + if (have_guti) { + s_tmsi->mmec = ctxt.guti.mme_code; + s_tmsi->m_tmsi = ctxt.guti.m_tmsi; return true; } else { return false; } } +bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) { + if(!have_ctxt) { + nas_log->error("K_asme requested before security context established\n"); + return false; + } + if(NULL == k_asme_ || n < 32) { + nas_log->error("Invalid parameters to get_k_asme"); + return false; + } + + memcpy(k_asme_, ctxt.k_asme, 32); + return true; +} + /******************************************************************************* -Security + PCAP *******************************************************************************/ +void nas::start_pcap(srslte::nas_pcap *pcap_) +{ + pcap = pcap_; +} + +/******************************************************************************* + * Security + ******************************************************************************/ + void nas::integrity_generate(uint8_t *key_128, uint32_t count, - uint8_t rb_id, uint8_t direction, uint8_t *msg, uint32_t msg_len, uint8_t *mac) { - switch (integ_algo) { + switch (ctxt.integ_algo) { case INTEGRITY_ALGORITHM_ID_EIA0: break; case INTEGRITY_ALGORITHM_ID_128_EIA1: security_128_eia1(key_128, count, - rb_id, + 0, // Bearer always 0 for NAS direction, msg, msg_len, @@ -246,7 +328,7 @@ void nas::integrity_generate(uint8_t *key_128, case INTEGRITY_ALGORITHM_ID_128_EIA2: security_128_eia2(key_128, count, - rb_id, + 0, // Bearer always 0 for NAS direction, msg, msg_len, @@ -257,22 +339,118 @@ void nas::integrity_generate(uint8_t *key_128, } } -void nas::integrity_check() { +// This function depends to a valid k_nas_int. +// This key is generated in the security mode command. +bool nas::integrity_check(byte_buffer_t *pdu) +{ + uint8_t exp_mac[4]; + uint8_t *mac = &pdu->msg[1]; + int i; + + integrity_generate(&k_nas_int[16], + ctxt.rx_count, + SECURITY_DIRECTION_DOWNLINK, + &pdu->msg[5], + pdu->N_bytes-5, + &exp_mac[0]); + + // Check if expected mac equals the sent mac + for(i=0; i<4; i++){ + if(exp_mac[i] != mac[i]){ + nas_log->warning("Integrity check failure. Local: count=%d, [%02x %02x %02x %02x], " + "Received: count=%d, [%02x %02x %02x %02x]\n", + ctxt.rx_count, exp_mac[0], exp_mac[1], exp_mac[2], exp_mac[3], + pdu->msg[5], mac[0], mac[1], mac[2], mac[3]); + return false; + } + } + nas_log->info("Integrity check ok. Local: count=%d, Received: count=%d\n", + ctxt.rx_count, pdu->msg[5]); + return true; } -void nas::cipher_encrypt() { - +void nas::cipher_encrypt(byte_buffer_t *pdu) +{ + byte_buffer_t pdu_tmp; + switch(ctxt.cipher_algo) + { + case CIPHERING_ALGORITHM_ID_EEA0: + break; + case CIPHERING_ALGORITHM_ID_128_EEA1: + security_128_eea1(&k_nas_enc[16], + pdu->msg[5], + 0, // Bearer always 0 for NAS + SECURITY_DIRECTION_UPLINK, + &pdu->msg[6], + pdu->N_bytes-6, + &pdu_tmp.msg[6]); + memcpy(&pdu->msg[6], &pdu_tmp.msg[6], pdu->N_bytes-6); + break; + case CIPHERING_ALGORITHM_ID_128_EEA2: + security_128_eea2(&k_nas_enc[16], + pdu->msg[5], + 0, // Bearer always 0 for NAS + SECURITY_DIRECTION_UPLINK, + &pdu->msg[6], + pdu->N_bytes-6, + &pdu_tmp.msg[6]); + memcpy(&pdu->msg[6], &pdu_tmp.msg[6], pdu->N_bytes-6); + break; + default: + nas_log->error("Ciphering algorithmus not known"); + break; + } } -void nas::cipher_decrypt() { +void nas::cipher_decrypt(byte_buffer_t *pdu) +{ + byte_buffer_t tmp_pdu; + switch(ctxt.cipher_algo) + { + case CIPHERING_ALGORITHM_ID_EEA0: + break; + case CIPHERING_ALGORITHM_ID_128_EEA1: + security_128_eea1(&k_nas_enc[16], + pdu->msg[5], + 0, // Bearer always 0 for NAS + SECURITY_DIRECTION_DOWNLINK, + &pdu->msg[6], + pdu->N_bytes-6, + &tmp_pdu.msg[6]); + memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6); + break; + case CIPHERING_ALGORITHM_ID_128_EEA2: + security_128_eea2(&k_nas_enc[16], + pdu->msg[5], + 0, // Bearer always 0 for NAS + SECURITY_DIRECTION_DOWNLINK, + &pdu->msg[6], + pdu->N_bytes-6, + &tmp_pdu.msg[6]); + nas_log->debug_hex(tmp_pdu.msg, pdu->N_bytes, "Decrypted"); + memcpy(&pdu->msg[6], &tmp_pdu.msg[6], pdu->N_bytes-6); + break; + default: + nas_log->error("Ciphering algorithmus not known"); + break; + } +} +bool nas::check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps) +{ + for(uint32_t i=0; i<8; i++) { + if(caps->eea[i] != eea_caps[i] || caps->eia[i] != eia_caps[i]) { + return false; + } + } + return true; } /******************************************************************************* -Parsers -*******************************************************************************/ + * Parsers + ******************************************************************************/ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept; @@ -281,7 +459,6 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT act_def_eps_bearer_context_accept; nas_log->info("Received Attach Accept\n"); - count_dl++; liblte_mme_unpack_attach_accept_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &attach_accept); @@ -289,21 +466,19 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { //FIXME: Handle t3412.unit //FIXME: Handle tai_list if (attach_accept.guti_present) { - memcpy(&guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); - is_guti_set = true; - // TODO: log message to console - } - if (attach_accept.lai_present) { + memcpy(&ctxt.guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); + have_guti = true; } + if (attach_accept.lai_present) {} if (attach_accept.ms_id_present) {} if (attach_accept.emm_cause_present) {} if (attach_accept.t3402_present) {} + if (attach_accept.t3412_ext_present) {} if (attach_accept.t3423_present) {} if (attach_accept.equivalent_plmns_present) {} if (attach_accept.emerg_num_list_present) {} if (attach_accept.eps_network_feature_support_present) {} if (attach_accept.additional_update_result_present) {} - if (attach_accept.t3412_ext_present) {} liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(&attach_accept.esm_msg, &act_def_eps_bearer_context_req); @@ -314,13 +489,14 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[2] << 8; ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[3]; - nas_log->info("IP allocated by network %u.%u.%u.%u\n", + nas_log->info("Network attach successful. APN: %s, IP: %u.%u.%u.%u\n", + act_def_eps_bearer_context_req.apn.apn.c_str(), act_def_eps_bearer_context_req.pdn_addr.addr[0], act_def_eps_bearer_context_req.pdn_addr.addr[1], act_def_eps_bearer_context_req.pdn_addr.addr[2], act_def_eps_bearer_context_req.pdn_addr.addr[3]); - nas_log->console("Network attach successful. IP: %u.%u.%u.%u\n", + nas_log->console("Network attach successful. IP: %u.%u.%u.%u\n", act_def_eps_bearer_context_req.pdn_addr.addr[0], act_def_eps_bearer_context_req.pdn_addr.addr[1], act_def_eps_bearer_context_req.pdn_addr.addr[2], @@ -359,8 +535,9 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { state = EMM_STATE_REGISTERED; current_plmn = selecting_plmn; + ctxt.rx_count++; + // Send EPS bearer context accept and attach complete - count_ul++; act_def_eps_bearer_context_accept.eps_bearer_id = eps_bearer_id; act_def_eps_bearer_context_accept.proc_transaction_id = transaction_id; act_def_eps_bearer_context_accept.protocol_cnfg_opts_present = false; @@ -368,11 +545,16 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { &attach_complete.esm_msg); liblte_mme_pack_attach_complete_msg(&attach_complete, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, - count_ul, + ctxt.tx_count, (LIBLTE_BYTE_MSG_STRUCT *) pdu); + // Write NAS pcap + if (pcap != NULL) { + pcap->write_nas(pdu->msg, pdu->N_bytes); + } + + cipher_encrypt(pdu); integrity_generate(&k_nas_int[16], - count_ul, - lcid - 1, + ctxt.tx_count, SECURITY_DIRECTION_UPLINK, &pdu->msg[5], pdu->N_bytes - 5, @@ -383,6 +565,7 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { nas_log->info("Sending Attach Complete\n"); rrc->write_sdu(lcid, pdu); + ctxt.tx_count++; } else { nas_log->info("Not handling attach type %u\n", attach_accept.eps_attach_result); @@ -406,7 +589,7 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) { LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req; LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res; - nas_log->info("Received Authentication Request\n");; + nas_log->info("Received Authentication Request\n"); liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req); // Reuse the pdu for the response message @@ -421,7 +604,15 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) { bool net_valid; uint8_t res[16]; - usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc, &net_valid, res); + usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc, + &net_valid, res, ctxt.k_asme); + nas_log->info("Generated k_asme=%s\n", hex_to_string(ctxt.k_asme, 32).c_str()); + if(LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE == auth_req.nas_ksi.tsc_flag) { + ctxt.ksi = auth_req.nas_ksi.nas_ksi; + } else { + nas_log->error("NAS mapped security context not currently supported\n"); + nas_log->console("Warning: NAS mapped security context not currently supported\n"); + } if (net_valid) { nas_log->info("Network authentication successful\n"); @@ -431,6 +622,10 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) { liblte_mme_pack_authentication_response_msg(&auth_res, (LIBLTE_BYTE_MSG_STRUCT *) pdu); nas_log->info("Sending Authentication Response\n"); + // Write NAS pcap + if (pcap != NULL) { + pcap->write_nas(pdu->msg, pdu->N_bytes); + } rrc->write_sdu(lcid, pdu); } else { nas_log->warning("Network authentication failure\n"); @@ -447,105 +642,138 @@ void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) { } void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) { - nas_log->error("TODO:parse_identity_request\n"); + LIBLTE_MME_ID_REQUEST_MSG_STRUCT id_req; + LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp; + + liblte_mme_unpack_identity_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &id_req); + nas_log->info("Received Identity Request. ID type: %d\n", id_req.id_type); + + switch(id_req.id_type) { + case LIBLTE_MME_MOBILE_ID_TYPE_IMSI: + id_resp.mobile_id.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMSI; + usim->get_imsi_vec(id_resp.mobile_id.imsi, 15); + break; + case LIBLTE_MME_MOBILE_ID_TYPE_IMEI: + id_resp.mobile_id.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEI; + usim->get_imei_vec(id_resp.mobile_id.imei, 15); + break; + default: + nas_log->error("Unhandled ID type: %d\n"); + pool->deallocate(pdu); + return; + } + + pdu->reset(); + liblte_mme_pack_identity_response_msg(&id_resp, (LIBLTE_BYTE_MSG_STRUCT *) pdu); + rrc->write_sdu(lcid, pdu); } -void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) { - bool success; +void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) +{ LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd; LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sec_mode_comp; - LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej; - nas_log->info("Received Security Mode Command\n"); liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &sec_mode_cmd); + nas_log->info("Received Security Mode Command ksi: %d, eea: %s, eia: %s\n", + sec_mode_cmd.nas_ksi.nas_ksi, + ciphering_algorithm_id_text[sec_mode_cmd.selected_nas_sec_algs.type_of_eea], + integrity_algorithm_id_text[sec_mode_cmd.selected_nas_sec_algs.type_of_eia]); - ksi = sec_mode_cmd.nas_ksi.nas_ksi; - cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eea; - integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eia; - // FIXME: Handle nonce_ue, nonce_mme - // FIXME: Currently only handling ciphering EEA0 (null) and integrity EIA1,EIA2 - // FIXME: Use selected_nas_sec_algs to choose correct algos + if(sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE) { + nas_log->error("Mapped security context not supported\n"); + pool->deallocate(pdu); + return; + } - nas_log->debug("Security details: ksi=%d, eea=%s, eia=%s\n", - ksi, ciphering_algorithm_id_text[cipher_algo], integrity_algorithm_id_text[integ_algo]); + if (have_ctxt) { + if(sec_mode_cmd.nas_ksi.nas_ksi != ctxt.ksi) { + nas_log->warning("Sending Security Mode Reject due to key set ID mismatch\n"); + send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED); + pool->deallocate(pdu); + return; + } + } + // MME is setting up security context - if (CIPHERING_ALGORITHM_ID_EEA0 != cipher_algo || - (INTEGRITY_ALGORITHM_ID_128_EIA2 != integ_algo && - INTEGRITY_ALGORITHM_ID_128_EIA1 != integ_algo) || - sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE) { - sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH; + // TODO: check nonce (not sent by Amari) + + // Check capabilities replay + if(!check_cap_replay(&sec_mode_cmd.ue_security_cap)) { nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n"); - success = false; + send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH); + pool->deallocate(pdu); + return; + } + + // Reset counters (as per 24.301 5.4.3.2) + ctxt.rx_count = 0; + ctxt.tx_count = 0; + + ctxt.cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eea; + ctxt.integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eia; + + // Check capabilities + if(!eea_caps[ctxt.cipher_algo] || !eia_caps[ctxt.integ_algo]) { + nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n"); + send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH); + pool->deallocate(pdu); + return; + } + + // Generate NAS keys + usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, + ctxt.cipher_algo, ctxt.integ_algo); + nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc"); + nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int"); + + nas_log->debug("Generating integrity check. integ_algo:%d, count_dl:%d, lcid:%d\n", + ctxt.integ_algo, ctxt.rx_count, lcid); + + if (integrity_check(pdu) != true) { + nas_log->warning("Sending Security Mode Reject due to integrity check failure\n"); + send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_MAC_FAILURE); + pool->deallocate(pdu); + return; + } + + ctxt.rx_count++; + + // Take security context into use + have_ctxt = true; + + if (sec_mode_cmd.imeisv_req_present && LIBLTE_MME_IMEISV_REQUESTED == sec_mode_cmd.imeisv_req) { + sec_mode_comp.imeisv_present = true; + sec_mode_comp.imeisv.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEISV; + usim->get_imei_vec(sec_mode_comp.imeisv.imeisv, 15); + sec_mode_comp.imeisv.imeisv[14] = 5; + sec_mode_comp.imeisv.imeisv[15] = 3; } else { - // Generate NAS encryption key and integrity protection key - usim->generate_nas_keys(k_nas_enc, k_nas_int, cipher_algo, integ_algo); - nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc"); - nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int"); - - // Check incoming MAC - uint8_t *inMAC = &pdu->msg[1]; - uint8_t genMAC[4]; - integrity_generate(&k_nas_int[16], - count_dl, - lcid - 1, - SECURITY_DIRECTION_DOWNLINK, - &pdu->msg[5], - pdu->N_bytes - 5, - genMAC); - - nas_log->info_hex(inMAC, 4, "Incoming PDU MAC:"); - nas_log->info_hex(genMAC, 4, "Generated PDU MAC:"); - - bool match = true; - for (int i = 0; i < 4; i++) { - if (inMAC[i] != genMAC[i]) { - match = false; - } - } - if (!match) { - sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED; - nas_log->warning("Sending Security Mode Reject due to integrity check failure\n"); - success = false; - } else { - - if (sec_mode_cmd.imeisv_req_present && LIBLTE_MME_IMEISV_REQUESTED == sec_mode_cmd.imeisv_req) { - sec_mode_comp.imeisv_present = true; - sec_mode_comp.imeisv.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEISV; - usim->get_imei_vec(sec_mode_comp.imeisv.imeisv, 15); - sec_mode_comp.imeisv.imeisv[14] = 5; - sec_mode_comp.imeisv.imeisv[15] = 3; - } else { - sec_mode_comp.imeisv_present = false; - } - - // Reuse pdu for response - pdu->reset(); - liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp, - LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, - count_ul, - (LIBLTE_BYTE_MSG_STRUCT *) pdu); - integrity_generate(&k_nas_int[16], - count_ul, - lcid - 1, - SECURITY_DIRECTION_UPLINK, - &pdu->msg[5], - pdu->N_bytes - 5, - &pdu->msg[1]); - nas_log->info("Sending Security Mode Complete nas_count_ul=%d, RB=%s\n", - count_ul, - rrc->get_rb_name(lcid).c_str()); - success = true; - } + sec_mode_comp.imeisv_present = false; } - if (!success) { - // Reuse pdu for response - pdu->reset(); - liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) pdu); + // Send response + byte_buffer_t *sdu = pool_allocate; + liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp, + LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT, + ctxt.tx_count, + (LIBLTE_BYTE_MSG_STRUCT *) sdu); + if(pcap != NULL) { + pcap->write_nas(sdu->msg, sdu->N_bytes); } - - rrc->write_sdu(lcid, pdu); + cipher_encrypt(sdu); + integrity_generate(&k_nas_int[16], + ctxt.tx_count, + SECURITY_DIRECTION_UPLINK, + &sdu->msg[5], + sdu->N_bytes - 5, + &sdu->msg[1]); + nas_log->info("Sending Security Mode Complete nas_current_ctxt.tx_count=%d, RB=%s\n", + ctxt.tx_count, + get_rb_name(lcid)); + rrc->write_sdu(lcid, sdu); + ctxt.tx_count++; + pool->deallocate(pdu); } void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) { @@ -554,15 +782,20 @@ void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) { nas_log->error("TODO:parse_esm_information_request\n"); + } void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) { - nas_log->error("TODO:parse_emm_information\n"); + liblte_mme_unpack_emm_information_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &emm_info); + std::string str = emm_info_str(&emm_info); + nas_log->info("Received EMM Information: %s\n", str.c_str()); + nas_log->console("%s\n", str.c_str()); + ctxt.rx_count++; } /******************************************************************************* -Senders -*******************************************************************************/ + * Senders + ******************************************************************************/ void nas::send_attach_request() { LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req; @@ -572,30 +805,17 @@ void nas::send_attach_request() { attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH; for (i = 0; i < 8; i++) { - attach_req.ue_network_cap.eea[i] = false; - attach_req.ue_network_cap.eia[i] = false; + attach_req.ue_network_cap.eea[i] = eea_caps[i]; + attach_req.ue_network_cap.eia[i] = eia_caps[i]; } - attach_req.ue_network_cap.eea[0] = true; // EEA0 supported - attach_req.ue_network_cap.eia[0] = true; // EIA0 supported - attach_req.ue_network_cap.eia[1] = true; // EIA1 supported - attach_req.ue_network_cap.eia[2] = true; // EIA2 supported - - attach_req.ue_network_cap.uea_present = false; // UMTS encryption algos - attach_req.ue_network_cap.uia_present = false; // UMTS integrity algos - - attach_req.ms_network_cap_present = false; // A/Gb mode (2G) or Iu mode (3G) - - attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI; - usim->get_imsi_vec(attach_req.eps_mobile_id.imsi, 15); - - // ESM message (PDN connectivity request) for first default bearer - gen_pdn_connectivity_request(&attach_req.esm_msg); + attach_req.ue_network_cap.uea_present = false; // UMTS encryption algos + attach_req.ue_network_cap.uia_present = false; // UMTS integrity algos + attach_req.ms_network_cap_present = false; // A/Gb mode (2G) or Iu mode (3G) attach_req.old_p_tmsi_signature_present = false; attach_req.additional_guti_present = false; attach_req.last_visited_registered_tai_present = false; attach_req.drx_param_present = false; - attach_req.ms_network_cap_present = false; attach_req.old_lai_present = false; attach_req.tmsi_status_present = false; attach_req.ms_cm2_present = false; @@ -606,11 +826,49 @@ void nas::send_attach_request() { attach_req.device_properties_present = false; attach_req.old_guti_type_present = false; - // Pack the message - liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg); + // ESM message (PDN connectivity request) for first default bearer + gen_pdn_connectivity_request(&attach_req.esm_msg); + + // GUTI or IMSI attach + if(have_guti && have_ctxt) { + attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_GUTI; + memcpy(&attach_req.eps_mobile_id.guti, &ctxt.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); + attach_req.old_guti_type = LIBLTE_MME_GUTI_TYPE_NATIVE; + attach_req.old_guti_type_present = true; + attach_req.nas_ksi.tsc_flag = LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE; + attach_req.nas_ksi.nas_ksi = ctxt.ksi; + nas_log->info("Requesting GUTI attach. " + "m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n", + ctxt.guti.m_tmsi, ctxt.guti.mcc, ctxt.guti.mnc, ctxt.guti.mme_group_id, ctxt.guti.mme_code); + liblte_mme_pack_attach_request_msg(&attach_req, + LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY, + ctxt.tx_count, + (LIBLTE_BYTE_MSG_STRUCT *) msg); + + // Add MAC + integrity_generate(&k_nas_int[16], + ctxt.tx_count, + SECURITY_DIRECTION_UPLINK, + &msg->msg[5], + msg->N_bytes - 5, + &msg->msg[1]); + } else { + attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI; + usim->get_imsi_vec(attach_req.eps_mobile_id.imsi, 15); + nas_log->info("Requesting IMSI attach (IMSI=%s)\n", usim->get_imsi_str().c_str()); + liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg); + } + + if(pcap != NULL) { + pcap->write_nas(msg->msg, msg->N_bytes); + } nas_log->info("Sending attach request\n"); rrc->write_sdu(cfg.lcid, msg); + + if (have_ctxt) { + ctxt.tx_count++; + } } void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) { @@ -634,36 +892,211 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) { liblte_mme_pack_pdn_connectivity_request_msg(&pdn_con_req, msg); } +void nas::send_security_mode_reject(uint8_t cause) { + byte_buffer_t *msg = pool_allocate; + + LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej; + sec_mode_rej.emm_cause = cause; + liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) msg); + if(pcap != NULL) { + pcap->write_nas(msg->msg, msg->N_bytes); + } + nas_log->info("Sending security mode reject\n"); + rrc->write_sdu(cfg.lcid, msg); +} + void nas::send_identity_response() {} void nas::send_service_request() { byte_buffer_t *msg = pool_allocate; - count_ul++; // Pack the service request message directly msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg->N_bytes++; - msg->msg[1] = (ksi & 0x07) << 5; - msg->msg[1] |= count_ul & 0x1F; + msg->msg[1] = (ctxt.ksi & 0x07) << 5; + msg->msg[1] |= ctxt.tx_count & 0x1F; msg->N_bytes++; uint8_t mac[4]; integrity_generate(&k_nas_int[16], - count_ul, - cfg.lcid-1, - SECURITY_DIRECTION_UPLINK, - &msg->msg[0], - 2, - &mac[0]); + ctxt.tx_count, + SECURITY_DIRECTION_UPLINK, + &msg->msg[0], + 2, + &mac[0]); // Set the short MAC msg->msg[2] = mac[2]; msg->N_bytes++; msg->msg[3] = mac[3]; msg->N_bytes++; + + if(pcap != NULL) { + pcap->write_nas(msg->msg, msg->N_bytes); + } + nas_log->info("Sending service request\n"); rrc->write_sdu(cfg.lcid, msg); + ctxt.tx_count++; } void nas::send_esm_information_response() {} + +/******************************************************************************* + * Security context persistence file + ******************************************************************************/ + +bool nas::read_ctxt_file(nas_sec_ctxt *ctxt) +{ + std::ifstream file; + if(!ctxt) { + return false; + } + + file.open(".ctxt", std::ios::in); + if(file.is_open()) { + if(!readvar(file, "m_tmsi=", &ctxt->guti.m_tmsi)) {return false;} + if(!readvar(file, "mcc=", &ctxt->guti.mcc)) {return false;} + if(!readvar(file, "mnc=", &ctxt->guti.mnc)) {return false;} + if(!readvar(file, "mme_group_id=", &ctxt->guti.mme_group_id)) {return false;} + if(!readvar(file, "mme_code=", &ctxt->guti.mme_code)) {return false;} + if(!readvar(file, "tx_count=", &ctxt->tx_count)) {return false;} + if(!readvar(file, "rx_count=", &ctxt->rx_count)) {return false;} + if(!readvar(file, "int_alg=", &ctxt->integ_algo)) {return false;} + if(!readvar(file, "enc_alg=", &ctxt->cipher_algo)) {return false;} + if(!readvar(file, "ksi=", &ctxt->ksi)) {return false;} + + if(!readvar(file, "k_asme=", ctxt->k_asme, 32)) {return false;} + + file.close(); + have_guti = true; + nas_log->info("Read GUTI from file " + "m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n", + ctxt->guti.m_tmsi, + ctxt->guti.mcc, + ctxt->guti.mnc, + ctxt->guti.mme_group_id, + ctxt->guti.mme_code); + have_ctxt = true; + nas_log->info("Read security ctxt from file .ctxt. " + "ksi: %x, k_asme: %s, tx_count: %x, rx_count: %x, int_alg: %d, enc_alg: %d\n", + ctxt->ksi, + hex_to_string(ctxt->k_asme,32).c_str(), + ctxt->tx_count, + ctxt->rx_count, + ctxt->integ_algo, + ctxt->cipher_algo); + return true; + + } else { + return false; + } +} + +bool nas::write_ctxt_file(nas_sec_ctxt ctxt) +{ + if (!have_guti || !have_ctxt) { + return false; + } + std::ofstream file; + file.open(".ctxt", std::ios::out | std::ios::trunc); + if (file.is_open()) { + file << "m_tmsi=" << (int) ctxt.guti.m_tmsi << std::endl; + file << "mcc=" << (int) ctxt.guti.mcc << std::endl; + file << "mnc=" << (int) ctxt.guti.mnc << std::endl; + file << "mme_group_id=" << (int) ctxt.guti.mme_group_id << std::endl; + file << "mme_code=" << (int) ctxt.guti.mme_code << std::endl; + file << "tx_count=" << (int) ctxt.tx_count << std::endl; + file << "rx_count=" << (int) ctxt.rx_count << std::endl; + file << "int_alg=" << (int) ctxt.integ_algo << std::endl; + file << "enc_alg=" << (int) ctxt.cipher_algo << std::endl; + file << "ksi=" << (int) ctxt.ksi << std::endl; + + file << "k_asme=" << hex_to_string(ctxt.k_asme, 32) << std::endl; + + nas_log->info("Saved GUTI to file " + "m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n", + ctxt.guti.m_tmsi, + ctxt.guti.mcc, + ctxt.guti.mnc, + ctxt.guti.mme_group_id, + ctxt.guti.mme_code); + nas_log->info("Saved security ctxt to file .ctxt. " + "ksi: %x, k_asme: %s, tx_count: %x, rx_count: %x, int_alg: %d, enc_alg: %d\n", + ctxt.ksi, + hex_to_string(ctxt.k_asme,32).c_str(), + ctxt.tx_count, + ctxt.rx_count, + ctxt.integ_algo, + ctxt.cipher_algo); + file.close(); + return true; + } else { + return false; + } +} + +/********************************************************************* + * Conversion helpers + ********************************************************************/ +std::string nas::hex_to_string(uint8_t *hex, int size) +{ + std::stringstream ss; + + ss << std::hex << std::setfill('0'); + for(int i=0; i(hex[i]); + } + return ss.str(); +} + +bool nas::string_to_hex(std::string hex_str, uint8_t *hex, uint32_t len) +{ + static const char* const lut = "0123456789abcdef"; + uint32_t str_len = hex_str.length(); + if(str_len & 1) { + return false; // uneven hex_str length + } + if(str_len > len*2) { + return false; // not enough space in hex buffer + } + for(uint32_t i=0; ifull_net_name_present) { + ss << info->full_net_name.name; + } + if(info->short_net_name_present) { + ss << " (" << info->short_net_name.name << ")"; + } + if(info->utc_and_local_time_zone_present) { + ss << " " << (int)info->utc_and_local_time_zone.day; + ss << "/" << (int)info->utc_and_local_time_zone.month; + ss << "/" << (int)info->utc_and_local_time_zone.year; + ss << " " << (int)info->utc_and_local_time_zone.hour; + ss << ":" << (int)info->utc_and_local_time_zone.minute; + ss << ":" << (int)info->utc_and_local_time_zone.second; + ss << " TZ:" << (int)info->utc_and_local_time_zone.tz; + } + return ss.str(); +} + + } // namespace srsue diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 7b78bd774..2ea1b877d 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -26,17 +26,16 @@ #include +#include #include -#include "srslte/asn1/liblte_rrc.h" -#include "upper/rrc.h" -#include -#include +#include +#include #include +#include "upper/rrc.h" +#include "srslte/asn1/liblte_rrc.h" #include "srslte/common/security.h" #include "srslte/common/bcd_helpers.h" -#define TIMEOUT_RESYNC_REESTABLISH 100 - using namespace srslte; namespace srsue { @@ -49,7 +48,10 @@ namespace srsue { rrc::rrc() :state(RRC_STATE_IDLE) ,drb_up(false) + ,sysinfo_index(0) { + n310_cnt = 0; + n311_cnt = 0; } static void liblte_rrc_handler(void *ctx, char *str) { @@ -87,15 +89,24 @@ void rrc::init(phy_interface_rrc *phy_, state = RRC_STATE_IDLE; si_acquire_state = SI_ACQUIRE_IDLE; + bzero(known_cells, MAX_KNOWN_CELLS*sizeof(cell_t)); + thread_running = true; start(); pthread_mutex_init(&mutex, NULL); - ue_category = SRSLTE_UE_CATEGORY; + first_stimsi_attempt = false; + + args.ue_category = SRSLTE_UE_CATEGORY; + args.supported_bands[0] = 7; + args.nof_supported_bands = 1; + args.feature_group = 0xe6041c00; + t301 = mac_timers->timer_get_unique_id(); t310 = mac_timers->timer_get_unique_id(); t311 = mac_timers->timer_get_unique_id(); + t304 = mac_timers->timer_get_unique_id(); transaction_id = 0; @@ -105,10 +116,16 @@ void rrc::init(phy_interface_rrc *phy_, nof_sib1_trials = 0; last_win_start = 0; + pending_mob_reconf = false; + // Set default values for all layers set_rrc_default(); set_phy_default(); set_mac_default(); + + measurements.init(this); + // set seed for rand (used in attach) + srand(time(NULL)); } void rrc::stop() { @@ -116,6 +133,10 @@ void rrc::stop() { wait_thread_finish(); } +void rrc::run_tti(uint32_t tti) { + measurements.run_tti(tti); +} + rrc_state_t rrc::get_state() { return state; } @@ -128,12 +149,8 @@ bool rrc::have_drb() { return drb_up; } -void rrc::set_ue_category(int category) { - if (category >= 1 && category <= 5) { - ue_category = category; - } else { - rrc_log->error("Unsupported UE category %d\n", category); - } +void rrc::set_args(rrc_args_t *args) { + memcpy(&this->args, args, sizeof(rrc_args_t)); } /* @@ -143,6 +160,8 @@ void rrc::set_ue_category(int category) { */ void rrc::run_thread() { + uint32_t failure_test = 0; + while (thread_running) { if (state >= RRC_STATE_IDLE && state < RRC_STATE_CONNECTING) { @@ -158,14 +177,14 @@ void rrc::run_thread() { if (nas->is_attaching()) { sleep(1); rrc_log->info("RRC IDLE: NAS is attaching and camping on cell, reselecting...\n"); - plmn_select(selected_plmn_id); + plmn_select_rrc(selected_plmn_id); } // If not camping on a cell } else { // If NAS is attached, perform cell reselection on current PLMN if (nas->is_attached()) { rrc_log->info("RRC IDLE: NAS is attached, PHY not synchronized. Re-selecting cell...\n"); - plmn_select(selected_plmn_id); + plmn_select_rrc(selected_plmn_id); } else if (nas->is_attaching()) { sleep(1); rrc_log->info("RRC IDLE: NAS is attaching, searching again PLMN\n"); @@ -186,9 +205,14 @@ void rrc::run_thread() { } break; case RRC_STATE_CELL_SELECTING: + + /* During cell selection, apply SIB configurations if available or receive them if not. + * Cell is selected when all SIBs downloaded or applied. + */ if (phy->sync_status()) { if (!current_cell->has_valid_sib1) { si_acquire_state = SI_ACQUIRE_SIB1; + sysinfo_index = 0; } else if (!current_cell->has_valid_sib2) { si_acquire_state = SI_ACQUIRE_SIB2; } else { @@ -197,19 +221,41 @@ void rrc::run_thread() { state = RRC_STATE_CELL_SELECTED; } } - select_cell_timeout++; - if (select_cell_timeout >= RRC_SELECT_CELL_TIMEOUT) { - rrc_log->info("RRC Cell Selecting: timeout expired. Starting Cell Search...\n"); - state = RRC_STATE_PLMN_SELECTION; - plmn_select_timeout = 0; - phy->cell_search_start(); + // Don't time out during restablishment (T311 running) + if (!mac_timers->timer_get(t311)->is_running()) { + select_cell_timeout++; + if (select_cell_timeout >= RRC_SELECT_CELL_TIMEOUT) { + rrc_log->info("RRC Cell Selecting: timeout expired. Starting Cell Search...\n"); + plmn_select_timeout = 0; + select_cell_timeout = 0; + phy->cell_search_start(); + } } break; case RRC_STATE_CELL_SELECTED: - rrc_log->info("RRC Cell Selected: Sending connection request...\n"); - send_con_request(); - state = RRC_STATE_CONNECTING; - connecting_timeout = 0; + + /* The cell is selected when the SIBs are received and applied. + * If we were in RRC_CONNECTED and arrive here it means a RLF occurred and we are in Reestablishment procedure. + * If T311 is running means there is a reestablishment in progress, send ConnectionReestablishmentRequest. + * If not, do a ConnectionRequest if NAS is established or go to IDLE an camp on cell otherwise. + */ + if (mac_timers->timer_get(t311)->is_running()) { + // + rrc_log->info("RRC Cell Selected: Sending connection reestablishment...\n"); + con_restablish_cell_reselected(); + state = RRC_STATE_CONNECTING; + connecting_timeout = 0; + } else if (connection_requested) { + connection_requested = false; + rrc_log->info("RRC Cell Selected: Sending connection request...\n"); + send_con_request(); + state = RRC_STATE_CONNECTING; + connecting_timeout = 0; + } else { + rrc_log->info("RRC Cell Selected: Starting paging and going to IDLE...\n"); + mac->pcch_start_rx(); + state = RRC_STATE_IDLE; + } break; case RRC_STATE_CONNECTING: connecting_timeout++; @@ -220,22 +266,47 @@ void rrc::run_thread() { } break; case RRC_STATE_CONNECTED: + /* + failure_test++; + if (failure_test >= 100) { + mac_interface_rrc::ue_rnti_t ue_rnti; + mac->get_rntis(&ue_rnti); + send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE, ue_rnti.crnti); + }*/ // Take measurements, cell reselection, etc break; + case RRC_STATE_HO_PREPARE: + if (ho_prepare()) { + state = RRC_STATE_HO_PROCESS; + } else { + state = RRC_STATE_CONNECTED; + } + break; + case RRC_STATE_HO_PROCESS: + // wait for HO to finish + break; case RRC_STATE_LEAVE_CONNECTED: usleep(60000); + rrc_log->console("RRC IDLE\n"); rrc_log->info("Leaving RRC_CONNECTED state\n"); drb_up = false; + measurements.reset(); pdcp->reset(); rlc->reset(); phy->reset(); mac->reset(); set_phy_default(); set_mac_default(); - mac->pcch_start_rx(); - mac_timers->timer_get(t311)->run(); mac_timers->timer_get(t310)->stop(); mac_timers->timer_get(t311)->stop(); + if (phy->sync_status()) { + // Instruct MAC to look for P-RNTI + mac->pcch_start_rx(); + // Instruct PHY to measure serving cell for cell reselection + phy->meas_start(phy->get_current_earfcn(), phy->get_current_pci()); + } + + // Move to RRC_IDLE state = RRC_STATE_IDLE; break; default: @@ -263,8 +334,8 @@ void rrc::run_thread() { // Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message -uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) { - return (period * 10 * (1 + tti / (period * 10)) + x) % 10240; // the 1 means next opportunity +uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf) { + return (period*10*(1+tti/(period*10))+(offset*10)+sf)%10240; // the 1 means next opportunity } void rrc::run_si_acquisition_procedure() @@ -272,13 +343,14 @@ void rrc::run_si_acquisition_procedure() uint32_t tti; uint32_t si_win_start=0, si_win_len=0; uint16_t period; + uint32_t x, sf, offset; const int SIB1_SEARCH_TIMEOUT = 30; switch (si_acquire_state) { case SI_ACQUIRE_SIB1: // Instruct MAC to look for SIB1 tti = mac->get_current_tti(); - si_win_start = sib_start_tti(tti, 2, 5); + si_win_start = sib_start_tti(tti, 2, 0, 5); if (tti > last_win_start + 10) { last_win_start = si_win_start; mac->bcch_start_rx(si_win_start, 1); @@ -297,17 +369,30 @@ void rrc::run_si_acquisition_procedure() } break; case SI_ACQUIRE_SIB2: - // Instruct MAC to look for SIB2 only when selecting a cell - tti = mac->get_current_tti(); - period = liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]; - si_win_start = sib_start_tti(tti, period, 0); - if (tti > last_win_start + 10) { - last_win_start = si_win_start; - si_win_len = liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length]; + // Instruct MAC to look for next SIB + if(sysinfo_index < current_cell->sib1.N_sched_info) { + si_win_len = liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length]; + x = sysinfo_index*si_win_len; + sf = x%10; + offset = x/10; - mac->bcch_start_rx(si_win_start, si_win_len); - rrc_log->debug("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n", - si_win_start, si_win_len); + tti = mac->get_current_tti(); + period = liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[sysinfo_index].si_periodicity]; + si_win_start = sib_start_tti(tti, period, offset, sf); + + if (tti > last_win_start + 10) { + last_win_start = si_win_start; + si_win_len = liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length]; + + mac->bcch_start_rx(si_win_start, si_win_len); + rrc_log->debug("Instructed MAC to search for system info, win_start=%d, win_len=%d\n", + si_win_start, si_win_len); + } + + } else { + // We've received all SIBs, move on to connection request + si_acquire_state = SI_ACQUIRE_IDLE; + state = RRC_STATE_CELL_SELECTED; } break; default: @@ -360,8 +445,18 @@ void rrc::plmn_search() { plmn_select_timeout = 0; } +/* This is the NAS interface. When NAS requests to select a PLMN we have to + * connect to either register or because there is pending higher layer traffic. + */ void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { + connection_requested = true; + plmn_select_rrc(plmn_id); +} +/* This is called by RRC only. In this case, we do not want to connect, just camp on the + * selected PLMN + */ +void rrc::plmn_select_rrc(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { // If already camping on the selected PLMN, select this cell if (state == RRC_STATE_IDLE || state == RRC_STATE_CONNECTED || state == RRC_STATE_PLMN_SELECTION) { if (phy->sync_status() && selected_plmn_id.mcc == plmn_id.mcc && selected_plmn_id.mnc == plmn_id.mnc) { @@ -385,7 +480,7 @@ void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { } void rrc::select_next_cell_in_plmn() { - for (uint32_t i = last_selected_cell + 1; i < known_cells.size(); i++) { + for (uint32_t i = last_selected_cell + 1; i < MAX_KNOWN_CELLS && known_cells[i].earfcn; i++) { for (uint32_t j = 0; j < known_cells[i].sib1.N_plmn_ids; j++) { if (known_cells[i].sib1.plmn_id[j].id.mcc == selected_plmn_id.mcc || known_cells[i].sib1.plmn_id[j].id.mnc == selected_plmn_id.mnc) { @@ -402,6 +497,9 @@ void rrc::select_next_cell_in_plmn() { { last_selected_cell = i; current_cell = &known_cells[i]; + rrc_log->info("Selected cell PCI=%d, EARFCN=%d, Cell ID=0x%x, addr=0x%x\n", + current_cell->phy_cell.id, current_cell->earfcn, + current_cell->sib1.cell_id, current_cell); return; } else { rrc_log->warning("Selecting cell EARFCN=%d, Cell ID=0x%x.\n", @@ -411,25 +509,61 @@ void rrc::select_next_cell_in_plmn() { } } } - rrc_log->info("No more known cells...\n"); + rrc_log->info("No more known cells. Starting again\n"); + last_selected_cell = -1; +} + +void rrc::new_phy_meas(float rsrp, float rsrq, uint32_t tti, uint32_t earfcn, uint32_t pci) { + if (state != RRC_STATE_IDLE) { + measurements.new_phy_meas(earfcn, pci, rsrp, rsrq, tti); + } else { + // If measurement is of the serving cell, evaluate cell reselection criteria + if ((earfcn == phy->get_current_earfcn() && pci == phy->get_current_pci()) || (earfcn == 0 && pci == 0)) { + cell_reselection_eval(rsrp, rsrq); + current_cell->rsrp = rsrp; + rrc_log->info("MEAS: New measurement serving cell, rsrp=%f, rsrq=%f, tti=%d\n", rsrp, rsrq, tti); + } else { + // Add/update cell measurement + srslte_cell_t cell; + phy->get_current_cell(&cell, NULL); + cell.id = pci; + add_new_cell(earfcn, cell, rsrp); + + rrc_log->info("MEAS: New measurement PCI=%d, RSRP=%.1f dBm.\n", pci, rsrp); + } + + srslte_cell_t best_cell; + uint32_t best_cell_idx = find_best_cell(phy->get_current_earfcn(), &best_cell); + + // Verify cell selection criteria + if (cell_selection_eval(known_cells[best_cell_idx].rsrp) && + known_cells[best_cell_idx].rsrp > current_cell->rsrp + 5 && + best_cell.id != phy->get_current_pci()) + { + rrc_log->info("Selecting best neighbour cell PCI=%d, rsrp=%.1f dBm\n", best_cell.id, known_cells[best_cell_idx].rsrp); + state = RRC_STATE_CELL_SELECTING; + current_cell = &known_cells[best_cell_idx]; + phy->cell_select(phy->get_current_earfcn(), best_cell); + } + } } void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { // find if cell_id-earfcn combination already exists - for (uint32_t i = 0; i < known_cells.size(); i++) { + for (uint32_t i = 0; i < MAX_KNOWN_CELLS && known_cells[i].earfcn; i++) { if (earfcn == known_cells[i].earfcn && phy_cell.id == known_cells[i].phy_cell.id) { - known_cells[i].rsrp = rsrp; - known_cells[i].in_sync = true; current_cell = &known_cells[i]; - rrc_log->info("Updating cell EARFCN=%d, PCI=%d, RSRP=%.1f dBm\n", known_cells[i].earfcn, - known_cells[i].phy_cell.id, known_cells[i].rsrp); + current_cell->rsrp = rsrp; + current_cell->in_sync = true; + rrc_log->info("Updating cell EARFCN=%d, PCI=%d, RSRP=%.1f dBm\n", current_cell->earfcn, + current_cell->phy_cell.id, current_cell->rsrp); - if (!known_cells[i].has_valid_sib1) { + if (!current_cell->has_valid_sib1) { si_acquire_state = SI_ACQUIRE_SIB1; } else if (state == RRC_STATE_PLMN_SELECTION) { - for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) { - nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code); + for (uint32_t j = 0; j < current_cell->sib1.N_plmn_ids; j++) { + nas->plmn_found(current_cell->sib1.plmn_id[j].id, current_cell->sib1.tracking_area_code); } usleep(5000); phy->cell_search_next(); @@ -437,39 +571,142 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { return; } } - // add to list of known cells - cell_t cell; - cell.phy_cell = phy_cell; - cell.rsrp = rsrp; - cell.earfcn = earfcn; - cell.has_valid_sib1 = false; - cell.has_valid_sib2 = false; - known_cells.push_back(cell); - - // save current cell - current_cell = &known_cells.back(); + // add to list of known cells and set current_cell + current_cell = add_new_cell(earfcn, phy_cell, rsrp); + if(!current_cell) { + current_cell = &known_cells[0]; + rrc_log->error("Couldn't add new cell\n"); + return; + } si_acquire_state = SI_ACQUIRE_SIB1; - rrc_log->info("New Cell: PCI=%d, PRB=%d, Ports=%d, EARFCN=%d, RSRP=%.1f dBm\n", - cell.phy_cell.id, cell.phy_cell.nof_prb, cell.phy_cell.nof_ports, - cell.earfcn, cell.rsrp); + rrc_log->info("New Cell: PCI=%d, PRB=%d, Ports=%d, EARFCN=%d, RSRP=%.1f dBm, addr=0x%x\n", + current_cell->phy_cell.id, current_cell->phy_cell.nof_prb, current_cell->phy_cell.nof_ports, + current_cell->earfcn, current_cell->rsrp, current_cell); +} + +uint32_t rrc::find_best_cell(uint32_t earfcn, srslte_cell_t *cell) { + float best_rsrp = -INFINITY; + uint32_t best_cell_idx = 0; + for (int i=0;i best_rsrp) { + best_rsrp = known_cells[i].rsrp; + best_cell_idx = i; + } + } + } + if (cell) { + memcpy(cell, &known_cells[best_cell_idx].phy_cell, sizeof(srslte_cell_t)); + } + return best_cell_idx; +} + +rrc::cell_t* rrc::add_new_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { + if (earfcn == 0) { + return NULL; + } + int idx = find_cell_idx(earfcn, phy_cell.id); + if (idx >= 0) { + known_cells[idx].rsrp = rsrp; + return &known_cells[idx]; + } + + // if does not exist, find empty slot + int i=0; + while(ierror("Can't add more cells\n"); + return NULL; + } + + known_cells[i].phy_cell = phy_cell; + known_cells[i].rsrp = rsrp; + known_cells[i].earfcn = earfcn; + known_cells[i].has_valid_sib1 = false; + known_cells[i].has_valid_sib2 = false; + known_cells[i].has_valid_sib3 = false; + return &known_cells[i]; +} + +void rrc::add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp) { + int idx = find_cell_idx(earfcn, pci); + if (idx >= 0) { + known_cells[idx].rsrp = rsrp; + return; + } + + rrc_log->info("Added neighbour cell earfcn=%d, pci=%d, rsrp=%f\n", earfcn, pci, rsrp); + + srslte_cell_t cell; + cell = current_cell->phy_cell; + cell.id = pci; + add_new_cell(earfcn, cell, rsrp); +} + +int rrc::find_cell_idx(uint32_t earfcn, uint32_t pci) { + for (uint32_t i = 0; i < MAX_KNOWN_CELLS; i++) { + if (earfcn == known_cells[i].earfcn && pci == known_cells[i].phy_cell.id) { + return (int) i; + } + } + return -1; } // PHY indicates that has gone through all known EARFCN void rrc::earfcn_end() { - rrc_log->debug("Finished searching cells in EARFCN set while in state %s\n", rrc_state_text[state]); + rrc_log->info("Finished searching cells in EARFCN set while in state %s\n", rrc_state_text[state]); // If searching for PLMN, indicate NAS we scanned all frequencies if (state == RRC_STATE_PLMN_SELECTION) { nas->plmn_search_end(); + } else if (state == RRC_STATE_CELL_SELECTING) { + select_cell_timeout = 0; + rrc_log->info("Starting cell search again\n"); + phy->cell_search_start(); } } +// Cell reselection in IDLE Section 5.2.4 of 36.304 +void rrc::cell_reselection_eval(float rsrp, float rsrq) +{ + // Intra-frequency cell-reselection criteria + if (get_srxlev(rsrp) > cell_resel_cfg.s_intrasearchP && rsrp > -95.0) { + // UE may not perform intra-frequency measurements. + phy->meas_reset(); + // keep measuring serving cell + phy->meas_start(phy->get_current_earfcn(), phy->get_current_pci()); + } else { + // UE must start intra-frequency measurements + phy->meas_start(phy->get_current_earfcn(), -1); + } + // TODO: Inter-frequency cell reselection +} +// Cell selection in IDLE Section 5.2.3.2 of 36.304 +bool rrc::cell_selection_eval(float rsrp, float rsrq) +{ + if (get_srxlev(rsrp) > 0) { + return true; + } else { + return false; + } +} +float rrc::get_srxlev(float Qrxlevmeas) { + // TODO: Do max power limitation + float Pcompensation = 0; + return Qrxlevmeas - (cell_resel_cfg.Qrxlevmin + cell_resel_cfg.Qrxlevminoffset) - Pcompensation; +} + +float rrc::get_squal(float Qqualmeas) { + return Qqualmeas - (cell_resel_cfg.Qqualmin + cell_resel_cfg.Qqualminoffset); +} @@ -485,13 +722,11 @@ void rrc::earfcn_end() { // Detection of physical layer problems (5.3.11.1) void rrc::out_of_sync() { - current_cell->in_sync = false; + // attempt resync + current_cell->in_sync = false; if (!mac_timers->timer_get(t311)->is_running() && !mac_timers->timer_get(t310)->is_running()) { n310_cnt++; if (n310_cnt == N310) { - // attempt resync - phy->sync_reset(); - mac_timers->timer_get(t310)->reset(); mac_timers->timer_get(t310)->run(); n310_cnt = 0; @@ -525,7 +760,9 @@ void rrc::radio_link_failure() { if (state != RRC_STATE_CONNECTED) { state = RRC_STATE_LEAVE_CONNECTED; } else { - send_con_restablish_request(); + mac_interface_rrc::ue_rnti_t uernti; + mac->get_rntis(&uernti); + send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE, uernti.crnti); } } @@ -556,9 +793,17 @@ void rrc::timer_expired(uint32_t timeout_id) { rrc_log->info("Timer T311 expired: Going to RRC IDLE\n"); state = RRC_STATE_LEAVE_CONNECTED; } else if (timeout_id == t301) { - rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); - state = RRC_STATE_LEAVE_CONNECTED; - } else { + if (state == RRC_STATE_IDLE) { + rrc_log->info("Timer T301 expired: Already in IDLE.\n"); + } else { + rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); + state = RRC_STATE_LEAVE_CONNECTED; + } + } else if (timeout_id == t304) { + rrc_log->console("Timer T304 expired: Handover failed\n"); + ho_failed(); + // fw to measurement + } else if (!measurements.timer_expired(timeout_id)) { rrc_log->error("Timeout from unknown timer id %d\n", timeout_id); } } @@ -582,87 +827,77 @@ void rrc::timer_expired(uint32_t timeout_id) { void rrc::send_con_request() { rrc_log->debug("Preparing RRC Connection Request\n"); - LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; // Prepare ConnectionRequest packet ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ; + if (nas->get_s_tmsi(&s_tmsi)) { ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI; ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = s_tmsi; } else { ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE; - ul_ccch_msg.msg.rrc_con_req.ue_id.random = 1000; + ul_ccch_msg.msg.rrc_con_req.ue_id.random = rand() % 2^40; } + ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING; - liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - byte_buffer_t *pdcp_buf = pool_allocate;; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits / 8; - pdcp_buf->set_timestamp(); + send_ul_ccch_msg(); - // Set UE contention resolution ID in MAC - uint64_t uecri = 0; - uint8_t *ue_cri_ptr = (uint8_t *) &uecri; - uint32_t nbytes = 6; - for (uint32_t i = 0; i < nbytes; i++) { - ue_cri_ptr[nbytes - i - 1] = pdcp_buf->msg[i]; - } - rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); - - mac->set_contention_id(uecri); - - rrc_log->info("Sending RRC Connection Request on SRB0\n"); - pdcp->write_sdu(RB_ID_SRB0, pdcp_buf); } /* RRC connection re-establishment procedure (5.3.7) */ -void rrc::send_con_restablish_request() { - - srslte_cell_t cell; - phy->get_current_cell(&cell); - - LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; - LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; - +void rrc::send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause, uint16_t crnti) +{ // Compute shortMAC-I uint8_t varShortMAC[128], varShortMAC_packed[16]; bzero(varShortMAC, 128); bzero(varShortMAC_packed, 16); uint8_t *msg_ptr = varShortMAC; - liblte_rrc_pack_cell_identity_ie(0x1a2d0, &msg_ptr); - liblte_rrc_pack_phys_cell_id_ie(cell.id, &msg_ptr); - mac_interface_rrc::ue_rnti_t ue_rnti; - mac->get_rntis(&ue_rnti); - liblte_rrc_pack_c_rnti_ie(ue_rnti.crnti, &msg_ptr); - srslte_bit_pack_vector(varShortMAC, varShortMAC_packed, msg_ptr - varShortMAC); + // ASN.1 encode byte-aligned VarShortMAC-Input + liblte_rrc_pack_cell_identity_ie(current_cell->sib1.cell_id, &msg_ptr); + msg_ptr = &varShortMAC[4]; + liblte_rrc_pack_phys_cell_id_ie(phy->get_current_pci(), &msg_ptr); + msg_ptr = &varShortMAC[4+2]; + liblte_rrc_pack_c_rnti_ie(crnti, &msg_ptr); + srslte_bit_pack_vector(varShortMAC, varShortMAC_packed, (4+2+4)*8); + + rrc_log->info("Generated varShortMAC: cellId=0x%x, PCI=%d, rnti=%d\n", + current_cell->sib1.cell_id, phy->get_current_pci(), crnti); + + // Compute MAC-I uint8_t mac_key[4]; - security_128_eia2(&k_rrc_int[16], - 1, - 1, - 1, - varShortMAC_packed, - 7, - mac_key); - - mac_interface_rrc::ue_rnti_t uernti; - mac->get_rntis(&uernti); + switch(integ_algo) { + case INTEGRITY_ALGORITHM_ID_128_EIA1: + security_128_eia1(&k_rrc_int[16], + 1, + 1, + 1, + varShortMAC_packed, + 10, + mac_key); + break; + case INTEGRITY_ALGORITHM_ID_128_EIA2: + security_128_eia2(&k_rrc_int[16], + 1, + 1, + 1, + varShortMAC_packed, + 10, + mac_key); + break; + default: + rrc_log->info("Unsupported integrity algorithm during reestablishment\n"); + return; + } // Prepare ConnectionRestalishmentRequest packet ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REEST_REQ; - ul_ccch_msg.msg.rrc_con_reest_req.ue_id.c_rnti = uernti.crnti; - ul_ccch_msg.msg.rrc_con_reest_req.ue_id.phys_cell_id = cell.id; - ul_ccch_msg.msg.rrc_con_reest_req.ue_id.short_mac_i = mac_key[2] << 8 | mac_key[3]; - ul_ccch_msg.msg.rrc_con_reest_req.cause = LIBLTE_RRC_CON_REEST_REQ_CAUSE_OTHER_FAILURE; - liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.c_rnti = crnti; + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.phys_cell_id = phy->get_current_pci(); + ul_ccch_msg.msg.rrc_con_reest_req.ue_id.short_mac_i = mac_key[1] << 8 | mac_key[0]; + ul_ccch_msg.msg.rrc_con_reest_req.cause = cause; rrc_log->info("Initiating RRC Connection Reestablishment Procedure\n"); rrc_log->console("RRC Connection Reestablishment\n"); @@ -674,72 +909,41 @@ void rrc::send_con_restablish_request() { set_phy_default(); mac->reset(); set_mac_default(); + state = RRC_STATE_CELL_SELECTING; +} - // FIXME: Cell selection should be different?? +// Actions following cell reselection 5.3.7.3 +void rrc::con_restablish_cell_reselected() +{ + liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Wait for cell re-synchronization - uint32_t timeout_cnt = 0; - while (!phy->sync_status() && timeout_cnt < TIMEOUT_RESYNC_REESTABLISH) { - usleep(10000); - timeout_cnt++; - } + rrc_log->info("Cell Selection finished. Initiating transmission of RRC Connection Reestablishment Request\n"); mac_timers->timer_get(t301)->reset(); mac_timers->timer_get(t301)->run(); mac_timers->timer_get(t311)->stop(); - rrc_log->info("Cell Selection finished. Initiating transmission of RRC Connection Reestablishment Request\n"); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - byte_buffer_t *pdcp_buf = pool_allocate;; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits / 8; + send_ul_ccch_msg(); - // Set UE contention resolution ID in MAC - uint64_t uecri = 0; - uint8_t *ue_cri_ptr = (uint8_t *) &uecri; - uint32_t nbytes = 6; - for (uint32_t i = 0; i < nbytes; i++) { - ue_cri_ptr[nbytes - i - 1] = pdcp_buf->msg[i]; - } - rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); - mac->set_contention_id(uecri); - - rrc_log->info("Sending RRC Connection Reestablishment Request on SRB0\n"); - pdcp->write_sdu(RB_ID_SRB0, pdcp_buf); } void rrc::send_con_restablish_complete() { rrc_log->debug("Preparing RRC Connection Reestablishment Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + rrc_log->console("RRC Connected\n"); + state = RRC_STATE_CONNECTED; // Prepare ConnectionSetupComplete packet ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_REEST_COMPLETE; ul_dcch_msg.msg.rrc_con_reest_complete.rrc_transaction_id = transaction_id; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - byte_buffer_t *pdcp_buf = pool_allocate;; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits / 8; - - state = RRC_STATE_CONNECTED; - rrc_log->console("RRC Connected\n"); - rrc_log->info("Sending RRC Connection Reestablishment Complete\n"); - pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); + send_ul_dcch_msg(); } void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) { rrc_log->debug("Preparing RRC Connection Setup Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + + state = RRC_STATE_CONNECTED; + rrc_log->console("RRC Connected\n"); // Prepare ConnectionSetupComplete packet ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_SETUP_COMPLETE; @@ -748,123 +952,209 @@ void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) { ul_dcch_msg.msg.rrc_con_setup_complete.selected_plmn_id = 1; memcpy(ul_dcch_msg.msg.rrc_con_setup_complete.dedicated_info_nas.msg, nas_msg->msg, nas_msg->N_bytes); ul_dcch_msg.msg.rrc_con_setup_complete.dedicated_info_nas.N_bytes = nas_msg->N_bytes; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - byte_buffer_t *pdcp_buf = pool_allocate;; - srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); - pdcp_buf->N_bytes = bit_buf.N_bits / 8; - pdcp_buf->set_timestamp(); - - state = RRC_STATE_CONNECTED; - rrc_log->console("RRC Connected\n"); - rrc_log->info("Sending RRC Connection Setup Complete\n"); - pdcp->write_sdu(RB_ID_SRB1, pdcp_buf); + send_ul_dcch_msg(); } void rrc::send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu) { rrc_log->debug("Preparing RX Info Transfer\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; // Prepare RX INFO packet ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_UL_INFO_TRANSFER; ul_dcch_msg.msg.ul_info_transfer.dedicated_info_type = LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_NAS; memcpy(ul_dcch_msg.msg.ul_info_transfer.dedicated_info.msg, sdu->msg, sdu->N_bytes); ul_dcch_msg.msg.ul_info_transfer.dedicated_info.N_bytes = sdu->N_bytes; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Reset and reuse sdu buffer - byte_buffer_t *pdu = sdu; - pdu->reset(); - - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits / 8; - pdu->set_timestamp(); - pdu->set_timestamp(); - - rrc_log->info("Sending RX Info Transfer\n"); - pdcp->write_sdu(lcid, pdu); + send_ul_dcch_msg(sdu); } void rrc::send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu) { rrc_log->debug("Preparing Security Mode Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; + ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_SECURITY_MODE_COMPLETE; ul_dcch_msg.msg.security_mode_complete.rrc_transaction_id = transaction_id; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits / 8; - pdu->set_timestamp(); - - rrc_log->info("Sending Security Mode Complete\n"); - pdcp->write_sdu(lcid, pdu); + send_ul_dcch_msg(pdu); } -void rrc::send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu) { +void rrc::send_rrc_con_reconfig_complete(byte_buffer_t *pdu) { rrc_log->debug("Preparing RRC Connection Reconfig Complete\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_RECONFIG_COMPLETE; ul_dcch_msg.msg.rrc_con_reconfig_complete.rrc_transaction_id = transaction_id; - liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits / 8; - pdu->set_timestamp(); - - rrc_log->info("Sending RRC Connection Reconfig Complete\n"); - pdcp->write_sdu(lcid, pdu); + send_ul_dcch_msg(pdu); } +bool rrc::ho_prepare() { + if (pending_mob_reconf) { + rrc_log->info("Processing HO command to target PCell=%d\n", mob_reconf.mob_ctrl_info.target_pci); + + int cell_idx = find_cell_idx(phy->get_current_earfcn(), mob_reconf.mob_ctrl_info.target_pci); + if (cell_idx < 0) { + rrc_log->error("Could not find target cell pci=%d\n", mob_reconf.mob_ctrl_info.target_pci); + return false; + } + + // Section 5.3.5.4 + mac_timers->timer_get(t310)->stop(); + mac_timers->timer_get(t304)->set(this, liblte_rrc_t304_num[mob_reconf.mob_ctrl_info.t304]); + if (mob_reconf.mob_ctrl_info.carrier_freq_eutra_present && + mob_reconf.mob_ctrl_info.carrier_freq_eutra.dl_carrier_freq != current_cell->earfcn) { + rrc_log->warning("Received mobilityControlInfo for inter-frequency handover\n"); + } + + // Save cell and current configuration + ho_src_cell_idx = find_cell_idx(phy->get_current_earfcn(), phy->get_current_pci()); + if (ho_src_cell_idx < 0) { + rrc_log->error("Source cell not found in known cells. Reconnecting to cell 0 in case of failure\n"); + ho_src_cell_idx = 0; + } + phy->get_config(&ho_src_phy_cfg); + mac->get_config(&ho_src_mac_cfg); + mac_interface_rrc::ue_rnti_t uernti; + mac->get_rntis(&uernti); + ho_src_rnti = uernti.crnti; + + // Reset/Reestablish stack + phy->meas_reset(); + mac->wait_uplink(); + pdcp->reestablish(); + rlc->reestablish(); + mac->reset(); + phy->reset(); + mac->set_ho_rnti(mob_reconf.mob_ctrl_info.new_ue_id, mob_reconf.mob_ctrl_info.target_pci); + apply_rr_config_common_dl(&mob_reconf.mob_ctrl_info.rr_cnfg_common); + + rrc_log->info("Selecting new cell pci=%d\n", known_cells[cell_idx].phy_cell.id); + if (!phy->cell_handover(known_cells[cell_idx].phy_cell)) { + rrc_log->error("Could not synchronize with target cell pci=%d\n", known_cells[cell_idx].phy_cell.id); + return false; + } + + if (mob_reconf.mob_ctrl_info.rach_cnfg_ded_present) { + rrc_log->info("Starting non-contention based RA with preamble_idx=%d, mask_idx=%d\n", + mob_reconf.mob_ctrl_info.rach_cnfg_ded.preamble_index, + mob_reconf.mob_ctrl_info.rach_cnfg_ded.prach_mask_index); + mac->start_noncont_ho(mob_reconf.mob_ctrl_info.rach_cnfg_ded.preamble_index, + mob_reconf.mob_ctrl_info.rach_cnfg_ded.prach_mask_index); + } else { + rrc_log->info("Starting contention-based RA\n"); + mac->start_cont_ho(); + } + + int ncc = -1; + if (mob_reconf.sec_cnfg_ho_present) { + ncc = mob_reconf.sec_cnfg_ho.intra_lte.next_hop_chaining_count; + if (mob_reconf.sec_cnfg_ho.intra_lte.key_change_ind) { + rrc_log->console("keyChangeIndicator in securityConfigHO not supported\n"); + return false; + } + if (mob_reconf.sec_cnfg_ho.intra_lte.sec_alg_cnfg_present) { + cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) mob_reconf.sec_cnfg_ho.intra_lte.sec_alg_cnfg.cipher_alg; + integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) mob_reconf.sec_cnfg_ho.intra_lte.sec_alg_cnfg.int_alg; + rrc_log->info("Changed Ciphering to %s and Integrity to %s\n", + ciphering_algorithm_id_text[cipher_algo], + integrity_algorithm_id_text[integ_algo]); + } + } + + usim->generate_as_keys_ho(mob_reconf.mob_ctrl_info.target_pci, phy->get_current_earfcn(), + ncc, + k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); + + pdcp->config_security_all(k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + send_rrc_con_reconfig_complete(NULL); + } + return true; +} + +void rrc::ho_ra_completed(bool ra_successful) { + if (pending_mob_reconf) { + + measurements.ho_finish(); + + if (mob_reconf.meas_cnfg_present) { + measurements.parse_meas_config(&mob_reconf.meas_cnfg); + } + + if (ra_successful) { + mac_timers->timer_get(t304)->stop(); + + apply_rr_config_common_ul(&mob_reconf.mob_ctrl_info.rr_cnfg_common); + if (mob_reconf.rr_cnfg_ded_present) { + apply_rr_config_dedicated(&mob_reconf.rr_cnfg_ded); + } + } + + rrc_log->info("HO %ssuccessful\n", ra_successful?"":"un"); + rrc_log->console("HO %ssuccessful\n", ra_successful?"":"un"); + + pending_mob_reconf = false; + if (ra_successful) { + state = RRC_STATE_CONNECTED; + } + } else { + rrc_log->error("Received HO random access completed but no pending mobility reconfiguration info\n"); + } +} + +// This is T304 expiry 5.3.5.6 +void rrc::ho_failed() { + + // Instruct PHY to resync with source PCI + if (!phy->cell_handover(known_cells[ho_src_cell_idx].phy_cell)) { + rrc_log->error("Could not synchronize with target cell pci=%d\n", known_cells[ho_src_cell_idx].phy_cell.id); + return; + } + + // Set previous PHY/MAC configuration + phy->set_config(&ho_src_phy_cfg); + mac->set_config(&ho_src_mac_cfg); + + // Start the Reestablishment Procedure + send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_HANDOVER_FAILURE, ho_src_rnti); +} void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, byte_buffer_t *pdu) { uint32_t i; - if (reconfig->rr_cnfg_ded_present) { - apply_rr_config_dedicated(&reconfig->rr_cnfg_ded); - } else { - printf("received con reconfig no rr confg present\n"); - } - if (reconfig->meas_cnfg_present) { - //TODO: handle meas_cnfg - } if (reconfig->mob_ctrl_info_present) { - //TODO: handle mob_ctrl_info - } - send_rrc_con_reconfig_complete(lcid, pdu); + if (reconfig->mob_ctrl_info.target_pci == phy->get_current_pci()) { + rrc_log->warning("Received HO command to own cell\n"); + send_rrc_con_reconfig_complete(pdu); + } else { + rrc_log->info("Received HO command to target PCell=%d\n", reconfig->mob_ctrl_info.target_pci); + rrc_log->console("Received HO command to target PCell=%d, NCC=%d\n", + reconfig->mob_ctrl_info.target_pci, reconfig->sec_cnfg_ho.intra_lte.next_hop_chaining_count); - byte_buffer_t *nas_sdu; - for (i = 0; i < reconfig->N_ded_info_nas; i++) { - nas_sdu = pool_allocate;; - memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes); - nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; - nas->write_pdu(lcid, nas_sdu); + // store mobilityControlInfo + memcpy(&mob_reconf, reconfig, sizeof(LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT)); + pending_mob_reconf = true; + + state = RRC_STATE_HO_PREPARE; + } + + } else { + // Section 5.3.5.3 + if (reconfig->rr_cnfg_ded_present) { + apply_rr_config_dedicated(&reconfig->rr_cnfg_ded); + } + if (reconfig->meas_cnfg_present) { + measurements.parse_meas_config(&reconfig->meas_cnfg); + } + + send_rrc_con_reconfig_complete(pdu); + + byte_buffer_t *nas_sdu; + for (i = 0; i < reconfig->N_ded_info_nas; i++) { + nas_sdu = pool_allocate; + memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes); + nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; + nas->write_pdu(lcid, nas_sdu); + } } } @@ -902,6 +1192,8 @@ void rrc::write_pdu_bcch_bch(byte_buffer_t *pdu) { } void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) { + mac->bcch_stop_rx(); + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received."); rrc_log->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us()); LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg; @@ -910,72 +1202,120 @@ void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) { pool->deallocate(pdu); liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dlsch_msg); - if (dlsch_msg.N_sibs > 0) { - if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && SI_ACQUIRE_SIB1 == si_acquire_state) { - mac->bcch_stop_rx(); - - // Handle SIB1 - memcpy(¤t_cell->sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); - - rrc_log->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n", - current_cell->sib1.cell_id & 0xfff, - liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length], - liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]); - - - // Set TDD Config - if (current_cell->sib1.tdd) { - phy->set_config_tdd(¤t_cell->sib1.tdd_cnfg); - } + for(uint32_t i=0; iinfo("Processing SIB: %d\n", liblte_rrc_sys_info_block_type_num[dlsch_msg.sibs[i].sib_type]); + if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[i].sib_type && SI_ACQUIRE_SIB1 == si_acquire_state) { + memcpy(¤t_cell->sib1, &dlsch_msg.sibs[i].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); current_cell->has_valid_sib1 = true; - - // Send PLMN and TAC to NAS - std::stringstream ss; - for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) { - nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code); - } - - // Jump to next state - switch(state) { - case RRC_STATE_CELL_SELECTING: - si_acquire_state = SI_ACQUIRE_SIB2; - break; - case RRC_STATE_PLMN_SELECTION: - si_acquire_state = SI_ACQUIRE_IDLE; - rrc_log->info("SI Acquisition done. Searching next cell...\n"); - usleep(5000); - phy->cell_search_next(); - break; - default: - si_acquire_state = SI_ACQUIRE_IDLE; - } - - } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && - SI_ACQUIRE_SIB2 == si_acquire_state) { - mac->bcch_stop_rx(); - - // Handle SIB2 - memcpy(¤t_cell->sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); - rrc_log->info("SIB2 received\n"); - - apply_sib2_configs(¤t_cell->sib2); - + handle_sib1(); + } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[i].sib_type && !current_cell->has_valid_sib2) { + memcpy(¤t_cell->sib2, &dlsch_msg.sibs[i].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); current_cell->has_valid_sib2 = true; - - // Jump to next state - switch(state) { - case RRC_STATE_CELL_SELECTING: - si_acquire_state = SI_ACQUIRE_IDLE; - state = RRC_STATE_CELL_SELECTED; - break; - default: - si_acquire_state = SI_ACQUIRE_IDLE; - } + handle_sib2(); + } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3 == dlsch_msg.sibs[i].sib_type && !current_cell->has_valid_sib3) { + memcpy(¤t_cell->sib3, &dlsch_msg.sibs[i].sib.sib3, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT)); + current_cell->has_valid_sib3 = true; + handle_sib3(); + }else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13 == dlsch_msg.sibs[i].sib_type && !current_cell->has_valid_sib13) { + memcpy(¤t_cell->sib13, &dlsch_msg.sibs[0].sib.sib13, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT)); + current_cell->has_valid_sib13 = true; + handle_sib13(); } } + if(current_cell->has_valid_sib2) { + sysinfo_index++; + } } +void rrc::handle_sib1() +{ + rrc_log->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n", + current_cell->sib1.cell_id&0xfff, + liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length], + liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]); + + // Print SIB scheduling info + uint32_t i,j; + for(i=0;isib1.N_sched_info;i++){ + for(j=0;jsib1.sched_info[i].N_sib_mapping_info;j++){ + LIBLTE_RRC_SIB_TYPE_ENUM t = current_cell->sib1.sched_info[i].sib_mapping_info[j].sib_type; + LIBLTE_RRC_SI_PERIODICITY_ENUM p = current_cell->sib1.sched_info[i].si_periodicity; + rrc_log->debug("SIB scheduling info, sib_type=%d, si_periodicity=%d\n", + liblte_rrc_sib_type_num[t], + liblte_rrc_si_periodicity_num[p]); + } + } + + // Set TDD Config + if(current_cell->sib1.tdd) { + phy->set_config_tdd(¤t_cell->sib1.tdd_cnfg); + } + + current_cell->has_valid_sib1 = true; + + // Send PLMN and TAC to NAS + std::stringstream ss; + for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) { + nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code); + } + + // Jump to next state + switch(state) { + case RRC_STATE_CELL_SELECTING: + si_acquire_state = SI_ACQUIRE_SIB2; + break; + case RRC_STATE_PLMN_SELECTION: + si_acquire_state = SI_ACQUIRE_IDLE; + rrc_log->info("SI Acquisition done. Searching next cell...\n"); + usleep(5000); + phy->cell_search_next(); + break; + default: + si_acquire_state = SI_ACQUIRE_IDLE; + } +} + +void rrc::handle_sib2() +{ + rrc_log->info("SIB2 received\n"); + + apply_sib2_configs(¤t_cell->sib2); + +} + +void rrc::handle_sib3() +{ + rrc_log->info("SIB3 received\n"); + + LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3 = ¤t_cell->sib3; + + // cellReselectionInfoCommon + cell_resel_cfg.q_hyst = liblte_rrc_q_hyst_num[sib3->q_hyst]; + + // cellReselectionServingFreqInfo + cell_resel_cfg.threshservinglow = sib3->thresh_serving_low; + + // intraFreqCellReselectionInfo + cell_resel_cfg.Qrxlevmin = sib3->q_rx_lev_min; + if (sib3->s_intra_search_present) { + cell_resel_cfg.s_intrasearchP = sib3->s_intra_search; + } else { + cell_resel_cfg.s_intrasearchP = INFINITY; + } + +} + +void rrc::handle_sib13() +{ + rrc_log->info("SIB13 received\n"); + +// mac->set_config_mbsfn_sib13(¤t_cell->sib13.mbsfn_area_info_list_r9[0], +// current_cell->sib13.mbsfn_area_info_list_r9_size, +// ¤t_cell->sib13.mbsfn_notification_config); +} + + /******************************************************************************* @@ -1012,17 +1352,20 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) { LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi_paged; for (uint32_t i = 0; i < pcch_msg.paging_record_list_size; i++) { s_tmsi_paged = &pcch_msg.paging_record_list[i].ue_identity.s_tmsi; - rrc_log->info("Received paging (%d/%d) for UE 0x%x\n", i + 1, pcch_msg.paging_record_list_size, - pcch_msg.paging_record_list[i].ue_identity.s_tmsi); - rrc_log->console("Received paging (%d/%d) for UE 0x%x\n", i + 1, pcch_msg.paging_record_list_size, - pcch_msg.paging_record_list[i].ue_identity.s_tmsi); + rrc_log->info("Received paging (%d/%d) for UE %x:%x\n", i + 1, pcch_msg.paging_record_list_size, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi.mmec, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi.m_tmsi); + rrc_log->console("Received paging (%d/%d) for UE %x:%x\n", i + 1, pcch_msg.paging_record_list_size, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi.mmec, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi.m_tmsi); if (s_tmsi.mmec == s_tmsi_paged->mmec && s_tmsi.m_tmsi == s_tmsi_paged->m_tmsi) { rrc_log->info("S-TMSI match in paging message\n"); rrc_log->console("S-TMSI match in paging message\n"); mac->pcch_stop_rx(); if (RRC_STATE_IDLE == state) { rrc_log->info("RRC in IDLE state - sending connection request.\n"); - state = RRC_STATE_CELL_SELECTING; + connection_requested = true; + state = RRC_STATE_CELL_SELECTED; } } } @@ -1046,10 +1389,65 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) { * Packet processing * * -* *******************************************************************************/ +byte_buffer_t* rrc::byte_align_and_pack(byte_buffer_t *pdu) +{ + // Byte align and pack the message bits for PDCP + if ((bit_buf.N_bits % 8) != 0) { + for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) + bit_buf.msg[bit_buf.N_bits + i] = 0; + bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); + } + + // Reset and reuse sdu buffer if provided + byte_buffer_t *pdcp_buf = pdu; + + if (pdcp_buf) { + pdcp_buf->reset(); + } else { + pdcp_buf = pool_allocate; + } + + srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits); + pdcp_buf->N_bytes = bit_buf.N_bits / 8; + pdcp_buf->set_timestamp(); + + return pdcp_buf; +} + +void rrc::send_ul_ccch_msg(byte_buffer_t *pdu) +{ + liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + pdu = byte_align_and_pack(pdu); + + // Set UE contention resolution ID in MAC + uint64_t uecri = 0; + uint8_t *ue_cri_ptr = (uint8_t *) &uecri; + uint32_t nbytes = 6; + for (uint32_t i = 0; i < nbytes; i++) { + ue_cri_ptr[nbytes - i - 1] = pdu->msg[i]; + } + + rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); + mac->set_contention_id(uecri); + + rrc_log->info("Sending %s\n", liblte_rrc_ul_ccch_msg_type_text[ul_ccch_msg.msg_type]); + pdcp->write_sdu(RB_ID_SRB0, pdu); +} + +void rrc::send_ul_dcch_msg(byte_buffer_t *pdu) +{ + liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); + + pdu = byte_align_and_pack(pdu); + + rrc_log->info("Sending %s\n", liblte_rrc_ul_dcch_msg_type_text[ul_dcch_msg.msg_type]); + pdcp->write_sdu(RB_ID_SRB1, pdu); +} + void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { - rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", get_rb_name(lcid).c_str()); + + rrc_log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU", get_rb_name(lcid)); switch (state) { case RRC_STATE_CONNECTING: send_con_setup_complete(sdu); @@ -1058,14 +1456,13 @@ void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { send_ul_info_transfer(lcid, sdu); break; default: - rrc_log->error("SDU received from NAS while RRC state = %s", rrc_state_text[state]); + rrc_log->error("SDU received from NAS while RRC state = %s\n", rrc_state_text[state]); break; } } void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { - rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", get_rb_name(lcid).c_str()); - rrc_log->info("TX PDU Stack latency: %ld us\n", pdu->get_latency_us()); + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "RX %s PDU", get_rb_name(lcid)); switch (lcid) { case RB_ID_SRB0: @@ -1076,7 +1473,7 @@ void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { parse_dl_dcch(lcid, pdu); break; default: - rrc_log->error("TX PDU with invalid bearer id: %s", lcid); + rrc_log->error("RX PDU with invalid bearer id: %s", lcid); break; } } @@ -1127,7 +1524,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dl_dcch_msg); rrc_log->info("%s - Received %s\n", - get_rb_name(lcid).c_str(), + get_rb_name(lcid), liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg.msg_type]); // Reset and reuse pdu buffer if possible @@ -1146,10 +1543,23 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.cipher_alg; integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg; + rrc_log->info("Received Security Mode Command eea: %s, eia: %s\n", + ciphering_algorithm_id_text[cipher_algo], + integrity_algorithm_id_text[integ_algo]); + + // Generate AS security keys + uint8_t k_asme[32]; + nas->get_k_asme(k_asme, 32); + usim->generate_as_keys(k_asme, nas->get_ul_count()-1, k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); + rrc_log->debug_hex(k_rrc_enc, 32, "RRC encryption key - k_rrc_enc"); + rrc_log->debug_hex(k_rrc_int, 32, "RRC integrity key - k_rrc_int"); + rrc_log->debug_hex(k_up_enc, 32, "UP encryption key - k_up_enc"); + // Configure PDCP for security - usim->generate_as_keys(nas->get_ul_count(), k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + pdcp->enable_integrity(lcid); send_security_mode_complete(lcid, pdu); + pdcp->enable_encryption(lcid); break; case LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG: transaction_id = dl_dcch_msg.msg.rrc_con_reconfig.rrc_transaction_id; @@ -1159,7 +1569,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { transaction_id = dl_dcch_msg.msg.ue_cap_enquiry.rrc_transaction_id; for (uint32_t i = 0; i < dl_dcch_msg.msg.ue_cap_enquiry.N_ue_cap_reqs; i++) { if (LIBLTE_RRC_RAT_TYPE_EUTRA == dl_dcch_msg.msg.ue_cap_enquiry.ue_capability_request[i]) { - send_rrc_ue_cap_info(lcid, pdu); + send_rrc_ue_cap_info(pdu); break; } } @@ -1190,14 +1600,13 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { * *******************************************************************************/ void rrc::enable_capabilities() { - bool enable_ul_64 = ue_category >= 5 && current_cell->sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam; + bool enable_ul_64 = args.ue_category >= 5 && current_cell->sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam; rrc_log->info("%s 64QAM PUSCH\n", enable_ul_64 ? "Enabling" : "Disabling"); phy->set_config_64qam_en(enable_ul_64); } -void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { +void rrc::send_rrc_ue_cap_info(byte_buffer_t *pdu) { rrc_log->debug("Preparing UE Capability Info\n"); - LIBLTE_RRC_UL_DCCH_MSG_STRUCT ul_dcch_msg; ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_UE_CAPABILITY_INFO; ul_dcch_msg.msg.ue_capability_info.rrc_transaction_id = transaction_id; @@ -1208,7 +1617,7 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *cap = &info->ue_capability_rat[0].eutra_capability; cap->access_stratum_release = LIBLTE_RRC_ACCESS_STRATUM_RELEASE_REL8; - cap->ue_category = ue_category; + cap->ue_category = args.ue_category; cap->pdcp_params.max_rohc_ctxts_present = false; cap->pdcp_params.supported_rohc_profiles[0] = false; @@ -1224,31 +1633,17 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { cap->phy_params.specific_ref_sigs_supported = false; cap->phy_params.tx_antenna_selection_supported = false; - //TODO: Generate this from user input? - cap->rf_params.N_supported_band_eutras = 3; - cap->rf_params.supported_band_eutra[0].band_eutra = 3; - cap->rf_params.supported_band_eutra[0].half_duplex = false; - cap->rf_params.supported_band_eutra[1].band_eutra = 7; - cap->rf_params.supported_band_eutra[1].half_duplex = false; - cap->rf_params.supported_band_eutra[2].band_eutra = 20; - cap->rf_params.supported_band_eutra[2].half_duplex = false; - - cap->meas_params.N_band_list_eutra = 3; - cap->meas_params.band_list_eutra[0].N_inter_freq_need_for_gaps = 3; - cap->meas_params.band_list_eutra[0].inter_freq_need_for_gaps[0] = true; - cap->meas_params.band_list_eutra[0].inter_freq_need_for_gaps[1] = true; - cap->meas_params.band_list_eutra[0].inter_freq_need_for_gaps[2] = true; - cap->meas_params.band_list_eutra[1].N_inter_freq_need_for_gaps = 3; - cap->meas_params.band_list_eutra[1].inter_freq_need_for_gaps[0] = true; - cap->meas_params.band_list_eutra[1].inter_freq_need_for_gaps[1] = true; - cap->meas_params.band_list_eutra[1].inter_freq_need_for_gaps[2] = true; - cap->meas_params.band_list_eutra[2].N_inter_freq_need_for_gaps = 3; - cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[0] = true; - cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[1] = true; - cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[2] = true; + cap->rf_params.N_supported_band_eutras = args.nof_supported_bands; + cap->meas_params.N_band_list_eutra = args.nof_supported_bands; + for (uint32_t i=0;irf_params.supported_band_eutra[i].band_eutra = args.supported_bands[i]; + cap->rf_params.supported_band_eutra[i].half_duplex = false; + cap->meas_params.band_list_eutra[i].N_inter_freq_need_for_gaps = 1; + cap->meas_params.band_list_eutra[i].inter_freq_need_for_gaps[0] = true; + } cap->feature_group_indicator_present = true; - cap->feature_group_indicator = 0x62001000; + cap->feature_group_indicator = args.feature_group; cap->inter_rat_params.utra_fdd_present = false; cap->inter_rat_params.utra_tdd128_present = false; cap->inter_rat_params.utra_tdd384_present = false; @@ -1259,18 +1654,7 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { liblte_rrc_pack_ul_dcch_msg(&ul_dcch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); - // Byte align and pack the message bits for PDCP - if ((bit_buf.N_bits % 8) != 0) { - for (uint32_t i = 0; i < 8 - (bit_buf.N_bits % 8); i++) - bit_buf.msg[bit_buf.N_bits + i] = 0; - bit_buf.N_bits += 8 - (bit_buf.N_bits % 8); - } - srslte_bit_pack_vector(bit_buf.msg, pdu->msg, bit_buf.N_bits); - pdu->N_bytes = bit_buf.N_bits / 8; - pdu->set_timestamp(); - - rrc_log->info("Sending UE Capability Info\n"); - pdcp->write_sdu(lcid, pdu); + send_ul_dcch_msg(pdu); } @@ -1292,6 +1676,54 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { * *******************************************************************************/ +void rrc::apply_rr_config_common_dl(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config) { + mac_interface_rrc::mac_cfg_t mac_cfg; + mac->get_config(&mac_cfg); + if (config->rach_cnfg_present) { + memcpy(&mac_cfg.rach, &config->rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); + } + mac_cfg.prach_config_index = config->prach_cnfg.root_sequence_index; + mac_cfg.ul_harq_params.max_harq_msg3_tx = config->rach_cnfg.max_harq_msg3_tx; + + mac->set_config(&mac_cfg); + + phy_interface_rrc::phy_cfg_t phy_cfg; + phy->get_config(&phy_cfg); + phy_interface_rrc::phy_cfg_common_t *common = &phy_cfg.common; + + if (config->pdsch_cnfg_present) { + memcpy(&common->pdsch_cnfg, &config->pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT)); + } + common->prach_cnfg.root_sequence_index = config->prach_cnfg.root_sequence_index; + if (config->prach_cnfg.prach_cnfg_info_present) { + memcpy(&common->prach_cnfg.prach_cnfg_info, &config->prach_cnfg.prach_cnfg_info, sizeof(LIBLTE_RRC_PRACH_CONFIG_INFO_STRUCT)); + } + + phy->set_config_common(common); +} + +void rrc::apply_rr_config_common_ul(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config) { + phy_interface_rrc::phy_cfg_t phy_cfg; + phy->get_config(&phy_cfg); + phy_interface_rrc::phy_cfg_common_t *common = &phy_cfg.common; + + memcpy(&common->pusch_cnfg, &config->pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT)); + if (config->pucch_cnfg_present) { + memcpy(&common->pucch_cnfg, &config->pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT)); + } + if (config->ul_pwr_ctrl_present) { + memcpy(&common->ul_pwr_ctrl, &config->ul_pwr_ctrl, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT)); + } + if (config->srs_ul_cnfg.present) { + memcpy(&common->srs_ul_cnfg, &config->srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT)); + } else { + // default is release + common->srs_ul_cnfg.present = false; + } + phy->set_config_common(common); + phy->configure_ul_params(); +} + void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) { // Apply RACH timeAlginmentTimer configuration @@ -1302,6 +1734,11 @@ void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) { memcpy(&cfg.rach, &sib2->rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); cfg.prach_config_index = sib2->rr_config_common_sib.prach_cnfg.root_sequence_index; cfg.ul_harq_params.max_harq_msg3_tx = cfg.rach.max_harq_msg3_tx; + // Apply MBSFN configuration +// cfg.mbsfn_subfr_cnfg_list_size = sib2->mbsfn_subfr_cnfg_list_size; +// for(uint8_t i=0;imbsfn_subfr_cnfg_list_size;i++) { +// memcpy(&cfg.mbsfn_subfr_cnfg_list[i], &sib2->mbsfn_subfr_cnfg_list[i], sizeof(LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT)); +// } mac->set_config(&cfg); @@ -1391,8 +1828,8 @@ void rrc::apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT sizeof(LIBLTE_RRC_UL_POWER_CONTROL_DEDICATED_STRUCT)); } else if (apply_defaults) { current_cfg->ul_pwr_ctrl_ded.p0_ue_pusch = 0; - current_cfg->ul_pwr_ctrl_ded.delta_mcs_en = LIBLTE_RRC_DELTA_MCS_ENABLED_EN0; - current_cfg->ul_pwr_ctrl_ded.accumulation_en = true; + current_cfg->ul_pwr_ctrl_ded.delta_mcs_en = LIBLTE_RRC_DELTA_MCS_ENABLED_EN0; + current_cfg->ul_pwr_ctrl_ded.accumulation_en = true; current_cfg->ul_pwr_ctrl_ded.p0_ue_pucch = 0; current_cfg->ul_pwr_ctrl_ded.p_srs_offset = 7; } @@ -1438,7 +1875,9 @@ void rrc::apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT if (phy_cnfg->antenna_info_present) { if (!phy_cnfg->antenna_info_default_value) { if (phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_1 && - phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_2) { + phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_2 && + phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_3 && + phy_cnfg->antenna_info_explicit_value.tx_mode != LIBLTE_RRC_TRANSMISSION_MODE_4) { rrc_log->error("Transmission mode TM%s not currently supported by srsUE\n", liblte_rrc_transmission_mode_text[phy_cnfg->antenna_info_explicit_value.tx_mode]); } @@ -1462,8 +1901,10 @@ void rrc::apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT } if (phy_cnfg->pdsch_cnfg_ded_present) { current_cfg->pdsch_cnfg_ded = phy_cnfg->pdsch_cnfg_ded; + rrc_log->info("Set PDSCH-Config=%s (present)\n", liblte_rrc_pdsch_config_p_a_text[(int) current_cfg->pdsch_cnfg_ded]); } else if (apply_defaults) { current_cfg->pdsch_cnfg_ded = LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_0; + rrc_log->info("Set PDSCH-Config=%s (default)\n", liblte_rrc_pdsch_config_p_a_text[(int) current_cfg->pdsch_cnfg_ded]); } if (phy_cnfg->cqi_report_cnfg_present) { @@ -1539,7 +1980,7 @@ void rrc::apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cnfg default_cfg.time_alignment_timer = mac_cnfg->time_alignment_timer; } - // Setup MAC configuration + // Setup MAC configuration mac->set_config_main(&default_cfg); // Update UL HARQ config @@ -1601,7 +2042,7 @@ void rrc::handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup) { void rrc::handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup) { mac_timers->timer_get(t301)->stop(); - // TODO: Restablish DRB1. Not done because never was suspended + // TODO: Reestablish DRB1. Not done because never was suspended // Apply the Radio Resource configuration apply_rr_config_dedicated(&setup->rr_cnfg); @@ -1617,6 +2058,8 @@ void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) { pdcp->add_bearer(srb_cnfg->srb_id, srslte_pdcp_config_t(true)); // Set PDCP config control flag if(RB_ID_SRB2 == srb_cnfg->srb_id) { pdcp->config_security(srb_cnfg->srb_id, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + pdcp->enable_integrity(srb_cnfg->srb_id); + pdcp->enable_encryption(srb_cnfg->srb_id); } // Setup RLC @@ -1655,7 +2098,7 @@ void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) { } srbs[srb_cnfg->srb_id] = *srb_cnfg; - rrc_log->info("Added radio bearer %s\n", get_rb_name(srb_cnfg->srb_id).c_str()); + rrc_log->info("Added radio bearer %s\n", get_rb_name(srb_cnfg->srb_id)); } void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) { @@ -1683,7 +2126,8 @@ void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) { } } pdcp->add_bearer(lcid, pdcp_cfg); - // TODO: setup PDCP security (using k_up_enc) + pdcp->config_security(lcid, k_up_enc, k_up_int, cipher_algo, integ_algo); + pdcp->enable_encryption(lcid); // Setup RLC rlc->add_bearer(lcid, srslte_rlc_config_t(&drb_cnfg->rlc_cnfg)); @@ -1713,7 +2157,7 @@ void rrc::add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg) { drbs[lcid] = *drb_cnfg; drb_up = true; - rrc_log->info("Added radio bearer %s\n", get_rb_name(lcid).c_str()); + rrc_log->info("Added radio bearer %s\n", get_rb_name(lcid)); } void rrc::release_drb(uint8_t lcid) { @@ -1761,4 +2205,615 @@ void rrc::set_rrc_default() { } + + + + + + + + + + + + + + + + + +/************************************************************************ + * + * + * RRC Measurements + * + * + ************************************************************************/ + +void rrc::rrc_meas::init(rrc *parent) { + this->parent = parent; + this->log_h = parent->rrc_log; + this->phy = parent->phy; + this->mac_timers = parent->mac_timers; + s_measure_enabled = false; + reset(); +} + +void rrc::rrc_meas::reset() +{ + filter_k_rsrp = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; + filter_k_rsrq = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; + objects.clear(); + active.clear(); + reports_cfg.clear(); + phy->meas_reset(); + bzero(&pcell_measurement, sizeof(meas_value_t)); +} + +/* L3 filtering 5.5.3.2 */ +void rrc::rrc_meas::L3_filter(meas_value_t *value, float values[NOF_MEASUREMENTS]) +{ + for (int i=0;ims[i]) { + value->ms[i] = SRSLTE_VEC_EMA(values[i], value->ms[i], filter_a[i]); + } else { + value->ms[i] = values[i]; + } + } +} + +void rrc::rrc_meas::new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, float rsrq, uint32_t tti) +{ + float values[NOF_MEASUREMENTS] = {rsrp, rsrq}; + // This indicates serving cell + if (earfcn == 0) { + + log_h->info("MEAS: New measurement serving cell, rsrp=%f, rsrq=%f, tti=%d\n", rsrp, rsrq, tti); + + L3_filter(&pcell_measurement, values); + } else { + // Add to known cells + parent->add_neighbour_cell(earfcn, pci, rsrp); + + log_h->info("MEAS: New measurement earfcn=%d, pci=%d, rsrp=%f, rsrq=%f, tti=%d\n", earfcn, pci, rsrp, rsrq, tti); + + // Save PHY measurement for all active measurements whose earfcn/pci matches + for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { + meas_t *m = &iter->second; + if (objects[m->object_id].earfcn == earfcn) { + // If it's a newly discovered cell, add it to objects + if (!m->cell_values.count(pci)) { + uint32_t cell_idx = objects[m->object_id].cells.size(); + objects[m->object_id].cells[cell_idx].pci = pci; + objects[m->object_id].cells[cell_idx].q_offset = 0; + } + // Update or add cell + L3_filter(&m->cell_values[pci], values); + return; + } + } + + parent->rrc_log->warning("MEAS: Received measurement from unknown EARFCN=%d\n", earfcn); + } +} + +void rrc::rrc_meas::run_tti(uint32_t tti) { + // Measurement Report Triggering Section 5.5.4 + calculate_triggers(tti); +} + +bool rrc::rrc_meas::find_earfcn_cell(uint32_t earfcn, uint32_t pci, meas_obj_t **object, int *cell_idx) { + if (object) { + *object = NULL; + } + for (std::map::iterator obj = objects.begin(); obj != objects.end(); ++obj) { + if (obj->second.earfcn == earfcn) { + if (object) { + *object = &obj->second; + } + for (std::map::iterator c = obj->second.cells.begin(); c != obj->second.cells.end(); ++c) { + if (c->second.pci == pci) { + if (cell_idx) { + *cell_idx = c->first; + return true; + } + } + } + // return true if cell idx not found but frequency is found + if (cell_idx) { + *cell_idx = -1; + } + return true; + } + } + return false; +} + +/* Generate report procedure 5.5.5 */ +void rrc::rrc_meas::generate_report(uint32_t meas_id) +{ + parent->ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_MEASUREMENT_REPORT; + LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT *report = &parent->ul_dcch_msg.msg.measurement_report; + + bzero(report, sizeof(LIBLTE_RRC_MEASUREMENT_REPORT_STRUCT)); + + meas_t *m = &active[meas_id]; + report_cfg_t *cfg = &reports_cfg[m->report_id]; + + report->meas_id = meas_id; + report->pcell_rsrp_result = value_to_range(RSRP, pcell_measurement.ms[RSRP]); + report->pcell_rsrq_result = value_to_range(RSRQ, pcell_measurement.ms[RSRQ]); + + log_h->console("MEAS: Generate report MeasId=%d, rsrp=%f rsrq=%f\n", + report->meas_id, pcell_measurement.ms[RSRP], pcell_measurement.ms[RSRQ]); + + // TODO: report up to 8 best cells + for (std::map::iterator cell = m->cell_values.begin(); cell != m->cell_values.end(); ++cell) + { + if (cell->second.triggered && report->meas_result_neigh_cells.eutra.n_result < 8) + { + LIBLTE_RRC_MEAS_RESULT_EUTRA_STRUCT *rc = &report->meas_result_neigh_cells.eutra.result_eutra_list[report->meas_result_neigh_cells.eutra.n_result]; + + rc->phys_cell_id = cell->first; + rc->meas_result.have_rsrp = cfg->report_quantity==RSRP || cfg->report_quantity==BOTH; + rc->meas_result.have_rsrq = cfg->report_quantity==RSRQ || cfg->report_quantity==BOTH; + rc->meas_result.rsrp_result = value_to_range(RSRP, cell->second.ms[RSRP]); + rc->meas_result.rsrq_result = value_to_range(RSRQ, cell->second.ms[RSRQ]); + + log_h->info("MEAS: Add neigh=%d, pci=%d, rsrp=%f, rsrq=%f\n", + report->meas_result_neigh_cells.eutra.n_result, rc->phys_cell_id, + cell->second.ms[RSRP], cell->second.ms[RSRQ]); + + report->meas_result_neigh_cells.eutra.n_result++; + } + } + report->have_meas_result_neigh_cells = report->meas_result_neigh_cells.eutra.n_result > 0; + + m->nof_reports_sent++; + mac_timers->timer_get(m->periodic_timer)->stop(); + + if (m->nof_reports_sent < cfg->amount) { + mac_timers->timer_get(m->periodic_timer)->reset(); + mac_timers->timer_get(m->periodic_timer)->run(); + } else { + if (cfg->trigger_type == report_cfg_t::PERIODIC) { + m->triggered = false; + } + } + + // Send to lower layers + parent->send_ul_dcch_msg(); +} + +/* Handle entering/leaving event conditions 5.5.4.1 */ +bool rrc::rrc_meas::process_event(LIBLTE_RRC_EVENT_EUTRA_STRUCT *event, uint32_t tti, + bool enter_condition, bool exit_condition, + meas_t *m, meas_value_t *cell) +{ + bool generate_report = false; + if (enter_condition && (!m->triggered || !cell->triggered)) { + if (!cell->timer_enter_triggered) { + cell->timer_enter_triggered = true; + cell->enter_tti = tti; + } else if (srslte_tti_interval(tti, cell->enter_tti) >= event->time_to_trigger) { + m->triggered = true; + cell->triggered = true; + m->nof_reports_sent = 0; + generate_report = true; + } + } else if (exit_condition) { + if (!cell->timer_exit_triggered) { + cell->timer_exit_triggered = true; + cell->exit_tti = tti; + } else if (srslte_tti_interval(tti, cell->exit_tti) >= event->time_to_trigger) { + m->triggered = false; + cell->triggered = false; + mac_timers->timer_get(m->periodic_timer)->stop(); + if (event) { + if (event->event_id == LIBLTE_RRC_EVENT_ID_EUTRA_A3 && event->event_a3.report_on_leave) { + generate_report = true; + } + } + } + } + if (!enter_condition) { + cell->timer_enter_triggered = false; + } + if (!enter_condition) { + cell->timer_exit_triggered = false; + } + return generate_report; +} + +/* Calculate trigger conditions for each cell 5.5.4 */ +void rrc::rrc_meas::calculate_triggers(uint32_t tti) +{ + float Ofp = 0, Ocp = 0; + meas_obj_t *serving_object = NULL; + int serving_cell_idx = 0; + + // Get serving cell + if (active.size()) { + if (find_earfcn_cell(phy->get_current_earfcn(), phy->get_current_pci(), &serving_object, &serving_cell_idx)) { + Ofp = serving_object->q_offset; + if (serving_cell_idx >= 0) { + Ocp = serving_object->cells[serving_cell_idx].q_offset; + } + } else { + log_h->warning("Can't find current eafcn=%d, pci=%d in objects list. Using Ofp=0, Ocp=0\n", + phy->get_current_earfcn(), phy->get_current_pci()); + } + } + + for (std::map::iterator m = active.begin(); m != active.end(); ++m) { + report_cfg_t *cfg = &reports_cfg[m->second.report_id]; + float hyst = 0.5*cfg->event.hysteresis; + float Mp = pcell_measurement.ms[cfg->trigger_quantity]; + + LIBLTE_RRC_EVENT_ID_EUTRA_ENUM event_id = cfg->event.event_id; + const char *event_str = liblte_rrc_event_id_eutra_text[event_id]; + + bool gen_report = false; + + if (cfg->trigger_type == report_cfg_t::EVENT) { + + // A1 & A2 are for serving cell only + if (event_id < LIBLTE_RRC_EVENT_ID_EUTRA_A3) { + + bool enter_condition; + bool exit_condition; + if (event_id == LIBLTE_RRC_EVENT_ID_EUTRA_A1) { + enter_condition = Mp - hyst > range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range); + exit_condition = Mp + hyst < range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range); + } else { + enter_condition = Mp + hyst < range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range); + exit_condition = Mp - hyst > range_to_value(cfg->trigger_quantity, cfg->event.event_a1.eutra.range); + } + gen_report |= process_event(&cfg->event, tti, enter_condition, exit_condition, + &m->second, &m->second.cell_values[serving_cell_idx]); + + // Rest are evaluated for every cell in frequency + } else { + meas_obj_t *obj = &objects[m->second.object_id]; + for (std::map::iterator cell = obj->cells.begin(); cell != obj->cells.end(); ++cell) { + float Ofn = obj->q_offset; + float Ocn = cell->second.q_offset; + float Mn = m->second.cell_values[cell->second.pci].ms[cfg->trigger_quantity]; + float Off=0, th=0, th1=0, th2=0; + bool enter_condition = false; + bool exit_condition = false; + switch (event_id) { + case LIBLTE_RRC_EVENT_ID_EUTRA_A3: + Off = 0.5*cfg->event.event_a3.offset; + enter_condition = Mn + Ofn + Ocn - hyst > Mp + Ofp + Ocp + Off; + exit_condition = Mn + Ofn + Ocn + hyst < Mp + Ofp + Ocp + Off; + break; + case LIBLTE_RRC_EVENT_ID_EUTRA_A4: + th = range_to_value(cfg->trigger_quantity, cfg->event.event_a4.eutra.range); + enter_condition = Mn + Ofn + Ocn - hyst > th; + exit_condition = Mn + Ofn + Ocn + hyst < th; + break; + case LIBLTE_RRC_EVENT_ID_EUTRA_A5: + th1 = range_to_value(cfg->trigger_quantity, cfg->event.event_a5.eutra1.range); + th2 = range_to_value(cfg->trigger_quantity, cfg->event.event_a5.eutra2.range); + enter_condition = (Mp + hyst < th1) && (Mn + Ofn + Ocn - hyst > th2); + exit_condition = (Mp - hyst > th1) && (Mn + Ofn + Ocn + hyst < th2); + break; + default: + log_h->error("Error event %s not implemented\n", event_str); + } + gen_report |= process_event(&cfg->event, tti, enter_condition, exit_condition, + &m->second, &m->second.cell_values[cell->second.pci]); + } + } + } + if (gen_report) { + generate_report(m->first); + } + } +} + +// Procedure upon handover or reestablishment 5.5.6.1 +void rrc::rrc_meas::ho_finish() { + // Remove all measId with trigger periodic + std::map::iterator iter = active.begin(); + while (iter != active.end()) { + if (reports_cfg[iter->second.report_id].trigger_type == report_cfg_t::PERIODIC) { + remove_meas_id(iter++); + } else { + ++iter; + } + } + + //TODO: Inter-frequency handover + + // Stop all reports + for (std::map::iterator iter = active.begin(); iter != active.end(); ++iter) { + stop_reports(&iter->second); + } +} + +// 5.5.4.1 expiry of periodical reporting timer +bool rrc::rrc_meas::timer_expired(uint32_t timer_id) { + for (std::map::iterator iter = active.begin(); iter != active.end(); ++iter) { + if (iter->second.periodic_timer == timer_id) { + generate_report(iter->first); + return true; + } + } + return false; +} + +void rrc::rrc_meas::stop_reports(meas_t *m) { + mac_timers->timer_get(m->periodic_timer)->stop(); + m->triggered = false; +} + +void rrc::rrc_meas::stop_reports_object(uint32_t object_id) { + for (std::map::iterator iter = active.begin(); iter != active.end(); ++iter) { + if (iter->second.object_id == object_id) { + stop_reports(&iter->second); + } + } +} + +void rrc::rrc_meas::remove_meas_object(uint32_t object_id) { + std::map::iterator iter = active.begin(); + while (iter != active.end()) { + if (iter->second.object_id == object_id) { + remove_meas_id(iter++); + } else { + ++iter; + } + } +} + +void rrc::rrc_meas::remove_meas_report(uint32_t report_id) { + std::map::iterator iter = active.begin(); + while (iter != active.end()) { + if (iter->second.report_id == report_id) { + remove_meas_id(iter++); + } else { + ++iter; + } + } +} + +void rrc::rrc_meas::remove_meas_id(uint32_t measId) { + mac_timers->timer_get(active[measId].periodic_timer)->stop(); + mac_timers->timer_release_id(active[measId].periodic_timer); + log_h->info("MEAS: Removed measId=%d\n", measId); + active.erase(measId); +} + +void rrc::rrc_meas::remove_meas_id(std::map::iterator it) { + mac_timers->timer_get(it->second.periodic_timer)->stop(); + mac_timers->timer_release_id(it->second.periodic_timer); + log_h->info("MEAS: Removed measId=%d\n", it->first); + active.erase(it); +} + +/* Parses MeasConfig object from RRCConnectionReconfiguration message and applies configuration + * as per section 5.5.2 + */ +void rrc::rrc_meas::parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *cfg) +{ + + // Measurement object removal 5.5.2.4 + for (uint32_t i=0;iN_meas_obj_to_remove;i++) { + objects.erase(cfg->meas_obj_to_remove_list[i]); + remove_meas_object(cfg->meas_obj_to_remove_list[i]); + log_h->info("MEAS: Removed measObjectId=%d\n", cfg->meas_obj_to_remove_list[i]); + } + + // Measurement object addition/modification Section 5.5.2.5 + if (cfg->meas_obj_to_add_mod_list_present) { + for (uint32_t i=0;imeas_obj_to_add_mod_list.N_meas_obj;i++) { + if (cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_type == LIBLTE_RRC_MEAS_OBJECT_TYPE_EUTRA) { + LIBLTE_RRC_MEAS_OBJECT_EUTRA_STRUCT *src_obj = &cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_eutra; + + // Access the object if exists or create it + meas_obj_t *dst_obj = &objects[cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_id]; + + dst_obj->earfcn = src_obj->carrier_freq;; + if (src_obj->offset_freq_not_default) { + dst_obj->q_offset = liblte_rrc_q_offset_range_num[src_obj->offset_freq]; + } else { + dst_obj->q_offset = 0; + } + + if (src_obj->black_cells_to_remove_list_present) { + for (uint32_t j=0;jblack_cells_to_remove_list.N_cell_idx;j++) { + dst_obj->cells.erase(src_obj->black_cells_to_remove_list.cell_idx[j]); + } + } + + for (uint32_t j=0;jN_cells_to_add_mod;j++) { + dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].q_offset = liblte_rrc_q_offset_range_num[src_obj->cells_to_add_mod_list[j].cell_offset]; + dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].pci = src_obj->cells_to_add_mod_list[j].pci; + + log_h->info("MEAS: Added measObjectId=%d, earfcn=%d, q_offset=%f, pci=%d, offset_cell=%f\n", + cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_id, dst_obj->earfcn, dst_obj->q_offset, + dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].q_offset, + dst_obj->cells[src_obj->cells_to_add_mod_list[j].cell_idx].pci); + + } + + // Untrigger reports and stop timers + stop_reports_object(cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_id); + + // TODO: Blackcells + // TODO: meassubframepattern + + } else { + log_h->warning("MEAS: Unsupported MeasObject type %s\n", + liblte_rrc_meas_object_type_text[cfg->meas_obj_to_add_mod_list.meas_obj_list[i].meas_obj_type]); + } + } + } + + // Reporting configuration removal 5.5.2.6 + for (uint32_t i=0;iN_rep_cnfg_to_remove;i++) { + reports_cfg.erase(cfg->rep_cnfg_to_remove_list[i]); + remove_meas_report(cfg->rep_cnfg_to_remove_list[i]); + log_h->info("MEAS: Removed reportConfigId=%d\n", cfg->rep_cnfg_to_remove_list[i]); + } + + // Reporting configuration addition/modification 5.5.2.7 + if (cfg->rep_cnfg_to_add_mod_list_present) { + for (uint32_t i=0;irep_cnfg_to_add_mod_list.N_rep_cnfg;i++) { + if (cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_type == LIBLTE_RRC_REPORT_CONFIG_TYPE_EUTRA) { + LIBLTE_RRC_REPORT_CONFIG_EUTRA_STRUCT *src_rep = &cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_eutra; + // Access the object if exists or create it + report_cfg_t *dst_rep = &reports_cfg[cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_id]; + + dst_rep->trigger_type = src_rep->trigger_type==LIBLTE_RRC_TRIGGER_TYPE_EUTRA_EVENT?report_cfg_t::EVENT:report_cfg_t::PERIODIC; + dst_rep->event = src_rep->event; + dst_rep->amount = liblte_rrc_report_amount_num[src_rep->report_amount]; + dst_rep->interval = liblte_rrc_report_interval_num[src_rep->report_interval]; + dst_rep->max_cell = src_rep->max_report_cells; + dst_rep->trigger_quantity = (quantity_t) src_rep->trigger_quantity; + dst_rep->report_quantity = src_rep->report_quantity==LIBLTE_RRC_REPORT_QUANTITY_SAME_AS_TRIGGER_QUANTITY?dst_rep->trigger_quantity:BOTH; + + log_h->info("MEAS: Added reportConfigId=%d, event=%s, amount=%d, interval=%d\n", + cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_id, + liblte_rrc_event_id_eutra_text[dst_rep->event.event_id], + dst_rep->amount, dst_rep->interval); + + // Reset reports counter + for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { + if (iter->second.report_id == cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_id) { + iter->second.nof_reports_sent = 0; + stop_reports(&iter->second); + } + } + } else { + log_h->warning("MEAS: Unsupported reportConfigType %s\n", liblte_rrc_report_config_type_text[cfg->rep_cnfg_to_add_mod_list.rep_cnfg_list[i].rep_cnfg_type]); + } + } + } + + // Quantity configuration 5.5.2.8 + if (cfg->quantity_cnfg_present && cfg->quantity_cnfg.qc_eutra_present) { + if (cfg->quantity_cnfg.qc_eutra.fc_rsrp_not_default) { + filter_k_rsrp = liblte_rrc_filter_coefficient_num[cfg->quantity_cnfg.qc_eutra.fc_rsrp]; + } else { + filter_k_rsrp = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; + } + if (cfg->quantity_cnfg.qc_eutra.fc_rsrq_not_default) { + filter_k_rsrq = liblte_rrc_filter_coefficient_num[cfg->quantity_cnfg.qc_eutra.fc_rsrq]; + } else { + filter_k_rsrq = liblte_rrc_filter_coefficient_num[LIBLTE_RRC_FILTER_COEFFICIENT_FC4]; + } + filter_a[RSRP] = pow(0.5, (float) filter_k_rsrp/4); + filter_a[RSRQ] = pow(0.5, (float) filter_k_rsrq/4); + + log_h->info("MEAS: Quantity configuration k_rsrp=%d, k_rsrq=%d\n", filter_k_rsrp, filter_k_rsrq); + } + + // Measurement identity removal 5.5.2.2 + for (uint32_t i=0;iN_meas_id_to_remove;i++) { + remove_meas_id(cfg->meas_id_to_remove_list[i]); + } + + // Measurement identity addition/modification 5.5.2.3 + if (cfg->meas_id_to_add_mod_list_present) { + for (uint32_t i=0;imeas_id_to_add_mod_list.N_meas_id;i++) { + LIBLTE_RRC_MEAS_ID_TO_ADD_MOD_STRUCT *measId = &cfg->meas_id_to_add_mod_list.meas_id_list[i]; + // Stop the timer if the entry exists or create the timer if not + if (active.count(measId->meas_id)) { + mac_timers->timer_get(active[measId->meas_id].periodic_timer)->stop(); + } else { + active[measId->meas_id].periodic_timer = mac_timers->timer_get_unique_id(); + } + active[measId->meas_id].object_id = measId->meas_obj_id; + active[measId->meas_id].report_id = measId->rep_cnfg_id; + log_h->info("MEAS: Added measId=%d, measObjectId=%d, reportConfigId=%d\n", + measId->meas_id, measId->meas_obj_id, measId->rep_cnfg_id); + } + } + + // S-Measure + if (cfg->s_meas_present) { + if (cfg->s_meas) { + s_measure_enabled = true; + s_measure_value = range_to_value(RSRP, cfg->s_meas); + } else { + s_measure_enabled = false; + } + } + + update_phy(); +} + +/* Instruct PHY to start measurement */ +void rrc::rrc_meas::update_phy() +{ + phy->meas_reset(); + for(std::map::iterator iter=active.begin(); iter!=active.end(); ++iter) { + meas_t m = iter->second; + meas_obj_t o = objects[m.object_id]; + // Instruct PHY to look for neighbour cells on this frequency + phy->meas_start(o.earfcn); + for(std::map::iterator iter=o.cells.begin(); iter!=o.cells.end(); ++iter) { + // Instruct PHY to look for cells IDs on this frequency + phy->meas_start(o.earfcn, iter->second.pci); + } + } +} + + +uint8_t rrc::rrc_meas::value_to_range(quantity_t quant, float value) { + uint8_t range = 0; + switch(quant) { + case RSRP: + if (value < -140) { + range = 0; + } else if (-140 <= value && value < -44) { + range = 1 + (uint8_t) (value + 140); + } else { + range = 97; + } + break; + case RSRQ: + if (value < -19.5) { + range = 0; + } else if (-19.5 <= value && value < -3) { + range = 1 + (uint8_t) (2*(value + 19.5)); + } else { + range = 34; + } + break; + case BOTH: + printf("Error quantity both not supported in value_to_range\n"); + break; + } + return range; +} + +float rrc::rrc_meas::range_to_value(quantity_t quant, uint8_t range) { + float val = 0; + switch(quant) { + case RSRP: + val = -140+(float) range; + break; + case RSRQ: + val = -19.5+(float) range/2; + break; + case BOTH: + printf("Error quantity both not supported in range_to_value\n"); + break; + } + return val; +} + + + + + + + + + + } // namespace srsue diff --git a/srsue/src/upper/usim.cc b/srsue/src/upper/usim.cc index 9be69383e..fe70797e3 100644 --- a/srsue/src/upper/usim.cc +++ b/srsue/src/upper/usim.cc @@ -39,9 +39,11 @@ usim::usim() : initiated(false) void usim::init(usim_args_t *args, srslte::log *usim_log_) { usim_log = usim_log_; + imsi_str = args->imsi; + imei_str = args->imei; - const char *imsi_str = args->imsi.c_str(); - const char *imei_str = args->imei.c_str(); + const char *imsi_c = args->imsi.c_str(); + const char *imei_c = args->imei.c_str(); uint32_t i; if(32 == args->op.length()) { @@ -63,7 +65,7 @@ void usim::init(usim_args_t *args, srslte::log *usim_log_) for(i=0; i<15; i++) { imsi *= 10; - imsi += imsi_str[i] - '0'; + imsi += imsi_c[i] - '0'; } } else { usim_log->error("Invalid length for ISMI: %d should be %d", args->imsi.length(), 15); @@ -75,7 +77,7 @@ void usim::init(usim_args_t *args, srslte::log *usim_log_) for(i=0; i<15; i++) { imei *= 10; - imei += imei_str[i] - '0'; + imei += imei_c[i] - '0'; } } else { usim_log->error("Invalid length for IMEI: %d should be %d", args->imei.length(), 15); @@ -103,38 +105,45 @@ void usim::stop() NAS interface *******************************************************************************/ -void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) +std::string usim::get_imsi_str() { - if (!initiated) - { - usim_log->error("Getting IMSI: USIM not initiated\n"); - return; + return imsi_str; +} +std::string usim::get_imei_str() +{ + return imei_str; +} + +bool usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) +{ + if (!initiated) { + fprintf(stderr, "USIM not initiated!\n"); + return false; } - if(NULL == imsi_ || n < 15) - { + + if(NULL == imsi_ || n < 15) { usim_log->error("Invalid parameters to get_imsi_vec"); - return; + return false; } uint64_t temp = imsi; - for(int i=14;i>=0;i--) - { + for(int i=14;i>=0;i--) { imsi_[i] = temp % 10; temp /= 10; } + return true; } -void usim::get_imei_vec(uint8_t* imei_, uint32_t n) +bool usim::get_imei_vec(uint8_t* imei_, uint32_t n) { - if (!initiated) - { - usim_log->error("Getting IMEI: USIM not initiated\n"); - return; + if (!initiated) { + fprintf(stderr, "USIM not initiated!\n"); + return false; } - if(NULL == imei_ || n < 15) - { + + if(NULL == imei_ || n < 15) { usim_log->error("Invalid parameters to get_imei_vec"); - return; + return false; } uint64 temp = imei; @@ -143,14 +152,14 @@ void usim::get_imei_vec(uint8_t* imei_, uint32_t n) imei_[i] = temp % 10; temp /= 10; } + return true; } -int usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) +bool usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) { - if (!initiated) - { - usim_log->error("Getting Home PLMN Id: USIM not initiated\n"); - return -1; + if (!initiated) { + fprintf(stderr, "USIM not initiated!\n"); + return false; } int mcc_len = 3; @@ -184,7 +193,7 @@ int usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) usim_log->info("Read Home PLMN Id=%s\n", plmn_id_to_string(*home_plmn_id).c_str()); - return 0; + return true; } void usim::generate_authentication_response(uint8_t *rand, @@ -192,16 +201,18 @@ void usim::generate_authentication_response(uint8_t *rand, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res) + uint8_t *res, + uint8_t *k_asme) { if(auth_algo_xor == auth_algo) { - gen_auth_res_xor(rand, autn_enb, mcc, mnc, net_valid, res); + gen_auth_res_xor(rand, autn_enb, mcc, mnc, net_valid, res, k_asme); } else { - gen_auth_res_milenage(rand, autn_enb, mcc, mnc, net_valid, res); + gen_auth_res_milenage(rand, autn_enb, mcc, mnc, net_valid, res, k_asme); } } -void usim::generate_nas_keys(uint8_t *k_nas_enc, +void usim::generate_nas_keys(uint8_t *k_asme, + uint8_t *k_nas_enc, uint8_t *k_nas_int, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) @@ -212,13 +223,16 @@ void usim::generate_nas_keys(uint8_t *k_nas_enc, integ_algo, k_nas_enc, k_nas_int); + + } /******************************************************************************* RRC interface *******************************************************************************/ -void usim::generate_as_keys(uint32_t count_ul, +void usim::generate_as_keys(uint8_t *k_asme, + uint32_t count_ul, uint8_t *k_rrc_enc, uint8_t *k_rrc_int, uint8_t *k_up_enc, @@ -226,10 +240,75 @@ void usim::generate_as_keys(uint32_t count_ul, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { + // Generate K_enb - security_generate_k_enb( k_asme, - count_ul, - k_enb); + security_generate_k_enb( k_asme, + count_ul, + k_enb); + + memcpy(this->k_asme, k_asme, 32); + + // Generate K_rrc_enc and K_rrc_int + security_generate_k_rrc( k_enb, + cipher_algo, + integ_algo, + k_rrc_enc, + k_rrc_int); + + // Generate K_up_enc and K_up_int + security_generate_k_up( k_enb, + cipher_algo, + integ_algo, + k_up_enc, + k_up_int); + + current_ncc = 0; +} + +void usim::generate_as_keys_ho(uint32_t pci, + uint32_t earfcn, + int ncc, + uint8_t *k_rrc_enc, + uint8_t *k_rrc_int, + uint8_t *k_up_enc, + uint8_t *k_up_int, + CIPHERING_ALGORITHM_ID_ENUM cipher_algo, + INTEGRITY_ALGORITHM_ID_ENUM integ_algo) +{ + uint8_t *enb_star_key = k_enb; + + if (ncc < 0) { + ncc = current_ncc; + } + + // Generate successive NH + while(current_ncc != (uint32_t) ncc) { + uint8_t *sync = NULL; + if (current_ncc) { + sync = nh; + } else { + sync = k_enb; + } + // Generate NH + security_generate_nh(k_asme, + sync, + nh); + + current_ncc++; + if (current_ncc == 7) { + current_ncc = 0; + } + enb_star_key = nh; + } + + // Generate K_enb + security_generate_k_enb_star( enb_star_key, + pci, + earfcn, + k_enb_star); + + // K_enb becomes K_enb* + memcpy(k_enb, k_enb_star, 32); // Generate K_rrc_enc and K_rrc_int security_generate_k_rrc( k_enb, @@ -255,7 +334,8 @@ void usim::gen_auth_res_milenage( uint8_t *rand, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res) + uint8_t *res, + uint8_t *k_asme) { uint32_t i; uint8_t sqn[6]; @@ -324,7 +404,8 @@ void usim::gen_auth_res_xor(uint8_t *rand, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res) + uint8_t *res, + uint8_t *k_asme) { uint32_t i; uint8_t sqn[6]; diff --git a/srsue/test/upper/usim_test.cc b/srsue/test/upper/usim_test.cc index c8a248184..4ac468673 100644 --- a/srsue/test/upper/usim_test.cc +++ b/srsue/test/upper/usim_test.cc @@ -70,6 +70,7 @@ int main(int argc, char **argv) srslte::log_filter usim_log("USIM"); bool net_valid; uint8_t res[16]; + uint8_t k_asme[32]; usim_args_t args; args.algo = "milenage"; @@ -81,7 +82,7 @@ int main(int argc, char **argv) srsue::usim usim; usim.init(&args, &usim_log); - usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, &net_valid, res); + usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, &net_valid, res, k_asme); assert(net_valid == true); } diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 30c05069a..7c096a268 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -9,6 +9,8 @@ # rx_gain: Optional receive gain (dB). If disabled, AGC if enabled # # Optional parameters: +# dl_freq: Override DL frequency corresponding to dl_earfcn +# ul_freq: Override UL frequency corresponding to dl_earfcn # nof_rx_ant: Number of RX antennas (Default 1, supported 1 or 2) # device_name: Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF" # device_args: Arguments for the device driver. Options are "auto" or any string. @@ -48,6 +50,8 @@ rx_gain = 40 [pcap] enable = false filename = /tmp/ue.pcap +nas_enable = false +nas_filename = /tmp/nas.pcap ##################################################################### # Log configuration @@ -69,6 +73,7 @@ filename = /tmp/ue.pcap ##################################################################### [log] all_level = info +phy_lib_level = none all_hex_limit = 32 filename = /tmp/ue.log @@ -90,15 +95,36 @@ k = 00112233445566778899aabbccddeeff imsi = 001010123456789 imei = 353490069873319 + +##################################################################### +# RRC configuration +# +# stimsi_attach: If enabled, always tries first an S-TMSI attach using the +# S-TMSI value stored in .stimsi file generated in previous run +# mmec_value: If defined (non-zero), overwrites the value stored in .stimsi file +# m_tmsi_value: If defined (non-zero), overwrites the value stored in .stimsi file +# +# ue_category: Sets UE category (range 1-5). Default: 4 +# feature_group: Hex value of the featureGroupIndicators field in the +# UECapabilityInformation message. Default 0xe6041c00 +##################################################################### +[rrc] +#stmsi_attach = false +#mmec_value = 0 +#mtmsi_value = 0 +#ue_category = 4 +#feature_group = 0xe6041c00 + [gui] enable = false ##################################################################### # Expert configuration options # -# ue_category: Sets UE category (range 1-5). Default: 4 -# -# prach_gain: PRACH gain (dB). If defined, forces a gain for the tranmsission of PRACH only., +# ip_netmask: Netmask of the tun_srsue device. Default: 255.255.255.0 +# rssi_sensor_enabled: Enable or disable RF frontend RSSI sensor. Required for RSRP metrics but +# can cause UHD instability for long-duration testing. Default true. +# prach_gain: PRACH gain (dB). If defined, forces a gain for the tranmsission of PRACH only., # Default is to use tx_gain in [rf] section. # cqi_max: Upper bound on the maximum CQI to be reported. Default 15. # cqi_fixed: Fixes the reported CQI to a constant value. Default disabled. @@ -113,12 +139,8 @@ enable = false # nof_phy_threads: Selects the number of PHY threads (maximum 4, minimum 1, default 2) # equalizer_mode: Selects equalizer mode. Valid modes are: "mmse", "zf" or any # non-negative real number to indicate a regularized zf coefficient. -# Default is MMSE. -# cfo_integer_enabled: Enables integer CFO estimation and correction. This needs improvement -# and may lead to incorrect synchronization. Use with caution. -# cfo_correct_tol_hz: Tolerance (in Hz) for digial CFO compensation. Lower tolerance means that -# a new table will be generated more often. -# time_correct_period: Period for sampling time offset correction. Default is 10 (ue_sync.c), +# Default is MMSE. +# time_correct_period: Period for sampling time offset correction. Default is 10 (ue_sync.c), # good for long channels. For best performance at highest SNR reduce it to 1. # sfo_correct_disable: Disables phase correction before channel estimation to compensate for # sampling frequency offset. Default is enabled. @@ -130,13 +152,36 @@ enable = false # # pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance. # +# average_subframe_enabled: Averages in the time domain the channel estimates within 1 subframe. +# Needs accurate CFO correction. +# +# sic_pss_enabled: Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells. +# Must be disabled if cells have identical channel and timing, for instance if generated from +# the same source. +# # metrics_csv_enable: Write UE metrics to CSV file. # # metrics_csv_filename: File path to use for CSV metrics. # +# cfo_integer_enabled: Enables integer CFO estimation and correction. This needs improvement +# and may lead to incorrect synchronization. Use with caution. +# cfo_correct_tol_hz: Tolerance (in Hz) for digial CFO compensation. Lower tolerance means that +# a new table will be generated more often. +# +# cfo_pss_ema: CFO Exponential Moving Average coefficient for PSS estimation during TRACK. +# cfo_ref_ema: CFO Exponential Moving Average coefficient for RS estimation after PSS acquisition +# cfo_ref_mask: Bitmask for subframes on which to run RS estimation (set to 0 to disable, default sf=[1, 5]) +# cfo_loop_bw: CFO feedback loop bandwidth for samples from PSS or RS +# cfo_loop_pss_tol: Tolerance (in Hz) of the PSS estimation method. Below this value, PSS estimation does not feeds back the loop +# and RS estimations are used instead (when available) +# cfo_loop_ref_min: Tolerance (in Hz) of the RS estimation method. Below this value, RS estimation does not feeds back the loop +# cfo_loop_pss_timeout: After the PSS estimation is below cfo_loop_pss_tol for cfo_loop_pss_timeout times consecutively, +# RS adjustments are allowed. +# ##################################################################### [expert] -#ue_category = 4 +#ip_netmask = 255.255.255.0 +#rssi_sensor_enabled = false #prach_gain = 30 #cqi_max = 15 #cqi_fixed = 10 @@ -146,16 +191,27 @@ enable = false #attach_enable_64qam = false #nof_phy_threads = 2 #equalizer_mode = mmse -#cfo_integer_enabled = false -#cfo_correct_tol_hz = 50 #time_correct_period = 5 #sfo_correct_disable = false #sss_algorithm = full #estimator_fil_w = 0.1 +#average_subframe_enabled = false +#sic_pss_enabled = true #pregenerate_signals = false #metrics_csv_enable = false #metrics_csv_filename = /tmp/ue_metrics.csv +# CFO related values +#cfo_integer_enabled = false +#cfo_correct_tol_hz = 1.0 +#cfo_pss_ema = 0.05 +#cfo_ref_mask = 1023 +#cfo_loop_bw_pss = 0.05 +#cfo_loop_bw_ref = 0.01 +#cfo_loop_pss_tol = 400 +#cfo_loop_ref_min = 0 +#cfo_loop_pss_conv = 20 + ##################################################################### # Manual RF calibration #