diff --git a/CMakeLists.txt b/CMakeLists.txt index c8f92b065..8abc0c063 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ PROJECT (LIBLTE) LIST(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules") -INCLUDE(libLTEPackage) #setup cpack +INCLUDE(libLTEPackage) #setup cpack include(CTest) set( CTEST_MEMORYCHECK_COMMAND valgrind ) @@ -78,6 +78,9 @@ ENDIF(CMAKE_COMPILER_IS_GNUCXX) IF(CMAKE_COMPILER_IS_GNUCC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE") + # IF(${CMAKE_BUILD_TYPE} STREQUAL "Debug") + # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wno-error=implicit-function-declaration -Wno-error=unused-but-set-variable") + # ENDIF(${CMAKE_BUILD_TYPE} STREQUAL "Debug") IF(NOT WIN32) ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) ENDIF(NOT WIN32) diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake index 7a9cb5349..7a3660f18 100644 --- a/cmake/modules/FindVolk.cmake +++ b/cmake/modules/FindVolk.cmake @@ -5,7 +5,7 @@ FIND_PATH( VOLK_INCLUDE_DIRS NAMES volk.h HINTS $ENV{VOLK_DIR}/include/volk - ${CMAKE_INSTALL_PREFIX}/include/volk + ${CMAKE_INSTALL_PREFIX}/include/volk ${PC_VOLK_INCLUDE_DIR} PATHS /usr/local/include/volk /usr/include/volk @@ -15,9 +15,9 @@ FIND_LIBRARY( VOLK_LIBRARIES NAMES volk HINTS $ENV{VOLK_DIR}/lib - ${CMAKE_INSTALL_PREFIX}/lib - ${CMAKE_INSTALL_PREFIX}/lib64 - ${PC_VOLK_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + ${PC_VOLK_LIBDIR} PATHS /usr/local/lib /usr/local/lib64 /usr/lib @@ -25,35 +25,79 @@ FIND_LIBRARY( ) # Some functions are not defined in old volk versions -SET(CMAKE_REQUIRED_LIBRARIES volk m) +SET(CMAKE_REQUIRED_LIBRARIES ${VOLK_LIBRARIES} m) CHECK_FUNCTION_EXISTS_MATH(volk_32f_index_max_16u HAVE_VOLK_MAX_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_32f_x2_divide_32f HAVE_VOLK_DIVIDE_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_dot_prod_32fc HAVE_VOLK_DOTPROD_FC_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_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION) SET(VOLK_DEFINITIONS "HAVE_VOLK") +IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_SUB_FLOAT_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SUB_FLOAT_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_MULT2_CONJ_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_CONJ_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_CONVERT_FI_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_FI_FUNCTION") +ENDIF() IF(${HAVE_VOLK_MAX_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION") ENDIF() IF(${HAVE_VOLK_ACC_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; 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") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FUNCTION") ENDIF() IF(${HAVE_VOLK_CONJ_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; 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") + 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") + 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_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() - 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) diff --git a/cuhd/include/liblte/cuhd/cuhd.h b/cuhd/include/liblte/cuhd/cuhd.h index d67c2eba1..48da5883d 100644 --- a/cuhd/include/liblte/cuhd/cuhd.h +++ b/cuhd/include/liblte/cuhd/cuhd.h @@ -31,26 +31,63 @@ extern "C" { #endif #include - +#include + #include "liblte/config.h" #include "liblte/cuhd/cuhd_utils.h" -LIBLTE_API int cuhd_open(char *args, void **handler); +LIBLTE_API int cuhd_open(char *args, + void **handler); + LIBLTE_API int cuhd_close(void *h); LIBLTE_API int cuhd_start_rx_stream(void *h); -LIBLTE_API int cuhd_start_rx_stream_nsamples(void *h, int nsamples); -LIBLTE_API int cuhd_stop_rx_stream(void *h); -LIBLTE_API bool cuhd_rx_wait_lo_locked(void *h); -LIBLTE_API double cuhd_set_rx_srate(void *h, double freq); -LIBLTE_API double cuhd_set_rx_gain(void *h, double gain); -LIBLTE_API double cuhd_set_rx_freq(void *h, double freq); -LIBLTE_API int cuhd_recv(void *h, void *data, int nsamples, int blocking); -LIBLTE_API double cuhd_set_tx_srate(void *h, double freq); -LIBLTE_API double cuhd_set_tx_gain(void *h, double gain); -LIBLTE_API double cuhd_set_tx_freq(void *h, double freq); -LIBLTE_API int cuhd_send(void *h, void *data, int nsamples, int blocking); +LIBLTE_API int cuhd_start_rx_stream_nsamples(void *h, + uint32_t nsamples); + +LIBLTE_API int cuhd_stop_rx_stream(void *h); + +LIBLTE_API bool cuhd_rx_wait_lo_locked(void *h); + +LIBLTE_API double cuhd_set_rx_srate(void *h, + double freq); + +LIBLTE_API double cuhd_set_rx_gain(void *h, + double gain); + +LIBLTE_API double cuhd_set_rx_freq(void *h, + double freq); + +LIBLTE_API double cuhd_set_rx_freq_offset(void *h, + double freq, + double off); + +LIBLTE_API int cuhd_recv(void *h, + void *data, + uint32_t nsamples, + bool blocking); + +LIBLTE_API int cuhd_recv_timed(void *h, + void *data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs); + +LIBLTE_API double cuhd_set_tx_srate(void *h, + double freq); + +LIBLTE_API double cuhd_set_tx_gain(void *h, + double gain); + +LIBLTE_API double cuhd_set_tx_freq(void *h, + double freq); + +LIBLTE_API int cuhd_send(void *h, + void *data, + uint32_t nsamples, + bool blocking); #ifdef __cplusplus diff --git a/cuhd/lib/cuhd_handler.hpp b/cuhd/lib/cuhd_handler.hpp index 349117a88..8e3ecedd6 100644 --- a/cuhd/lib/cuhd_handler.hpp +++ b/cuhd/lib/cuhd_handler.hpp @@ -30,9 +30,9 @@ class cuhd_handler { public: - uhd::usrp::multi_usrp::sptr usrp; - uhd::rx_streamer::sptr rx_stream; - bool rx_stream_enable; - uhd::tx_streamer::sptr tx_stream; + uhd::usrp::multi_usrp::sptr usrp; + uhd::rx_streamer::sptr rx_stream; + bool rx_stream_enable; + uhd::tx_streamer::sptr tx_stream; }; diff --git a/cuhd/lib/cuhd_imp.cpp b/cuhd/lib/cuhd_imp.cpp index 626415f7e..ca98b9e2e 100644 --- a/cuhd/lib/cuhd_imp.cpp +++ b/cuhd/lib/cuhd_imp.cpp @@ -35,8 +35,9 @@ #include "liblte/cuhd/cuhd.h" -void my_handler(uhd::msg::type_t type, const std::string &msg){ - //handle the message... +void my_handler(uhd::msg::type_t type, const std::string & msg) +{ + //handle the message... } typedef _Complex float complex_t; @@ -45,161 +46,216 @@ typedef _Complex float complex_t; bool isLocked(void *h) { - cuhd_handler* handler = static_cast(h); - std::vector mb_sensors = handler->usrp->get_mboard_sensor_names(); - std::vector rx_sensors = handler->usrp->get_rx_sensor_names(0); - if(std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") != rx_sensors.end()) { - return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool(); - } - else if(std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") != mb_sensors.end()) { - return handler->usrp->get_mboard_sensor("ref_locked", 0).to_bool(); - } - else { - usleep(500); - return true; - } + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + std::vector < std::string > mb_sensors = + handler->usrp->get_mboard_sensor_names(); + std::vector < std::string > rx_sensors = + handler->usrp->get_rx_sensor_names(0); + if (std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") != + rx_sensors.end()) { + return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool(); + } else if (std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") != + mb_sensors.end()) { + return handler->usrp->get_mboard_sensor("ref_locked", 0).to_bool(); + } else { + usleep(500); + return true; + } } bool cuhd_rx_wait_lo_locked(void *h) { - double report = 0.0; - while(isLocked(h) && report < 3.0) - { - report += 0.1; - usleep(1000); - } - return isLocked(h); + double report = 0.0; + while (isLocked(h) && report < 3.0) { + report += 0.1; + usleep(1000); + } + return isLocked(h); } -int cuhd_start_rx_stream(void *h) { - cuhd_handler* handler = static_cast(h); - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - cmd.time_spec = handler->usrp->get_time_now(); - cmd.stream_now = true; - handler->usrp->issue_stream_cmd(cmd); - return 0; +int cuhd_start_rx_stream(void *h) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); + cmd.time_spec = handler->usrp->get_time_now(); + cmd.stream_now = true; + handler->usrp->issue_stream_cmd(cmd); + return 0; } -int cuhd_stop_rx_stream(void *h) { - cuhd_handler* handler = static_cast(h); - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); - cmd.time_spec = handler->usrp->get_time_now(); - cmd.stream_now = true; - handler->usrp->issue_stream_cmd(cmd); - return 0; +int cuhd_stop_rx_stream(void *h) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); + cmd.time_spec = handler->usrp->get_time_now(); + cmd.stream_now = true; + handler->usrp->issue_stream_cmd(cmd); + return 0; } -int cuhd_start_rx_stream_nsamples(void *h, int nsamples) { - cuhd_handler* handler = static_cast(h); - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE); - cmd.time_spec = handler->usrp->get_time_now(); - cmd.stream_now = true; - cmd.num_samps = nsamples; - handler->usrp->issue_stream_cmd(cmd); - return 0; +int cuhd_start_rx_stream_nsamples(void *h, uint32_t nsamples) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE); + cmd.time_spec = handler->usrp->get_time_now(); + cmd.stream_now = true; + cmd.num_samps = nsamples; + handler->usrp->issue_stream_cmd(cmd); + return 0; } -int cuhd_open(char *args, void **h) { - cuhd_handler* handler = new cuhd_handler(); - std::string _args=std::string(args); - handler->usrp = uhd::usrp::multi_usrp::make(_args); +int cuhd_open(char *args, void **h) +{ + cuhd_handler *handler = new cuhd_handler(); + std::string _args = std::string(args); + handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=30720000"); - // Try to set LTE clock - handler->usrp->set_master_clock_rate(30720000); + handler->usrp->set_clock_source("internal"); - handler->usrp->set_clock_source("internal"); + std::string otw, cpu; + otw = "sc16"; + cpu = "fc32"; + uhd::stream_args_t stream_args(cpu, otw); + handler->rx_stream = handler->usrp->get_rx_stream(stream_args); + handler->tx_stream = handler->usrp->get_tx_stream(stream_args); - std::string otw, cpu; - otw="sc16"; - cpu="fc32"; - uhd::stream_args_t stream_args(cpu, otw); - handler->rx_stream = handler->usrp->get_rx_stream(stream_args); - handler->tx_stream = handler->usrp->get_tx_stream(stream_args); + *h = handler; - *h = handler; - - return 0; + return 0; } -int cuhd_close(void *h) { - cuhd_stop_rx_stream(h); - /** Something else to close the USRP?? */ - return 0; +int cuhd_close(void *h) +{ + cuhd_stop_rx_stream(h); + /** Something else to close the USRP?? */ + return 0; } -double cuhd_set_rx_srate(void *h, double freq) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_rx_rate(freq); - double ret = handler->usrp->get_rx_rate(); - return ret; +double cuhd_set_rx_srate(void *h, double freq) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_rx_rate(freq); + double ret = handler->usrp->get_rx_rate(); + return ret; } -double cuhd_set_rx_gain(void *h, double gain) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_rx_gain(gain); - return handler->usrp->get_rx_gain(); +double cuhd_set_rx_gain(void *h, double gain) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_rx_gain(gain); + return handler->usrp->get_rx_gain(); } -double cuhd_set_rx_freq(void *h, double freq) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_rx_freq(freq); - return handler->usrp->get_rx_freq(); +double cuhd_set_rx_freq(void *h, double freq) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_rx_freq(freq); + return handler->usrp->get_rx_freq(); } -int cuhd_recv(void *h, void *data, int nsamples, int blocking) { - cuhd_handler* handler = static_cast(h); - uhd::rx_metadata_t md; - if (blocking) { - int n=0,p; - complex_t *data_c = (complex_t*) data; - do { - p=handler->rx_stream->recv(&data_c[n], nsamples-n, md); - if (p == -1) { - return -1; - } - n+=p; - } while(nrx_stream->recv(data, nsamples, md, 0.0); - } +double cuhd_set_rx_freq_offset(void *h, double freq, double off) { + cuhd_handler* handler = static_cast(h); + handler->usrp->set_rx_freq(uhd::tune_request_t(freq,off)); + return handler->usrp->get_rx_freq(); } -double cuhd_set_tx_gain(void *h, double gain) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_tx_gain(gain); - return handler->usrp->get_tx_gain(); +int cuhd_recv(void *h, void *data, uint32_t nsamples, bool blocking) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::rx_metadata_t md; + if (blocking) { + int n = 0, p; + complex_t *data_c = (complex_t *) data; + do { + p = handler->rx_stream->recv(&data_c[n], nsamples - n, md); + if (p == -1) { + return -1; + } + n += p; + if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) { + std::cout << "\nError code: " << md.to_pp_string() << "\n\n"; + } + } while (n < nsamples); + return nsamples; + } else { + return handler->rx_stream->recv(data, nsamples, md, 0.0); + } } -double cuhd_set_tx_srate(void *h, double freq) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_tx_rate(freq); - return handler->usrp->get_tx_rate(); +int cuhd_recv_timed(void *h, + void *data, + uint32_t nsamples, + int blocking, + time_t *secs, + double *frac_secs) { + cuhd_handler* handler = static_cast(h); + uhd::rx_metadata_t md; + *secs = -1; + *frac_secs = -1; + int p; + if (blocking) { + int n=0; + complex_t *data_c = (complex_t*) data; + do { + p=handler->rx_stream->recv(&data_c[n], nsamples-n, md); + if (p == -1) { + return -1; + } + if(*secs < 0){ + *secs = md.time_spec.get_full_secs(); + *frac_secs = md.time_spec.get_frac_secs(); + } + n+=p; + } while(nrx_stream->recv(data, nsamples, md, 0.0); + *secs = md.time_spec.get_full_secs(); + *frac_secs = md.time_spec.get_frac_secs(); + return p; + } } -double cuhd_set_tx_freq(void *h, double freq) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_tx_freq(freq); - return handler->usrp->get_tx_freq(); + +double cuhd_set_tx_gain(void *h, double gain) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_tx_gain(gain); + return handler->usrp->get_tx_gain(); } -int cuhd_send(void *h, void *data, int nsamples, int blocking) { - cuhd_handler* handler = static_cast(h); - uhd::tx_metadata_t md; - if (blocking) { - int n=0,p; - complex_t *data_c = (complex_t*) data; - do { - p=handler->tx_stream->send(&data_c[n], nsamples-n, md); - if (p == -1) { - return -1; - } - n+=p; - } while(ntx_stream->send(data, nsamples, md, 0.0); - } +double cuhd_set_tx_srate(void *h, double freq) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_tx_rate(freq); + return handler->usrp->get_tx_rate(); +} + +double cuhd_set_tx_freq(void *h, double freq) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_tx_freq(freq); + return handler->usrp->get_tx_freq(); +} + +int cuhd_send(void *h, void *data, uint32_t nsamples, bool blocking) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::tx_metadata_t md; + if (blocking) { + int n = 0, p; + complex_t *data_c = (complex_t *) data; + do { + p = handler->tx_stream->send(&data_c[n], nsamples - n, md); + if (p == -1) { + return -1; + } + n += p; + } while (n < nsamples); + return nsamples; + } else { + return handler->tx_stream->send(data, nsamples, md, 0.0); + } } diff --git a/lte/phy/CMakeLists.txt b/lte/phy/CMakeLists.txt index 77373e308..886b9d311 100644 --- a/lte/phy/CMakeLists.txt +++ b/lte/phy/CMakeLists.txt @@ -34,10 +34,10 @@ INSTALL(DIRECTORY include/ SET(HEADERS_ALL "") FILE(GLOB headers *) FOREACH (_header ${headers}) - IF(IS_DIRECTORY ${_header}) - FILE(GLOB_RECURSE tmp "${_header}/*.h") - LIST(APPEND HEADERS_ALL ${tmp}) - ENDIF(IS_DIRECTORY ${_header}) + IF(IS_DIRECTORY ${_header}) + FILE(GLOB_RECURSE tmp "${_header}/*.h") + LIST(APPEND HEADERS_ALL ${tmp}) + ENDIF(IS_DIRECTORY ${_header}) ENDFOREACH() ADD_CUSTOM_TARGET (add_lte_headers SOURCES ${HEADERS_ALL}) diff --git a/lte/phy/examples/CMakeLists.txt b/lte/phy/examples/CMakeLists.txt index 78a02353a..b14924cc7 100644 --- a/lte/phy/examples/CMakeLists.txt +++ b/lte/phy/examples/CMakeLists.txt @@ -51,26 +51,26 @@ LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND) # These two can be compiled without UHD or graphics support ################################################################# -add_executable(pbch_ue pbch_ue.c) -target_link_libraries(pbch_ue lte_phy) +add_executable(pdsch_ue pdsch_ue.c iodev.c) +target_link_libraries(pdsch_ue lte_phy) -add_executable(pbch_enodeb pbch_enodeb.c) -target_link_libraries(pbch_enodeb lte_phy) +add_executable(pdsch_enodeb pdsch_enodeb.c) +target_link_libraries(pdsch_enodeb lte_phy) IF(${CUHD_FIND} EQUAL -1) - SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") - SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") + SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") + SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") ELSE(${CUHD_FIND} EQUAL -1) - target_link_libraries(pbch_ue cuhd) - target_link_libraries(pbch_enodeb cuhd) + target_link_libraries(pdsch_ue cuhd) + target_link_libraries(pdsch_enodeb cuhd) ENDIF(${CUHD_FIND} EQUAL -1) IF(${GRAPHICS_FIND} EQUAL -1) - SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") - SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") + SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") + SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") ELSE(${GRAPHICS_FIND} EQUAL -1) - target_link_libraries(pbch_ue graphics) - target_link_libraries(pbch_enodeb graphics) + target_link_libraries(pdsch_ue graphics) + target_link_libraries(pdsch_enodeb graphics) ENDIF(${GRAPHICS_FIND} EQUAL -1) @@ -81,17 +81,17 @@ ENDIF(${GRAPHICS_FIND} EQUAL -1) IF(${CUHD_FIND} GREATER -1) - add_executable(scan_rssi scan_rssi.c) - target_link_libraries(scan_rssi lte_phy cuhd ) + add_executable(scan_rssi scan_rssi.c) + target_link_libraries(scan_rssi lte_phy cuhd ) - add_executable(scan_pss scan_pss.c) - target_link_libraries(scan_pss lte_phy cuhd ) + add_executable(scan_pss scan_pss.c) + target_link_libraries(scan_pss lte_phy cuhd ) - add_executable(scan_mib scan_mib.c) - target_link_libraries(scan_mib lte_phy cuhd ) + add_executable(scan_mib scan_mib.c) + target_link_libraries(scan_mib lte_phy cuhd ) - MESSAGE(STATUS " UHD examples will be installed.") + MESSAGE(STATUS " UHD examples will be installed.") ELSE(${CUHD_FIND} GREATER -1) - MESSAGE(STATUS " UHD examples NOT INSTALLED: CUHD library not compiled.") + MESSAGE(STATUS " UHD examples NOT INSTALLED: CUHD library not compiled.") ENDIF(${CUHD_FIND} GREATER -1) diff --git a/lte/phy/examples/iodev.c b/lte/phy/examples/iodev.c new file mode 100644 index 000000000..056c64f16 --- /dev/null +++ b/lte/phy/examples/iodev.c @@ -0,0 +1,167 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE 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 Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 "iodev.h" + +#include "liblte/phy/io/filesource.h" +#include "liblte/phy/phch/ue_sync.h" +#include "liblte/phy/utils/debug.h" +#include "liblte/phy/utils/vector.h" + +#ifndef DISABLE_UHD +#include "liblte/cuhd/cuhd.h" +#endif + + +int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) { + DEBUG(" ---- Receive %d samples ---- \n", nsamples); + return cuhd_recv(h, data, nsamples, 1); +} + +/* Setup USRP or input file */ +int iodev_init(iodev_t *q, iodev_cfg_t *config) { + + if (config->input_file_name) { + if (filesource_init(&q->fsrc, config->input_file_name, COMPLEX_FLOAT_BIN)) { + return LIBLTE_ERROR; + } + q->input_buffer_file = vec_malloc(SF_LEN_MAX * sizeof(cf_t)); + if (!q->input_buffer_file) { + perror("malloc"); + return LIBLTE_ERROR; + } + + q->mode = FILESOURCE; + q->sf_len = 1920; + + } else { +#ifndef DISABLE_UHD + printf("Opening UHD device...\n"); + if (cuhd_open(config->uhd_args, &q->uhd)) { + fprintf(stderr, "Error opening uhd\n"); + return LIBLTE_ERROR; + } + + /* set uhd_freq */ + cuhd_set_rx_gain(q->uhd, config->uhd_gain); + cuhd_set_rx_freq(q->uhd, (double) config->uhd_freq); + + cuhd_rx_wait_lo_locked(q->uhd); + DEBUG("Set uhd_freq to %.3f MHz\n", (double ) config->uhd_freq); + + DEBUG("Starting receiver...\n", 0); + cuhd_start_rx_stream(q->uhd); + + if (config->find_threshold > 0.0) { + ue_sync_set_threshold(&q->sframe, config->find_threshold); + } + + ue_sync_init(&q->sframe, cuhd_set_rx_srate, cuhd_recv_wrapper, q->uhd); + + // Here, the subframe length and input buffer is managed by ue_sync + q->mode = UHD; + +#else + printf("Error UHD not available. Select an input file\n"); + return LIBLTE_ERROR; +#endif + } + + memcpy(&q->config, config, sizeof(iodev_cfg_t)); + + return LIBLTE_SUCCESS; +} + + + +void iodev_free(iodev_t *q) { + + if (q->mode == FILESOURCE) { + filesource_free(&q->fsrc); + } else { +#ifndef DISABLE_UHD + cuhd_close(q->uhd); +#endif + } +} +/* Receive samples from the USRP or read from file */ +int iodev_receive(iodev_t *q, cf_t **buffer) { + int n; + if (q->mode == FILESOURCE) { + DEBUG(" ----- READING %d SAMPLES ---- \n", q->sf_len); + n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len); + *buffer = q->input_buffer_file; + if (n == -1) { + fprintf(stderr, "Error reading file\n"); + /* wrap file if arrive to end */ + } else if (n < q->sf_len) { + DEBUG("Read %d from file. Seeking to 0\n",n); + filesource_seek(&q->fsrc, 0); + n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len); + if (n == -1) { + fprintf(stderr, "Error reading file\n"); + /* wrap file if arrive to end */ + } else { + n = 1; + } + } else { + n = 1; + } + } else { + /* Use ue_sync_work which returns a synchronized buffer of subframe samples */ +#ifndef DISABLE_UHD + n = ue_sync_get_buffer(&q->sframe, buffer); + if (n < 0) { + fprintf(stderr, "Error calling ue_sync_work()\n"); + } +#endif + } + return n; +} + +void* iodev_get_cuhd(iodev_t *q) { + if (q->mode == UHD) { + return q->uhd; + } else { + return NULL; + } +} + +bool iodev_isfile(iodev_t *q) { + return q->mode == FILESOURCE; +} + +bool iodev_isUSRP(iodev_t *q) { + return q->mode == UHD; +} + + diff --git a/lte/phy/examples/iodev.h b/lte/phy/examples/iodev.h new file mode 100644 index 000000000..87264eda6 --- /dev/null +++ b/lte/phy/examples/iodev.h @@ -0,0 +1,90 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE 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 Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 IODEF_H +#define IODEF_H + +#include "liblte/config.h" + +#include "liblte/phy/phch/ue_sync.h" +#include "liblte/phy/io/filesource.h" + +#ifndef DISABLE_UHD +#include "liblte/cuhd/cuhd.h" +#endif + +/********* + * + * This component is a wrapper to the cuhd or filesource modules. It uses + * sync_frame_t to read aligned subframes from the USRP or filesource to read + * subframes from a file. + * + * When created, it starts receiving/reading at 1.92 MHz. The sampling frequency + * can then be changed using iodev_set_srate() + */ + + +typedef enum LIBLTE_API {FILESOURCE, UHD} iodev_mode_t; + +typedef _Complex float cf_t; + +typedef struct LIBLTE_API { + char *input_file_name; + float uhd_freq; + float uhd_gain; + char *uhd_args; + float find_threshold; +} iodev_cfg_t; + +typedef struct LIBLTE_API { + #ifndef DISABLE_UHD + void *uhd; + ue_sync_t sframe; + #endif + uint32_t sf_len; + cf_t *input_buffer_file; // for UHD mode, the input buffer is managed by sync_frame_t + filesource_t fsrc; + iodev_cfg_t config; + iodev_mode_t mode; +} iodev_t; + + +LIBLTE_API int iodev_init(iodev_t *q, + iodev_cfg_t *config); + +LIBLTE_API void iodev_free(iodev_t *q); + +LIBLTE_API int iodev_receive(iodev_t *q, + cf_t **buffer); + +LIBLTE_API void* iodev_get_cuhd(iodev_t *q); + +LIBLTE_API bool iodev_isfile(iodev_t *q); + +LIBLTE_API bool iodev_isUSRP(iodev_t *q); + +#endif \ No newline at end of file diff --git a/lte/phy/examples/pbch_enodeb.c b/lte/phy/examples/pbch_enodeb.c deleted file mode 100644 index 5a0f9c583..000000000 --- a/lte/phy/examples/pbch_enodeb.c +++ /dev/null @@ -1,283 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2014 The libLTE Developers. See the - * COPYRIGHT file at the top-level directory of this distribution. - * - * \section LICENSE - * - * This file is part of the libLTE library. - * - * libLTE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * libLTE 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 Lesser General Public License for more details. - * - * A copy of the GNU Lesser 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 "liblte/phy/phy.h" - -#ifndef DISABLE_UHD - #include "liblte/cuhd/cuhd.h" - void *uhd; -#endif - -char *output_file_name = NULL; -int nof_frames=-1; -int cell_id = 1; -int nof_prb = 6; -char *uhd_args = ""; - -float uhd_amp=0.25, uhd_gain=10.0, uhd_freq=2400000000; - -filesink_t fsink; -lte_fft_t ifft; -pbch_t pbch; - -cf_t *slot_buffer = NULL, *output_buffer = NULL; -int slot_n_re, slot_n_samples; - -#define UHD_SAMP_FREQ 1920000 - -void usage(char *prog) { - printf("Usage: %s [agmfoncvp]\n", prog); -#ifndef DISABLE_UHD - printf("\t-a UHD args [Default %s]\n", uhd_args); - printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain); - printf("\t-m UHD signal amplitude [Default %.2f]\n", uhd_amp); - printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq/1000000); -#else - printf("\t UHD is disabled. CUHD library not available\n"); -#endif - printf("\t-o output_file [Default USRP]\n"); - printf("\t-n number of frames [Default %d]\n", nof_frames); - printf("\t-c cell id [Default %d]\n", cell_id); - printf("\t-p nof_prb [Default %d]\n", nof_prb); - printf("\t-v [set verbose to debug, default none]\n"); -} - -void parse_args(int argc, char **argv) { - int opt; - while ((opt = getopt(argc, argv, "agfmoncpv")) != -1) { - switch(opt) { - case 'a': - uhd_args = argv[optind]; - break; - case 'g': - uhd_gain = atof(argv[optind]); - break; - case 'm': - uhd_amp = atof(argv[optind]); - break; - case 'f': - uhd_freq = atof(argv[optind]); - break; - case 'o': - output_file_name = argv[optind]; - break; - case 'n': - nof_frames = atoi(argv[optind]); - break; - case 'p': - nof_prb = atoi(argv[optind]); - break; - case 'c': - cell_id = atoi(argv[optind]); - break; - case 'v': - verbose++; - break; - default: - usage(argv[0]); - exit(-1); - } - } -#ifdef DISABLE_UHD - if (!output_file_name) { - usage(argv[0]); - exit(-1); - } -#endif -} - -void base_init() { - /* init memory */ - slot_buffer = malloc(sizeof(cf_t) * slot_n_re); - if (!slot_buffer) { - perror("malloc"); - exit(-1); - } - output_buffer = malloc(sizeof(cf_t) * slot_n_samples); - if (!output_buffer) { - perror("malloc"); - exit(-1); - } - /* open file or USRP */ - if (output_file_name) { - if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) { - fprintf(stderr, "Error opening file %s\n", output_file_name); - exit(-1); - } - } else { -#ifndef DISABLE_UHD - printf("Opening UHD device...\n"); - if (cuhd_open(uhd_args,&uhd)) { - fprintf(stderr, "Error opening uhd\n"); - exit(-1); - } -#else - printf("Error UHD not available. Select an output file\n"); - exit(-1); -#endif - } - - /* create ifft object */ - if (lte_ifft_init(&ifft, CPNORM, nof_prb)) { - fprintf(stderr, "Error creating iFFT object\n"); - exit(-1); - } - if (pbch_init(&pbch, 6, cell_id, CPNORM)) { - fprintf(stderr, "Error creating PBCH object\n"); - exit(-1); - } -} - -void base_free() { - - pbch_free(&pbch); - - lte_ifft_free(&ifft); - - if (slot_buffer) { - free(slot_buffer); - } - if (output_buffer) { - free(output_buffer); - } - if (output_file_name) { - filesink_free(&fsink); - } else { -#ifndef DISABLE_UHD - cuhd_close(&uhd); -#endif - } -} - -int main(int argc, char **argv) { - int nf, ns, N_id_2; - cf_t pss_signal[PSS_LEN]; - float sss_signal0[SSS_LEN]; // for subframe 0 - float sss_signal5[SSS_LEN]; // for subframe 5 - pbch_mib_t mib; - refsignal_t refs[NSLOTS_X_FRAME]; - int i; - cf_t *slot1_symbols[MAX_PORTS_CTRL]; - - -#ifdef DISABLE_UHD - if (argc < 3) { - usage(argv[0]); - exit(-1); - } -#endif - - parse_args(argc,argv); - - N_id_2 = cell_id%3; - slot_n_re = CPNORM_NSYMB * nof_prb * RE_X_RB; - slot_n_samples = SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb)); - - /* this *must* be called after setting slot_len_* */ - base_init(); - - /* Generate PSS/SSS signals */ - pss_generate(pss_signal, N_id_2); - sss_generate(sss_signal0, sss_signal5, cell_id); - - /* Generate CRS signals */ - for (i=0;i -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "liblte/phy/phy.h" - -#ifndef DISABLE_UHD - #include "liblte/cuhd/cuhd.h" - void *uhd; -#endif - -#ifndef DISABLE_GRAPHICS - #include "liblte/graphics/plot.h" - plot_real_t poutfft; - plot_complex_t pce; - plot_scatter_t pscatrecv, pscatequal; -#endif - -#define MHZ 1000000 -#define SAMP_FREQ 1920000 -#define FLEN 9600 -#define FLEN_PERIOD 0.005 - -#define NOF_PORTS 2 - -float find_threshold = 20.0, track_threshold = 10.0; -int max_track_lost = 20, nof_frames = -1; -int track_len=300; -char *input_file_name = NULL; -int disable_plots = 0; - -int go_exit=0; - -float uhd_freq = 2600000000.0, uhd_gain = 20.0; -char *uhd_args = ""; - -filesource_t fsrc; -cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL]; -pbch_t pbch; -lte_fft_t fft; -chest_t chest; -sync_t sfind, strack; -cfo_t cfocorr; - - -enum sync_state {FIND, TRACK}; - -void usage(char *prog) { - printf("Usage: %s [iagfndvp]\n", prog); - printf("\t-i input_file [Default use USRP]\n"); -#ifndef DISABLE_UHD - printf("\t-a UHD args [Default %s]\n", uhd_args); - printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain); - printf("\t-f UHD RX frequency [Default %.1f MHz]\n", uhd_freq/1000000); -#else - printf("\t UHD is disabled. CUHD library not available\n"); -#endif - printf("\t-n nof_frames [Default %d]\n", nof_frames); - printf("\t-p PSS threshold [Default %f]\n", find_threshold); -#ifndef DISABLE_GRAPHICS - printf("\t-d disable plots [Default enabled]\n"); -#else - printf("\t plots are disabled. Graphics library not available\n"); -#endif - printf("\t-v [set verbose to debug, default none]\n"); -} - -void parse_args(int argc, char **argv) { - int opt; - while ((opt = getopt(argc, argv, "iagfndvp")) != -1) { - switch(opt) { - case 'i': - input_file_name = argv[optind]; - break; - case 'a': - uhd_args = argv[optind]; - break; - case 'g': - uhd_gain = atof(argv[optind]); - break; - case 'f': - uhd_freq = atof(argv[optind]); - break; - case 'p': - find_threshold = atof(argv[optind]); - break; - case 'n': - nof_frames = atoi(argv[optind]); - break; - case 'd': - disable_plots = 1; - break; - case 'v': - verbose++; - break; - default: - usage(argv[0]); - exit(-1); - } - } -} - -#ifndef DISABLE_GRAPHICS - -void init_plots() { - plot_init(); - plot_real_init(&poutfft); - plot_real_setTitle(&poutfft, "Output FFT - Magnitude"); - plot_real_setLabels(&poutfft, "Index", "dB"); - plot_real_setYAxisScale(&poutfft, -60, 0); - plot_real_setXAxisScale(&poutfft, 1, 504); - - plot_complex_init(&pce); - plot_complex_setTitle(&pce, "Channel Estimates"); - plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01); - plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01); - plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01); - plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI); - - plot_scatter_init(&pscatrecv); - plot_scatter_setTitle(&pscatrecv, "Received Symbols"); - plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01); - plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01); - - plot_scatter_init(&pscatequal); - plot_scatter_setTitle(&pscatequal, "Equalized Symbols"); - plot_scatter_setXAxisScale(&pscatequal, -1, 1); - plot_scatter_setYAxisScale(&pscatequal, -1, 1); -} - -#endif - -int base_init(int frame_length) { - int i; - -#ifndef DISABLE_GRAPHICS - if (!disable_plots) { - init_plots(); - } -#else - printf("-- PLOTS are disabled. Graphics library not available --\n\n"); -#endif - - if (input_file_name) { - if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { - return -1; - } - } else { - /* open UHD device */ - #ifndef DISABLE_UHD - printf("Opening UHD device...\n"); - if (cuhd_open(uhd_args,&uhd)) { - fprintf(stderr, "Error opening uhd\n"); - return -1; - } - #else - printf("Error UHD not available. Select an input file\n"); - return -1; - #endif - } - - input_buffer = (cf_t*) malloc(frame_length * sizeof(cf_t)); - if (!input_buffer) { - perror("malloc"); - return -1; - } - - fft_buffer = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t)); - if (!fft_buffer) { - perror("malloc"); - return -1; - } - - for (i=0;i max_track_lost) { - INFO("%d frames lost. Going back to FIND", frame_cnt - last_found); - printf("\r\n"); - fflush(stdout); - printf("\r\n"); - state = FIND; - } - - // Correct CFO - INFO("Correcting CFO=%.4f\n", cfo); - - cfo_correct(&cfocorr, input_buffer, -cfo/128); - - if (nslot == 0 && find_idx + 960 < FLEN) { - INFO("Finding MIB at idx %d\n", find_idx); - if (mib_decoder_run(&input_buffer[find_idx], &mib)) { - INFO("MIB detected attempt=%d\n", frame_cnt); - if (verbose == VERBOSE_NONE) { - if (!nof_found_mib) { - printf("\r\n"); - fflush(stdout); - printf("\r\n"); - printf(" - Phy. CellId:\t%d\n", cell_id); - pbch_mib_fprint(stdout, &mib); - } - } - nof_found_mib++; - } else { - INFO("MIB not found attempt %d\n",frame_cnt); - } - if (frame_cnt) { - printf("SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, ErrorRate: %.1e\r", mib.sfn, - cfo*15, timeoffset/5, find_idx, frame_cnt-2*(nof_found_mib-1), frame_cnt, - (float) (frame_cnt-2*(nof_found_mib-1))/frame_cnt); - fflush(stdout); - } - } - if (input_file_name) { - usleep(5000); - } - nslot = (nslot+10)%20; - break; - } - frame_cnt++; - } - - base_free(); - - printf("\nBye\n"); - exit(0); -} - diff --git a/lte/phy/examples/pdsch_enodeb.c b/lte/phy/examples/pdsch_enodeb.c new file mode 100644 index 000000000..7aeb435f2 --- /dev/null +++ b/lte/phy/examples/pdsch_enodeb.c @@ -0,0 +1,386 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE 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 Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 "liblte/phy/phy.h" + +#ifndef DISABLE_UHD +#include "liblte/cuhd/cuhd.h" +void *uhd; +#endif + +char *output_file_name = NULL; + +lte_cell_t cell = { + 6, // nof_prb + 1, // nof_ports + 1, // cell_id + CPNORM // cyclic prefix +}; + +uint32_t cfi=1; +uint32_t mcs_idx = 12; +int nof_frames = -1; + +char *uhd_args = ""; +float uhd_amp = 0.25, uhd_gain = 10.0, uhd_freq = 2400000000; + +filesink_t fsink; +lte_fft_t ifft; +pbch_t pbch; +pcfich_t pcfich; +pdcch_t pdcch; +pdsch_t pdsch; +pdsch_harq_t harq_process; +regs_t regs; + +cf_t *sf_buffer = NULL, *output_buffer = NULL; +int sf_n_re, sf_n_samples; + +void usage(char *prog) { + printf("Usage: %s [agmfoncvp]\n", prog); +#ifndef DISABLE_UHD + printf("\t-a UHD args [Default %s]\n", uhd_args); + printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain); + printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq / 1000000); +#else + printf("\t UHD is disabled. CUHD library not available\n"); +#endif + printf("\t-o output_file [Default USRP]\n"); + printf("\t-m MCS index [Default %d]\n", mcs_idx); + printf("\t-n number of frames [Default %d]\n", nof_frames); + printf("\t-c cell id [Default %d]\n", cell.id); + printf("\t-p nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "agfmoncpv")) != -1) { + switch (opt) { + case 'a': + uhd_args = argv[optind]; + break; + case 'g': + uhd_gain = atof(argv[optind]); + break; + case 'f': + uhd_freq = atof(argv[optind]); + break; + case 'o': + output_file_name = argv[optind]; + break; + case 'm': + mcs_idx = atoi(argv[optind]); + break; + case 'n': + nof_frames = atoi(argv[optind]); + break; + case 'p': + cell.nof_prb = atoi(argv[optind]); + break; + case 'c': + cell.id = atoi(argv[optind]); + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +#ifdef DISABLE_UHD + if (!output_file_name) { + usage(argv[0]); + exit(-1); + } +#endif +} + +void base_init() { + + /* init memory */ + sf_buffer = malloc(sizeof(cf_t) * sf_n_re); + if (!sf_buffer) { + perror("malloc"); + exit(-1); + } + output_buffer = malloc(sizeof(cf_t) * sf_n_samples); + if (!output_buffer) { + perror("malloc"); + exit(-1); + } + /* open file or USRP */ + if (output_file_name) { + if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) { + fprintf(stderr, "Error opening file %s\n", output_file_name); + exit(-1); + } + } else { +#ifndef DISABLE_UHD + printf("Opening UHD device...\n"); + if (cuhd_open(uhd_args, &uhd)) { + fprintf(stderr, "Error opening uhd\n"); + exit(-1); + } +#else + printf("Error UHD not available. Select an output file\n"); + exit(-1); +#endif + } + + /* create ifft object */ + if (lte_ifft_init(&ifft, CPNORM, cell.nof_prb)) { + fprintf(stderr, "Error creating iFFT object\n"); + exit(-1); + } + if (pbch_init(&pbch, cell)) { + fprintf(stderr, "Error creating PBCH object\n"); + exit(-1); + } + + if (regs_init(®s, R_1, PHICH_NORM, cell)) { + fprintf(stderr, "Error initiating regs\n"); + exit(-1); + } + + if (pcfich_init(&pcfich, ®s, cell)) { + fprintf(stderr, "Error creating PBCH object\n"); + exit(-1); + } + + if (regs_set_cfi(®s, cfi)) { + fprintf(stderr, "Error setting CFI\n"); + exit(-1); + } + + if (pdcch_init(&pdcch, ®s, cell)) { + fprintf(stderr, "Error creating PDCCH object\n"); + exit(-1); + } + + if (pdsch_init(&pdsch, cell)) { + fprintf(stderr, "Error creating PDSCH object\n"); + exit(-1); + } + + pdsch_set_rnti(&pdsch, 1234); + + if (pdsch_harq_init(&harq_process, &pdsch)) { + fprintf(stderr, "Error initiating HARQ process\n"); + exit(-1); + } +} + +void base_free() { + + pdsch_harq_free(&harq_process); + pdsch_free(&pdsch); + pdcch_free(&pdcch); + regs_free(®s); + pbch_free(&pbch); + + lte_ifft_free(&ifft); + + if (sf_buffer) { + free(sf_buffer); + } + if (output_buffer) { + free(output_buffer); + } + if (output_file_name) { + filesink_free(&fsink); + } else { +#ifndef DISABLE_UHD + cuhd_close(&uhd); +#endif + } +} + +int main(int argc, char **argv) { + int nf, sf_idx, N_id_2; + cf_t pss_signal[PSS_LEN]; + float sss_signal0[SSS_LEN]; // for subframe 0 + float sss_signal5[SSS_LEN]; // for subframe 5 + pbch_mib_t mib; + ra_pdsch_t ra_dl; + ra_prb_t prb_alloc; + refsignal_t refs[NSLOTS_X_FRAME]; + int i, n; + char *data; + cf_t *sf_symbols[MAX_PORTS]; + dci_msg_t dci_msg; + dci_location_t locations[NSUBFRAMES_X_FRAME][10]; + +#ifdef DISABLE_UHD + if (argc < 3) { + usage(argv[0]); + exit(-1); + } +#endif + + parse_args(argc, argv); + + N_id_2 = cell.id % 3; + sf_n_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB; + sf_n_samples = 2 * SLOT_LEN_CPNORM(lte_symbol_sz(cell.nof_prb)); + + /* this *must* be called after setting slot_len_* */ + base_init(); + + /* Generate PSS/SSS signals */ + pss_generate(pss_signal, N_id_2); + sss_generate(sss_signal0, sss_signal5, cell.id); + + /* Generate CRS signals */ + for (i = 0; i < NSLOTS_X_FRAME; i++) { + if (refsignal_init_LTEDL(&refs[i], 0, i, cell)) { + fprintf(stderr, "Error initiating CRS slot=%d\n", i); + return -1; + } + } + + mib.nof_ports = cell.nof_ports; + mib.nof_prb = cell.nof_prb; + mib.phich_length = PHICH_NORM; + mib.phich_resources = R_1; + mib.sfn = 0; + + for (i = 0; i < MAX_PORTS; i++) { // now there's only 1 port + sf_symbols[i] = sf_buffer; + } + +#ifndef DISABLE_UHD + if (!output_file_name) { + printf("Set TX rate: %.2f MHz\n", + cuhd_set_tx_srate(uhd, lte_sampling_freq_hz(cell.nof_prb)) / 1000000); + printf("Set TX gain: %.1f dB\n", cuhd_set_tx_gain(uhd, uhd_gain)); + printf("Set TX freq: %.2f MHz\n", + cuhd_set_tx_freq(uhd, uhd_freq) / 1000000); + } +#endif + + bzero(&ra_dl, sizeof(ra_pdsch_t)); + ra_dl.harq_process = 0; + ra_dl.mcs_idx = mcs_idx; + ra_dl.ndi = 0; + ra_dl.rv_idx = 0; + ra_dl.alloc_type = alloc_type0; + ra_dl.type0_alloc.rbg_bitmask = 0xffffffff; + + dci_msg_pack_pdsch(&ra_dl, &dci_msg, Format1, cell.nof_prb, false); + + ra_prb_get_dl(&prb_alloc, &ra_dl, cell.nof_prb); + ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, 1, cell.nof_prb<10?(cfi+1):cfi, CPNORM); + ra_mcs_from_idx_dl(mcs_idx, cell.nof_prb, &ra_dl.mcs); + + ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb); + + /* Initiate valid DCI locations */ + for (i=0;i +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "liblte/phy/phy.h" +#include "iodev.h" + +#ifndef DISABLE_GRAPHICS +void init_plots(); +void do_plots(ue_dl_t *q, uint32_t sf_idx); +#endif + +int go_exit = 0; + +/* Local function definitions */ +void init_plots(); + +/********************************************************************** + * Program arguments processing + ***********************************************************************/ +typedef struct { + uint32_t cell_id_file; + uint32_t nof_prb_file; + uint16_t rnti; + int nof_subframes; + bool disable_plots; + iodev_cfg_t io_config; +}prog_args_t; + +void args_default(prog_args_t *args) { + args->cell_id_file = 1; + args->nof_prb_file = 6; + args->rnti = SIRNTI; + args->nof_subframes = -1; + args->disable_plots = false; + args->io_config.find_threshold = -1.0; + args->io_config.input_file_name = NULL; + args->io_config.uhd_args = ""; + args->io_config.uhd_freq = -1.0; + args->io_config.uhd_gain = 20.0; +} + +void usage(prog_args_t *args, char *prog) { + printf("Usage: %s [cargfndvtb] [-i input_file | -f rx_frequency (in Hz)]\n", prog); + printf("\t-c cell_id if reading from file [Default %d]\n", args->cell_id_file); + printf("\t-p nof_prb if reading from file [Default %d]\n", args->nof_prb_file); + printf("\t-r RNTI to look for [Default 0x%x]\n", args->rnti); +#ifndef DISABLE_UHD + printf("\t-a UHD args [Default %s]\n", args->io_config.uhd_args); + printf("\t-g UHD RX gain [Default %.2f dB]\n", args->io_config.uhd_gain); +#else + printf("\t UHD is disabled. CUHD library not available\n"); +#endif + printf("\t-b Decode PBCH only [Default All channels]\n"); + printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes); + printf("\t-t PSS threshold [Default %f]\n", args->io_config.find_threshold); +#ifndef DISABLE_GRAPHICS + printf("\t-d disable plots [Default enabled]\n"); +#else + printf("\t plots are disabled. Graphics library not available\n"); +#endif + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(prog_args_t *args, int argc, char **argv) { + int opt; + args_default(args); + while ((opt = getopt(argc, argv, "icagfndvtbp")) != -1) { + switch (opt) { + case 'i': + args->io_config.input_file_name = argv[optind]; + break; + case 'c': + args->cell_id_file = atoi(argv[optind]); + break; + case 'p': + args->nof_prb_file = atoi(argv[optind]); + break; + case 'a': + args->io_config.uhd_args = argv[optind]; + break; + case 'g': + args->io_config.uhd_gain = atof(argv[optind]); + break; + case 'f': + args->io_config.uhd_freq = atof(argv[optind]); + break; + case 't': + args->io_config.find_threshold = atof(argv[optind]); + break; + case 'n': + args->nof_subframes = atoi(argv[optind]); + break; + case 'd': + args->disable_plots = true; + break; + case 'v': + verbose++; + break; + default: + usage(args, argv[0]); + exit(-1); + } + } + if (args->io_config.uhd_freq < 0 && args->io_config.input_file_name == NULL) { + usage(args, argv[0]); + } +} +/**********************************************************************/ + +void sigintHandler(int x) { + go_exit = 1; +} + +/* TODO: Do something with the output data */ +char data[10000]; + +int main(int argc, char **argv) { + int ret; + cf_t *sf_buffer; + iodev_t iodev; + prog_args_t prog_args; + lte_cell_t cell; + ue_dl_t ue_dl; + bool ue_dl_initiated = false; + int64_t sf_cnt; + uint32_t sf_idx; + pbch_mib_t mib; + bool printed_sib = false; + uint32_t rlen; + + parse_args(&prog_args, argc, argv); + + if (iodev_init(&iodev, &prog_args.io_config)) { + fprintf(stderr, "Error initiating input device\n"); + exit(-1); + } + + if (!prog_args.disable_plots) { + init_plots(); + } + + /* Setup SIGINT handler */ + printf("\n --- Press Ctrl+C to exit --- \n"); + signal(SIGINT, sigintHandler); + + /* Initialize frame and subframe counters */ + sf_cnt = 0; + sf_idx = 0; + + /* Main loop */ + while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { + + ret = iodev_receive(&iodev, &sf_buffer); + if (ret < 0) { + fprintf(stderr, "Error reading from input device (%d)\n", ret); + break; + } + + /* iodev_receive returns 1 if successfully read 1 aligned subframe */ + if (ret == 1) { + if (!ue_dl_initiated) { + if (iodev_isUSRP(&iodev)) { + cell = ue_sync_get_cell(&iodev.sframe); + mib = ue_sync_get_mib(&iodev.sframe); + } else { + cell.id = prog_args.cell_id_file; + cell.cp = CPNORM; + cell.nof_ports = 1; // TODO: Use prog_args + cell.nof_prb = prog_args.nof_prb_file; + mib.phich_resources = R_1; + mib.phich_length = PHICH_NORM; + } + if (ue_dl_init(&ue_dl, cell, mib.phich_resources, mib.phich_length, 1234)) { + fprintf(stderr, "Error initiating UE downlink processing module\n"); + exit(-1); + } + pdsch_set_rnti(&ue_dl.pdsch, prog_args.rnti); + ue_dl_initiated = true; + } else { + if (iodev_isUSRP(&iodev)) { + sf_idx = ue_sync_get_sfidx(&iodev.sframe); + } + rlen = ue_dl_receive(&ue_dl, sf_buffer, data, sf_idx, ue_sync_get_mib(&iodev.sframe).sfn, prog_args.rnti); + if (rlen < 0) { + fprintf(stderr, "\nError running receiver\n");fflush(stdout); + exit(-1); + } + if (prog_args.rnti == SIRNTI && !printed_sib && rlen > 0) { + printf("\n\nDecoded SIB1 Message: "); + vec_fprint_hex(stdout, data, rlen); + printf("\n");fflush(stdout); + printed_sib = true; + } + if (!(sf_cnt % 10)) { + printf("Cell ID: %3d, RSSI: %+.2f dBm, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, BLER: %.1e\r", + cell.id, 20*log10f(agc_get_rssi(&iodev.sframe.agc)), iodev.sframe.cur_cfo * 15, iodev.sframe.mean_time_offset / 5, iodev.sframe.peak_idx, + (int) ue_dl.pkt_errors, (int) ue_dl.pkts_total, (float) ue_dl.pkt_errors / ue_dl.pkts_total); + fflush(stdout); + if (VERBOSE_ISINFO()) { + printf("\n"); + } + } + if (!prog_args.disable_plots && sf_idx == 5) { + do_plots(&ue_dl, sf_idx); + } + } + if (iodev_isfile(&iodev)) { + sf_idx++; + if (sf_idx == NSUBFRAMES_X_FRAME) { + sf_idx = 0; + } + } + } + if (prog_args.nof_subframes > 0) { + sf_cnt++; + } + if (iodev_isfile(&iodev)) { + usleep(5000); + } + } + + if (ue_dl_initiated) { + ue_dl_free(&ue_dl); + } + iodev_free(&iodev); + + printf("\nBye\n"); + exit(0); +} + + + + +/********************************************************************** + * Plotting Functions + ***********************************************************************/ +#ifndef DISABLE_GRAPHICS + + +#include "liblte/graphics/plot.h" +plot_real_t poutfft; +plot_complex_t pce; +plot_scatter_t pscatrecv, pscatequal; + +float tmp_plot[SLOT_LEN_RE(MAX_PRB, CPNORM)]; + +void init_plots() { + plot_init(); + plot_real_init(&poutfft); + plot_real_setTitle(&poutfft, "Output FFT - Magnitude"); + plot_real_setLabels(&poutfft, "Index", "dB"); + plot_real_setYAxisScale(&poutfft, -30, 20); + + plot_complex_init(&pce); + plot_complex_setTitle(&pce, "Channel Estimates"); + plot_complex_setYAxisScale(&pce, Ip, -3, 3); + plot_complex_setYAxisScale(&pce, Q, -3, 3); + plot_complex_setYAxisScale(&pce, Magnitude, 0, 4); + plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI); + + plot_scatter_init(&pscatrecv); + plot_scatter_setTitle(&pscatrecv, "Received Symbols"); + plot_scatter_setXAxisScale(&pscatrecv, -4, 4); + plot_scatter_setYAxisScale(&pscatrecv, -4, 4); + + plot_scatter_init(&pscatequal); + plot_scatter_setTitle(&pscatequal, "Equalized Symbols"); + plot_scatter_setXAxisScale(&pscatequal, -2, 2); + plot_scatter_setYAxisScale(&pscatequal, -2, 2); +} + +void do_plots(ue_dl_t *q, uint32_t sf_idx) { + int i; + uint32_t nof_re = SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp); + uint32_t nof_symbols = q->harq_process[0].prb_alloc.re_sf[sf_idx]; + for (i = 0; i < nof_re; i++) { + tmp_plot[i] = 10 * log10f(cabsf(q->sf_symbols[i])); + if (isinf(tmp_plot[i])) { + tmp_plot[i] = -80; + } + } + plot_real_setNewData(&poutfft, tmp_plot, nof_re); + plot_complex_setNewData(&pce, q->ce[0], nof_re); + plot_scatter_setNewData(&pscatrecv, q->pdsch.pdsch_symbols[0], nof_symbols); + plot_scatter_setNewData(&pscatequal, q->pdsch.pdsch_d, nof_symbols); +} + +#endif diff --git a/lte/phy/examples/scan_mib.c b/lte/phy/examples/scan_mib.c index 9bdf883e6..d92b06aea 100644 --- a/lte/phy/examples/scan_mib.c +++ b/lte/phy/examples/scan_mib.c @@ -53,7 +53,7 @@ #define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold) int band, earfcn=-1; -float find_threshold = 10.0, track_threshold = 8.0; +float find_threshold = 10.0; int earfcn_start=-1, earfcn_end = -1; float rssi_threshold = -45.0; int max_track_lost=9; @@ -64,7 +64,7 @@ cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS]; pbch_t pbch; lte_fft_t fft; chest_t chest; -sync_t sfind, strack; +sync_t ssync; cfo_t cfocorr; float *cfo_v; @@ -86,7 +86,7 @@ enum sync_state {INIT, FIND, TRACK, MIB, DONE}; void usage(char *prog) { - printf("Usage: %s [seRrFfTtgv] -b band\n", prog); + printf("Usage: %s [seRrFfTgv] -b band\n", prog); printf("\t-s earfcn_start [Default All]\n"); printf("\t-e earfcn_end [Default All]\n"); printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi); @@ -94,7 +94,6 @@ void usage(char *prog) { printf("\t-F pss_find_nof_frames [Default %d]\n", nof_frames_find); printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold); printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track); - printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold); printf("\t-l pss_track_len [Default %d]\n", track_len); printf("\t-g gain [Default %.2f dB]\n", uhd_gain); printf("\t-v [set verbose to debug, default none]\n"); @@ -102,7 +101,7 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -1) { + while ((opt = getopt(argc, argv, "bseRrFfTgv")) != -1) { switch(opt) { case 'b': band = atoi(argv[optind]); @@ -128,9 +127,6 @@ void parse_args(int argc, char **argv) { case 'T': nof_frames_track = atoi(argv[optind]); break; - case 't': - track_threshold = atof(argv[optind]); - break; case 'g': uhd_gain = atof(argv[optind]); break; @@ -166,15 +162,11 @@ int base_init(int frame_length) { return -1; } } - if (sync_init(&sfind, FLEN)) { + if (sync_init(&ssync, FLEN, 128, 128)) { fprintf(stderr, "Error initiating PSS/SSS\n"); return -1; } - if (sync_init(&strack, track_len)) { - fprintf(stderr, "Error initiating PSS/SSS\n"); - return -1; - } - if (chest_init(&chest, LINEAR, CPNORM, 6, MAX_PORTS)) { + if (chest_init(&chest, CPNORM, 6, MAX_PORTS)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } @@ -235,8 +227,7 @@ void base_free() { cuhd_close(uhd); #endif - sync_free(&sfind); - sync_free(&strack); + sync_free(&ssync); lte_fft_free(&fft); chest_free(&chest); cfo_free(&cfocorr); @@ -320,12 +311,18 @@ int rssi_scan() { int mib_decoder_init(int cell_id) { - if (chest_ref_LTEDL(&chest, cell_id)) { + lte_cell_t cell; + cell.id = cell_id; + cell.nof_prb = 6; + cell.nof_ports = 2; + cell.cp = CPNORM; + + if (chest_ref_LTEDL(&chest, cell)) { fprintf(stderr, "Error initializing reference signal\n"); return -1; } - if (pbch_init(&pbch, 6, cell_id, CPNORM)) { + if (pbch_init(&pbch, cell)) { fprintf(stderr, "Error initiating PBCH\n"); return -1; } @@ -335,7 +332,7 @@ int mib_decoder_init(int cell_id) { int mib_decoder_run(cf_t *input, pbch_mib_t *mib) { int i; - lte_fft_run(&fft, input, fft_buffer); + lte_fft_run_slot(&fft, input, fft_buffer); /* Get channel estimates for each port */ for (i=0;i= nof_frames_find) { state = INIT; @@ -469,20 +464,20 @@ int main(int argc, char **argv) { case TRACK: INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx - track_len); - track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]); - p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack); + ret = sync_track(&ssync, input_buffer, FLEN + find_idx - track_len, &track_idx); + p2a_v[frame_cnt] = sync_get_peak_value(&ssync); /* save cell id for the best peak-to-avg */ if (p2a_v[frame_cnt] > max_peak_to_avg) { max_peak_to_avg = p2a_v[frame_cnt]; - cell_id = sync_get_cell_id(&strack); + cell_id = sync_get_cell_id(&ssync); } - if (track_idx != -1) { - cfo_v[frame_cnt] = sync_get_cfo(&strack); + if (ret == 1) { + cfo_v[frame_cnt] = sync_get_cfo(&ssync); last_found = frame_cnt; find_idx += track_idx - track_len; idx_v[frame_cnt] = find_idx; - nslot = sync_get_slot_id(&strack); + nslot = sync_get_slot_id(&ssync); } else { idx_v[frame_cnt] = -1; cfo_v[frame_cnt] = 0.0; @@ -513,7 +508,7 @@ int main(int argc, char **argv) { // Correct CFO INFO("Correcting CFO=%.4f\n", cfo[freq]); - cfo_correct(&cfocorr, &input_buffer[FLEN], (-cfo[freq])/128); + cfo_correct(&cfocorr, &input_buffer[FLEN], &input_buffer[FLEN], (-cfo[freq])/128); if (nslot == 0) { if (mib_decoder_run(&input_buffer[FLEN+find_idx], &mib)) { diff --git a/lte/phy/examples/scan_pss.c b/lte/phy/examples/scan_pss.c index 7f86b9f30..0e0868b2e 100644 --- a/lte/phy/examples/scan_pss.c +++ b/lte/phy/examples/scan_pss.c @@ -261,10 +261,12 @@ int main(int argc, char **argv) { sync_t sfind, strack; float max_peak_to_avg; float sfo; - int find_idx, track_idx, last_found; + uint32_t find_idx, track_idx; + int last_found; enum sync_state state; int n; filesink_t fs; + int ret; if (argc < 3) { usage(argv[0]); @@ -278,13 +280,13 @@ int main(int argc, char **argv) { exit(-1); } - if (sync_init(&sfind, FLEN)) { + if (sync_init(&sfind, FLEN, 128, 128)) { fprintf(stderr, "Error initiating PSS/SSS\n"); exit(-1); } sync_pss_det_peak_to_avg(&sfind); - if (sync_init(&strack, track_len)) { + if (sync_init(&strack, track_len, 128, 128)) { fprintf(stderr, "Error initiating PSS/SSS\n"); exit(-1); } @@ -315,6 +317,9 @@ int main(int argc, char **argv) { max_peak_to_avg = 0; last_found = 0; frame_cnt = 0; + + sync_set_threshold(&sfind, find_threshold, track_threshold); + while(freq= nof_frames_find) { state = INIT; @@ -382,15 +382,15 @@ int main(int argc, char **argv) { filesink_write(&fs, &input_buffer[FLEN+find_idx+track_len], track_len); - track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]); - p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack); + ret = sync_find(&strack, &input_buffer[FLEN + find_idx - track_len], &track_idx); + p2a_v[frame_cnt] = sync_get_peak_value(&strack); /* save cell id for the best peak-to-avg */ if (p2a_v[frame_cnt] > max_peak_to_avg) { max_peak_to_avg = p2a_v[frame_cnt]; cell_id = sync_get_cell_id(&strack); } - if (track_idx != -1) { + if (ret == 1) { cfo_v[frame_cnt] = sync_get_cfo(&strack); last_found = frame_cnt; find_idx += track_idx - track_len; diff --git a/lte/phy/examples/synch_file.c b/lte/phy/examples/synch_file.c index bd7e02e60..4bd746f87 100644 --- a/lte/phy/examples/synch_file.c +++ b/lte/phy/examples/synch_file.c @@ -112,10 +112,10 @@ int main(int argc, char **argv) { float mean_value[3]; int frame_cnt; cf_t *input; - int m0, m1; + uint32_t m0, m1; float m0_value, m1_value; - int N_id_2; - int sss_idx; + uint32_t N_id_2; + uint32_t sss_idx; struct timeval tdata[3]; int *exec_time; @@ -173,7 +173,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Error initializing N_id_2\n"); exit(-1); } - if (sss_synch_init(&sss[N_id_2])) { + if (sss_synch_init(&sss[N_id_2], 128)) { fprintf(stderr, "Error initializing SSS object\n"); exit(-1); } @@ -196,7 +196,7 @@ int main(int argc, char **argv) { gettimeofday(&tdata[1], NULL); if (force_cfo != CFO_AUTO) { - cfo_correct(&cfocorr, input, -force_cfo/128); + cfo_correct(&cfocorr, input, input, -force_cfo/128); } if (force_N_id_2 != -1) { diff --git a/lte/phy/include/liblte/phy/agc/agc.h b/lte/phy/include/liblte/phy/agc/agc.h new file mode 100644 index 000000000..f28e7a09b --- /dev/null +++ b/lte/phy/include/liblte/phy/agc/agc.h @@ -0,0 +1,69 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE 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 Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 AGC_ +#define AGC_ + +#include +#include +#include + +#include "liblte/config.h" + +/* Automatic Gain Control + * + */ +typedef _Complex float cf_t; + +#define AGC_DEFAULT_BW (1e-2f) + +typedef struct LIBLTE_API{ + float bandwidth; + float gain; + float y_out; + bool lock; +} agc_t; + +LIBLTE_API int agc_init (agc_t *q); + +LIBLTE_API void agc_free(agc_t *q); + +LIBLTE_API void agc_set_bandwidth(agc_t *q, + float bandwidth); + +LIBLTE_API float agc_get_rssi(agc_t *q); + +LIBLTE_API void agc_lock(agc_t *q, bool enable); + +LIBLTE_API void agc_push(agc_t *q, + cf_t *input, + cf_t *output, + uint32_t len); + +#endif // AGC_ diff --git a/lte/phy/include/liblte/phy/ch_estimation/chest.h b/lte/phy/include/liblte/phy/ch_estimation/chest.h index b1f1e59a7..2e4434fab 100644 --- a/lte/phy/include/liblte/phy/ch_estimation/chest.h +++ b/lte/phy/include/liblte/phy/ch_estimation/chest.h @@ -33,14 +33,19 @@ #include #include "liblte/config.h" + +#include "liblte/phy/resampling/interp.h" #include "liblte/phy/ch_estimation/refsignal.h" -#include "liblte/phy/filter/filter2d.h" #include "liblte/phy/common/phy_common.h" typedef _Complex float cf_t; /* this is only a shortcut */ -typedef enum {LINEAR} chest_interp_t; -typedef void (*interpolate_fnc_t) (cf_t *input, cf_t *output, int M, int len, int off_st, int off_end); +typedef void (*interpolate_fnc_t) (cf_t *input, + cf_t *output, + uint32_t M, + uint32_t len, + uint32_t off_st, + uint32_t off_end); /** This is an OFDM channel estimator. * It works with any reference signal pattern, provided by the object @@ -50,31 +55,94 @@ typedef void (*interpolate_fnc_t) (cf_t *input, cf_t *output, int M, int len, in */ /* Low-level API */ -typedef struct LIBLTE_API{ - int nof_ports; - int nof_symbols; - int nof_prb; - lte_cp_t cp; +typedef struct LIBLTE_API { + uint32_t nof_ports; + uint32_t nof_re; + uint32_t nof_symbols; + refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME]; - interpolate_fnc_t interp; + interp_t interp_time[MAX_PORTS]; + interp_t interp_freq[MAX_PORTS]; + }chest_t; -LIBLTE_API int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports); +LIBLTE_API int chest_init(chest_t *q, + uint32_t nof_re, + uint32_t nof_symbols, + uint32_t nof_ports); + LIBLTE_API void chest_free(chest_t *q); -LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id); -LIBLTE_API int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id); -LIBLTE_API int chest_ref_LTEDL(chest_t *q, int cell_id); +LIBLTE_API int chest_set_nof_ports(chest_t *q, + uint32_t nof_ports); -LIBLTE_API void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref); -LIBLTE_API void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_id); -LIBLTE_API void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot); +LIBLTE_API int chest_init_LTEDL(chest_t *q, + lte_cell_t cell); -LIBLTE_API void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id); -LIBLTE_API void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id); -LIBLTE_API void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id); -LIBLTE_API void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id); -LIBLTE_API int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]); +LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q, + uint32_t nslot, + uint32_t port_id, + lte_cell_t cell); + +LIBLTE_API int chest_ref_LTEDL_slot(chest_t *q, + uint32_t nslot, + lte_cell_t cell); + +LIBLTE_API int chest_ref_LTEDL(chest_t *q, + lte_cell_t cell); + +LIBLTE_API int chest_ce_ref(chest_t *q, + cf_t *input, + uint32_t nslot, + uint32_t port_id, + uint32_t nref); + +LIBLTE_API int chest_ce_slot_port(chest_t *q, + cf_t *input, + cf_t *ce, + uint32_t nslot, + uint32_t port_id); + +LIBLTE_API int chest_ce_sf_port(chest_t *q, + cf_t *input, + cf_t *ce, + uint32_t sf_idx, + uint32_t port_id); + +LIBLTE_API int chest_ce_slot(chest_t *q, + cf_t *input, + cf_t *ce[MAX_PORTS], + uint32_t nslot); + +LIBLTE_API int chest_ce_sf(chest_t *q, + cf_t *input, + cf_t *ce[MAX_PORTS], + uint32_t sf_idx); + +LIBLTE_API void chest_fprint(chest_t *q, + FILE *stream, + uint32_t nslot, + uint32_t port_id); + +LIBLTE_API void chest_ref_fprint(chest_t *q, + FILE *stream, + uint32_t nslot, + uint32_t port_id); + +LIBLTE_API void chest_recvsig_fprint(chest_t *q, + FILE *stream, + uint32_t nslot, + uint32_t port_id); + +LIBLTE_API void chest_ce_fprint(chest_t *q, + FILE *stream, + uint32_t nslot, + uint32_t port_id); + +LIBLTE_API int chest_ref_symbols(chest_t *q, + uint32_t port_id, + uint32_t nslot, + uint32_t l[2]); /* High-level API */ @@ -91,8 +159,7 @@ typedef struct LIBLTE_API{ cf_t *input; int in_len; struct chest_ctrl_in { - int slot_id; // slot id in the 10ms frame - int cell_id; + int sf_idx; // subframe id in the 10ms frame } ctrl_in; cf_t *output[MAX_PORTS]; int out_len[MAX_PORTS]; @@ -105,3 +172,11 @@ LIBLTE_API int chest_work(chest_hl* hl); LIBLTE_API int chest_stop(chest_hl* hl); #endif + + + + + + + + diff --git a/lte/phy/include/liblte/phy/ch_estimation/refsignal.h b/lte/phy/include/liblte/phy/ch_estimation/refsignal.h index 7b1f6518a..51ad505ff 100644 --- a/lte/phy/include/liblte/phy/ch_estimation/refsignal.h +++ b/lte/phy/include/liblte/phy/ch_estimation/refsignal.h @@ -43,26 +43,30 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API{ - int time_idx; - int freq_idx; + uint32_t time_idx; + uint32_t freq_idx; cf_t simbol; cf_t recv_simbol; }ref_t; typedef struct LIBLTE_API{ - int nof_refs; // number of reference signals - int *symbols_ref; // symbols with at least one reference - int nsymbols; // number of symbols with at least one reference - int voffset; // offset of the first reference in the freq domain - int nof_prb; + uint32_t nof_refs; // number of reference signals + uint32_t *symbols_ref; // symbols with at least one reference + uint32_t nsymbols; // number of symbols with at least one reference + uint32_t voffset; // offset of the first reference in the freq domain + uint32_t nof_prb; ref_t *refs; cf_t *ch_est; } refsignal_t; -LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot, - int cell_id, lte_cp_t cp, int nof_prb); +LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q, + uint32_t port_id, + uint32_t nslot, + lte_cell_t cell); + LIBLTE_API void refsignal_free(refsignal_t *q); -LIBLTE_API void refsignal_put(refsignal_t *q, cf_t *slot_symbols); +LIBLTE_API int refsignal_put(refsignal_t *q, + cf_t *slot_symbols); #endif diff --git a/lte/phy/include/liblte/phy/channel/ch_awgn.h b/lte/phy/include/liblte/phy/channel/ch_awgn.h index 19a452cb1..fa209dfe3 100644 --- a/lte/phy/include/liblte/phy/channel/ch_awgn.h +++ b/lte/phy/include/liblte/phy/channel/ch_awgn.h @@ -34,8 +34,16 @@ typedef _Complex float cf_t; -LIBLTE_API void ch_awgn_c(const cf_t* input, cf_t* output, float variance, int buff_sz); -LIBLTE_API void ch_awgn_f(const float* x, float* y, float variance, int buff_sz); +LIBLTE_API void ch_awgn_c(const cf_t* input, + cf_t* output, + float variance, + int buff_sz); + +LIBLTE_API void ch_awgn_f(const float* x, + float* y, + float variance, + int buff_sz); + /* High-level API */ diff --git a/lte/phy/include/liblte/phy/common/fft.h b/lte/phy/include/liblte/phy/common/fft.h index 0b0f1dd0b..3e20c475f 100644 --- a/lte/phy/include/liblte/phy/common/fft.h +++ b/lte/phy/include/liblte/phy/common/fft.h @@ -42,20 +42,41 @@ typedef _Complex float cf_t; /* this is only a shortcut */ /* This is common for both directions */ typedef struct LIBLTE_API{ dft_plan_t fft_plan; - int nof_symbols; - int symbol_sz; - int nof_guards; - int nof_re; - lte_cp_t cp_type; + uint32_t nof_symbols; + uint32_t symbol_sz; + uint32_t nof_guards; + uint32_t nof_re; + uint32_t slot_sz; + lte_cp_t cp; cf_t *tmp; // for removing zero padding }lte_fft_t; -LIBLTE_API int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb); -LIBLTE_API void lte_fft_free(lte_fft_t *q); -LIBLTE_API void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output); +LIBLTE_API int lte_fft_init(lte_fft_t *q, + lte_cp_t cp_type, + uint32_t nof_prb); + +LIBLTE_API void lte_fft_free(lte_fft_t *q); + +LIBLTE_API void lte_fft_run_slot(lte_fft_t *q, + cf_t *input, + cf_t *output); + +LIBLTE_API void lte_fft_run_sf(lte_fft_t *q, + cf_t *input, + cf_t *output); + +LIBLTE_API int lte_ifft_init(lte_fft_t *q, + lte_cp_t cp_type, + uint32_t nof_prb); -LIBLTE_API int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb); LIBLTE_API void lte_ifft_free(lte_fft_t *q); -LIBLTE_API void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output); + +LIBLTE_API void lte_ifft_run_slot(lte_fft_t *q, + cf_t *input, + cf_t *output); + +LIBLTE_API void lte_ifft_run_sf(lte_fft_t *q, + cf_t *input, + cf_t *output); #endif diff --git a/lte/phy/include/liblte/phy/common/phy_common.h b/lte/phy/include/liblte/phy/common/phy_common.h index 3449449c8..29e8c233e 100644 --- a/lte/phy/include/liblte/phy/common/phy_common.h +++ b/lte/phy/include/liblte/phy/common/phy_common.h @@ -29,44 +29,50 @@ #ifndef _LTEBASE_ #define _LTEBASE_ +#include +#include #include "liblte/config.h" #define NSUBFRAMES_X_FRAME 10 -#define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME) +#define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME) #define LTE_NSOFT_BITS 250368 // Soft buffer size for Category 1 UE -#define LTE_NULL_BIT 0 +#define LTE_NULL_BIT 0 #define LTE_NULL_SYMBOL 2 #define LTE_NIL_SYMBOL 2 -#define MAX_PORTS 4 -#define MAX_PORTS_CTRL 4 +#define MAX_PORTS 4 #define MAX_LAYERS 8 #define MAX_CODEWORDS 2 #define LTE_CRC24A 0x1864CFB #define LTE_CRC24B 0X1800063 -#define LTE_CRC16 0x11021 -#define LTE_CRC8 0x19B +#define LTE_CRC16 0x11021 +#define LTE_CRC8 0x19B typedef enum {CPNORM, CPEXT} lte_cp_t; -#define SIRNTI 0xFFFF +#define SIRNTI 0xFFFF #define PRNTI 0xFFFE #define MRNTI 0xFFFD -#define MAX_NSYMB 7 +#define MAX_NSYMB 7 -#define CPNORM_NSYMB 7 +#define MAX_PRB 110 +#define RE_X_RB 12 + +#define SYMBOL_SZ_MAX 2048 + +#define CPNORM_NSYMB 7 #define CPNORM_SF_NSYMB 2*CPNORM_NSYMB -#define CPNORM_0_LEN 160 -#define CPNORM_LEN 144 +#define CPNORM_0_LEN 160 +#define CPNORM_LEN 144 -#define CPEXT_NSYMB 6 +#define CPEXT_NSYMB 6 #define CPEXT_SF_NSYMB 2*CPEXT_NSYMB -#define CPEXT_LEN 512 -#define CPEXT_7_5_LEN 1024 +#define CPEXT_LEN 512 +#define CPEXT_7_5_LEN 1024 #define CP_ISNORM(cp) (cp==CPNORM) #define CP_ISEXT(cp) (cp==CPEXT) @@ -78,33 +84,40 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define SLOT_LEN_CPNORM(symbol_sz) (symbol_sz+CP(symbol_sz,CPNORM_0_LEN)+(CPNORM_NSYMB-1)*(symbol_sz+CP(symbol_sz,CPNORM_LEN))) #define SLOT_LEN_CPEXT(symbol_sz) (CPEXT_NSYMB*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) -#define SLOT_LEN(symbol_sz, cp) CP_ISNORM(cp)?SLOT_LEN_CPNORM(symbol_sz):SLOT_LEN_CPEXT(symbol_sz) +#define SLOT_LEN(symbol_sz, cp) (CP_ISNORM(cp)?SLOT_LEN_CPNORM(symbol_sz):SLOT_LEN_CPEXT(symbol_sz)) -#define SF_LEN_CPNORM(symbol_sz) 2*SLOT_LEN_CPNORM(symbol_sz) -#define SF_LEN_CPEXT(symbol_sz) 2*SLOT_LEN_CPEXT(symbol_sz) -#define SF_LEN(symbol_sz, cp) 2*SLOT_LEN(cp, symbol_sz) +#define SF_LEN_CPNORM(symbol_sz) (2*SLOT_LEN_CPNORM(symbol_sz)) +#define SF_LEN_CPEXT(symbol_sz) (2*SLOT_LEN_CPEXT(symbol_sz)) +#define SF_LEN(symbol_sz, cp) (2*SLOT_LEN(symbol_sz, cp)) +#define SF_LEN_MAX SF_LEN(SYMBOL_SZ_MAX, CPNORM) + +#define SLOT_LEN_RE(nof_prb, cp) (nof_prb*RE_X_RB*CP_NSYMB(cp)) +#define SF_LEN_RE(nof_prb, cp) (2*SLOT_LEN_RE(nof_prb, cp)) #define SLOT_IDX_CPNORM(idx, symbol_sz) (idx==0?(CP(symbol_sz, CPNORM_0_LEN)):(CP(symbol_sz, CPNORM_0_LEN)+idx*(symbol_sz+CP(symbol_sz, CPNORM_LEN)))) #define SLOT_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) #define SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) (symbol_idx*nof_prb*RE_X_RB + sample_idx) -#define MAX_PRB 110 -#define RE_X_RB 12 - #define RS_VSHIFT(cell_id) (cell_id%6) #define GUARD_RE(nof_prb) ((lte_symbol_sz(nof_prb)-nof_prb*RE_X_RB)/2) +#define SYMBOL_HAS_REF(l, cp, nof_ports) ((l == 1 && nof_ports == 4) \ + || l == 0 \ + || l == CP_NSYMB(cp) - 3) -LIBLTE_API const int lte_symbol_sz(int nof_prb); -LIBLTE_API int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols); -LIBLTE_API int lte_voffset(int symbol_id, int cell_id, int nof_ports); #define NOF_LTE_BANDS 29 #define NOF_TC_CB_SIZES 188 +typedef struct LIBLTE_API { + uint32_t nof_prb; + uint32_t nof_ports; + uint32_t id; + lte_cp_t cp; +}lte_cell_t; typedef enum LIBLTE_API { SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX @@ -113,6 +126,10 @@ typedef enum LIBLTE_API { typedef enum LIBLTE_API { PHICH_NORM, PHICH_EXT} phich_length_t; typedef enum LIBLTE_API { R_1_6, R_1_2, R_1, R_2} phich_resources_t; +typedef enum LIBLTE_API { + LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6 +} lte_mod_t; + typedef struct LIBLTE_API { int id; @@ -123,16 +140,59 @@ LIBLTE_API enum band_geographical_area { ALL, NAR, APAC, EMEA, JAPAN, CALA, NA }; -LIBLTE_API int lte_cb_size(int index); -LIBLTE_API int lte_find_cb_index(int long_cb); +LIBLTE_API bool lte_cell_isvalid(lte_cell_t *cell); -LIBLTE_API float lte_band_fd(int earfcn); -LIBLTE_API int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int earfcn_start, int earfcn_end, int max_elems); -LIBLTE_API int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_nelems); -LIBLTE_API int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems); +LIBLTE_API bool lte_N_id_2_isvalid(uint32_t N_id_2); + +LIBLTE_API bool lte_N_id_1_isvalid(uint32_t N_id_1); + +LIBLTE_API bool lte_symbol_sz_isvalid(uint32_t symbol_sz); + +LIBLTE_API int lte_symbol_sz(uint32_t nof_prb); + + +LIBLTE_API int lte_sampling_freq_hz(uint32_t nof_prb); + +LIBLTE_API uint32_t lte_re_x_prb(uint32_t ns, + uint32_t symbol, + uint32_t nof_ports, + uint32_t nof_symbols); + +LIBLTE_API uint32_t lte_voffset(uint32_t symbol_id, + uint32_t cell_id, + uint32_t nof_ports); + +LIBLTE_API int lte_cb_size(uint32_t index); + +LIBLTE_API char *lte_cp_string(lte_cp_t cp); + +LIBLTE_API char *lte_mod_string(lte_mod_t mod); + +LIBLTE_API uint32_t lte_mod_bits_x_symbol(lte_mod_t mod); + +LIBLTE_API int lte_find_cb_index(uint32_t long_cb); + +LIBLTE_API float lte_band_fd(uint32_t earfcn); + +LIBLTE_API int lte_band_get_fd_band(uint32_t band, + lte_earfcn_t *earfcn, + int earfcn_start, + int earfcn_end, + uint32_t max_elems); + +LIBLTE_API int lte_band_get_fd_band_all(uint32_t band, + lte_earfcn_t *earfcn, + uint32_t max_nelems); + +LIBLTE_API int lte_band_get_fd_region(enum band_geographical_area region, + lte_earfcn_t *earfcn, + uint32_t max_elems); + +LIBLTE_API int lte_str2mimotype(char *mimo_type_str, + lte_mimo_type_t *type); -LIBLTE_API int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type); LIBLTE_API char *lte_mimotype2str(lte_mimo_type_t type); + #endif diff --git a/lte/phy/include/liblte/phy/common/sequence.h b/lte/phy/include/liblte/phy/common/sequence.h index 0fb52df2f..972a31ebf 100644 --- a/lte/phy/include/liblte/phy/common/sequence.h +++ b/lte/phy/include/liblte/phy/common/sequence.h @@ -33,19 +33,39 @@ typedef struct LIBLTE_API { char *c; - int len; + uint32_t len; } sequence_t; -LIBLTE_API int sequence_init(sequence_t *q, int len); +LIBLTE_API int sequence_init(sequence_t *q, uint32_t len); + LIBLTE_API void sequence_free(sequence_t *q); -LIBLTE_API int sequence_LTEPRS(sequence_t *q, int len, int seed); +LIBLTE_API int sequence_LTEPRS(sequence_t *q, + uint32_t len, + uint32_t seed); -LIBLTE_API int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id); -LIBLTE_API int sequence_pcfich(sequence_t *seq, int nslot, int cell_id); -LIBLTE_API int sequence_phich(sequence_t *seq, int nslot, int cell_id); -LIBLTE_API int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len); -LIBLTE_API int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, - int nslot, int cell_id, int len); +LIBLTE_API int sequence_pbch(sequence_t *seq, + lte_cp_t cp, + uint32_t cell_id); + +LIBLTE_API int sequence_pcfich(sequence_t *seq, + uint32_t nslot, + uint32_t cell_id); + +LIBLTE_API int sequence_phich(sequence_t *seq, + uint32_t nslot, + uint32_t cell_id); + +LIBLTE_API int sequence_pdcch(sequence_t *seq, + uint32_t nslot, + uint32_t cell_id, + uint32_t len); + +LIBLTE_API int sequence_pdsch(sequence_t *seq, + unsigned short rnti, + int q, + uint32_t nslot, + uint32_t cell_id, + uint32_t len); #endif diff --git a/lte/phy/include/liblte/phy/fec/convcoder.h b/lte/phy/include/liblte/phy/fec/convcoder.h index 79416289f..38dd5857d 100644 --- a/lte/phy/include/liblte/phy/fec/convcoder.h +++ b/lte/phy/include/liblte/phy/fec/convcoder.h @@ -34,13 +34,13 @@ #include "liblte/config.h" typedef struct LIBLTE_API { - int R; - int K; - int poly[3]; + uint32_t R; + uint32_t K; + uint32_t poly[3]; bool tail_biting; }convcoder_t; -LIBLTE_API int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length); +LIBLTE_API int convcoder_encode(convcoder_t *q, char *input, char *output, uint32_t frame_length); /* High-level API */ diff --git a/lte/phy/include/liblte/phy/fec/crc.h b/lte/phy/include/liblte/phy/fec/crc.h index e071f3398..e9d148a52 100644 --- a/lte/phy/include/liblte/phy/fec/crc.h +++ b/lte/phy/include/liblte/phy/fec/crc.h @@ -30,6 +30,7 @@ #define CRC_ #include "liblte/config.h" +#include typedef struct LIBLTE_API { unsigned long table[256]; @@ -45,6 +46,6 @@ typedef struct LIBLTE_API { LIBLTE_API int crc_init(crc_t *h, unsigned int crc_poly, int crc_order); LIBLTE_API int crc_set_init(crc_t *h, unsigned long crc_init_value); LIBLTE_API void crc_attach(crc_t *h, char *data, int len); -LIBLTE_API unsigned int crc_checksum(crc_t *h, char *data, int len); +LIBLTE_API uint32_t crc_checksum(crc_t *h, char *data, int len); #endif diff --git a/lte/phy/include/liblte/phy/fec/rm_conv.h b/lte/phy/include/liblte/phy/fec/rm_conv.h index e161fe47d..6a37177b0 100644 --- a/lte/phy/include/liblte/phy/fec/rm_conv.h +++ b/lte/phy/include/liblte/phy/fec/rm_conv.h @@ -33,8 +33,15 @@ #define RX_NULL 10000 #define TX_NULL 80 -LIBLTE_API int rm_conv_tx(char *input, int in_len, char *output, int out_len); -LIBLTE_API int rm_conv_rx(float *input, int in_len, float *output, int out_len); +LIBLTE_API int rm_conv_tx(char *input, + uint32_t in_len, + char *output, + uint32_t out_len); + +LIBLTE_API int rm_conv_rx(float *input, + uint32_t in_len, + float *output, + uint32_t out_len); /* High-level API */ typedef struct diff --git a/lte/phy/include/liblte/phy/fec/rm_turbo.h b/lte/phy/include/liblte/phy/fec/rm_turbo.h index 7f1c45db3..0b5fad70e 100644 --- a/lte/phy/include/liblte/phy/fec/rm_turbo.h +++ b/lte/phy/include/liblte/phy/fec/rm_turbo.h @@ -40,25 +40,30 @@ #include "liblte/config.h" -typedef struct LIBLTE_API { - int buffer_len; - char *buffer; -} rm_turbo_t; -LIBLTE_API int rm_turbo_init(rm_turbo_t *q, int max_codeblock_len); -LIBLTE_API void rm_turbo_free(rm_turbo_t *q); -LIBLTE_API int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, - int out_len, int rv_idx); -LIBLTE_API int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, - float *output, int out_len, int rv_idx); +LIBLTE_API int rm_turbo_tx(char *w_buff, + uint32_t buff_len, + char *input, + uint32_t in_len, + char *output, + uint32_t out_len, + uint32_t rv_idx); + +LIBLTE_API int rm_turbo_rx(float *w_buff, + uint32_t buff_len, + float *input, + uint32_t in_len, + float *output, + uint32_t out_len, + uint32_t rv_idx); /* High-level API */ typedef struct LIBLTE_API { - rm_turbo_t q; + struct rm_turbo_init { int direction; } init; - void *input; // input type may be char or float depending on hard + void *input; // input type may be char or float depending on hard int in_len; struct rm_turbo_ctrl_in { int E; diff --git a/lte/phy/include/liblte/phy/fec/tc_interl.h b/lte/phy/include/liblte/phy/fec/tc_interl.h index 03a9eb824..ec9eb747f 100644 --- a/lte/phy/include/liblte/phy/fec/tc_interl.h +++ b/lte/phy/include/liblte/phy/fec/tc_interl.h @@ -31,15 +31,15 @@ #include "liblte/config.h" typedef struct LIBLTE_API { - int *forward; - int *reverse; - int max_long_cb; + uint32_t *forward; + uint32_t *reverse; + uint32_t max_long_cb; } tc_interl_t; -LIBLTE_API int tc_interl_LTE_gen(tc_interl_t *h, int long_cb); -LIBLTE_API int tc_interl_UMTS_gen(tc_interl_t *h, int long_cb); +LIBLTE_API int tc_interl_LTE_gen(tc_interl_t *h, uint32_t long_cb); +LIBLTE_API int tc_interl_UMTS_gen(tc_interl_t *h, uint32_t long_cb); -LIBLTE_API int tc_interl_init(tc_interl_t *h, int max_long_cb); +LIBLTE_API int tc_interl_init(tc_interl_t *h, uint32_t max_long_cb); LIBLTE_API void tc_interl_free(tc_interl_t *h); #endif diff --git a/lte/phy/include/liblte/phy/fec/turbocoder.h b/lte/phy/include/liblte/phy/fec/turbocoder.h index f150446bf..af272e223 100644 --- a/lte/phy/include/liblte/phy/fec/turbocoder.h +++ b/lte/phy/include/liblte/phy/fec/turbocoder.h @@ -37,13 +37,13 @@ #define TOTALTAIL 12 typedef struct LIBLTE_API { - int max_long_cb; + uint32_t max_long_cb; tc_interl_t interl; } tcod_t; -LIBLTE_API int tcod_init(tcod_t *h, int max_long_cb); +LIBLTE_API int tcod_init(tcod_t *h, uint32_t max_long_cb); LIBLTE_API void tcod_free(tcod_t *h); -LIBLTE_API int tcod_encode(tcod_t *h, char *input, char *output, int long_cb); +LIBLTE_API int tcod_encode(tcod_t *h, char *input, char *output, uint32_t long_cb); #endif diff --git a/lte/phy/include/liblte/phy/fec/turbodecoder.h b/lte/phy/include/liblte/phy/fec/turbodecoder.h index da2e60b5f..178f51956 100644 --- a/lte/phy/include/liblte/phy/fec/turbodecoder.h +++ b/lte/phy/include/liblte/phy/fec/turbodecoder.h @@ -68,13 +68,25 @@ typedef struct LIBLTE_API { tc_interl_t interleaver; } tdec_t; -LIBLTE_API int tdec_init(tdec_t *h, int max_long_cb); -LIBLTE_API void tdec_free(tdec_t *h); +LIBLTE_API int tdec_init(tdec_t * h, + uint32_t max_long_cb); -LIBLTE_API int tdec_reset(tdec_t *h, int long_cb); -LIBLTE_API void tdec_iteration(tdec_t *h, llr_t *input, int long_cb); -LIBLTE_API void tdec_decision(tdec_t *h, char *output, int long_cb); -LIBLTE_API void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations, - int long_cb); +LIBLTE_API void tdec_free(tdec_t * h); + +LIBLTE_API int tdec_reset(tdec_t * h, uint32_t long_cb); + +LIBLTE_API void tdec_iteration(tdec_t * h, + llr_t * input, + uint32_t long_cb); + +LIBLTE_API void tdec_decision(tdec_t * h, + char *output, + uint32_t long_cb); + +LIBLTE_API void tdec_run_all(tdec_t * h, + llr_t * input, + char *output, + uint32_t nof_iterations, + uint32_t long_cb); #endif diff --git a/lte/phy/include/liblte/phy/fec/viterbi.h b/lte/phy/include/liblte/phy/fec/viterbi.h index 0d955656d..a94c58e19 100644 --- a/lte/phy/include/liblte/phy/fec/viterbi.h +++ b/lte/phy/include/liblte/phy/fec/viterbi.h @@ -38,21 +38,34 @@ typedef enum { typedef struct LIBLTE_API{ void *ptr; - int R; - int K; + uint32_t R; + uint32_t K; unsigned int framebits; bool tail_biting; - int poly[3]; - int (*decode) (void*, unsigned char*, char*, int); + uint32_t poly[3]; + int (*decode) (void*, uint8_t*, char*, uint32_t); void (*free) (void*); unsigned char *tmp; unsigned char *symbols_uc; }viterbi_t; -LIBLTE_API int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int max_frame_length, bool tail_bitting); +LIBLTE_API int viterbi_init(viterbi_t *q, + viterbi_type_t type, + uint32_t poly[3], + uint32_t max_frame_length, + bool tail_bitting); + LIBLTE_API void viterbi_free(viterbi_t *q); -LIBLTE_API int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length); -LIBLTE_API int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, int frame_length); + +LIBLTE_API int viterbi_decode_f(viterbi_t *q, + float *symbols, + char *data, + uint32_t frame_length); + +LIBLTE_API int viterbi_decode_uc(viterbi_t *q, + uint8_t *symbols, + char *data, + uint32_t frame_length); /* High-level API */ diff --git a/lte/phy/include/liblte/phy/modem/demod_hard.h b/lte/phy/include/liblte/phy/modem/demod_hard.h index a3b621819..51f5b6c53 100644 --- a/lte/phy/include/liblte/phy/modem/demod_hard.h +++ b/lte/phy/include/liblte/phy/modem/demod_hard.h @@ -38,13 +38,13 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API { - enum modem_std table; /* In this implementation, mapping table is hard-coded */ + lte_mod_t mod; /* In this implementation, mapping table is hard-coded */ }demod_hard_t; LIBLTE_API void demod_hard_init(demod_hard_t* q); -LIBLTE_API void demod_hard_table_set(demod_hard_t* q, enum modem_std table); -LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, int nsymbols); +LIBLTE_API void demod_hard_table_set(demod_hard_t* q, lte_mod_t mod); +LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, uint32_t nsymbols); @@ -52,7 +52,7 @@ LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, typedef struct LIBLTE_API { demod_hard_t obj; struct demod_hard_init { - enum modem_std std; // Symbol mapping standard (see modem_table.h) + lte_mod_t std; // Symbol mapping standard (see modem_table.h) } init; cf_t* input; diff --git a/lte/phy/include/liblte/phy/modem/demod_soft.h b/lte/phy/include/liblte/phy/modem/demod_soft.h index bb2c4368b..2a2e40b55 100644 --- a/lte/phy/include/liblte/phy/modem/demod_soft.h +++ b/lte/phy/include/liblte/phy/modem/demod_soft.h @@ -56,7 +56,7 @@ typedef struct LIBLTE_API { modem_table_t table; struct demod_soft_init{ - enum modem_std std; // symbol mapping standard (see modem_table.h) + lte_mod_t std; // symbol mapping standard (see modem_table.h) } init; const cf_t* input; diff --git a/lte/phy/include/liblte/phy/modem/mod.h b/lte/phy/include/liblte/phy/modem/mod.h index 5467f13d0..8ee5defc8 100644 --- a/lte/phy/include/liblte/phy/modem/mod.h +++ b/lte/phy/include/liblte/phy/modem/mod.h @@ -37,13 +37,13 @@ typedef _Complex float cf_t; -LIBLTE_API int mod_modulate(modem_table_t* table, const char *bits, cf_t* symbols, int nbits); +LIBLTE_API int mod_modulate(modem_table_t* table, const char *bits, cf_t* symbols, uint32_t nbits); /* High-level API */ typedef struct LIBLTE_API { modem_table_t obj; struct mod_init { - enum modem_std std; // symbol mapping standard (see modem_table.h) + lte_mod_t std; // symbol mapping standard (see modem_table.h) } init; const char* input; diff --git a/lte/phy/include/liblte/phy/modem/modem_table.h b/lte/phy/include/liblte/phy/modem/modem_table.h index f94c03f86..cbc4fbee9 100644 --- a/lte/phy/include/liblte/phy/modem/modem_table.h +++ b/lte/phy/include/liblte/phy/modem/modem_table.h @@ -34,30 +34,36 @@ #include #include +#include "liblte/phy/common/phy_common.h" #include "liblte/config.h" typedef _Complex float cf_t; typedef struct LIBLTE_API { - int idx[2][6][32]; + uint32_t idx[2][6][32]; }soft_table_t; typedef struct LIBLTE_API { cf_t* symbol_table; // bit-to-symbol mapping soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating) - int nsymbols; // number of modulation symbols - int nbits_x_symbol; // number of bits per symbol + uint32_t nsymbols; // number of modulation symbols + uint32_t nbits_x_symbol; // number of bits per symbol }modem_table_t; -// Modulation standards -enum modem_std { - LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6 -}; - LIBLTE_API void modem_table_init(modem_table_t* q); + LIBLTE_API void modem_table_free(modem_table_t* q); + LIBLTE_API void modem_table_reset(modem_table_t* q); -LIBLTE_API int modem_table_set(modem_table_t* q, cf_t* table, soft_table_t *soft_table, int nsymbols, int nbits_x_symbol); -LIBLTE_API int modem_table_std(modem_table_t* q, enum modem_std table, bool compute_soft_demod); + +LIBLTE_API int modem_table_set(modem_table_t* q, + cf_t* table, + soft_table_t *soft_table, + uint32_t nsymbols, + uint32_t nbits_x_symbol); + +LIBLTE_API int modem_table_lte(modem_table_t* q, + lte_mod_t modulation, + bool compute_soft_demod); #endif // MODEM_TABLE_ diff --git a/lte/phy/include/liblte/phy/phch/dci.h b/lte/phy/include/liblte/phy/phch/dci.h index eb6b8afd3..be57914c0 100644 --- a/lte/phy/include/liblte/phy/phch/dci.h +++ b/lte/phy/include/liblte/phy/phch/dci.h @@ -62,41 +62,72 @@ typedef enum { } dci_spec_t; typedef struct LIBLTE_API { - unsigned char nof_bits; - unsigned char L; // Aggregation level - unsigned char ncce; // Position of first CCE of the dci - unsigned short rnti; -} dci_candidate_t; + uint32_t L; // Aggregation level + uint32_t ncce; // Position of first CCE of the dci +} dci_location_t; typedef struct LIBLTE_API { char data[DCI_MAX_BITS]; - dci_candidate_t location; + uint32_t nof_bits; } dci_msg_t; -typedef struct LIBLTE_API { - dci_msg_t *msg; - int nof_dcis; - int max_dcis; -} dci_t; +/* Converts a received PDSCH DL scheduling DCI message + * to ra structures ready to be passed to the harq setup function + */ +LIBLTE_API int dci_msg_to_ra_dl(dci_msg_t *msg, + uint16_t msg_rnti, + uint16_t c_rnti, + lte_cell_t cell, + uint32_t cfi, + ra_pdsch_t *ra_dl); -LIBLTE_API int dci_init(dci_t *q, int max_dci); -LIBLTE_API void dci_free(dci_t *q); +/* TODO +LIBLTE_API int dci_msg_to_ra_ul(dci_msg_t *msg, + uint16_t msg_rnti, + uint16_t c_rnti, + lte_cell_t cell, + uint32_t cfi, + ra_pusch_t *ra_ul); +*/ LIBLTE_API char* dci_format_string(dci_format_t format); -LIBLTE_API int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti); -LIBLTE_API void dci_candidate_fprint(FILE *f, dci_candidate_t *q); +LIBLTE_API int dci_location_set(dci_location_t *c, + uint32_t L, + uint32_t nCCE); -LIBLTE_API int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti); -LIBLTE_API void dci_msg_type_fprint(FILE *f, dci_msg_type_t type); +LIBLTE_API bool dci_location_isvalid(dci_location_t *c); + +LIBLTE_API int dci_msg_get_type(dci_msg_t *msg, + dci_msg_type_t *type, + uint32_t nof_prb, + uint16_t msg_rnti, + uint16_t crnti); + +LIBLTE_API void dci_msg_type_fprint(FILE *f, + dci_msg_type_t type); // For dci_msg_type_t = PUSCH_SCHED -LIBLTE_API int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb); -LIBLTE_API int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb); +LIBLTE_API int dci_msg_pack_pusch(ra_pusch_t *data, + dci_msg_t *msg, + uint32_t nof_prb); + +LIBLTE_API int dci_msg_unpack_pusch(dci_msg_t *msg, + ra_pusch_t *data, + uint32_t nof_prb); // For dci_msg_type_t = PDSCH_SCHED -LIBLTE_API int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti); -LIBLTE_API int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti); +LIBLTE_API int dci_msg_pack_pdsch(ra_pdsch_t *data, + dci_msg_t *msg, + dci_format_t format, + uint32_t nof_prb, + bool crc_is_crnti); -LIBLTE_API int dci_format_sizeof(dci_format_t format, int nof_prb); +LIBLTE_API int dci_msg_unpack_pdsch(dci_msg_t *msg, + ra_pdsch_t *data, + uint32_t nof_prb, + bool crc_is_crnti); + +LIBLTE_API uint32_t dci_format_sizeof(dci_format_t format, + uint32_t nof_prb); #endif // DCI_ diff --git a/lte/phy/include/liblte/phy/phch/pbch.h b/lte/phy/include/liblte/phy/phch/pbch.h index 65c11f9e0..080702807 100644 --- a/lte/phy/include/liblte/phy/phch/pbch.h +++ b/lte/phy/include/liblte/phy/phch/pbch.h @@ -47,24 +47,23 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API { - int nof_ports; - int nof_prb; - int sfn; + uint32_t nof_ports; + uint32_t nof_prb; + uint32_t sfn; phich_length_t phich_length; phich_resources_t phich_resources; }pbch_mib_t; /* PBCH object */ typedef struct LIBLTE_API { - int cell_id; - lte_cp_t cp; - int nof_prb; - int nof_symbols; + lte_cell_t cell; + + uint32_t nof_symbols; /* buffers */ - cf_t *ce[MAX_PORTS_CTRL]; - cf_t *pbch_symbols[MAX_PORTS_CTRL]; - cf_t *pbch_x[MAX_PORTS_CTRL]; + cf_t *ce[MAX_PORTS]; + cf_t *pbch_symbols[MAX_PORTS]; + cf_t *pbch_x[MAX_PORTS]; cf_t *pbch_d; float *pbch_llr; float *temp; @@ -73,7 +72,7 @@ typedef struct LIBLTE_API { char *data; char *data_enc; - int frame_idx; + uint32_t frame_idx; /* tx & rx objects */ modem_table_t mod; @@ -83,17 +82,24 @@ typedef struct LIBLTE_API { crc_t crc; convcoder_t encoder; -}pbch_t; +} pbch_t; + +LIBLTE_API int pbch_init(pbch_t *q, + lte_cell_t cell); -LIBLTE_API int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp); LIBLTE_API void pbch_free(pbch_t *q); -LIBLTE_API int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float ebno, pbch_mib_t *mib); -LIBLTE_API void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports); +LIBLTE_API int pbch_decode(pbch_t *q, + cf_t *sf_symbols, + cf_t *ce[MAX_PORTS], + pbch_mib_t *mib); + +LIBLTE_API int pbch_encode(pbch_t *q, + pbch_mib_t *mib, + cf_t *sf_symbols[MAX_PORTS]); + LIBLTE_API void pbch_decode_reset(pbch_t *q); -LIBLTE_API void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib); -LIBLTE_API bool pbch_exists(int nframe, int nslot); -LIBLTE_API int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id); -LIBLTE_API int pbch_get(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id); +LIBLTE_API void pbch_mib_fprint(FILE *stream, + pbch_mib_t *mib); #endif // PBCH_ diff --git a/lte/phy/include/liblte/phy/phch/pcfich.h b/lte/phy/include/liblte/phy/phch/pcfich.h index e092ce4e5..80ad465f9 100644 --- a/lte/phy/include/liblte/phy/phch/pcfich.h +++ b/lte/phy/include/liblte/phy/phch/pcfich.h @@ -45,19 +45,16 @@ typedef _Complex float cf_t; /* PCFICH object */ typedef struct LIBLTE_API { - int cell_id; - lte_cp_t cp; + lte_cell_t cell; int nof_symbols; - int nof_prb; - int nof_ports; /* handler to REGs resource mapper */ regs_t *regs; /* buffers */ - cf_t ce[MAX_PORTS_CTRL][PCFICH_RE]; - cf_t pcfich_symbols[MAX_PORTS_CTRL][PCFICH_RE]; - cf_t pcfich_x[MAX_PORTS_CTRL][PCFICH_RE]; + cf_t ce[MAX_PORTS][PCFICH_RE]; + cf_t pcfich_symbols[MAX_PORTS][PCFICH_RE]; + cf_t pcfich_x[MAX_PORTS][PCFICH_RE]; cf_t pcfich_d[PCFICH_RE]; /* bit message */ @@ -70,16 +67,22 @@ typedef struct LIBLTE_API { } pcfich_t; -LIBLTE_API int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, - int nof_tx_ports, lte_cp_t cp); -LIBLTE_API void pcfich_free(pcfich_t *q); -LIBLTE_API int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], - int nsubframe, int *cfi, int *distance); -LIBLTE_API int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], - int nsubframe); +LIBLTE_API int pcfich_init(pcfich_t *q, + regs_t *regs, + lte_cell_t cell); -LIBLTE_API bool pcfich_exists(int nframe, int nslot); -LIBLTE_API int pcfich_put(regs_t *h, cf_t *pcfich, cf_t *slot_data); -LIBLTE_API int pcfich_get(regs_t *h, cf_t *pcfich, cf_t *slot_data); +LIBLTE_API void pcfich_free(pcfich_t *q); + +LIBLTE_API int pcfich_decode(pcfich_t *q, + cf_t *sf_symbols, + cf_t *ce[MAX_PORTS], + uint32_t subframe, + uint32_t *cfi, + uint32_t *distance); + +LIBLTE_API int pcfich_encode(pcfich_t *q, + uint32_t cfi, + cf_t *sf_symbols[MAX_PORTS], + uint32_t subframe); #endif diff --git a/lte/phy/include/liblte/phy/phch/pdcch.h b/lte/phy/include/liblte/phy/phch/pdcch.h index 7ae5f6918..f15dd1519 100644 --- a/lte/phy/include/liblte/phy/phch/pdcch.h +++ b/lte/phy/include/liblte/phy/phch/pdcch.h @@ -44,41 +44,26 @@ typedef _Complex float cf_t; -#define PDCCH_NOF_SEARCH_MODES 3 typedef enum LIBLTE_API { - SEARCH_NONE = 3, SEARCH_SI = 0, SEARCH_RA = 1, SEARCH_UE = 2 + SEARCH_UE, SEARCH_COMMON } pdcch_search_mode_t; -/* - * A search mode is indicated by higher layers to look for SI/C/RA-RNTI - * DCI messages as defined in Section 7.1 of 36.213 - */ -typedef struct LIBLTE_API { - int nof_candidates; - dci_candidate_t *candidates[NSUBFRAMES_X_FRAME]; -} pdcch_search_t; /* PDCCH object */ typedef struct LIBLTE_API { - int cell_id; - lte_cp_t cp; - int nof_prb; - int nof_bits; - int nof_symbols; - int nof_ports; - int nof_regs; - int nof_cce; - - pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES]; - pdcch_search_mode_t current_search_mode; + lte_cell_t cell; + uint32_t e_bits; + uint32_t nof_regs; + uint32_t nof_cce; + uint32_t max_bits; regs_t *regs; /* buffers */ - cf_t *ce[MAX_PORTS_CTRL]; - cf_t *pdcch_symbols[MAX_PORTS_CTRL]; - cf_t *pdcch_x[MAX_PORTS_CTRL]; + cf_t *ce[MAX_PORTS]; + cf_t *pdcch_symbols[MAX_PORTS]; + cf_t *pdcch_x[MAX_PORTS]; cf_t *pdcch_d; char *pdcch_e; float *pdcch_llr; @@ -91,36 +76,48 @@ typedef struct LIBLTE_API { crc_t crc; } pdcch_t; -LIBLTE_API int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, - int cell_id, lte_cp_t cp); +LIBLTE_API int pdcch_init(pdcch_t *q, + regs_t *regs, + lte_cell_t cell); + LIBLTE_API void pdcch_free(pdcch_t *q); -/* Encoding functions */ -LIBLTE_API int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS_CTRL], - int nsubframe); -/* Decoding functions */ +/* Encoding function */ +LIBLTE_API int pdcch_encode(pdcch_t *q, + dci_msg_t *msg, + dci_location_t location, + uint16_t rnti, + cf_t *sf_symbols[MAX_PORTS], + uint32_t nsubframe, + uint32_t cfi); -/* There are two ways to decode the DCI messages: - * a) call pdcch_set_search_si/ue/ra and then call pdcch_decode() - * b) call pdcch_extract_llr() and then call pdcch_decode_si/ue/ra - */ +/* Decoding functions: Extract the LLRs and save them in the pdcch_t object */ +LIBLTE_API int pdcch_extract_llr(pdcch_t *q, + cf_t *sf_symbols, + cf_t *ce[MAX_PORTS], + dci_location_t location, + uint32_t nsubframe, + uint32_t cfi); -LIBLTE_API int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], - dci_t *dci, int nsubframe, float ebno); -LIBLTE_API int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], - float *llr, int nsubframe, float ebno); +/* Decoding functions: Try to decode a DCI message after calling pdcch_extract_llr */ +LIBLTE_API int pdcch_decode_msg(pdcch_t *q, + dci_msg_t *msg, + dci_format_t format, + uint16_t *crc_rem); -LIBLTE_API void pdcch_init_search_si(pdcch_t *q); -LIBLTE_API void pdcch_set_search_si(pdcch_t *q); -LIBLTE_API int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci); +/* Function for generation of UE-specific search space DCI locations */ +LIBLTE_API uint32_t pdcch_ue_locations(pdcch_t *q, + dci_location_t *locations, + uint32_t max_locations, + uint32_t nsubframe, + uint32_t cfi, + uint16_t rnti); -LIBLTE_API void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti); -LIBLTE_API void pdcch_set_search_ue(pdcch_t *q); -LIBLTE_API int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe); - -LIBLTE_API void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti); -LIBLTE_API void pdcch_set_search_ra(pdcch_t *q); -LIBLTE_API int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci); +/* Function for generation of common search space DCI locations */ +LIBLTE_API uint32_t pdcch_common_locations(pdcch_t *q, + dci_location_t *locations, + uint32_t max_locations, + uint32_t cfi); #endif diff --git a/lte/phy/include/liblte/phy/phch/pdsch.h b/lte/phy/include/liblte/phy/phch/pdsch.h index 207a5bf7a..44717689b 100644 --- a/lte/phy/include/liblte/phy/phch/pdsch.h +++ b/lte/phy/include/liblte/phy/phch/pdsch.h @@ -43,49 +43,95 @@ #include "liblte/phy/phch/dci.h" #include "liblte/phy/phch/regs.h" -#define TDEC_ITERATIONS 1 +#define TDEC_ITERATIONS 6 typedef _Complex float cf_t; +typedef struct LIBLTE_API { + ra_mcs_t mcs; + ra_prb_t prb_alloc; + lte_cell_t cell; + + uint32_t max_cb; + uint32_t w_buff_size; + float **pdsch_w_buff_f; + char **pdsch_w_buff_c; + + struct cb_segm { + uint32_t F; + uint32_t C; + uint32_t K1; + uint32_t K2; + uint32_t C1; + uint32_t C2; + } cb_segm; + +} pdsch_harq_t; + /* PDSCH object */ typedef struct LIBLTE_API { - int cell_id; - lte_cp_t cp; - int nof_prb; - int nof_ports; - int max_symbols; - unsigned short rnti; + lte_cell_t cell; + + uint32_t max_symbols; + bool rnti_is_set; + uint16_t rnti; + + /* buffers */ + // void buffers are shared for tx and rx + cf_t *ce[MAX_PORTS]; + cf_t *pdsch_symbols[MAX_PORTS]; + cf_t *pdsch_x[MAX_PORTS]; + cf_t *pdsch_d; + char *cb_in; + void *cb_out; + void *pdsch_e; - /* buffers */ - cf_t *ce[MAX_PORTS]; - cf_t *pdsch_symbols[MAX_PORTS]; - cf_t *pdsch_x[MAX_PORTS]; - cf_t *pdsch_d; - char *pdsch_e_bits; - char *cb_in_b; - char *cb_out_b; - float *pdsch_llr; - float *pdsch_rm_f; - - /* tx & rx objects */ - modem_table_t mod[4]; - demod_soft_t demod; - sequence_t seq_pdsch[NSUBFRAMES_X_FRAME]; - tcod_t encoder; - tdec_t decoder; - rm_turbo_t rm_turbo; - crc_t crc_tb; - crc_t crc_cb; + /* tx & rx objects */ + modem_table_t mod[4]; + demod_soft_t demod; + sequence_t seq_pdsch[NSUBFRAMES_X_FRAME]; + tcod_t encoder; + tdec_t decoder; + crc_t crc_tb; + crc_t crc_cb; }pdsch_t; -LIBLTE_API int pdsch_init(pdsch_t *q, unsigned short user_rnti, int nof_prb, - int nof_ports, int cell_id, lte_cp_t cp); +LIBLTE_API int pdsch_init(pdsch_t *q, + lte_cell_t cell); + LIBLTE_API void pdsch_free(pdsch_t *q); -LIBLTE_API int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], - int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc); -LIBLTE_API int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], - char *data, int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc); +LIBLTE_API int pdsch_set_rnti(pdsch_t *q, + uint16_t rnti); +LIBLTE_API int pdsch_harq_init(pdsch_harq_t *p, + pdsch_t *pdsch); + +LIBLTE_API int pdsch_harq_setup(pdsch_harq_t *p, + ra_mcs_t mcs, + ra_prb_t *prb_alloc); + +LIBLTE_API void pdsch_harq_free(pdsch_harq_t *p); + +LIBLTE_API int pdsch_encode(pdsch_t *q, + char *data, + cf_t *sf_symbols[MAX_PORTS], + uint32_t nsubframe, + pdsch_harq_t *harq_process, + uint32_t rv_idx); + +LIBLTE_API int pdsch_decode(pdsch_t *q, + cf_t *sf_symbols, + cf_t *ce[MAX_PORTS], + char *data, + uint32_t nsubframe, + pdsch_harq_t *harq_process, + uint32_t rv_idx); + +LIBLTE_API int pdsch_get(pdsch_t *q, + cf_t *sf_symbols, + cf_t *pdsch_symbols, + ra_prb_t *prb_alloc, + uint32_t subframe); #endif diff --git a/lte/phy/include/liblte/phy/phch/phich.h b/lte/phy/include/liblte/phy/phch/phich.h index d01b10fc7..dbe68dfea 100644 --- a/lte/phy/include/liblte/phy/phch/phich.h +++ b/lte/phy/include/liblte/phy/phch/phich.h @@ -55,17 +55,15 @@ typedef _Complex float cf_t; /* phich object */ typedef struct LIBLTE_API { - lte_cp_t cp; - int nof_prb; - int nof_tx_ports; - + lte_cell_t cell; + /* handler to REGs resource mapper */ regs_t *regs; /* buffers */ - cf_t ce[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; - cf_t phich_symbols[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; - cf_t phich_x[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; + cf_t ce[MAX_PORTS][PHICH_MAX_NSYMB]; + cf_t phich_symbols[MAX_PORTS][PHICH_MAX_NSYMB]; + cf_t phich_x[MAX_PORTS][PHICH_MAX_NSYMB]; cf_t phich_d[PHICH_MAX_NSYMB]; cf_t phich_d0[PHICH_MAX_NSYMB]; cf_t phich_z[PHICH_NBITS]; @@ -80,18 +78,31 @@ typedef struct LIBLTE_API { }phich_t; -LIBLTE_API int phich_init(phich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp); +LIBLTE_API int phich_init(phich_t *q, + regs_t *regs, + lte_cell_t cell); + LIBLTE_API void phich_free(phich_t *q); -LIBLTE_API int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], - int ngroup, int nseq, int nsubframe, char *ack, int *distance); -LIBLTE_API int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, - cf_t *slot_symbols[MAX_PORTS_CTRL]); +LIBLTE_API int phich_decode(phich_t *q, + cf_t *slot_symbols, + cf_t *ce[MAX_PORTS], + uint32_t ngroup, + uint32_t nseq, + uint32_t nsubframe, + char *ack, + uint32_t *distance); -LIBLTE_API void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS_CTRL]); -LIBLTE_API int phich_ngroups(phich_t *q); -LIBLTE_API bool phich_exists(int nframe, int nslot); -LIBLTE_API int phich_put(regs_t *h, cf_t *phich, cf_t *slot_data); -LIBLTE_API int phich_get(regs_t *h, cf_t *phich, cf_t *slot_data); +LIBLTE_API int phich_encode(phich_t *q, + char ack, + uint32_t ngroup, + uint32_t nseq, + uint32_t nsubframe, + cf_t *slot_symbols[MAX_PORTS]); + +LIBLTE_API void phich_reset(phich_t *q, + cf_t *slot_symbols[MAX_PORTS]); + +LIBLTE_API uint32_t phich_ngroups(phich_t *q); #endif // PHICH_ diff --git a/lte/phy/include/liblte/phy/phch/prach.h b/lte/phy/include/liblte/phy/phch/prach.h index b50e78b0d..4bdd08778 100644 --- a/lte/phy/include/liblte/phy/phch/prach.h +++ b/lte/phy/include/liblte/phy/phch/prach.h @@ -46,7 +46,7 @@ typedef _Complex float cf_t; * Based on 3GPP TS 36.211 version 10.7.0 Release 10. */ -typedef struct LIBLTE_API{ +typedef struct LIBLTE_API { // Parameters from higher layers (extracted from SIB2) uint32_t f; // preamble format uint32_t rsi; // rootSequenceIndex diff --git a/lte/phy/include/liblte/phy/phch/ra.h b/lte/phy/include/liblte/phy/phch/ra.h index 4e94f277a..0d519c031 100644 --- a/lte/phy/include/liblte/phy/phch/ra.h +++ b/lte/phy/include/liblte/phy/phch/ra.h @@ -37,17 +37,9 @@ * allocation. */ -typedef enum LIBLTE_API { - MOD_NULL = 0, BPSK = 1, QPSK = 2, QAM16 = 3, QAM64 = 4 -} ra_mod_t; - typedef struct LIBLTE_API { - ra_mod_t mod; // By default, mod = MOD_NULL and the mcs_idx value is taken by the packing functions - // otherwise mod + tbs values are used to generate the mcs_idx automatically. - uint8_t tbs_idx; - uint8_t mcs_idx; - int tbs;// If tbs<=0, the tbs_idx value is taken by the packing functions to generate the DCI - // message. Otherwise the tbs_idx corresponding to the lower nearest TBS is taken. + lte_mod_t mod; + uint32_t tbs; } ra_mcs_t; typedef enum LIBLTE_API { @@ -60,13 +52,14 @@ typedef struct LIBLTE_API { typedef struct LIBLTE_API { uint32_t vrb_bitmask; - uint8_t rbg_subset;bool shift; + uint32_t rbg_subset; + bool shift; } ra_type1_t; typedef struct LIBLTE_API { uint32_t riv; // if L_crb==0, DCI message packer will take this value directly - uint16_t L_crb; - uint16_t RB_start; + uint32_t L_crb; + uint32_t RB_start; enum { nprb1a_2 = 0, nprb1a_3 = 1 } n_prb1a; @@ -79,20 +72,34 @@ typedef struct LIBLTE_API { } ra_type2_t; typedef struct LIBLTE_API { - unsigned short rnti; + uint32_t prb_idx[MAX_PRB]; + uint32_t nof_prb; +} ra_prb_slot_t; + +typedef struct LIBLTE_API { + ra_prb_slot_t slot[2]; + uint32_t lstart; + uint32_t re_sf[NSUBFRAMES_X_FRAME]; +} ra_prb_t; + +typedef struct LIBLTE_API { + uint16_t rnti; ra_type_t alloc_type; union { ra_type0_t type0_alloc; ra_type1_t type1_alloc; ra_type2_t type2_alloc; }; + ra_prb_t prb_alloc; + uint32_t mcs_idx; ra_mcs_t mcs; - uint8_t harq_process; - uint8_t rv_idx;bool ndi; + uint32_t harq_process; + uint32_t rv_idx; + bool ndi; } ra_pdsch_t; typedef struct LIBLTE_API { - /* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh. + /* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mhz. * hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz. */ enum { @@ -103,64 +110,85 @@ typedef struct LIBLTE_API { hop_type_2 = 3 } freq_hop_fl; + ra_prb_t prb_alloc; + ra_type2_t type2_alloc; + uint32_t mcs_idx; ra_mcs_t mcs; - uint8_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation + uint32_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation // than before (Format0 message, see also 8.6.1 in 36.2313). - bool ndi;bool cqi_request; + bool ndi; + bool cqi_request; } ra_pusch_t; -typedef struct LIBLTE_API { - uint8_t prb_idx[110]; - int nof_prb; -} ra_prb_slot_t; +LIBLTE_API void ra_prb_fprint(FILE *f, + ra_prb_slot_t *prb); -typedef struct LIBLTE_API { - ra_prb_slot_t slot[2]; - int lstart; - int re_sf[NSUBFRAMES_X_FRAME]; -} ra_prb_t; +LIBLTE_API int ra_prb_get_dl(ra_prb_t *prb, + ra_pdsch_t *ra, + uint32_t nof_prb); -LIBLTE_API void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb); +LIBLTE_API int ra_prb_get_ul(ra_prb_slot_t *prb, + ra_pusch_t *ra, + uint32_t nof_prb); -LIBLTE_API int ra_prb_get_dl(ra_prb_t *prb, ra_pdsch_t *ra, int nof_prb); -LIBLTE_API int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb); -LIBLTE_API void ra_prb_get_re(ra_prb_t *prb_dist, int nof_prb, int nof_ports, - int nof_ctrl_symbols, lte_cp_t cp); +LIBLTE_API void ra_prb_get_re_dl(ra_prb_t *prb_dist, + uint32_t nof_prb, + uint32_t nof_ports, + uint32_t nof_ctrl_symbols, + lte_cp_t cp); -LIBLTE_API int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb); -LIBLTE_API int ra_nprb_ul(ra_pusch_t *ra, int nof_prb); -LIBLTE_API int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb, - int nof_ports, int nof_ctrl_symbols, lte_cp_t cp); +LIBLTE_API uint32_t ra_nprb_dl(ra_pdsch_t *ra, + uint32_t nof_prb); -LIBLTE_API uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs); -LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs); -LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs); -LIBLTE_API int ra_tbs_from_idx_format1c(uint8_t tbs_idx); -LIBLTE_API int ra_tbs_to_table_idx_format1c(int tbs); -LIBLTE_API int ra_tbs_from_idx(uint8_t tbs_idx, int n_prb); -LIBLTE_API int ra_tbs_to_table_idx(int tbs, int n_prb); +LIBLTE_API uint32_t ra_nprb_ul(ra_pusch_t *ra, + uint32_t nof_prb); -LIBLTE_API uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs); -LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs); -LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs); +LIBLTE_API int ra_mcs_from_idx_dl(uint32_t mcs_idx, + uint32_t nof_prb, + ra_mcs_t *mcs); -LIBLTE_API char *ra_mod_string(ra_mod_t mod); +LIBLTE_API int ra_mcs_from_idx_ul(uint32_t mcs_idx, + uint32_t nof_prb, + ra_mcs_t *mcs); -LIBLTE_API int ra_type0_P(int nof_prb); +LIBLTE_API int ra_tbs_from_idx_format1c(uint32_t tbs_idx); -LIBLTE_API uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb); -LIBLTE_API void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, - int nof_prb, int nof_vrb); -LIBLTE_API int ra_type2_n_vrb_dl(int nof_prb, bool ngap_is_1); -LIBLTE_API int ra_type2_n_rb_step(int nof_prb); -LIBLTE_API int ra_type2_ngap(int nof_prb, bool ngap_is_1); -LIBLTE_API int ra_type1_N_rb(int nof_prb); +LIBLTE_API int ra_tbs_from_idx(uint32_t tbs_idx, + uint32_t n_prb); -LIBLTE_API void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint8_t mcs_idx); -LIBLTE_API void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx); -LIBLTE_API void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb); -LIBLTE_API void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, int nof_prb); +LIBLTE_API int ra_tbs_to_table_idx(uint32_t tbs, + uint32_t n_prb); + +LIBLTE_API uint32_t ra_type0_P(uint32_t nof_prb); + +LIBLTE_API uint32_t ra_type2_to_riv(uint32_t L_crb, + uint32_t RB_start, + uint32_t nof_prb); + +LIBLTE_API void ra_type2_from_riv(uint32_t riv, + uint32_t *L_crb, + uint32_t *RB_start, + uint32_t nof_prb, + uint32_t nof_vrb); + +LIBLTE_API uint32_t ra_type2_n_vrb_dl(uint32_t nof_prb, + bool ngap_is_1); + +LIBLTE_API uint32_t ra_type2_n_rb_step(uint32_t nof_prb); + +LIBLTE_API uint32_t ra_type2_ngap(uint32_t nof_prb, + bool ngap_is_1); + +LIBLTE_API uint32_t ra_type1_N_rb(uint32_t nof_prb); + +LIBLTE_API void ra_pdsch_fprint(FILE *f, + ra_pdsch_t *ra, + uint32_t nof_prb); + +LIBLTE_API void ra_pusch_fprint(FILE *f, + ra_pusch_t *ra, + uint32_t nof_prb); #endif /* RB_ALLOC_H_ */ diff --git a/lte/phy/include/liblte/phy/phch/regs.h b/lte/phy/include/liblte/phy/phch/regs.h index 79d90d615..1b2f470d6 100644 --- a/lte/phy/include/liblte/phy/phch/regs.h +++ b/lte/phy/include/liblte/phy/phch/regs.h @@ -45,57 +45,91 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API { - int k[4]; - int k0; - int l; + uint32_t k[4]; + uint32_t k0; + uint32_t l; bool assigned; }regs_reg_t; typedef struct LIBLTE_API { - int nof_regs; + uint32_t nof_regs; regs_reg_t **regs; }regs_ch_t; typedef struct LIBLTE_API { - int cell_id; - int nof_prb; - int max_ctrl_symbols; - int cfi; - int ngroups_phich; - int nof_ports; - lte_cp_t cp; + lte_cell_t cell; + uint32_t max_ctrl_symbols; + uint32_t cfi; + bool cfi_initiated; + uint32_t ngroups_phich; + phich_resources_t phich_res; phich_length_t phich_len; + regs_ch_t pcfich; regs_ch_t *phich; // there are several phich regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for the three possible CFI value */ - int nof_regs; + + uint32_t nof_regs; regs_reg_t *regs; }regs_t; -LIBLTE_API int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports, - phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp); +LIBLTE_API int regs_init(regs_t *h, + phich_resources_t phich_res, + phich_length_t phich_len, + lte_cell_t cell); + LIBLTE_API void regs_free(regs_t *h); -LIBLTE_API int regs_set_cfi(regs_t *h, int nof_ctrl_symbols); +LIBLTE_API int regs_set_cfi(regs_t *h, + uint32_t nof_ctrl_symbols); -LIBLTE_API int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb); -LIBLTE_API int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb); -LIBLTE_API int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb); -LIBLTE_API int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb); -LIBLTE_API int regs_pcfich_nregs(regs_t *h); -LIBLTE_API int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols); -LIBLTE_API int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t pcfich_symbols[REGS_PCFICH_NSYM]); +LIBLTE_API uint32_t regs_pcfich_nregs(regs_t *h); +LIBLTE_API int regs_pcfich_put(regs_t *h, + cf_t pcfich_symbols[REGS_PCFICH_NSYM], + cf_t *slot_symbols); -LIBLTE_API int regs_phich_nregs(regs_t *h); -LIBLTE_API int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, cf_t *slot_symbols); -LIBLTE_API int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup); -LIBLTE_API int regs_phich_ngroups(regs_t *h); -LIBLTE_API int regs_phich_reset(regs_t *h, cf_t *slot_symbols); +LIBLTE_API int regs_pcfich_get(regs_t *h, + cf_t *slot_symbols, + cf_t pcfich_symbols[REGS_PCFICH_NSYM]); -LIBLTE_API int regs_pdcch_nregs(regs_t *h); -LIBLTE_API int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols); -LIBLTE_API int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols); +LIBLTE_API uint32_t regs_phich_nregs(regs_t *h); +LIBLTE_API int regs_phich_add(regs_t *h, + cf_t phich_symbols[REGS_PHICH_NSYM], + uint32_t ngroup, + cf_t *slot_symbols); + +LIBLTE_API int regs_phich_get(regs_t *h, + cf_t *slot_symbols, + cf_t phich_symbols[REGS_PHICH_NSYM], + uint32_t ngroup); + +LIBLTE_API uint32_t regs_phich_ngroups(regs_t *h); +LIBLTE_API int regs_phich_reset(regs_t *h, + cf_t *slot_symbols); + +LIBLTE_API int regs_pdcch_nregs(regs_t *h, uint32_t cfi); +LIBLTE_API int regs_pdcch_put(regs_t *h, + cf_t *pdcch_symbols, + cf_t *slot_symbols); + +LIBLTE_API int regs_pdcch_put_offset(regs_t *h, + cf_t *pdcch_symbols, + cf_t *slot_symbols, + uint32_t start_reg, + uint32_t nof_regs); + +LIBLTE_API int regs_pdcch_get(regs_t *h, + cf_t *slot_symbols, + cf_t *pdcch_symbols); + +LIBLTE_API int regs_pdcch_get_offset(regs_t *h, + cf_t *slot_symbols, + cf_t *pdcch_symbols, + uint32_t start_reg, + uint32_t nof_regs); #endif // REGS_H_ + + diff --git a/lte/phy/include/liblte/phy/phch/ue_dl.h b/lte/phy/include/liblte/phy/phch/ue_dl.h new file mode 100644 index 000000000..22ecd718d --- /dev/null +++ b/lte/phy/include/liblte/phy/phch/ue_dl.h @@ -0,0 +1,96 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE 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 Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 UEDL_H +#define UEDL_H + +/******************************************************* + * + * This module is a frontend to all the data and control channels processing + * modules. + ********************************************************/ + + + +#include "liblte/phy/ch_estimation/chest.h" +#include "liblte/phy/common/fft.h" +#include "liblte/phy/common/phy_common.h" + +#include "liblte/phy/phch/dci.h" +#include "liblte/phy/phch/pbch.h" +#include "liblte/phy/phch/pcfich.h" +#include "liblte/phy/phch/pdcch.h" +#include "liblte/phy/phch/pdsch.h" +#include "liblte/phy/phch/phich.h" +#include "liblte/phy/phch/ra.h" +#include "liblte/phy/phch/regs.h" + +#include "liblte/phy/utils/vector.h" +#include "liblte/phy/utils/debug.h" + +#include "liblte/config.h" + +#define NOF_HARQ_PROCESSES 8 + +typedef struct LIBLTE_API { + pcfich_t pcfich; + pdcch_t pdcch; + pdsch_t pdsch; + pdsch_harq_t harq_process[NOF_HARQ_PROCESSES]; + regs_t regs; + lte_fft_t fft; + chest_t chest; + + lte_cell_t cell; + + cf_t *sf_symbols; + cf_t *ce[MAX_PORTS]; + + uint64_t pkt_errors; + uint64_t pkts_total; + uint64_t nof_trials; + + uint16_t user_rnti; +}ue_dl_t; + +/* This function shall be called just after the initial synchronization */ +LIBLTE_API int ue_dl_init(ue_dl_t *q, + lte_cell_t cell, + phich_resources_t phich_resources, + phich_length_t phich_length, + uint16_t user_rnti); + +LIBLTE_API void ue_dl_free(ue_dl_t *q); + +LIBLTE_API int ue_dl_receive(ue_dl_t *q, + cf_t *sf_buffer, + char *data, + uint32_t sf_idx, + uint32_t sfn, + uint16_t rnti); + +#endif \ No newline at end of file diff --git a/lte/phy/include/liblte/phy/phch/ue_sync.h b/lte/phy/include/liblte/phy/phch/ue_sync.h new file mode 100644 index 000000000..dc374e238 --- /dev/null +++ b/lte/phy/include/liblte/phy/phch/ue_sync.h @@ -0,0 +1,171 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE 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 Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 UE_SYNC_ +#define UE_SYNC_ + +#include + +#include "liblte/config.h" +#include "liblte/phy/sync/sync.h" +#include "liblte/phy/sync/cfo.h" +#include "liblte/phy/ch_estimation/chest.h" +#include "liblte/phy/phch/pbch.h" +#include "liblte/phy/common/fft.h" +#include "liblte/phy/agc/agc.h" + +/************************************************************** + * + * This object automatically manages the cell association and + * synchronization procedure. By default, it associates with the + * CELL whose correlation peak to average ratio is the highest. + * + * TODO: Associate with arbitrary CELL ID + * + * The main function is ue_sync_get_buffer(), which returns a pointer + * to the aligned subframe of samples (before FFT). This function + * should be called regularly, returning every 1 ms. It reads from the + * USRP, aligns the samples to the subframe and performs time/freq synch. + * + * The function returns 0 during the cell association procedure, which includes + * PSS/SSS synchronization, MIB decoding from the PBCH and sampling frequency + * adjustment (according to signal bandwidth) and resynchronization. + * + * The function returns 1 when the signal is correctly acquired and the + * returned buffer is aligned with the subframe. + * + * + *************************************************************/ + +typedef enum LIBLTE_API { SF_FIND, SF_TRACK} ue_sync_state_t; + +#define SYNC_PBCH_NOF_PRB 6 +#define SYNC_PBCH_NOF_PORTS 2 + +#define TRACK_MAX_LOST 10 +#define PSS_THRESHOLD 1 + +#define NOF_MIB_DECODES 10 + +#define MEASURE_EXEC_TIME + +typedef struct LIBLTE_API { + sync_t s; + + void *stream; + double (*set_rate_callback)(void*, double); + int (*recv_callback)(void*, void*, uint32_t); + + ue_sync_state_t state; + + cf_t *input_buffer; + cf_t *receive_buffer; + cf_t *sf_symbols; + cf_t *ce[SYNC_PBCH_NOF_PORTS]; + + /* These count half frames (5ms) */ + uint64_t frame_ok_cnt; + uint32_t frame_no_cnt; + uint32_t frame_total_cnt; + + /* this is the system frame number (SFN) */ + uint32_t frame_number; + + lte_cell_t cell; + uint32_t sf_idx; + + cfo_t cfocorr; + float cur_cfo; + + /* Variables for PBCH decoding */ + agc_t agc; + pbch_mib_t mib; + lte_fft_t fft; + chest_t chest; + pbch_t pbch; + bool pbch_initialized; + uint32_t pbch_decoded; + bool pbch_decode_always; + bool pbch_decoder_enabled; + uint32_t pbch_last_trial; + + bool decode_sss_on_track; + + uint32_t peak_idx; + int time_offset; + float mean_time_offset; + #ifdef MEASURE_EXEC_TIME + float mean_exec_time; + #endif +} ue_sync_t; + + +LIBLTE_API int ue_sync_init(ue_sync_t *q, + double (set_rate_callback)(void*, double), + int (recv_callback)(void*, void*, uint32_t), + void *stream_handler); + +LIBLTE_API void ue_sync_free(ue_sync_t *q); + +LIBLTE_API int ue_sync_get_buffer(ue_sync_t *q, + cf_t **sf_symbols); + + +LIBLTE_API void ue_sync_reset(ue_sync_t *q); + +LIBLTE_API void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled); + +LIBLTE_API void ue_sync_pbch_enable(ue_sync_t *q, bool enabled); + +LIBLTE_API void ue_sync_pbch_always(ue_sync_t *q, bool enabled); + +LIBLTE_API void ue_sync_set_threshold(ue_sync_t *q, + float threshold); + +LIBLTE_API ue_sync_state_t ue_sync_get_state(ue_sync_t *q); + +LIBLTE_API uint32_t ue_sync_get_sfidx(ue_sync_t *q); + +LIBLTE_API uint32_t ue_sync_get_peak_idx(ue_sync_t *q); + +LIBLTE_API lte_cell_t ue_sync_get_cell(ue_sync_t *q); + +LIBLTE_API pbch_mib_t ue_sync_get_mib(ue_sync_t *q); + +LIBLTE_API bool ue_sync_is_mib_decoded(ue_sync_t *q); + +LIBLTE_API float ue_sync_get_cfo(ue_sync_t *q); + +LIBLTE_API float ue_sync_get_sfo(ue_sync_t *q); + + + + + + +#endif // SYNC_FRAME_ + diff --git a/lte/phy/include/liblte/phy/phy.h b/lte/phy/include/liblte/phy/phy.h index bf1d67626..3de436895 100644 --- a/lte/phy/include/liblte/phy/phy.h +++ b/lte/phy/include/liblte/phy/phy.h @@ -50,11 +50,14 @@ #include "liblte/phy/common/phy_common.h" #include "liblte/phy/common/fft.h" -#include "liblte/phy/common/sequence.h" - + #include "liblte/phy/ch_estimation/chest.h" #include "liblte/phy/ch_estimation/refsignal.h" +#include "liblte/phy/resampling/interp.h" +#include "liblte/phy/resampling/decim.h" +#include "liblte/phy/resampling/resample_arb.h" + #include "liblte/phy/channel/ch_awgn.h" #include "liblte/phy/fec/viterbi.h" @@ -89,11 +92,11 @@ #include "liblte/phy/phch/pbch.h" #include "liblte/phy/phch/pcfich.h" #include "liblte/phy/phch/phich.h" +#include "liblte/phy/phch/ue_sync.h" +#include "liblte/phy/phch/ue_dl.h" #include "liblte/phy/scrambling/scrambling.h" -#include "liblte/phy/resampling/interp.h" - #include "liblte/phy/sync/pss.h" #include "liblte/phy/sync/sfo.h" #include "liblte/phy/sync/sss.h" diff --git a/lte/phy/include/liblte/phy/resampling/decim.h b/lte/phy/include/liblte/phy/resampling/decim.h new file mode 100644 index 000000000..4d3036784 --- /dev/null +++ b/lte/phy/include/liblte/phy/resampling/decim.h @@ -0,0 +1,39 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE 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 Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 DECIM_H +#define DECIM_H_ + +#include "liblte/config.h" + +typedef _Complex float cf_t; + + +LIBLTE_API void decim_c(cf_t *input, cf_t *output, int M, int len); +LIBLTE_API void decim_f(float *input, float *output, int M, int len); + +#endif // DECIM_H diff --git a/lte/phy/include/liblte/phy/resampling/interp.h b/lte/phy/include/liblte/phy/resampling/interp.h index ef7e87205..c39c83602 100644 --- a/lte/phy/include/liblte/phy/resampling/interp.h +++ b/lte/phy/include/liblte/phy/resampling/interp.h @@ -26,15 +26,73 @@ */ #ifndef INTERP_H -#define INTERP_H_ +#define INTERP_H + +#include #include "liblte/config.h" typedef _Complex float cf_t; +typedef enum LIBLTE_API {LINEAR} interp_type_t; -LIBLTE_API void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end); -LIBLTE_API void interp_linear(cf_t *input, cf_t *output, int M, int len); -LIBLTE_API void interp_linear_f(float *input, float *output, int M, int len); +typedef struct LIBLTE_API { + interp_type_t type; + + float *in_mag; + float *in_arg; + float *in_mag0; + float *in_arg0; + float *in_mag1; + float *in_arg1; + + float *out_mag; + float *out_arg; + float *out_arg2; + int16_t *table_idx; + + cf_t *out_cexp; + cf_t *out_prod; + + cf_t *cexptable; + + uint32_t len; + uint32_t M; + +}interp_t; + +LIBLTE_API int interp_init(interp_t *q, + interp_type_t type, + uint32_t len, + uint32_t M); + +LIBLTE_API void interp_free(interp_t *q); + +LIBLTE_API void interp_run(interp_t *q, + cf_t *input, + cf_t *output); + +LIBLTE_API void interp_run_offset(interp_t *q, + cf_t *input, + cf_t *output, + uint32_t off_st, + uint32_t off_end); + +LIBLTE_API void interp_linear_offset(cf_t *input, + cf_t *output, + uint32_t M, + uint32_t len, + uint32_t off_st, + uint32_t off_end); + +LIBLTE_API void interp_linear_c(cf_t *input, + cf_t *output, + uint32_t M, + uint32_t len); + +LIBLTE_API void interp_linear_f(float *input, + float *output, + uint32_t M, + uint32_t len); #endif // INTERP_H diff --git a/lte/phy/include/liblte/phy/sync/cfo.h b/lte/phy/include/liblte/phy/sync/cfo.h index c2adb9a04..b88683ad1 100644 --- a/lte/phy/include/liblte/phy/sync/cfo.h +++ b/lte/phy/include/liblte/phy/sync/cfo.h @@ -32,6 +32,7 @@ #include #include "liblte/config.h" +#include "liblte/phy/utils/cexptab.h" typedef _Complex float cf_t; @@ -48,10 +49,20 @@ typedef struct LIBLTE_API { cf_t *cur_cexp; }cfo_t; -LIBLTE_API int cfo_init(cfo_t *h, int nsamples); +LIBLTE_API int cfo_init(cfo_t *h, + uint32_t nsamples); + LIBLTE_API void cfo_free(cfo_t *h); -LIBLTE_API void cfo_set_tol(cfo_t *h, float tol); -LIBLTE_API void cfo_correct(cfo_t *h, cf_t *x, float freq); +LIBLTE_API int cfo_realloc(cfo_t *h, + uint32_t samples); + +LIBLTE_API void cfo_set_tol(cfo_t *h, + float tol); + +LIBLTE_API void cfo_correct(cfo_t *h, + cf_t *input, + cf_t *output, + float freq); #endif // CFO_ diff --git a/lte/phy/include/liblte/phy/sync/pss.h b/lte/phy/include/liblte/phy/sync/pss.h index 62ad0cc7a..a27f92f6b 100644 --- a/lte/phy/include/liblte/phy/sync/pss.h +++ b/lte/phy/include/liblte/phy/sync/pss.h @@ -42,8 +42,7 @@ typedef _Complex float cf_t; /* this is only a shortcut */ #define DEFAULT_CORRELATION_TH 10000 #define DEFAULT_NOSYNC_TIMEOUT 5 -#define PSS_LEN_FREQ 129 // FFT-based convolution removes 1 leaving it in 128 -#define PSS_LEN 62 +#define PSS_LEN 62 #define PSS_RE 6*12 @@ -67,45 +66,47 @@ typedef struct LIBLTE_API { conv_fft_cc_t conv_fft; #endif - int frame_size; - int N_id_2; - float current_cfo; - bool cfo_auto; // default true - int nof_nosync_frames; - int nosync_timeout_frames; // default 5 - float correlation_threshold; // default 10000 - int frame_start_idx; - int fb_wp; + uint32_t frame_size; + uint32_t N_id_2; + uint32_t fft_size; - cf_t *pss_signal_freq; + cf_t *pss_signal_freq[3]; // One sequence for each N_id_2 cf_t *tmp_input; float *conv_abs; - cf_t *frame_buffer; cf_t *conv_output; - cf_t *tmp_nco; + }pss_synch_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t; /* Basic functionality */ -LIBLTE_API int pss_synch_init(pss_synch_t *q, int frame_size); +LIBLTE_API int pss_synch_init_fft(pss_synch_t *q, + uint32_t frame_size, + uint32_t fft_size); + +LIBLTE_API int pss_synch_init(pss_synch_t *q, + uint32_t frame_size); + LIBLTE_API void pss_synch_free(pss_synch_t *q); -LIBLTE_API int pss_generate(cf_t *signal, int N_id_2); -LIBLTE_API void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp); -LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2); -LIBLTE_API int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, float *corr_mean_value); -LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv); +LIBLTE_API int pss_generate(cf_t *signal, + uint32_t N_id_2); +LIBLTE_API void pss_put_slot(cf_t *pss_signal, + cf_t *slot, + uint32_t nof_prb, + lte_cp_t cp); -/* Automatic frame management functions (for periodic calling) */ -LIBLTE_API int pss_synch_periodic(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples); -LIBLTE_API void pss_synch_set_timeout(pss_synch_t *q, int nof_frames); -LIBLTE_API void pss_synch_set_threshold(pss_synch_t *q, float threshold); -LIBLTE_API void pss_synch_set_cfo_mode(pss_synch_t *q, bool cfo_auto); -LIBLTE_API float pss_synch_get_cfo(pss_synch_t *q); -LIBLTE_API int pss_synch_get_frame_start_idx(pss_synch_t *q); +LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q, + uint32_t N_id_2); +LIBLTE_API int pss_synch_find_pss(pss_synch_t *q, + cf_t *input, + float *corr_peak_value, + float *corr_mean_value); + +LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q, + cf_t *pss_recv); /* High-level API */ diff --git a/lte/phy/include/liblte/phy/sync/sss.h b/lte/phy/include/liblte/phy/sync/sss.h index 0426e1502..bdc219542 100644 --- a/lte/phy/include/liblte/phy/sync/sss.h +++ b/lte/phy/include/liblte/phy/sync/sss.h @@ -38,26 +38,20 @@ typedef _Complex float cf_t; /* this is only a shortcut */ -/** gives the beginning of the SSS symbol (to be passed to sss_synch_m0m1). - * subframe_sz is the length of the subframe, e.g. 1920 for the 1.9 MHz - * symbol_sz is the OFDM symbol size (including CP), e.g. 137 for the 1.9 MHz - */ -#define SSS_SYMBOL_ST(subframe_sz, symbol_sz) (subframe_sz/2-2*symbol_sz) -#define SSS_POS_SYMBOL 33 -#define SSS_DFT_LEN 128 -#define N_SSS 31 +#define N_SSS 31 #define SSS_LEN 2*N_SSS +#define SSS_MAX_FFT_LEN 2048 + struct sss_tables{ int z1[N_SSS][N_SSS]; int c[2][N_SSS]; int s[N_SSS][N_SSS]; - int N_id_2; }; /* Allocate 32 complex to make it multiple of 32-byte AVX instructions alignment requirement. - * Should use vect_malloc() to make it platform agnostic. + * Should use vec_malloc() to make it platform agnostic. */ struct fc_tables{ cf_t z1[N_SSS+1][N_SSS+1]; @@ -70,34 +64,68 @@ struct fc_tables{ typedef struct LIBLTE_API { dft_plan_t dftp_input; + + uint32_t fft_size; float corr_peak_threshold; - int symbol_sz; - int subframe_sz; - - int N_id_1_table[30][30]; - struct fc_tables fc_tables; + uint32_t symbol_sz; + uint32_t subframe_sz; + uint32_t N_id_2; + + uint32_t N_id_1_table[30][30]; + struct fc_tables fc_tables[3]; // one for each N_id_2 }sss_synch_t; /* Basic functionality */ -LIBLTE_API int sss_synch_init(sss_synch_t *q); +LIBLTE_API int sss_synch_init(sss_synch_t *q, + uint32_t fft_size); + +LIBLTE_API int sss_synch_realloc(sss_synch_t *q, + uint32_t fft_size); + LIBLTE_API void sss_synch_free(sss_synch_t *q); -LIBLTE_API void sss_generate(float *signal0, float *signal5, int cell_id); -LIBLTE_API void sss_put_slot(float *sss, cf_t *symbol, int nof_prb, lte_cp_t cp); -LIBLTE_API int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2); +LIBLTE_API void sss_generate(float *signal0, + float *signal5, + uint32_t cell_id); -LIBLTE_API void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value, - int *m1, float *m1_value); -LIBLTE_API int sss_synch_subframe(int m0, int m1); -LIBLTE_API int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1); +LIBLTE_API void sss_put_slot(float *sss, + cf_t *symbol, + uint32_t nof_prb, + lte_cp_t cp); -LIBLTE_API int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx, int *N_id_1); -LIBLTE_API void sss_synch_set_threshold(sss_synch_t *q, float threshold); -LIBLTE_API void sss_synch_set_symbol_sz(sss_synch_t *q, int symbol_sz); -LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz); +LIBLTE_API int sss_synch_set_N_id_2(sss_synch_t *q, + uint32_t N_id_2); + +LIBLTE_API int sss_synch_m0m1(sss_synch_t *q, + cf_t *input, + uint32_t *m0, + float *m0_value, + uint32_t *m1, + float *m1_value); + +LIBLTE_API uint32_t sss_synch_subframe(uint32_t m0, + uint32_t m1); + +LIBLTE_API int sss_synch_N_id_1(sss_synch_t *q, + uint32_t m0, + uint32_t m1); + +LIBLTE_API int sss_synch_frame(sss_synch_t *q, + cf_t *input, + uint32_t *subframe_idx, + uint32_t *N_id_1); + +LIBLTE_API void sss_synch_set_threshold(sss_synch_t *q, + float threshold); + +LIBLTE_API void sss_synch_set_symbol_sz(sss_synch_t *q, + uint32_t symbol_sz); + +LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, + uint32_t subframe_sz); /* High-level API */ @@ -105,18 +133,18 @@ LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz); typedef struct LIBLTE_API { sss_synch_t obj; struct sss_synch_init { - int N_id_2; + uint32_t N_id_2; } init; cf_t *input; - int in_len; + uint32_t in_len; struct sss_synch_ctrl_in { - int symbol_sz; - int subframe_sz; - int correlation_threshold; + uint32_t symbol_sz; + uint32_t subframe_sz; + uint32_t correlation_threshold; } ctrl_in; struct sss_synch_ctrl_out { - int subframe_idx; - int N_id_1; + uint32_t subframe_idx; + uint32_t N_id_1; } ctrl_out; }sss_synch_hl; diff --git a/lte/phy/include/liblte/phy/sync/sync.h b/lte/phy/include/liblte/phy/sync/sync.h index b1602a117..8dddbc7b5 100644 --- a/lte/phy/include/liblte/phy/sync/sync.h +++ b/lte/phy/include/liblte/phy/sync/sync.h @@ -30,15 +30,19 @@ #define SYNC_ #include +#include #include "liblte/config.h" -#include "pss.h" -#include "sss.h" -#include "sfo.h" +#include "liblte/phy/sync/pss.h" +#include "liblte/phy/sync/sss.h" + +#define FFT_SIZE_MIN 64 +#define FFT_SIZE_MAX 2048 /** * * This object performs time and frequency synchronization using the PSS and SSS signals. + * * The object is designed to work with signals sampled at 1.92 Mhz centered at the carrier frequency. * Thus, downsampling is required if the signal is sampled at higher frequencies. * @@ -50,57 +54,91 @@ enum sync_pss_det { ABSOLUTE, PEAK_MEAN}; typedef struct LIBLTE_API { - pss_synch_t pss[3]; // One for each N_id_2 - sss_synch_t sss[3]; // One for each N_id_2 + pss_synch_t pss_find; + pss_synch_t pss_track; + sss_synch_t sss; enum sync_pss_det pss_mode; - float threshold; - float peak_to_avg; - int force_N_id_2; - int N_id_2; - int N_id_1; - int slot_id; + float find_threshold; + float track_threshold; + float peak_value; + uint32_t N_id_2; + uint32_t N_id_1; + uint32_t slot_id; + uint32_t fft_size; + uint32_t find_frame_size; float cfo; - lte_cp_t cp; bool detect_cp; bool sss_en; + lte_cp_t cp; }sync_t; -LIBLTE_API int sync_init(sync_t *q, int frame_size); +LIBLTE_API int sync_init(sync_t *q, + uint32_t find_frame_size, + uint32_t track_frame_size, + uint32_t fft_size); + LIBLTE_API void sync_free(sync_t *q); -/* Runs the synchronization algorithm. input signal must be sampled at 1.92 MHz and should be frame_size long at least */ -LIBLTE_API int sync_run(sync_t *q, cf_t *input); +LIBLTE_API int sync_realloc(sync_t *q, + uint32_t find_frame_size, + uint32_t track_frame_size, + uint32_t fft_size); + +/* Finds a correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be + subframe_size long at least */ +LIBLTE_API int sync_find(sync_t *q, + cf_t *input, + uint32_t *peak_position); + +/* Tracks the correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be + TRACK_LEN long at least */ +LIBLTE_API int sync_track(sync_t *q, + cf_t *input, + uint32_t offset, + uint32_t *peak_position); /* Sets the threshold for peak comparison */ -LIBLTE_API void sync_set_threshold(sync_t *q, float threshold); +LIBLTE_API void sync_set_threshold(sync_t *q, + float find_threshold, + float track_threshold); + /* Set peak comparison to absolute value */ LIBLTE_API void sync_pss_det_absolute(sync_t *q); + /* Set peak comparison to relative to the mean */ LIBLTE_API void sync_pss_det_peak_to_avg(sync_t *q); -/* Forces the synchronizer to check one N_id_2 PSS sequence only (useful for tracking mode) */ -LIBLTE_API void sync_force_N_id_2(sync_t *q, int force_N_id_2); -/* Forces the synchronizer to skip CP detection (useful for tracking mode) */ -LIBLTE_API void sync_force_cp(sync_t *q, lte_cp_t cp); -/* Enables/Disables SSS detection (useful for tracking mode) */ -LIBLTE_API void sync_sss_en(sync_t *q, bool enabled); - - /* Gets the slot id (0 or 10) */ -LIBLTE_API int sync_get_slot_id(sync_t *q); +LIBLTE_API uint32_t sync_get_slot_id(sync_t *q); + /* Gets the last peak-to-average ratio */ -LIBLTE_API float sync_get_peak_to_avg(sync_t *q); +LIBLTE_API float sync_get_peak_value(sync_t *q); + /* Gets the N_id_2 from the last call to synch_run() */ -LIBLTE_API int sync_get_N_id_2(sync_t *q); +LIBLTE_API uint32_t sync_get_N_id_2(sync_t *q); + /* Gets the N_id_1 from the last call to synch_run() */ -LIBLTE_API int sync_get_N_id_1(sync_t *q); +LIBLTE_API uint32_t sync_get_N_id_1(sync_t *q); + /* Gets the Physical CellId from the last call to synch_run() */ LIBLTE_API int sync_get_cell_id(sync_t *q); + /* Gets the CFO estimation from the last call to synch_run() */ LIBLTE_API float sync_get_cfo(sync_t *q); + /* Gets the CP length estimation from the last call to synch_run() */ LIBLTE_API lte_cp_t sync_get_cp(sync_t *q); +/* Enables/Disables SSS detection */ +LIBLTE_API void sync_sss_en(sync_t *q, + bool enabled); + +LIBLTE_API bool sync_sss_detected(sync_t *q); + +/* Enables/Disables CP detection */ +LIBLTE_API void sync_cp_en(sync_t *q, + bool enabled); + #endif // SYNC_ diff --git a/lte/phy/include/liblte/phy/utils/bit.h b/lte/phy/include/liblte/phy/utils/bit.h index 7256b6d09..acfdbce3c 100644 --- a/lte/phy/include/liblte/phy/utils/bit.h +++ b/lte/phy/include/liblte/phy/utils/bit.h @@ -38,7 +38,7 @@ LIBLTE_API uint32_t bit_unpack(char **bits, int nof_bits); LIBLTE_API void bit_pack(uint32_t value, char **bits, int nof_bits); LIBLTE_API void bit_fprint(FILE *stream, char *bits, int nof_bits); LIBLTE_API unsigned int bit_diff(char *x, char *y, int nbits); -LIBLTE_API int bit_count(unsigned int n); +LIBLTE_API uint32_t bit_count(uint32_t n); #endif // BIT_ diff --git a/lte/phy/include/liblte/phy/utils/cexptab.h b/lte/phy/include/liblte/phy/utils/cexptab.h index 058ea81c4..6922eff32 100644 --- a/lte/phy/include/liblte/phy/utils/cexptab.h +++ b/lte/phy/include/liblte/phy/utils/cexptab.h @@ -30,19 +30,28 @@ #define CEXPTAB_ #include +#include #include "liblte/config.h" typedef _Complex float cf_t; typedef struct LIBLTE_API { - int size; + uint32_t size; cf_t *tab; }cexptab_t; -LIBLTE_API int cexptab_init(cexptab_t *nco, int size); +LIBLTE_API int cexptab_init(cexptab_t *nco, + uint32_t size); + LIBLTE_API void cexptab_free(cexptab_t *nco); -LIBLTE_API void cexptab_gen(cexptab_t *nco, cf_t *x, float freq, int len); -LIBLTE_API void cexptab_gen_direct(cf_t *x, float freq, int len); +LIBLTE_API void cexptab_gen(cexptab_t *nco, + cf_t *x, + float freq, + uint32_t len); + +LIBLTE_API void cexptab_gen_direct(cf_t *x, + float freq, + uint32_t len); #endif // CEXPTAB_ diff --git a/lte/phy/include/liblte/phy/utils/convolution.h b/lte/phy/include/liblte/phy/utils/convolution.h index 99c058f02..ed9404738 100644 --- a/lte/phy/include/liblte/phy/utils/convolution.h +++ b/lte/phy/include/liblte/phy/utils/convolution.h @@ -32,23 +32,36 @@ #include "liblte/config.h" #include "liblte/phy/utils/dft.h" +typedef _Complex float cf_t; + typedef struct LIBLTE_API { - _Complex float *input_fft; - _Complex float *filter_fft; - _Complex float *output_fft; - _Complex float *output_fft2; - int input_len; - int filter_len; - int output_len; + cf_t *input_fft; + cf_t *filter_fft; + cf_t *output_fft; + cf_t *output_fft2; + uint32_t input_len; + uint32_t filter_len; + uint32_t output_len; dft_plan_t input_plan; dft_plan_t filter_plan; dft_plan_t output_plan; }conv_fft_cc_t; -LIBLTE_API int conv_fft_cc_init(conv_fft_cc_t *state, int input_len, int filter_len); -LIBLTE_API void conv_fft_cc_free(conv_fft_cc_t *state); -LIBLTE_API int conv_fft_cc_run(conv_fft_cc_t *state, _Complex float *input, _Complex float *filter, _Complex float *output); +LIBLTE_API int conv_fft_cc_init(conv_fft_cc_t *q, + uint32_t input_len, + uint32_t filter_len); -LIBLTE_API int conv_cc(_Complex float *input, _Complex float *filter, _Complex float *output, int input_len, int filter_len); +LIBLTE_API void conv_fft_cc_free(conv_fft_cc_t *q); + +LIBLTE_API uint32_t conv_fft_cc_run(conv_fft_cc_t *q, + cf_t *input, + cf_t *filter, + cf_t *output); + +LIBLTE_API uint32_t conv_cc(cf_t *input, + cf_t *filter, + cf_t *output, + uint32_t input_len, + uint32_t filter_len); #endif // CONVOLUTION_H_ diff --git a/lte/phy/include/liblte/phy/utils/debug.h b/lte/phy/include/liblte/phy/utils/debug.h index 06b03079c..78bba353a 100644 --- a/lte/phy/include/liblte/phy/utils/debug.h +++ b/lte/phy/include/liblte/phy/utils/debug.h @@ -44,6 +44,7 @@ LIBLTE_API extern int verbose; #define VERBOSE_ISINFO() (verbose>=VERBOSE_INFO) #define VERBOSE_ISDEBUG() (verbose>=VERBOSE_DEBUG) +#define VERBOSE_ISNONE() (verbose==VERBOSE_NONE) #define PRINT_DEBUG verbose=VERBOSE_DEBUG #define PRINT_INFO verbose=VERBOSE_INFO diff --git a/lte/phy/include/liblte/phy/utils/vector.h b/lte/phy/include/liblte/phy/utils/vector.h index 4456f8036..369428fb9 100644 --- a/lte/phy/include/liblte/phy/utils/vector.h +++ b/lte/phy/include/liblte/phy/utils/vector.h @@ -30,51 +30,79 @@ #define VECTOR_ #include +#include #include "liblte/config.h" typedef _Complex float cf_t; /** Return the sum of all the elements */ -LIBLTE_API int vec_acc_ii(int *x, int len); -LIBLTE_API float vec_acc_ff(float *x, int len); -LIBLTE_API cf_t vec_acc_cc(cf_t *x, int len); +LIBLTE_API int vec_acc_ii(int *x, uint32_t len); +LIBLTE_API float vec_acc_ff(float *x, uint32_t len); +LIBLTE_API cf_t vec_acc_cc(cf_t *x, uint32_t len); -LIBLTE_API void *vec_malloc(int size); +LIBLTE_API void *vec_malloc(uint32_t size); + +LIBLTE_API void *vec_realloc(void *ptr, uint32_t old_size, uint32_t new_size); /* print vectors */ -LIBLTE_API void vec_fprint_c(FILE *stream, cf_t *x, int len); -LIBLTE_API void vec_fprint_f(FILE *stream, float *x, int len); -LIBLTE_API void vec_fprint_b(FILE *stream, char *x, int len); -LIBLTE_API void vec_fprint_i(FILE *stream, int *x, int len); +LIBLTE_API void vec_fprint_c(FILE *stream, cf_t *x, uint32_t len); +LIBLTE_API void vec_fprint_f(FILE *stream, float *x, uint32_t len); +LIBLTE_API void vec_fprint_b(FILE *stream, char *x, uint32_t len); +LIBLTE_API void vec_fprint_i(FILE *stream, int *x, uint32_t len); +LIBLTE_API void vec_fprint_hex(FILE *stream, char *x, uint32_t len); + +/* Saves a vector to a file */ +LIBLTE_API void vec_save_file(char *filename, void *buffer, uint32_t len); /* sum two vectors */ -LIBLTE_API void vec_sum_ch(char *z, char *x, char *y, int len); -LIBLTE_API void vec_sum_ccc(cf_t *z, cf_t *x, cf_t *y, int len); +LIBLTE_API void vec_sum_ch(char *x, char *y, char *z, uint32_t len); +LIBLTE_API void vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); + +/* substract two vectors z=x-y */ +LIBLTE_API void vec_sub_fff(float *x, float *y, float *z, uint32_t len); /* scalar product */ -LIBLTE_API void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, int len); -LIBLTE_API void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, int len); +LIBLTE_API void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len); +LIBLTE_API void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len); +LIBLTE_API void vec_sc_prod_fff(float *x, float h, float *z, uint32_t len); + +LIBLTE_API void vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len); + +LIBLTE_API void vec_deinterleave_cf(cf_t *x, float *real, float *imag, uint32_t len); /* vector product (element-wise) */ -LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, int len); -LIBLTE_API void vec_prod_ccc_unalign(cf_t *x, cf_t *y, cf_t *z, int len); +LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); + +/* vector product (element-wise) */ +LIBLTE_API void vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len); + +/* conjugate vector product (element-wise) */ +LIBLTE_API void vec_prod_conj_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); + +/* Dot-product */ +LIBLTE_API cf_t vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len); +LIBLTE_API cf_t vec_dot_prod_conj_ccc(cf_t *x, cf_t *y, uint32_t len); +LIBLTE_API float vec_dot_prod_fff(float *x, float *y, uint32_t len); /* z=x/y vector division (element-wise) */ -LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, int len); +LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); /* conjugate */ -LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, int len); +LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, uint32_t len); /* average vector power */ -LIBLTE_API float vec_avg_power_cf(cf_t *x, int len); +LIBLTE_API float vec_avg_power_cf(cf_t *x, uint32_t len); /* return the index of the maximum value in the vector */ -LIBLTE_API int vec_max_fi(float *x, int len); +LIBLTE_API uint32_t vec_max_fi(float *x, uint32_t len); /* quantify vector of floats and convert to unsigned char */ -LIBLTE_API void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, int len); +LIBLTE_API void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, uint32_t len); /* magnitude of each vector element */ -LIBLTE_API void vec_abs_cf(cf_t *x, float *abs, int len); +LIBLTE_API void vec_abs_cf(cf_t *x, float *abs, uint32_t len); + +/* argument of each vector element */ +LIBLTE_API void vec_arg_cf(cf_t *x, float *arg, uint32_t len); #endif // VECTOR_ diff --git a/lte/phy/lib/CMakeLists.txt b/lte/phy/lib/CMakeLists.txt index ec06db805..bbb80299c 100644 --- a/lte/phy/lib/CMakeLists.txt +++ b/lte/phy/lib/CMakeLists.txt @@ -29,13 +29,13 @@ FIND_PACKAGE(FFTW3F REQUIRED) # TODO: distribute kissfft instead INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS}) IF(${DISABLE_VOLK}) - IF(${DISABLE_VOLK} EQUAL 0) - FIND_PACKAGE(Volk) - ELSE(${DISABLE_VOLK} EQUAL 0) - MESSAGE(STATUS "VOLK library disabled (DISABLE_VOLK=1)") - ENDIF(${DISABLE_VOLK} EQUAL 0) + IF(${DISABLE_VOLK} EQUAL 0) + FIND_PACKAGE(Volk) + ELSE(${DISABLE_VOLK} EQUAL 0) + MESSAGE(STATUS "VOLK library disabled (DISABLE_VOLK=1)") + ENDIF(${DISABLE_VOLK} EQUAL 0) ELSE(${DISABLE_VOLK}) - FIND_PACKAGE(Volk) + FIND_PACKAGE(Volk) ENDIF(${DISABLE_VOLK}) ######################################################################## @@ -44,10 +44,10 @@ ENDIF(${DISABLE_VOLK}) FILE(GLOB modules *) SET(SOURCES_ALL "") FOREACH (_module ${modules}) - IF(IS_DIRECTORY ${_module}) - FILE(GLOB_RECURSE tmp "${_module}/src/*.c") - LIST(APPEND SOURCES_ALL ${tmp}) - ENDIF(IS_DIRECTORY ${_module}) + IF(IS_DIRECTORY ${_module}) + FILE(GLOB_RECURSE tmp "${_module}/src/*.c") + LIST(APPEND SOURCES_ALL ${tmp}) + ENDIF(IS_DIRECTORY ${_module}) ENDFOREACH() ADD_LIBRARY(lte_phy SHARED ${SOURCES_ALL}) @@ -56,12 +56,12 @@ INSTALL(TARGETS lte_phy DESTINATION ${LIBRARY_DIR}) LIBLTE_SET_PIC(lte_phy) IF(VOLK_FOUND) - INCLUDE_DIRECTORIES(${VOLK_INCLUDE_DIRS}) - SET_TARGET_PROPERTIES(lte_phy PROPERTIES COMPILE_DEFINITIONS "${VOLK_DEFINITIONS}") - TARGET_LINK_LIBRARIES(lte_phy ${VOLK_LIBRARIES}) - MESSAGE(STATUS " Compiling with VOLK SIMD library.") + INCLUDE_DIRECTORIES(${VOLK_INCLUDE_DIRS}) + SET_TARGET_PROPERTIES(lte_phy PROPERTIES COMPILE_DEFINITIONS "${VOLK_DEFINITIONS}") + TARGET_LINK_LIBRARIES(lte_phy ${VOLK_LIBRARIES}) + MESSAGE(STATUS " Compiling with VOLK SIMD library.") ELSE(VOLK_FOUND) - MESSAGE(STATUS " VOLK SIMD library NOT found. Using generic implementation.") + MESSAGE(STATUS " VOLK SIMD library NOT found. Using generic implementation.") ENDIF(VOLK_FOUND) @@ -70,10 +70,10 @@ ENDIF(VOLK_FOUND) ######################################################################## FILE(GLOB_RECURSE cmakefiles CMakeLists.txt) FOREACH (_file ${cmakefiles}) - GET_FILENAME_COMPONENT(dir ${_file} PATH) - IF (NOT ${dir} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) - ADD_SUBDIRECTORY(${dir}) - ENDIF () + GET_FILENAME_COMPONENT(dir ${_file} PATH) + IF (NOT ${dir} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + ADD_SUBDIRECTORY(${dir}) + ENDIF () ENDFOREACH() diff --git a/lte/phy/lib/agc/src/agc.c b/lte/phy/lib/agc/src/agc.c new file mode 100644 index 000000000..e377ac1be --- /dev/null +++ b/lte/phy/lib/agc/src/agc.c @@ -0,0 +1,79 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE 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 Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 "liblte/phy/utils/debug.h" + +#include "liblte/phy/agc/agc.h" +#include "liblte/phy/utils/vector.h" +#include "liblte/phy/utils/debug.h" + + +int agc_init (agc_t *q) { + bzero(q, sizeof(agc_t)); + q->bandwidth = AGC_DEFAULT_BW; + q->lock = false; + q->gain = 1.0; + q->y_out = 1.0; + return LIBLTE_SUCCESS; +} + +void agc_free(agc_t *q) { + bzero(q, sizeof(agc_t)); +} + +void agc_set_bandwidth(agc_t *q, float bandwidth) { + q->bandwidth = bandwidth; +} + +float agc_get_rssi(agc_t *q) { + return 1.0/q->gain; +} + +void agc_lock(agc_t *q, bool enable) { + q->lock = enable; +} + +void agc_push(agc_t *q, cf_t *input, cf_t *output, uint32_t len) { + + // Apply current gain to input signal + vec_sc_prod_cfc(input, q->gain, output, len); + + // compute output energy estimate + float y = sqrtf(crealf(vec_dot_prod_conj_ccc(output, output, len))/len); + + q->y_out = (1-q->bandwidth) * q->y_out + q->bandwidth * y; + if (!q->lock) { + q->gain *= expf(-0.5*q->bandwidth*logf(q->y_out)); + } +} diff --git a/lte/phy/lib/ch_estimation/src/chest.c b/lte/phy/lib/ch_estimation/src/chest.c index a953153d9..843266d7f 100644 --- a/lte/phy/lib/ch_estimation/src/chest.c +++ b/lte/phy/lib/ch_estimation/src/chest.c @@ -29,24 +29,36 @@ #include #include #include -#include #include #include "liblte/phy/ch_estimation/chest.h" -#include "liblte/phy/resampling/interp.h" #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" #define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz) #define SF_SZ(q) (2 * SLOT_SZ(q)) -void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { +//#define VOLK_INTERP + +void chest_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { chest_ref_fprint(q, stream, nslot, port_id); chest_recvsig_fprint(q, stream, nslot, port_id); chest_ce_fprint(q, stream, nslot, port_id); } -void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { +/* Sets the number of ports to estimate. nof_ports must be smaler than nof_ports + * used during the call to chest_init(). + */ +int chest_set_nof_ports(chest_t *q, uint32_t nof_ports) { + if (nof_ports < q->nof_ports) { + q->nof_ports = nof_ports; + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; + } +} + +void chest_ref_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { int i; fprintf(stream, "refs%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { @@ -56,7 +68,7 @@ void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { fprintf(stream, "];\n"); } -void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { +void chest_recvsig_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { int i; fprintf(stream, "recvsig%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { @@ -66,7 +78,7 @@ void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { fprintf(stream, "];\n"); } -void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { +void chest_ce_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { int i; fprintf(stream, "mag%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { @@ -80,143 +92,223 @@ void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { fprintf(stream, "];\n"); } -void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref) { +int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint32_t nref) { int fidx, tidx; cf_t known_ref, channel_ref; + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + input != NULL && + nslot < NSLOTS_X_FRAME && + port_id < q->nof_ports) + { + if (nref < q->refsignal[port_id][nslot].nof_refs) { - fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index - tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index - known_ref = q->refsignal[port_id][nslot].refs[nref].simbol; - channel_ref = input[SAMPLE_IDX(q->nof_prb, tidx, fidx)]; - q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref; + fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index + tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index - DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, SAMPLE_IDX(q->nof_prb, tidx, fidx), - 10*log10f(cabsf(channel_ref/known_ref)), - cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,cargf(channel_ref/known_ref)/M_PI); + known_ref = q->refsignal[port_id][nslot].refs[nref].simbol; + channel_ref = input[tidx * q->nof_re + fidx]; + q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref; - /* FIXME: compare with threshold */ - if (channel_ref != 0) { - q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref; - } else { - q->refsignal[port_id][nslot].ch_est[nref] = 0; + DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, tidx * q->nof_re + fidx, + 10*log10f(cabsf(channel_ref/known_ref)), + cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI, + cargf(channel_ref/known_ref)/M_PI); + + /* FIXME: compare with threshold */ + if (channel_ref != 0) { + q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref; + } else { + q->refsignal[port_id][nslot].ch_est[nref] = 0; + } + ret = LIBLTE_SUCCESS; + } } + return ret; } /* Computes channel estimates for each reference in a slot and port. * Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce */ -void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_id) { - int i, j; +int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32_t port_id) { + uint32_t i, j; cf_t x[2], y[MAX_NSYMB]; - assert(nslot >= 0 && nslot < NSLOTS_X_FRAME); - assert(port_id >= 0 && port_id < q->nof_ports); - assert(q->refsignal[port_id][nslot].nsymbols <= 2); + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + input != NULL && + nslot < NSLOTS_X_FRAME && + port_id < q->nof_ports) + { + if (q->refsignal[port_id][nslot].nsymbols <= 2) { + refsignal_t *r = &q->refsignal[port_id][nslot]; - refsignal_t *r = &q->refsignal[port_id][nslot]; + INFO("Estimating channel slot=%d port=%d using %d reference signals\n", + nslot, port_id, r->nof_refs); - INFO("Estimating channel slot=%d port=%d using %d reference signals\n", - nslot, port_id, r->nof_refs); - - for (i=0;inof_refs;i++) { - chest_ce_ref(q, input, nslot, port_id, i); - } - - /* interpolate the symbols with references - * in the freq domain */ - for (i=0;insymbols;i++) { - interp_linear_offset(&r->ch_est[i * r->nof_refs/2], - &ce[r->symbols_ref[i] * q->nof_prb * RE_X_RB], RE_X_RB/2, - r->nof_refs/2, r->voffset, RE_X_RB/2-r->voffset); - - } - /* now interpolate in the time domain */ - for (i=0;inof_prb * RE_X_RB; i++) { - if (r->nsymbols > 1) { - for (j=0;jnsymbols;j++) { - x[j] = ce[r->symbols_ref[j] * q->nof_prb * RE_X_RB + i]; + for (i=0;inof_refs;i++) { + chest_ce_ref(q, input, nslot, port_id, i); } - interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0], - 2, r->symbols_ref[0], 3); - } else { - for (j=0;jsymbols_ref[0] * q->nof_prb * RE_X_RB + i]; + + /* interpolate the symbols with references + * in the freq domain */ + for (i=0;insymbols;i++) { +#ifdef VOLK_INTERP + interp_run_offset(&q->interp_freq[port_id], + &r->ch_est[i * r->nof_refs/2], &ce[r->symbols_ref[i] * q->nof_re], + r->voffset, RE_X_RB/2-r->voffset); +#else + interp_linear_offset(&r->ch_est[i * r->nof_refs/2], + &ce[r->symbols_ref[i] * q->nof_re], RE_X_RB/2, + r->nof_refs/2, r->voffset, RE_X_RB/2-r->voffset); +#endif } - } - for (j=0;jnof_symbols;j++) { - ce[j * q->nof_prb * RE_X_RB + i] = y[j]; + /* now interpolate in the time domain */ + for (i=0;inof_re; i++) { + if (r->nsymbols > 1) { + for (j=0;jnsymbols;j++) { + x[j] = ce[r->symbols_ref[j] * q->nof_re + i]; + } +#ifdef VOLK_INTERP + interp_run_offset(&q->interp_time[port_id], x, y, + r->symbols_ref[0], 3); +#else + interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0], + 2, r->symbols_ref[0], 3); +#endif + } else { + for (j=0;jsymbols_ref[0] * q->nof_re + i]; + } + } + for (j=0;jnof_symbols;j++) { + ce[j * q->nof_re + i] = y[j]; + } + } + ret = LIBLTE_SUCCESS; } } + return ret; } -/* Computes channel estimates for each reference in a slot. - * Saves the result for the p-th port to the pointer ce[p] + +/* Computes channel estimates for each reference in a subframe and port id. */ -void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot) { - int p; - for (p=0;pnof_ports;p++) { - chest_ce_slot_port(q, input, ce[p], nslot, p); - } -} - -int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports) { - - if (nof_ports > MAX_PORTS) { - fprintf(stderr, "Error: Maximum ports %d\n", MAX_PORTS); - return -1; - } - bzero(q, sizeof(chest_t)); - - q->nof_ports = nof_ports; - q->nof_symbols = CP_NSYMB(cp); - q->cp = cp; - q->nof_prb = nof_prb; - - switch(interp) { - case LINEAR: - q->interp = interp_linear_offset; - } - - INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n", - q->nof_symbols, nof_prb, nof_ports); - - return 0; -} - -int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id) { - if (port < 0 || port > q->nof_ports) { - return -1; - } - if (nslot < 0 || nslot > NSLOTS_X_FRAME) { - return -1; - } - - if (refsignal_init_LTEDL(&q->refsignal[port][nslot], port, nslot, cell_id, q->cp, q->nof_prb)) { - fprintf(stderr, "Error initiating CRS port=%d, slot=%d\n", port, nslot); - return -1; - } - - return 0; -} - -int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id) { - int p; - for (p=0;pnof_ports;p++) { - if (chest_ref_LTEDL_slot_port(q, p, nslot, cell_id)) { - return -1; +int chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id) { + int n, slotsz, ret; + slotsz = q->nof_symbols*q->nof_re; + for (n=0;n<2;n++) { + ret = chest_ce_slot_port(q, &input[n*slotsz], &ce[n*slotsz], 2*sf_idx+n, port_id); + if (ret != LIBLTE_SUCCESS) { + return ret; } } - return 0; + return LIBLTE_SUCCESS; } -int chest_ref_LTEDL(chest_t *q, int cell_id) { - int n; +/* Computes channel estimates for each reference in a slot for all ports. + */ +int chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, uint32_t nslot) { + int p, ret; + for (p=0;pnof_ports;p++) { + ret = chest_ce_slot_port(q, input, ce[p], nslot, p); + if (ret != LIBLTE_SUCCESS) { + return ret; + } + } + return LIBLTE_SUCCESS; +} + +/* Computes channel estimates for each reference in a subframe for all ports. + */ +int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint32_t sf_idx) { + int p, n, slotsz, ret; + slotsz = q->nof_symbols*q->nof_re; + for (p=0;pnof_ports;p++) { + for (n=0;n<2;n++) { + ret = chest_ce_slot_port(q, &input[n*slotsz], &ce[p][n*slotsz], 2*sf_idx+n, p); + if (ret != LIBLTE_SUCCESS) { + return ret; + } + } + } + return LIBLTE_SUCCESS; +} + +int chest_init(chest_t *q, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_ports) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + nof_ports <= MAX_PORTS) + { + bzero(q, sizeof(chest_t)); + + q->nof_ports = nof_ports; + q->nof_symbols = nof_symbols; + q->nof_re = nof_re; + + INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n", + q->nof_symbols, q->nof_re, nof_ports); + + ret = LIBLTE_SUCCESS; + } + return ret; +} + +int chest_init_LTEDL(chest_t *q, lte_cell_t cell) { + int ret; + ret = chest_init(q, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports); + if (ret != LIBLTE_SUCCESS) { + return ret; + } else { + return chest_ref_LTEDL(q, cell); + } +} + +int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + port_id < MAX_PORTS && + nslot < NSLOTS_X_FRAME) + { + ret = refsignal_init_LTEDL(&q->refsignal[port_id][nslot], port_id, nslot, cell); + + if (ret == LIBLTE_SUCCESS) { + if (nslot == 0) { + ret = interp_init(&q->interp_freq[port_id], LINEAR, q->refsignal[port_id][nslot].nof_refs/2, RE_X_RB/2); + if (ret == LIBLTE_SUCCESS) { + ret = interp_init(&q->interp_time[port_id], LINEAR, 2, + q->refsignal[port_id][nslot].symbols_ref[1] - q->refsignal[port_id][nslot].symbols_ref[0]); + } + } + } + } + return ret; +} + +int chest_ref_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) { + int p, ret; + for (p=0;pnof_ports;p++) { + ret = chest_ref_LTEDL_slot_port(q, nslot, p, cell); + if (ret != LIBLTE_SUCCESS) { + return ret; + } + } + return LIBLTE_SUCCESS; +} + +int chest_ref_LTEDL(chest_t *q, lte_cell_t cell) { + int n, ret; for (n=0;n NSLOTS_X_FRAME) { - return -1; +int chest_ref_symbols(chest_t *q, uint32_t port_id, uint32_t nslot, uint32_t l[2]) { + + if (q != NULL && + port_id < MAX_PORTS && + nslot < NSLOTS_X_FRAME) + { + memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(uint32_t) * q->refsignal[port_id][nslot].nsymbols); + return q->refsignal[port_id][nslot].nsymbols; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; } - memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(int) * q->refsignal[port_id][nslot].nsymbols); - return q->refsignal[port_id][nslot].nsymbols; } @@ -245,6 +342,8 @@ int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]) { */ int chest_initialize(chest_hl* h) { + lte_cell_t cell; + if (!h->init.nof_symbols) { h->init.nof_symbols = CPNORM_NSYMB; // Normal CP } @@ -252,37 +351,23 @@ int chest_initialize(chest_hl* h) { h->init.nof_prb = 6; } - if (chest_init(&h->obj, LINEAR, (h->init.nof_symbols==CPNORM_NSYMB)?CPNORM:CPEXT, - h->init.nof_prb, h->init.nof_ports)) { + cell.id = h->init.cell_id; + cell.nof_ports = h->init.nof_ports; + cell.nof_prb = h->init.nof_prb; + cell.cp = h->init.nof_symbols == CPNORM_NSYMB ? CPNORM : CPEXT; + + if (chest_init_LTEDL(&h->obj, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } - if (h->init.cell_id != -1) { - if (chest_ref_LTEDL(&h->obj, h->init.cell_id)) { - fprintf(stderr, "Error initializing reference signal\n"); - return -1; - } - } return 0; } -/** This function must be called in an slot basis (0.5ms) for LTE */ +/** This function must be called in an subframe basis (1ms) for LTE */ int chest_work(chest_hl* hl) { - int i; chest_t *q = &hl->obj; - - if (hl->init.cell_id != hl->ctrl_in.cell_id) { - if (chest_ref_LTEDL(q, hl->init.cell_id)) { - fprintf(stderr, "Error initializing reference signal\n"); - return -1; - } - } - - for (i=0;iinit.nof_ports;i++) { - chest_ce_slot_port(q, hl->input, hl->output[i], 1, 0); - hl->out_len[i] = hl->in_len; - } + chest_ce_sf(q, hl->input, hl->output, hl->ctrl_in.sf_idx); return 0; } diff --git a/lte/phy/lib/ch_estimation/src/refsignal.c b/lte/phy/lib/ch_estimation/src/refsignal.c index 3303899a9..0ecdb59c1 100644 --- a/lte/phy/lib/ch_estimation/src/refsignal.c +++ b/lte/phy/lib/ch_estimation/src/refsignal.c @@ -40,7 +40,7 @@ #define idx(x, y) (l*nof_refs_x_symbol+i) -int refsignal_v(int port_id, int ns, int symbol_id) { +int refsignal_v(uint32_t port_id, uint32_t ns, uint32_t symbol_id) { int v=-1; switch(port_id) { case 0: @@ -67,108 +67,121 @@ int refsignal_v(int port_id, int ns, int symbol_id) { return v; } -int refsignal_k(int m, int v, int cell_id) { +uint32_t refsignal_k(uint32_t m, uint32_t v, uint32_t cell_id) { return 6*m+((v+(cell_id%6))%6); } -void refsignal_put(refsignal_t *q, cf_t *slot_symbols) { - int i; - int fidx, tidx; - for (i=0;inof_refs;i++) { - fidx = q->refs[i].freq_idx; // reference frequency index - tidx = q->refs[i].time_idx; // reference time index - slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol; +int refsignal_put(refsignal_t *q, cf_t *slot_symbols) { + uint32_t i; + uint32_t fidx, tidx; + if (q != NULL && + slot_symbols != NULL) + { + for (i=0;inof_refs;i++) { + fidx = q->refs[i].freq_idx; // reference frequency index + tidx = q->refs[i].time_idx; // reference time index + slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol; + } + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; } } /** Initializes refsignal_t object according to 3GPP 36.211 6.10.1 * */ -int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot, - int cell_id, lte_cp_t cp, int nof_prb) { +int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, + lte_cell_t cell) { - unsigned int c_init; - int ns, l, lp[2]; - int N_cp; - int i; - int ret = -1; + uint32_t c_init; + uint32_t ns, l, lp[2]; + uint32_t N_cp; + uint32_t i; + int ret = LIBLTE_ERROR_INVALID_INPUTS; sequence_t seq; int v; - int mp; - int nof_refs_x_symbol, nof_ref_symbols; + uint32_t mp; + uint32_t nof_refs_x_symbol, nof_ref_symbols; - bzero(q, sizeof(refsignal_t)); - bzero(&seq, sizeof(sequence_t)); + if (q != NULL && + port_id < MAX_PORTS && + nslot < NSLOTS_X_FRAME && + lte_cell_isvalid(&cell)) + { + + bzero(q, sizeof(refsignal_t)); + bzero(&seq, sizeof(sequence_t)); - if (CP_ISNORM(cp)) { - N_cp = 1; - } else { - N_cp = 0; - } + if (CP_ISNORM(cell.cp)) { + N_cp = 1; + } else { + N_cp = 0; + } - if (port_id < 0 || port_id > (MAX_PORTS - 1)) { - fprintf(stderr, "Invalid port id %d\n", port_id); - return -1; - } + if (port_id < 2) { + nof_ref_symbols = 2; + lp[0] = 0; + lp[1] = CP_NSYMB(cell.cp) - 3; + } else { + nof_ref_symbols = 1; + lp[0] = 1; + } + nof_refs_x_symbol = 2 * cell.nof_prb; - if (port_id < 2) { - nof_ref_symbols = 2; - lp[0] = 0; - lp[1] = CP_NSYMB(cp) - 3; - } else { - nof_ref_symbols = 1; - lp[0] = 1; - } - nof_refs_x_symbol = 2 * nof_prb; + q->nof_refs = nof_refs_x_symbol * nof_ref_symbols; + q->nsymbols = nof_ref_symbols; + q->voffset = cell.id%6; + q->nof_prb = cell.nof_prb; - q->nof_refs = nof_refs_x_symbol * nof_ref_symbols; - q->nsymbols = nof_ref_symbols; - q->symbols_ref = malloc(sizeof(int) * nof_ref_symbols); - q->voffset = cell_id%6; - q->nof_prb = nof_prb; - if (!q->symbols_ref) { - return -1; - } - - memcpy(q->symbols_ref, lp, sizeof(int) * nof_ref_symbols); - - q->refs = vec_malloc(q->nof_refs * sizeof(ref_t)); - if (!q->refs) { - goto free_and_exit; - } - q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t)); - if (!q->ch_est) { - goto free_and_exit; - } - - ns = nslot; - for (l = 0; l < nof_ref_symbols; l++) { - - c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell_id + 1) - + 2 * cell_id + N_cp; - if (sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init)) { + q->symbols_ref = malloc(sizeof(uint32_t) * nof_ref_symbols); + if (!q->symbols_ref) { + perror("malloc"); goto free_and_exit; } - v = refsignal_v(port_id, ns, lp[l]); + memcpy(q->symbols_ref, lp, sizeof(uint32_t) * nof_ref_symbols); - for (i = 0; i < nof_refs_x_symbol; i++) { - mp = i + MAX_PRB - nof_prb; - - /* generate signal */ - __real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2); - __imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); - - /* mapping to resource elements */ - q->refs[idx(l,i)].freq_idx = refsignal_k(i, v, cell_id); - q->refs[idx(l,i)].time_idx = lp[l]; + q->refs = vec_malloc(q->nof_refs * sizeof(ref_t)); + if (!q->refs) { + goto free_and_exit; + } + q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t)); + if (!q->ch_est) { + goto free_and_exit; } - } - ret = 0; + ns = nslot; + for (l = 0; l < nof_ref_symbols; l++) { + + c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell.id + 1) + + 2 * cell.id + N_cp; + ret = sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init); + if (ret != LIBLTE_SUCCESS) { + goto free_and_exit; + } + + v = refsignal_v(port_id, ns, lp[l]); + + for (i = 0; i < nof_refs_x_symbol; i++) { + mp = i + MAX_PRB - cell.nof_prb; + + /* generate signal */ + __real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2); + __imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); + + /* mapping to resource elements */ + q->refs[idx(l,i)].freq_idx = refsignal_k(i, (uint32_t) v, cell.id); + q->refs[idx(l,i)].time_idx = lp[l]; + } + } + ret = LIBLTE_SUCCESS; + } free_and_exit: - sequence_free(&seq); - if (ret == -1) { + if (ret != LIBLTE_ERROR_INVALID_INPUTS) { + sequence_free(&seq); + } + if (ret == LIBLTE_ERROR) { refsignal_free(q); } return ret; diff --git a/lte/phy/lib/ch_estimation/test/chest_test.c b/lte/phy/lib/ch_estimation/test/chest_test.c index 5f5d6647e..b0328b4ba 100644 --- a/lte/phy/lib/ch_estimation/test/chest_test.c +++ b/lte/phy/lib/ch_estimation/test/chest_test.c @@ -33,19 +33,22 @@ #include "liblte/phy/phy.h" -int cell_id = -1; -int nof_prb = 6; -lte_cp_t cp = CPNORM; +lte_cell_t cell = { + 6, // nof_prb + MAX_PORTS, // nof_ports + 1000, // cell_id + CPNORM // cyclic prefix +}; char *output_matlab = NULL; void usage(char *prog) { printf("Usage: %s [recov]\n", prog); - printf("\t-r nof_prb [Default %d]\n", nof_prb); + printf("\t-r nof_prb [Default %d]\n", cell.nof_prb); printf("\t-e extended cyclic prefix [Default normal]\n"); - printf("\t-c cell_id (-1 tests all). [Default %d]\n", cell_id); + printf("\t-c cell_id (1000 tests all). [Default %d]\n", cell.id); printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None"); printf("\t-v increase verbosity\n"); @@ -56,13 +59,13 @@ void parse_args(int argc, char **argv) { while ((opt = getopt(argc, argv, "recov")) != -1) { switch(opt) { case 'r': - nof_prb = atoi(argv[optind]); + cell.nof_prb = atoi(argv[optind]); break; case 'e': - cp = CPEXT; + cell.cp = CPEXT; break; case 'c': - cell_id = atoi(argv[optind]); + cell.id = atoi(argv[optind]); break; case 'o': output_matlab = argv[optind]; @@ -120,7 +123,7 @@ int main(int argc, char **argv) { int max_cid; FILE *fmatlab = NULL; float mse_mag, mse_phase; - + parse_args(argc,argv); if (output_matlab) { @@ -131,7 +134,7 @@ int main(int argc, char **argv) { } } - num_re = nof_prb * RE_X_RB * CP_NSYMB(cp); + num_re = cell.nof_prb * RE_X_RB * CP_NSYMB(cell.cp); input = malloc(num_re * sizeof(cf_t)); if (!input) { @@ -149,28 +152,25 @@ int main(int argc, char **argv) { goto do_exit; } - if (cell_id == -1) { + if (cell.id == 1000) { cid = 0; max_cid = 504; } else { - cid = cell_id; - max_cid = cell_id; + cid = cell.id; + max_cid = cell.id; } + while(cid <= max_cid) { - if (chest_init(&eq, LINEAR, cp, nof_prb, MAX_PORTS)) { + cell.id = cid; + if (chest_init_LTEDL(&eq, cell)) { fprintf(stderr, "Error initializing equalizer\n"); goto do_exit; } - if (chest_ref_LTEDL(&eq, cid)) { - fprintf(stderr, "Error initializing reference signal\n"); - goto do_exit; - } - for (n_slot=0;n_slottmp = malloc(symbol_sz * sizeof(cf_t)); + q->tmp = malloc((uint32_t) symbol_sz * sizeof(cf_t)); if (!q->tmp) { perror("malloc"); return -1; @@ -56,15 +56,18 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) { dft_plan_set_norm(&q->fft_plan, true); dft_plan_set_dc(&q->fft_plan, true); - q->symbol_sz = symbol_sz; - q->nof_symbols = CP_NSYMB(cp_type); - q->cp_type = cp_type; + q->symbol_sz = (uint32_t) symbol_sz; + q->nof_symbols = CP_NSYMB(cp); + q->cp = cp; q->nof_re = nof_prb * RE_X_RB; q->nof_guards = ((symbol_sz - q->nof_re) / 2); - DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp_type=%s, nof_re=%d, nof_guards=%d\n", + q->slot_sz = SLOT_LEN(symbol_sz, cp); + + DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp=%s, nof_re=%d, nof_guards=%d\n", dir==FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols, - q->cp_type==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards); - return 0; + q->cp==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards); + + return LIBLTE_SUCCESS; } void lte_fft_free_(lte_fft_t *q) { @@ -75,25 +78,28 @@ void lte_fft_free_(lte_fft_t *q) { bzero(q, sizeof(lte_fft_t)); } -int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) { - return lte_fft_init_(q, cp_type, nof_prb, FORWARD); +int lte_fft_init(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb) { + return lte_fft_init_(q, cp, nof_prb, FORWARD); } void lte_fft_free(lte_fft_t *q) { lte_fft_free_(q); } -int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) { - int i; - if (lte_fft_init_(q, cp_type, nof_prb, BACKWARD)) { - return -1; +int lte_ifft_init(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb) { + uint32_t i; + int ret; + + ret = lte_fft_init_(q, cp, nof_prb, BACKWARD); + + if (ret == LIBLTE_SUCCESS) { + /* set now zeros at CP */ + for (i=0;inof_symbols;i++) { + bzero(q->tmp, q->nof_guards * sizeof(cf_t)); + bzero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards * sizeof(cf_t)); + } } - /* set now zeros at CP */ - for (i=0;inof_symbols;i++) { - bzero(q->tmp, q->nof_guards * sizeof(cf_t)); - bzero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards * sizeof(cf_t)); - } - return 0; + return ret; } void lte_ifft_free(lte_fft_t *q) { @@ -103,10 +109,10 @@ void lte_ifft_free(lte_fft_t *q) { /* Transforms input samples into output OFDM symbols. * Performs FFT on a each symbol and removes CP. */ -void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output) { - int i; +void lte_fft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) { + uint32_t i; for (i=0;inof_symbols;i++) { - input += CP_ISNORM(q->cp_type)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz); + input += CP_ISNORM(q->cp)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz); dft_run_c(&q->fft_plan, input, q->tmp); memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t)); input += q->symbol_sz; @@ -114,13 +120,20 @@ void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output) { } } +void lte_fft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output) { + uint32_t n; + for (n=0;n<2;n++) { + lte_fft_run_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]); + } +} + /* Transforms input OFDM symbols into output samples. * Performs FFT on a each symbol and adds CP. */ -void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output) { - int i, cp_len; +void lte_ifft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) { + uint32_t i, cp_len; for (i=0;inof_symbols;i++) { - cp_len = CP_ISNORM(q->cp_type)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz); + cp_len = CP_ISNORM(q->cp)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz); memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t)); dft_run_c(&q->fft_plan, q->tmp, &output[cp_len]); input += q->nof_re; @@ -130,3 +143,9 @@ void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output) { } } +void lte_ifft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output) { + uint32_t n; + for (n=0;n<2;n++) { + lte_ifft_run_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]); + } +} diff --git a/lte/phy/lib/common/src/phy_common.c b/lte/phy/lib/common/src/phy_common.c index c87f6eecf..223d2e299 100644 --- a/lte/phy/lib/common/src/phy_common.c +++ b/lte/phy/lib/common/src/phy_common.c @@ -50,36 +50,115 @@ const int tc_cb_sizes[NOF_TC_CB_SIZES] = { 40, 48, 56, 64, 72, 80, 88, 96, 104, 4800, 4864, 4928, 4992, 5056, 5120, 5184, 5248, 5312, 5376, 5440, 5504, 5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144 }; +/* Returns true if the structure pointed by cell has valid parameters + */ +bool lte_cell_isvalid(lte_cell_t *cell) { + if (cell->id < 504 && + cell->nof_ports > 0 && + cell->nof_ports < MAX_PORTS+1 && + cell->nof_prb > 5 && + cell->nof_prb < MAX_PRB+1 + ) { + return true; + } else { + return false; + } +} + +bool lte_N_id_2_isvalid(uint32_t N_id_2) { + if (N_id_2 < 3) { + return true; + } else { + return false; + } +} + +bool lte_N_id_1_isvalid(uint32_t N_id_1) { + if (N_id_1 < 169) { + return true; + } else { + return false; + } +} + + /* * Returns Turbo coder interleaver size for Table 5.1.3-3 (36.212) index */ -int lte_cb_size(int index) { - if (index >= 0 && index < NOF_TC_CB_SIZES) { +int lte_cb_size(uint32_t index) { + if (index < NOF_TC_CB_SIZES) { return tc_cb_sizes[index]; } else { - return -1; + return LIBLTE_ERROR; + } +} + +char *lte_mod_string(lte_mod_t mod) { + switch (mod) { + case LTE_BPSK: + return "BPSK"; + case LTE_QPSK: + return "QPSK"; + case LTE_QAM16: + return "QAM16"; + case LTE_QAM64: + return "QAM64"; + default: + return "N/A"; + } +} + +uint32_t lte_mod_bits_x_symbol(lte_mod_t mod) { + switch (mod) { + case LTE_BPSK: + return 1; + case LTE_QPSK: + return 2; + case LTE_QAM16: + return 4; + case LTE_QAM64: + return 6; + default: + return 0; + } +} + +char *lte_cp_string(lte_cp_t cp) { + if (cp == CPNORM) { + return "Normal"; + } else { + return "Extended"; } } /* * Finds index of minimum K>=long_cb in Table 5.1.3-3 of 36.212 */ -int lte_find_cb_index(int long_cb) { +int lte_find_cb_index(uint32_t long_cb) { int j = 0; while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) { j++; } if (j == NOF_TC_CB_SIZES) { - return -1; + return LIBLTE_ERROR; } else { return j; } } -const int lte_symbol_sz(int nof_prb) { +int lte_sampling_freq_hz(uint32_t nof_prb) { + int n = lte_symbol_sz(nof_prb); + if (n == -1) { + return LIBLTE_ERROR; + } else { + return 15000 * n; + } +} + +int lte_symbol_sz(uint32_t nof_prb) { if (nof_prb<=0) { - return -1; + return LIBLTE_ERROR; } if (nof_prb<=6) { return 128; @@ -94,10 +173,22 @@ const int lte_symbol_sz(int nof_prb) { } else if (nof_prb<=100) { return 2048; } - return -1; + return LIBLTE_ERROR; } -int lte_voffset(int symbol_id, int cell_id, int nof_ports) { +bool lte_symbol_sz_isvalid(uint32_t symbol_sz) { + if (symbol_sz == 128 || + symbol_sz == 256 || + symbol_sz == 512 || + symbol_sz == 1024 || + symbol_sz == 2048) { + return true; + } else { + return false; + } +} + +uint32_t lte_voffset(uint32_t symbol_id, uint32_t cell_id, uint32_t nof_ports) { if (nof_ports == 1 && symbol_id==0) { return (cell_id+3) % 6; } else { @@ -106,7 +197,7 @@ int lte_voffset(int symbol_id, int cell_id, int nof_ports) { } /* Returns the number of available RE per PRB */ -int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) { +uint32_t lte_re_x_prb(uint32_t ns, uint32_t symbol, uint32_t nof_ports, uint32_t nof_symbols) { if (symbol == 0) { if (((ns % 2) == 0) || (ns == 1)) { return RE_X_RB - 4; @@ -138,10 +229,10 @@ int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) { struct lte_band { - int band; + uint32_t band; float fd_low_mhz; - int earfcn_offset; - int earfcn_max; + uint32_t earfcn_offset; + uint32_t earfcn_max; enum band_geographical_area area; }; @@ -186,9 +277,9 @@ int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type) { } else if (!strcmp(mimo_type_str, "multiplex")) { *type = SPATIAL_MULTIPLEX; } else { - return -1; + return LIBLTE_ERROR; } - return 0; + return LIBLTE_SUCCESS; } char *lte_mimotype2str(lte_mimo_type_t type) { @@ -203,12 +294,16 @@ char *lte_mimotype2str(lte_mimo_type_t type) { return NULL; } -float get_fd(struct lte_band *band, int earfcn) { - return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset); +float get_fd(struct lte_band *band, uint32_t earfcn) { + if (earfcn > band->earfcn_offset) { + return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset); + } else { + return 0.0; + } } -float lte_band_fd(int earfcn) { - int i; +float lte_band_fd(uint32_t earfcn) { + uint32_t i; i=0; while(i < NOF_LTE_BANDS && lte_bands[i].earfcn_offset lte_bands[i].earfcn_max) { fprintf(stderr, "Error: Invalid end earfcn %d. Max is %d\n", end_earfcn, lte_bands[i].earfcn_max); - return -1; + return LIBLTE_ERROR; } } if (start_earfcn == -1) { @@ -248,7 +343,7 @@ int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int start_earfcn, int e } else { if (start_earfcn < lte_bands[i].earfcn_offset) { fprintf(stderr, "Error: Invalid start earfcn %d. Min is %d\n", start_earfcn, lte_bands[i].earfcn_offset); - return -1; + return LIBLTE_ERROR; } } nof_earfcn = end_earfcn - start_earfcn; @@ -260,11 +355,11 @@ int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int start_earfcn, int e earfcn[j].id = j + start_earfcn; earfcn[j].fd = get_fd(<e_bands[i], earfcn[j].id); } - return j; + return (int) j; } -int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems) { - int i; +int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, uint32_t max_elems) { + uint32_t i; int n; int nof_fd = 0; for (i=0;i 0;i++) { @@ -274,7 +369,7 @@ int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *ear nof_fd += n; max_elems -= n; } else { - return -1; + return LIBLTE_ERROR; } } } diff --git a/lte/phy/lib/common/src/sequence.c b/lte/phy/lib/common/src/sequence.c index a659b0562..f4325ccd7 100644 --- a/lte/phy/lib/common/src/sequence.c +++ b/lte/phy/lib/common/src/sequence.c @@ -41,17 +41,16 @@ * It follows the 3GPP Release 8 (LTE) 36.211 * Section 7.2 */ -void generate_prs_c(sequence_t *q, unsigned int seed) { +void generate_prs_c(sequence_t *q, uint32_t seed) { int n; - unsigned int *x1; - unsigned int *x2; + uint32_t *x1, *x2; - x1 = calloc(Nc + q->len + 31, sizeof(unsigned int)); + x1 = calloc(Nc + q->len + 31, sizeof(uint32_t)); if (!x1) { perror("calloc"); return; } - x2 = calloc(Nc + q->len + 31, sizeof(unsigned int)); + x2 = calloc(Nc + q->len + 31, sizeof(uint32_t)); if (!x2) { free(x1); perror("calloc"); @@ -76,26 +75,26 @@ void generate_prs_c(sequence_t *q, unsigned int seed) { free(x2); } -int sequence_LTEPRS(sequence_t *q, int len, int seed) { +int sequence_LTEPRS(sequence_t *q, uint32_t len, uint32_t seed) { if (sequence_init(q, len)) { - return -1; + return LIBLTE_ERROR; } q->len = len; generate_prs_c(q, seed); - return 0; + return LIBLTE_SUCCESS; } -int sequence_init(sequence_t *q, int len) { +int sequence_init(sequence_t *q, uint32_t len) { if (q->c && (q->len != len)) { free(q->c); } if (!q->c) { q->c = malloc(len * sizeof(char)); if (!q->c) { - return -1; + return LIBLTE_ERROR; } } - return 0; + return LIBLTE_SUCCESS; } void sequence_free(sequence_t *q) { diff --git a/lte/phy/lib/common/test/fft_test.c b/lte/phy/lib/common/test/fft_test.c index a5e1e3662..8d6f883bf 100644 --- a/lte/phy/lib/common/test/fft_test.c +++ b/lte/phy/lib/common/test/fft_test.c @@ -111,8 +111,8 @@ int main(int argc, char **argv) { input[i] = 100 * ((float) rand()/RAND_MAX + (float) I*rand()/RAND_MAX); } - lte_ifft_run(&ifft, input, outfft); - lte_fft_run(&fft, outfft, outifft); + lte_ifft_run_slot(&ifft, input, outfft); + lte_fft_run_slot(&fft, outfft, outifft); /* compute MSE */ diff --git a/lte/phy/lib/fec/src/convcoder.c b/lte/phy/lib/fec/src/convcoder.c index c20121d5c..2153327ac 100644 --- a/lte/phy/lib/fec/src/convcoder.c +++ b/lte/phy/lib/fec/src/convcoder.c @@ -28,33 +28,41 @@ #include #include +#include #include #include "liblte/phy/fec/convcoder.h" #include "parity.h" -int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length) { - unsigned int sr; - int i,j; - int len = q->tail_biting ? frame_length : (frame_length + q->K - 1); +int convcoder_encode(convcoder_t *q, char *input, char *output, uint32_t frame_length) { + uint32_t sr; + uint32_t i,j; + uint32_t len = q->tail_biting ? frame_length : (frame_length + q->K - 1); - if (q->tail_biting) { - sr = 0; - for (i=frame_length - q->K + 1; i q->K + 1) + { + if (q->tail_biting) { + sr = 0; + for (i=frame_length - q->K + 1; iR;j++) { + output[q->R * i + j] = parity(sr & q->poly[j]); + } + } + return q->R*len; } else { - sr = 0; + return LIBLTE_ERROR_INVALID_INPUTS; } - for (i = 0; i < len; i++) { - int bit = (i < frame_length) ? (input[i] & 1) : 0; - sr = (sr << 1) | bit; - for (j=0;jR;j++) { - output[q->R * i + j] = parity(sr & q->poly[j]); - } - } - - return q->R*len; } diff --git a/lte/phy/lib/fec/src/crc.c b/lte/phy/lib/fec/src/crc.c index 00f74785c..c286c2f63 100644 --- a/lte/phy/lib/fec/src/crc.c +++ b/lte/phy/lib/fec/src/crc.c @@ -114,7 +114,7 @@ int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) { return 0; } -unsigned int crc_checksum(crc_t *h, char *data, int len) { +uint32_t crc_checksum(crc_t *h, char *data, int len) { int i, k, len8, res8, a = 0; unsigned int crc = 0; char *pter; diff --git a/lte/phy/lib/fec/src/parity.c b/lte/phy/lib/fec/src/parity.c index 568994888..b12edfaee 100644 --- a/lte/phy/lib/fec/src/parity.c +++ b/lte/phy/lib/fec/src/parity.c @@ -4,26 +4,27 @@ */ #include +#include -unsigned char Partab[256]; -int P_init; +uint8_t Partab[256]; +uint32_t P_init; /* Create 256-entry odd-parity lookup table * Needed only on non-ia32 machines */ void partab_init(void) { - int i, cnt, ti; + uint32_t i, cnt, ti; - /* Initialize parity lookup table */ - for (i = 0; i < 256; i++) { - cnt = 0; - ti = i; - while (ti) { - if (ti & 1) - cnt++; - ti >>= 1; - } - Partab[i] = cnt & 1; - } - P_init = 1; + /* Initialize parity lookup table */ + for (i = 0; i < 256; i++) { + cnt = 0; + ti = i; + while (ti) { + if (ti & 1) + cnt++; + ti >>= 1; + } + Partab[i] = cnt & 1; + } + P_init = 1; } diff --git a/lte/phy/lib/fec/src/parity.h b/lte/phy/lib/fec/src/parity.h index dfda24f57..5ad4b1b5c 100644 --- a/lte/phy/lib/fec/src/parity.h +++ b/lte/phy/lib/fec/src/parity.h @@ -10,16 +10,16 @@ /* Determine parity of argument: 1 = odd, 0 = even */ #ifdef __i386__ -static inline int parityb(unsigned char x){ +static inline uint32_t parityb(uint8_t x){ __asm__ __volatile__ ("test %1,%1;setpo %0" : "=qhm" (x) : "qh" (x)); return x; } #else void partab_init(); -static inline int parityb(unsigned char x){ - extern unsigned char Partab[256]; - extern int P_init; +static inline uint32_t parityb(uint8_t x){ + extern uint8_t Partab[256]; + extern uint32_t P_init; if(!P_init){ partab_init(); } @@ -28,7 +28,7 @@ static inline int parityb(unsigned char x){ #endif -static inline int parity(int x){ +static inline uint32_t parity(int x){ /* Fold down to one byte */ x ^= (x >> 16); x ^= (x >> 8); diff --git a/lte/phy/lib/fec/src/rm_conv.c b/lte/phy/lib/fec/src/rm_conv.c index 3b4254c5f..0c10c9a0d 100644 --- a/lte/phy/lib/fec/src/rm_conv.c +++ b/lte/phy/lib/fec/src/rm_conv.c @@ -27,25 +27,27 @@ #include #include +#include + #include "liblte/phy/fec/rm_conv.h" #define NCOLS 32 #define NROWS_MAX NCOLS -unsigned char RM_PERM_CC[NCOLS] = { 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, +uint8_t RM_PERM_CC[NCOLS] = { 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31, 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30 }; -unsigned char RM_PERM_CC_INV[NCOLS] = +uint8_t RM_PERM_CC_INV[NCOLS] = { 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26, 10, 22, 6, 30, 14, 17, 1, 25, 9, 21, 5, 29, 13, 19, 3, 27, 11, 23, 7, 31, 15 }; -int rm_conv_tx(char *input, int in_len, char *output, int out_len) { +int rm_conv_tx(char *input, uint32_t in_len, char *output, uint32_t out_len) { char tmp[3 * NCOLS * NROWS_MAX]; int nrows, ndummy, K_p; int i, j, k, s; - nrows = (int) (in_len / 3 - 1) / NCOLS + 1; + nrows = (uint32_t) (in_len / 3 - 1) / NCOLS + 1; if (nrows > NROWS_MAX) { fprintf(stderr, "Input too large. Max input length is %d\n", 3 * NCOLS * NROWS_MAX); @@ -89,7 +91,7 @@ int rm_conv_tx(char *input, int in_len, char *output, int out_len) { /* Undoes Convolutional Code Rate Matching. * 3GPP TS 36.212 v10.1.0 section 5.1.4.2 */ -int rm_conv_rx(float *input, int in_len, float *output, int out_len) { +int rm_conv_rx(float *input, uint32_t in_len, float *output, uint32_t out_len) { int nrows, ndummy, K_p; int i, j, k; @@ -97,7 +99,7 @@ int rm_conv_rx(float *input, int in_len, float *output, int out_len) { float tmp[3 * NCOLS * NROWS_MAX]; - nrows = (int) (out_len / 3 - 1) / NCOLS + 1; + nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1; if (nrows > NROWS_MAX) { fprintf(stderr, "Output too large. Max output length is %d\n", 3 * NCOLS * NROWS_MAX); diff --git a/lte/phy/lib/fec/src/rm_turbo.c b/lte/phy/lib/fec/src/rm_turbo.c index f678a7685..ae52d9593 100644 --- a/lte/phy/lib/fec/src/rm_turbo.c +++ b/lte/phy/lib/fec/src/rm_turbo.c @@ -30,50 +30,43 @@ #include #include #include +#include #include "liblte/phy/fec/rm_turbo.h" #define NCOLS 32 #define NROWS_MAX NCOLS -unsigned char RM_PERM_TC[NCOLS] = { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, +uint8_t RM_PERM_TC[NCOLS] = { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 }; -int rm_turbo_init(rm_turbo_t *q, int buffer_len) { - q->buffer_len = buffer_len; - q->buffer = malloc(buffer_len * sizeof(float)); - if (!q->buffer) { - perror("malloc"); - return -1; - } - return 0; -} - -void rm_turbo_free(rm_turbo_t *q) { - if (q->buffer) { - free(q->buffer); - } -} /* Turbo Code Rate Matching. * 3GPP TS 36.212 v10.1.0 section 5.1.4.1 * + * If rv_idx==0, the circular buffer w_buff is filled with all redundancy versions and + * the corresponding version of length out_len is saved in the output buffer. + * Otherwise, the corresponding version is directly obtained from w_buff and saved into output. + * + * Note that calling this function with rv_idx!=0 without having called it first with rv_idx=0 + * will produce unwanted results. + * * TODO: Soft buffer size limitation according to UE category */ -int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, - int out_len, int rv_idx) { +int rm_turbo_tx(char *w_buff, uint32_t w_buff_len, char *input, uint32_t in_len, char *output, + uint32_t out_len, uint32_t rv_idx) { - char *tmp = (char*) q->buffer; - int nrows, ndummy, K_p; + int ndummy, kidx; + int nrows, K_p; - int i, j, k, s, kidx, N_cb, k0; + int i, j, k, s, N_cb, k0; - nrows = (int) (in_len / 3 - 1) / NCOLS + 1; + nrows = (uint32_t) (in_len / 3 - 1) / NCOLS + 1; K_p = nrows * NCOLS; - if (3 * K_p > q->buffer_len) { + if (3 * K_p > w_buff_len) { fprintf(stderr, "Input too large. Max input length including dummy bits is %d (3x%dx32, in_len %d)\n", - q->buffer_len, nrows, in_len); + w_buff_len, nrows, in_len); return -1; } @@ -82,47 +75,49 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, ndummy = 0; } - /* Sub-block interleaver (5.1.4.1.1) and bit collection */ - k = 0; - for (s = 0; s < 2; s++) { - for (j = 0; j < NCOLS; j++) { - for (i = 0; i < nrows; i++) { - if (s == 0) { - kidx = k % K_p; - } else { - kidx = K_p + 2 * (k % K_p); + if (rv_idx == 0) { + /* Sub-block interleaver (5.1.4.1.1) and bit collection */ + k = 0; + for (s = 0; s < 2; s++) { + for (j = 0; j < NCOLS; j++) { + for (i = 0; i < nrows; i++) { + if (s == 0) { + kidx = k % K_p; + } else { + kidx = K_p + 2 * (k % K_p); + } + if (i * NCOLS + RM_PERM_TC[j] < ndummy) { + w_buff[kidx] = TX_NULL; + } else { + w_buff[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s]; + } + k++; } - if (i * NCOLS + RM_PERM_TC[j] < ndummy) { - tmp[kidx] = TX_NULL; - } else { - tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s]; - } - k++; + } + } + + // d_k^(2) goes through special permutation + for (k = 0; k < K_p; k++) { + kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p; + if ((kidx - ndummy) < 0) { + w_buff[K_p + 2 * k + 1] = TX_NULL; + } else { + w_buff[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2]; } } } - // d_k^(2) goes through special permutation - for (k = 0; k < K_p; k++) { - kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p; - if ((kidx - ndummy) < 0) { - tmp[K_p + 2 * k + 1] = TX_NULL; - } else { - tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2]; - } - } - /* Bit selection and transmission 5.1.4.1.2 */ - N_cb = 3 * K_p; // TODO: Soft buffer size limitation + N_cb = 3 * K_p; // TODO: Soft buffer size limitation k0 = nrows - * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2); + * (2 * (uint32_t) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2); k = 0; j = 0; while (k < out_len) { - if (tmp[(k0 + j) % N_cb] != TX_NULL) { - output[k] = tmp[(k0 + j) % N_cb]; + if (w_buff[(k0 + j) % N_cb] != TX_NULL) { + output[k] = w_buff[(k0 + j) % N_cb]; k++; } j++; @@ -132,23 +127,24 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, /* Undoes Turbo Code Rate Matching. * 3GPP TS 36.212 v10.1.0 section 5.1.4.1 + * + * If rv_idx==0, the w_buff circular buffer is initialized. Every subsequent call + * with rv_idx!=0 will soft-combine the LLRs from input with w_buff */ -int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, - int out_len, int rv_idx) { +int rm_turbo_rx(float *w_buff, uint32_t w_buff_len, float *input, uint32_t in_len, float *output, + uint32_t out_len, uint32_t rv_idx) { int nrows, ndummy, K_p, k0, N_cb, jp, kidx; int i, j, k; int d_i, d_j; bool isdummy; - float *tmp = (float*) q->buffer; - - nrows = (int) (out_len / 3 - 1) / NCOLS + 1; + nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1; K_p = nrows * NCOLS; - if (3 * K_p > q->buffer_len) { + if (3 * K_p > w_buff_len) { fprintf(stderr, "Input too large. Max output length including dummy bits is %d (3x%dx32, in_len %d)\n", - q->buffer_len, nrows, out_len); + w_buff_len, nrows, out_len); return -1; } @@ -157,14 +153,16 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, ndummy = 0; } - for (i = 0; i < 3 * K_p; i++) { - tmp[i] = RX_NULL; + if (rv_idx == 0) { + for (i = 0; i < 3 * K_p; i++) { + w_buff[i] = RX_NULL; + } } /* Undo bit collection. Account for dummy bits */ - N_cb = 3 * K_p; // TODO: Soft buffer size limitation + N_cb = 3 * K_p; // TODO: Soft buffer size limitation k0 = nrows - * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2); + * (2 * (uint32_t) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2); k = 0; j = 0; @@ -185,7 +183,7 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, isdummy = true; } } else { - int jpp = (jp - K_p - 1) / 2; + uint32_t jpp = (jp - K_p - 1) / 2; kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p; if ((kidx - ndummy) < 0) { isdummy = true; @@ -195,10 +193,10 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, } if (!isdummy) { - if (tmp[jp] == RX_NULL) { - tmp[jp] = input[k]; + if (w_buff[jp] == RX_NULL) { + w_buff[jp] = input[k]; } else if (input[k] != RX_NULL) { - tmp[jp] += input[k]; /* soft combine LLRs */ + w_buff[jp] += input[k]; /* soft combine LLRs */ } k++; } @@ -213,15 +211,14 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, if (j != 2) { kidx = K_p * j + (j + 1) * (RM_PERM_TC[d_j] * nrows + d_i); } else { - k = (i + ndummy - 1) % K_p; if (k < 0) k += K_p; kidx = (k / NCOLS + nrows * RM_PERM_TC[k % NCOLS]) % K_p; kidx = 2 * kidx + K_p + 1; } - if (tmp[kidx] != RX_NULL) { - output[i * 3 + j] = tmp[kidx]; + if (w_buff[kidx] != RX_NULL) { + output[i * 3 + j] = w_buff[kidx]; } else { output[i * 3 + j] = 0; } @@ -233,25 +230,15 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, /** High-level API */ int rm_turbo_initialize(rm_turbo_hl* h) { - return rm_turbo_init(&h->q, 7000); + return 0; } /** This function can be called in a subframe (1ms) basis */ int rm_turbo_work(rm_turbo_hl* hl) { - if (hl->init.direction) { - rm_turbo_tx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.E, - hl->ctrl_in.rv_idx); - hl->out_len = hl->ctrl_in.E; - } else { - rm_turbo_rx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.S, - hl->ctrl_in.rv_idx); - hl->out_len = hl->ctrl_in.S; - } return 0; } int rm_turbo_stop(rm_turbo_hl* hl) { - rm_turbo_free(&hl->q); return 0; } diff --git a/lte/phy/lib/fec/src/tc_interl_lte.c b/lte/phy/lib/fec/src/tc_interl_lte.c index 227d4d9f9..b77c04779 100644 --- a/lte/phy/lib/fec/src/tc_interl_lte.c +++ b/lte/phy/lib/fec/src/tc_interl_lte.c @@ -27,6 +27,7 @@ #include #include +#include #include "liblte/phy/common/phy_common.h" #include "liblte/phy/fec/tc_interl.h" @@ -39,7 +40,7 @@ * ************************************************/ -const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103, +const uint32_t f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103, 15, 9, 17, 9, 21, 101, 21, 57, 23, 13, 27, 11, 27, 85, 29, 33, 15, 17, 33, 103, 19, 19, 37, 19, 21, 21, 115, 193, 21, 133, 81, 45, 23, 243, 151, 155, 25, 51, 47, 91, 29, 29, 247, 29, 89, 91, 157, 55, 31, 17, 35, 227, 65, 19, @@ -52,7 +53,7 @@ const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103, 39, 127, 39, 39, 31, 113, 41, 251, 43, 21, 43, 45, 45, 161, 89, 323, 47, 23, 47, 263 }; -const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84, +const uint32_t f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84, 90, 32, 34, 108, 38, 120, 84, 44, 46, 48, 50, 52, 36, 56, 58, 60, 62, 32, 198, 68, 210, 36, 74, 76, 78, 120, 82, 84, 86, 44, 90, 46, 94, 48, 98, 40, 102, 52, 106, 72, 110, 168, 114, 58, 118, 180, 122, 62, 84, 64, 66, 68, 420, @@ -65,9 +66,9 @@ const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84, 280, 142, 480, 146, 444, 120, 152, 462, 234, 158, 80, 96, 902, 166, 336, 170, 86, 174, 176, 178, 120, 182, 184, 186, 94, 190, 480 }; -int tc_interl_LTE_gen(tc_interl_t *h, int long_cb) { - int cb_table_idx, f1, f2; - unsigned long long i, j; +int tc_interl_LTE_gen(tc_interl_t *h, uint32_t long_cb) { + uint32_t cb_table_idx, f1, f2; + uint64_t i, j; if (long_cb > h->max_long_cb) { fprintf(stderr, "Interleaver initiated for max_long_cb=%d\n", @@ -90,8 +91,8 @@ int tc_interl_LTE_gen(tc_interl_t *h, int long_cb) { h->reverse[0] = 0; for (i = 1; i < long_cb; i++) { j = (f1 * i + f2 * i * i) % (long_cb); - h->forward[i] = j; - h->reverse[j] = i; + h->forward[i] = (uint32_t) j; + h->reverse[j] = (uint32_t) i; } return 0; diff --git a/lte/phy/lib/fec/src/tc_interl_umts.c b/lte/phy/lib/fec/src/tc_interl_umts.c index 5c2e3213d..931749347 100644 --- a/lte/phy/lib/fec/src/tc_interl_umts.c +++ b/lte/phy/lib/fec/src/tc_interl_umts.c @@ -28,13 +28,14 @@ #include #include #include +#include #include "liblte/phy/fec/tc_interl.h" #include "liblte/phy/fec/turbocoder.h" #define TURBO_RATE 3 -int mcd(int x, int y); +uint32_t mcd(uint32_t x, uint32_t y); /************************************************ * @@ -53,14 +54,14 @@ const unsigned char table_v[52] = { 3, 2, 2, 3, 2, 5, 2, 3, 2, 6, 3, 5, 2, 2, 2, 2, 7, 5, 3, 2, 3, 5, 2, 5, 2, 6, 3, 3, 2, 3, 2, 2, 6, 5, 2, 5, 2, 2, 2, 19, 5, 2, 3, 2, 3, 2, 6, 3, 7, 7, 6, 3 }; -int tc_interl_init(tc_interl_t *h, int max_long_cb) { +int tc_interl_init(tc_interl_t *h, uint32_t max_long_cb) { int ret = -1; - h->forward = malloc(sizeof(int) * max_long_cb); + h->forward = malloc(sizeof(uint32_t) * max_long_cb); if (!h->forward) { perror("malloc"); goto clean_exit; } - h->reverse = malloc(sizeof(int) * max_long_cb); + h->reverse = malloc(sizeof(uint32_t) * max_long_cb); if (!h->reverse) { perror("malloc"); goto clean_exit; @@ -83,17 +84,17 @@ void tc_interl_free(tc_interl_t *h) { bzero(h, sizeof(tc_interl_t)); } -int tc_interl_UMTS_gen(tc_interl_t *h, int long_cb) { +int tc_interl_UMTS_gen(tc_interl_t *h, uint32_t long_cb) { - int i, j; - int res, prim, aux; - int kp, k; - int *per, *desper; - unsigned char v; - unsigned short p; - unsigned short s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS]; - unsigned short U[MAX_COLS * MAX_ROWS]; - int M_Rows, M_Cols, M_long; + uint32_t i, j; + uint32_t res, prim, aux; + uint32_t kp, k; + uint32_t *per, *desper; + uint8_t v; + uint16_t p; + uint16_t s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS]; + uint16_t U[MAX_COLS * MAX_ROWS]; + uint32_t M_Rows, M_Cols, M_long; M_long = long_cb; @@ -260,8 +261,8 @@ int tc_interl_UMTS_gen(tc_interl_t *h, int long_cb) { } -int mcd(int x, int y) { - int r = 1; +uint32_t mcd(uint32_t x, uint32_t y) { + uint32_t r = 1; while (r) { r = x % y; diff --git a/lte/phy/lib/fec/src/turbocoder.c b/lte/phy/lib/fec/src/turbocoder.c index 75aebb6e9..7483601d9 100644 --- a/lte/phy/lib/fec/src/turbocoder.c +++ b/lte/phy/lib/fec/src/turbocoder.c @@ -26,12 +26,14 @@ */ -#include "liblte/phy/fec/turbocoder.h" #include +#include + +#include "liblte/phy/fec/turbocoder.h" #define NOF_REGS 3 -int tcod_init(tcod_t *h, int max_long_cb) { +int tcod_init(tcod_t *h, uint32_t max_long_cb) { if (tc_interl_init(&h->interl, max_long_cb)) { return -1; @@ -45,13 +47,13 @@ void tcod_free(tcod_t *h) { h->max_long_cb = 0; } -int tcod_encode(tcod_t *h, char *input, char *output, int long_cb) { +int tcod_encode(tcod_t *h, char *input, char *output, uint32_t long_cb) { char reg1_0, reg1_1, reg1_2, reg2_0, reg2_1, reg2_2; - int i, k = 0, j; + uint32_t i, k = 0, j; char bit; char in, out; - int *per; + uint32_t *per; if (long_cb > h->max_long_cb) { fprintf(stderr, "Turbo coder initiated for max_long_cb=%d\n", diff --git a/lte/phy/lib/fec/src/turbodecoder.c b/lte/phy/lib/fec/src/turbodecoder.c index 2fbb61787..250b078fd 100644 --- a/lte/phy/lib/fec/src/turbodecoder.c +++ b/lte/phy/lib/fec/src/turbodecoder.c @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -38,13 +39,13 @@ * Decoder * ************************************************/ -void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, int long_cb) { +void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, uint32_t long_cb) { llr_t m_b[8], new[8], old[8]; llr_t x, y, xy; int k; - int end = long_cb + RATE; + uint32_t end = long_cb + RATE; llr_t *beta = s->beta; - int i; + uint32_t i; for (i = 0; i < 8; i++) { old[i] = beta[8 * (end) + i]; @@ -84,15 +85,15 @@ void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, int long_cb) { } void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output, - int long_cb) { + uint32_t long_cb) { llr_t m_b[8], new[8], old[8], max1[8], max0[8]; llr_t m1, m0; llr_t x, y, xy; llr_t out; - int k; - int end = long_cb; + uint32_t k; + uint32_t end = long_cb; llr_t *beta = s->beta; - int i; + uint32_t i; old[0] = 0; for (i = 1; i < 8; i++) { @@ -168,8 +169,8 @@ void map_gen_free(map_gen_t *h) { } void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output, - int long_cb) { - int k; + uint32_t long_cb) { + uint32_t k; h->beta[(long_cb + TAIL) * NUMSTATES] = 0; for (k = 1; k < NUMSTATES; k++) @@ -184,10 +185,10 @@ void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output, * TURBO DECODER INTERFACE * ************************************************/ -int tdec_init(tdec_t *h, int max_long_cb) { +int tdec_init(tdec_t *h, uint32_t max_long_cb) { int ret = -1; bzero(h, sizeof(tdec_t)); - int len = max_long_cb + TOTALTAIL; + uint32_t len = max_long_cb + TOTALTAIL; h->max_long_cb = max_long_cb; @@ -256,8 +257,8 @@ void tdec_free(tdec_t *h) { bzero(h, sizeof(tdec_t)); } -void tdec_iteration(tdec_t *h, llr_t *input, int long_cb) { - int i; +void tdec_iteration(tdec_t *h, llr_t *input, uint32_t long_cb) { + uint32_t i; // Prepare systematic and parity bits for MAP DEC #1 for (i = 0; i < long_cb; i++) { @@ -295,7 +296,7 @@ void tdec_iteration(tdec_t *h, llr_t *input, int long_cb) { } -int tdec_reset(tdec_t *h, int long_cb) { +int tdec_reset(tdec_t *h, uint32_t long_cb) { memset(h->w, 0, sizeof(llr_t) * long_cb); if (long_cb > h->max_long_cb) { fprintf(stderr, "TDEC was initialized for max_long_cb=%d\n", @@ -305,16 +306,16 @@ int tdec_reset(tdec_t *h, int long_cb) { return tc_interl_LTE_gen(&h->interleaver, long_cb); } -void tdec_decision(tdec_t *h, char *output, int long_cb) { - int i; +void tdec_decision(tdec_t *h, char *output, uint32_t long_cb) { + uint32_t i; for (i = 0; i < long_cb; i++) { output[i] = (h->llr2[h->interleaver.reverse[i]] > 0) ? 1 : 0; } } -void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations, - int long_cb) { - int iter = 0; +void tdec_run_all(tdec_t *h, llr_t *input, char *output, uint32_t nof_iterations, + uint32_t long_cb) { + uint32_t iter = 0; tdec_reset(h, long_cb); diff --git a/lte/phy/lib/fec/src/viterbi.c b/lte/phy/lib/fec/src/viterbi.c index 4b79ea983..b9fb2b0ec 100644 --- a/lte/phy/lib/fec/src/viterbi.c +++ b/lte/phy/lib/fec/src/viterbi.c @@ -27,6 +27,8 @@ #include #include +#include + #include #include @@ -38,11 +40,11 @@ #define DEB 0 -int decode37(void *o, unsigned char *symbols, char *data, int frame_length) { +int decode37(void *o, uint8_t *symbols, char *data, uint32_t frame_length) { viterbi_t *q = o; - int i; + uint32_t i; - int best_state; + uint32_t best_state; if (frame_length > q->framebits) { fprintf(stderr, "Initialized decoder for max frame length %d bits\n", @@ -73,7 +75,7 @@ int decode37(void *o, unsigned char *symbols, char *data, int frame_length) { return q->framebits; } -int decode39(void *o, unsigned char *symbols, char *data, int frame_length) { +int decode39(void *o, uint8_t *symbols, char *data, uint32_t frame_length) { viterbi_t *q = o; if (frame_length > q->framebits) { @@ -113,7 +115,7 @@ void free39(void *o) { delete_viterbi39_port(q->ptr); } -int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { +int init37(viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool tail_biting) { q->K = 7; q->R = 3; q->framebits = framebits; @@ -145,7 +147,7 @@ int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { } } -int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { +int init39(viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool tail_biting) { q->K = 9; q->R = 3; q->framebits = framebits; @@ -171,8 +173,8 @@ int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { } } -int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], - int max_frame_length, bool tail_bitting) { +int viterbi_init(viterbi_t *q, viterbi_type_t type, uint32_t poly[3], + uint32_t max_frame_length, bool tail_bitting) { switch (type) { case viterbi_37: return init37(q, poly, max_frame_length, tail_bitting); @@ -185,12 +187,14 @@ int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], } void viterbi_free(viterbi_t *q) { - q->free(q); + if (q->free) { + q->free(q); + } } /* symbols are real-valued */ -int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length) { - int len; +int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, uint32_t frame_length) { + uint32_t len; if (frame_length > q->framebits) { fprintf(stderr, "Initialized decoder for max frame length %d bits\n", q->framebits); @@ -205,13 +209,13 @@ int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length) return q->decode(q, q->symbols_uc, data, frame_length); } -int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, - int frame_length) { +int viterbi_decode_uc(viterbi_t *q, uint8_t *symbols, char *data, + uint32_t frame_length) { return q->decode(q, symbols, data, frame_length); } int viterbi_initialize(viterbi_hl* h) { - int poly[3]; + uint32_t poly[3]; viterbi_type_t type; if (h->init.rate == 2) { if (h->init.constraint_length == 7) { @@ -241,7 +245,7 @@ int viterbi_initialize(viterbi_hl* h) { poly[0] = h->init.generator_0; poly[1] = h->init.generator_1; poly[2] = h->init.generator_2; - return viterbi_init(&h->obj, type, poly, h->init.frame_length, + return viterbi_init(&h->obj, type, poly, (uint32_t) h->init.frame_length, h->init.tail_bitting ? true : false); } diff --git a/lte/phy/lib/fec/src/viterbi37.h b/lte/phy/lib/fec/src/viterbi37.h index 6afc563e8..7bacca2c8 100644 --- a/lte/phy/lib/fec/src/viterbi37.h +++ b/lte/phy/lib/fec/src/viterbi37.h @@ -27,8 +27,20 @@ #include -void *create_viterbi37_port(int polys[3], int len); -int init_viterbi37_port(void *p, int starting_state); -int chainback_viterbi37_port(void *p, char *data, unsigned int nbits, unsigned int endstate); +void *create_viterbi37_port(uint32_t polys[3], + uint32_t len); + +int init_viterbi37_port(void *p, + uint32_t starting_state); + +int chainback_viterbi37_port(void *p, + char *data, + uint32_t nbits, + uint32_t endstate); + void delete_viterbi37_port(void *p); -int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best_state); + +int update_viterbi37_blk_port(void *p, + unsigned char *syms, + uint32_t nbits, + uint32_t *best_state); diff --git a/lte/phy/lib/fec/src/viterbi37_port.c b/lte/phy/lib/fec/src/viterbi37_port.c index 7eb311324..09dfa4bdc 100644 --- a/lte/phy/lib/fec/src/viterbi37_port.c +++ b/lte/phy/lib/fec/src/viterbi37_port.c @@ -4,6 +4,8 @@ */ #include #include +#include + #include #include "viterbi37.h" #include "parity.h" @@ -30,9 +32,9 @@ struct v37 { }; /* Initialize Viterbi decoder for start of new frame */ -int init_viterbi37_port(void *p, int starting_state) { +int init_viterbi37_port(void *p, uint32_t starting_state) { struct v37 *vp = p; - int i; + uint32_t i; if (p == NULL) return -1; @@ -48,8 +50,8 @@ int init_viterbi37_port(void *p, int starting_state) { return 0; } -void set_viterbi37_polynomial_port(int polys[3]) { - int state; +void set_viterbi37_polynomial_port(uint32_t polys[3]) { + uint32_t state; for (state = 0; state < 32; state++) { Branchtab37[0].c[state] = @@ -62,7 +64,7 @@ void set_viterbi37_polynomial_port(int polys[3]) { } /* Create a new instance of a Viterbi decoder */ -void *create_viterbi37_port(int polys[3], int len) { +void *create_viterbi37_port(uint32_t polys[3], uint32_t len) { struct v37 *vp; set_viterbi37_polynomial_port(polys); @@ -82,8 +84,8 @@ void *create_viterbi37_port(int polys[3], int len) { /* Viterbi chainback */ int chainback_viterbi37_port(void *p, char *data, /* Decoded output data */ - unsigned int nbits, /* Number of data bits */ - unsigned int endstate) { /* Terminal encoder state */ + uint32_t nbits, /* Number of data bits */ + uint32_t endstate) { /* Terminal encoder state */ struct v37 *vp = p; decision_t *d; @@ -145,18 +147,18 @@ unsigned int metric,m0,m1,decision;\ * of symbols! */ -int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best_state) { +int update_viterbi37_blk_port(void *p, uint8_t *syms, uint32_t nbits, uint32_t *best_state) { struct v37 *vp = p; decision_t *d; if (p == NULL) return -1; - int k=0; + uint32_t k=0; d = (decision_t *) vp->dp; while (nbits--) { void *tmp; - unsigned char sym0, sym1, sym2; - int i; + uint8_t sym0, sym1, sym2; + uint32_t i; d->w[0] = d->w[1] = 0; @@ -174,8 +176,8 @@ int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best vp->new_metrics = tmp; } if (best_state) { - int i, bst=0; - unsigned int minmetric=UINT_MAX; + uint32_t i, bst=0; + uint32_t minmetric=UINT_MAX; for (i=0;i<64;i++) { if (vp->old_metrics->w[i] < minmetric) { bst = i; diff --git a/lte/phy/lib/fec/src/viterbi39.h b/lte/phy/lib/fec/src/viterbi39.h index a5830d145..09a3280cf 100644 --- a/lte/phy/lib/fec/src/viterbi39.h +++ b/lte/phy/lib/fec/src/viterbi39.h @@ -27,10 +27,19 @@ #include -void *create_viterbi39_port(int polys[3], int len); -int init_viterbi39_port(void *p, int starting_state); -int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */ - unsigned int nbits, /* Number of data bits */ - unsigned int endstate); +void *create_viterbi39_port(uint32_t polys[3], + uint32_t len); + +int init_viterbi39_port(void *p, + uint32_t starting_state); + +int chainback_viterbi39_port(void *p, + char *data, /* Decoded output data */ + uint32_t nbits, /* Number of data bits */ + uint32_t endstate); + void delete_viterbi39_port(void *p); -int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits); + +int update_viterbi39_blk_port(void *p, + uint8_t *syms, + uint32_t nbits); diff --git a/lte/phy/lib/fec/src/viterbi39_port.c b/lte/phy/lib/fec/src/viterbi39_port.c index fe57297c7..1d87b2c4a 100644 --- a/lte/phy/lib/fec/src/viterbi39_port.c +++ b/lte/phy/lib/fec/src/viterbi39_port.c @@ -4,6 +4,7 @@ */ #include #include +#include #include #include "viterbi39.h" #include "parity.h" @@ -29,9 +30,9 @@ struct v39 { }; /* Initialize Viterbi decoder for start of new frame */ -int init_viterbi39_port(void *p, int starting_state) { +int init_viterbi39_port(void *p, uint32_t starting_state) { struct v39 *vp = p; - int i; + uint32_t i; if (p == NULL) return -1; @@ -45,8 +46,8 @@ int init_viterbi39_port(void *p, int starting_state) { return 0; } -void set_viterbi39_polynomial_port(int polys[3]) { - int state; +void set_viterbi39_polynomial_port(uint32_t polys[3]) { + uint32_t state; for (state = 0; state < 128; state++) { Branchtab39[0].c[state] = @@ -59,7 +60,7 @@ void set_viterbi39_polynomial_port(int polys[3]) { } /* Create a new instance of a Viterbi decoder */ -void *create_viterbi39_port(int polys[3], int len) { +void *create_viterbi39_port(uint32_t polys[3], uint32_t len) { struct v39 *vp; set_viterbi39_polynomial_port(polys); @@ -79,8 +80,8 @@ void *create_viterbi39_port(int polys[3], int len) { /* Viterbi chainback */ int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */ - unsigned int nbits, /* Number of data bits */ - unsigned int endstate) { /* Terminal encoder state */ + uint32_t nbits, /* Number of data bits */ + uint32_t endstate) { /* Terminal encoder state */ struct v39 *vp = p; decision_t *d; @@ -140,7 +141,7 @@ unsigned int metric,m0,m1,decision;\ * of symbols! */ -int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits) { +int update_viterbi39_blk_port(void *p, uint8_t *syms, uint32_t nbits) { struct v39 *vp = p; decision_t *d; @@ -150,8 +151,8 @@ int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits) { d = (decision_t *) vp->dp; while (nbits--) { void *tmp; - unsigned char sym0, sym1, sym2; - int i; + uint8_t sym0, sym1, sym2; + uint32_t i; for (i = 0; i < 8; i++) d->w[i] = 0; diff --git a/lte/phy/lib/fec/test/rm_turbo_test.c b/lte/phy/lib/fec/test/rm_turbo_test.c index aa42ca832..42db72696 100644 --- a/lte/phy/lib/fec/test/rm_turbo_test.c +++ b/lte/phy/lib/fec/test/rm_turbo_test.c @@ -73,10 +73,9 @@ void parse_args(int argc, char **argv) { int main(int argc, char **argv) { int i; - char *bits, *rm_bits; - float *rm_symbols, *unrm_symbols; + char *bits, *rm_bits, *w_buff_c; + float *rm_symbols, *unrm_symbols, *w_buff_f; int nof_errors; - rm_turbo_t rm_turbo; parse_args(argc, argv); @@ -85,6 +84,11 @@ int main(int argc, char **argv) { perror("malloc"); exit(-1); } + w_buff_c = malloc(sizeof(char) * nof_tx_bits * 10); + if (!w_buff_c) { + perror("malloc"); + exit(-1); + } rm_bits = malloc(sizeof(char) * nof_rx_bits); if (!rm_bits) { perror("malloc"); @@ -95,6 +99,11 @@ int main(int argc, char **argv) { perror("malloc"); exit(-1); } + w_buff_f = malloc(sizeof(float) * nof_rx_bits * 10); + if (!w_buff_c) { + perror("malloc"); + exit(-1); + } unrm_symbols = malloc(sizeof(float) * nof_tx_bits); if (!unrm_symbols) { perror("malloc"); @@ -105,15 +114,13 @@ int main(int argc, char **argv) { bits[i] = rand() % 2; } - rm_turbo_init(&rm_turbo, 2000); - - rm_turbo_tx(&rm_turbo, bits, nof_tx_bits, rm_bits, nof_rx_bits, rv_idx); + rm_turbo_tx(w_buff_c, nof_tx_bits * 10, bits, nof_tx_bits, rm_bits, nof_rx_bits, rv_idx); for (i = 0; i < nof_rx_bits; i++) { rm_symbols[i] = (float) rm_bits[i] ? 1 : -1; } - rm_turbo_rx(&rm_turbo, rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits, + rm_turbo_rx(w_buff_f, nof_rx_bits * 10, rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits, rv_idx); nof_errors = 0; @@ -123,8 +130,6 @@ int main(int argc, char **argv) { } } - rm_turbo_free(&rm_turbo); - free(bits); free(rm_bits); free(rm_symbols); diff --git a/lte/phy/lib/fec/test/turbocoder_test.c b/lte/phy/lib/fec/test/turbocoder_test.c index a222b9750..fb0fabc85 100644 --- a/lte/phy/lib/fec/test/turbocoder_test.c +++ b/lte/phy/lib/fec/test/turbocoder_test.c @@ -41,9 +41,9 @@ typedef _Complex float cf_t; -int frame_length = 1000, nof_frames = 100; +uint32_t frame_length = 1000, nof_frames = 100; float ebno_db = 100.0; -unsigned int seed = 0; +uint32_t seed = 0; int K = -1; #define MAX_ITERATIONS 4 @@ -51,9 +51,9 @@ int nof_iterations = MAX_ITERATIONS; int test_known_data = 0; int test_errors = 0; -#define SNR_POINTS 8 -#define SNR_MIN 0.0 -#define SNR_MAX 4.0 +#define SNR_POINTS 8 +#define SNR_MIN 0.0 +#define SNR_MAX 4.0 void usage(char *prog) { printf("Usage: %s [nlesv]\n", prog); @@ -127,16 +127,16 @@ void output_matlab(float ber[MAX_ITERATIONS][SNR_POINTS], int snr_points) { } int main(int argc, char **argv) { - int frame_cnt; + uint32_t frame_cnt; float *llr; unsigned char *llr_c; char *data_tx, *data_rx, *symbols; - int i, j; + uint32_t i, j; float var[SNR_POINTS]; - int snr_points; + uint32_t snr_points; float ber[MAX_ITERATIONS][SNR_POINTS]; - unsigned int errors[100]; - int coded_length; + uint32_t errors[100]; + uint32_t coded_length; struct timeval tdata[3]; float mean_usec; tdec_t tdec; @@ -247,7 +247,7 @@ int main(int argc, char **argv) { /* decoder */ tdec_reset(&tdec, frame_length); - int t; + uint32_t t; if (nof_iterations == -1) { t = MAX_ITERATIONS; } else { diff --git a/lte/phy/lib/modem/src/demod_hard.c b/lte/phy/lib/modem/src/demod_hard.c index 7664821a8..a3b306e0b 100644 --- a/lte/phy/lib/modem/src/demod_hard.c +++ b/lte/phy/lib/modem/src/demod_hard.c @@ -37,14 +37,14 @@ void demod_hard_init(demod_hard_t* q) { bzero((void*) q, sizeof(demod_hard_t)); } -void demod_hard_table_set(demod_hard_t* q, enum modem_std table) { - q->table = table; +void demod_hard_table_set(demod_hard_t* q, lte_mod_t mod) { + q->mod = mod; } -int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, int nsymbols) { +int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, uint32_t nsymbols) { int nbits=-1; - switch(q->table) { + switch(q->mod) { case LTE_BPSK: hard_bpsk_demod(symbols,bits,nsymbols); nbits=nsymbols; diff --git a/lte/phy/lib/modem/src/demod_soft.c b/lte/phy/lib/modem/src/demod_soft.c index 2c874a1af..f79863199 100644 --- a/lte/phy/lib/modem/src/demod_soft.c +++ b/lte/phy/lib/modem/src/demod_soft.c @@ -69,7 +69,7 @@ int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int /* High-Level API */ int demod_soft_initialize(demod_soft_hl* hl) { modem_table_init(&hl->table); - if (modem_table_std(&hl->table,hl->init.std,true)) { + if (modem_table_lte(&hl->table,hl->init.std,true)) { return -1; } demod_soft_init(&hl->obj); diff --git a/lte/phy/lib/modem/src/hard_demod_lte.c b/lte/phy/lib/modem/src/hard_demod_lte.c index 761c72140..f841f3ac7 100644 --- a/lte/phy/lib/modem/src/hard_demod_lte.c +++ b/lte/phy/lib/modem/src/hard_demod_lte.c @@ -33,6 +33,7 @@ #include "liblte/phy/modem/demod_hard.h" #include "hard_demod_lte.h" + /** * @ingroup Hard BPSK demodulator * @@ -46,9 +47,9 @@ * \param N Number of input symbols * \param modulation Modulation type */ -inline void hard_bpsk_demod(const cf_t* in, char* out, int N) +inline void hard_bpsk_demod(const cf_t* in, char* out, uint32_t N) { - int s; + uint32_t s; for (s=0; s 0) { @@ -81,9 +82,9 @@ inline void hard_bpsk_demod(const cf_t* in, char* out, int N) * \param N Number of input symbols * \param modulation Modulation type */ -inline void hard_qpsk_demod(const cf_t* in, char* out, int N) +inline void hard_qpsk_demod(const cf_t* in, char* out, uint32_t N) { - int s; + uint32_t s; for (s=0; s 0) { @@ -115,9 +116,9 @@ inline void hard_qpsk_demod(const cf_t* in, char* out, int N) * \param N Number of input symbols * \param modulation Modulation type */ -inline void hard_qam16_demod(const cf_t* in, char* out, int N) +inline void hard_qam16_demod(const cf_t* in, char* out, uint32_t N) { - int s; + uint32_t s; for (s=0; s 0) { @@ -157,9 +158,9 @@ inline void hard_qam16_demod(const cf_t* in, char* out, int N) * \param N Number of input symbols * \param modulation Modulation type */ -inline void hard_qam64_demod(const cf_t* in, char* out, int N) +inline void hard_qam64_demod(const cf_t* in, char* out, uint32_t N) { - int s; + uint32_t s; for (s=0; snbits_x_symbol) { idx = bit_unpack(&b_ptr,q->nbits_x_symbol); - assert(idx >= 0 && idx < q->nsymbols); - symbols[j] = q->symbol_table[idx]; + if (idx < q->nsymbols) { + symbols[j] = q->symbol_table[idx]; + } else { + return LIBLTE_ERROR; + } j++; } return j; @@ -52,7 +55,7 @@ int mod_modulate(modem_table_t* q, const char *bits, cf_t* symbols, int nbits) { /* High-Level API */ int mod_initialize(mod_hl* hl) { modem_table_init(&hl->obj); - if (modem_table_std(&hl->obj,hl->init.std,false)) { + if (modem_table_lte(&hl->obj,hl->init.std,false)) { return -1; } diff --git a/lte/phy/lib/modem/src/modem_table.c b/lte/phy/lib/modem/src/modem_table.c index 578b6dc98..e62ca981e 100644 --- a/lte/phy/lib/modem/src/modem_table.c +++ b/lte/phy/lib/modem/src/modem_table.c @@ -33,6 +33,7 @@ #include #include +#include "liblte/phy/common/phy_common.h" #include "liblte/phy/modem/modem_table.h" #include "lte_tables.h" @@ -56,27 +57,27 @@ void modem_table_reset(modem_table_t* q) { modem_table_init(q); } -int modem_table_set(modem_table_t* q, cf_t* table, soft_table_t *soft_table, int nsymbols, int nbits_x_symbol) { +int modem_table_set(modem_table_t* q, cf_t* table, soft_table_t *soft_table, uint32_t nsymbols, uint32_t nbits_x_symbol) { if (q->nsymbols) { - return -1; + return LIBLTE_ERROR; } q->nsymbols = nsymbols; if (table_create(q)) { - return -1; + return LIBLTE_ERROR; } memcpy(q->symbol_table,table,q->nsymbols*sizeof(cf_t)); memcpy(&q->soft_table,soft_table,sizeof(soft_table_t)); q->nbits_x_symbol = nbits_x_symbol; - return 0; + return LIBLTE_SUCCESS; } -int modem_table_std(modem_table_t* q, enum modem_std std, bool compute_soft_demod) { - switch(std) { +int modem_table_lte(modem_table_t* q, lte_mod_t modulation, bool compute_soft_demod) { + switch(modulation) { case LTE_BPSK: q->nbits_x_symbol = 1; q->nsymbols = 2; if (table_create(q)) { - return -1; + return LIBLTE_ERROR; } set_BPSKtable(q->symbol_table, &q->soft_table, compute_soft_demod); break; @@ -84,7 +85,7 @@ int modem_table_std(modem_table_t* q, enum modem_std std, bool compute_soft_dem q->nbits_x_symbol = 2; q->nsymbols = 4; if (table_create(q)) { - return -1; + return LIBLTE_ERROR; } set_QPSKtable(q->symbol_table, &q->soft_table, compute_soft_demod); break; @@ -92,7 +93,7 @@ int modem_table_std(modem_table_t* q, enum modem_std std, bool compute_soft_dem q->nbits_x_symbol = 4; q->nsymbols = 16; if (table_create(q)) { - return -1; + return LIBLTE_ERROR; } set_16QAMtable(q->symbol_table, &q->soft_table, compute_soft_demod); break; @@ -100,10 +101,10 @@ int modem_table_std(modem_table_t* q, enum modem_std std, bool compute_soft_dem q->nbits_x_symbol = 6; q->nsymbols = 64; if (table_create(q)) { - return -1; + return LIBLTE_ERROR; } set_64QAMtable(q->symbol_table, &q->soft_table, compute_soft_demod); break; } - return 0; + return LIBLTE_SUCCESS; } diff --git a/lte/phy/lib/modem/src/soft_algs.c b/lte/phy/lib/modem/src/soft_algs.c index 7268d2a31..9ecd2b599 100644 --- a/lte/phy/lib/modem/src/soft_algs.c +++ b/lte/phy/lib/modem/src/soft_algs.c @@ -51,7 +51,7 @@ * \param sigma2 Noise vatiance */ void llr_approx(const _Complex float *in, float *out, int N, int M, int B, - _Complex float *symbols, int (*S)[6][32], float sigma2) { + _Complex float *symbols, uint32_t (*S)[6][32], float sigma2) { int i, s, b; float num, den; float new_num, new_den; @@ -112,7 +112,7 @@ void llr_approx(const _Complex float *in, float *out, int N, int M, int B, * \param sigma2 Noise vatiance */ void llr_exact(const _Complex float *in, float *out, int N, int M, int B, - _Complex float *symbols, int (*S)[6][32], float sigma2) { + _Complex float *symbols, uint32_t (*S)[6][32], float sigma2) { int i, s, b; float num, den; float idiff0, qdiff0, idiff1, qdiff1; diff --git a/lte/phy/lib/modem/src/soft_algs.h b/lte/phy/lib/modem/src/soft_algs.h index b0e065b4d..c683700a6 100644 --- a/lte/phy/lib/modem/src/soft_algs.h +++ b/lte/phy/lib/modem/src/soft_algs.h @@ -26,8 +26,20 @@ */ -void llr_approx(const _Complex float *in, float *out, int N, int M, int B, - _Complex float *symbols, int (*S)[6][32], float sigma2); +void llr_approx(const _Complex float *in, + float *out, + int N, + int M, + int B, + _Complex float *symbols, + uint32_t (*S)[6][32], + float sigma2); -void llr_exact(const _Complex float *in, float *out, int N, int M, int B, - _Complex float *symbols, int (*S)[6][32], float sigma2); +void llr_exact(const _Complex float *in, + float *out, + int N, + int M, + int B, + _Complex float *symbols, + uint32_t (*S)[6][32], + float sigma2); diff --git a/lte/phy/lib/modem/test/modem_test.c b/lte/phy/lib/modem/test/modem_test.c index 6a483c0a6..0fc09a642 100644 --- a/lte/phy/lib/modem/test/modem_test.c +++ b/lte/phy/lib/modem/test/modem_test.c @@ -37,7 +37,7 @@ #include "liblte/phy/phy.h" int num_bits = 1000; -enum modem_std modulation; +lte_mod_t modulation; bool soft_output = false, soft_exact = false; void usage(char *prog) { @@ -101,7 +101,7 @@ int main(int argc, char **argv) { parse_args(argc, argv); /* initialize objects */ - if (modem_table_std(&mod, modulation, soft_output)) { + if (modem_table_lte(&mod, modulation, soft_output)) { fprintf(stderr, "Error initializing modem table\n"); exit(-1); } diff --git a/lte/phy/lib/phch/src/dci.c b/lte/phy/lib/phch/src/dci.c index b2745d607..5d57a28ab 100644 --- a/lte/phy/lib/phch/src/dci.c +++ b/lte/phy/lib/phch/src/dci.c @@ -40,52 +40,86 @@ #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" -int dci_init(dci_t *q, int max_dcis) { - q->msg = calloc(sizeof(dci_msg_t), max_dcis); - if (!q->msg) { - perror("malloc"); - return -1; + +int dci_msg_to_ra_dl(dci_msg_t *msg, uint16_t msg_rnti, uint16_t c_rnti, + lte_cell_t cell, uint32_t cfi, + ra_pdsch_t *ra_dl) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (msg != NULL && + ra_dl != NULL && + lte_cell_isvalid(&cell) && + cfi > 0 && + cfi < 4) + { + ret = LIBLTE_ERROR; + + dci_msg_type_t type; + if (dci_msg_get_type(msg, &type, cell.nof_prb, msg_rnti, c_rnti)) { + fprintf(stderr, "Can't get DCI message type\n"); + return ret; + } + + if (VERBOSE_ISDEBUG()) { + dci_msg_type_fprint(stdout, type); + } + if (type.type == PDSCH_SCHED) { + bzero(ra_dl, sizeof(ra_pdsch_t)); + + if (dci_msg_unpack_pdsch(msg, ra_dl, cell.nof_prb, msg_rnti != SIRNTI)) { + fprintf(stderr, "Can't unpack PDSCH message\n"); + return ret; + } + + if (VERBOSE_ISDEBUG()) { + ra_pdsch_fprint(stdout, ra_dl, cell.nof_prb); + } + + if (ra_prb_get_dl(&ra_dl->prb_alloc, ra_dl, cell.nof_prb)) { + fprintf(stderr, "Error computing resource allocation\n"); + return ret; + } + + ra_prb_get_re_dl(&ra_dl->prb_alloc, cell.nof_prb, cell.nof_ports, cell.nof_prb<10?(cfi+1):cfi, cell.cp); + + ret = LIBLTE_SUCCESS; + } } - q->nof_dcis = 0; - q->max_dcis = max_dcis; - return 0; + return ret; } -void dci_free(dci_t *q) { - if (q->msg) { - free(q->msg); - } -} - -void dci_candidate_fprint(FILE *f, dci_candidate_t *q) { - fprintf(f, "L: %d, nCCE: %d, RNTI: 0x%x, nBits: %d\n", q->L, q->ncce, q->rnti, - q->nof_bits); -} - -int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti) { - if (L >= 0 && L <= 3) { - msg->location.L = (unsigned char) L; +int dci_location_set(dci_location_t *c, uint32_t L, uint32_t nCCE) { + if (L <= 3) { + c->L = L; } else { fprintf(stderr, "Invalid L %d\n", L); - return -1; + return LIBLTE_ERROR; } - if (nCCE >= 0 && nCCE <= 87) { - msg->location.ncce = (unsigned char) nCCE; + if (nCCE <= 87) { + c->ncce = nCCE; } else { fprintf(stderr, "Invalid nCCE %d\n", nCCE); - return -1; + return LIBLTE_ERROR; } - msg->location.rnti = rnti; - return 0; + return LIBLTE_SUCCESS; } -int riv_nbits(int nof_prb) { - return (int) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2)); +bool dci_location_isvalid(dci_location_t *c) { + if (c->L <= 3 && c->ncce <= 87) { + return true; + } else { + return false; + } } -const int ambiguous_sizes[10] = { 12, 14, 16, 20, 24, 26, 32, 40, 44, 56 }; +uint32_t riv_nbits(uint32_t nof_prb) { + return (uint32_t) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2)); +} -bool is_ambiguous_size(int size) { +const uint32_t ambiguous_sizes[10] = { 12, 14, 16, 20, 24, 26, 32, 40, 44, 56 }; + +bool is_ambiguous_size(uint32_t size) { int i; for (i = 0; i < 10; i++) { if (size == ambiguous_sizes[i]) { @@ -98,12 +132,12 @@ bool is_ambiguous_size(int size) { /********************************** * PAYLOAD sizeof functions * ********************************/ -int dci_format0_sizeof_(int nof_prb) { +uint32_t dci_format0_sizeof_(uint32_t nof_prb) { return 1 + 1 + riv_nbits(nof_prb) + 5 + 1 + 2 + 3 + 1; } -int dci_format1A_sizeof(int nof_prb) { - int n; +uint32_t dci_format1A_sizeof(uint32_t nof_prb) { + uint32_t n; n = 1 + 1 + riv_nbits(nof_prb) + 5 + 3 + 1 + 2 + 2; while (n < dci_format0_sizeof_(nof_prb)) { n++; @@ -114,17 +148,17 @@ int dci_format1A_sizeof(int nof_prb) { return n; } -int dci_format0_sizeof(int nof_prb) { - int n = dci_format0_sizeof_(nof_prb); +uint32_t dci_format0_sizeof(uint32_t nof_prb) { + uint32_t n = dci_format0_sizeof_(nof_prb); while (n < dci_format1A_sizeof(nof_prb)) { n++; } return n; } -int dci_format1_sizeof(int nof_prb) { +uint32_t dci_format1_sizeof(uint32_t nof_prb) { - int n = (int) ceilf((float) nof_prb / ra_type0_P(nof_prb)) + 5 + 3 + 1 + 2 + uint32_t n = (uint32_t) ceilf((float) nof_prb / ra_type0_P(nof_prb)) + 5 + 3 + 1 + 2 + 2; if (nof_prb > 10) { n++; @@ -136,17 +170,17 @@ int dci_format1_sizeof(int nof_prb) { return n; } -int dci_format1C_sizeof(int nof_prb) { - int n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true); - int n_step = ra_type2_n_rb_step(nof_prb); - int n = +riv_nbits((int) n_vrb_dl_gap1 / n_step) + 5; +uint32_t dci_format1C_sizeof(uint32_t nof_prb) { + uint32_t n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true); + uint32_t n_step = ra_type2_n_rb_step(nof_prb); + uint32_t n = riv_nbits((uint32_t) n_vrb_dl_gap1 / n_step) + 5; if (nof_prb >= 50) { n++; } return n; } -int dci_format_sizeof(dci_format_t format, int nof_prb) { +uint32_t dci_format_sizeof(dci_format_t format, uint32_t nof_prb) { switch (format) { case Format0: return dci_format0_sizeof(nof_prb); @@ -157,7 +191,7 @@ int dci_format_sizeof(dci_format_t format, int nof_prb) { case Format1C: return dci_format1C_sizeof(nof_prb); default: - return -1; + return LIBLTE_ERROR; } } @@ -170,11 +204,11 @@ int dci_format_sizeof(dci_format_t format, int nof_prb) { * * TODO: TPC and cyclic shift for DM RS not implemented */ -int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) { +int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint32_t nof_prb) { /* pack bits */ char *y = msg->data; - int n_ul_hop; + uint32_t n_ul_hop; *y++ = 0; // format differentiation if (data->freq_hop_fl == hop_disabled) { // frequency hopping @@ -203,28 +237,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) { bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop); /* pack MCS according to 8.6.1 of 36.213 */ - uint32_t mcs; - if (data->cqi_request) { - mcs = 29; - } else { - if (data->rv_idx) { - mcs = 28 + data->rv_idx; - } else { - if (data->mcs.mod == MOD_NULL) { - mcs = data->mcs.mcs_idx; - } else { - if (data->mcs.tbs) { - if (data->mcs.tbs) { - data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, - ra_nprb_ul(data, nof_prb)); - } - } - mcs = ra_mcs_to_table_idx(&data->mcs); - } - } - } - - bit_pack(mcs, &y, 5); + bit_pack(data->mcs_idx, &y, 5); *y++ = data->ndi; @@ -241,33 +254,33 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) { *y++ = data->cqi_request; // Padding with zeros - int n = dci_format0_sizeof(nof_prb); + uint32_t n = dci_format0_sizeof(nof_prb); while (y - msg->data < n) { *y++ = 0; } - msg->location.nof_bits = (y - msg->data); - return 0; + msg->nof_bits = (y - msg->data); + return LIBLTE_SUCCESS; } /* Unpacks DCI format 0 data and store result in msg according * to 36.212 5.3.3.1.1 * * TODO: TPC and cyclic shift for DM RS not implemented */ -int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) { +int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint32_t nof_prb) { /* pack bits */ char *y = msg->data; - int n_ul_hop; + uint32_t n_ul_hop; /* Make sure it's a Format0 message */ - if (msg->location.nof_bits != dci_format_sizeof(Format0, nof_prb)) { + if (msg->nof_bits != dci_format_sizeof(Format0, nof_prb)) { fprintf(stderr, "Invalid message length for format 0\n"); - return -1; + return LIBLTE_ERROR; } if (*y++ != 0) { fprintf(stderr, "Invalid format differentiation field value. This is Format1A\n"); - return -1; + return LIBLTE_ERROR; } if (*y++ == 0) { data->freq_hop_fl = hop_disabled; @@ -286,11 +299,11 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) { uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - n_ul_hop); ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, nof_prb, nof_prb); - bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop); + bit_pack((uint32_t) riv, &y, riv_nbits(nof_prb) - n_ul_hop); data->type2_alloc.riv = riv; /* unpack MCS according to 8.6 of 36.213 */ - uint32_t mcs = bit_unpack(&y, 5); + data->mcs_idx = bit_unpack(&y, 5); data->ndi = *y++ ? true : false; @@ -301,23 +314,19 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) { data->cqi_request = *y++ ? true : false; // 8.6.2 First paragraph - if (mcs <= 28) { - ra_mcs_from_idx_ul(mcs, &data->mcs); - data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, - ra_nprb_ul(data, nof_prb)); + if (data->mcs_idx <= 28) { + ra_mcs_from_idx_ul(data->mcs_idx, ra_nprb_ul(data, nof_prb), &data->mcs); + } else if (data->mcs_idx == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) { + // 8.6.1 and 8.6.2 36.213 second paragraph + data->mcs.mod = LTE_QPSK; + data->mcs.tbs = 0; + } else if (data->mcs_idx >= 29) { + // Else leave TBS and use the previously used PUSCH modulation + data->mcs.tbs = 0; + data->rv_idx = data->mcs_idx - 28; } - // 8.6.1 and 8.6.2 36.213 second paragraph - if (mcs == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) { - data->mcs.mod = QPSK; - } - if (mcs > 29) { - // Else leave MOD_NULL and use the previously used PUSCH modulation - data->mcs.mod = MOD_NULL; - data->rv_idx = mcs - 28; - } - - return 0; + return LIBLTE_SUCCESS; } /* Packs DCI format 1 data to a sequence of bits and store them in msg according @@ -326,7 +335,7 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) { * TODO: TPC commands */ -int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { +int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) { /* pack bits */ char *y = msg->data; @@ -336,36 +345,26 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { } /* Resource allocation: type0 or type 1 */ - int P = ra_type0_P(nof_prb); - int alloc_size = (int) ceilf((float) nof_prb / P); + uint32_t P = ra_type0_P(nof_prb); + uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P); switch (data->alloc_type) { case alloc_type0: - bit_pack(data->type0_alloc.rbg_bitmask, &y, alloc_size); + bit_pack((uint32_t) data->type0_alloc.rbg_bitmask, &y, alloc_size); break; case alloc_type1: - bit_pack(data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P))); + bit_pack((uint32_t) data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P))); *y++ = data->type1_alloc.shift ? 1 : 0; - bit_pack(data->type1_alloc.vrb_bitmask, &y, + bit_pack((uint32_t) data->type1_alloc.vrb_bitmask, &y, alloc_size - (int) ceilf(log2f(P)) - 1); break; default: fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n"); - return -1; + return LIBLTE_ERROR; } - /* pack MCS according to 7.1.7 of 36.213 */ - uint32_t mcs; - if (data->mcs.mod == MOD_NULL) { - mcs = data->mcs.mcs_idx; - } else { - if (data->mcs.tbs) { - data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, - ra_nprb_dl(data, nof_prb)); - } - mcs = ra_mcs_to_table_idx(&data->mcs); - } - bit_pack(mcs, &y, 5); + /* pack MCS */ + bit_pack(data->mcs_idx, &y, 5); /* harq process number */ bit_pack(data->harq_process, &y, 3); @@ -380,24 +379,24 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { *y++ = 0; // Padding with zeros - int n = dci_format1_sizeof(nof_prb); + uint32_t n = dci_format1_sizeof(nof_prb); while (y - msg->data < n) { *y++ = 0; } - msg->location.nof_bits = (y - msg->data); + msg->nof_bits = (y - msg->data); - return 0; + return LIBLTE_SUCCESS; } -int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { +int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) { /* pack bits */ char *y = msg->data; /* Make sure it's a Format1 message */ - if (msg->location.nof_bits != dci_format_sizeof(Format1, nof_prb)) { + if (msg->nof_bits != dci_format_sizeof(Format1, nof_prb)) { fprintf(stderr, "Invalid message length for format 1\n"); - return -1; + return LIBLTE_ERROR; } if (nof_prb > 10) { @@ -407,8 +406,8 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { } /* Resource allocation: type0 or type 1 */ - int P = ra_type0_P(nof_prb); - int alloc_size = (int) ceilf((float) nof_prb / P); + uint32_t P = ra_type0_P(nof_prb); + uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P); switch (data->alloc_type) { case alloc_type0: data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size); @@ -420,17 +419,17 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { alloc_size - (int) ceilf(log2f(P)) - 1); break; default: - fprintf(stderr, - "Format 1 accepts type0 or type1 resource allocation only\n"); - return -1; + fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n"); + return LIBLTE_ERROR; } - /* pack MCS according to 7.1.7 of 36.213 */ - uint32_t mcs = bit_unpack(&y, 5); - data->mcs.mcs_idx = mcs; - ra_mcs_from_idx_dl(mcs, &data->mcs); - data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_dl(data, nof_prb)); - + /* unpack MCS according to 7.1.7 of 36.213 */ + data->mcs_idx = bit_unpack(&y, 5); + if (ra_mcs_from_idx_dl(data->mcs_idx, ra_nprb_dl(data, nof_prb), &data->mcs)) { + fprintf(stderr, "Error getting MCS\n"); + return LIBLTE_ERROR; + } + /* harq process number */ data->harq_process = bit_unpack(&y, 3); @@ -441,14 +440,14 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { // TPC not implemented - return 0; + return LIBLTE_SUCCESS; } /* Packs DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3 * * TODO: RA procedure initiated by PDCCH, TPC commands */ -int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, +int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb, bool crc_is_crnti) { /* pack bits */ @@ -458,7 +457,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, if (data->alloc_type != alloc_type2) { fprintf(stderr, "Format 1A accepts type2 resource allocation only\n"); - return -1; + return LIBLTE_ERROR; } *y++ = data->type2_alloc.mode; // localized or distributed VRB assignment @@ -467,10 +466,10 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, if (data->type2_alloc.L_crb > nof_prb) { fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n", data->type2_alloc.L_crb); - return -1; + return LIBLTE_ERROR; } } else { - int n_vrb_dl; + uint32_t n_vrb_dl; if (crc_is_crnti && nof_prb > 50) { n_vrb_dl = 16; } else { @@ -480,7 +479,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", data->type2_alloc.L_crb, n_vrb_dl); - return -1; + return LIBLTE_ERROR; } } /* pack RIV according to 7.1.6.3 of 36.213 */ @@ -491,7 +490,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, } else { riv = data->type2_alloc.riv; } - int nb_gap = 0; + uint32_t nb_gap = 0; if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) { nb_gap = 1; *y++ = data->type2_alloc.n_gap; @@ -499,23 +498,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, bit_pack(riv, &y, riv_nbits(nof_prb) - nb_gap); // in format1A, MCS = TBS according to 7.1.7.2 of 36.213 - uint32_t mcs; - if (data->mcs.mod == MOD_NULL) { - mcs = data->mcs.mcs_idx; - } else { - if (data->mcs.tbs) { - // In format 1A, n_prb_1a is 2 or 3 if crc is not scrambled with C-RNTI - int n_prb; - if (!crc_is_crnti) { - n_prb = ra_nprb_dl(data, nof_prb); - } else { - n_prb = data->type2_alloc.n_prb1a == nprb1a_2 ? 2 : 3; - } - data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, n_prb); - } - mcs = data->mcs.tbs_idx; - } - bit_pack(mcs, &y, 5); + bit_pack(data->mcs_idx, &y, 5); bit_pack(data->harq_process, &y, 3); @@ -538,34 +521,33 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, } // Padding with zeros - int n = dci_format1A_sizeof(nof_prb); + uint32_t n = dci_format1A_sizeof(nof_prb); while (y - msg->data < n) { *y++ = 0; } - msg->location.nof_bits = (y - msg->data); + msg->nof_bits = (y - msg->data); - return 0; + return LIBLTE_SUCCESS; } /* Unpacks DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3 * */ -int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, +int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb, bool crc_is_crnti) { /* pack bits */ char *y = msg->data; /* Make sure it's a Format0 message */ - if (msg->location.nof_bits != dci_format_sizeof(Format1A, nof_prb)) { + if (msg->nof_bits != dci_format_sizeof(Format1A, nof_prb)) { fprintf(stderr, "Invalid message length for format 1A\n"); - return -1; + return LIBLTE_ERROR; } if (*y++ != 1) { - fprintf(stderr, - "Invalid format differentiation field value. This is Format0\n"); - return -1; + fprintf(stderr, "Invalid format differentiation field value. This is Format0\n"); + return LIBLTE_ERROR; } data->alloc_type = alloc_type2; @@ -575,12 +557,12 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, data->type2_alloc.n_gap = t2_ng1; /* unpack RIV according to 7.1.6.3 of 36.213 */ - int nb_gap = 0; + uint32_t nb_gap = 0; if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) { nb_gap = 1; data->type2_alloc.n_gap = *y++; } - int nof_vrb; + uint32_t nof_vrb; if (data->type2_alloc.mode == t2_loc) { nof_vrb = nof_prb; } else { @@ -592,7 +574,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, data->type2_alloc.riv = riv; // unpack MCS - data->mcs.mcs_idx = bit_unpack(&y, 5); + data->mcs_idx = bit_unpack(&y, 5); data->harq_process = bit_unpack(&y, 3); @@ -613,23 +595,23 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, y++; // MSB of TPC is reserved data->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS } - data->mcs.tbs_idx = data->mcs.mcs_idx; - int n_prb; + + uint32_t n_prb; if (crc_is_crnti) { n_prb = ra_nprb_dl(data, nof_prb); } else { n_prb = data->type2_alloc.n_prb1a == nprb1a_2 ? 2 : 3; } - data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, n_prb); - data->mcs.mod = QPSK; + data->mcs.tbs = ra_tbs_from_idx(data->mcs_idx, n_prb); + data->mcs.mod = LTE_QPSK; - return 0; + return LIBLTE_SUCCESS; } /* Format 1C for compact scheduling of PDSCH words * */ -int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { +int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) { /* pack bits */ char *y = msg->data; @@ -637,32 +619,31 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { if (data->alloc_type != alloc_type2 || data->type2_alloc.mode != t2_dist) { fprintf(stderr, "Format 1C accepts distributed type2 resource allocation only\n"); - return -1; + return LIBLTE_ERROR; } if (nof_prb >= 50) { *y++ = data->type2_alloc.n_gap; } - int n_step = ra_type2_n_rb_step(nof_prb); - int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); + uint32_t n_step = ra_type2_n_rb_step(nof_prb); + uint32_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); - if (data->type2_alloc.L_crb > ((int) n_vrb_dl / n_step) * n_step) { - fprintf(stderr, - "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", - data->type2_alloc.L_crb, ((int) n_vrb_dl / n_step) * n_step); - return -1; + if (data->type2_alloc.L_crb > ((uint32_t) n_vrb_dl / n_step) * n_step) { + fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", + data->type2_alloc.L_crb, ((uint32_t) n_vrb_dl / n_step) * n_step); + return LIBLTE_ERROR; } if (data->type2_alloc.L_crb % n_step) { fprintf(stderr, "L_crb must be multiple of n_step\n"); - return -1; + return LIBLTE_ERROR; } if (data->type2_alloc.RB_start % n_step) { fprintf(stderr, "RB_start must be multiple of n_step\n"); - return -1; + return LIBLTE_ERROR; } - int L_p = data->type2_alloc.L_crb / n_step; - int RB_p = data->type2_alloc.RB_start / n_step; - int n_vrb_p = (int) n_vrb_dl / n_step; + uint32_t L_p = data->type2_alloc.L_crb / n_step; + uint32_t RB_p = data->type2_alloc.RB_start / n_step; + uint32_t n_vrb_p = (int) n_vrb_dl / n_step; uint32_t riv; if (data->type2_alloc.L_crb) { @@ -673,60 +654,50 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { bit_pack(riv, &y, riv_nbits((int) n_vrb_dl / n_step)); // in format1C, MCS = TBS according to 7.1.7.2 of 36.213 - uint32_t mcs; - if (data->mcs.mod == MOD_NULL) { - mcs = data->mcs.mcs_idx; - } else { - if (data->mcs.tbs) { - data->mcs.tbs_idx = ra_tbs_to_table_idx_format1c(data->mcs.tbs); - } - mcs = data->mcs.tbs_idx; - } - bit_pack(mcs, &y, 5); + bit_pack(data->mcs_idx, &y, 5); - msg->location.nof_bits = (y - msg->data); + msg->nof_bits = (y - msg->data); - return 0; + return LIBLTE_SUCCESS; } -int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { - uint16_t L_p, RB_p; +int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) { + uint32_t L_p, RB_p; /* pack bits */ char *y = msg->data; - if (msg->location.nof_bits != dci_format_sizeof(Format1C, nof_prb)) { + if (msg->nof_bits != dci_format_sizeof(Format1C, nof_prb)) { fprintf(stderr, "Invalid message length for format 1C\n"); - return -1; + return LIBLTE_ERROR; } data->alloc_type = alloc_type2; data->type2_alloc.mode = t2_dist; if (nof_prb >= 50) { data->type2_alloc.n_gap = *y++; } - int n_step = ra_type2_n_rb_step(nof_prb); - int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); + uint32_t n_step = ra_type2_n_rb_step(nof_prb); + uint32_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); uint32_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl / n_step)); - int n_vrb_p = (int) n_vrb_dl / n_step; + uint32_t n_vrb_p = (uint32_t) n_vrb_dl / n_step; ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p); data->type2_alloc.L_crb = L_p * n_step; data->type2_alloc.RB_start = RB_p * n_step; data->type2_alloc.riv = riv; - data->mcs.mcs_idx = bit_unpack(&y, 5); - data->mcs.tbs_idx = data->mcs.mcs_idx; - data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs.tbs_idx); - data->mcs.mod = QPSK; + data->mcs_idx = bit_unpack(&y, 5); + data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs_idx); + data->mcs.mod = LTE_QPSK; - msg->location.nof_bits = (y - msg->data); + msg->nof_bits = (y - msg->data); - return 0; + return LIBLTE_SUCCESS; } int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, - int nof_prb, bool crc_is_crnti) { + uint32_t nof_prb, bool crc_is_crnti) { switch (format) { case Format1: return dci_format1_pack(data, msg, nof_prb); @@ -737,28 +708,28 @@ int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, default: fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n", dci_format_string(format)); - return -1; + return LIBLTE_ERROR; } } -int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, +int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb, bool crc_is_crnti) { - if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) { + if (msg->nof_bits == dci_format_sizeof(Format1, nof_prb)) { return dci_format1_unpack(msg, data, nof_prb); - } else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) { + } else if (msg->nof_bits == dci_format_sizeof(Format1A, nof_prb)) { return dci_format1As_unpack(msg, data, nof_prb, crc_is_crnti); - } else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) { + } else if (msg->nof_bits == dci_format_sizeof(Format1C, nof_prb)) { return dci_format1Cs_unpack(msg, data, nof_prb); } else { - return -1; + return LIBLTE_ERROR; } } -int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) { +int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, uint32_t nof_prb) { return dci_format0_pack(data, msg, nof_prb); } -int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) { +int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, uint32_t nof_prb) { return dci_format0_unpack(msg, data, nof_prb); } @@ -798,36 +769,38 @@ void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) { } } -int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, - unsigned short crnti) { - if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb) +int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint32_t nof_prb, + uint16_t msg_rnti, uint16_t crnti) +{ + DEBUG("Get message type: nof_bits=%d, msg_rnti=0x%x, crnti=0x%x\n", msg->nof_bits, msg_rnti, crnti); + if (msg->nof_bits == dci_format_sizeof(Format0, nof_prb) && !msg->data[0]) { type->type = PUSCH_SCHED; type->format = Format0; - return 0; - } else if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) { + return LIBLTE_SUCCESS; + } else if (msg->nof_bits == dci_format_sizeof(Format1, nof_prb)) { type->type = PDSCH_SCHED; // only these 2 types supported type->format = Format1; - return 0; - } else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) { - if (msg->location.rnti == crnti) { + return LIBLTE_SUCCESS; + } else if (msg->nof_bits == dci_format_sizeof(Format1A, nof_prb)) { + if (msg_rnti == crnti) { type->type = RA_PROC_PDCCH; type->format = Format1A; } else { type->type = PDSCH_SCHED; // only these 2 types supported type->format = Format1A; } - return 0; - } else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) { - if (msg->location.rnti == MRNTI) { + return LIBLTE_SUCCESS; + } else if (msg->nof_bits == dci_format_sizeof(Format1C, nof_prb)) { + if (msg_rnti == MRNTI) { type->type = MCCH_CHANGE; type->format = Format1C; } else { type->type = PDSCH_SCHED; // only these 2 types supported type->format = Format1C; } - return 0; + return LIBLTE_SUCCESS; } - return -1; + return LIBLTE_ERROR; } diff --git a/lte/phy/lib/phch/src/pbch.c b/lte/phy/lib/phch/src/pbch.c index 6113e5342..353dc7639 100644 --- a/lte/phy/lib/phch/src/pbch.c +++ b/lte/phy/lib/phch/src/pbch.c @@ -50,31 +50,45 @@ bool pbch_exists(int nframe, int nslot) { return (!(nframe % 5) && nslot == 1); } -int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, - bool put) { +int pbch_cp(cf_t *input, cf_t *output, lte_cell_t cell, bool put) { int i; cf_t *ptr; - assert(cell_id >= 0); + if (put) { ptr = input; - output += nof_prb * RE_X_RB / 2 - 36; + output += cell.nof_prb * RE_X_RB / 2 - 36; } else { ptr = output; - input += nof_prb * RE_X_RB / 2 - 36; + input += cell.nof_prb * RE_X_RB / 2 - 36; } - + /* symbol 0 & 1 */ for (i = 0; i < 2; i++) { - prb_cp_ref(&input, &output, cell_id % 3, 4, 6, put); + prb_cp_ref(&input, &output, cell.id % 3, 4, 4*6, put); + if (put) { + output += cell.nof_prb * RE_X_RB - 2*36; + } else { + input += cell.nof_prb * RE_X_RB - 2*36; + } } /* symbols 2 & 3 */ - if (CP_ISNORM(cp)) { + if (CP_ISNORM(cell.cp)) { for (i = 0; i < 2; i++) { prb_cp(&input, &output, 6); + if (put) { + output += cell.nof_prb * RE_X_RB - 2*36; + } else { + input += cell.nof_prb * RE_X_RB - 2*36; + } } } else { prb_cp(&input, &output, 6); - prb_cp_ref(&input, &output, cell_id % 3, 4, 6, put); + if (put) { + output += cell.nof_prb * RE_X_RB - 2*36; + } else { + input += cell.nof_prb * RE_X_RB - 2*36; + } + prb_cp_ref(&input, &output, cell.id % 3, 4, 4*6, put); } if (put) { return input - ptr; @@ -90,9 +104,8 @@ int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, * * 36.211 10.3 section 6.6.4 */ -int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, - int cell_id) { - return pbch_cp(pbch, slot1_data, nof_prb, cp, cell_id, true); +int pbch_put(cf_t *pbch, cf_t *slot1_data, lte_cell_t cell) { + return pbch_cp(pbch, slot1_data, cell, true); } /** @@ -102,92 +115,96 @@ int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, * * 36.211 10.3 section 6.6.4 */ -int pbch_get(cf_t *slot1_data, cf_t *pbch, int nof_prb, lte_cp_t cp, - int cell_id) { - return pbch_cp(slot1_data, pbch, nof_prb, cp, cell_id, false); +int pbch_get(cf_t *slot1_data, cf_t *pbch, lte_cell_t cell) { + return pbch_cp(slot1_data, pbch, cell, false); } -/** Initializes the PBCH transmitter and receiver */ -int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) { - int ret = -1; - if (cell_id < 0) { - return -1; - } - bzero(q, sizeof(pbch_t)); - q->cell_id = cell_id; - q->cp = cp; - q->nof_prb = nof_prb; +/** Initializes the PBCH transmitter and receiver. + * At the receiver, the field nof_ports in the cell structure indicates the + * maximum number of BS transmitter ports to look for. + */ +int pbch_init(pbch_t *q, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; - if (modem_table_std(&q->mod, LTE_QPSK, true)) { - goto clean; - } - demod_soft_init(&q->demod); - demod_soft_table_set(&q->demod, &q->mod); - demod_soft_alg_set(&q->demod, APPROX); - if (sequence_pbch(&q->seq_pbch, q->cp, q->cell_id)) { - goto clean; - } + if (q != NULL && + lte_cell_isvalid(&cell)) + { + ret = LIBLTE_ERROR; - int poly[3] = { 0x6D, 0x4F, 0x57 }; - if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) { - goto clean; - } - if (crc_init(&q->crc, LTE_CRC16, 16)) { - goto clean; - } - q->encoder.K = 7; - q->encoder.R = 3; - q->encoder.tail_biting = true; - memcpy(q->encoder.poly, poly, 3 * sizeof(int)); + bzero(q, sizeof(pbch_t)); + q->cell = cell; - q->nof_symbols = (CP_ISNORM(q->cp)) ? PBCH_RE_CPNORM : PBCH_RE_CPEXT; - - q->pbch_d = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->pbch_d) { - goto clean; - } - int i; - for (i = 0; i < MAX_PORTS_CTRL; i++) { - q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->ce[i]) { + if (modem_table_lte(&q->mod, LTE_QPSK, true)) { goto clean; } - q->pbch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->pbch_x[i]) { + demod_soft_init(&q->demod); + demod_soft_table_set(&q->demod, &q->mod); + demod_soft_alg_set(&q->demod, APPROX); + if (sequence_pbch(&q->seq_pbch, q->cell.cp, q->cell.id)) { goto clean; } - q->pbch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->pbch_symbols[i]) { - goto clean; - } - } - q->pbch_llr = malloc(sizeof(float) * q->nof_symbols * 4 * 2); - if (!q->pbch_llr) { - goto clean; - } - q->temp = malloc(sizeof(float) * q->nof_symbols * 4 * 2); - if (!q->temp) { - goto clean; - } - q->pbch_rm_f = malloc(sizeof(float) * 120); - if (!q->pbch_rm_f) { - goto clean; - } - q->pbch_rm_b = malloc(sizeof(float) * q->nof_symbols * 4 * 2); - if (!q->pbch_rm_b) { - goto clean; - } - q->data = malloc(sizeof(char) * 40); - if (!q->data) { - goto clean; - } - q->data_enc = malloc(sizeof(char) * 120); - if (!q->data_enc) { - goto clean; - } - ret = 0; - clean: if (ret == -1) { + uint32_t poly[3] = { 0x6D, 0x4F, 0x57 }; + if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) { + goto clean; + } + if (crc_init(&q->crc, LTE_CRC16, 16)) { + goto clean; + } + q->encoder.K = 7; + q->encoder.R = 3; + q->encoder.tail_biting = true; + memcpy(q->encoder.poly, poly, 3 * sizeof(int)); + + q->nof_symbols = (CP_ISNORM(q->cell.cp)) ? PBCH_RE_CPNORM : PBCH_RE_CPEXT; + + q->pbch_d = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pbch_d) { + goto clean; + } + int i; + for (i = 0; i < q->cell.nof_ports; i++) { + q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->ce[i]) { + goto clean; + } + q->pbch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pbch_x[i]) { + goto clean; + } + q->pbch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pbch_symbols[i]) { + goto clean; + } + } + q->pbch_llr = malloc(sizeof(float) * q->nof_symbols * 4 * 2); + if (!q->pbch_llr) { + goto clean; + } + q->temp = malloc(sizeof(float) * q->nof_symbols * 4 * 2); + if (!q->temp) { + goto clean; + } + q->pbch_rm_f = malloc(sizeof(float) * 120); + if (!q->pbch_rm_f) { + goto clean; + } + q->pbch_rm_b = malloc(sizeof(float) * q->nof_symbols * 4 * 2); + if (!q->pbch_rm_b) { + goto clean; + } + q->data = malloc(sizeof(char) * 40); + if (!q->data) { + goto clean; + } + q->data_enc = malloc(sizeof(char) * 120); + if (!q->data_enc) { + goto clean; + } + ret = LIBLTE_SUCCESS; + } +clean: + if (ret == LIBLTE_ERROR) { pbch_free(q); } return ret; @@ -198,7 +215,7 @@ void pbch_free(pbch_t *q) { free(q->pbch_d); } int i; - for (i = 0; i < MAX_PORTS_CTRL; i++) { + for (i = 0; i < q->cell.nof_ports; i++) { if (q->ce[i]) { free(q->ce[i]); } @@ -355,15 +372,15 @@ void crc_set_mask(char *data, int nof_ports) { * * Returns 0 if the data is correct, -1 otherwise */ -int pbch_crc_check(pbch_t *q, char *bits, int nof_ports) { +uint32_t pbch_crc_check(pbch_t *q, char *bits, uint32_t nof_ports) { char data[40]; memcpy(data, bits, 40 * sizeof(char)); crc_set_mask(data, nof_ports); return crc_checksum(&q->crc, data, 40); } -int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, - int nof_bits, int nof_ports) { +int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, uint32_t src, uint32_t dst, uint32_t n, + uint32_t nof_bits, uint32_t nof_ports) { int j; memcpy(&q->temp[dst * nof_bits], &q->pbch_llr[src * nof_bits], @@ -417,150 +434,178 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, /* Decodes the PBCH channel * * The PBCH spans in 40 ms. This function is called every 10 ms. It tries to decode the MIB - * given the symbols of the slot #1 of each radio frame. Successive calls will use more frames + * given the symbols of a subframe (1 ms). Successive calls will use more subframes * to help the decoding process. * * Returns 1 if successfully decoded MIB, 0 if not and -1 on error */ -int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], - float ebno, pbch_mib_t *mib) { - int src, dst, res, nb; - int nant_[3] = { 1, 2, 4 }; - int na, nant; - - /* Set pointers for layermapping & precoding */ +int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mib) { + uint32_t src, dst, nb; + uint32_t nant_[3] = { 1, 2, 4 }; + uint32_t na, nant; + cf_t *slot1_symbols; int i; - int nof_bits = 2 * q->nof_symbols; + int nof_bits; cf_t *x[MAX_LAYERS]; + cf_t *ce_slot[MAX_PORTS]; + + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + sf_symbols != NULL && + mib != NULL) + { + for (i=0;icell.nof_ports;i++) { + if (ce[i] == NULL) { + return LIBLTE_ERROR_INVALID_INPUTS; + } else { + ce_slot[i] = &ce[i][q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)]; + } + } + slot1_symbols = &sf_symbols[q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)]; - /* number of layers equals number of ports */ - for (i = 0; i < MAX_PORTS_CTRL; i++) { - x[i] = q->pbch_x[i]; - } - memset(&x[MAX_PORTS_CTRL], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS_CTRL)); + /* Set pointers for layermapping & precoding */ + nof_bits = 2 * q->nof_symbols; - /* extract symbols */ - if (q->nof_symbols - != pbch_get(slot1_symbols, q->pbch_symbols[0], q->nof_prb, q->cp, - q->cell_id)) { - fprintf(stderr, "There was an error getting the PBCH symbols\n"); - return -1; - } - - /* extract channel estimates */ - for (i = 0; i < MAX_PORTS_CTRL; i++) { - if (q->nof_symbols - != pbch_get(ce[i], q->ce[i], q->nof_prb, q->cp, q->cell_id)) { + /* number of layers equals number of ports */ + for (i = 0; i < MAX_PORTS; i++) { + x[i] = q->pbch_x[i]; + } + memset(&x[MAX_PORTS], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS)); + + /* extract symbols */ + if (q->nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols[0], q->cell)) { fprintf(stderr, "There was an error getting the PBCH symbols\n"); - return -1; - } - } - - q->frame_idx++; - res = 0; - - /* Try decoding for 1 to 4 antennas */ - for (na = 0; na < 3 && !res; na++) { - nant = nant_[na]; - - INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx); - - /* in conctrol channels, only diversity is supported */ - if (nant == 1) { - /* no need for layer demapping */ - predecoding_single_zf(q->pbch_symbols[0], q->ce[0], q->pbch_d, - q->nof_symbols); - } else { - predecoding_diversity_zf(q->pbch_symbols[0], q->ce, x, nant, - q->nof_symbols); - layerdemap_diversity(x, q->pbch_d, nant, q->nof_symbols / nant); + return LIBLTE_ERROR; } - /* demodulate symbols */ - demod_soft_sigma_set(&q->demod, ebno); - demod_soft_demodulate(&q->demod, q->pbch_d, - &q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols); + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + if (q->nof_symbols != pbch_get(ce_slot[i], q->ce[i], q->cell)) { + fprintf(stderr, "There was an error getting the PBCH symbols\n"); + return LIBLTE_ERROR; + } + } - /* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received - * 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234. - * We know they are ordered. - * - * FIXME: There are unnecessary checks because 2,3,4 have already been processed in the previous - * calls. - */ - for (nb = 0; nb < q->frame_idx && !res; nb++) { - for (dst = 0; (dst < 4 - nb) && !res; dst++) { - for (src = 0; src < q->frame_idx - nb && !res; src++) { - DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n", - nb + 1, src, dst); - res = pbch_decode_frame(q, mib, src, dst, nb + 1, nof_bits, nant); + q->frame_idx++; + ret = 0; + + /* Try decoding for 1 to cell.nof_ports antennas */ + for (na = 0; na < q->cell.nof_ports && !ret; na++) { + nant = nant_[na]; + + INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx); + + /* in conctrol channels, only diversity is supported */ + if (nant == 1) { + /* no need for layer demapping */ + predecoding_single_zf(q->pbch_symbols[0], q->ce[0], q->pbch_d, + q->nof_symbols); + } else { + predecoding_diversity_zf(q->pbch_symbols[0], q->ce, x, nant, + q->nof_symbols); + layerdemap_diversity(x, q->pbch_d, nant, q->nof_symbols / nant); + } + + /* demodulate symbols */ + demod_soft_sigma_set(&q->demod, 1.0); + demod_soft_demodulate(&q->demod, q->pbch_d, + &q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols); + + /* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received + * 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234. + * We know they are ordered. + * + * FIXME: There are unnecessary checks because 2,3,4 have already been processed in the previous + * calls. + */ + for (nb = 0; nb < q->frame_idx && !ret; nb++) { + for (dst = 0; (dst < 4 - nb) && !ret; dst++) { + for (src = 0; src < q->frame_idx - nb && !ret; src++) { + DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n", + nb + 1, src, dst); + ret = pbch_decode_frame(q, mib, src, dst, nb + 1, nof_bits, nant); + + } } } } - } - /* If not found, make room for the next packet of radio frame symbols */ - if (q->frame_idx == 4) { - memmove(q->pbch_llr, &q->pbch_llr[nof_bits], nof_bits * 3 * sizeof(float)); - q->frame_idx = 3; + /* If not found, make room for the next packet of radio frame symbols */ + if (q->frame_idx == 4) { + memmove(q->pbch_llr, &q->pbch_llr[nof_bits], nof_bits * 3 * sizeof(float)); + q->frame_idx = 3; + } } - return res; + return ret; } /** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission */ -void pbch_encode(pbch_t *q, pbch_mib_t *mib, - cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports) { +int pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *sf_symbols[MAX_PORTS]) { int i; - int nof_bits = 2 * q->nof_symbols; - - assert(nof_ports <= MAX_PORTS_CTRL); - - /* Set pointers for layermapping & precoding */ + int nof_bits; + cf_t *slot1_symbols[MAX_PORTS]; cf_t *x[MAX_LAYERS]; + + if (q != NULL && + mib != NULL) + { + for (i=0;icell.nof_ports;i++) { + if (sf_symbols[i] == NULL) { + return LIBLTE_ERROR_INVALID_INPUTS; + } else { + slot1_symbols[i] = &sf_symbols[i][q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)]; + } + } + /* Set pointers for layermapping & precoding */ + nof_bits = 2 * q->nof_symbols; - /* number of layers equals number of ports */ - for (i = 0; i < nof_ports; i++) { - x[i] = q->pbch_x[i]; - } - memset(&x[nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - nof_ports)); + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pbch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); + + if (q->frame_idx == 0) { + /* pack MIB */ + pbch_mib_pack(mib, q->data); - if (q->frame_idx == 0) { - /* pack MIB */ - pbch_mib_pack(mib, q->data); + /* encode & modulate */ + crc_attach(&q->crc, q->data, 24); + crc_set_mask(q->data, q->cell.nof_ports); - /* encode & modulate */ - crc_attach(&q->crc, q->data, 24); - crc_set_mask(q->data, nof_ports); + convcoder_encode(&q->encoder, q->data, q->data_enc, 40); - convcoder_encode(&q->encoder, q->data, q->data_enc, 40); + rm_conv_tx(q->data_enc, 120, q->pbch_rm_b, 4 * nof_bits); - rm_conv_tx(q->data_enc, 120, q->pbch_rm_b, 4 * nof_bits); + } - } + scrambling_b_offset(&q->seq_pbch, &q->pbch_rm_b[q->frame_idx * nof_bits], + q->frame_idx * nof_bits, nof_bits); + mod_modulate(&q->mod, &q->pbch_rm_b[q->frame_idx * nof_bits], q->pbch_d, + nof_bits); - scrambling_b_offset(&q->seq_pbch, &q->pbch_rm_b[q->frame_idx * nof_bits], - q->frame_idx * nof_bits, nof_bits); - mod_modulate(&q->mod, &q->pbch_rm_b[q->frame_idx * nof_bits], q->pbch_d, - nof_bits); + /* layer mapping & precoding */ + if (q->cell.nof_ports > 1) { + layermap_diversity(q->pbch_d, x, q->cell.nof_ports, q->nof_symbols); + precoding_diversity(x, q->pbch_symbols, q->cell.nof_ports, + q->nof_symbols / q->cell.nof_ports); + } else { + memcpy(q->pbch_symbols[0], q->pbch_d, q->nof_symbols * sizeof(cf_t)); + } - /* layer mapping & precoding */ - if (nof_ports > 1) { - layermap_diversity(q->pbch_d, x, nof_ports, q->nof_symbols); - precoding_diversity(x, q->pbch_symbols, nof_ports, - q->nof_symbols / nof_ports); + /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { + pbch_put(q->pbch_symbols[i], slot1_symbols[i], q->cell); + } + q->frame_idx++; + if (q->frame_idx == 4) { + q->frame_idx = 0; + } + return LIBLTE_SUCCESS; } else { - memcpy(q->pbch_symbols[0], q->pbch_d, q->nof_symbols * sizeof(cf_t)); - } - - /* mapping to resource elements */ - for (i = 0; i < nof_ports; i++) { - pbch_put(q->pbch_symbols[i], slot1_symbols[i], q->nof_prb, q->cp, - q->cell_id); - } - q->frame_idx++; - if (q->frame_idx == 4) { - q->frame_idx = 0; + return LIBLTE_ERROR_INVALID_INPUTS; } } diff --git a/lte/phy/lib/phch/src/pcfich.c b/lte/phy/lib/phch/src/pcfich.c index e2fd52c5b..f65d3394e 100644 --- a/lte/phy/lib/phch/src/pcfich.c +++ b/lte/phy/lib/phch/src/pcfich.c @@ -54,37 +54,42 @@ bool pcfich_exists(int nframe, int nslot) { return true; } -/** Initializes the pcfich channel receiver */ -int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, - int nof_ports, lte_cp_t cp) { - int ret = -1; - if (cell_id < 0) { - return -1; - } - bzero(q, sizeof(pcfich_t)); - q->cell_id = cell_id; - q->cp = cp; - q->regs = regs; - q->nof_prb = nof_prb; - q->nof_ports = nof_ports; +/** Initializes the pcfich channel receiver. + * On error, returns -1 and frees the structrure + */ +int pcfich_init(pcfich_t *q, regs_t *regs, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + regs != NULL && + lte_cell_isvalid(&cell)) + { + ret = LIBLTE_ERROR; + + bzero(q, sizeof(pcfich_t)); + q->cell = cell; + q->regs = regs; - if (modem_table_std(&q->mod, LTE_QPSK, false)) { - goto clean; - } - - demod_hard_init(&q->demod); - demod_hard_table_set(&q->demod, LTE_QPSK); - - for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) { - if (sequence_pcfich(&q->seq_pcfich[nsf], 2 * nsf, q->cell_id)) { + if (modem_table_lte(&q->mod, LTE_QPSK, false)) { goto clean; } + + demod_hard_init(&q->demod); + demod_hard_table_set(&q->demod, LTE_QPSK); + + for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) { + if (sequence_pcfich(&q->seq_pcfich[nsf], 2 * nsf, q->cell.id)) { + goto clean; + } + } + + q->nof_symbols = PCFICH_RE; + + ret = LIBLTE_SUCCESS; } - - q->nof_symbols = PCFICH_RE; - - ret = 0; - clean: if (ret == -1) { + + clean: + if (ret == LIBLTE_ERROR) { pcfich_free(q); } return ret; @@ -100,7 +105,7 @@ void pcfich_free(pcfich_t *q) { /** Finds the CFI with minimum distance with the vector of received 32 bits. * Saves the CFI value in the cfi pointer and returns the distance. */ -int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], int *cfi) { +int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], uint32_t *cfi) { int i, j; int distance, index = -1; int min = 32; @@ -120,7 +125,6 @@ int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], int *cfi) { *cfi = index + 1; } return min; - } /** Encodes the CFI producing a vector of 32 bits. @@ -128,19 +132,19 @@ int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], int *cfi) { */ int pcfich_cfi_encode(int cfi, char bits[PCFICH_CFI_LEN]) { if (cfi < 1 || cfi > 3) { - fprintf(stderr, "Invalid CFI %d\n", cfi); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; + } else{ + memcpy(bits, cfi_table[cfi - 1], PCFICH_CFI_LEN * sizeof(char)); + return LIBLTE_SUCCESS; } - memcpy(bits, cfi_table[cfi - 1], PCFICH_CFI_LEN * sizeof(char)); - return 0; } /* Decodes the PCFICH channel and saves the CFI in the cfi pointer. * * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ -int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], - int nsubframe, int *cfi, int *distance) { +int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], + uint32_t nsubframe, uint32_t *cfi, uint32_t *distance) { int dist; /* Set pointers for layermapping & precoding */ @@ -148,112 +152,120 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], cf_t *x[MAX_LAYERS]; cf_t *ce_precoding[MAX_PORTS]; - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid nslot %d\n", nsubframe); - return -1; - } + if (q != NULL && + slot_symbols != NULL && + nsubframe < NSUBFRAMES_X_FRAME) + { - /* number of layers equals number of ports */ - for (i = 0; i < MAX_PORTS_CTRL; i++) { - x[i] = q->pcfich_x[i]; - } - for (i = 0; i < MAX_PORTS; i++) { - ce_precoding[i] = q->ce[i]; - } - - /* extract symbols */ - if (q->nof_symbols - != regs_pcfich_get(q->regs, slot_symbols, q->pcfich_symbols[0])) { - fprintf(stderr, "There was an error getting the PCFICH symbols\n"); - return -1; - } - - /* extract channel estimates */ - for (i = 0; i < q->nof_ports; i++) { - if (q->nof_symbols != regs_pcfich_get(q->regs, ce[i], q->ce[i])) { - fprintf(stderr, "There was an error getting the PCFICH symbols\n"); - return -1; + /* number of layers equals number of ports */ + for (i = 0; i < MAX_PORTS; i++) { + x[i] = q->pcfich_x[i]; + } + for (i = 0; i < MAX_PORTS; i++) { + ce_precoding[i] = q->ce[i]; } - } - /* in control channels, only diversity is supported */ - if (q->nof_ports == 1) { - /* no need for layer demapping */ - predecoding_single_zf(q->pcfich_symbols[0], q->ce[0], q->pcfich_d, - q->nof_symbols); + /* extract symbols */ + if (q->nof_symbols + != regs_pcfich_get(q->regs, slot_symbols, q->pcfich_symbols[0])) { + fprintf(stderr, "There was an error getting the PCFICH symbols\n"); + return LIBLTE_ERROR; + } + + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + if (q->nof_symbols != regs_pcfich_get(q->regs, ce[i], q->ce[i])) { + fprintf(stderr, "There was an error getting the PCFICH symbols\n"); + return LIBLTE_ERROR; + } + } + + /* in control channels, only diversity is supported */ + if (q->cell.nof_ports == 1) { + /* no need for layer demapping */ + predecoding_single_zf(q->pcfich_symbols[0], q->ce[0], q->pcfich_d, + q->nof_symbols); + } else { + predecoding_diversity_zf(q->pcfich_symbols[0], ce_precoding, x, + q->cell.nof_ports, q->nof_symbols); + layerdemap_diversity(x, q->pcfich_d, q->cell.nof_ports, + q->nof_symbols / q->cell.nof_ports); + } + + /* demodulate symbols */ + demod_hard_demodulate(&q->demod, q->pcfich_d, q->data, q->nof_symbols); + + /* Scramble with the sequence for slot nslot */ + scrambling_b(&q->seq_pcfich[nsubframe], q->data); + + /* decode CFI */ + dist = pcfich_cfi_decode(q->data, cfi); + if (distance) { + *distance = dist; + } + if (dist < PCFICH_MAX_DISTANCE) { + return 1; + } else { + return 0; + } } else { - predecoding_diversity_zf(q->pcfich_symbols[0], ce_precoding, x, - q->nof_ports, q->nof_symbols); - layerdemap_diversity(x, q->pcfich_d, q->nof_ports, - q->nof_symbols / q->nof_ports); - } - - /* demodulate symbols */ - demod_hard_demodulate(&q->demod, q->pcfich_d, q->data, q->nof_symbols); - - /* Scramble with the sequence for slot nslot */ - scrambling_b(&q->seq_pcfich[nsubframe], q->data); - - /* decode CFI */ - dist = pcfich_cfi_decode(q->data, cfi); - if (distance) { - *distance = dist; - } - if (dist < PCFICH_MAX_DISTANCE) { - return 1; - } else { - return 0; + return LIBLTE_ERROR_INVALID_INPUTS; } + } /** Encodes CFI and maps symbols to the slot */ -int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], - int nsubframe) { +int pcfich_encode(pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[MAX_PORTS], + uint32_t subframe) { int i; - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid nslot %d\n", nsubframe); - return -1; - } + if (q != NULL && + cfi < 3 && + slot_symbols != NULL && + subframe < NSUBFRAMES_X_FRAME) + { - /* Set pointers for layermapping & precoding */ - cf_t *x[MAX_LAYERS]; - cf_t *symbols_precoding[MAX_PORTS]; + /* Set pointers for layermapping & precoding */ + cf_t *x[MAX_LAYERS]; + cf_t *symbols_precoding[MAX_PORTS]; - /* number of layers equals number of ports */ - for (i = 0; i < q->nof_ports; i++) { - x[i] = q->pcfich_x[i]; - } - for (i = 0; i < MAX_PORTS; i++) { - symbols_precoding[i] = q->pcfich_symbols[i]; - } - - /* pack MIB */ - pcfich_cfi_encode(cfi, q->data); - - /* scramble for slot sequence nslot */ - scrambling_b(&q->seq_pcfich[nsubframe], q->data); - - mod_modulate(&q->mod, q->data, q->pcfich_d, PCFICH_CFI_LEN); - - /* layer mapping & precoding */ - if (q->nof_ports > 1) { - layermap_diversity(q->pcfich_d, x, q->nof_ports, q->nof_symbols); - precoding_diversity(x, symbols_precoding, q->nof_ports, - q->nof_symbols / q->nof_ports); - } else { - memcpy(q->pcfich_symbols[0], q->pcfich_d, q->nof_symbols * sizeof(cf_t)); - } - - /* mapping to resource elements */ - for (i = 0; i < q->nof_ports; i++) { - if (regs_pcfich_put(q->regs, q->pcfich_symbols[i], slot_symbols[i]) < 0) { - fprintf(stderr, "Error putting PCHICH resource elements\n"); - return -1; + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pcfich_x[i]; + } + for (i = 0; i < MAX_PORTS; i++) { + symbols_precoding[i] = q->pcfich_symbols[i]; } - } - return 0; + /* pack CFI */ + pcfich_cfi_encode(cfi, q->data); + + /* scramble for slot sequence nslot */ + scrambling_b(&q->seq_pcfich[subframe], q->data); + + mod_modulate(&q->mod, q->data, q->pcfich_d, PCFICH_CFI_LEN); + + /* layer mapping & precoding */ + if (q->cell.nof_ports > 1) { + layermap_diversity(q->pcfich_d, x, q->cell.nof_ports, q->nof_symbols); + precoding_diversity(x, symbols_precoding, q->cell.nof_ports, + q->nof_symbols / q->cell.nof_ports); + } else { + memcpy(q->pcfich_symbols[0], q->pcfich_d, q->nof_symbols * sizeof(cf_t)); + } + + /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { + if (regs_pcfich_put(q->regs, q->pcfich_symbols[i], slot_symbols[i]) < 0) { + fprintf(stderr, "Error putting PCHICH resource elements\n"); + return LIBLTE_ERROR; + } + } + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; + } } + diff --git a/lte/phy/lib/phch/src/pdcch.c b/lte/phy/lib/phch/src/pdcch.c index d0522322c..99d49b4aa 100644 --- a/lte/phy/lib/phch/src/pdcch.c +++ b/lte/phy/lib/phch/src/pdcch.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include "liblte/phy/phch/dci.h" @@ -42,257 +41,115 @@ #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" -#define PDCCH_NOF_FORMATS 4 -#define PDCCH_FORMAT_NOF_CCE(i) (1<b)?b:a) -/** - * 36.213 9.1 - */ -int gen_common_search(dci_candidate_t *c, int nof_cce, int nof_bits, - unsigned short rnti) { - int i, l, L, k; - k = 0; - for (l = 3; l > 1; l--) { - L = (1 << l); - for (i = 0; i < MIN(nof_cce,16) / (L); i++) { - c[k].L = l; - c[k].nof_bits = nof_bits; - c[k].rnti = rnti; - c[k].ncce = (L) * (i % (nof_cce / (L))); - INFO("Common SS Candidate %d: RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n", - k, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L); - k++; - } - } - return k; + +#define NOF_COMMON_FORMATS 2 +const dci_format_t common_formats[NOF_COMMON_FORMATS] = { Format1A, Format1C }; + +#define NOF_UE_FORMATS 2 +const dci_format_t ue_formats[NOF_UE_FORMATS] = { Format0, Format1 }; // 1A has the same payload as 0 + + +static void set_cfi(pdcch_t *q, uint32_t cfi) { + if (cfi > 0 && cfi < 4) { + q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9; + q->nof_cce = q->nof_regs / 9; + } } -/** - * 36.213 9.1 - */ -int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, - unsigned short rnti, int subframe) { - int i, l, L, k, m; - unsigned int Yk; - const int S[4] = { 6, 12, 8, 16 }; - k = 0; - if (!subframe) { - INFO("UE-specific candidates for RNTI: 0x%x, NofBits: %d, NofCCE: %d\n", - rnti, nof_bits, nof_cce); - if (VERBOSE_ISINFO()) - printf("[INFO]: "); - } - for (l = 3; l >= 0; l--) { - L = (1 << l); - for (i = 0; i < MIN(nof_cce / L, 16 / S[l]); i++) { - c[k].L = l; - c[k].nof_bits = nof_bits; - c[k].rnti = rnti; - Yk = rnti; - for (m = 0; m < subframe; m++) { - Yk = (39827 * Yk) % 65537; - } - c[k].ncce = L * ((Yk + i) % (nof_cce / L)); - if (!subframe) { - if (VERBOSE_ISINFO()) { - printf("(%d, %d), ", c[k].ncce, c[k].L); - } - } - k++; - } - } - if (!subframe) { - if (VERBOSE_ISINFO()) - printf("\n"); - } - return k; -} - -void pdcch_init_common(pdcch_t *q, pdcch_search_t *s, unsigned short rnti) { - int k, i; - s->nof_candidates = NOF_COMMON_FORMATS - * (MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8); - if (s->nof_candidates) { - s->candidates[0] = malloc(sizeof(dci_candidate_t) * s->nof_candidates); - dci_candidate_t *c = s->candidates[0]; - s->nof_candidates = 0; - if (c) { - // Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16 - k = 0; - for (i = 0; i < NOF_COMMON_FORMATS; i++) { - k += gen_common_search(&c[k], q->nof_cce, - dci_format_sizeof(common_formats[i], q->nof_prb), SIRNTI); - s->nof_candidates++; - } - } - } -} - -/** 36.213 v9.3 Table 7.1-1: System Information DCI messages - * Expect DCI formats 1C and 1A in the common search space - */ -void pdcch_init_search_si(pdcch_t *q) { - pdcch_init_common(q, &q->search_mode[SEARCH_SI], SIRNTI); - q->current_search_mode = SEARCH_SI; -} - -/** 36.213 v9.3 Table 7.1-5 - * user-specific search space. Currently supported transmission Mode 1: - * DCI Format 1A and 1 + PUSCH scheduling format 0 - */ -void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) { - int l, n, k, i; - pdcch_search_t *s = &q->search_mode[SEARCH_UE]; - s->nof_candidates = 0; - for (l = 0; l < 3; l++) { - s->nof_candidates += NOF_UE_FORMATS * (MIN(q->nof_cce,16) / (1 << l)); - } - INFO( - "Initiating %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", - s->nof_candidates, c_rnti); - if (s->nof_candidates) { - for (n = 0; n < NSUBFRAMES_X_FRAME; n++) { - s->candidates[n] = malloc(sizeof(dci_candidate_t) * s->nof_candidates); - dci_candidate_t *c = s->candidates[n]; - - if (c) { - // Expect Formats 1, 1A, 0 - k = 0; - for (i = 0; i < NOF_UE_FORMATS; i++) { - k += gen_ue_search(&c[k], q->nof_cce, - dci_format_sizeof(ue_formats[i], q->nof_prb), c_rnti, n); - } - } - } - } - q->current_search_mode = SEARCH_UE; -} - -/** 36.213 v9.3 Table 7.1-3 - * Expect DCI formats 1C and 1A in the common search space - */ -void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti) { - pdcch_init_common(q, &q->search_mode[SEARCH_RA], ra_rnti); - q->current_search_mode = SEARCH_RA; -} - -void pdcch_set_search_si(pdcch_t *q) { - q->current_search_mode = SEARCH_SI; -} -void pdcch_set_search_ue(pdcch_t *q) { - q->current_search_mode = SEARCH_UE; -} -void pdcch_set_search_ra(pdcch_t *q) { - q->current_search_mode = SEARCH_RA; -} /** Initializes the PDCCH transmitter and receiver */ -int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, - int cell_id, lte_cp_t cp) { - int ret = -1; - int i; +int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + uint32_t i; - if (cell_id < 0) { - return -1; - } - if (nof_ports > MAX_PORTS_CTRL) { - fprintf(stderr, "Invalid number of ports %d\n", nof_ports); - return -1; - } - bzero(q, sizeof(pdcch_t)); - q->cell_id = cell_id; - q->cp = cp; - q->regs = regs; - q->nof_ports = nof_ports; - q->nof_prb = nof_prb; - q->current_search_mode = SEARCH_NONE; + if (q != NULL && + regs != NULL && + lte_cell_isvalid(&cell)) + { + ret = LIBLTE_ERROR; + bzero(q, sizeof(pdcch_t)); + q->cell = cell; + q->regs = regs; - q->nof_regs = (regs_pdcch_nregs(q->regs) / 9) * 9; - q->nof_cce = q->nof_regs / 9; - q->nof_symbols = 4 * q->nof_regs; - q->nof_bits = 2 * q->nof_symbols; + /* Allocate memory for the largest aggregation level L=3 */ + q->max_bits = PDCCH_FORMAT_NOF_BITS(3); - INFO("Init PDCCH: %d CCEs (%d REGs), %d bits, %d symbols, %d ports\n", - q->nof_cce, q->nof_regs, q->nof_bits, q->nof_symbols, q->nof_ports); + INFO("Init PDCCH: %d bits, %d symbols, %d ports\n", q->max_bits, q->max_bits/2, q->cell.nof_ports); - if (modem_table_std(&q->mod, LTE_QPSK, true)) { - goto clean; - } - if (crc_init(&q->crc, LTE_CRC16, 16)) { - goto clean; - } - - demod_soft_init(&q->demod); - demod_soft_table_set(&q->demod, &q->mod); - demod_soft_alg_set(&q->demod, APPROX); - - for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { - if (sequence_pdcch(&q->seq_pdcch[i], 2 * i, q->cell_id, q->nof_bits)) { + if (modem_table_lte(&q->mod, LTE_QPSK, true)) { goto clean; } - } - - int poly[3] = { 0x6D, 0x4F, 0x57 }; - if (viterbi_init(&q->decoder, viterbi_37, poly, DCI_MAX_BITS + 16, true)) { - goto clean; - } - - q->pdcch_e = malloc(sizeof(char) * q->nof_bits); - if (!q->pdcch_e) { - goto clean; - } - - q->pdcch_llr = malloc(sizeof(float) * q->nof_bits); - if (!q->pdcch_llr) { - goto clean; - } - - q->pdcch_d = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->pdcch_d) { - goto clean; - } - - for (i = 0; i < MAX_PORTS_CTRL; i++) { - q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->ce[i]) { + if (crc_init(&q->crc, LTE_CRC16, 16)) { goto clean; } - q->pdcch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->pdcch_x[i]) { + + demod_soft_init(&q->demod); + demod_soft_table_set(&q->demod, &q->mod); + demod_soft_alg_set(&q->demod, APPROX); + + for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { + // we need to pregenerate the sequence for the maximum number of bits, which is 8 times + // the maximum number of REGs (for CFI=3) + if (sequence_pdcch(&q->seq_pdcch[i], 2 * i, q->cell.id, 8*regs_pdcch_nregs(q->regs, 3))) { + goto clean; + } + } + + uint32_t poly[3] = { 0x6D, 0x4F, 0x57 }; + if (viterbi_init(&q->decoder, viterbi_37, poly, DCI_MAX_BITS + 16, true)) { goto clean; } - q->pdcch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->pdcch_symbols[i]) { + + q->pdcch_e = malloc(sizeof(char) * q->max_bits); + if (!q->pdcch_e) { goto clean; } + + q->pdcch_llr = malloc(sizeof(float) * q->max_bits); + if (!q->pdcch_llr) { + goto clean; + } + + q->pdcch_d = malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->pdcch_d) { + goto clean; + } + + for (i = 0; i < MAX_PORTS; i++) { + q->ce[i] = malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->ce[i]) { + goto clean; + } + q->pdcch_x[i] = malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->pdcch_x[i]) { + goto clean; + } + q->pdcch_symbols[i] = malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->pdcch_symbols[i]) { + goto clean; + } + } + + ret = LIBLTE_SUCCESS; } - ret = 0; - clean: if (ret == -1) { + clean: + if (ret == LIBLTE_ERROR) { pdcch_free(q); } return ret; } void pdcch_free(pdcch_t *q) { - int i, j; + int i; - for (i = 0; i < PDCCH_NOF_SEARCH_MODES; i++) { - for (j = 0; j < NSUBFRAMES_X_FRAME; j++) { - if (q->search_mode[i].candidates[j]) { - free(q->search_mode[i].candidates[j]); - } - } - } if (q->pdcch_e) { free(q->pdcch_e); } @@ -302,7 +159,7 @@ void pdcch_free(pdcch_t *q) { if (q->pdcch_d) { free(q->pdcch_d); } - for (i = 0; i < MAX_PORTS_CTRL; i++) { + for (i = 0; i < MAX_PORTS; i++) { if (q->ce[i]) { free(q->ce[i]); } @@ -322,189 +179,257 @@ void pdcch_free(pdcch_t *q) { viterbi_free(&q->decoder); } +/** 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 pdcch_ue_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidates, + uint32_t nsubframe, uint32_t cfi, uint16_t rnti) { + + int l; // this must be int because of the for(;;--) loop + uint32_t i, k, L, m; + uint32_t Yk, ncce; + const int S[4] = { 6, 12, 8, 16 }; + + set_cfi(q, cfi); + + // Compute Yk for this subframe + Yk = rnti; + for (m = 0; m < nsubframe; m++) { + Yk = (39827 * Yk) % 65537; + } + + k = 0; + // All aggregation levels from 8 to 1 + for (l = 3; l >= 0; l--) { + L = (1 << l); + // For all possible ncce offset + for (i = 0; i < MIN(q->nof_cce / L, 16 / S[l]); i++) { + ncce = L * ((Yk + i) % (q->nof_cce / L)); + if (k < max_candidates && + ncce + PDCCH_FORMAT_NOF_CCE(l) <= q->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); + + k++; + } + } + } + + INFO("Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", k, rnti); + + return k; +} + + + +/** + * 36.213 9.1.1 + * Computes up to max_candidates candidates in the common search space + * for DCI messages and saves them in the structure pointed by c. + * Returns the number of candidates saved in the array c. + */ +uint32_t pdcch_common_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidates, + uint32_t cfi) +{ + uint32_t i, l, L, k; + + set_cfi(q, cfi); + + k = 0; + for (l = 3; l > 1; l--) { + L = (1 << l); + for (i = 0; i < MIN(q->nof_cce, 16) / (L); i++) { + if (k < max_candidates) { + c[k].L = l; + c[k].ncce = (L) * (i % (q->nof_cce / (L))); + DEBUG("Common SS Candidate %d: nCCE: %d, L: %d\n", + k, c[k].ncce, c[k].L); + k++; + } + } + } + + INFO("Initiated %d candidate(s) in the Common search space\n", k); + + return k; +} + + + + + + /** 36.212 5.3.3.2 to 5.3.3.4 * * Returns XOR between parity and remainder bits * * TODO: UE transmit antenna selection CRC mask */ -unsigned short dci_decode(pdcch_t *q, float *e, char *data, int E, int nof_bits) { +static int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof_bits, uint16_t *crc) { float tmp[3 * (DCI_MAX_BITS + 16)]; - unsigned short p_bits, crc_res; + uint16_t p_bits, crc_res; char *x; - assert(nof_bits < DCI_MAX_BITS); + if (q != NULL && + data != NULL && + E <= q->max_bits && + nof_bits <= DCI_MAX_BITS) + { - /* unrate matching */ - rm_conv_rx(e, E, tmp, 3 * (nof_bits + 16)); + /* unrate matching */ + rm_conv_rx(e, E, tmp, 3 * (nof_bits + 16)); - DEBUG("Viterbi input: ", 0); - if (VERBOSE_ISDEBUG()) { - vec_fprint_f(stdout, tmp, 3 * (nof_bits + 16)); + DEBUG("Viterbi input: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_f(stdout, tmp, 3 * (nof_bits + 16)); + } + + /* viterbi decoder */ + viterbi_decode_f(&q->decoder, tmp, data, nof_bits + 16); + + if (VERBOSE_ISDEBUG()) { + bit_fprint(stdout, data, nof_bits + 16); + } + + x = &data[nof_bits]; + p_bits = (uint16_t) bit_unpack(&x, 16); + crc_res = ((uint16_t) crc_checksum(&q->crc, data, nof_bits) & 0xffff); + DEBUG("p_bits: 0x%x, crc_checksum: 0x%x, crc_rem: 0x%x\n", p_bits, crc_res, + p_bits ^ crc_res); + + if (crc) { + *crc = p_bits ^ crc_res; + } + return LIBLTE_SUCCESS; + } else { + fprintf(stderr, "Invalid parameters: E: %d, max_bits: %d, nof_bits: %d\n", E, q->max_bits, nof_bits); + return LIBLTE_ERROR_INVALID_INPUTS; } - - /* viterbi decoder */ - viterbi_decode_f(&q->decoder, tmp, data, nof_bits + 16); - - if (VERBOSE_ISDEBUG()) { - bit_fprint(stdout, data, nof_bits + 16); - } - - x = &data[nof_bits]; - p_bits = (unsigned short) bit_unpack(&x, 16); - crc_res = ((unsigned short) crc_checksum(&q->crc, data, nof_bits) & 0xffff); - DEBUG("p_bits: 0x%x, crc_res: 0x%x, tot: 0x%x\n", p_bits, crc_res, - p_bits ^ crc_res); - return (p_bits ^ crc_res); } -int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c, - dci_msg_t *msg) { - unsigned short crc_res; - DEBUG("Trying Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", - c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L, c->rnti); - crc_res = dci_decode(q, &llr[72 * c->ncce], msg->data, - PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits); - - if (c->rnti == crc_res) { - memcpy(&msg->location, c, sizeof(dci_candidate_t)); - INFO("FOUND Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", - c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L, c->rnti); - return 1; +/** Tries to decode a DCI message from the LLRs stored in the pdcch_t structure by the function + * pdcch_extract_llr(). This function can be called multiple times. + * The decoded message is stored in msg and the CRC remainder in crc_rem pointer + * + */ +int pdcch_decode_msg(pdcch_t *q, dci_msg_t *msg, dci_format_t format, uint16_t *crc_rem) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + if (q != NULL && + msg != NULL && + crc_rem != NULL) + { + uint32_t nof_bits = dci_format_sizeof(format, q->cell.nof_prb); + + ret = dci_decode(q, q->pdcch_llr, msg->data, q->e_bits, nof_bits, crc_rem); + if (ret == LIBLTE_SUCCESS) { + msg->nof_bits = nof_bits; + } } - return 0; + return ret; } -int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], - float *llr, int nsubframe, float ebno) { +/** Extracts the LLRs from dci_location_t location of the subframe and stores them in the pdcch_t structure. + * DCI messages can be extracted from this location calling the function pdcch_decode_msg(). + * Every time this function is called (with a different location), the last demodulated symbols are overwritten and + * new messages from other locations can be decoded + */ +int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], + dci_location_t location, uint32_t nsubframe, uint32_t cfi) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + /* Set pointers for layermapping & precoding */ - int i; + uint32_t i, nof_symbols; cf_t *x[MAX_LAYERS]; - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid subframe %d\n", nsubframe); - return -1; - } + if (q != NULL && + nsubframe < 10 && + cfi > 0 && + cfi < 4 && + dci_location_isvalid(&location)) + { + set_cfi(q, cfi); + + q->e_bits = PDCCH_FORMAT_NOF_BITS(location.L); + nof_symbols = q->e_bits/2; + ret = LIBLTE_ERROR; + + if (location.ncce + PDCCH_FORMAT_NOF_CCE(location.L) <= q->nof_cce) { + + INFO("Extracting LLRs: E: %d, nCCE: %d, L: %d, SF: %d, CFI: %d\n", + q->e_bits, location.ncce, location.L, nsubframe, cfi); - if (ebno == 0.0) { - fprintf(stderr, "EbNo is Zero\n"); - return -1; - } + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pdcch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); - /* number of layers equals number of ports */ - for (i = 0; i < q->nof_ports; i++) { - x[i] = q->pdcch_x[i]; - } - memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports)); + /* extract symbols */ + int n = regs_pdcch_get_offset(q->regs, sf_symbols, q->pdcch_symbols[0], + location.ncce * 9, PDCCH_FORMAT_NOF_REGS(location.L)); + if (nof_symbols != n) { + fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); + return ret; + } - /* extract symbols */ - int n = regs_pdcch_get(q->regs, slot_symbols, q->pdcch_symbols[0]); - if (q->nof_symbols != n) { - fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", - q->nof_symbols, n); - return -1; - } + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + n = regs_pdcch_get_offset(q->regs, ce[i], q->ce[i], + location.ncce * 9, PDCCH_FORMAT_NOF_REGS(location.L)); + if (nof_symbols != n) { + fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); + return ret; + } + } - /* extract channel estimates */ - for (i = 0; i < q->nof_ports; i++) { - n = regs_pdcch_get(q->regs, ce[i], q->ce[i]); - if (q->nof_symbols != n) { - fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", - q->nof_symbols, n); - return -1; + /* in control channels, only diversity is supported */ + if (q->cell.nof_ports == 1) { + /* no need for layer demapping */ + predecoding_single_zf(q->pdcch_symbols[0], q->ce[0], q->pdcch_d, nof_symbols); + } else { + predecoding_diversity_zf(q->pdcch_symbols[0], q->ce, x, q->cell.nof_ports, nof_symbols); + layerdemap_diversity(x, q->pdcch_d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); + } + + DEBUG("pdcch d symbols: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_c(stdout, q->pdcch_d, nof_symbols); + } + + /* demodulate symbols */ + demod_soft_sigma_set(&q->demod, 1.0); + demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, nof_symbols); + + DEBUG("llr: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_f(stdout, q->pdcch_llr, q->e_bits); + } + + /* descramble */ + scrambling_f_offset(&q->seq_pdcch[nsubframe], q->pdcch_llr, 72 * location.ncce, q->e_bits); + + ret = LIBLTE_SUCCESS; + } else { + fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d\n", location.ncce, location.L, q->nof_cce); } - } - - /* in control channels, only diversity is supported */ - if (q->nof_ports == 1) { - /* no need for layer demapping */ - predecoding_single_zf(q->pdcch_symbols[0], q->ce[0], q->pdcch_d, - q->nof_symbols); - } else { - predecoding_diversity_zf(q->pdcch_symbols[0], q->ce, x, q->nof_ports, - q->nof_symbols); - layerdemap_diversity(x, q->pdcch_d, q->nof_ports, - q->nof_symbols / q->nof_ports); - } - - DEBUG("pdcch d symbols: ", 0); - if (VERBOSE_ISDEBUG()) { - vec_fprint_c(stdout, q->pdcch_d, q->nof_symbols); - } - - /* demodulate symbols */ - demod_soft_sigma_set(&q->demod, ebno); - demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, q->nof_symbols); - - DEBUG("llr: ", 0); - if (VERBOSE_ISDEBUG()) { - vec_fprint_f(stdout, q->pdcch_llr, q->nof_bits); - } - - /* descramble */ - scrambling_f_offset(&q->seq_pdcch[nsubframe], llr, 0, q->nof_bits); - - return 0; + } + return ret; } -int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) { - int k, i; - if (q->current_search_mode == SEARCH_UE) { - k = subframe; - } else { - k = 0; - } - for (i = 0; - i < q->search_mode[q->current_search_mode].nof_candidates - && dci->nof_dcis < dci->max_dcis; i++) { - if (pdcch_decode_candidate(q, q->pdcch_llr, - &q->search_mode[q->current_search_mode].candidates[k][i], - &dci->msg[dci->nof_dcis])) { - dci->nof_dcis++; - } - } - return dci->nof_dcis; -} -int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci) { - pdcch_set_search_si(q); - return pdcch_decode_current_mode(q, llr, dci, 0); -} -int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci) { - pdcch_set_search_ra(q); - return pdcch_decode_current_mode(q, llr, dci, 0); -} -int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe) { - pdcch_set_search_ue(q); - return pdcch_decode_current_mode(q, llr, dci, nsubframe); -} - -/* Decodes PDCCH channels - * - * dci->nof_dcis is the size of the dci->msg buffer (ie max number of messages) - * - * Returns number of messages stored in dci - */ -int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], - dci_t *dci, int nsubframe, float ebno) { - - if (pdcch_extract_llr(q, slot_symbols, ce, q->pdcch_llr, nsubframe, ebno)) { - return -1; - } - - if (q->current_search_mode != SEARCH_NONE) { - return pdcch_decode_current_mode(q, q->pdcch_llr, dci, nsubframe); - } - - return 0; -} - -void crc_set_mask_rnti(char *crc, unsigned short rnti) { - int i; +static void crc_set_mask_rnti(char *crc, uint16_t rnti) { + uint32_t i; char mask[16]; char *r = mask; @@ -519,92 +444,115 @@ void crc_set_mask_rnti(char *crc, unsigned short rnti) { /** 36.212 5.3.3.2 to 5.3.3.4 * TODO: UE transmit antenna selection CRC mask */ -void dci_encode(pdcch_t *q, char *data, char *e, int nof_bits, int E, - unsigned short rnti) { +static int dci_encode(pdcch_t *q, char *data, char *e, uint32_t nof_bits, uint32_t E, + uint16_t rnti) { convcoder_t encoder; char tmp[3 * (DCI_MAX_BITS + 16)]; + + if (q != NULL && + data != NULL && + e != NULL && + nof_bits < DCI_MAX_BITS && + E < q->max_bits) + { - assert(nof_bits < DCI_MAX_BITS); + int poly[3] = { 0x6D, 0x4F, 0x57 }; + encoder.K = 7; + encoder.R = 3; + encoder.tail_biting = true; + memcpy(encoder.poly, poly, 3 * sizeof(int)); - int poly[3] = { 0x6D, 0x4F, 0x57 }; - encoder.K = 7; - encoder.R = 3; - encoder.tail_biting = true; - memcpy(encoder.poly, poly, 3 * sizeof(int)); + crc_attach(&q->crc, data, nof_bits); + crc_set_mask_rnti(&data[nof_bits], rnti); - crc_attach(&q->crc, data, nof_bits); - crc_set_mask_rnti(&data[nof_bits], rnti); + convcoder_encode(&encoder, data, tmp, nof_bits + 16); - convcoder_encode(&encoder, data, tmp, nof_bits + 16); - - DEBUG("CConv output: ", 0); - if (VERBOSE_ISDEBUG()) { - vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16)); - } - - rm_conv_tx(tmp, 3 * (nof_bits + 16), e, E); -} - -/** Converts the set of DCI messages to symbols mapped to the slot ready for transmission - */ -int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS_CTRL], - int nsubframe) { - int i; - /* Set pointers for layermapping & precoding */ - cf_t *x[MAX_LAYERS]; - - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid subframe %d\n", nsubframe); - return -1; - } - - /* number of layers equals number of ports */ - for (i = 0; i < q->nof_ports; i++) { - x[i] = q->pdcch_x[i]; - } - memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports)); - - /* should add elements? Or maybe random bits to facilitate power estimation */ - bzero(q->pdcch_e, q->nof_bits); - - /* Encode DCIs */ - for (i = 0; i < dci->nof_dcis; i++) { - /* do some sanity checks */ - if (dci->msg[i].location.ncce + PDCCH_FORMAT_NOF_CCE(dci->msg[i].location.L) - > q->nof_cce || dci->msg[i].location.L > 3 - || dci->msg[i].location.nof_bits > DCI_MAX_BITS) { - fprintf(stderr, "Illegal DCI message %d\n", i); - return -1; + DEBUG("CConv output: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16)); } - INFO("Encoding DCI %d: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", i, - dci->msg[i].location.nof_bits, - PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L), - dci->msg[i].location.ncce, dci->msg[i].location.L, - dci->msg[i].location.rnti); - dci_encode(q, dci->msg[i].data, &q->pdcch_e[72 * dci->msg[i].location.ncce], - dci->msg[i].location.nof_bits, - PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L), - dci->msg[i].location.rnti); - } - - scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 0, q->nof_bits); - - mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->nof_bits); - - /* layer mapping & precoding */ - if (q->nof_ports > 1) { - layermap_diversity(q->pdcch_d, x, q->nof_ports, q->nof_symbols); - precoding_diversity(x, q->pdcch_symbols, q->nof_ports, - q->nof_symbols / q->nof_ports); + rm_conv_tx(tmp, 3 * (nof_bits + 16), e, E); + + return LIBLTE_SUCCESS; } else { - memcpy(q->pdcch_symbols[0], q->pdcch_d, q->nof_symbols * sizeof(cf_t)); + return LIBLTE_ERROR_INVALID_INPUTS; } - - /* mapping to resource elements */ - for (i = 0; i < q->nof_ports; i++) { - regs_pdcch_put(q->regs, q->pdcch_symbols[i], slot_symbols[i]); - } - return 0; +} + +/** Encodes ONE DCI message and allocates the encoded bits to the dci_location_t indicated by + * the parameter location. The CRC is scrambled with the RNTI parameter. + * This function can be called multiple times and encoded DCI messages will be allocated to the + * sf_symbols buffer ready for transmission. + * If the same location is provided in multiple messages, the encoded bits will be overwritten. + * + * @TODO: Use a bitmask and CFI to ensure message locations are valid and old messages are not overwritten. + */ +int pdcch_encode(pdcch_t *q, dci_msg_t *msg, dci_location_t location, uint16_t rnti, + cf_t *sf_symbols[MAX_PORTS], uint32_t nsubframe, uint32_t cfi) { + + int ret = LIBLTE_ERROR_INVALID_INPUTS; + uint32_t i; + cf_t *x[MAX_LAYERS]; + uint32_t nof_symbols; + + if (q != NULL && + sf_symbols != NULL && + nsubframe < 10 && + cfi > 0 && + cfi < 4 && + dci_location_isvalid(&location)) + { + + set_cfi(q, cfi); + + q->e_bits = PDCCH_FORMAT_NOF_BITS(location.L); + nof_symbols = q->e_bits/2; + ret = LIBLTE_ERROR; + + if (location.ncce + PDCCH_FORMAT_NOF_CCE(location.L) <= q->nof_cce && + msg->nof_bits < DCI_MAX_BITS) + { + INFO("Encoding DCI: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", + msg->nof_bits, q->e_bits, location.ncce, location.L, rnti); + + dci_encode(q, msg->data, q->pdcch_e, msg->nof_bits, q->e_bits, rnti); + + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pdcch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); + + scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 72 * location.ncce, q->e_bits); + + DEBUG("Scrambling output: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_b(stdout, q->pdcch_e, q->e_bits); + } + + mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->e_bits); + + /* layer mapping & precoding */ + if (q->cell.nof_ports > 1) { + layermap_diversity(q->pdcch_d, x, q->cell.nof_ports, nof_symbols); + precoding_diversity(x, q->pdcch_symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); + } else { + memcpy(q->pdcch_symbols[0], q->pdcch_d, nof_symbols * sizeof(cf_t)); + } + + /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { + regs_pdcch_put_offset(q->regs, q->pdcch_symbols[i], sf_symbols[i], + location.ncce * 9, PDCCH_FORMAT_NOF_REGS(location.L)); + } + + ret = LIBLTE_SUCCESS; + + } else { + fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d\n", location.ncce, location.L, q->nof_cce); + } + } + return ret; } diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index 0314cd95b..0f5a508d4 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -41,93 +41,98 @@ #include "liblte/phy/utils/debug.h" #include "liblte/phy/utils/vector.h" -const enum modem_std modulations[4] = - { LTE_BPSK, LTE_QPSK, LTE_QAM16, LTE_QAM64 }; -#define MAX_PDSCH_RE(cp) (2 * (CP_NSYMB(cp) - 1) * 12 - 6) -#define HAS_REF(l, cp, nof_ports) ((l == 1 && nof_ports == 4) \ - || l == 0 \ - || l == CP_NSYMB(cp) - 3) +#define MAX_PDSCH_RE(cp) (2 * CP_NSYMB(cp) * 12) + + + +const lte_mod_t modulations[4] = + { LTE_BPSK, LTE_QPSK, LTE_QAM16, LTE_QAM64 }; + + + int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, - int nsubframe, bool put) { - int s, n, l, lp, lstart, lend, nof_refs; + uint32_t nsubframe, bool put) { + uint32_t s, n, l, lp, lstart, lend, nof_refs; bool is_pbch, is_sss; cf_t *in_ptr = input, *out_ptr = output; - int offset; + uint32_t offset = 0; -assert(q->cell_id >= 0); - - INFO("%s %d RE from %d PRB\n", put ? "Putting" : "Getting", + INFO("%s %d RE from %d PRB\n", put ? "Putting" : "Getting", prb_alloc->re_sf[nsubframe], prb_alloc->slot[0].nof_prb); - if (q->nof_ports == 1) { + if (q->cell.nof_ports == 1) { nof_refs = 2; } else { nof_refs = 4; } for (s = 0; s < 2; s++) { - if (s == 0) { - lstart = prb_alloc->lstart; - } else { - lstart = 0; - } - - for (l = lstart; l < CP_NSYMB(q->cp); l++) { + for (l = 0; l < CP_NSYMB(q->cell.cp); l++) { for (n = 0; n < prb_alloc->slot[s].nof_prb; n++) { - lend = CP_NSYMB(q->cp); + if (s == 0) { + lstart = prb_alloc->lstart; + } else { + lstart = 0; + } + lend = CP_NSYMB(q->cell.cp); is_pbch = is_sss = false; // Skip PSS/SSS signals if (s == 0 && (nsubframe == 0 || nsubframe == 5)) { - if (prb_alloc->slot[s].prb_idx[n] >= q->nof_prb / 2 - 3 - && prb_alloc->slot[s].prb_idx[n] <= q->nof_prb / 2 + 3) { - lend = CP_NSYMB(q->cp) - 2; + if (prb_alloc->slot[s].prb_idx[n] >= q->cell.nof_prb / 2 - 3 + && prb_alloc->slot[s].prb_idx[n] <= q->cell.nof_prb / 2 + 3) { + lend = CP_NSYMB(q->cell.cp) - 2; is_sss = true; } } // Skip PBCH if (s == 1 && nsubframe == 0) { - if (prb_alloc->slot[s].prb_idx[n] >= q->nof_prb / 2 - 3 - && prb_alloc->slot[s].prb_idx[n] <= q->nof_prb / 2 + 3) { + if (prb_alloc->slot[s].prb_idx[n] >= q->cell.nof_prb / 2 - 3 + && prb_alloc->slot[s].prb_idx[n] <= q->cell.nof_prb / 2 + 3) { lstart = 4; is_pbch = true; } } - lp = l + s * CP_NSYMB(q->cp); + lp = l + s * CP_NSYMB(q->cell.cp); if (put) { - out_ptr = &output[(lp * q->nof_prb + prb_alloc->slot[s].prb_idx[n]) + out_ptr = &output[(lp * q->cell.nof_prb + prb_alloc->slot[s].prb_idx[n]) * RE_X_RB]; } else { - in_ptr = &input[(lp * q->nof_prb + prb_alloc->slot[s].prb_idx[n]) + in_ptr = &input[(lp * q->cell.nof_prb + prb_alloc->slot[s].prb_idx[n]) * RE_X_RB]; } - - if (is_pbch && (q->nof_prb % 2) - && (prb_alloc->slot[s].prb_idx[n] == q->nof_prb / 2 - 3 - && prb_alloc->slot[s].prb_idx[n] == q->nof_prb / 2 + 3)) { - if (l < lstart) { - prb_cp_half(&in_ptr, &out_ptr, 1); - } - } if (l >= lstart && l < lend) { - if (HAS_REF(l, q->cp, q->nof_ports)) { + if (SYMBOL_HAS_REF(l, q->cell.cp, q->cell.nof_ports)) { if (nof_refs == 2 && l != 0) { - offset = q->cell_id % 3 + 3; + offset = q->cell.id % 3 + 3; } else { - offset = q->cell_id % 3; + offset = q->cell.id % 3; } - prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, 1, put); + prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs, put); } else { prb_cp(&in_ptr, &out_ptr, 1); } } - if (is_sss && (q->nof_prb % 2) - && (prb_alloc->slot[s].prb_idx[n] == q->nof_prb / 2 - 3 - && prb_alloc->slot[s].prb_idx[n] == q->nof_prb / 2 + 3)) { - if (l >= lend) { - prb_cp_half(&in_ptr, &out_ptr, 1); + if ((q->cell.nof_prb % 2) && ((is_pbch && l < lstart) || (is_sss && l >= lend))) { + if (prb_alloc->slot[s].prb_idx[n] == q->cell.nof_prb / 2 - 3) { + if (SYMBOL_HAS_REF(l, q->cell.cp, q->cell.nof_ports)) { + prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs/2, put); + } else { + prb_cp_half(&in_ptr, &out_ptr, 1); + } + } else if (prb_alloc->slot[s].prb_idx[n] == q->cell.nof_prb / 2 + 3) { + if (put) { + out_ptr += 6; + } else { + in_ptr += 6; + } + if (SYMBOL_HAS_REF(l, q->cell.cp, q->cell.nof_ports)) { + prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs/2, put); + } else { + prb_cp_half(&in_ptr, &out_ptr, 1); + } } } } @@ -135,9 +140,9 @@ assert(q->cell_id >= 0); } if (put) { - return (int) (input - in_ptr); + return abs((int) (input - in_ptr)); } else { - return (int) (output - out_ptr); + return abs((int) (output - out_ptr)); } } @@ -149,8 +154,8 @@ assert(q->cell_id >= 0); * 36.211 10.3 section 6.3.5 */ int pdsch_put(pdsch_t *q, cf_t *pdsch_symbols, cf_t *sf_symbols, - ra_prb_t *prb_alloc, int nsubframe) { - return pdsch_cp(q, pdsch_symbols, sf_symbols, prb_alloc, nsubframe, true); + ra_prb_t *prb_alloc, uint32_t subframe) { + return pdsch_cp(q, pdsch_symbols, sf_symbols, prb_alloc, subframe, true); } /** @@ -161,117 +166,94 @@ int pdsch_put(pdsch_t *q, cf_t *pdsch_symbols, cf_t *sf_symbols, * 36.211 10.3 section 6.3.5 */ int pdsch_get(pdsch_t *q, cf_t *sf_symbols, cf_t *pdsch_symbols, - ra_prb_t *prb_alloc, int nsubframe) { - return pdsch_cp(q, sf_symbols, pdsch_symbols, prb_alloc, nsubframe, false); + ra_prb_t *prb_alloc, uint32_t subframe) { + return pdsch_cp(q, sf_symbols, pdsch_symbols, prb_alloc, subframe, false); } /** Initializes the PDCCH transmitter and receiver */ -int pdsch_init(pdsch_t *q, unsigned short user_rnti, int nof_prb, int nof_ports, - int cell_id, lte_cp_t cp) { - int ret = -1; +int pdsch_init(pdsch_t *q, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; int i; - if (cell_id < 0) { - return -1; - } + if (q != NULL && + lte_cell_isvalid(&cell)) + { + + bzero(q, sizeof(pdsch_t)); + ret = LIBLTE_ERROR; + + q->cell = cell; + + q->max_symbols = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); - if (nof_ports > MAX_PORTS) { - fprintf(stderr, "Invalid number of ports %d\n", nof_ports); - return -1; - } + INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports, + q->cell.nof_prb, q->max_symbols); - bzero(q, sizeof(pdsch_t)); - q->cell_id = cell_id; - q->cp = cp; - q->nof_ports = nof_ports; - q->nof_prb = nof_prb; - q->rnti = user_rnti; - - q->max_symbols = nof_prb * MAX_PDSCH_RE(cp); - - INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->nof_ports, - q->nof_prb, q->max_symbols); - - for (i = 0; i < 4; i++) { - if (modem_table_std(&q->mod[i], modulations[i], true)) { + for (i = 0; i < 4; i++) { + if (modem_table_lte(&q->mod[i], modulations[i], true)) { + goto clean; + } + } + if (crc_init(&q->crc_tb, LTE_CRC24A, 24)) { goto clean; } - } - if (crc_init(&q->crc_tb, LTE_CRC24A, 24)) { - goto clean; - } - if (crc_init(&q->crc_cb, LTE_CRC24B, 24)) { - goto clean; - } - - demod_soft_init(&q->demod); - demod_soft_alg_set(&q->demod, APPROX); - - for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { - if (sequence_pdsch(&q->seq_pdsch[i], q->rnti, 0, 2 * i, q->cell_id, - q->max_symbols * q->mod[3].nbits_x_symbol)) { + if (crc_init(&q->crc_cb, LTE_CRC24B, 24)) { goto clean; } - } - if (tcod_init(&q->encoder, MAX_LONG_CB)) { - goto clean; - } - if (tdec_init(&q->decoder, MAX_LONG_CB)) { - goto clean; - } - if (rm_turbo_init(&q->rm_turbo, 3 * MAX_LONG_CB)) { - goto clean; - } + demod_soft_init(&q->demod); + demod_soft_alg_set(&q->demod, APPROX); + + q->rnti_is_set = false; - q->cb_in_b = malloc(sizeof(char) * MAX_LONG_CB); - if (!q->cb_in_b) { - goto clean; - } - q->cb_out_b = malloc(sizeof(char) * (3 * MAX_LONG_CB + 12)); - if (!q->cb_out_b) { - goto clean; - } - - q->pdsch_rm_f = malloc(sizeof(float) * (3 * MAX_LONG_CB + 12)); - if (!q->pdsch_rm_f) { - goto clean; - } - - q->pdsch_e_bits = malloc( - sizeof(char) * q->max_symbols * q->mod[3].nbits_x_symbol); - if (!q->pdsch_e_bits) { - goto clean; - } - - q->pdsch_llr = malloc( - sizeof(float) * q->max_symbols * q->mod[3].nbits_x_symbol); - if (!q->pdsch_llr) { - goto clean; - } - - q->pdsch_d = malloc(sizeof(cf_t) * q->max_symbols); - if (!q->pdsch_d) { - goto clean; - } - - for (i = 0; i < nof_ports; i++) { - q->ce[i] = malloc(sizeof(cf_t) * q->max_symbols); - if (!q->ce[i]) { + if (tcod_init(&q->encoder, MAX_LONG_CB)) { goto clean; } - q->pdsch_x[i] = malloc(sizeof(cf_t) * q->max_symbols); - if (!q->pdsch_x[i]) { + if (tdec_init(&q->decoder, MAX_LONG_CB)) { goto clean; } - q->pdsch_symbols[i] = malloc(sizeof(cf_t) * q->max_symbols); - if (!q->pdsch_symbols[i]) { - goto clean; - } - } - ret = 0; - clean: if (ret == -1) { + // Allocate floats for reception (LLRs) + q->cb_in = malloc(sizeof(char) * MAX_LONG_CB); + if (!q->cb_in) { + goto clean; + } + + q->cb_out = malloc(sizeof(float) * (3 * MAX_LONG_CB + 12)); + if (!q->cb_out) { + goto clean; + } + + // Allocate floats for reception (LLRs) + q->pdsch_e = malloc(sizeof(float) * q->max_symbols * q->mod[3].nbits_x_symbol); + if (!q->pdsch_e) { + goto clean; + } + + q->pdsch_d = malloc(sizeof(cf_t) * q->max_symbols); + if (!q->pdsch_d) { + goto clean; + } + + for (i = 0; i < q->cell.nof_ports; i++) { + q->ce[i] = malloc(sizeof(cf_t) * q->max_symbols); + if (!q->ce[i]) { + goto clean; + } + q->pdsch_x[i] = malloc(sizeof(cf_t) * q->max_symbols); + if (!q->pdsch_x[i]) { + goto clean; + } + q->pdsch_symbols[i] = malloc(sizeof(cf_t) * q->max_symbols); + if (!q->pdsch_symbols[i]) { + goto clean; + } + } + + ret = LIBLTE_SUCCESS; + } + clean: + if (ret == LIBLTE_ERROR) { pdsch_free(q); } return ret; @@ -280,25 +262,19 @@ int pdsch_init(pdsch_t *q, unsigned short user_rnti, int nof_prb, int nof_ports, void pdsch_free(pdsch_t *q) { int i; - if (q->cb_in_b) { - free(q->cb_in_b); + if (q->cb_in) { + free(q->cb_in); } - if (q->cb_out_b) { - free(q->cb_out_b); + if (q->cb_out) { + free(q->cb_out); } - if (q->pdsch_e_bits) { - free(q->pdsch_e_bits); - } - if (q->pdsch_rm_f) { - free(q->pdsch_rm_f); - } - if (q->pdsch_llr) { - free(q->pdsch_llr); + if (q->pdsch_e) { + free(q->pdsch_e); } if (q->pdsch_d) { free(q->pdsch_d); } - for (i = 0; i < q->nof_ports; i++) { + for (i = 0; i < q->cell.nof_ports; i++) { if (q->ce[i]) { free(q->ce[i]); } @@ -319,23 +295,26 @@ void pdsch_free(pdsch_t *q) { } tdec_free(&q->decoder); tcod_free(&q->encoder); - rm_turbo_free(&q->rm_turbo); } -struct cb_segm { - int F; - int C; - int K1; - int K2; - int C1; - int C2; -}; - +int pdsch_set_rnti(pdsch_t *q, uint16_t rnti) { + uint32_t i; + for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { + if (sequence_pdsch(&q->seq_pdsch[i], rnti, 0, 2 * i, q->cell.id, + q->max_symbols * q->mod[3].nbits_x_symbol)) { + return LIBLTE_ERROR; + } + } + q->rnti_is_set = true; + q->rnti = rnti; + return LIBLTE_SUCCESS; +} /* Calculate Codeblock Segmentation as in Section 5.1.2 of 36.212 */ -void codeblock_segmentation(struct cb_segm *s, int tbs) { - int Bp, B, idx1; - +static int codeblock_segmentation(struct cb_segm *s, uint32_t tbs) { + uint32_t Bp, B, idx1; + int ret; + B = tbs + 24; /* Calculate CB sizes */ @@ -343,356 +322,527 @@ void codeblock_segmentation(struct cb_segm *s, int tbs) { s->C = 1; Bp = B; } else { - s->C = (int) ceilf((float) B / (6114 - 24)); + s->C = (uint32_t) ceilf((float) B / (6114 - 24)); Bp = B + 24 * s->C; } - idx1 = lte_find_cb_index(Bp / s->C); - s->K1 = lte_cb_size(idx1); - if (s->C == 1) { - s->K2 = 0; - s->C2 = 0; - s->C1 = 1; - } else { - s->K2 = lte_cb_size(idx1 - 1); - s->C2 = (s->C * s->K1 - Bp) / (s->K1 - s->K2); - s->C1 = s->C - s->C2; - } - s->F = s->C1 * s->K1 + s->C2 * s->K2 - Bp; - INFO( - "CB Segmentation: TBS: %d, C=%d, C+=%d K+=%d, C-=%d, K-=%d, F=%d, Bp=%d\n", - tbs, s->C, s->C1, s->K1, s->C2, s->K2, s->F, Bp); + ret = lte_find_cb_index(Bp / s->C); + if (ret != LIBLTE_ERROR) { + idx1 = (uint32_t) ret; + ret = lte_cb_size(idx1); + if (ret != LIBLTE_ERROR) { + s->K1 = (uint32_t) ret; + ret = lte_cb_size(idx1 - 1); + if (ret != LIBLTE_ERROR) { + if (s->C == 1) { + s->K2 = 0; + s->C2 = 0; + s->C1 = 1; + } else { + s->K2 = (uint32_t) ret; + s->C2 = (s->C * s->K1 - Bp) / (s->K1 - s->K2); + s->C1 = s->C - s->C2; + } + s->F = s->C1 * s->K1 + s->C2 * s->K2 - Bp; + INFO("CB Segmentation: TBS: %d, C=%d, C+=%d K+=%d, C-=%d, K-=%d, F=%d, Bp=%d\n", + tbs, s->C, s->C1, s->K1, s->C2, s->K2, s->F, Bp); + } + } + } + return ret; } +int pdsch_harq_init(pdsch_harq_t *p, pdsch_t *pdsch) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (p != NULL) { + uint32_t i; + bzero(p, sizeof(pdsch_harq_t)); + + p->cell = pdsch->cell; + ret = ra_tbs_from_idx(26, p->cell.nof_prb); + if (ret != LIBLTE_ERROR) { + p->max_cb = (uint32_t) ret / (6114 - 24) + 1; + + p->pdsch_w_buff_f = malloc(sizeof(float*) * p->max_cb); + if (!p->pdsch_w_buff_f) { + perror("malloc"); + return LIBLTE_ERROR; + } + + p->pdsch_w_buff_c = malloc(sizeof(char*) * p->max_cb); + if (!p->pdsch_w_buff_c) { + perror("malloc"); + return LIBLTE_ERROR; + } + + // We add 50 % larger buffer to the maximum expected bits per subframe + // FIXME: Use HARQ buffer limitation based on UE category + p->w_buff_size = p->cell.nof_prb * MAX_PDSCH_RE(p->cell.cp) * 6 * 2 / p->max_cb; + for (i=0;imax_cb;i++) { + p->pdsch_w_buff_f[i] = malloc(sizeof(float) * p->w_buff_size); + if (!p->pdsch_w_buff_f[i]) { + perror("malloc"); + return LIBLTE_ERROR; + } + p->pdsch_w_buff_c[i] = malloc(sizeof(char) * p->w_buff_size); + if (!p->pdsch_w_buff_c[i]) { + perror("malloc"); + return LIBLTE_ERROR; + } + } + ret = LIBLTE_SUCCESS; + } + } + return ret; +} + +void pdsch_harq_free(pdsch_harq_t *p) { + if (p) { + uint32_t i; + if (p->pdsch_w_buff_f) { + for (i=0;imax_cb;i++) { + if (p->pdsch_w_buff_f[i]) { + free(p->pdsch_w_buff_f[i]); + } + } + free(p->pdsch_w_buff_f); + } + if (p->pdsch_w_buff_c) { + for (i=0;imax_cb;i++) { + if (p->pdsch_w_buff_c[i]) { + free(p->pdsch_w_buff_c[i]); + } + } + free(p->pdsch_w_buff_c); + } + bzero(p, sizeof(pdsch_harq_t)); + } +} + +int pdsch_harq_setup(pdsch_harq_t *p, ra_mcs_t mcs, ra_prb_t *prb_alloc) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (p != NULL && + mcs.tbs > 0) + { + uint32_t nof_bits, nof_bits_e, nof_symbols; + + p->mcs = mcs; + memcpy(&p->prb_alloc, prb_alloc, sizeof(ra_prb_t)); + + codeblock_segmentation(&p->cb_segm, mcs.tbs); + + nof_bits = mcs.tbs; + nof_symbols = prb_alloc->re_sf[1]; // Any subframe except 0 and 5 has maximum RE + nof_bits_e = nof_symbols * lte_mod_bits_x_symbol(mcs.mod); + + if (nof_bits > nof_bits_e) { + fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); + return LIBLTE_ERROR; + } + + if (nof_symbols > p->cell.nof_prb * MAX_PDSCH_RE(p->cell.cp)) { + fprintf(stderr, + "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", + nof_symbols, p->cell.nof_prb * MAX_PDSCH_RE(p->cell.cp), p->cell.nof_prb); + return LIBLTE_ERROR; + } + + if (p->cb_segm.C > p->max_cb) { + fprintf(stderr, "Codeblock segmentation returned more CBs (%d) than allocated (%d)\n", + p->cb_segm.C, p->max_cb); + return LIBLTE_ERROR; + } + ret = LIBLTE_SUCCESS; + } + return ret; +} + + /* Decode a transport block according to 36.212 5.3.2 * */ -int pdsch_decode_tb(pdsch_t *q, char *data, int tbs, int nb_e, int rv_idx) { +int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, + pdsch_harq_t *harq_process, uint32_t rv_idx) +{ char parity[24]; char *p_parity = parity; - unsigned int par_rx, par_tx; - int i; - int cb_len, rp, wp, rlen, F, n_e; - struct cb_segm cbs; + uint32_t par_rx, par_tx; + uint32_t i; + uint32_t cb_len, rp, wp, rlen, F, n_e; + float *e_bits = q->pdsch_e; + + if (q != NULL && + data != NULL && + nb_e < q->max_symbols * q->mod[3].nbits_x_symbol) + { - /* Compute CB segmentation for this TBS */ - codeblock_segmentation(&cbs, tbs); + rp = 0; + rp = 0; + wp = 0; + for (i = 0; i < harq_process->cb_segm.C; i++) { - rp = 0; - rp = 0; - wp = 0; - for (i = 0; i < cbs.C; i++) { + /* Get read/write lengths */ + if (i < harq_process->cb_segm.C - harq_process->cb_segm.C2) { + cb_len = harq_process->cb_segm.K1; + } else { + cb_len = harq_process->cb_segm.K2; + } + if (harq_process->cb_segm.C == 1) { + rlen = cb_len; + } else { + rlen = cb_len - 24; + } + if (i == 0) { + F = harq_process->cb_segm.F; + } else { + F = 0; + } - /* Get read/write lengths */ - if (i < cbs.C - cbs.C2) { - cb_len = cbs.K1; + if (i < harq_process->cb_segm.C - 1) { + n_e = nb_e / harq_process->cb_segm.C; + } else { + n_e = nb_e - rp; + } + + DEBUG("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i, + cb_len, rlen - F, wp, rp, F, n_e); + + /* Rate Unmatching */ + if (rm_turbo_rx(harq_process->pdsch_w_buff_f[i], harq_process->w_buff_size, + &e_bits[rp], n_e, + (float*) q->cb_out, 3 * cb_len + 12, rv_idx)) { + fprintf(stderr, "Error in rate matching\n"); + return LIBLTE_ERROR; + } + + /* Turbo Decoding */ + tdec_run_all(&q->decoder, (float*) q->cb_out, q->cb_in, TDEC_ITERATIONS, + cb_len); + + if (harq_process->cb_segm.C > 1) { + /* Check Codeblock CRC and stop early if incorrect */ + if (crc_checksum(&q->crc_cb, q->cb_in, cb_len)) { + INFO("Error in CB#%d\n",i); + return LIBLTE_ERROR; + } + } + + /* Copy data to another buffer, removing the Codeblock CRC */ + if (i < harq_process->cb_segm.C - 1) { + memcpy(&data[wp], &q->cb_in[F], (rlen - F) * sizeof(char)); + } else { + DEBUG("Last CB, appending parity: %d to %d from %d and 24 from %d\n", + rlen - F - 24, wp, F, rlen - 24); + /* Append Transport Block parity bits to the last CB */ + memcpy(&data[wp], &q->cb_in[F], (rlen - F - 24) * sizeof(char)); + memcpy(parity, &q->cb_in[rlen - 24], 24 * sizeof(char)); + } + + /* Set read/write pointers */ + wp += (rlen - F); + rp += n_e; + } + + DEBUG("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); + + // Compute transport block CRC + par_rx = crc_checksum(&q->crc_tb, data, tbs); + + // check parity bits + par_tx = bit_unpack(&p_parity, 24); + + if (!par_rx) { + printf("\n\tCAUTION!! Received all-zero transport block\n\n"); + } + + if (par_rx == par_tx) { + INFO("TB decoded OK\n",i); + return LIBLTE_SUCCESS; } else { - cb_len = cbs.K2; + INFO("Error in TB parity\n",i); + return LIBLTE_ERROR; } - if (cbs.C == 1) { - rlen = cb_len; - } else { - rlen = cb_len - 24; - } - if (i == 0) { - F = cbs.F; - } else { - F = 0; - } - - if (i < cbs.C - 1) { - n_e = nb_e / cbs.C; - } else { - n_e = nb_e - rp; - } - - INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i, - cb_len, rlen - F, wp, rp, F, n_e); - - /* Rate Unmatching */ - rm_turbo_rx(&q->rm_turbo, &q->pdsch_llr[rp], n_e, q->pdsch_rm_f, - 3 * cb_len + 12, rv_idx); - - /* Turbo Decoding */ - tdec_run_all(&q->decoder, q->pdsch_rm_f, q->cb_in_b, TDEC_ITERATIONS, - cb_len); - - if (cbs.C > 1) { - /* Check Codeblock CRC */ - //crc_attach(&q->crc_cb, q->pdsch_b[wp], cb_len); - } - - if (VERBOSE_ISDEBUG()) { - DEBUG("CB#%d Len=%d: ", i, cb_len); - vec_fprint_b(stdout, q->cb_in_b, cb_len); - } - - /* Copy data to another buffer, removing the Codeblock CRC */ - if (i < cbs.C - 1) { - memcpy(&data[wp], &q->cb_in_b[F], (rlen - F) * sizeof(char)); - } else { - INFO("Last CB, appending parity: %d to %d from %d and 24 from %d\n", - rlen - F - 24, wp, F, rlen - 24); - /* Append Transport Block parity bits to the last CB */ - memcpy(&data[wp], &q->cb_in_b[F], (rlen - F - 24) * sizeof(char)); - memcpy(parity, &q->cb_in_b[rlen - 24], 24 * sizeof(char)); - } - - /* Set read/write pointers */ - wp += (rlen - F); - rp += n_e; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; } - - INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); - - // Compute transport block CRC - par_rx = crc_checksum(&q->crc_tb, data, tbs); - - // check parity bits - par_tx = bit_unpack(&p_parity, 24); - - if (VERBOSE_ISDEBUG()) { - DEBUG("DATA: ", 0); - vec_fprint_b(stdout, data, tbs); - DEBUG("PARITY: ", 0); - vec_fprint_b(stdout, parity, 24); - } - - if (!par_rx) { - printf("\n\tCAUTION!! Received all-zero transport block\n\n"); - } - - return (par_rx != par_tx); } /** Decodes the PDSCH from the received symbols */ -int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, - int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc) { +int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, uint32_t subframe, + pdsch_harq_t *harq_process, uint32_t rv_idx) +{ /* Set pointers for layermapping & precoding */ - int i; + uint32_t i, n; cf_t *x[MAX_LAYERS]; - int nof_symbols, nof_bits, nof_bits_e; + uint32_t nof_symbols, nof_bits, nof_bits_e; + + if (q != NULL && + sf_symbols != NULL && + data != NULL && + subframe < 10 && + harq_process != NULL && + harq_process->mcs.mod > 0) + { + + nof_bits = harq_process->mcs.tbs; + nof_symbols = harq_process->prb_alloc.re_sf[subframe]; + nof_bits_e = nof_symbols * q->mod[harq_process->mcs.mod - 1].nbits_x_symbol; - nof_bits = mcs.tbs; - nof_symbols = prb_alloc->re_sf[nsubframe]; - nof_bits_e = nof_symbols * q->mod[mcs.mod - 1].nbits_x_symbol; - if (nof_bits > nof_bits_e) { - fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); - return -1; - } + INFO("Decoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e, rv_idx); - if (nof_symbols > q->max_symbols) { - fprintf(stderr, - "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", - nof_symbols, q->max_symbols, q->nof_prb); - return -1; - } + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pdsch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); + + /* extract symbols */ + n = pdsch_get(q, sf_symbols, q->pdsch_symbols[0], &harq_process->prb_alloc, subframe); + if (n != nof_symbols) { + fprintf(stderr, "Error expecting %d symbols but got %d\n", nof_symbols, n); + return LIBLTE_ERROR; + } - INFO( - "Decoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d\n", - nsubframe, mcs.mod, nof_bits, nof_symbols, nof_bits_e); + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + n = pdsch_get(q, ce[i], q->ce[i], &harq_process->prb_alloc, subframe); + if (n != nof_symbols) { + fprintf(stderr, "Error expecting %d symbols but got %d\n", nof_symbols, n); + return LIBLTE_ERROR; + } + } + + /* TODO: only diversity is supported */ + if (q->cell.nof_ports == 1) { + /* no need for layer demapping */ + predecoding_single_zf(q->pdsch_symbols[0], q->ce[0], q->pdsch_d, + nof_symbols); + } else { + predecoding_diversity_zf(q->pdsch_symbols[0], q->ce, x, q->cell.nof_ports, + nof_symbols); + layerdemap_diversity(x, q->pdsch_d, q->cell.nof_ports, + nof_symbols / q->cell.nof_ports); + } + + /* demodulate symbols + * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, + * thus we don't need tot set it in the LLRs normalization + */ + demod_soft_sigma_set(&q->demod, 2.0 / q->mod[harq_process->mcs.mod - 1].nbits_x_symbol); + demod_soft_table_set(&q->demod, &q->mod[harq_process->mcs.mod - 1]); + demod_soft_demodulate(&q->demod, q->pdsch_d, q->pdsch_e, nof_symbols); - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid subframe %d\n", nsubframe); - return -1; - } + /* descramble */ + scrambling_f_offset(&q->seq_pdsch[subframe], q->pdsch_e, 0, nof_bits_e); - /* number of layers equals number of ports */ - for (i = 0; i < q->nof_ports; i++) { - x[i] = q->pdsch_x[i]; - } - memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports)); - - /* extract symbols */ - pdsch_get(q, sf_symbols, q->pdsch_symbols[0], prb_alloc, nsubframe); - - /* extract channel estimates */ - for (i = 0; i < q->nof_ports; i++) { - pdsch_get(q, ce[i], q->ce[i], prb_alloc, nsubframe); - } - - /* TODO: only diversity is supported */ - if (q->nof_ports == 1) { - /* no need for layer demapping */ - predecoding_single_zf(q->pdsch_symbols[0], q->ce[0], q->pdsch_d, - nof_symbols); + return pdsch_decode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx); } else { - predecoding_diversity_zf(q->pdsch_symbols[0], q->ce, x, q->nof_ports, - nof_symbols); - layerdemap_diversity(x, q->pdsch_d, q->nof_ports, - nof_symbols / q->nof_ports); + return LIBLTE_ERROR_INVALID_INPUTS; } - - /* demodulate symbols */ - demod_soft_sigma_set(&q->demod, 2.0 / q->mod[mcs.mod - 1].nbits_x_symbol); - demod_soft_table_set(&q->demod, &q->mod[mcs.mod - 1]); - demod_soft_demodulate(&q->demod, q->pdsch_d, q->pdsch_llr, nof_symbols); - - /* descramble */ - scrambling_f_offset(&q->seq_pdsch[nsubframe], q->pdsch_llr, 0, nof_bits_e); - - return pdsch_decode_tb(q, data, nof_bits, nof_bits_e, 0); } /* Encode a transport block according to 36.212 5.3.2 * */ -void pdsch_encode_tb(pdsch_t *q, char *data, int tbs, int nb_e, int rv_idx) { +int pdsch_encode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, + pdsch_harq_t *harq_process, uint32_t rv_idx) +{ char parity[24]; char *p_parity = parity; - unsigned int par; - int i; - int cb_len, rp, wp, rlen, F, n_e; - struct cb_segm cbs; + uint32_t par; + uint32_t i; + uint32_t cb_len, rp, wp, rlen, F, n_e; + char *e_bits = q->pdsch_e; + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + data != NULL && + nb_e < q->max_symbols * q->mod[3].nbits_x_symbol) + { + + if (q->rnti_is_set) { + if (rv_idx == 0) { + /* Compute transport block CRC */ + par = crc_checksum(&q->crc_tb, data, tbs); - /* Compute CB segmentation */ - codeblock_segmentation(&cbs, tbs); + /* parity bits will be appended later */ + bit_pack(par, &p_parity, 24); - /* Compute transport block CRC */ - par = crc_checksum(&q->crc_tb, data, tbs); + if (VERBOSE_ISDEBUG()) { + DEBUG("DATA: ", 0); + vec_fprint_b(stdout, data, tbs); + DEBUG("PARITY: ", 0); + vec_fprint_b(stdout, parity, 24); + } - /* parity bits will be appended later */ - bit_pack(par, &p_parity, 24); + /* Add filler bits to the new data buffer */ + for (i = 0; i < harq_process->cb_segm.F; i++) { + q->cb_in[i] = LTE_NULL_BIT; + } + } + + wp = 0; + rp = 0; + for (i = 0; i < harq_process->cb_segm.C; i++) { - if (VERBOSE_ISDEBUG()) { - DEBUG("DATA: ", 0); - vec_fprint_b(stdout, data, tbs); - DEBUG("PARITY: ", 0); - vec_fprint_b(stdout, parity, 24); - } + /* Get read lengths */ + if (i < harq_process->cb_segm.C - harq_process->cb_segm.C2) { + cb_len = harq_process->cb_segm.K1; + } else { + cb_len = harq_process->cb_segm.K2; + } + if (harq_process->cb_segm.C > 1) { + rlen = cb_len - 24; + } else { + rlen = cb_len; + } + if (i == 0) { + F = harq_process->cb_segm.F; + } else { + F = 0; + } - /* Add filler bits to the new data buffer */ - for (i = 0; i < cbs.F; i++) { - q->cb_in_b[i] = LTE_NULL_BIT; - } + if (i < harq_process->cb_segm.C - 1) { + n_e = nb_e / harq_process->cb_segm.C; + } else { + n_e = nb_e - wp; + } - wp = 0; - rp = 0; - for (i = 0; i < cbs.C; i++) { + INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i, + cb_len, rlen - F, wp, rp, F, n_e); - /* Get read lengths */ - if (i < cbs.C - cbs.C2) { - cb_len = cbs.K1; + if (rv_idx == 0) { + /* Copy data to another buffer, making space for the Codeblock CRC */ + if (i < harq_process->cb_segm.C - 1) { + memcpy(&q->cb_in[F], &data[rp], (rlen - F) * sizeof(char)); + } else { + INFO("Last CB, appending parity: %d from %d and 24 to %d\n", + rlen - F - 24, rp, rlen - 24); + /* Append Transport Block parity bits to the last CB */ + memcpy(&q->cb_in[F], &data[rp], (rlen - F - 24) * sizeof(char)); + memcpy(&q->cb_in[rlen - 24], parity, 24 * sizeof(char)); + } + if (harq_process->cb_segm.C > 1) { + /* Attach Codeblock CRC */ + crc_attach(&q->crc_cb, q->cb_in, rlen); + } + if (VERBOSE_ISDEBUG()) { + DEBUG("CB#%d Len=%d: ", i, cb_len); + vec_fprint_b(stdout, q->cb_in, cb_len); + } + /* Turbo Encoding */ + tcod_encode(&q->encoder, q->cb_in, (char*) q->cb_out, cb_len); + } + + /* Rate matching */ + if (rm_turbo_tx(harq_process->pdsch_w_buff_c[i], harq_process->w_buff_size, + (char*) q->cb_out, 3 * cb_len + 12, + &e_bits[wp], n_e, rv_idx)) + { + fprintf(stderr, "Error in rate matching\n"); + return LIBLTE_ERROR; + } + + /* Set read/write pointers */ + rp += (rlen - F); + wp += n_e; + } + + INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); + + ret = LIBLTE_SUCCESS; } else { - cb_len = cbs.K2; + fprintf(stderr, "Must call pdsch_set_rnti() to set the encoder/decoder RNTI\n"); } - if (cbs.C > 1) { - rlen = cb_len - 24; - } else { - rlen = cb_len; - } - if (i == 0) { - F = cbs.F; - } else { - F = 0; - } - - if (i < cbs.C - 1) { - n_e = nb_e / cbs.C; - } else { - n_e = nb_e - wp; - } - - INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i, - cb_len, rlen - F, wp, rp, F, n_e); - - /* Copy data to another buffer, making space for the Codeblock CRC */ - if (i < cbs.C - 1) { - memcpy(&q->cb_in_b[F], &data[rp], (rlen - F) * sizeof(char)); - } else { - INFO("Last CB, appending parity: %d from %d and 24 to %d\n", - rlen - F - 24, rp, rlen - 24); - /* Append Transport Block parity bits to the last CB */ - memcpy(&q->cb_in_b[F], &data[rp], (rlen - F - 24) * sizeof(char)); - memcpy(&q->cb_in_b[rlen - 24], parity, 24 * sizeof(char)); - } - - if (cbs.C > 1) { - /* Attach Codeblock CRC */ - crc_attach(&q->crc_cb, q->cb_in_b, rlen); - } - - if (VERBOSE_ISDEBUG()) { - DEBUG("CB#%d Len=%d: ", i, cb_len); - vec_fprint_b(stdout, q->cb_in_b, cb_len); - } - - /* Turbo Encoding */ - tcod_encode(&q->encoder, q->cb_in_b, q->cb_out_b, cb_len); - - /* Rate matching */ - rm_turbo_tx(&q->rm_turbo, q->cb_out_b, 3 * cb_len + 12, - &q->pdsch_e_bits[wp], n_e, rv_idx); - - /* Set read/write pointers */ - rp += (rlen - F); - wp += n_e; - } - - INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); + } + return ret; } /** Converts the PDSCH data bits to symbols mapped to the slot ready for transmission */ -int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], - int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc) { +int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], uint32_t subframe, + pdsch_harq_t *harq_process, uint32_t rv_idx) +{ int i; - int nof_symbols, nof_bits, nof_bits_e; + uint32_t nof_symbols, nof_bits, nof_bits_e; /* Set pointers for layermapping & precoding */ cf_t *x[MAX_LAYERS]; + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + data != NULL && + subframe < 10 && + harq_process != NULL) + { - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid subframe %d\n", nsubframe); - return -1; - } + if (q->rnti_is_set) { + for (i=0;icell.nof_ports;i++) { + if (sf_symbols[i] == NULL) { + return LIBLTE_ERROR_INVALID_INPUTS; + } + } + + nof_bits = harq_process->mcs.tbs; + nof_symbols = harq_process->prb_alloc.re_sf[subframe]; + nof_bits_e = nof_symbols * q->mod[harq_process->mcs.mod - 1].nbits_x_symbol; - nof_bits = mcs.tbs; - nof_symbols = prb_alloc->re_sf[nsubframe]; - nof_bits_e = nof_symbols * q->mod[mcs.mod - 1].nbits_x_symbol; + if (harq_process->mcs.tbs == 0) { + return LIBLTE_ERROR_INVALID_INPUTS; + } + + if (nof_bits > nof_bits_e) { + fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); + return LIBLTE_ERROR_INVALID_INPUTS; + } - if (nof_bits > nof_bits_e) { - fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); - return -1; - } + if (nof_symbols > q->max_symbols) { + fprintf(stderr, + "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", + nof_symbols, q->max_symbols, q->cell.nof_prb); + return LIBLTE_ERROR_INVALID_INPUTS; + } - if (nof_symbols > q->max_symbols) { - fprintf(stderr, - "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", - nof_symbols, q->max_symbols, q->nof_prb); - return -1; - } + INFO("Encoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e, rv_idx); - INFO( - "Encoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d\n", - nsubframe, mcs.mod, nof_bits, nof_symbols, nof_bits_e); + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pdsch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); - /* number of layers equals number of ports */ - for (i = 0; i < q->nof_ports; i++) { - x[i] = q->pdsch_x[i]; - } - memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports)); + if (pdsch_encode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx)) { + fprintf(stderr, "Error encoding TB\n"); + return LIBLTE_ERROR; + } + + scrambling_b_offset(&q->seq_pdsch[subframe], (char*) q->pdsch_e, 0, nof_bits_e); - pdsch_encode_tb(q, data, nof_bits, nof_bits_e, 0); + mod_modulate(&q->mod[harq_process->mcs.mod - 1], (char*) q->pdsch_e, q->pdsch_d, nof_bits_e); - scrambling_b_offset(&q->seq_pdsch[nsubframe], q->pdsch_e_bits, 0, nof_bits_e); + /* TODO: only diversity supported */ + if (q->cell.nof_ports > 1) { + layermap_diversity(q->pdsch_d, x, q->cell.nof_ports, nof_symbols); + precoding_diversity(x, q->pdsch_symbols, q->cell.nof_ports, + nof_symbols / q->cell.nof_ports); + } else { + memcpy(q->pdsch_symbols[0], q->pdsch_d, nof_symbols * sizeof(cf_t)); + } - mod_modulate(&q->mod[mcs.mod - 1], q->pdsch_e_bits, q->pdsch_d, nof_bits_e); - - /* TODO: only diversity supported */ - if (q->nof_ports > 1) { - layermap_diversity(q->pdsch_d, x, q->nof_ports, nof_symbols); - precoding_diversity(x, q->pdsch_symbols, q->nof_ports, - nof_symbols / q->nof_ports); - } else { - memcpy(q->pdsch_symbols[0], q->pdsch_d, nof_symbols * sizeof(cf_t)); - } - - /* mapping to resource elements */ - for (i = 0; i < q->nof_ports; i++) { - pdsch_put(q, q->pdsch_symbols[i], sf_symbols[i], prb_alloc, nsubframe); - } - return 0; + /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { + pdsch_put(q, q->pdsch_symbols[i], sf_symbols[i], &harq_process->prb_alloc, subframe); + } + ret = LIBLTE_SUCCESS; + } else { + fprintf(stderr, "Must call pdsch_set_rnti() to set the encoder/decoder RNTI\n"); + } + } + return ret; } - + \ No newline at end of file diff --git a/lte/phy/lib/phch/src/phich.c b/lte/phy/lib/phch/src/phich.c index 31f282611..d27765269 100644 --- a/lte/phy/lib/phch/src/phich.c +++ b/lte/phy/lib/phch/src/phich.c @@ -49,46 +49,49 @@ const cf_t w_normal[PHICH_NORM_NSEQUENCES][4] = { { 1, 1, 1, 1 }, const cf_t w_ext[PHICH_EXT_NSEQUENCES][2] = { { 1, 1 }, { 1, -1 }, { I, I }, { I, -I } }; -bool phich_exists(int nframe, int nslot) { - return true; -} -int phich_ngroups(phich_t *q) { +uint32_t phich_ngroups(phich_t *q) { return regs_phich_ngroups(q->regs); } -void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS_CTRL]) { +void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS]) { int i; - for (i = 0; i < MAX_PORTS_CTRL; i++) { + for (i = 0; i < MAX_PORTS; i++) { regs_phich_reset(q->regs, slot_symbols[i]); } } /** Initializes the phich channel receiver */ -int phich_init(phich_t *q, regs_t *regs, int cell_id, int nof_prb, - int nof_tx_ports, lte_cp_t cp) { - int ret = -1; - bzero(q, sizeof(phich_t)); - q->cp = cp; - q->regs = regs; - q->nof_prb = nof_prb; - q->nof_tx_ports = nof_tx_ports; +int phich_init(phich_t *q, regs_t *regs, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + regs != NULL && + lte_cell_isvalid(&cell)) + { - if (modem_table_std(&q->mod, LTE_BPSK, false)) { - goto clean; - } + bzero(q, sizeof(phich_t)); + ret = LIBLTE_ERROR; + + q->cell = cell; + q->regs = regs; - demod_hard_init(&q->demod); - demod_hard_table_set(&q->demod, LTE_BPSK); - - for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) { - if (sequence_phich(&q->seq_phich[nsf], 2 * nsf, cell_id)) { + if (modem_table_lte(&q->mod, LTE_BPSK, false)) { goto clean; } - } - ret = 0; - clean: if (ret == -1) { + demod_hard_init(&q->demod); + demod_hard_table_set(&q->demod, LTE_BPSK); + + for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) { + if (sequence_phich(&q->seq_phich[nsf], 2 * nsf, q->cell.id)) { + goto clean; + } + } + ret = LIBLTE_SUCCESS; + } + clean: + if (ret == LIBLTE_ERROR) { phich_free(q); } return ret; @@ -104,7 +107,7 @@ void phich_free(phich_t *q) { /* Decodes ACK * */ -char phich_ack_decode(char bits[PHICH_NBITS], int *distance) { +char phich_ack_decode(char bits[PHICH_NBITS], uint32_t *distance) { int i, n; n = 0; @@ -136,39 +139,43 @@ void phich_ack_encode(char ack, char bits[PHICH_NBITS]) { * * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ -int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], - int ngroup, int nseq, int nsubframe, char *ack, int *distance) { +int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], + uint32_t ngroup, uint32_t nseq, uint32_t subframe, char *ack, uint32_t *distance) { /* Set pointers for layermapping & precoding */ int i, j; cf_t *x[MAX_LAYERS]; cf_t *ce_precoding[MAX_PORTS]; - - DEBUG("Decoding PHICH Ngroup: %d, Nseq: %d\n", ngroup, nseq); - - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid nslot %d\n", nsubframe); - return -1; + + if (q == NULL || slot_symbols == NULL) { + return LIBLTE_ERROR_INVALID_INPUTS; } - if (CP_ISEXT(q->cp)) { - if (nseq < 0 || nseq > PHICH_EXT_NSEQUENCES) { + if (subframe >= NSUBFRAMES_X_FRAME) { + fprintf(stderr, "Invalid nslot %d\n", subframe); + return LIBLTE_ERROR_INVALID_INPUTS; + } + + if (CP_ISEXT(q->cell.cp)) { + if (nseq >= PHICH_EXT_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } } else { - if (nseq < 0 || nseq > PHICH_NORM_NSEQUENCES) { + if (nseq >= PHICH_NORM_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } } if (ngroup >= regs_phich_ngroups(q->regs)) { fprintf(stderr, "Invalid ngroup %d\n", ngroup); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } + DEBUG("Decoding PHICH Ngroup: %d, Nseq: %d\n", ngroup, nseq); + /* number of layers equals number of ports */ - for (i = 0; i < MAX_PORTS_CTRL; i++) { + for (i = 0; i < MAX_PORTS; i++) { x[i] = q->phich_x[i]; } for (i = 0; i < MAX_PORTS; i++) { @@ -179,34 +186,34 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], if (PHICH_MAX_NSYMB != regs_phich_get(q->regs, slot_symbols, q->phich_symbols[0], ngroup)) { fprintf(stderr, "There was an error getting the phich symbols\n"); - return -1; + return LIBLTE_ERROR; } /* extract channel estimates */ - for (i = 0; i < q->nof_tx_ports; i++) { + for (i = 0; i < q->cell.nof_ports; i++) { if (PHICH_MAX_NSYMB != regs_phich_get(q->regs, ce[i], q->ce[i], ngroup)) { fprintf(stderr, "There was an error getting the phich symbols\n"); - return -1; + return LIBLTE_ERROR; } } /* in control channels, only diversity is supported */ - if (q->nof_tx_ports == 1) { + if (q->cell.nof_ports == 1) { /* no need for layer demapping */ predecoding_single_zf(q->phich_symbols[0], q->ce[0], q->phich_d0, PHICH_MAX_NSYMB); } else { predecoding_diversity_zf(q->phich_symbols[0], ce_precoding, x, - q->nof_tx_ports, PHICH_MAX_NSYMB); - layerdemap_diversity(x, q->phich_d0, q->nof_tx_ports, - PHICH_MAX_NSYMB / q->nof_tx_ports); + q->cell.nof_ports, PHICH_MAX_NSYMB); + layerdemap_diversity(x, q->phich_d0, q->cell.nof_ports, + PHICH_MAX_NSYMB / q->cell.nof_ports); } DEBUG("Recv!!: \n", 0); DEBUG("d0: ", 0); if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d0, PHICH_MAX_NSYMB); - if (CP_ISEXT(q->cp)) { + if (CP_ISEXT(q->cell.cp)) { if (ngroup % 2) { for (i = 0; i < PHICH_EXT_MSYMB / 2; i++) { q->phich_d[2 * i + 0] = q->phich_d0[4 * i + 2]; @@ -226,10 +233,10 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d, PHICH_EXT_MSYMB); - scrambling_c(&q->seq_phich[nsubframe], q->phich_d); + scrambling_c(&q->seq_phich[subframe], q->phich_d); /* De-spreading */ - if (CP_ISEXT(q->cp)) { + if (CP_ISEXT(q->cell.cp)) { for (i = 0; i < PHICH_NBITS; i++) { q->phich_z[i] = 0; for (j = 0; j < PHICH_EXT_NSF; j++) { @@ -257,43 +264,48 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], *ack = phich_ack_decode(q->data, distance); } - return 0; + return LIBLTE_SUCCESS; } /** Encodes ACK/NACK bits, modulates and inserts into resource. * The parameter ack is an array of phich_ngroups() pointers to buffers of nof_sequences chars */ -int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, - cf_t *slot_symbols[MAX_PORTS_CTRL]) { +int phich_encode(phich_t *q, char ack, uint32_t ngroup, uint32_t nseq, uint32_t subframe, + cf_t *slot_symbols[MAX_PORTS]) { int i; - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid nslot %d\n", nsubframe); - return -1; + if (q == NULL || slot_symbols == NULL) { + return LIBLTE_ERROR_INVALID_INPUTS; } - if (CP_ISEXT(q->cp)) { - if (nseq < 0 || nseq > PHICH_EXT_NSEQUENCES) { + if (subframe >= NSUBFRAMES_X_FRAME) { + fprintf(stderr, "Invalid nslot %d\n", subframe); + return LIBLTE_ERROR_INVALID_INPUTS; + } + + if (CP_ISEXT(q->cell.cp)) { + if (nseq >= PHICH_EXT_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } } else { - if (nseq < 0 || nseq > PHICH_NORM_NSEQUENCES) { + if (nseq >= PHICH_NORM_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } } if (ngroup >= regs_phich_ngroups(q->regs)) { fprintf(stderr, "Invalid ngroup %d\n", ngroup); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } + /* Set pointers for layermapping & precoding */ cf_t *x[MAX_LAYERS]; cf_t *symbols_precoding[MAX_PORTS]; /* number of layers equals number of ports */ - for (i = 0; i < q->nof_tx_ports; i++) { + for (i = 0; i < q->cell.nof_ports; i++) { x[i] = q->phich_x[i]; } for (i = 0; i < MAX_PORTS; i++) { @@ -310,7 +322,7 @@ int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, vec_fprint_c(stdout, q->phich_z, PHICH_NBITS); /* Spread with w */ - if (CP_ISEXT(q->cp)) { + if (CP_ISEXT(q->cell.cp)) { for (i = 0; i < PHICH_EXT_MSYMB; i++) { q->phich_d[i] = w_ext[nseq][i % PHICH_EXT_NSF] * q->phich_z[i / PHICH_EXT_NSF]; @@ -326,10 +338,10 @@ int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d, PHICH_EXT_MSYMB); - scrambling_c(&q->seq_phich[nsubframe], q->phich_d); + scrambling_c(&q->seq_phich[subframe], q->phich_d); /* align to REG */ - if (CP_ISEXT(q->cp)) { + if (CP_ISEXT(q->cell.cp)) { if (ngroup % 2) { for (i = 0; i < PHICH_EXT_MSYMB / 2; i++) { q->phich_d0[4 * i + 0] = 0; @@ -354,24 +366,24 @@ int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, vec_fprint_c(stdout, q->phich_d0, PHICH_MAX_NSYMB); /* layer mapping & precoding */ - if (q->nof_tx_ports > 1) { - layermap_diversity(q->phich_d0, x, q->nof_tx_ports, PHICH_MAX_NSYMB); - precoding_diversity(x, symbols_precoding, q->nof_tx_ports, - PHICH_MAX_NSYMB / q->nof_tx_ports); + if (q->cell.nof_ports > 1) { + layermap_diversity(q->phich_d0, x, q->cell.nof_ports, PHICH_MAX_NSYMB); + precoding_diversity(x, symbols_precoding, q->cell.nof_ports, + PHICH_MAX_NSYMB / q->cell.nof_ports); /**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */ } else { memcpy(q->phich_symbols[0], q->phich_d0, PHICH_MAX_NSYMB * sizeof(cf_t)); } /* mapping to resource elements */ - for (i = 0; i < q->nof_tx_ports; i++) { + for (i = 0; i < q->cell.nof_ports; i++) { if (regs_phich_add(q->regs, q->phich_symbols[i], ngroup, slot_symbols[i]) < 0) { fprintf(stderr, "Error putting PCHICH resource elements\n"); - return -1; + return LIBLTE_ERROR; } } - return 0; + return LIBLTE_SUCCESS; } diff --git a/lte/phy/lib/phch/src/prb.c b/lte/phy/lib/phch/src/prb.c index 527fb0716..3bd597af6 100644 --- a/lte/phy/lib/phch/src/prb.c +++ b/lte/phy/lib/phch/src/prb.c @@ -33,14 +33,14 @@ #include "liblte/phy/common/phy_common.h" void prb_cp_ref(cf_t **input, cf_t **output, int offset, int nof_refs, - int nof_prb, bool advance_output) { + int nof_intervals, bool advance_output) { int i; int ref_interval = ((RE_X_RB / nof_refs) - 1); memcpy(*output, *input, offset * sizeof(cf_t)); *input += offset; *output += offset; - for (i = 0; i < nof_refs * nof_prb - 1; i++) { + for (i = 0; i < nof_intervals - 1; i++) { if (advance_output) { (*output)++; } else { @@ -70,18 +70,18 @@ void prb_cp(cf_t **input, cf_t **output, int nof_prb) { void prb_cp_half(cf_t **input, cf_t **output, int nof_prb) { - memcpy(*output, *input, sizeof(cf_t) * RE_X_RB * nof_prb / 2); - *input += nof_prb * RE_X_RB / 2; - *output += nof_prb * RE_X_RB / 2; + memcpy(*output, *input, sizeof(cf_t) * RE_X_RB * nof_prb / 2); + *input += nof_prb * RE_X_RB / 2; + *output += nof_prb * RE_X_RB / 2; } void prb_put_ref_(cf_t **input, cf_t **output, int offset, int nof_refs, - int nof_prb) { - prb_cp_ref(input, output, offset, nof_refs, nof_prb, false); + int nof_intervals) { + prb_cp_ref(input, output, offset, nof_refs, nof_intervals, false); } void prb_get_ref_(cf_t **input, cf_t **output, int offset, int nof_refs, - int nof_prb) { - prb_cp_ref(input, output, offset, nof_refs, nof_prb, true); + int nof_intervals) { + prb_cp_ref(input, output, offset, nof_refs, nof_intervals, true); } diff --git a/lte/phy/lib/phch/src/prb.h b/lte/phy/lib/phch/src/prb.h index 9df8f1bf5..0ca10fd5a 100644 --- a/lte/phy/lib/phch/src/prb.h +++ b/lte/phy/lib/phch/src/prb.h @@ -29,10 +29,10 @@ typedef _Complex float cf_t; void prb_cp_ref(cf_t **input, cf_t **output, int offset, int nof_refs, - int nof_prb, bool advance_input); + int nof_intervals, bool advance_input); void prb_cp(cf_t **input, cf_t **output, int nof_prb); void prb_cp_half(cf_t **input, cf_t **output, int nof_prb); void prb_put_ref_(cf_t **input, cf_t **output, int offset, int nof_refs, - int nof_prb); + int nof_intervals); void phch_get_prb_ref(cf_t **input, cf_t **output, int offset, int nof_refs, - int nof_prb); + int nof_intervals); diff --git a/lte/phy/lib/phch/src/ra.c b/lte/phy/lib/phch/src/ra.c index db9d4df8c..f48ff6324 100644 --- a/lte/phy/lib/phch/src/ra.c +++ b/lte/phy/lib/phch/src/ra.c @@ -41,23 +41,23 @@ #define min(a,b) (a= nof_prb / 2 - 3 && prb_idx <= nof_prb / 2 + 3)) { - if (nsubframe == 0) { - if (nslot == 0) { + if (subframe == 0) { + if (slot == 0) { re = (CP_NSYMB(cp) - nof_ctrl_symbols - 2) * RE_X_RB; } else { if (CP_ISEXT(cp)) { @@ -67,16 +67,16 @@ int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb, re = (CP_NSYMB(cp) - 4) * RE_X_RB + 2 * nof_ports; } } - } else if (nsubframe == 5) { - if (nslot == 0) { + } else if (subframe == 5) { + if (slot == 0) { re = (CP_NSYMB(cp) - nof_ctrl_symbols - 2) * RE_X_RB; } } if ((nof_prb % 2) && (prb_idx == nof_prb / 2 - 3 || prb_idx == nof_prb / 2 + 3)) { - if (nslot == 0) { + if (slot == 0) { re += 2 * RE_X_RB / 2; - } else if (nsubframe == 0) { + } else if (subframe == 0) { re += 4 * RE_X_RB / 2 - nof_ports; if (CP_ISEXT(cp)) { re -= nof_ports > 2 ? 2 : nof_ports; @@ -90,10 +90,10 @@ int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb, switch (nof_ports) { case 1: case 2: - re -= 2 * (nslot + 1) * nof_ports; + re -= 2 * (slot + 1) * nof_ports; break; case 4: - if (nslot == 1) { + if (slot == 1) { re -= 12; } else { re -= 4; @@ -109,14 +109,15 @@ int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb, } /* Computes the number of RE for each PRB in the prb_dist structure */ -void ra_prb_get_re(ra_prb_t *prb_dist, int nof_prb, int nof_ports, - int nof_ctrl_symbols, lte_cp_t cp) { - int i, j, s; +void ra_prb_get_re_dl(ra_prb_t *prb_dist, uint32_t nof_prb, uint32_t nof_ports, + uint32_t nof_ctrl_symbols, lte_cp_t cp) { + uint32_t i, j, s; /* Set start symbol according to Section 7.1.6.4 in 36.213 */ prb_dist->lstart = nof_ctrl_symbols; // Compute number of RE per subframe for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { + prb_dist->re_sf[i] = 0; for (s = 0; s < 2; s++) { for (j = 0; j < prb_dist->slot[s].nof_prb; j++) { prb_dist->re_sf[i] += ra_re_x_prb(i, s, prb_dist->slot[s].prb_idx[j], @@ -138,25 +139,25 @@ void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb) { } /** Compute PRB allocation for Downlink as defined in 8.1 of 36.213 */ -int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb) { +int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, uint32_t nof_prb) { int i; if (ra->type2_alloc.mode != t2_loc) { fprintf(stderr, "Uplink only accepts type2 localized scheduling\n"); - return -1; + return LIBLTE_ERROR; } for (i = 0; i < ra->type2_alloc.L_crb; i++) { prb->prb_idx[i] = i + ra->type2_alloc.RB_start; prb->nof_prb++; } - return 0; + return LIBLTE_SUCCESS; } /** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 */ -int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, int nof_prb) { +int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, uint32_t nof_prb) { int i, j; uint32_t bitmask; - int P = ra_type0_P(nof_prb); - int n_rb_rbg_subset, n_rb_type1; + uint32_t P = ra_type0_P(nof_prb); + uint32_t n_rb_rbg_subset, n_rb_type1; bzero(prb_dist, sizeof(ra_prb_t)); switch (ra->alloc_type) { @@ -166,8 +167,10 @@ int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, int nof_prb) { for (i = 0; i < nb; i++) { if (bitmask & (1 << (nb - i - 1))) { for (j = 0; j < P; j++) { - prb_dist->slot[0].prb_idx[prb_dist->slot[0].nof_prb] = i * P + j; - prb_dist->slot[0].nof_prb++; + if (i*P+j < nof_prb) { + prb_dist->slot[0].prb_idx[prb_dist->slot[0].nof_prb] = i * P + j; + prb_dist->slot[0].nof_prb++; + } } } } @@ -257,35 +260,33 @@ int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, int nof_prb) { } break; default: - return -1; + return LIBLTE_ERROR; } - return 0; + return LIBLTE_SUCCESS; } /* Returns the number of allocated PRB for Uplink */ -int ra_nprb_ul(ra_pusch_t *ra, int nof_prb) { +uint32_t ra_nprb_ul(ra_pusch_t *ra, uint32_t nof_prb) { return ra->type2_alloc.L_crb; } /* Returns the number of allocated PRB for Downlink */ -int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb) { - int nprb; - int nof_rbg, P; +uint32_t ra_nprb_dl(ra_pdsch_t *ra, uint32_t nof_prb) { + uint32_t nprb; + uint32_t nof_rbg, P; switch (ra->alloc_type) { case alloc_type0: // Get the number of allocated RBG except the last RBG nof_rbg = bit_count(ra->type0_alloc.rbg_bitmask & 0xFFFFFFFE); P = ra_type0_P(nof_prb); - if (nof_rbg > (int) ceilf((float) nof_prb / P)) { - fprintf(stderr, "Number of RGB (%d) can not exceed %d\n", nof_prb, - (int) ceilf((float) nof_prb / P)); - return -1; + if (nof_rbg > (uint32_t) ceilf((float) nof_prb / P)) { + nof_rbg = (uint32_t) ceilf((float) nof_prb / P) - 1; } nprb = nof_rbg * P; // last RBG may have smaller size. Add if set - int P_last = (nof_prb % P); + uint32_t P_last = (nof_prb % P); if (!P_last) P_last = P; nprb += P_last * (ra->type0_alloc.rbg_bitmask & 1); @@ -295,20 +296,20 @@ int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb) { if (nprb > ra_type1_N_rb(nof_prb)) { fprintf(stderr, "Number of RB (%d) can not exceed %d\n", nprb, ra_type1_N_rb(nof_prb)); - return -1; + return LIBLTE_ERROR; } break; case alloc_type2: nprb = ra->type2_alloc.L_crb; break; default: - return -1; + return LIBLTE_ERROR; } return nprb; } /* RBG size for type0 scheduling as in table 7.1.6.1-1 of 36.213 */ -int ra_type0_P(int nof_prb) { +uint32_t ra_type0_P(uint32_t nof_prb) { if (nof_prb <= 10) { return 1; } else if (nof_prb <= 26) { @@ -321,15 +322,15 @@ int ra_type0_P(int nof_prb) { } /* Returns N_rb_type1 according to section 7.1.6.2 */ -int ra_type1_N_rb(int nof_prb) { - int P = ra_type0_P(nof_prb); - return (int) ceilf((float) nof_prb / P) - (int) ceilf(log2f((float) P)) - 1; +uint32_t ra_type1_N_rb(uint32_t nof_prb) { + uint32_t P = ra_type0_P(nof_prb); + return (uint32_t) ceilf((float) nof_prb / P) - (uint32_t) ceilf(log2f((float) P)) - 1; } /* Convert Type2 scheduling L_crb and RB_start to RIV value */ -uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb) { +uint32_t ra_type2_to_riv(uint32_t L_crb, uint32_t RB_start, uint32_t nof_prb) { uint32_t riv; - if (L_crb <= (int) nof_prb / 2) { + if (L_crb <= 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; @@ -338,10 +339,10 @@ uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb) { } /* Convert Type2 scheduling RIV value to L_crb and RB_start values */ -void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, - int nof_prb, int nof_vrb) { - *L_crb = (int) (riv / nof_prb) + 1; - *RB_start = riv % nof_prb; +void ra_type2_from_riv(uint32_t riv, uint32_t *L_crb, uint32_t *RB_start, + uint32_t nof_prb, uint32_t nof_vrb) { + *L_crb = (uint32_t) (riv / nof_prb) + 1; + *RB_start = (uint32_t) (riv % nof_prb); if (*L_crb > nof_vrb - *RB_start) { *L_crb = nof_prb - (int) (riv / nof_prb) + 1; *RB_start = nof_prb - riv % nof_prb - 1; @@ -349,7 +350,7 @@ void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, } /* Table 6.2.3.2-1 in 36.211 */ -int ra_type2_ngap(int nof_prb, bool ngap_is_1) { +uint32_t ra_type2_ngap(uint32_t nof_prb, bool ngap_is_1) { if (nof_prb <= 10) { return nof_prb / 2; } else if (nof_prb == 11) { @@ -372,7 +373,7 @@ int ra_type2_ngap(int nof_prb, bool ngap_is_1) { } /* Table 7.1.6.3-1 in 36.213 */ -int ra_type2_n_rb_step(int nof_prb) { +uint32_t ra_type2_n_rb_step(uint32_t nof_prb) { if (nof_prb < 50) { return 2; } else { @@ -381,143 +382,96 @@ int ra_type2_n_rb_step(int nof_prb) { } /* as defined in 6.2.3.2 of 36.211 */ -int ra_type2_n_vrb_dl(int nof_prb, bool ngap_is_1) { - int ngap = ra_type2_ngap(nof_prb, ngap_is_1); +uint32_t ra_type2_n_vrb_dl(uint32_t nof_prb, bool ngap_is_1) { + uint32_t ngap = ra_type2_ngap(nof_prb, ngap_is_1); if (ngap_is_1) { return 2 * (ngap < (nof_prb - ngap) ? ngap : nof_prb - ngap); } else { - return ((int) nof_prb / ngap) * 2 * ngap; - } -} - -/* Converts ra_mcs_t structure to MCS index for both Uplink and Downlink */ -uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs) { - switch (mcs->mod) { - case QPSK: - return mcs->tbs_idx; - case QAM16: - return mcs->tbs_idx + 1; - case QAM64: - return mcs->tbs_idx + 2; - default: - return 0; + return ((uint32_t) nof_prb / ngap) * 2 * ngap; } } /* Converts MCS index to ra_mcs_t structure for Downlink as defined inTable 7.1.7.1-1 on 36.213 */ -int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs) { - if (idx < 10) { - mcs->mod = QPSK; - mcs->tbs_idx = idx; - } else if (idx < 17) { - mcs->mod = QAM16; - mcs->tbs_idx = idx - 1; - } else if (idx < 29) { - mcs->mod = QAM64; - mcs->tbs_idx = idx - 2; - } else if (idx == 29) { - mcs->mod = QPSK; - mcs->tbs_idx = 0; - } else if (idx == 30) { - mcs->mod = QAM16; - mcs->tbs_idx = 0; - } else if (idx == 31) { - mcs->mod = QAM64; - mcs->tbs_idx = 0; +int ra_mcs_from_idx_dl(uint32_t mcs_idx, uint32_t nof_prb, ra_mcs_t *mcs) { + if (mcs_idx < 10) { + mcs->mod = LTE_QPSK; + mcs->tbs = ra_tbs_from_idx(mcs_idx, nof_prb); + } else if (mcs_idx < 17) { + mcs->mod = LTE_QAM16; + mcs->tbs = ra_tbs_from_idx(mcs_idx - 1, nof_prb); + } else if (mcs_idx < 29) { + mcs->mod = LTE_QAM64; + mcs->tbs = ra_tbs_from_idx(mcs_idx - 2, nof_prb); + } else if (mcs_idx == 29) { + mcs->mod = LTE_QPSK; + mcs->tbs = 0; + } else if (mcs_idx == 30) { + mcs->mod = LTE_QAM16; + mcs->tbs = 0; + } else if (mcs_idx == 31) { + mcs->mod = LTE_QAM64; + mcs->tbs = 0; } else { - mcs->mod = MOD_NULL; - mcs->tbs_idx = 0; - return -1; + return LIBLTE_ERROR; } - return 0; + return LIBLTE_SUCCESS; } /* Converts MCS index to ra_mcs_t structure for Uplink as defined in Table 8.6.1-1 on 36.213 */ -int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs) { - if (idx < 11) { - mcs->mod = QPSK; - mcs->tbs_idx = idx; - } else if (idx < 21) { - mcs->mod = QAM16; - mcs->tbs_idx = idx - 1; - } else if (idx < 29) { - mcs->mod = QAM64; - mcs->tbs_idx = idx - 2; +int ra_mcs_from_idx_ul(uint32_t mcs_idx, uint32_t nof_prb, ra_mcs_t *mcs) { + if (mcs_idx < 11) { + mcs->mod = LTE_QPSK; + mcs->tbs = ra_tbs_from_idx(mcs_idx, nof_prb); + } else if (mcs_idx < 21) { + mcs->mod = LTE_QAM16; + mcs->tbs = ra_tbs_from_idx(mcs_idx - 1, nof_prb); + } else if (mcs_idx < 29) { + mcs->mod = LTE_QAM64; + mcs->tbs = ra_tbs_from_idx(mcs_idx - 2, nof_prb); } else { - mcs->mod = MOD_NULL; - mcs->tbs_idx = 0; - return -1; + return LIBLTE_ERROR; } - return 0; + return LIBLTE_SUCCESS; } /* Downlink Transport Block size for Format 1C as defined in 7.1.7.2.2-1 on 36.213 */ -int ra_tbs_from_idx_format1c(uint8_t tbs_idx) { +int ra_tbs_from_idx_format1c(uint32_t tbs_idx) { if (tbs_idx < 32) { return tbs_format1c_table[tbs_idx]; } else { - return -1; + return LIBLTE_ERROR; } } -/* Returns lowest nearest index of TBS value in table 7.1.7.2.2-1 on 36.213 - * or -1 if the TBS value is not within the valid TBS values - */ -int ra_tbs_to_table_idx_format1c(int tbs) { - int idx; - if (tbs < tbs_format1c_table[0]) { - return -1; - } - for (idx = 1; idx < 32; idx++) { - if (tbs_format1c_table[idx - 1] <= tbs && tbs_format1c_table[idx] >= tbs) { - return idx; - } - } - return -1; -} - /* Downlink Transport Block size determination as defined in 7.1.7.2 on 36.213 */ -int ra_tbs_from_idx(uint8_t tbs_idx, int n_prb) { - if (tbs_idx < 27 && n_prb > 0 && n_prb <= 110) { +int ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb) { + if (tbs_idx < 27 && n_prb > 0 && n_prb <= MAX_PRB) { return tbs_table[tbs_idx][n_prb - 1]; } else { - return -1; + return LIBLTE_ERROR; } } /* Returns lowest nearest index of TBS value in table 7.1.7.2 on 36.213 * or -1 if the TBS value is not within the valid TBS values */ -int ra_tbs_to_table_idx(int tbs, int n_prb) { - int idx; - if (n_prb > 0 && n_prb <= 110) { - return -1; +int ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb) { + uint32_t idx; + if (n_prb > 0 && n_prb <= MAX_PRB) { + return LIBLTE_ERROR; } if (tbs < tbs_table[0][n_prb]) { - return -1; + return LIBLTE_ERROR; } for (idx = 1; idx < 28; idx++) { if (tbs_table[idx - 1][n_prb] <= tbs && tbs_table[idx][n_prb] >= tbs) { return idx; } } - return -1; + return LIBLTE_ERROR; } -char *ra_mod_string(ra_mod_t mod) { - switch (mod) { - case QPSK: - return "QPSK"; - case QAM16: - return "QAM16"; - case QAM64: - return "QAM64"; - default: - return "N/A"; - } -} - -void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, int nof_prb) { +void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, uint32_t nof_prb) { fprintf(f, "Frequency Hopping:\t"); if (ra->freq_hop_fl == hop_disabled) { fprintf(f, "No"); @@ -540,16 +494,8 @@ char *ra_type_string(ra_type_t alloc_type) { } } -void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint8_t mcs_idx) { - ra->mcs.mod = MOD_NULL; - ra->mcs.mcs_idx = mcs_idx; -} -void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx) { - ra->mcs.mod = mod; - ra->mcs.tbs_idx = tbs_idx; -} -void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb) { +void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, uint32_t nof_prb) { fprintf(f, " - Resource Allocation Type:\t\t%s\n", ra_type_string(ra->alloc_type)); switch (ra->alloc_type) { @@ -590,8 +536,8 @@ void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb) { } fprintf(f, " - Number of PRBs:\t\t\t%d\n", ra_nprb_dl(ra, nof_prb)); - fprintf(f, " - Modulation and coding scheme index:\t%d\n", ra->mcs.mcs_idx); - fprintf(f, " - Modulation type:\t\t\t%s\n", ra_mod_string(ra->mcs.mod)); + fprintf(f, " - Modulation and coding scheme index:\t%d\n", ra->mcs_idx); + fprintf(f, " - Modulation type:\t\t\t%s\n", lte_mod_string(ra->mcs.mod)); fprintf(f, " - Transport block size:\t\t%d\n", ra->mcs.tbs); fprintf(f, " - HARQ process:\t\t\t%d\n", ra->harq_process); fprintf(f, " - New data indicator:\t\t\t%s\n", ra->ndi ? "Yes" : "No"); diff --git a/lte/phy/lib/phch/src/regs.c b/lte/phy/lib/phch/src/regs.c index 014f0dce1..0c0bf5405 100644 --- a/lte/phy/lib/phch/src/regs.c +++ b/lte/phy/lib/phch/src/regs.c @@ -34,7 +34,26 @@ #include "liblte/phy/phch/regs.h" #include "liblte/phy/utils/debug.h" -regs_reg_t *regs_find_reg(regs_t *h, int k, int l); +#define REG_IDX(r, i, n) r->k[i]+r->l*n*RE_X_RB + + +regs_reg_t *regs_find_reg(regs_t *h, uint32_t k, uint32_t l); +int regs_put_reg(regs_reg_t *reg, + cf_t *reg_data, + cf_t *slot_symbols, + uint32_t nof_prb); + +int regs_add_reg(regs_reg_t *reg, + cf_t *reg_data, + cf_t *slot_symbols, + uint32_t nof_prb); + +int regs_get_reg(regs_reg_t *reg, + cf_t *slot_symbols, + cf_t *reg_data, + uint32_t nof_prb); + +int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, uint32_t nof_prb); /*************************************************************** @@ -62,14 +81,15 @@ const unsigned char PDCCH_PERM[PDCCH_NCOLS] = */ int regs_pdcch_init(regs_t *h) { int i, m, cfi, nof_ctrl_symbols; - int ret = -1; - int nrows, ndummy, j, k, kp; + int ret = LIBLTE_ERROR; + int nrows, ndummy, j; + uint32_t k, kp; regs_reg_t **tmp = NULL; bzero(&h->pdcch, sizeof(regs_ch_t)); for (cfi=0;cfi<3;cfi++) { - if (h->nof_prb < 10) { + if (h->cell.nof_prb < 10) { nof_ctrl_symbols = cfi+2; } else { nof_ctrl_symbols = cfi+1; @@ -110,9 +130,10 @@ int regs_pdcch_init(regs_t *h) { for (i = 0; i < nrows; i++) { if (i*PDCCH_NCOLS + PDCCH_PERM[j] >= ndummy) { m = i*PDCCH_NCOLS + PDCCH_PERM[j]-ndummy; - kp = (k-h->cell_id)%h->pdcch[cfi].nof_regs; - if (kp < 0) { - kp += h->pdcch[cfi].nof_regs; + if (k < h->cell.id) { + kp = (h->pdcch[cfi].nof_regs + k-h->cell.id)%h->pdcch[cfi].nof_regs; + } else { + kp = (k-h->cell.id)%h->pdcch[cfi].nof_regs; } h->pdcch[cfi].regs[m] = tmp[kp]; k++; @@ -122,59 +143,79 @@ int regs_pdcch_init(regs_t *h) { h->pdcch[cfi].nof_regs = (h->pdcch[cfi].nof_regs/9)*9; free(tmp); tmp = NULL; - if (VERBOSE_ISINFO() && cfi == 1) { - for (i=0;ipdcch[cfi].nof_regs;i++) { - INFO("Logical PDCCH REG#%d:%d (%d,%d)\n", i%9,i/9, - h->pdcch[cfi].regs[i]->k0, h->pdcch[cfi].regs[i]->l); - } - } } - ret = 0; + ret = LIBLTE_SUCCESS; clean_and_exit: if (tmp) { free(tmp); } - if (ret == -1) { + if (ret == LIBLTE_ERROR) { regs_pdcch_free(h); } return ret; } -int regs_pdcch_nregs(regs_t *h) { - if (h->cfi == -1) { - fprintf(stderr, "Must call regs_set_cfi() first\n"); - return -1; +int regs_pdcch_nregs(regs_t *h, uint32_t cfi) { + if (cfi < 1 || cfi > 3) { + fprintf(stderr, "Invalid CFI=%d\n", cfi); + return LIBLTE_ERROR; } else { - return h->pdcch[h->cfi].nof_regs; + return (int) h->pdcch[cfi-1].nof_regs; } } /** Copy quadruplets to REGs and cyclic shift them, according to the * second part of 6.8.5 in 36.211 */ -int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols) { - if (h->cfi == -1) { + +int regs_pdcch_put_offset(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols, uint32_t start_reg, uint32_t nof_regs) { + if (h->cfi_initiated) { + if (start_reg + nof_regs <= h->pdcch[h->cfi].nof_regs) { + uint32_t i, k; + k = 0; + for (i=start_reg;ipdcch[h->cfi].regs[i], &pdcch_symbols[k], slot_symbols, h->cell.nof_prb); + k += 4; + } + return k; + } else { + fprintf(stderr, "Out of range: start_reg + nof_reg must be lower than %d\n", h->pdcch[h->cfi].nof_regs); + return LIBLTE_ERROR; + } + } else { fprintf(stderr, "Must call regs_set_cfi() first\n"); - return -1; + return LIBLTE_ERROR; } - int i; - for (i=0;ipdcch[h->cfi].nof_regs;i++) { - regs_put_reg(h->pdcch[h->cfi].regs[i], &pdcch_symbols[i*4], slot_symbols, h->nof_prb); - } - return h->pdcch[h->cfi].nof_regs*4; } -int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols) { - if (h->cfi == -1) { +int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols) { + return regs_pdcch_put_offset(h, pdcch_symbols, slot_symbols, 0, h->pdcch[h->cfi].nof_regs); +} + +int regs_pdcch_get_offset(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols, uint32_t start_reg, uint32_t nof_regs) { + if (h->cfi_initiated) { + if (start_reg + nof_regs <= h->pdcch[h->cfi].nof_regs) { + uint32_t i, k; + k = 0; + for (i=start_reg;ipdcch[h->cfi].regs[i], slot_symbols, &pdcch_symbols[k], h->cell.nof_prb); + k += 4; + } + return k; + } else { + fprintf(stderr, "Out of range: start_reg + nof_reg must be lower than %d\n", h->pdcch[h->cfi].nof_regs); + return LIBLTE_ERROR; + } + } else { fprintf(stderr, "Must call regs_set_cfi() first\n"); - return -1; + return LIBLTE_ERROR; } - int i; - for (i=0;ipdcch[h->cfi].nof_regs;i++) { - regs_get_reg(h->pdcch[h->cfi].regs[i], slot_symbols, &pdcch_symbols[i*4], h->nof_prb); - } - return h->pdcch[h->cfi].nof_regs*4; +} + + +int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols) { + return regs_pdcch_get_offset(h, slot_symbols, pdcch_symbols, 0, h->pdcch[h->cfi].nof_regs); } @@ -191,9 +232,9 @@ int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols) { */ int regs_phich_init(regs_t *h) { float ng; - int i,ni,li,n[3],nreg,mi; + uint32_t i, ni, li, n[3], nreg, mi; regs_reg_t **regs_phich[3]; - int ret = -1; + int ret = LIBLTE_ERROR; switch(h->phich_res) { case R_1_6: @@ -212,7 +253,7 @@ int regs_phich_init(regs_t *h) { ng = 0; break; } - h->ngroups_phich = (int) ceilf(ng * ((float) h->nof_prb/8)); + h->ngroups_phich = (int) ceilf(ng * ((float) h->cell.nof_prb/8)); h->phich = malloc(sizeof(regs_ch_t) * h->ngroups_phich); if (!h->phich) { perror("malloc"); @@ -261,7 +302,7 @@ int regs_phich_init(regs_t *h) { for (mi=0;mingroups_phich;mi++) { // here ngroups is the number of mapping units for (i=0;i<3;i++) { li=h->phich_len==PHICH_EXT?i:0; // Step 7 - ni=((h->cell_id*n[li]/n[0])+mi+i*n[li]/3) % n[li]; // Step 8 + ni=((h->cell.id*n[li]/n[0])+mi+i*n[li]/3) % n[li]; // Step 8 h->phich[mi].regs[i] = regs_phich[li][ni]; h->phich[mi].regs[i]->assigned = true; INFO("Assigned PHICH REG#%d (%d,%d)\n",nreg,h->phich[mi].regs[i]->k0,li); @@ -271,13 +312,13 @@ int regs_phich_init(regs_t *h) { // now the number of mapping units = number of groups for normal cp. For extended cp // ngroups = 2 * number mapping units - if (CP_ISEXT(h->cp)) { + if (CP_ISEXT(h->cell.cp)) { h->ngroups_phich *= 2; } - ret = 0; + ret = LIBLTE_SUCCESS; clean_and_exit: - if (ret == -1) { + if (ret == LIBLTE_ERROR) { if (h->phich) { for (i=0;ingroups_phich;i++) { if (h->phich[i].regs) { @@ -296,9 +337,9 @@ clean_and_exit: } void regs_phich_free(regs_t *h) { - int i; + uint32_t i; if (h->phich) { - if (CP_ISEXT(h->cp)) { + if (CP_ISEXT(h->cell.cp)) { h->ngroups_phich /= 2; } for (i=0;ingroups_phich;i++) { @@ -310,8 +351,9 @@ void regs_phich_free(regs_t *h) { } } -int regs_phich_nregs(regs_t *h) { - int i, n; +uint32_t regs_phich_nregs(regs_t *h) { + uint32_t i; + uint32_t n; n=0; for (i=0;ingroups_phich;i++) { n += h->phich[i].nof_regs; @@ -320,7 +362,7 @@ int regs_phich_nregs(regs_t *h) { } -int regs_phich_ngroups(regs_t *h) { +uint32_t regs_phich_ngroups(regs_t *h) { return h->ngroups_phich; } @@ -331,18 +373,18 @@ int regs_phich_ngroups(regs_t *h) { * * Returns the number of written symbols, or -1 on error */ -int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, cf_t *slot_symbols) { - int i; - if (ngroup < 0 || ngroup > h->ngroups_phich) { +int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], uint32_t ngroup, cf_t *slot_symbols) { + uint32_t i; + if (ngroup >= h->ngroups_phich) { fprintf(stderr, "Error invalid ngroup %d\n", ngroup); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } - if (CP_ISEXT(h->cp)) { + if (CP_ISEXT(h->cell.cp)) { ngroup /= 2; } regs_ch_t *rch = &h->phich[ngroup]; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PHICH_NSYM; i++) { - regs_add_reg(rch->regs[i], &phich_symbols[i*REGS_RE_X_REG], slot_symbols, h->nof_prb); + regs_add_reg(rch->regs[i], &phich_symbols[i*REGS_RE_X_REG], slot_symbols, h->cell.nof_prb); } return i*REGS_RE_X_REG; } @@ -353,20 +395,20 @@ int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, c * Returns the number of written symbols, or -1 on error */ int regs_phich_reset(regs_t *h, cf_t *slot_symbols) { - int i; - int ngroup, ng; - for (ngroup = 0;ngroup < h->ngroups_phich;CP_ISEXT(h->cp)?ngroup+=2:ngroup++) { - if (CP_ISEXT(h->cp)) { + uint32_t i; + uint32_t ngroup, ng; + for (ngroup = 0;ngroup < h->ngroups_phich;CP_ISEXT(h->cell.cp)?ngroup+=2:ngroup++) { + if (CP_ISEXT(h->cell.cp)) { ng = ngroup/2; } else { ng = ngroup; } regs_ch_t *rch = &h->phich[ng]; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PHICH_NSYM; i++) { - regs_reset_reg(rch->regs[i], slot_symbols, h->nof_prb); + regs_reset_reg(rch->regs[i], slot_symbols, h->cell.nof_prb); } } - return 0; + return LIBLTE_SUCCESS; } /** @@ -374,18 +416,18 @@ int regs_phich_reset(regs_t *h, cf_t *slot_symbols) { * * Returns the number of written symbols, or -1 on error */ -int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup) { - int i; - if (ngroup < 0 || ngroup > h->ngroups_phich) { +int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], uint32_t ngroup) { + uint32_t i; + if (ngroup >= h->ngroups_phich) { fprintf(stderr, "Error invalid ngroup %d\n", ngroup); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } - if (CP_ISEXT(h->cp)) { + if (CP_ISEXT(h->cell.cp)) { ngroup /= 2; } regs_ch_t *rch = &h->phich[ngroup]; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PHICH_NSYM; i++) { - regs_get_reg(rch->regs[i], slot_symbols, &phich_symbols[i*REGS_RE_X_REG], h->nof_prb); + regs_get_reg(rch->regs[i], slot_symbols, &phich_symbols[i*REGS_RE_X_REG], h->cell.nof_prb); } return i*REGS_RE_X_REG; } @@ -410,39 +452,40 @@ int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_ * 36.211 10.3 section 6.7.4 */ int regs_pcfich_init(regs_t *h) { - int i, k_hat, k; + uint32_t i; + uint32_t k_hat, k; regs_ch_t *ch = &h->pcfich; ch->regs = malloc(sizeof(regs_reg_t*) * REGS_PCFICH_NREGS); if (!ch->regs) { perror("malloc"); - return -1; + return LIBLTE_ERROR; } ch->nof_regs = REGS_PCFICH_NREGS; - INFO("PCFICH allocating %d regs. CellID: %d, PRB: %d\n", ch->nof_regs, h->cell_id, h->nof_prb); + INFO("PCFICH allocating %d regs. CellID: %d, PRB: %d\n", ch->nof_regs, h->cell.id, h->cell.nof_prb); - k_hat = (RE_X_RB / 2) * (h->cell_id % (2 * h->nof_prb)); + k_hat = (RE_X_RB / 2) * (h->cell.id % (2 * h->cell.nof_prb)); for (i = 0; i < REGS_PCFICH_NREGS; i++) { - k = (k_hat + (i * h->nof_prb / 2) * (RE_X_RB / 2)) - % (h->nof_prb * RE_X_RB); + k = (k_hat + (i * h->cell.nof_prb / 2) * (RE_X_RB / 2)) + % (h->cell.nof_prb * RE_X_RB); ch->regs[i] = regs_find_reg(h, k, 0); if (!ch->regs[i]) { fprintf(stderr, "Error allocating PCFICH: REG (%d,0) not found\n", k); - return -1; + return LIBLTE_ERROR; } else if (ch->regs[i]->assigned) { fprintf(stderr, "Error allocating PCFICH: REG (%d,0) already allocated\n", k); - return -1; + return LIBLTE_ERROR; } else { ch->regs[i]->assigned = true; INFO("Assigned PCFICH REG#%d (%d,0)\n", i, k); } } - return 0; + return LIBLTE_SUCCESS; } void regs_pcfich_free(regs_t *h) { @@ -451,7 +494,7 @@ void regs_pcfich_free(regs_t *h) { } } -int regs_pcfich_nregs(regs_t *h) { +uint32_t regs_pcfich_nregs(regs_t *h) { return h->pcfich.nof_regs; } @@ -463,9 +506,9 @@ int regs_pcfich_nregs(regs_t *h) { int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols) { regs_ch_t *rch = &h->pcfich; - int i; + uint32_t i; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PCFICH_NSYM; i++) { - regs_put_reg(rch->regs[i], &pcfich_symbols[i*REGS_RE_X_REG], slot_symbols, h->nof_prb); + regs_put_reg(rch->regs[i], &pcfich_symbols[i*REGS_RE_X_REG], slot_symbols, h->cell.nof_prb); } return i*REGS_RE_X_REG; } @@ -477,9 +520,9 @@ int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot */ int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t ch_data[REGS_PCFICH_NSYM]) { regs_ch_t *rch = &h->pcfich; - int i; + uint32_t i; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PCFICH_NSYM; i++) { - regs_get_reg(rch->regs[i], slot_symbols, &ch_data[i*REGS_RE_X_REG], h->nof_prb); + regs_get_reg(rch->regs[i], slot_symbols, &ch_data[i*REGS_RE_X_REG], h->cell.nof_prb); } return i*REGS_RE_X_REG; } @@ -503,8 +546,8 @@ int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t ch_data[REGS_PCFICH_NSYM * ***************************************************************/ -regs_reg_t *regs_find_reg(regs_t *h, int k, int l) { - int i; +regs_reg_t *regs_find_reg(regs_t *h, uint32_t k, uint32_t l) { + uint32_t i; for (i=0;inof_regs;i++) { if (h->regs[i].l == l && h->regs[i].k0 == k) { return &h->regs[i]; @@ -517,7 +560,7 @@ regs_reg_t *regs_find_reg(regs_t *h, int k, int l) { * Returns the number of REGs in a PRB * 36.211 Section 6.2.4 */ -int regs_num_x_symbol(int symbol, int nof_port, lte_cp_t cp) { +int regs_num_x_symbol(uint32_t symbol, uint32_t nof_port, lte_cp_t cp) { switch (symbol) { case 0: @@ -530,7 +573,7 @@ int regs_num_x_symbol(int symbol, int nof_port, lte_cp_t cp) { case 4: return 2; default: - return -1; + return LIBLTE_ERROR; } break; case 2: @@ -542,7 +585,7 @@ int regs_num_x_symbol(int symbol, int nof_port, lte_cp_t cp) { return 2; } default: - return -1; + return LIBLTE_ERROR; } } @@ -550,8 +593,8 @@ int regs_num_x_symbol(int symbol, int nof_port, lte_cp_t cp) { * Initializes the indices of a REG * 36.211 Section 6.2.4 */ -int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int vo) { - int i, j, z; +int regs_reg_init(regs_reg_t *reg, uint32_t symbol, uint32_t nreg, uint32_t k0, uint32_t maxreg, uint32_t vo) { + uint32_t i, j, z; reg->l = symbol; reg->assigned = false; @@ -576,7 +619,7 @@ int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int } if (j != 4) { fprintf(stderr, "Something went wrong: expected 2 references\n"); - return -1; + return LIBLTE_ERROR; } break; @@ -589,9 +632,9 @@ int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int break; default: fprintf(stderr, "Invalid number of REGs per PRB: %d\n", maxreg); - return -1; + return LIBLTE_ERROR; } - return 0; + return LIBLTE_SUCCESS; } void regs_free(regs_t *h) { @@ -607,19 +650,20 @@ void regs_free(regs_t *h) { /** Sets the CFI value for this subframe (CFI must be in the range 1..3). */ -int regs_set_cfi(regs_t *h, int cfi) { +int regs_set_cfi(regs_t *h, uint32_t cfi) { if (cfi > 0 && cfi <= 3) { if (h->phich_len == PHICH_EXT && - ((h->nof_prb < 10 && cfi < 2) || (h->nof_prb >= 10 && cfi < 3))) { + ((h->cell.nof_prb < 10 && cfi < 2) || (h->cell.nof_prb >= 10 && cfi < 3))) { fprintf(stderr, "PHICH length is extended. The number of control symbols should be at least 3.\n"); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } else { + h->cfi_initiated = true; h->cfi = cfi - 1; - return 0; + return LIBLTE_SUCCESS; } } else { fprintf(stderr, "Invalid CFI %d\n", cfi); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } } @@ -628,97 +672,98 @@ int regs_set_cfi(regs_t *h, int cfi) { * Sets all REG indices and initializes PCFICH, PHICH and PDCCH REGs * Returns 0 if OK, -1 on error */ -int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports, - phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp) { - int ret = -1; - int i, j[4], jmax, n[4], prb, k; - int vo = cell_id % 3; - int max_ctrl_symbols = nof_prb<10?4:3; +int regs_init(regs_t *h, phich_resources_t phich_res, phich_length_t phich_len, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + uint32_t i, k; + uint32_t j[4], jmax, prb; + uint32_t n[4], vo; + uint32_t max_ctrl_symbols; - bzero(h, sizeof(regs_t)); + if (h != NULL && + lte_cell_isvalid(&cell)) + { + bzero(h, sizeof(regs_t)); + ret = LIBLTE_ERROR; + + max_ctrl_symbols = cell.nof_prb<10?4:3; + vo = cell.id % 3; + h->cell = cell; + h->max_ctrl_symbols = max_ctrl_symbols; + h->cfi_initiated = false; + h->phich_res = phich_res; + h->phich_len = phich_len; - h->cell_id = cell_id; - h->nof_prb = nof_prb; - h->max_ctrl_symbols = max_ctrl_symbols; - h->cfi = -1; // not yet initialized - h->phich_res = phich_res; - h->phich_len = phich_len; - h->cp = cp; - h->nof_ports = nof_ports; - - h->nof_regs = 0; - for (i = 0; i < max_ctrl_symbols; i++) { - n[i] = regs_num_x_symbol(i, nof_ports, cp); - if (n[i] == -1) { - return -1; - } - h->nof_regs += nof_prb * n[i]; - } - INFO("Indexing %d REGs. CellId: %d, %d PRB, CP: %s\n", h->nof_regs, h->cell_id, h->nof_prb, - CP_ISNORM(cp)?"Normal":"Extended"); - h->regs = malloc(sizeof(regs_reg_t) * h->nof_regs); - if (!h->regs) { - perror("malloc"); - goto clean_and_exit; - } - - /* Sort REGs according to PDCCH mapping, beggining from the lowest l index then k */ - bzero(j, sizeof(int) * 4); - k = i = prb = jmax = 0; - while (k < h->nof_regs) { - if (n[i] == 3 || (n[i] == 2 && jmax != 1)) { - if (regs_reg_init(&h->regs[k], i, j[i], prb * RE_X_RB, n[i], vo)) { - fprintf(stderr, "Error initializing REGs\n"); - goto clean_and_exit; + h->nof_regs = 0; + for (i = 0; i < max_ctrl_symbols; i++) { + n[i] = regs_num_x_symbol(i, h->cell.nof_ports, h->cell.cp); + if (n[i] == -1) { + return -1; } - DEBUG("Available REG #%3d: l=%d, prb=%d, nreg=%d (k0=%d)\n", k, i, prb, j[i], - h->regs[k].k0); - j[i]++; - k++; + h->nof_regs += h->cell.nof_prb * n[i]; } - i++; - if (i == max_ctrl_symbols) { - i = 0; - jmax++; + INFO("Indexing %d REGs. CellId: %d, %d PRB, CP: %s\n", h->nof_regs, h->cell.id, h->cell.nof_prb, + CP_ISNORM(h->cell.cp)?"Normal":"Extended"); + h->regs = malloc(sizeof(regs_reg_t) * h->nof_regs); + if (!h->regs) { + perror("malloc"); + goto clean_and_exit; } - if (jmax == 3) { - prb++; - bzero(j, sizeof(int) * 4); - jmax = 0; + + /* Sort REGs according to PDCCH mapping, beggining from the lowest l index then k */ + bzero(j, sizeof(int) * 4); + k = i = prb = jmax = 0; + while (k < h->nof_regs) { + if (n[i] == 3 || (n[i] == 2 && jmax != 1)) { + if (regs_reg_init(&h->regs[k], i, j[i], prb * RE_X_RB, n[i], vo)) { + fprintf(stderr, "Error initializing REGs\n"); + goto clean_and_exit; + } + /*DEBUG("Available REG #%3d: l=%d, prb=%d, nreg=%d (k0=%d)\n", k, i, prb, j[i], + h->regs[k].k0); + */ + j[i]++; + k++; + } + i++; + if (i == max_ctrl_symbols) { + i = 0; + jmax++; + } + if (jmax == 3) { + prb++; + bzero(j, sizeof(int) * 4); + jmax = 0; + } + } + if (regs_pcfich_init(h)) { + fprintf(stderr, "Error initializing PCFICH REGs\n"); + goto clean_and_exit; } - } - if (regs_pcfich_init(h)) { - fprintf(stderr, "Error initializing PCFICH REGs\n"); - goto clean_and_exit; - } - if (regs_phich_init(h)) { - fprintf(stderr, "Error initializing PHICH REGs\n"); - goto clean_and_exit; - } - if (regs_pdcch_init(h)) { - fprintf(stderr, "Error initializing PDCCH REGs\n"); - goto clean_and_exit; - } - - ret = 0; + if (regs_phich_init(h)) { + fprintf(stderr, "Error initializing PHICH REGs\n"); + goto clean_and_exit; + } + if (regs_pdcch_init(h)) { + fprintf(stderr, "Error initializing PDCCH REGs\n"); + goto clean_and_exit; + } + ret = LIBLTE_SUCCESS; + } clean_and_exit: - if (ret == -1) { + if (ret == LIBLTE_ERROR) { regs_free(h); } return ret; } -#define REG_IDX(r, i, n) r->k[i]+r->l*n*RE_X_RB - /** * Puts one REG data (4 symbols) in the slot symbols array */ -int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) { - int i; +int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint32_t nof_prb) { + uint32_t i; for (i = 0; i < REGS_RE_X_REG; i++) { - DEBUG("PUT REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l); slot_symbols[REG_IDX(reg, i, nof_prb)] = reg_data[i]; } return REGS_RE_X_REG; @@ -728,13 +773,10 @@ int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_pr * Adds one REG data (4 symbols) in the slot symbols array * Used by PHICH */ -int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) { - int i; +int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint32_t nof_prb) { + uint32_t i; for (i = 0; i < REGS_RE_X_REG; i++) { slot_symbols[REG_IDX(reg, i, nof_prb)] += reg_data[i]; - DEBUG("ADD REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l, - __real__ slot_symbols[REG_IDX(reg, i, nof_prb)], - __imag__ slot_symbols[REG_IDX(reg, i, nof_prb)]); } return REGS_RE_X_REG; } @@ -743,10 +785,9 @@ int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_pr /** * Reset REG data (4 symbols) in the slot symbols array */ -int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) { - int i; +int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, uint32_t nof_prb) { + uint32_t i; for (i = 0; i < REGS_RE_X_REG; i++) { - DEBUG("RESET REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l); slot_symbols[REG_IDX(reg, i, nof_prb)] = 0; } return REGS_RE_X_REG; @@ -755,13 +796,12 @@ int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) { /** * Gets one REG data (4 symbols) from the slot symbols array */ -int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb) { - int i; +int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, uint32_t nof_prb) { + uint32_t i; for (i = 0; i < REGS_RE_X_REG; i++) { reg_data[i] = slot_symbols[REG_IDX(reg, i, nof_prb)]; - //DEBUG("GET REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l, - // __real__ reg_data[i], __imag__ reg_data[i]); } return REGS_RE_X_REG; } + diff --git a/lte/phy/lib/phch/src/sequences.c b/lte/phy/lib/phch/src/sequences.c index 372179926..499eb1cd0 100644 --- a/lte/phy/lib/phch/src/sequences.c +++ b/lte/phy/lib/phch/src/sequences.c @@ -33,7 +33,7 @@ /** * 36.211 6.6.1 */ -int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id) { +int sequence_pbch(sequence_t *seq, lte_cp_t cp, uint32_t cell_id) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, CP_ISNORM(cp)?1920:1728, cell_id); } @@ -41,7 +41,7 @@ int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id) { /** * 36.211 6.7.1 */ -int sequence_pcfich(sequence_t *seq, int nslot, int cell_id) { +int sequence_pcfich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, 32, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } @@ -50,7 +50,7 @@ int sequence_pcfich(sequence_t *seq, int nslot, int cell_id) { /** * 36.211 6.9.1 */ -int sequence_phich(sequence_t *seq, int nslot, int cell_id) { +int sequence_phich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } @@ -58,7 +58,7 @@ int sequence_phich(sequence_t *seq, int nslot, int cell_id) { /** * 36.211 6.8.2 */ -int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len) { +int sequence_pdcch(sequence_t *seq, uint32_t nslot, uint32_t cell_id, uint32_t len) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, len, (nslot/2) * 512 + cell_id); } @@ -66,7 +66,7 @@ int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len) { /** * 36.211 6.3.1 */ -int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, int nslot, int cell_id, int len) { - bzero(seq, sizeof(sequence_t)); - return sequence_LTEPRS(seq, len, (rnti<<14) + (q<<13) + ((nslot/2)<<9) + cell_id); +int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, uint32_t nslot, uint32_t cell_id, uint32_t len) { + bzero(seq, sizeof(sequence_t)); + return sequence_LTEPRS(seq, len, (rnti<<14) + (q<<13) + ((nslot/2)<<9) + cell_id); } diff --git a/lte/phy/lib/phch/src/ue_dl.c b/lte/phy/lib/phch/src/ue_dl.c new file mode 100644 index 000000000..e48b28f62 --- /dev/null +++ b/lte/phy/lib/phch/src/ue_dl.c @@ -0,0 +1,257 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE 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 Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 "liblte/phy/phch/ue_dl.h" + + +#define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1)) + +#define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb) +#define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE, q->cell.cp) + +#define CURRENT_SLOTLEN_RE SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) +#define CURRENT_SFLEN_RE SF_LEN_RE(q->cell.nof_prb, q->cell.cp) + + +int ue_dl_init(ue_dl_t *q, + lte_cell_t cell, + phich_resources_t phich_resources, phich_length_t phich_length, + uint16_t user_rnti) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + lte_cell_isvalid(&cell)) + { + ret = LIBLTE_ERROR; + + q->cell = cell; + q->user_rnti = user_rnti; + q->pkt_errors = 0; + q->pkts_total = 0; + q->nof_trials = 0; + + if (lte_fft_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { + fprintf(stderr, "Error initiating FFT\n"); + goto clean_exit; + } + if (chest_init_LTEDL(&q->chest, cell)) { + fprintf(stderr, "Error initiating channel estimator\n"); + goto clean_exit; + } + if (regs_init(&q->regs, phich_resources, phich_length, q->cell)) { + fprintf(stderr, "Error initiating REGs\n"); + goto clean_exit; + } + + if (pcfich_init(&q->pcfich, &q->regs, q->cell)) { + fprintf(stderr, "Error creating PCFICH object\n"); + goto clean_exit; + } + + if (pdcch_init(&q->pdcch, &q->regs, q->cell)) { + fprintf(stderr, "Error creating PDCCH object\n"); + goto clean_exit; + } + + if (pdsch_init(&q->pdsch, q->cell)) { + fprintf(stderr, "Error creating PDSCH object\n"); + goto clean_exit; + } + for (uint32_t i=0;iharq_process[i], &q->pdsch)) { + fprintf(stderr, "Error initiating HARQ process\n"); + goto clean_exit; + } + } + q->sf_symbols = vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + if (!q->sf_symbols) { + perror("malloc"); + goto clean_exit; + } + for (uint32_t i=0;icell.nof_ports;i++) { + q->ce[i] = vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + if (!q->ce[i]) { + perror("malloc"); + goto clean_exit; + } + } + + ret = LIBLTE_SUCCESS; + } else { + fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", + cell.id, cell.nof_ports, cell.nof_prb); + } + +clean_exit: + if (ret == LIBLTE_ERROR) { + ue_dl_free(q); + } + return ret; +} + +void ue_dl_free(ue_dl_t *q) { + if (q) { + lte_fft_free(&q->fft); + chest_free(&q->chest); + regs_free(&q->regs); + pcfich_free(&q->pcfich); + pdcch_free(&q->pdcch); + pdsch_free(&q->pdsch); + for (uint32_t i=0;iharq_process[i]); + } + if (q->sf_symbols) { + free(q->sf_symbols); + } + for (uint32_t i=0;icell.nof_ports;i++) { + if (q->ce[i]) { + free(q->ce[i]); + } + } + } +} + +int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t sfn, uint16_t rnti) +{ + uint32_t cfi, cfi_distance, i; + ra_pdsch_t ra_dl; + dci_location_t locations[10]; + dci_msg_t dci_msg; + uint32_t nof_locations; + uint16_t crc_rem; + dci_format_t format; + + /* If we are looking for SI Blocks, search only in appropiate places */ + if ((rnti == SIRNTI && (sfn % 2) == 0 && sf_idx == 5) || + rnti != SIRNTI) + { + + /* Run FFT for all subframe data */ + lte_fft_run_sf(&q->fft, input, q->sf_symbols); + + /* Get channel estimates for each port */ + chest_ce_sf(&q->chest, q->sf_symbols, q->ce, sf_idx); + + /* First decode PCFICH and obtain CFI */ + if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce, sf_idx, &cfi, &cfi_distance)<0) { + fprintf(stderr, "Error decoding PCFICH\n"); + return LIBLTE_ERROR; + } + + INFO("Decoded CFI=%d with distance %d\n", cfi, cfi_distance); + + if (regs_set_cfi(&q->regs, cfi)) { + fprintf(stderr, "Error setting CFI\n"); + return LIBLTE_ERROR; + } + + /* Generate PDCCH candidates */ + if (rnti == SIRNTI) { + nof_locations = pdcch_common_locations(&q->pdcch, locations, 10, cfi); + format = Format1A; + } else { + nof_locations = pdcch_ue_locations(&q->pdcch, locations, 10, sf_idx, cfi, q->user_rnti); + format = Format1; + } + + crc_rem = 0; + for (i=0;ipdcch, q->sf_symbols, q->ce, locations[i], sf_idx, cfi)) { + fprintf(stderr, "Error extracting LLRs\n"); + return LIBLTE_ERROR; + } + if (pdcch_decode_msg(&q->pdcch, &dci_msg, format, &crc_rem)) { + fprintf(stderr, "Error decoding DCI msg\n"); + return LIBLTE_ERROR; + } + INFO("Decoded DCI message RNTI: 0x%x\n", crc_rem); + } + + + if (crc_rem == rnti) { + if (dci_msg_to_ra_dl(&dci_msg, rnti, q->user_rnti, q->cell, cfi, &ra_dl)) { + fprintf(stderr, "Error unpacking PDSCH scheduling DCI message\n"); + return LIBLTE_ERROR; + } + + uint32_t rvidx; + if (rnti == SIRNTI) { + switch((sfn%8)/2) { + case 0: + rvidx = 0; + break; + case 1: + rvidx = 2; + break; + case 2: + rvidx = 3; + break; + case 3: + rvidx = 1; + break; + } + } else { + rvidx = ra_dl.rv_idx; + } + + if (rvidx == 0) { + if (pdsch_harq_setup(&q->harq_process[0], ra_dl.mcs, &ra_dl.prb_alloc)) { + fprintf(stderr, "Error configuring HARQ process\n"); + return LIBLTE_ERROR; + } + } + if (q->harq_process[0].mcs.mod > 0) { + if (pdsch_decode(&q->pdsch, q->sf_symbols, q->ce, data, sf_idx, + &q->harq_process[0], rvidx)) { + if (rnti == SIRNTI && rvidx == 1) { + q->pkt_errors++; + } else { + q->pkt_errors++; + } + } else { + if (VERBOSE_ISINFO()) { + INFO("Decoded Message: ", 0); + vec_fprint_hex(stdout, data, ra_dl.mcs.tbs); + } + } + if (rnti == SIRNTI && rvidx == 1) { + q->pkts_total++; + } + } + } + if (rnti == SIRNTI && (sfn%8) == 0) { + q->nof_trials++; + } + } + + if (crc_rem == rnti) { + return ra_dl.mcs.tbs; + } else { + return 0; + } +} diff --git a/lte/phy/lib/phch/src/ue_sync.c b/lte/phy/lib/phch/src/ue_sync.c new file mode 100644 index 000000000..bf19c5516 --- /dev/null +++ b/lte/phy/lib/phch/src/ue_sync.c @@ -0,0 +1,570 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE 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 Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 "liblte/phy/phch/ue_sync.h" + +#include "liblte/phy/utils/debug.h" +#include "liblte/phy/utils/vector.h" + +#define MAX_TIME_OFFSET 128 +cf_t dummy[MAX_TIME_OFFSET]; + +#define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1)) + +#define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb) +#define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE, q->cell.cp) + +#define CURRENT_SLOTLEN_RE SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) +#define CURRENT_SFLEN_RE SF_LEN_RE(q->cell.nof_prb, q->cell.cp) + +#define MAXIMUM_SFLEN SF_LEN(2048, CPNORM) +#define MAXIMUM_SFLEN_RE SF_LEN_RE(110, CPNORM) + +static int mib_decoder_initialize(ue_sync_t *q); +static void mib_decoder_free(ue_sync_t *q); + +int ue_sync_init(ue_sync_t *q, + double (set_rate_callback)(void*, double), + int (recv_callback)(void*, void*, uint32_t), + void *stream_handler) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + stream_handler != NULL) + { + ret = LIBLTE_ERROR; + + bzero(q, sizeof(ue_sync_t)); + + ue_sync_reset(q); + + q->cell.nof_prb = SYNC_PBCH_NOF_PRB; + q->cell.nof_ports = SYNC_PBCH_NOF_PORTS; + q->cell.id = 0; + q->cell.cp = CPNORM; + + q->pbch_decoded = false; + q->pbch_initialized = false; + q->pbch_decoder_enabled = true; + q->pbch_decode_always = false; + q->decode_sss_on_track = false; + + q->stream = stream_handler; + q->recv_callback = recv_callback; + q->set_rate_callback = set_rate_callback; + + INFO("Setting sampling frequency 1.92 MHz\n",0); + q->set_rate_callback(q->stream, 1920000.0); + + if (agc_init(&q->agc)) { + goto clean_exit; + } + + if(sync_init(&q->s, CURRENT_SFLEN, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) { + goto clean_exit; + } + + sync_pss_det_absolute(&q->s); + + if (cfo_init(&q->cfocorr, MAXIMUM_SFLEN)) { + fprintf(stderr, "Error initiating CFO\n"); + goto clean_exit; + } + + q->input_buffer = vec_malloc(3 * MAXIMUM_SFLEN * sizeof(cf_t)); + if (!q->input_buffer) { + perror("malloc"); + goto clean_exit; + } + + q->receive_buffer = vec_malloc(3 * MAXIMUM_SFLEN * sizeof(cf_t)); + if (!q->receive_buffer) { + perror("malloc"); + goto clean_exit; + } + + q->sf_symbols = vec_malloc(MAXIMUM_SFLEN_RE * sizeof(cf_t)); + if (!q->sf_symbols) { + perror("malloc"); + goto clean_exit; + } + for (int i=0;ice[i] = vec_malloc(MAXIMUM_SFLEN_RE * sizeof(cf_t)); + if (!q->ce[i]) { + perror("malloc"); + goto clean_exit; + } + } + + sync_set_threshold(&q->s, PSS_THRESHOLD, PSS_THRESHOLD); + + ret = LIBLTE_SUCCESS; + } + +clean_exit: + if (ret == LIBLTE_ERROR) { + ue_sync_free(q); + } + return ret; +} + +void ue_sync_free(ue_sync_t *q) { + if (q->input_buffer) { + free(q->input_buffer); + } + if (q->receive_buffer) { + free(q->receive_buffer); + } + if (q->sf_symbols) { + free(q->sf_symbols); + } + for (int i=0;ice[i]) { + free(q->ce[i]); + } + } + mib_decoder_free(q); + cfo_free(&q->cfocorr); + sync_free(&q->s); + agc_free(&q->agc); +} + +void ue_sync_set_threshold(ue_sync_t *q, float threshold) { + sync_set_threshold(&q->s, threshold, threshold/2); +} + +lte_cell_t ue_sync_get_cell(ue_sync_t *q) { + return q->cell; +} + +pbch_mib_t ue_sync_get_mib(ue_sync_t *q) { + return q->mib; +} + +uint32_t ue_sync_peak_idx(ue_sync_t *q) { + return q->peak_idx; +} + +ue_sync_state_t ue_sync_get_state(ue_sync_t *q) { + return q->state; +} + +static int update_srate(ue_sync_t *q) { + struct timeval t[3]; + + gettimeofday(&t[1], NULL); + if (sync_realloc(&q->s, CURRENT_SFLEN, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) { + fprintf(stderr, "Error realloc'ing SYNC\n"); + return LIBLTE_ERROR; + } + gettimeofday(&t[2], NULL); + get_time_interval(t); + + if (NOF_MIB_DECODES > 1) { + mib_decoder_free(q); + if (mib_decoder_initialize(q)) { + fprintf(stderr, "Error reinitializing MIB decoder\n"); + return LIBLTE_ERROR; + } + } + + // Finally set the new sampling rate + q->set_rate_callback(q->stream, (float) lte_sampling_freq_hz(q->cell.nof_prb)); + + ue_sync_reset(q); + printf("Set sampling rate %.2f MHz, fft_size=%d, sf_len=%d Texec=%d us\n", + (float) lte_sampling_freq_hz(q->cell.nof_prb)/1000000, + CURRENT_FFTSIZE, CURRENT_SFLEN, (int) t[0].tv_usec); + + return LIBLTE_SUCCESS; +} + +uint32_t ue_sync_get_sfidx(ue_sync_t *q) { + return q->sf_idx; +} + +float ue_sync_get_cfo(ue_sync_t *q) { + return 15000 * q->cur_cfo; +} + +float ue_sync_get_sfo(ue_sync_t *q) { + return 1000*q->mean_time_offset/5; +} + +bool ue_sync_is_mib_decoded(ue_sync_t *q) { + return q->pbch_decoded; +} + +void ue_sync_pbch_enable(ue_sync_t *q, bool enabled) { + q->pbch_decoder_enabled = enabled; +} + +void ue_sync_pbch_always(ue_sync_t *q, bool enabled) { + q->pbch_decode_always = enabled; +} + +void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) { + q->decode_sss_on_track = enabled; +} + +static int mib_decoder_initialize(ue_sync_t *q) { + + if (lte_fft_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { + fprintf(stderr, "Error initializing FFT\n"); + return -1; + } + if (chest_init_LTEDL(&q->chest, q->cell)) { + fprintf(stderr, "Error initializing reference signal\n"); + return -1; + } + if (pbch_init(&q->pbch, q->cell)) { + fprintf(stderr, "Error initiating PBCH\n"); + return -1; + } + q->pbch_initialized = 1; + DEBUG("PBCH initiated cell_id=%d\n", q->cell.id); + + return 0; +} + +static void mib_decoder_free(ue_sync_t *q) { + chest_free(&q->chest); + pbch_free(&q->pbch); + lte_fft_free(&q->fft); +} + +static int mib_decoder_run(ue_sync_t *q) { + int ret; + + /* Run FFT for the second slot */ + lte_fft_run_sf(&q->fft, q->input_buffer, q->sf_symbols); + + /* Get channel estimates of slot #1 for each port */ + chest_ce_sf(&q->chest, q->sf_symbols, q->ce, 0); + + if (q->pbch_last_trial && + (q->frame_total_cnt - q->pbch_last_trial > 2)) + { + pbch_decode_reset(&q->pbch); + INFO("Resetting PBCH decoder: last trial %d, now is %d\n", + q->pbch_last_trial, q->frame_total_cnt); + q->pbch_last_trial = 0; + } + + if (pbch_decode(&q->pbch, q->sf_symbols, q->ce, &q->mib) == 1) { + q->frame_number = q->mib.sfn; + q->cell.nof_ports = q->mib.nof_ports; + q->cell.nof_prb = q->mib.nof_prb; + + if (!q->pbch_decoded) { + printf("MIB decoded:\n"); + pbch_mib_fprint(stdout, &q->mib); + ret = update_srate(q); + } else { + INFO("MIB decoded #%d SFN: %d\n", q->pbch_decoded, q->mib.sfn); + } + q->pbch_decoded++; + + pbch_decode_reset(&q->pbch); + + } else { + INFO("MIB not decoded: %d\n", q->frame_total_cnt); + q->pbch_last_trial = q->frame_total_cnt; + } + + return ret; +} + +static int find_peak_ok(ue_sync_t *q) { + int ret; + + if (q->peak_idx < CURRENT_SFLEN) { + /* Receive the rest of the next subframe */ + if (q->recv_callback(q->stream, &q->input_buffer[CURRENT_SFLEN], q->peak_idx+CURRENT_SFLEN/2) < 0) { + return LIBLTE_ERROR; + } + } + + if (sync_sss_detected(&q->s)) { + ret = sync_get_cell_id(&q->s); + if (ret >= 0) { + q->cell.id = (uint32_t) ret; + q->cell.cp = sync_get_cp(&q->s); + } + + /* Get the subframe index (0 or 5) */ + q->sf_idx = sync_get_slot_id(&q->s)/2; + + /* Reset variables */ + q->frame_ok_cnt = 0; + q->frame_no_cnt = 0; + q->frame_total_cnt = 0; + + /* Goto Tracking state */ + q->state = SF_TRACK; + ret = LIBLTE_SUCCESS; + + INFO("Found peak %d, SF_idx: %d, Cell_id: %d CP: %s\n", + q->peak_idx, q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp)); + + if (q->peak_idx < CURRENT_SFLEN) { + q->sf_idx++; + } + + return ret; + } else { + INFO("Found peak at %d, SSS not detected\n", q->peak_idx); + return 0; + } +} + +int track_peak_ok(ue_sync_t *q, uint32_t track_idx) { + int ret = LIBLTE_SUCCESS; + + /* Make sure subframe idx is what we expect */ + if ((q->sf_idx != sync_get_slot_id(&q->s)/2) && q->decode_sss_on_track) { + printf("\nWarning: Expected SF idx %d but got %d!\n", + q->sf_idx, sync_get_slot_id(&q->s)/2); + q->sf_idx = sync_get_slot_id(&q->s)/2; + } else { + q->time_offset = ((int) track_idx - (int) CURRENT_FFTSIZE); + + /* If the PSS peak is beyond the frame (we sample too slowly), + discard the offseted samples to align next frame */ + if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) { + ret = q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset); + } else { + ret = LIBLTE_SUCCESS; + } + + /* compute cumulative moving average CFO */ + q->cur_cfo = EXPAVERAGE(sync_get_cfo(&q->s), q->cur_cfo, q->frame_ok_cnt); + + /* compute cumulative moving average time offset */ + q->mean_time_offset = (float) EXPAVERAGE((float) q->time_offset, q->mean_time_offset, q->frame_ok_cnt); + + q->peak_idx = CURRENT_SFLEN/2 + q->time_offset; + q->frame_ok_cnt++; + q->frame_no_cnt = 0; + + + if (ret >= LIBLTE_SUCCESS) { + ret = LIBLTE_SUCCESS; + } + } + + return ret; +} + +int track_peak_no(ue_sync_t *q) { + + /* if we missed too many PSS go back to FIND */ + q->frame_no_cnt++; + if (q->frame_no_cnt >= TRACK_MAX_LOST) { + printf("\n%d frames lost. Going back to FIND\n", (int) q->frame_no_cnt); + q->state = SF_FIND; + } else { + INFO("Tracking peak not found, %d lost\n", (int) q->frame_no_cnt); + } + + return LIBLTE_SUCCESS; +} + +static int receive_samples(ue_sync_t *q) { + + /* A negative time offset means there are samples in our buffer for the next subframe, + because we are sampling too fast. + */ + if (q->time_offset < 0) { + q->time_offset = -q->time_offset; + } + /* copy last part of the last subframe (use move since there could be overlapping) */ + memcpy(q->receive_buffer, &q->input_buffer[CURRENT_SFLEN-q->time_offset], q->time_offset*sizeof(cf_t)); + + /* Get 1 subframe from the USRP getting more samples and keeping the previous samples, if any */ + if (q->recv_callback(q->stream, &q->receive_buffer[q->time_offset], CURRENT_SFLEN - q->time_offset) < 0) { + return LIBLTE_ERROR; + } + + /* reset time offset */ + q->time_offset = 0; + + return LIBLTE_SUCCESS; +} + +int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + uint32_t track_idx; + struct timeval t[3]; + + if (q != NULL && + sf_symbols != NULL && + q->input_buffer != NULL) + { + + if (receive_samples(q)) { + fprintf(stderr, "Error receiving samples\n"); + return -1; + } + + agc_push(&q->agc, q->receive_buffer, q->input_buffer, CURRENT_SFLEN); + + switch (q->state) { + case SF_FIND: + q->s.sss_en = true; + + /* Find peak and cell id */ + ret = sync_find(&q->s, q->input_buffer, &q->peak_idx); + if (ret < 0) { + fprintf(stderr, "Error finding correlation peak (%d)\n", ret); + return -1; + } + + DEBUG("Find PAR=%.2f\n", sync_get_peak_value(&q->s)); + + if (ret == 1) { + ret = find_peak_ok(q); + /* Initialize PBCH decoder */ + if (ret == LIBLTE_SUCCESS) { + if (!q->pbch_initialized && q->pbch_decoder_enabled) { + ret = mib_decoder_initialize(q); + if (ret < 0) { + fprintf(stderr, "Error initializing MIB decoder\n"); + } + } + } else if (ret < 0) { + if (ret < 0) { + fprintf(stderr, "Error processing find peak \n"); + } + } + } + break; + case SF_TRACK: + ret = LIBLTE_SUCCESS; + + q->s.sss_en = q->decode_sss_on_track; + + q->sf_idx = (q->sf_idx + 1) % 10; + + DEBUG("TRACK: SF=%d FrameCNT: %d\n", q->sf_idx, q->frame_total_cnt); + + /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ + if (q->sf_idx == 0 || q->sf_idx == 5) { + + #ifdef MEASURE_EXEC_TIME + gettimeofday(&t[1], NULL); + #endif + + track_idx = 0; + + /* track pss around the middle of the subframe, where the PSS is */ + ret = sync_track(&q->s, q->input_buffer, CURRENT_SFLEN/2-CURRENT_FFTSIZE, &track_idx); + if (ret < 0) { + fprintf(stderr, "Error tracking correlation peak\n"); + return -1; + } + + #ifdef MEASURE_EXEC_TIME + gettimeofday(&t[2], NULL); + get_time_interval(t); + q->mean_exec_time = (float) EXPAVERAGE((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt); + #endif + + if (ret == 1) { + ret = track_peak_ok(q, track_idx); + } else { + ret = track_peak_no(q); + } + + INFO("TRACK %3d: SF=%d Track_idx=%d Offset=%d CFO: %f\n", + (int) q->frame_total_cnt, q->sf_idx, track_idx, q->time_offset, sync_get_cfo(&q->s)); + + q->frame_total_cnt++; + + if (ret == LIBLTE_ERROR) { + fprintf(stderr, "Error processing tracking peak\n"); + ue_sync_reset(q); + return LIBLTE_SUCCESS; + } + } + + /* Do CFO Correction and deliver the frame */ + cfo_correct(&q->cfocorr, q->input_buffer, q->input_buffer, -q->cur_cfo / CURRENT_FFTSIZE); + *sf_symbols = q->input_buffer; + + /* At subframe 0, try to decode PBCH if not yet decoded */ + if (q->sf_idx == 0) { + if(q->pbch_decoder_enabled && + (q->pbch_decoded < NOF_MIB_DECODES || q->pbch_decode_always)) + { + mib_decoder_run(q); + } else { + q->mib.sfn = (q->mib.sfn + 1) % 1024; + } + } + + if (ret == LIBLTE_SUCCESS) { + if (q->pbch_decoder_enabled) { + if (q->pbch_decoded >= NOF_MIB_DECODES) { + ret = 1; + } else { + ret = 0; + } + } else { + ret = 1; + } + } + break; + } + } + DEBUG("UE SYNC returns %d\n", ret); + return ret; +} + +void ue_sync_reset(ue_sync_t *q) { + q->state = SF_FIND; + + q->pbch_last_trial = 0; + q->frame_ok_cnt = 0; + q->frame_no_cnt = 0; + q->frame_total_cnt = 0; + q->cur_cfo = 0; + q->mean_time_offset = 0; + q->time_offset = 0; + #ifdef MEASURE_EXEC_TIME + q->mean_exec_time = 0; + #endif +} + diff --git a/lte/phy/lib/phch/test/CMakeLists.txt b/lte/phy/lib/phch/test/CMakeLists.txt index 36ed64f2a..eb8b8dd1e 100644 --- a/lte/phy/lib/phch/test/CMakeLists.txt +++ b/lte/phy/lib/phch/test/CMakeLists.txt @@ -19,6 +19,23 @@ # and at http://www.gnu.org/licenses/. # +######################################################################## +# UE SYNC TEST (Only compiled if CUHD is available) +######################################################################## +LIST(FIND OPTIONAL_LIBS cuhd CUHD_FIND) +LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND) +IF(${CUHD_FIND} GREATER -1) + ADD_EXECUTABLE(ue_sync_usrp ue_sync_usrp.c) + TARGET_LINK_LIBRARIES(ue_sync_usrp lte_phy cuhd) +ENDIF(${CUHD_FIND} GREATER -1) + +IF(${GRAPHICS_FIND} EQUAL -1) + SET_TARGET_PROPERTIES(ue_sync_usrp PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") +ELSE(${GRAPHICS_FIND} EQUAL -1) + target_link_libraries(ue_sync_usrp graphics) +ENDIF(${GRAPHICS_FIND} EQUAL -1) + + ######################################################################## # PBCH TEST ######################################################################## @@ -92,6 +109,7 @@ TARGET_LINK_LIBRARIES(pdsch_re_test lte_phy) ADD_TEST(pdsch_re_test pdsch_re_test) ADD_TEST(pdsch_test pdsch_test -l 50000 -m 4 -n 110) +ADD_TEST(pdsch_test pdsch_test -l 500 -m 2 -n 50 -r 2) ######################################################################## # FILE TEST diff --git a/lte/phy/lib/phch/test/dci_unpacking.c b/lte/phy/lib/phch/test/dci_unpacking.c index b2e377b2e..6a1087d11 100644 --- a/lte/phy/lib/phch/test/dci_unpacking.c +++ b/lte/phy/lib/phch/test/dci_unpacking.c @@ -81,9 +81,8 @@ int main(int argc, char **argv) { printf("\n"); dci_msg_type_t dci_type; - msg.location.rnti = SIRNTI; - msg.location.nof_bits = len; - if (dci_msg_get_type(&msg, &dci_type, nof_prb, 1234)) { + msg.nof_bits = len; + if (dci_msg_get_type(&msg, &dci_type, nof_prb, SIRNTI, 1234)) { fprintf(stderr, "Can't obtain DCI message type\n"); exit(-1); } diff --git a/lte/phy/lib/phch/test/pbch_file_test.c b/lte/phy/lib/phch/test/pbch_file_test.c index c356620cf..92b2d8621 100644 --- a/lte/phy/lib/phch/test/pbch_file_test.c +++ b/lte/phy/lib/phch/test/pbch_file_test.c @@ -35,17 +35,20 @@ char *input_file_name = NULL; char *matlab_file_name = NULL; -int cell_id = 150; -lte_cp_t cp = CPNORM; -int nof_prb = 6; FILE *fmatlab = NULL; -#define NOF_PORTS 2 +lte_cell_t cell = { + 6, // nof_prb + 2, // nof_ports + 150, // cell_id + CPNORM // cyclic prefix +}; + #define FLEN 9600 filesource_t fsrc; -cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL]; +cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS]; pbch_t pbch; lte_fft_t fft; chest_t chest; @@ -53,20 +56,22 @@ chest_t chest; void usage(char *prog) { printf("Usage: %s [vcoe] -i input_file\n", prog); printf("\t-o output matlab file name [Default Disabled]\n"); - printf("\t-c cell_id [Default %d]\n", cell_id); + printf("\t-c cell_id [Default %d]\n", cell.id); + printf("\t-n nof_prb [Default %d]\n", cell.nof_prb); printf("\t-e Set extended prefix [Default Normal]\n"); printf("\t-v [set verbose to debug, default none]\n"); } void parse_args(int argc, char **argv) { int opt; + while ((opt = getopt(argc, argv, "iovce")) != -1) { switch(opt) { case 'i': input_file_name = argv[optind]; break; case 'c': - cell_id = atoi(argv[optind]); + cell.id = atoi(argv[optind]); break; case 'o': matlab_file_name = argv[optind]; @@ -75,7 +80,7 @@ void parse_args(int argc, char **argv) { verbose++; break; case 'e': - cp = CPEXT; + cell.cp = CPEXT; break; default: usage(argv[0]); @@ -112,36 +117,36 @@ int base_init() { exit(-1); } - fft_buffer = malloc(CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t)); + fft_buffer = malloc(2 * CP_NSYMB(cell.cp) * cell.nof_prb * RE_X_RB * sizeof(cf_t)); if (!fft_buffer) { perror("malloc"); return -1; } - for (i=0;i= 1234 && crc_rem < 1234 + nof_dcis) { + crc_rem -= 1234; + memcpy(&dci_rx[crc_rem], &dci_tmp, sizeof(dci_msg_t)); + } else { + printf("Received invalid DCI CRC 0x%x\n", crc_rem); + goto quit; + } + } + for (i = 0; i < nof_dcis; i++) { + if (memcmp(dci_tx[i].data, dci_rx[i].data, dci_tx[i].nof_bits)) { + printf("Error in DCI %d: Received data does not match\n", i); + goto quit; } - } else { - printf("Transmitted %d DCIs but got %d\n", dci_tx.nof_dcis, nof_dcis); - goto quit; } ret = 0; - quit: pdcch_free(&pdcch); - regs_free(®s); - dci_free(&dci_tx); - dci_free(&dci_rx); - for (i = 0; i < MAX_PORTS_CTRL; i++) { +quit: + pdcch_free(&pdcch); + regs_free(®s); + + for (i = 0; i < MAX_PORTS; i++) { free(ce[i]); free(slot_symbols[i]); } diff --git a/lte/phy/lib/phch/test/pdsch_file_test.c b/lte/phy/lib/phch/test/pdsch_file_test.c index 882b612fb..d180167f2 100644 --- a/lte/phy/lib/phch/test/pdsch_file_test.c +++ b/lte/phy/lib/phch/test/pdsch_file_test.c @@ -35,299 +35,294 @@ char *input_file_name = NULL; char *matlab_file_name = NULL; -int cell_id = 0; -int cfi = 2; -lte_cp_t cp = CPNORM; -int nof_prb = 6; -int nof_ports = 1; + +lte_cell_t cell = { + 6, // nof_prb + 1, // nof_ports + 0, // cell_id + CPNORM // cyclic prefix +}; + int flen; -unsigned short rnti = SIRNTI; + +uint32_t cfi = 2; +uint16_t rnti = SIRNTI; + int max_frames = 10; FILE *fmatlab = NULL; filesource_t fsrc; pdcch_t pdcch; pdsch_t pdsch; -cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL]; +pdsch_harq_t harq_process; +cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS]; regs_t regs; lte_fft_t fft; chest_t chest; -dci_t dci_rx; void usage(char *prog) { - printf("Usage: %s [vcfoe] -i input_file\n", prog); - printf("\t-o output matlab file name [Default Disabled]\n"); - printf("\t-c cell_id [Default %d]\n", cell_id); - printf("\t-f cfi [Default %d]\n", cfi); - printf("\t-r rnti [Default SI-RNTI]\n"); - printf("\t-p nof_ports [Default %d]\n", nof_ports); - printf("\t-n nof_prb [Default %d]\n", nof_prb); - printf("\t-m max_frames [Default %d]\n", max_frames); - printf("\t-e Set extended prefix [Default Normal]\n"); - printf("\t-v [set verbose to debug, default none]\n"); + printf("Usage: %s [vcfoe] -i input_file\n", prog); + printf("\t-o output matlab file name [Default Disabled]\n"); + printf("\t-c cell.id [Default %d]\n", cell.id); + printf("\t-f cfi [Default %d]\n", cfi); + printf("\t-r rnti [Default SI-RNTI]\n"); + printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports); + printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-m max_frames [Default %d]\n", max_frames); + printf("\t-e Set extended prefix [Default Normal]\n"); + printf("\t-v [set verbose to debug, default none]\n"); } void parse_args(int argc, char **argv) { - int opt; - while ((opt = getopt(argc, argv, "irovfcenmp")) != -1) { - switch(opt) { - case 'i': - input_file_name = argv[optind]; - break; - case 'c': - cell_id = atoi(argv[optind]); - break; - case 'r': - rnti = strtoul(argv[optind], NULL, 0); - break; - case 'm': - max_frames = strtoul(argv[optind], NULL, 0); - break; - case 'f': - cfi = atoi(argv[optind]); - break; - case 'n': - nof_prb = atoi(argv[optind]); - break; - case 'p': - nof_ports = atoi(argv[optind]); - break; - case 'o': - matlab_file_name = argv[optind]; - break; - case 'v': - verbose++; - break; - case 'e': - cp = CPEXT; - break; - default: - usage(argv[0]); - exit(-1); - } - } - if (!input_file_name) { - usage(argv[0]); - exit(-1); - } + int opt; + while ((opt = getopt(argc, argv, "irovfcenmp")) != -1) { + switch(opt) { + case 'i': + input_file_name = argv[optind]; + break; + case 'c': + cell.id = atoi(argv[optind]); + break; + case 'r': + rnti = strtoul(argv[optind], NULL, 0); + break; + case 'm': + max_frames = strtoul(argv[optind], NULL, 0); + break; + case 'f': + cfi = atoi(argv[optind]); + break; + case 'n': + cell.nof_prb = atoi(argv[optind]); + break; + case 'p': + cell.nof_ports = atoi(argv[optind]); + break; + case 'o': + matlab_file_name = argv[optind]; + break; + case 'v': + verbose++; + break; + case 'e': + cell.cp = CPEXT; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!input_file_name) { + usage(argv[0]); + exit(-1); + } } int base_init() { - int i; + int i; - if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { - fprintf(stderr, "Error opening file %s\n", input_file_name); - exit(-1); - } + if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { + fprintf(stderr, "Error opening file %s\n", input_file_name); + exit(-1); + } - if (matlab_file_name) { - fmatlab = fopen(matlab_file_name, "w"); - if (!fmatlab) { - perror("fopen"); - return -1; - } - } else { - fmatlab = NULL; - } + if (matlab_file_name) { + fmatlab = fopen(matlab_file_name, "w"); + if (!fmatlab) { + perror("fopen"); + return -1; + } + } else { + fmatlab = NULL; + } - flen = 2 * (SLOT_LEN(lte_symbol_sz(nof_prb), cp)); + flen = 2 * (SLOT_LEN(lte_symbol_sz(cell.nof_prb), cell.cp)); - input_buffer = malloc(flen * sizeof(cf_t)); - if (!input_buffer) { - perror("malloc"); - exit(-1); - } + input_buffer = malloc(flen * sizeof(cf_t)); + if (!input_buffer) { + perror("malloc"); + exit(-1); + } - fft_buffer = malloc(2 * CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t)); - if (!fft_buffer) { - perror("malloc"); - return -1; - } + fft_buffer = malloc(2 * CP_NSYMB(cell.cp) * cell.nof_prb * RE_X_RB * sizeof(cf_t)); + if (!fft_buffer) { + perror("malloc"); + return -1; + } - for (i=0;i 0) { - slot_symbols[0][j] += slot_symbols[i][j]; - } - ce[i][j] = 1; - } - } - - gettimeofday(&t[1], NULL); - int r = pdsch_decode(&pdsch, slot_symbols[0], ce, data, subframe, mcs, &prb_alloc); - gettimeofday(&t[2], NULL); - get_time_interval(t); - if (r) { - printf("Error decoding\n"); - ret = -1; - } else { - printf("DECODED OK in %d:%d (%.2f Mbps)\n", (int) t[0].tv_sec, (int) t[0].tv_usec, (float) mcs.tbs/t[0].tv_usec); - } - ret = 0; + /* combine outputs */ + for (i=0;i 0) { + slot_symbols[0][j] += slot_symbols[i][j]; + } + ce[i][j] = 1; + } + } + + gettimeofday(&t[1], NULL); + int r = pdsch_decode(&pdsch, slot_symbols[0], ce, data, subframe, &harq_process, rv); + gettimeofday(&t[2], NULL); + get_time_interval(t); + if (r) { + printf("Error decoding\n"); + ret = -1; + goto quit; + } else { + printf("DECODED OK in %d:%d (%.2f Mbps)\n", (int) t[0].tv_sec, (int) t[0].tv_usec, (float) mcs.tbs/t[0].tv_usec); + } + + } + ret = 0; quit: - pdsch_free(&pdsch); + pdsch_free(&pdsch); - for (i=0;i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "liblte/phy/phy.h" + +#include "liblte/cuhd/cuhd.h" +void *uhd; + +#ifndef DISABLE_GRAPHICS +#include "liblte/graphics/plot.h" +plot_real_t poutfft; +#endif + +int nof_frames = -1; +float threshold = -1.0; + +float uhd_freq = 0.0, uhd_gain = 20.0; +char *uhd_args = ""; +int disable_plots = 0; + +void usage(char *prog) { + printf("Usage: %s [agntdv] -f uhd_freq\n", prog); + printf("\t-a UHD args [Default %s]\n", uhd_args); + printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain); + printf("\t-n nof_frames [Default infinite]\n"); + printf("\t-t threshold [Default %.2f]\n",threshold); + +#ifndef DISABLE_GRAPHICS + printf("\t-d disable plots [Default enabled]\n"); +#endif + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "agntdvf")) != -1) { + switch (opt) { + case 'n': + nof_frames = atoi(argv[optind]); + break; + case 'a': + uhd_args = argv[optind]; + break; + case 'g': + uhd_gain = atof(argv[optind]); + break; + case 'f': + uhd_freq = atof(argv[optind]); + break; + case 't': + threshold = atof(argv[optind]); + break; + case 'd': + disable_plots = 1; + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (uhd_freq == 0.0) { + usage(argv[0]); + exit(-1); + } +} + +void input_init() { + + printf("Opening UHD device...\n"); + if (cuhd_open(uhd_args, &uhd)) { + fprintf(stderr, "Error opening uhd\n"); + exit(-1); + } + cuhd_set_rx_gain(uhd, uhd_gain); + + /* set uhd_freq */ + cuhd_set_rx_freq(uhd, (double) uhd_freq); + cuhd_rx_wait_lo_locked(uhd); + DEBUG("Set uhd_freq to %.3f MHz\n", (double ) uhd_freq/1000000); + + DEBUG("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); + +} + +int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) { + DEBUG(" ---- Receive %d samples ---- \n", nsamples); + return cuhd_recv(h, data, nsamples, 1); +} + +#ifndef DISABLE_GRAPHICS + +void init_plots() { + plot_init(); + + plot_real_init(&poutfft); + plot_real_setTitle(&poutfft, "Output FFT - Magnitude"); + plot_real_setLabels(&poutfft, "Index", "dB"); + plot_real_setYAxisScale(&poutfft, -60, 0); + +} + +#endif + +float tmp_plot[100000]; + +int main(int argc, char **argv) { + cf_t *input_buffer, *sf_symbols = NULL; + int frame_cnt; + ue_sync_t s; + int pos; + pss_synch_t pss; + float peak; + struct timeval t[3]; + float mean_ce_time=0; + bool signal_detected; + lte_fft_t fft; + lte_cell_t cell; + + bzero(&cell, sizeof(lte_cell_t)); + + parse_args(argc, argv); + + #ifndef DISABLE_GRAPHICS + if (!disable_plots) { + init_plots(); + } + #endif + + input_init(); + + if (ue_sync_init(&s, cuhd_set_rx_srate, cuhd_recv_wrapper, uhd)) { + fprintf(stderr, "Error initiating UE sync module\n"); + exit(-1); + } + + if (threshold > 0.0) { + ue_sync_set_threshold(&s, threshold); + } + + ue_sync_pbch_enable(&s, true); +// ue_sync_pbch_always(&s, true); +// ue_sync_decode_sss_on_track(&s, true); + + signal_detected = true; + frame_cnt = 0; + mean_ce_time=0; + uint32_t valid_frames=0; + //uint32_t unaligned = 0; + while (frame_cnt < nof_frames || nof_frames == -1) { + + int n = ue_sync_get_buffer(&s, &input_buffer); + if (n < 0) { + fprintf(stderr, "Error calling sync work()\n"); + exit(-1); + } + + if (n == 1 && ue_sync_get_sfidx(&s) == 0) { + + if (signal_detected) { + cell = ue_sync_get_cell(&s); + pss_synch_init_fft(&pss, + SF_LEN(lte_symbol_sz(cell.nof_prb), cell.cp), + lte_symbol_sz(cell.nof_prb)); + pss_synch_set_N_id_2(&pss, cell.id%3); + + sf_symbols = vec_malloc(SLOT_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); + if (!sf_symbols) { + perror("malloc"); + exit(-1); + } + lte_fft_init(&fft, cell.cp, cell.nof_prb); + signal_detected = false; + } + + mean_ce_time = (float) (mean_ce_time + (float) t[0].tv_usec * valid_frames) / (valid_frames+1); + valid_frames++; + + #ifndef DISABLE_GRAPHICS + if (!disable_plots && !(valid_frames % 5) && sf_symbols) { + + /* Run FFT for the second slot */ + lte_fft_run_slot(&fft, input_buffer, sf_symbols); + + int i; + int nof_re = SLOT_LEN_RE(cell.nof_prb, cell.cp); + for (i = 0; i < nof_re; i++) { + tmp_plot[i] = 10 * log10f(cabsf(sf_symbols[i])); + if (isinf(tmp_plot[i])) { + tmp_plot[i] = -80; + } + } + plot_real_setNewData(&poutfft, tmp_plot, nof_re); + } + #endif + + pos = pss_synch_find_pss(&pss, input_buffer, &peak, NULL); + /*if (pos > 962 || pos < 958) { + unaligned++; + } + */ + printf("CELL_ID: %3d CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Exec: %3.2f\r", + cell.id, ue_sync_get_cfo(&s)/1000, ue_sync_get_sfo(&s)/1000, pos, + s.mean_exec_time); + fflush(stdout); + if (VERBOSE_ISINFO()) { + printf("\n"); + } + } + + frame_cnt++; + } + + printf("\nBye\n"); + exit(0); +} + + diff --git a/lte/phy/lib/resampling/src/decim.c b/lte/phy/lib/resampling/src/decim.c new file mode 100644 index 000000000..6853c3921 --- /dev/null +++ b/lte/phy/lib/resampling/src/decim.c @@ -0,0 +1,49 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE 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 Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 "liblte/phy/resampling/decim.h" +#include "liblte/phy/utils/debug.h" + + +/* Performs integer linear decimation by a factor of M */ +void decim_c(cf_t *input, cf_t *output, int M, int len) { + int i; + for (i=0;i #include +#include + #include "liblte/phy/resampling/interp.h" +#include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" +#define TABLE_SIZE 1024 + + +#ifdef TABLE_SIZE + #define ARG2IDX(arg) ((uint32_t) ((1+(arg)/M_PI)*TABLE_SIZE/2)) + #define MYCEXP(arg) q->cexptable[ARG2IDX(arg)] +#else + #define MYCEXP(arg) (cosf(arg) + I*sinf(arg)) +#endif + +#define MAX_OFFSET 64 + +int interp_init(interp_t *q, interp_type_t type, uint32_t len, uint32_t M) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + ret = LIBLTE_ERROR; + + q->in_arg = vec_malloc(len * sizeof(float)); + if (!q->in_arg) { + goto clean_and_exit; + } + q->in_mag = vec_malloc(len * sizeof(float)); + if (!q->in_mag) { + goto clean_and_exit; + } + q->out_arg = vec_malloc((MAX_OFFSET + M * len) * sizeof(float)); + if (!q->out_arg) { + goto clean_and_exit; + } + q->out_arg2 = vec_malloc((MAX_OFFSET + M * len) * sizeof(float)); + if (!q->out_arg2) { + goto clean_and_exit; + } + q->table_idx = vec_malloc((MAX_OFFSET + M * len) * sizeof(int16_t)); + if (!q->table_idx) { + goto clean_and_exit; + } + q->out_mag = vec_malloc((MAX_OFFSET + M * len) * sizeof(float)); + if (!q->out_mag) { + goto clean_and_exit; + } + q->out_cexp = vec_malloc((MAX_OFFSET + M * len) * sizeof(cf_t)); + if (!q->out_cexp) { + goto clean_and_exit; + } + q->out_prod = vec_malloc((MAX_OFFSET + M * len) * sizeof(cf_t)); + if (!q->out_prod) { + goto clean_and_exit; + } +#ifdef TABLE_SIZE + q->cexptable = vec_malloc(TABLE_SIZE * sizeof(cf_t)); + uint32_t i; + for (i=0;icexptable[i] = cexpf(I*M_PI*(2*((float) i/TABLE_SIZE) - 1)); + } +#endif + q->M = M; + q->len = len; + ret = LIBLTE_SUCCESS; + } + +clean_and_exit: + if (ret == LIBLTE_ERROR) { + interp_free(q); + } + return ret; +} + +void interp_free(interp_t *q) { + if (q) { + if (q->in_arg) { + free(q->in_arg); + } + if (q->in_mag) { + free(q->in_mag); + } + if (q->out_arg) { + free(q->out_arg); + } + if (q->out_cexp) { + free(q->out_cexp); + } + if (q->out_mag) { + free(q->out_mag); + } + + if (q->out_prod) { + free(q->out_prod); + } +#ifdef TABLE_SIZE + if (q->cexptable) { + free(q->cexptable); + } +#endif + } +} + +void interp_run_offset(interp_t *q, cf_t *input, cf_t *output, uint32_t off_st, uint32_t off_end) { + uint32_t i, j, n; + float mag0=0, mag1=0, arg0=0, arg1=0; + float dmag, darg; + uint32_t M = q->M; + uint32_t len1 = q->len-1; + + if (off_st + off_end < MAX_OFFSET) { + vec_abs_cf(input, q->in_mag, q->len); + vec_arg_cf(input, q->in_arg, q->len); + + mag0 = q->in_mag[0]; + mag1 = q->in_mag[1]; + arg0 = q->in_arg[0]; + arg1 = q->in_arg[1]; + dmag=(mag1-mag0)/M; + darg=(arg1-arg0)/M; + for (j=0;jout_mag[j] = mag0 - (j+1)*dmag; + q->out_arg[j] = arg0 - (j+1)*darg; + } + + for (i=0;iin_mag[i]; + mag1 = q->in_mag[i+1]; + arg0 = q->in_arg[i]; + arg1 = q->in_arg[i+1]; + dmag=(mag1-mag0)/M; + darg=(arg1-arg0)/M; + for (j=0;jout_mag[i*M+j+off_st] = mag0 + j*dmag; + q->out_arg[i*M+j+off_st] = arg0 + j*darg; + } + } + if (q->len > 1) { + for (j=0;jout_mag[i*M+j+off_st] = mag1 + j*dmag; + q->out_arg[i*M+j+off_st] = arg1 + j*darg; + } + } + uint32_t len=i*M+j+off_st; +#ifdef TABLE_SIZE + vec_convert_fi(q->out_arg, q->table_idx, (float) TABLE_SIZE/2/M_PI, len); + for (n=0;nout_cexp[n] = q->cexptable[q->table_idx[n]+TABLE_SIZE/2]; + } +#else + for (n=0;nout_cexp[n] = MYCEXP(q->out_arg[n]); + } +#endif + vec_prod_cfc(q->out_cexp, q->out_mag, output, len); + } + +} + +void interp_run(interp_t *q, cf_t *input, cf_t *output) { + interp_run_offset(q, input, output, 0, 1); +} + /* Performs 1st order linear interpolation with out-of-bound interpolation */ -void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end) { - int i, j; +void interp_linear_offset(cf_t *input, cf_t *output, uint32_t M, uint32_t len, uint32_t off_st, uint32_t off_end) { + uint32_t i, j; float mag0=0, mag1=0, arg0=0, arg1=0, mag=0, arg=0; for (i=0;i +#include +#include +#include +#include +#include + +#include "liblte/phy/phy.h" + +typedef _Complex float cf_t; + +int main(int argc, char **argv) { + uint32_t N = 1000; // Number of sinwave samples + interp_t interp; + struct timeval t[3]; + + if (argc < 3) { + printf("usage: %s upsampling_rate nof_trials\n", argv[0]); + exit(-1); + } + + uint32_t M = atoi(argv[1]); + uint32_t nof_trials = atoi(argv[2]); + + if (interp_init(&interp, LINEAR, N, M)) { + exit(-1); + } + + cf_t *in = vec_malloc(N*sizeof(cf_t)); + if(!in) { + perror("malloc"); + exit(-1); + } + cf_t *out = vec_malloc(M * N*sizeof(cf_t)); + if(!out) { + perror("malloc"); + exit(-1); + } + cf_t *out_volk = vec_malloc(M * N*sizeof(cf_t)); + if(!out_volk) { + perror("malloc"); + exit(-1); + } + + srand(time(NULL)); + for(uint32_t i=0;ilen); for (i = 0; i < len; i++) { diff --git a/lte/phy/lib/sync/src/cfo.c b/lte/phy/lib/sync/src/cfo.c index 2f3c7dac5..204fb9d43 100644 --- a/lte/phy/lib/sync/src/cfo.c +++ b/lte/phy/lib/sync/src/cfo.c @@ -34,14 +34,14 @@ #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" -int cfo_init(cfo_t *h, int nsamples) { - int ret = -1; +int cfo_init(cfo_t *h, uint32_t nsamples) { + int ret = LIBLTE_ERROR; bzero(h, sizeof(cfo_t)); if (cexptab_init(&h->tab, CFO_CEXPTAB_SIZE)) { goto clean; } - h->cur_cexp = malloc(sizeof(cf_t) * nsamples); + h->cur_cexp = vec_malloc(sizeof(cf_t) * nsamples); if (!h->cur_cexp) { goto clean; } @@ -50,9 +50,9 @@ int cfo_init(cfo_t *h, int nsamples) { h->nsamples = nsamples; cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, h->nsamples); - ret = 0; + ret = LIBLTE_SUCCESS; clean: - if (ret == -1) { + if (ret == LIBLTE_ERROR) { cfo_free(h); } return ret; @@ -70,11 +70,23 @@ void cfo_set_tol(cfo_t *h, float tol) { h->tol = tol; } -void cfo_correct(cfo_t *h, cf_t *x, float freq) { +int cfo_realloc(cfo_t *h, uint32_t samples) { + h->cur_cexp = realloc(h->cur_cexp, sizeof(cf_t) * samples); + if (!h->cur_cexp) { + perror("realloc"); + return LIBLTE_ERROR; + } + cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, samples); + h->nsamples = samples; + + return LIBLTE_SUCCESS; +} + +void cfo_correct(cfo_t *h, cf_t *input, cf_t *output, float freq) { if (fabs(h->last_freq - freq) > h->tol) { h->last_freq = freq; cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, h->nsamples); - INFO("CFO generating new table for frequency %.4f\n", freq); + DEBUG("CFO generating new table for frequency %.4f\n", freq); } - vec_prod_ccc(h->cur_cexp, x, x, h->nsamples); + vec_prod_ccc(h->cur_cexp, input, output, h->nsamples); } diff --git a/lte/phy/lib/sync/src/find_sss.c b/lte/phy/lib/sync/src/find_sss.c index 33c4e015c..7bc52d558 100644 --- a/lte/phy/lib/sync/src/find_sss.c +++ b/lte/phy/lib/sync/src/find_sss.c @@ -31,18 +31,10 @@ #include "liblte/phy/utils/vector.h" #include "liblte/phy/sync/sss.h" -cf_t corr_sz(cf_t *z, cf_t *s) { - cf_t sum; - cf_t zsprod[32]; - vec_prod_ccc(z, s, zsprod, N_SSS - 1); - sum = vec_acc_cc(zsprod, N_SSS - 1); - - return sum; -} -void corr_all_zs(cf_t *z, cf_t s[32][32], cf_t *output) { - int m; +void corr_all_zs(cf_t *z, cf_t s[N_SSS+1][N_SSS+1], cf_t *output) { + uint32_t m; for (m = 0; m < N_SSS; m++) { - output[m] = corr_sz(z, s[m]); + output[m] = vec_dot_prod_ccc(z, s[m], N_SSS - 1); } } @@ -58,54 +50,64 @@ void corr_all_zs(cf_t *z, cf_t s[32][32], cf_t *output) { * */ -void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value, - int *m1, float *m1_value) { +int sss_synch_m0m1(sss_synch_t *q, cf_t *input, uint32_t *m0, float *m0_value, + uint32_t *m1, float *m1_value) +{ - /* This is aprox 3-4 kbytes of stack. Consider moving to sss_synch_t?? */ - cf_t zdelay[N_SSS+1],zconj[N_SSS+1],zprod[N_SSS+1]; - cf_t y[2][N_SSS+1], z[N_SSS+1], tmp[N_SSS+1]; - float tmp_real[N_SSS+1]; - cf_t input_fft[SSS_DFT_LEN]; + int ret = LIBLTE_ERROR_INVALID_INPUTS; - int i; + if (q != NULL && + input != NULL && + m0 != NULL && + m1 != NULL) + { + + /* Consider moving to sss_synch_t?? */ + cf_t zdelay[N_SSS+1],zconj[N_SSS+1],zprod[N_SSS+1]; + cf_t y[2][N_SSS+1], z[N_SSS+1], tmp[N_SSS+1]; + float tmp_real[N_SSS+1]; + cf_t input_fft[SSS_MAX_FFT_LEN]; + uint32_t i; - dft_run_c(&q->dftp_input, input, input_fft); + dft_run_c(&q->dftp_input, input, input_fft); + + for (i = 0; i < N_SSS; i++) { + y[0][i] = input_fft[q->fft_size/2-N_SSS + 2 * i]; + y[1][i] = input_fft[q->fft_size/2-N_SSS + 2 * i + 1]; + } + + vec_prod_ccc(y[0], q->fc_tables[q->N_id_2].c[0], z, N_SSS); + memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); + vec_conj_cc(z, zconj, N_SSS - 1); + vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); - for (i = 0; i < N_SSS; i++) { - y[0][i] = input_fft[SSS_POS_SYMBOL + 2 * i]; - y[1][i] = input_fft[SSS_POS_SYMBOL + 2 * i + 1]; - } + corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp); + vec_abs_cf(tmp, tmp_real, N_SSS); + *m0 = vec_max_fi(tmp_real, N_SSS); + if (m0_value) { + *m0_value = tmp_real[*m0]; + } - vec_prod_ccc(y[0], q->fc_tables.c[0], z, N_SSS); - memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); - vec_conj_cc(z, zconj, N_SSS - 1); - vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); - - corr_all_zs(zprod, q->fc_tables.s, tmp); - vec_abs_cf(tmp, tmp_real, N_SSS); - *m0 = vec_max_fi(tmp_real, N_SSS); - if (m0_value) { - *m0_value = tmp_real[*m0]; - } - - vec_prod_ccc(y[1], q->fc_tables.c[1], tmp, N_SSS); - vec_prod_ccc(tmp, q->fc_tables.z1[*m0], z, N_SSS); - memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); - vec_conj_cc(z, zconj, N_SSS - 1); - vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); - - corr_all_zs(zprod, q->fc_tables.s, tmp); - vec_abs_cf(tmp, tmp_real, N_SSS); - *m1 = vec_max_fi(tmp_real, N_SSS); - if (m1_value) { - *m1_value = tmp_real[*m1]; - } + vec_prod_ccc(y[1], q->fc_tables[q->N_id_2].c[1], tmp, N_SSS); + vec_prod_ccc(tmp, q->fc_tables[q->N_id_2].z1[*m0], z, N_SSS); + memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); + vec_conj_cc(z, zconj, N_SSS - 1); + vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); + corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp); + vec_abs_cf(tmp, tmp_real, N_SSS); + *m1 = vec_max_fi(tmp_real, N_SSS); + if (m1_value) { + *m1_value = tmp_real[*m1]; + } + ret = LIBLTE_SUCCESS; + } + return ret; } void convert_tables(struct fc_tables *fc_tables, struct sss_tables *in) { - int i, j; - bzero(fc_tables, sizeof(struct fc_tables)); + uint32_t i, j; + for (i = 0; i < N_SSS; i++) { for (j = 0; j < N_SSS; j++) { __real__ fc_tables->z1[i][j] = (float) in->z1[i][j]; diff --git a/lte/phy/lib/sync/src/gen_sss.c b/lte/phy/lib/sync/src/gen_sss.c index 89279cda3..da3e895b2 100644 --- a/lte/phy/lib/sync/src/gen_sss.c +++ b/lte/phy/lib/sync/src/gen_sss.c @@ -58,19 +58,19 @@ void generate_zsc_tilde(int *z_tilde, int *s_tilde, int *c_tilde) { z_tilde[i] = 1 - 2 * x[i]; } -void generate_m0m1(int N_id_1, int *m0, int *m1) { - int q_prime = N_id_1 / (N_SSS - 1); - int q = (N_id_1 + (q_prime * (q_prime + 1) / 2)) / (N_SSS - 1); - int m_prime = N_id_1 + (q * (q + 1) / 2); +void generate_m0m1(uint32_t N_id_1, uint32_t *m0, uint32_t *m1) { + uint32_t q_prime = N_id_1 / (N_SSS - 1); + uint32_t q = (N_id_1 + (q_prime * (q_prime + 1) / 2)) / (N_SSS - 1); + uint32_t m_prime = N_id_1 + (q * (q + 1) / 2); *m0 = m_prime % N_SSS; *m1 = (*m0 + m_prime / N_SSS + 1) % N_SSS; } /* table[m0][m1-1]=N_id_1 */ -void generate_N_id_1_table(int table[30][30]) { - int m0, m1; - int N_id_1; +void generate_N_id_1_table(uint32_t table[30][30]) { + uint32_t m0, m1; + uint32_t N_id_1; for (N_id_1=0;N_id_1<168;N_id_1++) { generate_m0m1(N_id_1, &m0, &m1); table[m0][m1-1] = N_id_1; @@ -78,61 +78,60 @@ void generate_N_id_1_table(int table[30][30]) { } -void generate_s(int *s, int *s_tilde, int m0_m1) { - int i; +void generate_s(int *s, int *s_tilde, uint32_t m0_m1) { + uint32_t i; for (i = 0; i < N_SSS; i++) { s[i] = s_tilde[(i + m0_m1) % N_SSS]; } } void generate_s_all(int s[N_SSS][N_SSS], int *s_tilde) { - int i; + uint32_t i; for (i = 0; i < N_SSS; i++) { generate_s(s[i], s_tilde, i); } } -void generate_c(int *c, int *c_tilde, int N_id_2, int is_c0) { - int i; +void generate_c(int *c, int *c_tilde, uint32_t N_id_2, bool is_c0) { + uint32_t i; for (i = 0; i < N_SSS; i++) { - c[i] = c_tilde[(i + N_id_2 + (is_c0 > 0 ? 3 : 0)) % N_SSS]; + c[i] = c_tilde[(i + N_id_2 + (is_c0 ? 3 : 0)) % N_SSS]; } } -void generate_z(int *z, int *z_tilde, int m0_m1) { - int i; +void generate_z(int *z, int *z_tilde, uint32_t m0_m1) { + uint32_t i; for (i = 0; i < N_SSS; i++) { z[i] = z_tilde[(i + (m0_m1 % 8)) % N_SSS]; } } void generate_z_all(int z[N_SSS][N_SSS], int *z_tilde) { - int i; + uint32_t i; for (i = 0; i < N_SSS; i++) { generate_z(z[i], z_tilde, i); } } -void generate_sss_all_tables(struct sss_tables *tables, int N_id_2) { - int i; +void generate_sss_all_tables(struct sss_tables *tables, uint32_t N_id_2) { + uint32_t i; int s_t[N_SSS], c_t[N_SSS], z_t[N_SSS]; generate_zsc_tilde(z_t, s_t, c_t); generate_s_all(tables->s, s_t); generate_z_all(tables->z1, z_t); for (i = 0; i < 2; i++) { - generate_c(tables->c[i], c_t, N_id_2, i); + generate_c(tables->c[i], c_t, N_id_2, i > 0); } - tables->N_id_2 = N_id_2; } -void sss_generate(float *signal0, float *signal5, int cell_id) { +void sss_generate(float *signal0, float *signal5, uint32_t cell_id) { - int i; - int id1 = cell_id / 3; - int id2 = cell_id % 3; - int m0; - int m1; + uint32_t i; + uint32_t id1 = cell_id / 3; + uint32_t id2 = cell_id % 3; + uint32_t m0; + uint32_t m1; int s_t[N_SSS], c_t[N_SSS], z_t[N_SSS]; int s0[N_SSS], s1[N_SSS], c0[N_SSS], c1[N_SSS], z1_0[N_SSS], z1_1[N_SSS]; diff --git a/lte/phy/lib/sync/src/pss.c b/lte/phy/lib/sync/src/pss.c index 6d17a93ff..29ca1608c 100644 --- a/lte/phy/lib/sync/src/pss.c +++ b/lte/phy/lib/sync/src/pss.c @@ -37,92 +37,142 @@ #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/convolution.h" -#define NOT_SYNC 0xF0F0F0F0 -/* Initializes the object. subframe_size is the size, in samples, of the 1ms subframe - * +int pss_synch_init_N_id_2(cf_t *pss_signal_freq, uint32_t N_id_2, uint32_t fft_size) { + dft_plan_t plan; + cf_t pss_signal_pad[2048]; + cf_t pss_signal_time[PSS_LEN]; + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (lte_N_id_2_isvalid(N_id_2) && + fft_size < 2048) + { + + pss_generate(pss_signal_time, N_id_2); + + bzero(pss_signal_pad, fft_size * sizeof(cf_t)); + bzero(pss_signal_freq, fft_size * sizeof(cf_t)); + memcpy(&pss_signal_pad[(fft_size-PSS_LEN)/2], pss_signal_time, PSS_LEN * sizeof(cf_t)); + + if (dft_plan(&plan, fft_size, BACKWARD, COMPLEX)) { + return LIBLTE_ERROR; + } + + dft_plan_set_mirror(&plan, true); + dft_plan_set_dc(&plan, true); + dft_run_c(&plan, pss_signal_pad, pss_signal_freq); + + vec_sc_prod_cfc(pss_signal_freq, (float) 1 / (fft_size), pss_signal_pad, fft_size); + vec_conj_cc(pss_signal_pad, pss_signal_freq, fft_size); + + dft_plan_free(&plan); + + ret = LIBLTE_SUCCESS; + } + return ret; +} + +/* Initializes the PSS synchronization object with fft_size=128 */ -int pss_synch_init(pss_synch_t *q, int frame_size) { - int ret = -1; - bzero(q, sizeof(pss_synch_t)); - - q->pss_signal_freq = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); - if (!q->pss_signal_freq) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } - q->conv_abs = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(float)); - if (!q->conv_abs) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } - q->tmp_input = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); - if (!q->tmp_input) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } - q->frame_buffer = vec_malloc(4 * frame_size * sizeof(cf_t)); - if (!q->frame_buffer) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } - q->conv_output = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); - if (!q->conv_output) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; +int pss_synch_init(pss_synch_t *q, uint32_t frame_size) { + return pss_synch_init_fft(q, frame_size, 128); +} +/* Initializes the PSS synchronization object. + * + * 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 pss_synch_init_fft(pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + + uint32_t N_id_2; + uint32_t buffer_size; + bzero(q, sizeof(pss_synch_t)); + + q->N_id_2 = 10; + q->fft_size = fft_size; + q->frame_size = frame_size; + + buffer_size = fft_size + frame_size + 1; + + q->conv_abs = vec_malloc(buffer_size * sizeof(float)); + if (!q->conv_abs) { + fprintf(stderr, "Error allocating memory\n"); + goto clean_and_exit; + } + q->tmp_input = vec_malloc(buffer_size * sizeof(cf_t)); + if (!q->tmp_input) { + fprintf(stderr, "Error allocating memory\n"); + goto clean_and_exit; + } + q->conv_output = vec_malloc(buffer_size * sizeof(cf_t)); + if (!q->conv_output) { + fprintf(stderr, "Error allocating memory\n"); + goto clean_and_exit; + } + for (N_id_2=0;N_id_2<3;N_id_2++) { + q->pss_signal_freq[N_id_2] = vec_malloc(buffer_size * sizeof(cf_t)); + if (!q->pss_signal_freq[N_id_2]) { + fprintf(stderr, "Error allocating memory\n"); + goto clean_and_exit; + } + /* The PSS is translated into the frequency domain for each N_id_2 */ + if (pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], N_id_2, fft_size)) { + fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); + goto clean_and_exit; + } + } + #ifdef CONVOLUTION_FFT + if (conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) { + fprintf(stderr, "Error initiating convolution FFT\n"); + goto clean_and_exit; + } + #endif + + ret = LIBLTE_SUCCESS; } -#ifdef CONVOLUTION_FFT - if (conv_fft_cc_init(&q->conv_fft, frame_size, PSS_LEN_FREQ)) { - fprintf(stderr, "Error initiating convolution FFT\n"); - goto clean_and_exit; - } -#endif - - q->correlation_threshold = DEFAULT_CORRELATION_TH; - q->nosync_timeout_frames = DEFAULT_NOSYNC_TIMEOUT; - q->cfo_auto = true; - q->N_id_2 = -1; - q->frame_size = frame_size; - q->frame_start_idx = NOT_SYNC; - q->fb_wp = 0; - - ret = 0; - clean_and_exit: if (ret == -1) { +clean_and_exit: + if (ret == LIBLTE_ERROR) { pss_synch_free(q); } return ret; } void pss_synch_free(pss_synch_t *q) { - if (q->pss_signal_freq) { - free(q->pss_signal_freq); - } - if (q->conv_abs) { - free(q->conv_abs); - } - if (q->tmp_input) { - free(q->tmp_input); - } - if (q->frame_buffer) { - free(q->frame_buffer); - } - if (q->conv_output) { - free(q->conv_output); - } + uint32_t i; -#ifdef CONVOLUTION_FFT - conv_fft_cc_free(&q->conv_fft); -#endif + if (q) { + for (i=0;i<3;i++) { + if (q->pss_signal_freq[i]) { + free(q->pss_signal_freq[i]); + } + } + #ifdef CONVOLUTION_FFT + conv_fft_cc_free(&q->conv_fft); + + #endif + if (q->tmp_input) { + free(q->tmp_input); + } + if (q->conv_output) { + free(q->conv_output); + } + if (q->conv_abs) { + free(q->conv_abs); + } - bzero(q, sizeof(pss_synch_t)); + bzero(q, sizeof(pss_synch_t)); + } } /** * This function calculates the Zadoff-Chu sequence. * @param signal Output array. */ -int pss_generate(cf_t *signal, int N_id_2) { +int pss_generate(cf_t *signal, uint32_t N_id_2) { int i; float arg; const float root_value[] = { 25.0, 29.0, 34.0 }; @@ -130,7 +180,7 @@ int pss_generate(cf_t *signal, int N_id_2) { int sign = -1; - if (N_id_2 < 0 || N_id_2 > 2) { + if (N_id_2 > 2) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return -1; } @@ -154,7 +204,7 @@ int pss_generate(cf_t *signal, int N_id_2) { /** 36.211 10.3 section 6.11.1.2 */ -void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp) { +void pss_put_slot(cf_t *pss_signal, cf_t *slot, uint32_t nof_prb, lte_cp_t cp) { int k; k = (CP_NSYMB(cp) - 1) * nof_prb * RE_X_RB + nof_prb * RE_X_RB / 2 - 31; memset(&slot[k - 5], 0, 5 * sizeof(cf_t)); @@ -162,45 +212,17 @@ void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp) { memset(&slot[k + PSS_LEN], 0, 5 * sizeof(cf_t)); } -/** Sets the current N_id_2 value. Initializes the object for this PSS sequence - * Returns -1 on error, 0 otherwise + +/** Sets the current N_id_2 value. Returns -1 on error, 0 otherwise */ -int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2) { - q->N_id_2 = N_id_2; - - dft_plan_t plan; - cf_t pss_signal_pad[PSS_LEN_FREQ]; - cf_t pss_signal_time[PSS_LEN]; - - if (N_id_2 < 0 || N_id_2 > 2) { +int pss_synch_set_N_id_2(pss_synch_t *q, uint32_t N_id_2) { + if (!lte_N_id_2_isvalid((N_id_2))) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return -1; + } else { + q->N_id_2 = N_id_2; + return 0; } - - pss_generate(pss_signal_time, N_id_2); - - memset(pss_signal_pad, 0, PSS_LEN_FREQ * sizeof(cf_t)); - memset(q->pss_signal_freq, 0, PSS_LEN_FREQ * sizeof(cf_t)); - memcpy(&pss_signal_pad[33], pss_signal_time, PSS_LEN * sizeof(cf_t)); - - if (dft_plan(&plan, PSS_LEN_FREQ - 1, BACKWARD, COMPLEX)) { - return -1; - } - dft_plan_set_mirror(&plan, true); - dft_plan_set_dc(&plan, true); - - dft_run_c(&plan, pss_signal_pad, q->pss_signal_freq); - - vec_sc_prod_cfc(q->pss_signal_freq, (float) 1 / (PSS_LEN_FREQ - 1), - pss_signal_pad, PSS_LEN_FREQ); - - vec_conj_cc(pss_signal_pad, q->pss_signal_freq, PSS_LEN_FREQ); - - q->N_id_2 = N_id_2; - - dft_plan_free(&plan); - - return 0; } /** Returns the index of the PSS correlation peak in a subframe. @@ -209,33 +231,47 @@ int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2) { * * Input buffer must be subframe_size long. */ -int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, - float *corr_mean_value) { - int corr_peak_pos; - int conv_output_len; +int pss_synch_find_pss(pss_synch_t *q, cf_t *input, + float *corr_peak_value, float *corr_mean_value) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + input != NULL) + { - memset(&q->pss_signal_freq[PSS_LEN_FREQ], 0, q->frame_size * sizeof(cf_t)); - memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); - memset(&q->tmp_input[q->frame_size], 0, PSS_LEN_FREQ * sizeof(cf_t)); + uint32_t corr_peak_pos; + uint32_t conv_output_len; + + if (!lte_N_id_2_isvalid(q->N_id_2)) { + fprintf(stderr, "Error finding PSS peak, N_id_2 not set\n"); + return LIBLTE_ERROR; + } + + bzero(&q->pss_signal_freq[q->N_id_2][q->fft_size], q->frame_size * sizeof(cf_t)); + memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); + bzero(&q->tmp_input[q->frame_size], q->fft_size * sizeof(cf_t)); -#ifdef CONVOLUTION_FFT - conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input, - q->pss_signal_freq, q->conv_output); -#else - conv_output_len = conv_cc(input, q->pss_signal_freq, q->conv_output, q->frame_size, PSS_LEN_FREQ); -#endif + #ifdef CONVOLUTION_FFT + conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input, + q->pss_signal_freq[q->N_id_2], q->conv_output); + #else + conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); + #endif - vec_abs_cf(q->conv_output, q->conv_abs, conv_output_len); - corr_peak_pos = vec_max_fi(q->conv_abs, conv_output_len); - if (corr_peak_value) { - *corr_peak_value = q->conv_abs[corr_peak_pos]; - } - if (corr_mean_value) { - *corr_mean_value = vec_acc_ff(q->conv_abs, conv_output_len) - / conv_output_len; - } + vec_abs_cf(q->conv_output, q->conv_abs, conv_output_len); + corr_peak_pos = vec_max_fi(q->conv_abs, conv_output_len); + if (corr_peak_value) { + *corr_peak_value = q->conv_abs[corr_peak_pos] / conv_output_len; + } + if (corr_mean_value) { + *corr_mean_value = vec_acc_ff(q->conv_abs, conv_output_len) + / conv_output_len; + } - return (int) corr_peak_pos; + ret = (int) corr_peak_pos; + } + return ret; } /* Returns the CFO estimation given a PSS received sequence @@ -245,155 +281,12 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, */ float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv) { cf_t y0, y1, yr; - cf_t y[PSS_LEN_FREQ - 1]; - vec_prod_ccc_unalign(q->pss_signal_freq, pss_recv, y, PSS_LEN_FREQ - 1); - - y0 = vec_acc_cc(y, (PSS_LEN_FREQ - 1) / 2); - y1 = vec_acc_cc(&y[(PSS_LEN_FREQ - 1) / 2], (PSS_LEN_FREQ - 1) / 2); + y0 = vec_dot_prod_ccc(q->pss_signal_freq[q->N_id_2], pss_recv, q->fft_size/2); + y1 = vec_dot_prod_ccc(&q->pss_signal_freq[q->N_id_2][q->fft_size/2], &pss_recv[q->fft_size/2], q->fft_size/2); + yr = conjf(y0) * y1; return atan2f(__imag__ yr, __real__ yr) / M_PI; } -/** This function is designed to be called periodically on a subframe basis. - * The function finds the PSS correlation peak and computes (does not adjust) CFO automatically as defined by - * pss_synch_set_cfo_mode(). - * - * If the PSS sequence is not found, returns 0 writes nothing to the output buffer. - * If the PSS sequence is found, aligns the beginning of the subframe to the output buffer and returns the number of samples - * written to the output buffer. - * If synchronized, subsequent calls to this function align the input buffer to the subframe beginning. - */ -int pss_synch_frame(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples) { - int max_idx, tmp_start_idx; - int retval; - float max_value; - - if (nsamples != q->frame_size) { - fprintf(stderr, "Configured for frame size %d but got %d samples\n", - q->frame_size, nsamples); - return -1; - } - - if (q->N_id_2 < 0) { - fprintf(stderr, - "N_id_2 must be configured before calling pss_synch()\n"); - return -1; - } - - max_idx = pss_synch_find_pss(q, input, &max_value, NULL); - if (max_value > q->correlation_threshold) { - tmp_start_idx = max_idx - nsamples / 2; - if (q->frame_start_idx != tmp_start_idx) { - printf("Re-synchronizing: new index is %d, old was %d\n", - tmp_start_idx, q->frame_start_idx); - } - q->frame_start_idx = tmp_start_idx; - } else { - if (q->nosync_timeout_frames > 0) { - q->nof_nosync_frames++; - if (q->nof_nosync_frames >= q->nosync_timeout_frames) { - q->frame_start_idx = NOT_SYNC; - } - } - } - - if (q->frame_start_idx == NOT_SYNC) { - - memcpy(q->frame_buffer, input, nsamples * sizeof(cf_t)); - retval = 0; - - } else if (q->frame_start_idx > 0) { - - if (q->fb_wp) { - memcpy(&q->frame_buffer[(nsamples - q->frame_start_idx)], input, - q->frame_start_idx * sizeof(cf_t)); - memcpy(output, q->frame_buffer, nsamples * sizeof(cf_t)); - retval = nsamples; - } else { - retval = 0; - } - memcpy(q->frame_buffer, &input[q->frame_start_idx], - (nsamples - q->frame_start_idx) * sizeof(cf_t)); - q->fb_wp = 1; - - } else { - - memcpy(output, &q->frame_buffer[nsamples + q->frame_start_idx], - (-q->frame_start_idx) * sizeof(cf_t)); - memcpy(&output[-q->frame_start_idx], input, - (nsamples + q->frame_start_idx) * sizeof(cf_t)); - memcpy(&q->frame_buffer[nsamples + q->frame_start_idx], - &input[nsamples + q->frame_start_idx], - (-q->frame_start_idx) * sizeof(cf_t)); - retval = nsamples; - } - - if (q->frame_start_idx != NOT_SYNC && q->cfo_auto && retval) { - q->current_cfo = pss_synch_cfo_compute(q, - &output[q->frame_size / 2 - PSS_LEN_FREQ + 1]); - } - - return retval; -} - -void pss_synch_set_timeout(pss_synch_t *q, int nof_frames) { - q->nosync_timeout_frames = nof_frames; -} - -void pss_synch_set_threshold(pss_synch_t *q, float threshold) { - q->correlation_threshold = threshold; -} - -void pss_synch_set_cfo_mode(pss_synch_t *q, bool cfo_auto) { - q->cfo_auto = cfo_auto; -} - -float pss_synch_get_cfo(pss_synch_t *q) { - return q->current_cfo; -} - -int pss_synch_get_frame_start_idx(pss_synch_t *q) { - return q->frame_start_idx; -} - -/** High-level API */ - -int pss_synch_initialize(pss_synch_hl* h) { - int fs = h->init.frame_size; - if (!fs) { - fs = DEFAULT_FRAME_SIZE; - } - if (pss_synch_init(&h->obj, fs)) { - return -1; - } - if (h->init.unsync_nof_pkts) { - pss_synch_set_timeout(&h->obj, h->init.unsync_nof_pkts); - } - - pss_synch_set_N_id_2(&h->obj, h->init.N_id_2); - if (h->init.do_cfo) { - pss_synch_set_cfo_mode(&h->obj, true); - } else { - pss_synch_set_cfo_mode(&h->obj, false); - } - return 0; -} - -int pss_synch_work(pss_synch_hl* hl) { - - if (hl->ctrl_in.correlation_threshold) { - pss_synch_set_threshold(&hl->obj, hl->ctrl_in.correlation_threshold); - } - - hl->out_len = pss_synch_frame(&hl->obj, hl->input, hl->output, hl->in_len); - - return 0; -} - -int pss_synch_stop(pss_synch_hl* hl) { - pss_synch_free(&hl->obj); - return 0; -} - diff --git a/lte/phy/lib/sync/src/sss.c b/lte/phy/lib/sync/src/sss.c index f3b4bb62a..6feef89da 100644 --- a/lte/phy/lib/sync/src/sss.c +++ b/lte/phy/lib/sync/src/sss.c @@ -35,21 +35,58 @@ #include "liblte/phy/sync/sss.h" #include "liblte/phy/utils/dft.h" #include "liblte/phy/utils/convolution.h" +#include "liblte/phy/utils/vector.h" -void generate_sss_all_tables(struct sss_tables *tables, int N_id_2); +void generate_sss_all_tables(struct sss_tables *tables, uint32_t N_id_2); void convert_tables(struct fc_tables *fc_tables, struct sss_tables *in); -void generate_N_id_1_table(int table[30][30]); +void generate_N_id_1_table(uint32_t table[30][30]); -int sss_synch_init(sss_synch_t *q) { - bzero(q, sizeof(sss_synch_t)); +int sss_synch_init(sss_synch_t *q, uint32_t fft_size) { + + if (q != NULL && + fft_size < 2048) + { + uint32_t N_id_2; + struct sss_tables sss_tables; - if (dft_plan(&q->dftp_input, SSS_DFT_LEN, FORWARD, COMPLEX)) { - return -1; + bzero(q, sizeof(sss_synch_t)); + + if (dft_plan(&q->dftp_input, fft_size, FORWARD, COMPLEX)) { + sss_synch_free(q); + return LIBLTE_ERROR; + } + q->fft_size = fft_size; + + generate_N_id_1_table(q->N_id_1_table); + dft_plan_set_mirror(&q->dftp_input, true); + dft_plan_set_dc(&q->dftp_input, true); + + for (N_id_2=0;N_id_2<3;N_id_2++) { + generate_sss_all_tables(&sss_tables, N_id_2); + convert_tables(&q->fc_tables[N_id_2], &sss_tables); + } + q->N_id_2 = 0; + return LIBLTE_SUCCESS; + } + return LIBLTE_ERROR_INVALID_INPUTS; +} + +int sss_synch_realloc(sss_synch_t *q, uint32_t fft_size) { + if (q != NULL && + fft_size < 2048) + { + dft_plan_free(&q->dftp_input); + if (dft_plan(&q->dftp_input, fft_size, FORWARD, COMPLEX)) { + sss_synch_free(q); + return LIBLTE_ERROR; + } + dft_plan_set_mirror(&q->dftp_input, true); + dft_plan_set_dc(&q->dftp_input, true); + + q->fft_size = fft_size; + return LIBLTE_SUCCESS; } - generate_N_id_1_table(q->N_id_1_table); - dft_plan_set_mirror(&q->dftp_input, true); - dft_plan_set_dc(&q->dftp_input, true); - return 0; + return LIBLTE_ERROR_INVALID_INPUTS; } void sss_synch_free(sss_synch_t *q) { @@ -57,84 +94,41 @@ void sss_synch_free(sss_synch_t *q) { bzero(q, sizeof(sss_synch_t)); } -/** Initializes the SSS sequences for the given N_id_2 */ -int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2) { - if (N_id_2 < 0 || N_id_2 > 2) { +/** Sets the N_id_2 to search for */ +int sss_synch_set_N_id_2(sss_synch_t *q, uint32_t N_id_2) { + if (!lte_N_id_2_isvalid(N_id_2)) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); - return -1; + return LIBLTE_ERROR; + } else { + q->N_id_2 = N_id_2; + return LIBLTE_SUCCESS; } - - struct sss_tables sss_tables; - generate_sss_all_tables(&sss_tables, N_id_2); - convert_tables(&q->fc_tables, &sss_tables); - - return 0; } /** 36.211 10.3 section 6.11.2.2 */ -void sss_put_slot(float *sss, cf_t *slot, int nof_prb, lte_cp_t cp) { - int i, k; +void sss_put_slot(float *sss, cf_t *slot, uint32_t nof_prb, lte_cp_t cp) { + uint32_t i, k; k = (CP_NSYMB(cp) - 2) * nof_prb * RE_X_RB + nof_prb * RE_X_RB / 2 - 31; - memset(&slot[k - 5], 0, 5 * sizeof(cf_t)); - for (i = 0; i < SSS_LEN; i++) { - __real__ slot[k + i] = sss[i]; - __imag__ slot[k + i] = 0; - } - memset(&slot[k + SSS_LEN], 0, 5 * sizeof(cf_t)); -} - -/* In this function, input points to the beginning of the subframe. Saves result in subframe_idx and N_id_1 - * Return 1 if the sequence was found, 0 if the peak is not found, -1 if the subframe_sz or symbol_sz are - * invalid or not configured. - * Before calling this function, the correlation threshold and symbol size duration need to be set - * using sss_synch_set_threshold() and sss_synch_set_symbol_sz(). - */ -int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx, int *N_id_1) { - int m0, m1; - float m0_value, m1_value; - - if (q->subframe_sz <= 0 || q->symbol_sz <= 0) { - return -1; - } - - sss_synch_m0m1(q, &input[SSS_SYMBOL_ST(q->subframe_sz, q->symbol_sz)], &m0, - &m0_value, &m1, &m1_value); - - if (m0_value > q->corr_peak_threshold - && m1_value > q->corr_peak_threshold) { - if (subframe_idx) { - *subframe_idx = sss_synch_subframe(m0, m1); + + if (k > 5) { + memset(&slot[k - 5], 0, 5 * sizeof(cf_t)); + for (i = 0; i < SSS_LEN; i++) { + __real__ slot[k + i] = sss[i]; + __imag__ slot[k + i] = 0; } - if (N_id_1) { - *N_id_1 = sss_synch_N_id_1(q, m0, m1); - } - return 1; - } else { - return 0; + memset(&slot[k + SSS_LEN], 0, 5 * sizeof(cf_t)); } } -/** Used by sss_synch_frame() to compute the beginning of the SSS symbol - * symbol_sz MUST INCLUDE THE CYCLIC PREFIX SIZE - */ -void sss_synch_set_symbol_sz(sss_synch_t *q, int symbol_sz) { - q->symbol_sz = symbol_sz; -} - -/** Used by sss_synch_frame() to compute the beginning of the SSS symbol */ -void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz) { - q->subframe_sz = subframe_sz; -} - /** Sets the SSS correlation peak detection threshold */ void sss_synch_set_threshold(sss_synch_t *q, float threshold) { q->corr_peak_threshold = threshold; } /** Returns the subframe index based on the m0 and m1 values */ -int sss_synch_subframe(int m0, int m1) { +uint32_t sss_synch_subframe(uint32_t m0, uint32_t m1) { if (m1 > m0) { return 0; } else { @@ -143,27 +137,27 @@ int sss_synch_subframe(int m0, int m1) { } /** Returns the N_id_1 value based on the m0 and m1 values */ -int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1) { - if (m0 < 0 || m0 > 29 || m1 < 0 || m1 > 29) { - return -1; +int sss_synch_N_id_1(sss_synch_t *q, uint32_t m0, uint32_t m1) { + if (m0==m1 || m0 > 29 || m1 > 29) { + return LIBLTE_ERROR; } if (m1 > m0) { return q->N_id_1_table[m0][m1 - 1]; } else { return q->N_id_1_table[m1][m0 - 1]; - } + } } /** High-level API */ int sss_synch_initialize(sss_synch_hl* h) { - if (sss_synch_init(&h->obj)) { - return -1; + if (sss_synch_init(&h->obj, 128)) { + return LIBLTE_ERROR; } sss_synch_set_N_id_2(&h->obj, h->init.N_id_2); - return 0; + return LIBLTE_SUCCESS; } int sss_synch_work(sss_synch_hl* hl) { @@ -171,20 +165,12 @@ int sss_synch_work(sss_synch_hl* hl) { if (hl->ctrl_in.correlation_threshold) { sss_synch_set_threshold(&hl->obj, hl->ctrl_in.correlation_threshold); } - if (hl->ctrl_in.subframe_sz) { - sss_synch_set_subframe_sz(&hl->obj, hl->ctrl_in.subframe_sz); - } - if (hl->ctrl_in.symbol_sz) { - sss_synch_set_symbol_sz(&hl->obj, hl->ctrl_in.symbol_sz); - } - sss_synch_frame(&hl->obj, hl->input, &hl->ctrl_out.subframe_idx, - &hl->ctrl_out.N_id_1); - - return 0; + + return LIBLTE_SUCCESS; } int sss_synch_stop(sss_synch_hl* hl) { sss_synch_free(&hl->obj); - return 0; + return LIBLTE_SUCCESS; } diff --git a/lte/phy/lib/sync/src/sync.c b/lte/phy/lib/sync/src/sync.c index aad208eae..bb62a806f 100644 --- a/lte/phy/lib/sync/src/sync.c +++ b/lte/phy/lib/sync/src/sync.c @@ -25,53 +25,104 @@ * */ - - #include #include "liblte/phy/utils/debug.h" #include "liblte/phy/common/phy_common.h" #include "liblte/phy/sync/sync.h" +#include "liblte/phy/utils/vector.h" -int sync_init(sync_t *q, int frame_size) { - int N_id_2; - bzero(q, sizeof(sync_t)); - q->force_N_id_2 = -1; - q->threshold = 1.5; - q->pss_mode = PEAK_MEAN; - q->detect_cp = true; - q->sss_en = true; - - for (N_id_2=0;N_id_2<3;N_id_2++) { - if (pss_synch_init(&q->pss[N_id_2], frame_size)) { - fprintf(stderr, "Error initializing PSS object\n"); - return -1; - } - if (pss_synch_set_N_id_2(&q->pss[N_id_2], N_id_2)) { - fprintf(stderr, "Error initializing N_id_2\n"); - return -1; - } - if (sss_synch_init(&q->sss[N_id_2])) { - fprintf(stderr, "Error initializing SSS object\n"); - return -1; - } - if (sss_synch_set_N_id_2(&q->sss[N_id_2], N_id_2)) { - fprintf(stderr, "Error initializing N_id_2\n"); - return -1; - } - DEBUG("PSS and SSS initiated N_id_2=%d\n", N_id_2); +static bool fft_size_isvalid(uint32_t fft_size) { + if (fft_size >= FFT_SIZE_MIN && fft_size <= FFT_SIZE_MAX && (fft_size%64) == 0) { + return true; + } else { + return false; } +} - return 0; +int sync_init(sync_t *q, uint32_t find_frame_size, uint32_t track_frame_size, uint32_t fft_size) { + + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + find_frame_size > fft_size && + find_frame_size < 307200 && + fft_size_isvalid(fft_size)) + { + bzero(q, sizeof(sync_t)); + q->pss_mode = PEAK_MEAN; + q->detect_cp = true; + q->sss_en = true; + q->N_id_2 = 1000; + q->N_id_1 = 1000; + q->fft_size = fft_size; + q->find_frame_size = find_frame_size; + + if (pss_synch_init_fft(&q->pss_find, find_frame_size, fft_size)) { + fprintf(stderr, "Error initializing PSS object\n"); + return LIBLTE_ERROR; + } + if (sss_synch_init(&q->sss, fft_size)) { + fprintf(stderr, "Error initializing SSS object\n"); + return LIBLTE_ERROR; + } + if (pss_synch_init_fft(&q->pss_track, track_frame_size, fft_size)) { + fprintf(stderr, "Error initializing PSS track object\n"); + return LIBLTE_ERROR; + } + + DEBUG("SYNC init with find_frame_size=%d and fft_size=%d\n", find_frame_size, fft_size); + + ret = LIBLTE_SUCCESS; + } + return ret; +} + +int sync_realloc(sync_t *q, uint32_t find_frame_size, uint32_t track_frame_size, + uint32_t fft_size) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + find_frame_size > fft_size && + find_frame_size < 307200 && + fft_size_isvalid(fft_size)) + { + q->N_id_2 = 1000; + q->N_id_1 = 1000; + q->fft_size = fft_size; + q->find_frame_size = find_frame_size; + + pss_synch_free(&q->pss_find); + if (pss_synch_init_fft(&q->pss_find, find_frame_size, fft_size)) { + fprintf(stderr, "Error initializing PSS object\n"); + return LIBLTE_ERROR; + } + + pss_synch_free(&q->pss_track); + if (pss_synch_init_fft(&q->pss_track, track_frame_size, fft_size)) { + fprintf(stderr, "Error initializing PSS track object\n"); + return LIBLTE_ERROR; + } + + if (sss_synch_realloc(&q->sss, fft_size)) { + fprintf(stderr, "Error realloc'ing SSS object\n"); + return LIBLTE_ERROR; + } + + DEBUG("SYNC init with find_frame_size=%d and fft_size=%d\n", find_frame_size, fft_size); + + ret = LIBLTE_SUCCESS; + } + return ret; } void sync_free(sync_t *q) { - int N_id_2; - - for (N_id_2=0;N_id_2<3;N_id_2++) { - pss_synch_free(&q->pss[N_id_2]); - sss_synch_free(&q->sss[N_id_2]); + if (q) { + pss_synch_free(&q->pss_track); + pss_synch_free(&q->pss_find); + sss_synch_free(&q->sss); } } @@ -82,40 +133,42 @@ void sync_pss_det_peak_to_avg(sync_t *q) { q->pss_mode = PEAK_MEAN; } -void sync_set_threshold(sync_t *q, float threshold) { - q->threshold = threshold; -} - -void sync_force_N_id_2(sync_t *q, int force_N_id_2) { - q->force_N_id_2 = force_N_id_2; -} - -void sync_force_cp(sync_t *q, lte_cp_t cp) { - q->cp = cp; - q->detect_cp = false; +void sync_set_threshold(sync_t *q, float find_threshold, float track_threshold) { + q->find_threshold = find_threshold; + q->track_threshold = track_threshold; } void sync_sss_en(sync_t *q, bool enabled) { q->sss_en = enabled; } +bool sync_sss_detected(sync_t *q) { + return lte_N_id_1_isvalid(q->N_id_1); +} + int sync_get_cell_id(sync_t *q) { - if (q->N_id_1 >=0 && q->N_id_2 >= 0) { - return q->N_id_1*3 + q->N_id_2; + if (q->N_id_2 != 10) { + if (lte_N_id_2_isvalid(q->N_id_2) && lte_N_id_1_isvalid(q->N_id_1)) { + return q->N_id_1*3 + q->N_id_2; + } else { + fprintf(stderr, "Error getting cell_id, invalid N_id_1 or N_id_2\n"); + return LIBLTE_ERROR; + } } else { - return -1; + fprintf(stderr, "Error getting cell_id, N_id_2 not set\n"); + return LIBLTE_ERROR; } } -int sync_get_N_id_1(sync_t *q) { +uint32_t sync_get_N_id_1(sync_t *q) { return q->N_id_1; } -int sync_get_N_id_2(sync_t *q) { +uint32_t sync_get_N_id_2(sync_t *q) { return q->N_id_2; } -int sync_get_slot_id(sync_t *q) { +uint32_t sync_get_slot_id(sync_t *q) { return q->slot_id; } @@ -123,134 +176,214 @@ float sync_get_cfo(sync_t *q) { return q->cfo; } -float sync_get_peak_to_avg(sync_t *q) { - return q->peak_to_avg; +float sync_get_peak_value(sync_t *q) { + return q->peak_value; +} + +void sync_cp_en(sync_t *q, bool enabled) { + q->detect_cp = enabled; } lte_cp_t sync_get_cp(sync_t *q) { return q->cp; } -int sync_run(sync_t *q, cf_t *input) { - int N_id_2, peak_pos[3], sss_idx_n, sss_idx_e; - int m0, m1; +int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, bool en_cp) { + uint32_t m0, m1; + int sss_idx_n, sss_idx_e, ret; float m0_value_e, m1_value_e,m0_value_n, m1_value_n; - int slot_id_e, N_id_1_e, slot_id_n, N_id_1_n; + uint32_t slot_id_e, N_id_1_e, slot_id_n, N_id_1_n; + + sss_synch_set_N_id_2(&q->sss, q->N_id_2); + + /* Make sure we have enough room to find SSS sequence */ + sss_idx_n = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, CPNORM_LEN)); + sss_idx_e = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, CPEXT_LEN)); + + if (en_cp) { + if (sss_idx_n < 0 || sss_idx_e < 0) { + INFO("Not enough room to decode SSS (%d, %d)\n", sss_idx_n, sss_idx_e); + return LIBLTE_SUCCESS; + } + } else { + if (CP_ISNORM(q->cp)) { + if (sss_idx_n < 0) { + INFO("Not enough room to decode normal CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx_n, peak_pos); + return LIBLTE_SUCCESS; + } + } else { + if (sss_idx_e < 0) { + INFO("Not enough room to decode extended CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx_e, peak_pos); + return LIBLTE_SUCCESS; + } + } + } + + slot_id_n = 0; + slot_id_e = 0; + N_id_1_n = 0; + N_id_1_e = 0; + + /* try Normal CP length */ + if (en_cp || CP_ISNORM(q->cp)) { + sss_synch_m0m1(&q->sss, &input[sss_idx_n], &m0, &m0_value_n, &m1, &m1_value_n); + + slot_id_n = 2 * sss_synch_subframe(m0, m1); + ret = sss_synch_N_id_1(&q->sss, m0, m1); + if (ret >= 0) { + N_id_1_n = (uint32_t) ret; + } else { + N_id_1_n = 1000; + } + } + + if (en_cp || CP_ISEXT(q->cp)) { + /* Now try Extended CP length */ + sss_synch_m0m1(&q->sss, &input[sss_idx_e], &m0, &m0_value_e, &m1, &m1_value_e); + + slot_id_e = 2 * sss_synch_subframe(m0, m1); + ret = sss_synch_N_id_1(&q->sss, m0, m1); + if (ret >= 0) { + N_id_1_e = (uint32_t) ret; + } else { + N_id_1_e = 1000; + } + } + + /* Correlation with extended CP hypoteshis is greater than with normal? */ + if ((en_cp && m0_value_e * m1_value_e > m0_value_n * m1_value_n) + || CP_ISEXT(q->cp)) { + q->cp = CPEXT; + q->slot_id = slot_id_e; + q->N_id_1 = N_id_1_e; + /* otherwise is normal CP */ + } else { + q->cp = CPNORM; + q->slot_id = slot_id_n; + q->N_id_1 = N_id_1_n; + } + + DEBUG("SSS detected N_id_1=%d, slot_idx=%d, position=%d/%d %s CP\n", + q->N_id_1, q->slot_id, sss_idx_n, sss_idx_e, CP_ISNORM(q->cp)?"Normal":"Extended"); + + return 1; +} + +int sync_track(sync_t *q, cf_t *input, uint32_t offset, uint32_t *peak_position) { + + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + input != NULL && + fft_size_isvalid(q->fft_size)) + { + float peak_value, mean_value, *mean_ptr; + uint32_t peak_pos; + + pss_synch_set_N_id_2(&q->pss_track, q->N_id_2); + + if (q->pss_mode == ABSOLUTE) { + mean_ptr = NULL; + } else { + mean_ptr = &mean_value; + } + + peak_pos = pss_synch_find_pss(&q->pss_track, &input[offset], &peak_value, mean_ptr); + + if (q->pss_mode == ABSOLUTE) { + q->peak_value = peak_value; + } else { + q->peak_value = peak_value / mean_value; + } + + DEBUG("PSS possible tracking peak pos=%d peak=%.2f threshold=%.2f\n", + peak_pos, peak_value, q->track_threshold); + + if (peak_value > q->track_threshold) { + q->cfo = pss_synch_cfo_compute(&q->pss_track, &input[offset+peak_pos-q->fft_size]); + + if (q->sss_en) { + if (sync_sss(q, input, offset + peak_pos, false) < 0) { + fprintf(stderr, "Error synchronizing with SSS\n"); + return LIBLTE_ERROR; + } + } + + if (peak_position) { + *peak_position = peak_pos; + } + ret = 1; + } else { + ret = LIBLTE_SUCCESS; + } + } + return ret; +} + +int sync_find(sync_t *q, cf_t *input, uint32_t *peak_position) { + uint32_t N_id_2, peak_pos[3]; float peak_value[3]; float mean_value[3]; float max=-999; - int i; - int peak_detected; - - if (q->force_N_id_2 == -1) { - for (N_id_2=0;N_id_2<3;N_id_2++) { - peak_pos[N_id_2] = pss_synch_find_pss(&q->pss[N_id_2], input, - &peak_value[N_id_2], &mean_value[N_id_2]); + uint32_t i; + int ret; + float *mean_ptr; + + for (N_id_2=0;N_id_2<3;N_id_2++) { + if (q->pss_mode == ABSOLUTE) { + mean_ptr = NULL; + } else { + mean_ptr = &mean_value[N_id_2]; } - for (i=0;i<3;i++) { - if (peak_value[i] > max) { - max = peak_value[i]; - N_id_2 = i; - } + pss_synch_set_N_id_2(&q->pss_find, N_id_2); + ret = pss_synch_find_pss(&q->pss_find, input, &peak_value[N_id_2], mean_ptr); + if (ret < 0) { + fprintf(stderr, "Error finding PSS for N_id_2=%d\n", N_id_2); + return LIBLTE_ERROR; + } + peak_pos[N_id_2] = (uint32_t) ret; + + } + for (i=0;i<3;i++) { + if (peak_value[i] > max) { + max = peak_value[i]; + N_id_2 = i; } - } else { - N_id_2 = q->force_N_id_2; - peak_pos[N_id_2] = pss_synch_find_pss(&q->pss[N_id_2], input, - &peak_value[N_id_2], &mean_value[N_id_2]); } - q->peak_to_avg = peak_value[N_id_2] / mean_value[N_id_2]; - - DEBUG("PSS possible peak N_id_2=%d, pos=%d peak=%.2f par=%.2f threshold=%.2f\n", - N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->threshold); + if (peak_pos[N_id_2] > q->fft_size) { + if (q->pss_mode == ABSOLUTE) { + q->peak_value = peak_value[N_id_2]; + } else { + q->peak_value = peak_value[N_id_2] / mean_value[N_id_2]; + } + } + + DEBUG("PSS possible peak N_id_2=%d, pos=%d peak=%.2f threshold=%.2f\n", + N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->find_threshold); /* If peak detected */ - peak_detected = 0; - if (peak_pos[N_id_2] - 128 >= 0) { - if (q->pss_mode == ABSOLUTE) { - if (peak_value[N_id_2] > q->threshold) { - peak_detected = 1; - } - } else { - if (q->peak_to_avg > q->threshold) { - peak_detected = 1; + if (q->peak_value > q->find_threshold) { + q->N_id_2 = N_id_2; + pss_synch_set_N_id_2(&q->pss_find, q->N_id_2); + q->cfo = pss_synch_cfo_compute(&q->pss_find, &input[peak_pos[N_id_2]-q->fft_size]); + + DEBUG("PSS peak detected N_id_2=%d, pos=%d peak=%.2f par=%.2f th=%.2f cfo=%.4f\n", N_id_2, + peak_pos[N_id_2], peak_value[N_id_2], q->peak_value, q->find_threshold, q->cfo); + + if (q->sss_en) { + if (sync_sss(q, input, peak_pos[q->N_id_2], q->detect_cp) < 0) { + fprintf(stderr, "Error synchronizing with SSS\n"); + return LIBLTE_ERROR; } } - } - if (peak_detected) { - - q->cfo = pss_synch_cfo_compute(&q->pss[N_id_2], &input[peak_pos[N_id_2]-128]); - - INFO("PSS peak detected N_id_2=%d, pos=%d peak=%.2f par=%.2f th=%.2f cfo=%.4f\n", N_id_2, - peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->threshold, q->cfo); - - if (q->sss_en) { - - /* Make sure we have enough room to find SSS sequence */ - sss_idx_n = peak_pos[N_id_2]-2*(128+CP(128,CPNORM_LEN)); - sss_idx_e = peak_pos[N_id_2]-2*(128+CP(128,CPEXT_LEN)); - - if (q->detect_cp) { - if (sss_idx_n < 0 || sss_idx_e < 0) { - INFO("Not enough room to decode SSS (%d, %d)\n", sss_idx_n, sss_idx_e); - return -1; - } - } else { - if (CP_ISNORM(q->cp)) { - if (sss_idx_n < 0) { - INFO("Not enough room to decode SSS (%d)\n", sss_idx_n); - return -1; - } - } else { - if (sss_idx_e < 0) { - INFO("Not enough room to decode SSS (%d)\n", sss_idx_e); - return -1; - } - } - } - N_id_1_e = -1; - N_id_1_n = -1; - slot_id_e = -1; - slot_id_n = -1; - /* try Normal CP length */ - if (q->detect_cp || CP_ISNORM(q->cp)) { - sss_synch_m0m1(&q->sss[N_id_2], &input[sss_idx_n], - &m0, &m0_value_n, &m1, &m1_value_n); - - slot_id_n = 2 * sss_synch_subframe(m0, m1); - N_id_1_n = sss_synch_N_id_1(&q->sss[N_id_2], m0, m1); - } - - if (q->detect_cp || CP_ISEXT(q->cp)) { - /* Now try Extended CP length */ - sss_synch_m0m1(&q->sss[N_id_2], &input[sss_idx_e], - &m0, &m0_value_e, &m1, &m1_value_e); - - slot_id_e = 2 * sss_synch_subframe(m0, m1); - N_id_1_e = sss_synch_N_id_1(&q->sss[N_id_2], m0, m1); - } - - /* Correlation with extended CP hypoteshis is greater than with normal? */ - if ((q->detect_cp && m0_value_e * m1_value_e > m0_value_n * m1_value_n) - || CP_ISEXT(q->cp)) { - q->cp = CPEXT; - q->slot_id = slot_id_e; - q->N_id_1 = N_id_1_e; - /* then is normal CP */ - } else { - q->cp = CPNORM; - q->slot_id = slot_id_n; - q->N_id_1 = N_id_1_n; - } - q->N_id_2 = N_id_2; - - INFO("SSS detected N_id_1=%d, slot_idx=%d, %s CP\n", - q->N_id_1, q->slot_id, CP_ISNORM(q->cp)?"Normal":"Extended"); + + if (peak_position) { + *peak_position = peak_pos[N_id_2]; } - return peak_pos[N_id_2]; - + return 1; } else { - return -1; + return LIBLTE_SUCCESS; } } diff --git a/lte/phy/lib/sync/test/CMakeLists.txt b/lte/phy/lib/sync/test/CMakeLists.txt index 2c5b29c3b..72b2ccb6a 100644 --- a/lte/phy/lib/sync/test/CMakeLists.txt +++ b/lte/phy/lib/sync/test/CMakeLists.txt @@ -19,6 +19,7 @@ # and at http://www.gnu.org/licenses/. # + ######################################################################## # SYNC TEST ######################################################################## diff --git a/lte/phy/lib/sync/test/cfo_test.c b/lte/phy/lib/sync/test/cfo_test.c index 1ccb17cc2..5c6086c15 100644 --- a/lte/phy/lib/sync/test/cfo_test.c +++ b/lte/phy/lib/sync/test/cfo_test.c @@ -96,8 +96,8 @@ int main(int argc, char **argv) { return -1; } - cfo_correct(&cfocorr, output, freq); - cfo_correct(&cfocorr, output, -freq); + cfo_correct(&cfocorr, output, output, freq); + cfo_correct(&cfocorr, output, output, -freq); mse = 0; for (i=0;isize = size; h->tab = malloc(sizeof(cf_t) * size); @@ -42,9 +42,9 @@ int cexptab_init(cexptab_t *h, int size) { for (i = 0; i < size; i++) { h->tab[i] = cexpf(_Complex_I * 2 * M_PI * (float) i / size); } - return 0; + return LIBLTE_SUCCESS; } else { - return -1; + return LIBLTE_ERROR; } } @@ -55,9 +55,9 @@ void cexptab_free(cexptab_t *h) { bzero(h, sizeof(cexptab_t)); } -void cexptab_gen(cexptab_t *h, cf_t *x, float freq, int len) { - int i; - unsigned int idx; +void cexptab_gen(cexptab_t *h, cf_t *x, float freq, uint32_t len) { + uint32_t i; + uint32_t idx; float phase_inc = freq * h->size; float phase=0; @@ -68,15 +68,15 @@ void cexptab_gen(cexptab_t *h, cf_t *x, float freq, int len) { while (phase < 0) { phase += (float) h->size; } - idx = (unsigned int) phase; + idx = (uint32_t) phase; x[i] = h->tab[idx]; phase += phase_inc; } } -void cexptab_gen_direct(cf_t *x, float freq, int len) { - int i; +void cexptab_gen_direct(cf_t *x, float freq, uint32_t len) { + uint32_t i; for (i = 0; i < len; i++) { x[i] = cexpf(_Complex_I * 2 * M_PI * freq * i); } diff --git a/lte/phy/lib/utils/src/convolution.c b/lte/phy/lib/utils/src/convolution.c index 2ab27e041..721595f80 100644 --- a/lte/phy/lib/utils/src/convolution.c +++ b/lte/phy/lib/utils/src/convolution.c @@ -34,61 +34,61 @@ #include "liblte/phy/utils/convolution.h" -int conv_fft_cc_init(conv_fft_cc_t *state, int input_len, int filter_len) { - state->input_len = input_len; - state->filter_len = filter_len; - state->output_len = input_len+filter_len-1; - state->input_fft = vec_malloc(sizeof(_Complex float)*state->output_len); - state->filter_fft = vec_malloc(sizeof(_Complex float)*state->output_len); - state->output_fft = vec_malloc(sizeof(_Complex float)*state->output_len); - if (!state->input_fft || !state->filter_fft || !state->output_fft) { - return -1; +int conv_fft_cc_init(conv_fft_cc_t *q, uint32_t input_len, uint32_t filter_len) { + q->input_len = input_len; + q->filter_len = filter_len; + q->output_len = input_len+filter_len; + q->input_fft = vec_malloc(sizeof(cf_t)*q->output_len); + q->filter_fft = vec_malloc(sizeof(cf_t)*q->output_len); + q->output_fft = vec_malloc(sizeof(cf_t)*q->output_len); + if (!q->input_fft || !q->filter_fft || !q->output_fft) { + return LIBLTE_ERROR; } - if (dft_plan(&state->input_plan,state->output_len,FORWARD,COMPLEX)) { - return -2; + if (dft_plan(&q->input_plan,q->output_len,FORWARD,COMPLEX)) { + return LIBLTE_ERROR; } - if (dft_plan(&state->filter_plan,state->output_len,FORWARD,COMPLEX)) { - return -3; + if (dft_plan(&q->filter_plan,q->output_len,FORWARD,COMPLEX)) { + return LIBLTE_ERROR; } - if (dft_plan(&state->output_plan,state->output_len,BACKWARD,COMPLEX)) { - return -4; + if (dft_plan(&q->output_plan,q->output_len,BACKWARD,COMPLEX)) { + return LIBLTE_ERROR; } - return 0; + return LIBLTE_SUCCESS; } -void conv_fft_cc_free(conv_fft_cc_t *state) { - if (state->input_fft) { - free(state->input_fft); +void conv_fft_cc_free(conv_fft_cc_t *q) { + if (q->input_fft) { + free(q->input_fft); } - if (state->filter_fft) { - free(state->filter_fft); + if (q->filter_fft) { + free(q->filter_fft); } - if (state->output_fft) { - free(state->output_fft); + if (q->output_fft) { + free(q->output_fft); } - dft_plan_free(&state->input_plan); - dft_plan_free(&state->filter_plan); - dft_plan_free(&state->output_plan); + dft_plan_free(&q->input_plan); + dft_plan_free(&q->filter_plan); + dft_plan_free(&q->output_plan); } -int conv_fft_cc_run(conv_fft_cc_t *state, _Complex float *input, _Complex float *filter, _Complex float *output) { +uint32_t conv_fft_cc_run(conv_fft_cc_t *q, cf_t *input, cf_t *filter, cf_t *output) { - dft_run_c(&state->input_plan, input, state->input_fft); - dft_run_c(&state->filter_plan, filter, state->filter_fft); + dft_run_c(&q->input_plan, input, q->input_fft); + dft_run_c(&q->filter_plan, filter, q->filter_fft); - vec_prod_ccc(state->input_fft,state->filter_fft,state->output_fft,state->output_len); + vec_prod_ccc(q->input_fft,q->filter_fft,q->output_fft,q->output_len); - dft_run_c(&state->output_plan, state->output_fft, output); + dft_run_c(&q->output_plan, q->output_fft, output); - return state->output_len; + return q->output_len; } -int conv_cc(_Complex float *input, _Complex float *filter, _Complex float *output, int input_len, int filter_len) { - int i,j; - int output_len; +uint32_t conv_cc(cf_t *input, cf_t *filter, cf_t *output, uint32_t input_len, uint32_t filter_len) { + uint32_t i,j; + uint32_t output_len; output_len=input_len+filter_len-1; - memset(output,0,output_len*sizeof(_Complex float)); + memset(output,0,output_len*sizeof(cf_t)); for (i=0;i #include #include +#include + +#include "liblte/phy/utils/vector.h" +#include "liblte/phy/utils/bit.h" #ifdef HAVE_VOLK #include "volk/volk.h" #endif -int vec_acc_ii(int *x, int len) { +int vec_acc_ii(int *x, uint32_t len) { int i; int z=0; for (i=0;im) { m=x[i]; @@ -244,7 +414,7 @@ int vec_max_fi(float *x, int len) { #endif } -void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, int len) { +void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, uint32_t len) { int i; int tmp; for (i=0;i 128 && i threshold) - y=ccf.*x(i-128:i-1); - - y0=y(1:64); - y1=y(65:length(y)); - - eps=angle(conj(sum(y0))*sum(y1))/pi; - else - eps = NaN; - fs = NaN; - end end diff --git a/matlab/sync/find_pss2.m b/matlab/sync/find_pss2.m new file mode 100644 index 000000000..a4b5b8d3d --- /dev/null +++ b/matlab/sync/find_pss2.m @@ -0,0 +1,18 @@ +function [ fs eps p_m w2] = find_pss( x, N_id_2, fft_size) + c=lte_pss_zc(N_id_2); + cc=[zeros(fft_size/2-31,1); c; zeros(fft_size/2-31,1)]; + cc=[0; cc(fft_size/2+1:fft_size); cc(2:fft_size/2)]; + ccf=conj(ifft(cc)); + + w2=conv(x,ccf); + %plot(10*log10(abs(w2)));%./mean(abs(w2)))); + plot(abs(w2)) + %axis([0 length(w2) 0 20]) + [m i]=max(abs(w2)); + p_m = m/mean(abs(w2)); + + fprintf('Frame starts at %d, m=%g, p=%g, p/m=%g dB\n',i, ... + mean(abs(w2)), m, 10*log10(m/mean(abs(w2)))); + +end + diff --git a/matlab/sync/lte_generate_sss.m b/matlab/sync/lte_generate_sss.m deleted file mode 100644 index d8b45e914..000000000 --- a/matlab/sync/lte_generate_sss.m +++ /dev/null @@ -1,123 +0,0 @@ -% -% Copyright 2011-2012 Ben Wojtowicz -% -% This program 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. -% -% This program 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. -% -% You should have received a copy of the GNU Affero General Public License -% along with this program. If not, see . -% -% Function: lte_generate_sss -% Description: Generates LTE secondary synchronization signals -% Inputs: N_id_1 - Physical layer cell identity group -% N_id_2 - Physical layer identity -% Outputs: sss_d_u_0 - The sequence d(n) used for the secondary -% synchronization signal, an interleaved -% concatenation of two length-31 binary -% sequences for subframe 0 -% Outputs: sss_d_u_5 - The sequence d(n) used for the secondary -% synchronization signal, an interleaved -% concatenation of two length-31 binary -% sequences for subframe 5 -% Spec: 3GPP TS 36.211 section 6.11.2.1 v10.1.0 -% Notes: None -% Rev History: Ben Wojtowicz 10/28/2011 Created -% Ben Wojtowicz 01/29/2012 Fixed license statement -% -function [sss_d_u_0, sss_d_u_5 c0 c1 m0 m1] = lte_generate_sss(N_id_1, N_id_2) - % Validate N_id_1 - if(~(N_id_1 >= 0 && N_id_1 <= 167)) - fprintf('ERROR: Invalid N_id_1 (%u)\n', N_id_1); - sss_d_u_0 = 0; - sss_d_u_5 = 0; - return; - end - - % Validate N_id_2 - if(~(N_id_2 >= 0 && N_id_2 <= 2)) - fprintf('ERROR: Invalid N_id_2 (%u)\n', N_id_2); - sss_d_u_0 = 0; - sss_d_u_5 = 0; - return; - end - - % Generate m0 and m1 - q_prime = floor(N_id_1/30); - q = floor((N_id_1 + (q_prime*(q_prime+1)/2))/30); - m_prime = N_id_1 + (q*(q+1)/2); - m0 = mod(m_prime, 31); - m1 = mod((m0 + floor(m_prime/31) + 1), 31); - - % Generate s_tilda - x_s_tilda(0+1) = 0; - x_s_tilda(1+1) = 0; - x_s_tilda(2+1) = 0; - x_s_tilda(3+1) = 0; - x_s_tilda(4+1) = 1; - for(i_hat=0:25) - x_s_tilda(i_hat+5+1) = mod((x_s_tilda(i_hat+2+1) + x_s_tilda(i_hat+1)), 2); - end - for(idx=0:30) - s_tilda(idx+1) = 1 - 2*x_s_tilda(idx+1); - end - - % Generate c_tilda - x_c_tilda(0+1) = 0; - x_c_tilda(1+1) = 0; - x_c_tilda(2+1) = 0; - x_c_tilda(3+1) = 0; - x_c_tilda(4+1) = 1; - for(i_hat=0:25) - x_c_tilda(i_hat+5+1) = mod((x_c_tilda(i_hat+3+1) + x_c_tilda(i_hat+1)), 2); - end - for(idx=0:30) - c_tilda(idx+1) = 1 - 2*x_c_tilda(idx+1); - end - - % Generate z_tilda - x_z_tilda(0+1) = 0; - x_z_tilda(1+1) = 0; - x_z_tilda(2+1) = 0; - x_z_tilda(3+1) = 0; - x_z_tilda(4+1) = 1; - for(i_hat=0:25) - x_z_tilda(i_hat+5+1) = mod((x_z_tilda(i_hat+4+1) + x_z_tilda(i_hat+2+1) + x_z_tilda(i_hat+1+1) + x_z_tilda(i_hat+1)), 2); - end - for(idx=0:30) - z_tilda(idx+1) = 1 - 2*x_z_tilda(idx+1); - end - - % Generate s0_m0 and s1_m1 - for(n=0:30) - s0_m0(n+1) = s_tilda(mod(n + m0, 31)+1); - s1_m1(n+1) = s_tilda(mod(n + m1, 31)+1); - end - - % Generate c0 and c1 - for(n=0:30) - c0(n+1) = c_tilda(mod(n + N_id_2, 31)+1); - c1(n+1) = c_tilda(mod(n + N_id_2 + 3, 31)+1); - end - - % Generate z1_m0 and z1_m1 - for(n=0:30) - z1_m0(n+1) = z_tilda(mod(n + mod(m0, 8), 31)+1); - z1_m1(n+1) = z_tilda(mod(n + mod(m1, 8), 31)+1); - end - - % Generate SSS - for(n=0:30) - sss_d_u_0(2*n+1) = s0_m0(n+1) * c0(n+1); - sss_d_u_5(2*n+1) = s1_m1(n+1) * c0(n+1); - - sss_d_u_0(2*n+1+1) = s1_m1(n+1) * c1(n+1) * z1_m0(n+1); - sss_d_u_5(2*n+1+1) = s0_m0(n+1) * c1(n+1) * z1_m1(n+1); - end -end diff --git a/matlab/sync/test.m b/matlab/sync/test.m deleted file mode 100644 index 33d3d6e92..000000000 --- a/matlab/sync/test.m +++ /dev/null @@ -1,35 +0,0 @@ -N=128; %128 subcarries -M=16; %QAM order -cp=9; %length of the cyclic prefix... Is increasing the cyclic prefix size gonna increase the efficiency? -scale = 1/sqrt(10); -hMod = modem.qammod(M); %QAM Modulator -hDemod = modem.qamdemod(hMod); %QAM demodulator -loops = 10; -SNR =0:5:35; -t1= cputime ; -% transmited signal. Contains N data points ranging from 0 to M-1 -ber=zeros(5,length(SNR)); -%% Creating the Rayleigh Multipath Channels -Ch = rayleighchan(1/1000,10); -Ch.ResetBeforeFiltering = 0; -sig = 1i*ones(loops,1); -h1 = filter(Ch,sig); -h2 = 0.1072*filter(Ch,sig); -h3 = 0.0120*filter(Ch,sig); -h4 = 0.0052*filter(Ch,sig); -% Delay Values -l1 = 4; -l2 = 7; -l3= 16; -%% -ofdm_cp=[]; - %tx=transmited_data; - for ik=1:loops%number of loops - tx = randi([0 M-1],1,N); % generate random data - sig=modulate(hMod, tx)*scale; % Modulate QAM modulated signal, devide by the square root of 10 to bring the average power of the signal to 1 - ofdm=sqrt(N).*ifft(sig,N); % generate OFDM signal IFFT on the parrellel data,multiply by sqrt(N) to adjust to the matlab computation , - ofdm_cp = [ofdm_cp ofdm(N-cp+1:N) ofdm]; % Add cyclic prefix - - end - - \ No newline at end of file