Merge pull request #37 from ismagom/master

Changed data types and introduced lte_cell_t structure. Fixed some bugs with PDSCH.
master
Ismael Gómez-Miguelez 11 years ago
commit 0f53f877ed

@ -36,7 +36,7 @@ PROJECT (LIBLTE)
LIST(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules") LIST(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules")
INCLUDE(libLTEPackage) #setup cpack INCLUDE(libLTEPackage) #setup cpack
include(CTest) include(CTest)
set( CTEST_MEMORYCHECK_COMMAND valgrind ) set( CTEST_MEMORYCHECK_COMMAND valgrind )
@ -78,6 +78,9 @@ ENDIF(CMAKE_COMPILER_IS_GNUCXX)
IF(CMAKE_COMPILER_IS_GNUCC) 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") 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) IF(NOT WIN32)
ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
ENDIF(NOT WIN32) ENDIF(NOT WIN32)

@ -5,7 +5,7 @@ FIND_PATH(
VOLK_INCLUDE_DIRS VOLK_INCLUDE_DIRS
NAMES volk.h NAMES volk.h
HINTS $ENV{VOLK_DIR}/include/volk HINTS $ENV{VOLK_DIR}/include/volk
${CMAKE_INSTALL_PREFIX}/include/volk ${CMAKE_INSTALL_PREFIX}/include/volk
${PC_VOLK_INCLUDE_DIR} ${PC_VOLK_INCLUDE_DIR}
PATHS /usr/local/include/volk PATHS /usr/local/include/volk
/usr/include/volk /usr/include/volk
@ -15,9 +15,9 @@ FIND_LIBRARY(
VOLK_LIBRARIES VOLK_LIBRARIES
NAMES volk NAMES volk
HINTS $ENV{VOLK_DIR}/lib HINTS $ENV{VOLK_DIR}/lib
${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/lib
${CMAKE_INSTALL_PREFIX}/lib64 ${CMAKE_INSTALL_PREFIX}/lib64
${PC_VOLK_LIBDIR} ${PC_VOLK_LIBDIR}
PATHS /usr/local/lib PATHS /usr/local/lib
/usr/local/lib64 /usr/local/lib64
/usr/lib /usr/lib
@ -25,35 +25,79 @@ FIND_LIBRARY(
) )
# Some functions are not defined in old volk versions # 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_index_max_16u HAVE_VOLK_MAX_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_accumulator_s32f HAVE_VOLK_ACC_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_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_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_32fc HAVE_VOLK_MULT2_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_conjugate_32fc HAVE_VOLK_MULT2_CONJ_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_multiply_32fc HAVE_VOLK_MULT_REAL_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_multiply_32f HAVE_VOLK_MULT_FLOAT_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_32f HAVE_VOLK_MAG_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_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") 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}) IF(${HAVE_VOLK_MAX_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION") SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION")
ENDIF() ENDIF()
IF(${HAVE_VOLK_ACC_FUNCTION}) IF(${HAVE_VOLK_ACC_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ACC_FUNCTION") SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ACC_FUNCTION")
ENDIF() ENDIF()
IF(${HAVE_VOLK_MULT_FUNCTION}) IF(${HAVE_VOLK_MULT_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FUNCTION") SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FUNCTION")
ENDIF() ENDIF()
IF(${HAVE_VOLK_CONJ_FUNCTION}) IF(${HAVE_VOLK_CONJ_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONJ_FUNCTION") SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONJ_FUNCTION")
ENDIF() ENDIF()
IF(${HAVE_VOLK_MULT2_FUNCTION}) 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() ENDIF()
IF(${HAVE_VOLK_MAG_FUNCTION}) 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() ENDIF()
INCLUDE(FindPackageHandleStandardArgs) INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS) FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS)
MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_DEFINITIONS) MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_DEFINITIONS)

@ -31,26 +31,63 @@
extern "C" { extern "C" {
#endif #endif
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include "liblte/config.h" #include "liblte/config.h"
#include "liblte/cuhd/cuhd_utils.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_close(void *h);
LIBLTE_API int cuhd_start_rx_stream(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_start_rx_stream_nsamples(void *h,
uint32_t nsamples);
LIBLTE_API int cuhd_stop_rx_stream(void *h); LIBLTE_API int cuhd_stop_rx_stream(void *h);
LIBLTE_API bool cuhd_rx_wait_lo_locked(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_srate(void *h,
LIBLTE_API double cuhd_set_rx_freq(void *h, double freq); double freq);
LIBLTE_API int cuhd_recv(void *h, void *data, int nsamples, int blocking);
LIBLTE_API double cuhd_set_rx_gain(void *h,
LIBLTE_API double cuhd_set_tx_srate(void *h, double freq); double gain);
LIBLTE_API double cuhd_set_tx_gain(void *h, double gain);
LIBLTE_API double cuhd_set_tx_freq(void *h, double freq); LIBLTE_API double cuhd_set_rx_freq(void *h,
LIBLTE_API int cuhd_send(void *h, void *data, int nsamples, int blocking); 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 #ifdef __cplusplus

@ -30,9 +30,9 @@
class cuhd_handler { class cuhd_handler {
public: public:
uhd::usrp::multi_usrp::sptr usrp; uhd::usrp::multi_usrp::sptr usrp;
uhd::rx_streamer::sptr rx_stream; uhd::rx_streamer::sptr rx_stream;
bool rx_stream_enable; bool rx_stream_enable;
uhd::tx_streamer::sptr tx_stream; uhd::tx_streamer::sptr tx_stream;
}; };

@ -35,8 +35,9 @@
#include "liblte/cuhd/cuhd.h" #include "liblte/cuhd/cuhd.h"
void my_handler(uhd::msg::type_t type, const std::string &msg){ void my_handler(uhd::msg::type_t type, const std::string & msg)
//handle the message... {
//handle the message...
} }
typedef _Complex float complex_t; typedef _Complex float complex_t;
@ -45,161 +46,216 @@ typedef _Complex float complex_t;
bool isLocked(void *h) bool isLocked(void *h)
{ {
cuhd_handler* handler = static_cast<cuhd_handler*>(h); cuhd_handler *handler = static_cast < cuhd_handler * >(h);
std::vector<std::string> mb_sensors = handler->usrp->get_mboard_sensor_names(); std::vector < std::string > mb_sensors =
std::vector<std::string> rx_sensors = handler->usrp->get_rx_sensor_names(0); handler->usrp->get_mboard_sensor_names();
if(std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") != rx_sensors.end()) { std::vector < std::string > rx_sensors =
return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool(); handler->usrp->get_rx_sensor_names(0);
} if (std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") !=
else if(std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") != mb_sensors.end()) { rx_sensors.end()) {
return handler->usrp->get_mboard_sensor("ref_locked", 0).to_bool(); return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool();
} } else if (std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") !=
else { mb_sensors.end()) {
usleep(500); return handler->usrp->get_mboard_sensor("ref_locked", 0).to_bool();
return true; } else {
} usleep(500);
return true;
}
} }
bool cuhd_rx_wait_lo_locked(void *h) bool cuhd_rx_wait_lo_locked(void *h)
{ {
double report = 0.0; double report = 0.0;
while(isLocked(h) && report < 3.0) while (isLocked(h) && report < 3.0) {
{ report += 0.1;
report += 0.1; usleep(1000);
usleep(1000); }
} return isLocked(h);
return isLocked(h); }
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 < 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, 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 + ", master_clock_rate=30720000");
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);
*h = handler;
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 < cuhd_handler * >(h);
handler->usrp->set_rx_rate(freq);
double ret = handler->usrp->get_rx_rate();
return ret;
} }
int cuhd_start_rx_stream(void *h) { double cuhd_set_rx_gain(void *h, double gain)
cuhd_handler* handler = static_cast<cuhd_handler*>(h); {
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); cuhd_handler *handler = static_cast < cuhd_handler * >(h);
cmd.time_spec = handler->usrp->get_time_now(); handler->usrp->set_rx_gain(gain);
cmd.stream_now = true; return handler->usrp->get_rx_gain();
handler->usrp->issue_stream_cmd(cmd);
return 0;
} }
int cuhd_stop_rx_stream(void *h) { double cuhd_set_rx_freq(void *h, double freq)
cuhd_handler* handler = static_cast<cuhd_handler*>(h); {
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); cuhd_handler *handler = static_cast < cuhd_handler * >(h);
cmd.time_spec = handler->usrp->get_time_now(); handler->usrp->set_rx_freq(freq);
cmd.stream_now = true; return handler->usrp->get_rx_freq();
handler->usrp->issue_stream_cmd(cmd);
return 0;
} }
int cuhd_start_rx_stream_nsamples(void *h, int nsamples) { double cuhd_set_rx_freq_offset(void *h, double freq, double off) {
cuhd_handler* handler = static_cast<cuhd_handler*>(h); cuhd_handler* handler = static_cast<cuhd_handler*>(h);
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE); handler->usrp->set_rx_freq(uhd::tune_request_t(freq,off));
cmd.time_spec = handler->usrp->get_time_now(); return handler->usrp->get_rx_freq();
cmd.stream_now = true;
cmd.num_samps = nsamples;
handler->usrp->issue_stream_cmd(cmd);
return 0;
} }
int cuhd_open(char *args, void **h) { int cuhd_recv(void *h, void *data, uint32_t nsamples, bool blocking)
cuhd_handler* handler = new cuhd_handler(); {
std::string _args=std::string(args); cuhd_handler *handler = static_cast < cuhd_handler * >(h);
handler->usrp = uhd::usrp::multi_usrp::make(_args); uhd::rx_metadata_t md;
if (blocking) {
// Try to set LTE clock int n = 0, p;
handler->usrp->set_master_clock_rate(30720000); complex_t *data_c = (complex_t *) data;
do {
handler->usrp->set_clock_source("internal"); p = handler->rx_stream->recv(&data_c[n], nsamples - n, md);
if (p == -1) {
std::string otw, cpu; return -1;
otw="sc16"; }
cpu="fc32"; n += p;
uhd::stream_args_t stream_args(cpu, otw); if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) {
handler->rx_stream = handler->usrp->get_rx_stream(stream_args); std::cout << "\nError code: " << md.to_pp_string() << "\n\n";
handler->tx_stream = handler->usrp->get_tx_stream(stream_args); }
} while (n < nsamples);
*h = handler; return nsamples;
} else {
return 0; return handler->rx_stream->recv(data, nsamples, md, 0.0);
} }
}
int cuhd_close(void *h) {
cuhd_stop_rx_stream(h); int cuhd_recv_timed(void *h,
/** Something else to close the USRP?? */ void *data,
return 0; uint32_t nsamples,
} int blocking,
time_t *secs,
double *frac_secs) {
double cuhd_set_rx_srate(void *h, double freq) { cuhd_handler* handler = static_cast<cuhd_handler*>(h);
cuhd_handler* handler = static_cast<cuhd_handler*>(h); uhd::rx_metadata_t md;
handler->usrp->set_rx_rate(freq); *secs = -1;
double ret = handler->usrp->get_rx_rate(); *frac_secs = -1;
return ret; int p;
} if (blocking) {
int n=0;
double cuhd_set_rx_gain(void *h, double gain) { complex_t *data_c = (complex_t*) data;
cuhd_handler* handler = static_cast<cuhd_handler*>(h); do {
handler->usrp->set_rx_gain(gain); p=handler->rx_stream->recv(&data_c[n], nsamples-n, md);
return handler->usrp->get_rx_gain(); if (p == -1) {
} return -1;
}
double cuhd_set_rx_freq(void *h, double freq) { if(*secs < 0){
cuhd_handler* handler = static_cast<cuhd_handler*>(h); *secs = md.time_spec.get_full_secs();
handler->usrp->set_rx_freq(freq); *frac_secs = md.time_spec.get_frac_secs();
return handler->usrp->get_rx_freq(); }
} n+=p;
} while(n<nsamples);
int cuhd_recv(void *h, void *data, int nsamples, int blocking) { return n;
cuhd_handler* handler = static_cast<cuhd_handler*>(h); } else {
uhd::rx_metadata_t md; p = handler->rx_stream->recv(data, nsamples, md, 0.0);
if (blocking) { *secs = md.time_spec.get_full_secs();
int n=0,p; *frac_secs = md.time_spec.get_frac_secs();
complex_t *data_c = (complex_t*) data; return p;
do { }
p=handler->rx_stream->recv(&data_c[n], nsamples-n, md); }
if (p == -1) {
return -1;
} double cuhd_set_tx_gain(void *h, double gain)
n+=p; {
} while(n<nsamples); cuhd_handler *handler = static_cast < cuhd_handler * >(h);
return nsamples; handler->usrp->set_tx_gain(gain);
} else { return handler->usrp->get_tx_gain();
return handler->rx_stream->recv(data, nsamples, md, 0.0); }
}
} double cuhd_set_tx_srate(void *h, double freq)
{
double cuhd_set_tx_gain(void *h, double gain) { cuhd_handler *handler = static_cast < cuhd_handler * >(h);
cuhd_handler* handler = static_cast<cuhd_handler*>(h); handler->usrp->set_tx_rate(freq);
handler->usrp->set_tx_gain(gain); return handler->usrp->get_tx_rate();
return handler->usrp->get_tx_gain(); }
}
double cuhd_set_tx_freq(void *h, double freq)
double cuhd_set_tx_srate(void *h, double freq) { {
cuhd_handler* handler = static_cast<cuhd_handler*>(h); cuhd_handler *handler = static_cast < cuhd_handler * >(h);
handler->usrp->set_tx_rate(freq); handler->usrp->set_tx_freq(freq);
return handler->usrp->get_tx_rate(); return handler->usrp->get_tx_freq();
} }
double cuhd_set_tx_freq(void *h, double freq) { int cuhd_send(void *h, void *data, uint32_t nsamples, bool blocking)
cuhd_handler* handler = static_cast<cuhd_handler*>(h); {
handler->usrp->set_tx_freq(freq); cuhd_handler *handler = static_cast < cuhd_handler * >(h);
return handler->usrp->get_tx_freq(); uhd::tx_metadata_t md;
} if (blocking) {
int n = 0, p;
int cuhd_send(void *h, void *data, int nsamples, int blocking) { complex_t *data_c = (complex_t *) data;
cuhd_handler* handler = static_cast<cuhd_handler*>(h); do {
uhd::tx_metadata_t md; p = handler->tx_stream->send(&data_c[n], nsamples - n, md);
if (blocking) { if (p == -1) {
int n=0,p; return -1;
complex_t *data_c = (complex_t*) data; }
do { n += p;
p=handler->tx_stream->send(&data_c[n], nsamples-n, md); } while (n < nsamples);
if (p == -1) { return nsamples;
return -1; } else {
} return handler->tx_stream->send(data, nsamples, md, 0.0);
n+=p; }
} while(n<nsamples);
return nsamples;
} else {
return handler->tx_stream->send(data, nsamples, md, 0.0);
}
} }

@ -34,10 +34,10 @@ INSTALL(DIRECTORY include/
SET(HEADERS_ALL "") SET(HEADERS_ALL "")
FILE(GLOB headers *) FILE(GLOB headers *)
FOREACH (_header ${headers}) FOREACH (_header ${headers})
IF(IS_DIRECTORY ${_header}) IF(IS_DIRECTORY ${_header})
FILE(GLOB_RECURSE tmp "${_header}/*.h") FILE(GLOB_RECURSE tmp "${_header}/*.h")
LIST(APPEND HEADERS_ALL ${tmp}) LIST(APPEND HEADERS_ALL ${tmp})
ENDIF(IS_DIRECTORY ${_header}) ENDIF(IS_DIRECTORY ${_header})
ENDFOREACH() ENDFOREACH()
ADD_CUSTOM_TARGET (add_lte_headers SOURCES ${HEADERS_ALL}) ADD_CUSTOM_TARGET (add_lte_headers SOURCES ${HEADERS_ALL})

@ -51,26 +51,26 @@ LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND)
# These two can be compiled without UHD or graphics support # These two can be compiled without UHD or graphics support
################################################################# #################################################################
add_executable(pbch_ue pbch_ue.c) add_executable(pdsch_ue pdsch_ue.c iodev.c)
target_link_libraries(pbch_ue lte_phy) target_link_libraries(pdsch_ue lte_phy)
add_executable(pbch_enodeb pbch_enodeb.c) add_executable(pdsch_enodeb pdsch_enodeb.c)
target_link_libraries(pbch_enodeb lte_phy) target_link_libraries(pdsch_enodeb lte_phy)
IF(${CUHD_FIND} EQUAL -1) IF(${CUHD_FIND} EQUAL -1)
SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
ELSE(${CUHD_FIND} EQUAL -1) ELSE(${CUHD_FIND} EQUAL -1)
target_link_libraries(pbch_ue cuhd) target_link_libraries(pdsch_ue cuhd)
target_link_libraries(pbch_enodeb cuhd) target_link_libraries(pdsch_enodeb cuhd)
ENDIF(${CUHD_FIND} EQUAL -1) ENDIF(${CUHD_FIND} EQUAL -1)
IF(${GRAPHICS_FIND} EQUAL -1) IF(${GRAPHICS_FIND} EQUAL -1)
SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
ELSE(${GRAPHICS_FIND} EQUAL -1) ELSE(${GRAPHICS_FIND} EQUAL -1)
target_link_libraries(pbch_ue graphics) target_link_libraries(pdsch_ue graphics)
target_link_libraries(pbch_enodeb graphics) target_link_libraries(pdsch_enodeb graphics)
ENDIF(${GRAPHICS_FIND} EQUAL -1) ENDIF(${GRAPHICS_FIND} EQUAL -1)
@ -81,17 +81,17 @@ ENDIF(${GRAPHICS_FIND} EQUAL -1)
IF(${CUHD_FIND} GREATER -1) IF(${CUHD_FIND} GREATER -1)
add_executable(scan_rssi scan_rssi.c) add_executable(scan_rssi scan_rssi.c)
target_link_libraries(scan_rssi lte_phy cuhd ) target_link_libraries(scan_rssi lte_phy cuhd )
add_executable(scan_pss scan_pss.c) add_executable(scan_pss scan_pss.c)
target_link_libraries(scan_pss lte_phy cuhd ) target_link_libraries(scan_pss lte_phy cuhd )
add_executable(scan_mib scan_mib.c) add_executable(scan_mib scan_mib.c)
target_link_libraries(scan_mib lte_phy cuhd ) 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) 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) ENDIF(${CUHD_FIND} GREATER -1)

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}

@ -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

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#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<NSLOTS_X_FRAME;i++) {
if (refsignal_init_LTEDL(&refs[i], 0, i, cell_id, CPNORM, nof_prb)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1;
}
}
mib.nof_ports = 1;
mib.nof_prb = 6;
mib.phich_length = PHICH_NORM;
mib.phich_resources = R_1;
mib.sfn = 0;
for (i=0;i<MAX_PORTS_CTRL;i++) { // now there's only 1 port
slot1_symbols[i] = slot_buffer;
}
#ifndef DISABLE_UHD
if (!output_file_name) {
printf("Set TX rate: %.2f MHz\n", cuhd_set_tx_srate(uhd, UHD_SAMP_FREQ)/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
nf = 0;
while(nf<nof_frames || nof_frames == -1) {
for (ns=0;ns<NSLOTS_X_FRAME;ns++) {
bzero(slot_buffer, sizeof(cf_t) * slot_n_re);
switch(ns) {
case 0: // tx pss/sss
case 10: // tx pss/sss
pss_put_slot(pss_signal, slot_buffer, nof_prb, CPNORM);
sss_put_slot(ns?sss_signal5:sss_signal0, slot_buffer, nof_prb, CPNORM);
break;
case 1: // tx pbch
pbch_encode(&pbch, &mib, slot1_symbols, 1);
break;
default: // transmit zeros
break;
}
refsignal_put(&refs[ns], slot_buffer);
/* Transform to OFDM symbols */
lte_ifft_run(&ifft, slot_buffer, output_buffer);
/* send to file or usrp */
if (output_file_name) {
filesink_write(&fsink, output_buffer, slot_n_samples);
usleep(5000);
} else {
#ifndef DISABLE_UHD
vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, slot_n_samples);
cuhd_send(uhd, output_buffer, slot_n_samples, 1);
#endif
}
}
mib.sfn=(mib.sfn+1)%1024;
printf("SFN: %4d\r", mib.sfn);fflush(stdout);
nf++;
}
base_free();
printf("Done\n");
exit(0);
}

@ -1,501 +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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#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_PORTS_CTRL;i++) {
ce[i] = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
if (!ce[i]) {
perror("malloc");
return -1;
}
}
if (sync_init(&sfind, FLEN)) {
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, NOF_PORTS)) {
fprintf(stderr, "Error initializing equalizer\n");
return -1;
}
if (cfo_init(&cfocorr, FLEN)) {
fprintf(stderr, "Error initiating CFO\n");
return -1;
}
if (lte_fft_init(&fft, CPNORM, 6)) {
fprintf(stderr, "Error initializing FFT\n");
return -1;
}
return 0;
}
void base_free() {
int i;
if (input_file_name) {
filesource_free(&fsrc);
} else {
#ifndef DISABLE_UHD
cuhd_close(uhd);
#endif
}
#ifndef DISABLE_GRAPHICS
plot_exit();
#endif
sync_free(&sfind);
sync_free(&strack);
lte_fft_free(&fft);
chest_free(&chest);
cfo_free(&cfocorr);
free(input_buffer);
free(fft_buffer);
for (i=0;i<MAX_PORTS_CTRL;i++) {
free(ce[i]);
}
}
int mib_decoder_init(int cell_id) {
if (chest_ref_LTEDL(&chest, cell_id)) {
fprintf(stderr, "Error initializing reference signal\n");
return -1;
}
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error initiating PBCH\n");
return -1;
}
DEBUG("PBCH initiated cell_id=%d\n", cell_id);
return 0;
}
int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
int i, n;
lte_fft_run(&fft, input, fft_buffer);
/* Get channel estimates for each port */
for (i=0;i<NOF_PORTS;i++) {
chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i);
}
DEBUG("Decoding PBCH\n", 0);
n = pbch_decode(&pbch, fft_buffer, ce, 1, mib);
#ifndef DISABLE_GRAPHICS
float tmp[72*7];
if (!disable_plots) {
for (i=0;i<72*7;i++) {
tmp[i] = 10*log10f(cabsf(fft_buffer[i]));
}
plot_real_setNewData(&poutfft, tmp, 72*7);
plot_complex_setNewData(&pce, ce[0], 72*7);
plot_scatter_setNewData(&pscatrecv, pbch.pbch_symbols[0], pbch.nof_symbols);
if (n) {
plot_scatter_setNewData(&pscatequal, pbch.pbch_d, pbch.nof_symbols);
}
}
#endif
return n;
}
void sigintHandler(int sig_num)
{
go_exit=1;
}
int main(int argc, char **argv) {
int frame_cnt;
int cell_id;
int find_idx, track_idx, last_found;
enum sync_state state;
int nslot;
pbch_mib_t mib;
float cfo;
int n;
int nof_found_mib = 0;
float timeoffset = 0;
#ifdef DISABLE_UHD
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
#endif
parse_args(argc,argv);
if (base_init(FLEN)) {
fprintf(stderr, "Error initializing memory\n");
exit(-1);
}
sync_pss_det_peak_to_avg(&sfind);
sync_pss_det_peak_to_avg(&strack);
if (!input_file_name) {
#ifndef DISABLE_UHD
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
cuhd_set_rx_srate(uhd, SAMP_FREQ);
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);
DEBUG("Starting receiver...\n",0);
cuhd_start_rx_stream(uhd);
#endif
}
printf("\n --- Press Ctrl+C to exit --- \n");
signal(SIGINT, sigintHandler);
state = FIND;
nslot = 0;
find_idx = 0;
cfo = 0;
mib.sfn = -1;
frame_cnt = 0;
last_found = 0;
sync_set_threshold(&sfind, find_threshold);
sync_force_N_id_2(&sfind, -1);
while(!go_exit && (frame_cnt < nof_frames || nof_frames==-1)) {
INFO(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
if (input_file_name) {
n = filesource_read(&fsrc, input_buffer, FLEN);
if (n == -1) {
fprintf(stderr, "Error reading file\n");
exit(-1);
} else if (n < FLEN) {
filesource_seek(&fsrc, 0);
filesource_read(&fsrc, input_buffer, FLEN);
}
} else {
#ifndef DISABLE_UHD
cuhd_recv(uhd, input_buffer, FLEN, 1);
#endif
}
switch(state) {
case FIND:
/* find peak in all frame */
find_idx = sync_run(&sfind, input_buffer);
INFO("FIND %3d:\tPAR=%.2f\n", frame_cnt, sync_get_peak_to_avg(&sfind));
if (find_idx != -1) {
/* if found peak, go to track and set track threshold */
cell_id = sync_get_cell_id(&sfind);
if (cell_id != -1) {
frame_cnt = -1;
last_found = 0;
sync_set_threshold(&strack, track_threshold);
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
sync_force_cp(&strack, sync_get_cp(&sfind));
mib_decoder_init(cell_id);
nof_found_mib = 0;
nslot = sync_get_slot_id(&sfind);
nslot=(nslot+10)%20;
cfo = 0;
timeoffset = 0;
printf("\n");
state = TRACK;
} else {
printf("cellid=-1\n");
}
}
if (verbose == VERBOSE_NONE) {
printf("Finding PSS... PAR=%.2f\r", sync_get_peak_to_avg(&sfind));
}
break;
case TRACK:
/* Find peak around known position find_idx */
INFO("TRACK %3d: PSS find_idx %d offset %d\n", frame_cnt, find_idx, find_idx - track_len);
track_idx = sync_run(&strack, &input_buffer[find_idx - track_len]);
if (track_idx != -1) {
/* compute cumulative moving average CFO */
cfo = (sync_get_cfo(&strack) + frame_cnt * cfo) / (frame_cnt + 1);
/* compute cumulative moving average time offset */
timeoffset = (float) (track_idx-track_len + timeoffset * frame_cnt) / (frame_cnt + 1);
last_found = frame_cnt;
find_idx = (find_idx + track_idx - track_len)%FLEN;
if (nslot != sync_get_slot_id(&strack)) {
INFO("Expected slot %d but got %d\n", nslot, sync_get_slot_id(&strack));
printf("\r\n");
fflush(stdout);
printf("\r\n");
state = FIND;
}
} else {
/* if sync not found, adjust time offset with the averaged value */
find_idx = (find_idx + (int) timeoffset)%FLEN;
}
/* if we missed too many PSS go back to FIND */
if (frame_cnt - last_found > 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);
}

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#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(&regs, R_1, PHICH_NORM, cell)) {
fprintf(stderr, "Error initiating regs\n");
exit(-1);
}
if (pcfich_init(&pcfich, &regs, cell)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
if (regs_set_cfi(&regs, cfi)) {
fprintf(stderr, "Error setting CFI\n");
exit(-1);
}
if (pdcch_init(&pdcch, &regs, 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(&regs);
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<NSUBFRAMES_X_FRAME;i++) {
pdcch_ue_locations(&pdcch, locations[i], 10, i, cfi, 1234);
}
data = malloc(sizeof(char) * ra_dl.mcs.tbs);
if (!data) {
perror("malloc");
exit(-1);
}
nf = 0;
if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &prb_alloc)) {
fprintf(stderr, "Error configuring HARQ process\n");
exit(-1);
}
while (nf < nof_frames || nof_frames == -1) {
for (sf_idx = 0; sf_idx < NSUBFRAMES_X_FRAME && (nf < nof_frames || nof_frames == -1); sf_idx++) {
bzero(sf_buffer, sizeof(cf_t) * sf_n_re);
if (sf_idx == 0 || sf_idx == 5) {
pss_put_slot(pss_signal, sf_buffer, cell.nof_prb, CPNORM);
sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, cell.nof_prb,
CPNORM);
}
if (sf_idx == 0) {
pbch_encode(&pbch, &mib, sf_symbols);
}
for (n=0;n<2;n++) {
refsignal_put(&refs[2*sf_idx+n], &sf_buffer[n*sf_n_re/2]);
}
pcfich_encode(&pcfich, cfi, sf_symbols, sf_idx);
INFO("SF: %d, Generating %d random bits\n", sf_idx, ra_dl.mcs.tbs);
for (i=0;i<ra_dl.mcs.tbs;i++) {
data[i] = rand()%2;
}
INFO("Puttting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L);
if (pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], 1234, sf_symbols, sf_idx, cfi)) {
fprintf(stderr, "Error encoding DCI message\n");
exit(-1);
}
pdsch_encode(&pdsch, data, sf_symbols, sf_idx, &harq_process, ra_dl.rv_idx);
/* Transform to OFDM symbols */
lte_ifft_run_sf(&ifft, sf_buffer, output_buffer);
/* send to file or usrp */
if (output_file_name) {
filesink_write(&fsink, output_buffer, sf_n_samples);
usleep(5000);
} else {
#ifndef DISABLE_UHD
vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, sf_n_samples);
cuhd_send(uhd, output_buffer, sf_n_samples, true);
#endif
}
nf++;
}
mib.sfn = (mib.sfn + 1) % 1024;
printf("SFN: %4d\r", mib.sfn);
fflush(stdout);
}
base_free();
printf("Done\n");
exit(0);
}

@ -0,0 +1,323 @@
/**
*
* \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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#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

@ -53,7 +53,7 @@
#define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold) #define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold)
int band, earfcn=-1; 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; int earfcn_start=-1, earfcn_end = -1;
float rssi_threshold = -45.0; float rssi_threshold = -45.0;
int max_track_lost=9; int max_track_lost=9;
@ -64,7 +64,7 @@ cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS];
pbch_t pbch; pbch_t pbch;
lte_fft_t fft; lte_fft_t fft;
chest_t chest; chest_t chest;
sync_t sfind, strack; sync_t ssync;
cfo_t cfocorr; cfo_t cfocorr;
float *cfo_v; float *cfo_v;
@ -86,7 +86,7 @@ enum sync_state {INIT, FIND, TRACK, MIB, DONE};
void usage(char *prog) { 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-s earfcn_start [Default All]\n");
printf("\t-e earfcn_end [Default All]\n"); printf("\t-e earfcn_end [Default All]\n");
printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi); 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_nof_frames [Default %d]\n", nof_frames_find);
printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold); 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_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-l pss_track_len [Default %d]\n", track_len);
printf("\t-g gain [Default %.2f dB]\n", uhd_gain); printf("\t-g gain [Default %.2f dB]\n", uhd_gain);
printf("\t-v [set verbose to debug, default none]\n"); 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) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -1) { while ((opt = getopt(argc, argv, "bseRrFfTgv")) != -1) {
switch(opt) { switch(opt) {
case 'b': case 'b':
band = atoi(argv[optind]); band = atoi(argv[optind]);
@ -128,9 +127,6 @@ void parse_args(int argc, char **argv) {
case 'T': case 'T':
nof_frames_track = atoi(argv[optind]); nof_frames_track = atoi(argv[optind]);
break; break;
case 't':
track_threshold = atof(argv[optind]);
break;
case 'g': case 'g':
uhd_gain = atof(argv[optind]); uhd_gain = atof(argv[optind]);
break; break;
@ -166,15 +162,11 @@ int base_init(int frame_length) {
return -1; return -1;
} }
} }
if (sync_init(&sfind, FLEN)) { if (sync_init(&ssync, FLEN, 128, 128)) {
fprintf(stderr, "Error initiating PSS/SSS\n"); fprintf(stderr, "Error initiating PSS/SSS\n");
return -1; return -1;
} }
if (sync_init(&strack, track_len)) { if (chest_init(&chest, CPNORM, 6, MAX_PORTS)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
return -1;
}
if (chest_init(&chest, LINEAR, CPNORM, 6, MAX_PORTS)) {
fprintf(stderr, "Error initializing equalizer\n"); fprintf(stderr, "Error initializing equalizer\n");
return -1; return -1;
} }
@ -235,8 +227,7 @@ void base_free() {
cuhd_close(uhd); cuhd_close(uhd);
#endif #endif
sync_free(&sfind); sync_free(&ssync);
sync_free(&strack);
lte_fft_free(&fft); lte_fft_free(&fft);
chest_free(&chest); chest_free(&chest);
cfo_free(&cfocorr); cfo_free(&cfocorr);
@ -320,12 +311,18 @@ int rssi_scan() {
int mib_decoder_init(int cell_id) { 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"); fprintf(stderr, "Error initializing reference signal\n");
return -1; return -1;
} }
if (pbch_init(&pbch, 6, cell_id, CPNORM)) { if (pbch_init(&pbch, cell)) {
fprintf(stderr, "Error initiating PBCH\n"); fprintf(stderr, "Error initiating PBCH\n");
return -1; 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 mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
int i; int i;
lte_fft_run(&fft, input, fft_buffer); lte_fft_run_slot(&fft, input, fft_buffer);
/* Get channel estimates for each port */ /* Get channel estimates for each port */
for (i=0;i<MAX_PORTS;i++) { for (i=0;i<MAX_PORTS;i++) {
@ -343,7 +340,7 @@ int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
} }
DEBUG("Decoding PBCH\n", 0); DEBUG("Decoding PBCH\n", 0);
return pbch_decode(&pbch, fft_buffer, ce, 1, mib); return pbch_decode(&pbch, fft_buffer, ce, mib);
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
@ -352,13 +349,15 @@ int main(int argc, char **argv) {
int cell_id; int cell_id;
float max_peak_to_avg; float max_peak_to_avg;
float sfo; float sfo;
int find_idx, track_idx, last_found; uint32_t track_idx, find_idx;
int last_found;
enum sync_state state; enum sync_state state;
int n; int n;
int mib_attempts; int mib_attempts;
int nslot; int nslot;
pbch_mib_t mib; pbch_mib_t mib;
int ret;
if (argc < 3) { if (argc < 3) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
@ -371,8 +370,7 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
sync_pss_det_peak_to_avg(&sfind); sync_pss_det_peak_to_avg(&ssync);
sync_pss_det_peak_to_avg(&strack);
nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN); nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
printf("RSSI scan: %d freqs in band %d, RSSI threshold %.2f dBm\n", nof_bands, band, rssi_threshold); printf("RSSI scan: %d freqs in band %d, RSSI threshold %.2f dBm\n", nof_bands, band, rssi_threshold);
@ -438,27 +436,24 @@ int main(int argc, char **argv) {
cuhd_recv(uhd, input_buffer, FLEN, 1); cuhd_recv(uhd, input_buffer, FLEN, 1);
#endif #endif
/* set find_threshold and go to FIND state */ /* set find_threshold and go to FIND state */
sync_set_threshold(&sfind, find_threshold); sync_set_threshold(&ssync, find_threshold, find_threshold/2);
sync_force_N_id_2(&sfind, -1);
state = FIND; state = FIND;
break; break;
case FIND: case FIND:
/* find peak in all frame */ /* find peak in all frame */
find_idx = sync_run(&sfind, &input_buffer[FLEN]); ret = sync_find(&ssync, &input_buffer[FLEN], &find_idx);
DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind)); DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_value(&ssync));
if (find_idx != -1) { if (ret == 1) {
/* if found peak, go to track and set lower threshold */ /* if found peak, go to track and set lower threshold */
frame_cnt = -1; frame_cnt = -1;
last_found = 0; last_found = 0;
max_peak_to_avg = -1; max_peak_to_avg = -1;
sync_set_threshold(&strack, track_threshold); cell_id = sync_get_cell_id(&ssync);
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
cell_id = sync_get_cell_id(&sfind);
state = TRACK; state = TRACK;
INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands, INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd, channels[freq].id, channels[freq].fd,
10*log10f(sync_get_peak_to_avg(&sfind))); 10*log10f(sync_get_peak_value(&ssync)));
} else { } else {
if (frame_cnt >= nof_frames_find) { if (frame_cnt >= nof_frames_find) {
state = INIT; state = INIT;
@ -469,20 +464,20 @@ int main(int argc, char **argv) {
case TRACK: case TRACK:
INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx - track_len); 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]); ret = sync_track(&ssync, input_buffer, FLEN + find_idx - track_len, &track_idx);
p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack); p2a_v[frame_cnt] = sync_get_peak_value(&ssync);
/* save cell id for the best peak-to-avg */ /* save cell id for the best peak-to-avg */
if (p2a_v[frame_cnt] > max_peak_to_avg) { if (p2a_v[frame_cnt] > max_peak_to_avg) {
max_peak_to_avg = p2a_v[frame_cnt]; 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) { if (ret == 1) {
cfo_v[frame_cnt] = sync_get_cfo(&strack); cfo_v[frame_cnt] = sync_get_cfo(&ssync);
last_found = frame_cnt; last_found = frame_cnt;
find_idx += track_idx - track_len; find_idx += track_idx - track_len;
idx_v[frame_cnt] = find_idx; idx_v[frame_cnt] = find_idx;
nslot = sync_get_slot_id(&strack); nslot = sync_get_slot_id(&ssync);
} else { } else {
idx_v[frame_cnt] = -1; idx_v[frame_cnt] = -1;
cfo_v[frame_cnt] = 0.0; cfo_v[frame_cnt] = 0.0;
@ -513,7 +508,7 @@ int main(int argc, char **argv) {
// Correct CFO // Correct CFO
INFO("Correcting CFO=%.4f\n", cfo[freq]); 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 (nslot == 0) {
if (mib_decoder_run(&input_buffer[FLEN+find_idx], &mib)) { if (mib_decoder_run(&input_buffer[FLEN+find_idx], &mib)) {

@ -261,10 +261,12 @@ int main(int argc, char **argv) {
sync_t sfind, strack; sync_t sfind, strack;
float max_peak_to_avg; float max_peak_to_avg;
float sfo; float sfo;
int find_idx, track_idx, last_found; uint32_t find_idx, track_idx;
int last_found;
enum sync_state state; enum sync_state state;
int n; int n;
filesink_t fs; filesink_t fs;
int ret;
if (argc < 3) { if (argc < 3) {
usage(argv[0]); usage(argv[0]);
@ -278,13 +280,13 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
if (sync_init(&sfind, FLEN)) { if (sync_init(&sfind, FLEN, 128, 128)) {
fprintf(stderr, "Error initiating PSS/SSS\n"); fprintf(stderr, "Error initiating PSS/SSS\n");
exit(-1); exit(-1);
} }
sync_pss_det_peak_to_avg(&sfind); 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"); fprintf(stderr, "Error initiating PSS/SSS\n");
exit(-1); exit(-1);
} }
@ -315,6 +317,9 @@ int main(int argc, char **argv) {
max_peak_to_avg = 0; max_peak_to_avg = 0;
last_found = 0; last_found = 0;
frame_cnt = 0; frame_cnt = 0;
sync_set_threshold(&sfind, find_threshold, track_threshold);
while(freq<nof_bands) { while(freq<nof_bands) {
/* scan only bands above rssi_threshold */ /* scan only bands above rssi_threshold */
if (!IS_SIGNAL(freq)) { if (!IS_SIGNAL(freq)) {
@ -346,25 +351,20 @@ int main(int argc, char **argv) {
/* receive first frame */ /* receive first frame */
cuhd_recv(uhd, input_buffer, FLEN, 1); cuhd_recv(uhd, input_buffer, FLEN, 1);
/* set find_threshold and go to FIND state */
sync_set_threshold(&sfind, find_threshold);
sync_force_N_id_2(&sfind, -1);
state = FIND; state = FIND;
break; break;
case FIND: case FIND:
/* find peak in all frame */ /* find peak in all frame */
find_idx = sync_run(&sfind, &input_buffer[FLEN]); ret = sync_find(&sfind, &input_buffer[FLEN], &find_idx);
DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind)); DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_value(&sfind));
if (find_idx != -1) { if (ret == 1) {
/* if found peak, go to track and set lower threshold */ /* if found peak, go to track and set lower threshold */
frame_cnt = -1; frame_cnt = -1;
last_found = 0; last_found = 0;
sync_set_threshold(&strack, track_threshold);
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
state = TRACK; state = TRACK;
INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands, INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd, channels[freq].id, channels[freq].fd,
10*log10f(sync_get_peak_to_avg(&sfind))); 10*log10f(sync_get_peak_value(&sfind)));
} else { } else {
if (frame_cnt >= nof_frames_find) { if (frame_cnt >= nof_frames_find) {
state = INIT; state = INIT;
@ -382,15 +382,15 @@ int main(int argc, char **argv) {
filesink_write(&fs, &input_buffer[FLEN+find_idx+track_len], track_len); filesink_write(&fs, &input_buffer[FLEN+find_idx+track_len], track_len);
track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]); ret = sync_find(&strack, &input_buffer[FLEN + find_idx - track_len], &track_idx);
p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack); p2a_v[frame_cnt] = sync_get_peak_value(&strack);
/* save cell id for the best peak-to-avg */ /* save cell id for the best peak-to-avg */
if (p2a_v[frame_cnt] > max_peak_to_avg) { if (p2a_v[frame_cnt] > max_peak_to_avg) {
max_peak_to_avg = p2a_v[frame_cnt]; max_peak_to_avg = p2a_v[frame_cnt];
cell_id = sync_get_cell_id(&strack); cell_id = sync_get_cell_id(&strack);
} }
if (track_idx != -1) { if (ret == 1) {
cfo_v[frame_cnt] = sync_get_cfo(&strack); cfo_v[frame_cnt] = sync_get_cfo(&strack);
last_found = frame_cnt; last_found = frame_cnt;
find_idx += track_idx - track_len; find_idx += track_idx - track_len;

@ -112,10 +112,10 @@ int main(int argc, char **argv) {
float mean_value[3]; float mean_value[3];
int frame_cnt; int frame_cnt;
cf_t *input; cf_t *input;
int m0, m1; uint32_t m0, m1;
float m0_value, m1_value; float m0_value, m1_value;
int N_id_2; uint32_t N_id_2;
int sss_idx; uint32_t sss_idx;
struct timeval tdata[3]; struct timeval tdata[3];
int *exec_time; int *exec_time;
@ -173,7 +173,7 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error initializing N_id_2\n"); fprintf(stderr, "Error initializing N_id_2\n");
exit(-1); 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"); fprintf(stderr, "Error initializing SSS object\n");
exit(-1); exit(-1);
} }
@ -196,7 +196,7 @@ int main(int argc, char **argv) {
gettimeofday(&tdata[1], NULL); gettimeofday(&tdata[1], NULL);
if (force_cfo != CFO_AUTO) { 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) { if (force_N_id_2 != -1) {

@ -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 <stdbool.h>
#include <stdint.h>
#include <complex.h>
#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_

@ -33,14 +33,19 @@
#include <stdio.h> #include <stdio.h>
#include "liblte/config.h" #include "liblte/config.h"
#include "liblte/phy/resampling/interp.h"
#include "liblte/phy/ch_estimation/refsignal.h" #include "liblte/phy/ch_estimation/refsignal.h"
#include "liblte/phy/filter/filter2d.h"
#include "liblte/phy/common/phy_common.h" #include "liblte/phy/common/phy_common.h"
typedef _Complex float cf_t; /* this is only a shortcut */ typedef _Complex float cf_t; /* this is only a shortcut */
typedef enum {LINEAR} chest_interp_t; typedef void (*interpolate_fnc_t) (cf_t *input,
typedef void (*interpolate_fnc_t) (cf_t *input, cf_t *output, int M, int len, int off_st, int off_end); cf_t *output,
uint32_t M,
uint32_t len,
uint32_t off_st,
uint32_t off_end);
/** This is an OFDM channel estimator. /** This is an OFDM channel estimator.
* It works with any reference signal pattern, provided by the object * 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 */ /* Low-level API */
typedef struct LIBLTE_API{ typedef struct LIBLTE_API {
int nof_ports; uint32_t nof_ports;
int nof_symbols; uint32_t nof_re;
int nof_prb; uint32_t nof_symbols;
lte_cp_t cp;
refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME]; 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; }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,
LIBLTE_API void chest_free(chest_t *q); uint32_t nof_re,
uint32_t nof_symbols,
LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id); uint32_t nof_ports);
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 void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref); LIBLTE_API void chest_free(chest_t *q);
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 void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id); LIBLTE_API int chest_set_nof_ports(chest_t *q,
LIBLTE_API void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id); uint32_t nof_ports);
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_init_LTEDL(chest_t *q,
LIBLTE_API int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]); lte_cell_t cell);
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 */ /* High-level API */
@ -91,8 +159,7 @@ typedef struct LIBLTE_API{
cf_t *input; cf_t *input;
int in_len; int in_len;
struct chest_ctrl_in { struct chest_ctrl_in {
int slot_id; // slot id in the 10ms frame int sf_idx; // subframe id in the 10ms frame
int cell_id;
} ctrl_in; } ctrl_in;
cf_t *output[MAX_PORTS]; cf_t *output[MAX_PORTS];
int out_len[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); LIBLTE_API int chest_stop(chest_hl* hl);
#endif #endif

@ -43,26 +43,30 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
int time_idx; uint32_t time_idx;
int freq_idx; uint32_t freq_idx;
cf_t simbol; cf_t simbol;
cf_t recv_simbol; cf_t recv_simbol;
}ref_t; }ref_t;
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
int nof_refs; // number of reference signals uint32_t nof_refs; // number of reference signals
int *symbols_ref; // symbols with at least one reference uint32_t *symbols_ref; // symbols with at least one reference
int nsymbols; // number of symbols with at least one reference uint32_t nsymbols; // number of symbols with at least one reference
int voffset; // offset of the first reference in the freq domain uint32_t voffset; // offset of the first reference in the freq domain
int nof_prb; uint32_t nof_prb;
ref_t *refs; ref_t *refs;
cf_t *ch_est; cf_t *ch_est;
} refsignal_t; } refsignal_t;
LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot, LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q,
int cell_id, lte_cp_t cp, int nof_prb); uint32_t port_id,
uint32_t nslot,
lte_cell_t cell);
LIBLTE_API void refsignal_free(refsignal_t *q); 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 #endif

@ -34,8 +34,16 @@
typedef _Complex float cf_t; 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_c(const cf_t* input,
LIBLTE_API void ch_awgn_f(const float* x, float* y, float variance, int buff_sz); 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 */ /* High-level API */

@ -42,20 +42,41 @@ typedef _Complex float cf_t; /* this is only a shortcut */
/* This is common for both directions */ /* This is common for both directions */
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
dft_plan_t fft_plan; dft_plan_t fft_plan;
int nof_symbols; uint32_t nof_symbols;
int symbol_sz; uint32_t symbol_sz;
int nof_guards; uint32_t nof_guards;
int nof_re; uint32_t nof_re;
lte_cp_t cp_type; uint32_t slot_sz;
lte_cp_t cp;
cf_t *tmp; // for removing zero padding cf_t *tmp; // for removing zero padding
}lte_fft_t; }lte_fft_t;
LIBLTE_API int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb); 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_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_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb); 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 void lte_ifft_free(lte_fft_t *q); 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 #endif

@ -29,44 +29,50 @@
#ifndef _LTEBASE_ #ifndef _LTEBASE_
#define _LTEBASE_ #define _LTEBASE_
#include <stdint.h>
#include <stdbool.h>
#include "liblte/config.h" #include "liblte/config.h"
#define NSUBFRAMES_X_FRAME 10 #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_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_NULL_SYMBOL 2
#define LTE_NIL_SYMBOL 2 #define LTE_NIL_SYMBOL 2
#define MAX_PORTS 4 #define MAX_PORTS 4
#define MAX_PORTS_CTRL 4
#define MAX_LAYERS 8 #define MAX_LAYERS 8
#define MAX_CODEWORDS 2 #define MAX_CODEWORDS 2
#define LTE_CRC24A 0x1864CFB #define LTE_CRC24A 0x1864CFB
#define LTE_CRC24B 0X1800063 #define LTE_CRC24B 0X1800063
#define LTE_CRC16 0x11021 #define LTE_CRC16 0x11021
#define LTE_CRC8 0x19B #define LTE_CRC8 0x19B
typedef enum {CPNORM, CPEXT} lte_cp_t; typedef enum {CPNORM, CPEXT} lte_cp_t;
#define SIRNTI 0xFFFF #define SIRNTI 0xFFFF
#define PRNTI 0xFFFE #define PRNTI 0xFFFE
#define MRNTI 0xFFFD #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_SF_NSYMB 2*CPNORM_NSYMB
#define CPNORM_0_LEN 160 #define CPNORM_0_LEN 160
#define CPNORM_LEN 144 #define CPNORM_LEN 144
#define CPEXT_NSYMB 6 #define CPEXT_NSYMB 6
#define CPEXT_SF_NSYMB 2*CPEXT_NSYMB #define CPEXT_SF_NSYMB 2*CPEXT_NSYMB
#define CPEXT_LEN 512 #define CPEXT_LEN 512
#define CPEXT_7_5_LEN 1024 #define CPEXT_7_5_LEN 1024
#define CP_ISNORM(cp) (cp==CPNORM) #define CP_ISNORM(cp) (cp==CPNORM)
#define CP_ISEXT(cp) (cp==CPEXT) #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_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_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_CPNORM(symbol_sz) (2*SLOT_LEN_CPNORM(symbol_sz))
#define SF_LEN_CPEXT(symbol_sz) 2*SLOT_LEN_CPEXT(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(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_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 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 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 RS_VSHIFT(cell_id) (cell_id%6)
#define GUARD_RE(nof_prb) ((lte_symbol_sz(nof_prb)-nof_prb*RE_X_RB)/2) #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_LTE_BANDS 29
#define NOF_TC_CB_SIZES 188 #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 { typedef enum LIBLTE_API {
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX 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 { 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 { 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 { typedef struct LIBLTE_API {
int id; int id;
@ -123,16 +140,59 @@ LIBLTE_API enum band_geographical_area {
ALL, NAR, APAC, EMEA, JAPAN, CALA, NA ALL, NAR, APAC, EMEA, JAPAN, CALA, NA
}; };
LIBLTE_API int lte_cb_size(int index); LIBLTE_API bool lte_cell_isvalid(lte_cell_t *cell);
LIBLTE_API int lte_find_cb_index(int long_cb);
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 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 int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type); 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 char *lte_mimotype2str(lte_mimo_type_t type); LIBLTE_API char *lte_mimotype2str(lte_mimo_type_t type);
#endif #endif

@ -33,19 +33,39 @@
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
char *c; char *c;
int len; uint32_t len;
} sequence_t; } 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 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,
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_pbch(sequence_t *seq, lte_cp_t cp, int cell_id); LIBLTE_API int sequence_pdsch(sequence_t *seq,
LIBLTE_API int sequence_pcfich(sequence_t *seq, int nslot, int cell_id); unsigned short rnti,
LIBLTE_API int sequence_phich(sequence_t *seq, int nslot, int cell_id); int q,
LIBLTE_API int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len); uint32_t nslot,
LIBLTE_API int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, uint32_t cell_id,
int nslot, int cell_id, int len); uint32_t len);
#endif #endif

@ -34,13 +34,13 @@
#include "liblte/config.h" #include "liblte/config.h"
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int R; uint32_t R;
int K; uint32_t K;
int poly[3]; uint32_t poly[3];
bool tail_biting; bool tail_biting;
}convcoder_t; }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 */ /* High-level API */

@ -30,6 +30,7 @@
#define CRC_ #define CRC_
#include "liblte/config.h" #include "liblte/config.h"
#include <stdint.h>
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
unsigned long table[256]; 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_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 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 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 #endif

@ -33,8 +33,15 @@
#define RX_NULL 10000 #define RX_NULL 10000
#define TX_NULL 80 #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_tx(char *input,
LIBLTE_API int rm_conv_rx(float *input, int in_len, float *output, int out_len); 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 */ /* High-level API */
typedef struct typedef struct

@ -40,25 +40,30 @@
#include "liblte/config.h" #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 int rm_turbo_tx(char *w_buff,
LIBLTE_API void rm_turbo_free(rm_turbo_t *q); uint32_t buff_len,
LIBLTE_API int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, char *input,
int out_len, int rv_idx); uint32_t in_len,
LIBLTE_API int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, char *output,
float *output, int out_len, int rv_idx); 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 */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
rm_turbo_t q;
struct rm_turbo_init { struct rm_turbo_init {
int direction; int direction;
} init; } 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; int in_len;
struct rm_turbo_ctrl_in { struct rm_turbo_ctrl_in {
int E; int E;

@ -31,15 +31,15 @@
#include "liblte/config.h" #include "liblte/config.h"
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int *forward; uint32_t *forward;
int *reverse; uint32_t *reverse;
int max_long_cb; uint32_t max_long_cb;
} tc_interl_t; } tc_interl_t;
LIBLTE_API int tc_interl_LTE_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, int 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); LIBLTE_API void tc_interl_free(tc_interl_t *h);
#endif #endif

@ -37,13 +37,13 @@
#define TOTALTAIL 12 #define TOTALTAIL 12
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int max_long_cb; uint32_t max_long_cb;
tc_interl_t interl; tc_interl_t interl;
} tcod_t; } 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 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 #endif

@ -68,13 +68,25 @@ typedef struct LIBLTE_API {
tc_interl_t interleaver; tc_interl_t interleaver;
} tdec_t; } tdec_t;
LIBLTE_API int tdec_init(tdec_t *h, int max_long_cb); LIBLTE_API int tdec_init(tdec_t * h,
LIBLTE_API void tdec_free(tdec_t *h); uint32_t max_long_cb);
LIBLTE_API int tdec_reset(tdec_t *h, int long_cb); LIBLTE_API void tdec_free(tdec_t * h);
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 int tdec_reset(tdec_t * h, uint32_t 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_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 #endif

@ -38,21 +38,34 @@ typedef enum {
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
void *ptr; void *ptr;
int R; uint32_t R;
int K; uint32_t K;
unsigned int framebits; unsigned int framebits;
bool tail_biting; bool tail_biting;
int poly[3]; uint32_t poly[3];
int (*decode) (void*, unsigned char*, char*, int); int (*decode) (void*, uint8_t*, char*, uint32_t);
void (*free) (void*); void (*free) (void*);
unsigned char *tmp; unsigned char *tmp;
unsigned char *symbols_uc; unsigned char *symbols_uc;
}viterbi_t; }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 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 */ /* High-level API */

@ -38,13 +38,13 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API { 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; }demod_hard_t;
LIBLTE_API void demod_hard_init(demod_hard_t* q); 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 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, int nsymbols); 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 { typedef struct LIBLTE_API {
demod_hard_t obj; demod_hard_t obj;
struct demod_hard_init { 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; } init;
cf_t* input; cf_t* input;

@ -56,7 +56,7 @@ typedef struct LIBLTE_API {
modem_table_t table; modem_table_t table;
struct demod_soft_init{ 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; } init;
const cf_t* input; const cf_t* input;

@ -37,13 +37,13 @@
typedef _Complex float cf_t; 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 */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
modem_table_t obj; modem_table_t obj;
struct mod_init { 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; } init;
const char* input; const char* input;

@ -34,30 +34,36 @@
#include <complex.h> #include <complex.h>
#include <stdint.h> #include <stdint.h>
#include "liblte/phy/common/phy_common.h"
#include "liblte/config.h" #include "liblte/config.h"
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int idx[2][6][32]; uint32_t idx[2][6][32];
}soft_table_t; }soft_table_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
cf_t* symbol_table; // bit-to-symbol mapping cf_t* symbol_table; // bit-to-symbol mapping
soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating) soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating)
int nsymbols; // number of modulation symbols uint32_t nsymbols; // number of modulation symbols
int nbits_x_symbol; // number of bits per symbol uint32_t nbits_x_symbol; // number of bits per symbol
}modem_table_t; }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_init(modem_table_t* q);
LIBLTE_API void modem_table_free(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 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_ #endif // MODEM_TABLE_

@ -62,41 +62,72 @@ typedef enum {
} dci_spec_t; } dci_spec_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
unsigned char nof_bits; uint32_t L; // Aggregation level
unsigned char L; // Aggregation level uint32_t ncce; // Position of first CCE of the dci
unsigned char ncce; // Position of first CCE of the dci } dci_location_t;
unsigned short rnti;
} dci_candidate_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
char data[DCI_MAX_BITS]; char data[DCI_MAX_BITS];
dci_candidate_t location; uint32_t nof_bits;
} dci_msg_t; } dci_msg_t;
typedef struct LIBLTE_API { /* Converts a received PDSCH DL scheduling DCI message
dci_msg_t *msg; * to ra structures ready to be passed to the harq setup function
int nof_dcis; */
int max_dcis; LIBLTE_API int dci_msg_to_ra_dl(dci_msg_t *msg,
} dci_t; uint16_t msg_rnti,
uint16_t c_rnti,
LIBLTE_API int dci_init(dci_t *q, int max_dci); lte_cell_t cell,
LIBLTE_API void dci_free(dci_t *q); uint32_t cfi,
ra_pdsch_t *ra_dl);
/* 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 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 int dci_location_set(dci_location_t *c,
LIBLTE_API void dci_candidate_fprint(FILE *f, dci_candidate_t *q); uint32_t L,
uint32_t nCCE);
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, int nof_prb, unsigned short crnti); LIBLTE_API int dci_msg_get_type(dci_msg_t *msg,
LIBLTE_API void dci_msg_type_fprint(FILE *f, dci_msg_type_t type); 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 // 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_pack_pusch(ra_pusch_t *data,
LIBLTE_API int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb); dci_msg_t *msg,
uint32_t nof_prb);
// For dci_msg_type_t = PDSCH_SCHED LIBLTE_API int dci_msg_unpack_pusch(dci_msg_t *msg,
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); ra_pusch_t *data,
LIBLTE_API int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti); uint32_t nof_prb);
LIBLTE_API int dci_format_sizeof(dci_format_t format, int 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,
uint32_t nof_prb,
bool crc_is_crnti);
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_ #endif // DCI_

@ -47,24 +47,23 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int nof_ports; uint32_t nof_ports;
int nof_prb; uint32_t nof_prb;
int sfn; uint32_t sfn;
phich_length_t phich_length; phich_length_t phich_length;
phich_resources_t phich_resources; phich_resources_t phich_resources;
}pbch_mib_t; }pbch_mib_t;
/* PBCH object */ /* PBCH object */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int cell_id; lte_cell_t cell;
lte_cp_t cp;
int nof_prb; uint32_t nof_symbols;
int nof_symbols;
/* buffers */ /* buffers */
cf_t *ce[MAX_PORTS_CTRL]; cf_t *ce[MAX_PORTS];
cf_t *pbch_symbols[MAX_PORTS_CTRL]; cf_t *pbch_symbols[MAX_PORTS];
cf_t *pbch_x[MAX_PORTS_CTRL]; cf_t *pbch_x[MAX_PORTS];
cf_t *pbch_d; cf_t *pbch_d;
float *pbch_llr; float *pbch_llr;
float *temp; float *temp;
@ -73,7 +72,7 @@ typedef struct LIBLTE_API {
char *data; char *data;
char *data_enc; char *data_enc;
int frame_idx; uint32_t frame_idx;
/* tx & rx objects */ /* tx & rx objects */
modem_table_t mod; modem_table_t mod;
@ -83,17 +82,24 @@ typedef struct LIBLTE_API {
crc_t crc; crc_t crc;
convcoder_t encoder; 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 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 int pbch_decode(pbch_t *q,
LIBLTE_API void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports); 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_decode_reset(pbch_t *q);
LIBLTE_API void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib); LIBLTE_API void pbch_mib_fprint(FILE *stream,
LIBLTE_API bool pbch_exists(int nframe, int nslot); pbch_mib_t *mib);
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);
#endif // PBCH_ #endif // PBCH_

@ -45,19 +45,16 @@ typedef _Complex float cf_t;
/* PCFICH object */ /* PCFICH object */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int cell_id; lte_cell_t cell;
lte_cp_t cp;
int nof_symbols; int nof_symbols;
int nof_prb;
int nof_ports;
/* handler to REGs resource mapper */ /* handler to REGs resource mapper */
regs_t *regs; regs_t *regs;
/* buffers */ /* buffers */
cf_t ce[MAX_PORTS_CTRL][PCFICH_RE]; cf_t ce[MAX_PORTS][PCFICH_RE];
cf_t pcfich_symbols[MAX_PORTS_CTRL][PCFICH_RE]; cf_t pcfich_symbols[MAX_PORTS][PCFICH_RE];
cf_t pcfich_x[MAX_PORTS_CTRL][PCFICH_RE]; cf_t pcfich_x[MAX_PORTS][PCFICH_RE];
cf_t pcfich_d[PCFICH_RE]; cf_t pcfich_d[PCFICH_RE];
/* bit message */ /* bit message */
@ -70,16 +67,22 @@ typedef struct LIBLTE_API {
} pcfich_t; } pcfich_t;
LIBLTE_API int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, LIBLTE_API int pcfich_init(pcfich_t *q,
int nof_tx_ports, lte_cp_t cp); regs_t *regs,
lte_cell_t cell);
LIBLTE_API void pcfich_free(pcfich_t *q); 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 bool pcfich_exists(int nframe, int nslot); LIBLTE_API int pcfich_decode(pcfich_t *q,
LIBLTE_API int pcfich_put(regs_t *h, cf_t *pcfich, cf_t *slot_data); cf_t *sf_symbols,
LIBLTE_API int pcfich_get(regs_t *h, cf_t *pcfich, cf_t *slot_data); 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 #endif

@ -44,41 +44,26 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
#define PDCCH_NOF_SEARCH_MODES 3
typedef enum LIBLTE_API { typedef enum LIBLTE_API {
SEARCH_NONE = 3, SEARCH_SI = 0, SEARCH_RA = 1, SEARCH_UE = 2 SEARCH_UE, SEARCH_COMMON
} pdcch_search_mode_t; } 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 */ /* PDCCH object */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int cell_id; lte_cell_t cell;
lte_cp_t cp; uint32_t e_bits;
int nof_prb; uint32_t nof_regs;
int nof_bits; uint32_t nof_cce;
int nof_symbols; uint32_t max_bits;
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;
regs_t *regs; regs_t *regs;
/* buffers */ /* buffers */
cf_t *ce[MAX_PORTS_CTRL]; cf_t *ce[MAX_PORTS];
cf_t *pdcch_symbols[MAX_PORTS_CTRL]; cf_t *pdcch_symbols[MAX_PORTS];
cf_t *pdcch_x[MAX_PORTS_CTRL]; cf_t *pdcch_x[MAX_PORTS];
cf_t *pdcch_d; cf_t *pdcch_d;
char *pdcch_e; char *pdcch_e;
float *pdcch_llr; float *pdcch_llr;
@ -91,36 +76,48 @@ typedef struct LIBLTE_API {
crc_t crc; crc_t crc;
} pdcch_t; } pdcch_t;
LIBLTE_API int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, LIBLTE_API int pdcch_init(pdcch_t *q,
int cell_id, lte_cp_t cp); regs_t *regs,
LIBLTE_API void pdcch_free(pdcch_t *q); lte_cell_t cell);
/* Encoding functions */
LIBLTE_API int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS_CTRL],
int nsubframe);
/* Decoding functions */
/* There are two ways to decode the DCI messages: LIBLTE_API void pdcch_free(pdcch_t *q);
* 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
*/
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);
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);
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); /* Encoding function */
LIBLTE_API void pdcch_set_search_ra(pdcch_t *q); LIBLTE_API int pdcch_encode(pdcch_t *q,
LIBLTE_API int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci); dci_msg_t *msg,
dci_location_t location,
uint16_t rnti,
cf_t *sf_symbols[MAX_PORTS],
uint32_t nsubframe,
uint32_t cfi);
/* 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);
/* 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);
/* 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);
/* 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 #endif

@ -43,49 +43,95 @@
#include "liblte/phy/phch/dci.h" #include "liblte/phy/phch/dci.h"
#include "liblte/phy/phch/regs.h" #include "liblte/phy/phch/regs.h"
#define TDEC_ITERATIONS 1 #define TDEC_ITERATIONS 6
typedef _Complex float cf_t; 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 */ /* PDSCH object */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int cell_id; lte_cell_t cell;
lte_cp_t cp;
int nof_prb; uint32_t max_symbols;
int nof_ports; bool rnti_is_set;
int max_symbols; uint16_t rnti;
unsigned short rnti;
/* buffers */
/* buffers */ // void buffers are shared for tx and rx
cf_t *ce[MAX_PORTS]; cf_t *ce[MAX_PORTS];
cf_t *pdsch_symbols[MAX_PORTS]; cf_t *pdsch_symbols[MAX_PORTS];
cf_t *pdsch_x[MAX_PORTS]; cf_t *pdsch_x[MAX_PORTS];
cf_t *pdsch_d; cf_t *pdsch_d;
char *pdsch_e_bits; char *cb_in;
char *cb_in_b; void *cb_out;
char *cb_out_b; void *pdsch_e;
float *pdsch_llr;
float *pdsch_rm_f; /* tx & rx objects */
modem_table_t mod[4];
/* tx & rx objects */ demod_soft_t demod;
modem_table_t mod[4]; sequence_t seq_pdsch[NSUBFRAMES_X_FRAME];
demod_soft_t demod; tcod_t encoder;
sequence_t seq_pdsch[NSUBFRAMES_X_FRAME]; tdec_t decoder;
tcod_t encoder; crc_t crc_tb;
tdec_t decoder; crc_t crc_cb;
rm_turbo_t rm_turbo;
crc_t crc_tb;
crc_t crc_cb;
}pdsch_t; }pdsch_t;
LIBLTE_API int pdsch_init(pdsch_t *q, unsigned short user_rnti, int nof_prb, LIBLTE_API int pdsch_init(pdsch_t *q,
int nof_ports, int cell_id, lte_cp_t cp); lte_cell_t cell);
LIBLTE_API void pdsch_free(pdsch_t *q); LIBLTE_API void pdsch_free(pdsch_t *q);
LIBLTE_API int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], LIBLTE_API int pdsch_set_rnti(pdsch_t *q,
int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc); uint16_t rnti);
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_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 #endif

@ -55,17 +55,15 @@ typedef _Complex float cf_t;
/* phich object */ /* phich object */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
lte_cp_t cp; lte_cell_t cell;
int nof_prb;
int nof_tx_ports;
/* handler to REGs resource mapper */ /* handler to REGs resource mapper */
regs_t *regs; regs_t *regs;
/* buffers */ /* buffers */
cf_t ce[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; cf_t ce[MAX_PORTS][PHICH_MAX_NSYMB];
cf_t phich_symbols[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; cf_t phich_symbols[MAX_PORTS][PHICH_MAX_NSYMB];
cf_t phich_x[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; cf_t phich_x[MAX_PORTS][PHICH_MAX_NSYMB];
cf_t phich_d[PHICH_MAX_NSYMB]; cf_t phich_d[PHICH_MAX_NSYMB];
cf_t phich_d0[PHICH_MAX_NSYMB]; cf_t phich_d0[PHICH_MAX_NSYMB];
cf_t phich_z[PHICH_NBITS]; cf_t phich_z[PHICH_NBITS];
@ -80,18 +78,31 @@ typedef struct LIBLTE_API {
}phich_t; }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,
LIBLTE_API void phich_free(phich_t *q); regs_t *regs,
LIBLTE_API int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], lte_cell_t cell);
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 void phich_free(phich_t *q);
LIBLTE_API void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS_CTRL]); LIBLTE_API int phich_decode(phich_t *q,
LIBLTE_API int phich_ngroups(phich_t *q); cf_t *slot_symbols,
LIBLTE_API bool phich_exists(int nframe, int nslot); cf_t *ce[MAX_PORTS],
LIBLTE_API int phich_put(regs_t *h, cf_t *phich, cf_t *slot_data); uint32_t ngroup,
LIBLTE_API int phich_get(regs_t *h, cf_t *phich, cf_t *slot_data); uint32_t nseq,
uint32_t nsubframe,
char *ack,
uint32_t *distance);
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_ #endif // PHICH_

@ -46,7 +46,7 @@ typedef _Complex float cf_t;
* Based on 3GPP TS 36.211 version 10.7.0 Release 10. * 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) // Parameters from higher layers (extracted from SIB2)
uint32_t f; // preamble format uint32_t f; // preamble format
uint32_t rsi; // rootSequenceIndex uint32_t rsi; // rootSequenceIndex

@ -37,17 +37,9 @@
* allocation. * allocation.
*/ */
typedef enum LIBLTE_API {
MOD_NULL = 0, BPSK = 1, QPSK = 2, QAM16 = 3, QAM64 = 4
} ra_mod_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
ra_mod_t mod; // By default, mod = MOD_NULL and the mcs_idx value is taken by the packing functions lte_mod_t mod;
// otherwise mod + tbs values are used to generate the mcs_idx automatically. uint32_t tbs;
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.
} ra_mcs_t; } ra_mcs_t;
typedef enum LIBLTE_API { typedef enum LIBLTE_API {
@ -60,13 +52,14 @@ typedef struct LIBLTE_API {
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
uint32_t vrb_bitmask; uint32_t vrb_bitmask;
uint8_t rbg_subset;bool shift; uint32_t rbg_subset;
bool shift;
} ra_type1_t; } ra_type1_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
uint32_t riv; // if L_crb==0, DCI message packer will take this value directly uint32_t riv; // if L_crb==0, DCI message packer will take this value directly
uint16_t L_crb; uint32_t L_crb;
uint16_t RB_start; uint32_t RB_start;
enum { enum {
nprb1a_2 = 0, nprb1a_3 = 1 nprb1a_2 = 0, nprb1a_3 = 1
} n_prb1a; } n_prb1a;
@ -79,20 +72,34 @@ typedef struct LIBLTE_API {
} ra_type2_t; } ra_type2_t;
typedef struct LIBLTE_API { 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; ra_type_t alloc_type;
union { union {
ra_type0_t type0_alloc; ra_type0_t type0_alloc;
ra_type1_t type1_alloc; ra_type1_t type1_alloc;
ra_type2_t type2_alloc; ra_type2_t type2_alloc;
}; };
ra_prb_t prb_alloc;
uint32_t mcs_idx;
ra_mcs_t mcs; ra_mcs_t mcs;
uint8_t harq_process; uint32_t harq_process;
uint8_t rv_idx;bool ndi; uint32_t rv_idx;
bool ndi;
} ra_pdsch_t; } ra_pdsch_t;
typedef struct LIBLTE_API { 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. * hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz.
*/ */
enum { enum {
@ -103,64 +110,85 @@ typedef struct LIBLTE_API {
hop_type_2 = 3 hop_type_2 = 3
} freq_hop_fl; } freq_hop_fl;
ra_prb_t prb_alloc;
ra_type2_t type2_alloc; ra_type2_t type2_alloc;
uint32_t mcs_idx;
ra_mcs_t mcs; 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). // 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; } ra_pusch_t;
typedef struct LIBLTE_API { LIBLTE_API void ra_prb_fprint(FILE *f,
uint8_t prb_idx[110]; ra_prb_slot_t *prb);
int nof_prb;
} ra_prb_slot_t;
typedef struct LIBLTE_API { LIBLTE_API int ra_prb_get_dl(ra_prb_t *prb,
ra_prb_slot_t slot[2]; ra_pdsch_t *ra,
int lstart; uint32_t nof_prb);
int re_sf[NSUBFRAMES_X_FRAME];
} ra_prb_t; LIBLTE_API int ra_prb_get_ul(ra_prb_slot_t *prb,
ra_pusch_t *ra,
uint32_t nof_prb);
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 uint32_t ra_nprb_dl(ra_pdsch_t *ra,
uint32_t nof_prb);
LIBLTE_API uint32_t ra_nprb_ul(ra_pusch_t *ra,
uint32_t nof_prb);
LIBLTE_API int ra_mcs_from_idx_dl(uint32_t mcs_idx,
uint32_t nof_prb,
ra_mcs_t *mcs);
LIBLTE_API int ra_mcs_from_idx_ul(uint32_t mcs_idx,
uint32_t nof_prb,
ra_mcs_t *mcs);
LIBLTE_API int ra_tbs_from_idx_format1c(uint32_t tbs_idx);
LIBLTE_API int ra_tbs_from_idx(uint32_t tbs_idx,
uint32_t n_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_prb_fprint(FILE *f, ra_prb_slot_t *prb); LIBLTE_API void ra_pusch_fprint(FILE *f,
ra_pusch_t *ra,
LIBLTE_API int ra_prb_get_dl(ra_prb_t *prb, ra_pdsch_t *ra, int nof_prb); uint32_t 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 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 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 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 char *ra_mod_string(ra_mod_t mod);
LIBLTE_API int ra_type0_P(int nof_prb);
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 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);
#endif /* RB_ALLOC_H_ */ #endif /* RB_ALLOC_H_ */

@ -45,57 +45,91 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int k[4]; uint32_t k[4];
int k0; uint32_t k0;
int l; uint32_t l;
bool assigned; bool assigned;
}regs_reg_t; }regs_reg_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int nof_regs; uint32_t nof_regs;
regs_reg_t **regs; regs_reg_t **regs;
}regs_ch_t; }regs_ch_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int cell_id; lte_cell_t cell;
int nof_prb; uint32_t max_ctrl_symbols;
int max_ctrl_symbols; uint32_t cfi;
int cfi; bool cfi_initiated;
int ngroups_phich; uint32_t ngroups_phich;
int nof_ports;
lte_cp_t cp;
phich_resources_t phich_res; phich_resources_t phich_res;
phich_length_t phich_len; phich_length_t phich_len;
regs_ch_t pcfich; regs_ch_t pcfich;
regs_ch_t *phich; // there are several phich regs_ch_t *phich; // there are several phich
regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for
the three possible CFI value */ the three possible CFI value */
int nof_regs;
uint32_t nof_regs;
regs_reg_t *regs; regs_reg_t *regs;
}regs_t; }regs_t;
LIBLTE_API int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports, LIBLTE_API int regs_init(regs_t *h,
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp); phich_resources_t phich_res,
LIBLTE_API void regs_free(regs_t *h); phich_length_t phich_len,
LIBLTE_API int regs_set_cfi(regs_t *h, int nof_ctrl_symbols); lte_cell_t cell);
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 void regs_free(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_set_cfi(regs_t *h,
LIBLTE_API int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t pcfich_symbols[REGS_PCFICH_NSYM]); uint32_t nof_ctrl_symbols);
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_pcfich_get(regs_t *h,
cf_t *slot_symbols,
cf_t pcfich_symbols[REGS_PCFICH_NSYM]);
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);
LIBLTE_API int regs_phich_nregs(regs_t *h); #endif // REGS_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_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);
#endif // REGS_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

@ -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 <stdbool.h>
#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_

@ -50,11 +50,14 @@
#include "liblte/phy/common/phy_common.h" #include "liblte/phy/common/phy_common.h"
#include "liblte/phy/common/fft.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/chest.h"
#include "liblte/phy/ch_estimation/refsignal.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/channel/ch_awgn.h"
#include "liblte/phy/fec/viterbi.h" #include "liblte/phy/fec/viterbi.h"
@ -89,11 +92,11 @@
#include "liblte/phy/phch/pbch.h" #include "liblte/phy/phch/pbch.h"
#include "liblte/phy/phch/pcfich.h" #include "liblte/phy/phch/pcfich.h"
#include "liblte/phy/phch/phich.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/scrambling/scrambling.h"
#include "liblte/phy/resampling/interp.h"
#include "liblte/phy/sync/pss.h" #include "liblte/phy/sync/pss.h"
#include "liblte/phy/sync/sfo.h" #include "liblte/phy/sync/sfo.h"
#include "liblte/phy/sync/sss.h" #include "liblte/phy/sync/sss.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

@ -26,15 +26,73 @@
*/ */
#ifndef INTERP_H #ifndef INTERP_H
#define INTERP_H_ #define INTERP_H
#include <stdint.h>
#include "liblte/config.h" #include "liblte/config.h"
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef enum LIBLTE_API {LINEAR} interp_type_t;
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_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end); LIBLTE_API void interp_linear_f(float *input,
LIBLTE_API void interp_linear(cf_t *input, cf_t *output, int M, int len); float *output,
LIBLTE_API void interp_linear_f(float *input, float *output, int M, int len); uint32_t M,
uint32_t len);
#endif // INTERP_H #endif // INTERP_H

@ -32,6 +32,7 @@
#include <complex.h> #include <complex.h>
#include "liblte/config.h" #include "liblte/config.h"
#include "liblte/phy/utils/cexptab.h"
typedef _Complex float cf_t; typedef _Complex float cf_t;
@ -48,10 +49,20 @@ typedef struct LIBLTE_API {
cf_t *cur_cexp; cf_t *cur_cexp;
}cfo_t; }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_free(cfo_t *h);
LIBLTE_API void cfo_set_tol(cfo_t *h, float tol); LIBLTE_API int cfo_realloc(cfo_t *h,
LIBLTE_API void cfo_correct(cfo_t *h, cf_t *x, float freq); 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_ #endif // CFO_

@ -42,8 +42,7 @@ typedef _Complex float cf_t; /* this is only a shortcut */
#define DEFAULT_CORRELATION_TH 10000 #define DEFAULT_CORRELATION_TH 10000
#define DEFAULT_NOSYNC_TIMEOUT 5 #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 #define PSS_RE 6*12
@ -67,45 +66,47 @@ typedef struct LIBLTE_API {
conv_fft_cc_t conv_fft; conv_fft_cc_t conv_fft;
#endif #endif
int frame_size; uint32_t frame_size;
int N_id_2; uint32_t N_id_2;
float current_cfo; uint32_t fft_size;
bool cfo_auto; // default true
int nof_nosync_frames; cf_t *pss_signal_freq[3]; // One sequence for each N_id_2
int nosync_timeout_frames; // default 5
float correlation_threshold; // default 10000
int frame_start_idx;
int fb_wp;
cf_t *pss_signal_freq;
cf_t *tmp_input; cf_t *tmp_input;
float *conv_abs; float *conv_abs;
cf_t *frame_buffer;
cf_t *conv_output; cf_t *conv_output;
cf_t *tmp_nco;
}pss_synch_t; }pss_synch_t;
typedef enum { PSS_TX, PSS_RX } pss_direction_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t;
/* Basic functionality */ /* 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 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_generate(cf_t *signal,
LIBLTE_API int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, float *corr_mean_value); uint32_t N_id_2);
LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv);
LIBLTE_API void pss_put_slot(cf_t *pss_signal,
cf_t *slot,
uint32_t nof_prb,
lte_cp_t cp);
LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q,
uint32_t N_id_2);
/* Automatic frame management functions (for periodic calling) */ LIBLTE_API int pss_synch_find_pss(pss_synch_t *q,
LIBLTE_API int pss_synch_periodic(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples); cf_t *input,
LIBLTE_API void pss_synch_set_timeout(pss_synch_t *q, int nof_frames); float *corr_peak_value,
LIBLTE_API void pss_synch_set_threshold(pss_synch_t *q, float threshold); float *corr_mean_value);
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 float pss_synch_cfo_compute(pss_synch_t* q,
cf_t *pss_recv);
/* High-level API */ /* High-level API */

@ -38,26 +38,20 @@
typedef _Complex float cf_t; /* this is only a shortcut */ 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_LEN 2*N_SSS
#define SSS_MAX_FFT_LEN 2048
struct sss_tables{ struct sss_tables{
int z1[N_SSS][N_SSS]; int z1[N_SSS][N_SSS];
int c[2][N_SSS]; int c[2][N_SSS];
int s[N_SSS][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. /* 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{ struct fc_tables{
cf_t z1[N_SSS+1][N_SSS+1]; cf_t z1[N_SSS+1][N_SSS+1];
@ -70,34 +64,68 @@ struct fc_tables{
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
dft_plan_t dftp_input; dft_plan_t dftp_input;
uint32_t fft_size;
float corr_peak_threshold; float corr_peak_threshold;
int symbol_sz; uint32_t symbol_sz;
int subframe_sz; uint32_t subframe_sz;
uint32_t N_id_2;
int N_id_1_table[30][30];
struct fc_tables fc_tables; uint32_t N_id_1_table[30][30];
struct fc_tables fc_tables[3]; // one for each N_id_2
}sss_synch_t; }sss_synch_t;
/* Basic functionality */ /* 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_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_put_slot(float *sss,
cf_t *symbol,
uint32_t nof_prb,
lte_cp_t cp);
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_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value, LIBLTE_API void sss_synch_set_symbol_sz(sss_synch_t *q,
int *m1, float *m1_value); uint32_t symbol_sz);
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 int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx, int *N_id_1); LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q,
LIBLTE_API void sss_synch_set_threshold(sss_synch_t *q, float threshold); uint32_t subframe_sz);
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);
/* High-level API */ /* 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 { typedef struct LIBLTE_API {
sss_synch_t obj; sss_synch_t obj;
struct sss_synch_init { struct sss_synch_init {
int N_id_2; uint32_t N_id_2;
} init; } init;
cf_t *input; cf_t *input;
int in_len; uint32_t in_len;
struct sss_synch_ctrl_in { struct sss_synch_ctrl_in {
int symbol_sz; uint32_t symbol_sz;
int subframe_sz; uint32_t subframe_sz;
int correlation_threshold; uint32_t correlation_threshold;
} ctrl_in; } ctrl_in;
struct sss_synch_ctrl_out { struct sss_synch_ctrl_out {
int subframe_idx; uint32_t subframe_idx;
int N_id_1; uint32_t N_id_1;
} ctrl_out; } ctrl_out;
}sss_synch_hl; }sss_synch_hl;

@ -30,15 +30,19 @@
#define SYNC_ #define SYNC_
#include <stdbool.h> #include <stdbool.h>
#include <math.h>
#include "liblte/config.h" #include "liblte/config.h"
#include "pss.h" #include "liblte/phy/sync/pss.h"
#include "sss.h" #include "liblte/phy/sync/sss.h"
#include "sfo.h"
#define FFT_SIZE_MIN 64
#define FFT_SIZE_MAX 2048
/** /**
* *
* This object performs time and frequency synchronization using the PSS and SSS signals. * 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. * 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. * Thus, downsampling is required if the signal is sampled at higher frequencies.
* *
@ -50,57 +54,91 @@
enum sync_pss_det { ABSOLUTE, PEAK_MEAN}; enum sync_pss_det { ABSOLUTE, PEAK_MEAN};
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
pss_synch_t pss[3]; // One for each N_id_2 pss_synch_t pss_find;
sss_synch_t sss[3]; // One for each N_id_2 pss_synch_t pss_track;
sss_synch_t sss;
enum sync_pss_det pss_mode; enum sync_pss_det pss_mode;
float threshold; float find_threshold;
float peak_to_avg; float track_threshold;
int force_N_id_2; float peak_value;
int N_id_2; uint32_t N_id_2;
int N_id_1; uint32_t N_id_1;
int slot_id; uint32_t slot_id;
uint32_t fft_size;
uint32_t find_frame_size;
float cfo; float cfo;
lte_cp_t cp;
bool detect_cp; bool detect_cp;
bool sss_en; bool sss_en;
lte_cp_t cp;
}sync_t; }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); 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_realloc(sync_t *q,
LIBLTE_API int sync_run(sync_t *q, cf_t *input); 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 */ /* 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 */ /* Set peak comparison to absolute value */
LIBLTE_API void sync_pss_det_absolute(sync_t *q); LIBLTE_API void sync_pss_det_absolute(sync_t *q);
/* Set peak comparison to relative to the mean */ /* Set peak comparison to relative to the mean */
LIBLTE_API void sync_pss_det_peak_to_avg(sync_t *q); 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) */ /* 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 */ /* 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() */ /* 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() */ /* 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() */ /* Gets the Physical CellId from the last call to synch_run() */
LIBLTE_API int sync_get_cell_id(sync_t *q); LIBLTE_API int sync_get_cell_id(sync_t *q);
/* Gets the CFO estimation from the last call to synch_run() */ /* Gets the CFO estimation from the last call to synch_run() */
LIBLTE_API float sync_get_cfo(sync_t *q); LIBLTE_API float sync_get_cfo(sync_t *q);
/* Gets the CP length estimation from the last call to synch_run() */ /* Gets the CP length estimation from the last call to synch_run() */
LIBLTE_API lte_cp_t sync_get_cp(sync_t *q); 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_ #endif // SYNC_

@ -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_pack(uint32_t value, char **bits, int nof_bits);
LIBLTE_API void bit_fprint(FILE *stream, 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 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_ #endif // BIT_

@ -30,19 +30,28 @@
#define CEXPTAB_ #define CEXPTAB_
#include <complex.h> #include <complex.h>
#include <stdint.h>
#include "liblte/config.h" #include "liblte/config.h"
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int size; uint32_t size;
cf_t *tab; cf_t *tab;
}cexptab_t; }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_free(cexptab_t *nco);
LIBLTE_API void cexptab_gen(cexptab_t *nco, cf_t *x, float freq, int len); LIBLTE_API void cexptab_gen(cexptab_t *nco,
LIBLTE_API void cexptab_gen_direct(cf_t *x, float freq, int len); cf_t *x,
float freq,
uint32_t len);
LIBLTE_API void cexptab_gen_direct(cf_t *x,
float freq,
uint32_t len);
#endif // CEXPTAB_ #endif // CEXPTAB_

@ -32,23 +32,36 @@
#include "liblte/config.h" #include "liblte/config.h"
#include "liblte/phy/utils/dft.h" #include "liblte/phy/utils/dft.h"
typedef _Complex float cf_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
_Complex float *input_fft; cf_t *input_fft;
_Complex float *filter_fft; cf_t *filter_fft;
_Complex float *output_fft; cf_t *output_fft;
_Complex float *output_fft2; cf_t *output_fft2;
int input_len; uint32_t input_len;
int filter_len; uint32_t filter_len;
int output_len; uint32_t output_len;
dft_plan_t input_plan; dft_plan_t input_plan;
dft_plan_t filter_plan; dft_plan_t filter_plan;
dft_plan_t output_plan; dft_plan_t output_plan;
}conv_fft_cc_t; }conv_fft_cc_t;
LIBLTE_API int conv_fft_cc_init(conv_fft_cc_t *state, int input_len, int filter_len); LIBLTE_API int conv_fft_cc_init(conv_fft_cc_t *q,
LIBLTE_API void conv_fft_cc_free(conv_fft_cc_t *state); uint32_t input_len,
LIBLTE_API int conv_fft_cc_run(conv_fft_cc_t *state, _Complex float *input, _Complex float *filter, _Complex float *output); uint32_t 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 int conv_cc(_Complex float *input, _Complex float *filter, _Complex float *output, int input_len, int filter_len); 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_ #endif // CONVOLUTION_H_

@ -44,6 +44,7 @@ LIBLTE_API extern int verbose;
#define VERBOSE_ISINFO() (verbose>=VERBOSE_INFO) #define VERBOSE_ISINFO() (verbose>=VERBOSE_INFO)
#define VERBOSE_ISDEBUG() (verbose>=VERBOSE_DEBUG) #define VERBOSE_ISDEBUG() (verbose>=VERBOSE_DEBUG)
#define VERBOSE_ISNONE() (verbose==VERBOSE_NONE)
#define PRINT_DEBUG verbose=VERBOSE_DEBUG #define PRINT_DEBUG verbose=VERBOSE_DEBUG
#define PRINT_INFO verbose=VERBOSE_INFO #define PRINT_INFO verbose=VERBOSE_INFO

@ -30,51 +30,79 @@
#define VECTOR_ #define VECTOR_
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include "liblte/config.h" #include "liblte/config.h"
typedef _Complex float cf_t; typedef _Complex float cf_t;
/** Return the sum of all the elements */ /** Return the sum of all the elements */
LIBLTE_API int vec_acc_ii(int *x, int len); LIBLTE_API int vec_acc_ii(int *x, uint32_t len);
LIBLTE_API float vec_acc_ff(float *x, int len); LIBLTE_API float vec_acc_ff(float *x, uint32_t len);
LIBLTE_API cf_t vec_acc_cc(cf_t *x, int 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 */ /* print vectors */
LIBLTE_API void vec_fprint_c(FILE *stream, cf_t *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, int len); LIBLTE_API void vec_fprint_f(FILE *stream, float *x, uint32_t len);
LIBLTE_API void vec_fprint_b(FILE *stream, char *x, int len); LIBLTE_API void vec_fprint_b(FILE *stream, char *x, uint32_t len);
LIBLTE_API void vec_fprint_i(FILE *stream, int *x, int 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 */ /* sum two vectors */
LIBLTE_API void vec_sum_ch(char *z, char *x, char *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 *z, cf_t *x, cf_t *y, int 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 */ /* 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_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, int 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) */ /* 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(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
LIBLTE_API void vec_prod_ccc_unalign(cf_t *x, cf_t *y, cf_t *z, int 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) */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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_ #endif // VECTOR_

@ -29,13 +29,13 @@ FIND_PACKAGE(FFTW3F REQUIRED) # TODO: distribute kissfft instead
INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS})
IF(${DISABLE_VOLK}) IF(${DISABLE_VOLK})
IF(${DISABLE_VOLK} EQUAL 0) IF(${DISABLE_VOLK} EQUAL 0)
FIND_PACKAGE(Volk) FIND_PACKAGE(Volk)
ELSE(${DISABLE_VOLK} EQUAL 0) ELSE(${DISABLE_VOLK} EQUAL 0)
MESSAGE(STATUS "VOLK library disabled (DISABLE_VOLK=1)") MESSAGE(STATUS "VOLK library disabled (DISABLE_VOLK=1)")
ENDIF(${DISABLE_VOLK} EQUAL 0) ENDIF(${DISABLE_VOLK} EQUAL 0)
ELSE(${DISABLE_VOLK}) ELSE(${DISABLE_VOLK})
FIND_PACKAGE(Volk) FIND_PACKAGE(Volk)
ENDIF(${DISABLE_VOLK}) ENDIF(${DISABLE_VOLK})
######################################################################## ########################################################################
@ -44,10 +44,10 @@ ENDIF(${DISABLE_VOLK})
FILE(GLOB modules *) FILE(GLOB modules *)
SET(SOURCES_ALL "") SET(SOURCES_ALL "")
FOREACH (_module ${modules}) FOREACH (_module ${modules})
IF(IS_DIRECTORY ${_module}) IF(IS_DIRECTORY ${_module})
FILE(GLOB_RECURSE tmp "${_module}/src/*.c") FILE(GLOB_RECURSE tmp "${_module}/src/*.c")
LIST(APPEND SOURCES_ALL ${tmp}) LIST(APPEND SOURCES_ALL ${tmp})
ENDIF(IS_DIRECTORY ${_module}) ENDIF(IS_DIRECTORY ${_module})
ENDFOREACH() ENDFOREACH()
ADD_LIBRARY(lte_phy SHARED ${SOURCES_ALL}) ADD_LIBRARY(lte_phy SHARED ${SOURCES_ALL})
@ -56,12 +56,12 @@ INSTALL(TARGETS lte_phy DESTINATION ${LIBRARY_DIR})
LIBLTE_SET_PIC(lte_phy) LIBLTE_SET_PIC(lte_phy)
IF(VOLK_FOUND) IF(VOLK_FOUND)
INCLUDE_DIRECTORIES(${VOLK_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${VOLK_INCLUDE_DIRS})
SET_TARGET_PROPERTIES(lte_phy PROPERTIES COMPILE_DEFINITIONS "${VOLK_DEFINITIONS}") SET_TARGET_PROPERTIES(lte_phy PROPERTIES COMPILE_DEFINITIONS "${VOLK_DEFINITIONS}")
TARGET_LINK_LIBRARIES(lte_phy ${VOLK_LIBRARIES}) TARGET_LINK_LIBRARIES(lte_phy ${VOLK_LIBRARIES})
MESSAGE(STATUS " Compiling with VOLK SIMD library.") MESSAGE(STATUS " Compiling with VOLK SIMD library.")
ELSE(VOLK_FOUND) 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) ENDIF(VOLK_FOUND)
@ -70,10 +70,10 @@ ENDIF(VOLK_FOUND)
######################################################################## ########################################################################
FILE(GLOB_RECURSE cmakefiles CMakeLists.txt) FILE(GLOB_RECURSE cmakefiles CMakeLists.txt)
FOREACH (_file ${cmakefiles}) FOREACH (_file ${cmakefiles})
GET_FILENAME_COMPONENT(dir ${_file} PATH) GET_FILENAME_COMPONENT(dir ${_file} PATH)
IF (NOT ${dir} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) IF (NOT ${dir} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
ADD_SUBDIRECTORY(${dir}) ADD_SUBDIRECTORY(${dir})
ENDIF () ENDIF ()
ENDFOREACH() ENDFOREACH()

@ -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 <string.h>
#include <strings.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
#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));
}
}

@ -29,24 +29,36 @@
#include <strings.h> #include <strings.h>
#include <string.h> #include <string.h>
#include <complex.h> #include <complex.h>
#include <assert.h>
#include <math.h> #include <math.h>
#include "liblte/phy/ch_estimation/chest.h" #include "liblte/phy/ch_estimation/chest.h"
#include "liblte/phy/resampling/interp.h"
#include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/vector.h"
#include "liblte/phy/utils/debug.h" #include "liblte/phy/utils/debug.h"
#define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz) #define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz)
#define SF_SZ(q) (2 * SLOT_SZ(q)) #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_ref_fprint(q, stream, nslot, port_id);
chest_recvsig_fprint(q, stream, nslot, port_id); chest_recvsig_fprint(q, stream, nslot, port_id);
chest_ce_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; int i;
fprintf(stream, "refs%d=[",port_id); fprintf(stream, "refs%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) { for (i=0;i<q->refsignal[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"); 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; int i;
fprintf(stream, "recvsig%d=[",port_id); fprintf(stream, "recvsig%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) { for (i=0;i<q->refsignal[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"); 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; int i;
fprintf(stream, "mag%d=[",port_id); fprintf(stream, "mag%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) { for (i=0;i<q->refsignal[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"); 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; int fidx, tidx;
cf_t known_ref, channel_ref; cf_t known_ref, channel_ref;
int ret = LIBLTE_ERROR_INVALID_INPUTS;
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 if (q != NULL &&
known_ref = q->refsignal[port_id][nslot].refs[nref].simbol; input != NULL &&
channel_ref = input[SAMPLE_IDX(q->nof_prb, tidx, fidx)]; nslot < NSLOTS_X_FRAME &&
q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref; port_id < q->nof_ports)
{
DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, SAMPLE_IDX(q->nof_prb, tidx, fidx), if (nref < q->refsignal[port_id][nslot].nof_refs) {
10*log10f(cabsf(channel_ref/known_ref)),
cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,cargf(channel_ref/known_ref)/M_PI); 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
/* FIXME: compare with threshold */
if (channel_ref != 0) { known_ref = q->refsignal[port_id][nslot].refs[nref].simbol;
q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref; channel_ref = input[tidx * q->nof_re + fidx];
} else { q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref;
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. /* Computes channel estimates for each reference in a slot and port.
* Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce * 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 chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32_t port_id) {
int i, j; uint32_t i, j;
cf_t x[2], y[MAX_NSYMB]; cf_t x[2], y[MAX_NSYMB];
assert(nslot >= 0 && nslot < NSLOTS_X_FRAME); int ret = LIBLTE_ERROR_INVALID_INPUTS;
assert(port_id >= 0 && port_id < q->nof_ports);
assert(q->refsignal[port_id][nslot].nsymbols <= 2); if (q != NULL &&
input != NULL &&
refsignal_t *r = &q->refsignal[port_id][nslot]; nslot < NSLOTS_X_FRAME &&
port_id < q->nof_ports)
INFO("Estimating channel slot=%d port=%d using %d reference signals\n", {
nslot, port_id, r->nof_refs); if (q->refsignal[port_id][nslot].nsymbols <= 2) {
refsignal_t *r = &q->refsignal[port_id][nslot];
for (i=0;i<r->nof_refs;i++) {
chest_ce_ref(q, input, nslot, port_id, i); INFO("Estimating channel slot=%d port=%d using %d reference signals\n",
} nslot, port_id, r->nof_refs);
/* interpolate the symbols with references for (i=0;i<r->nof_refs;i++) {
* in the freq domain */ chest_ce_ref(q, input, nslot, port_id, i);
for (i=0;i<r->nsymbols;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);
} /* interpolate the symbols with references
/* now interpolate in the time domain */ * in the freq domain */
for (i=0;i<q->nof_prb * RE_X_RB; i++) { for (i=0;i<r->nsymbols;i++) {
if (r->nsymbols > 1) { #ifdef VOLK_INTERP
for (j=0;j<r->nsymbols;j++) { interp_run_offset(&q->interp_freq[port_id],
x[j] = ce[r->symbols_ref[j] * q->nof_prb * RE_X_RB + i]; &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
} }
interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0], /* now interpolate in the time domain */
2, r->symbols_ref[0], 3); for (i=0;i<q->nof_re; i++) {
} else { if (r->nsymbols > 1) {
for (j=0;j<MAX_NSYMB;j++) { for (j=0;j<r->nsymbols;j++) {
y[j] = ce[r->symbols_ref[0] * q->nof_prb * RE_X_RB + i]; 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;j<MAX_NSYMB;j++) {
y[j] = ce[r->symbols_ref[0] * q->nof_re + i];
}
}
for (j=0;j<q->nof_symbols;j++) {
ce[j * q->nof_re + i] = y[j];
}
} }
ret = LIBLTE_SUCCESS;
} }
for (j=0;j<q->nof_symbols;j++) { }
ce[j * q->nof_prb * RE_X_RB + i] = y[j]; return ret;
}
/* Computes channel estimates for each reference in a subframe and port id.
*/
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 LIBLTE_SUCCESS;
} }
/* Computes channel estimates for each reference in a slot. /* Computes channel estimates for each reference in a slot for all ports.
* Saves the result for the p-th port to the pointer ce[p]
*/ */
void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot) { int chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, uint32_t nslot) {
int p; int p, ret;
for (p=0;p<q->nof_ports;p++) { for (p=0;p<q->nof_ports;p++) {
chest_ce_slot_port(q, input, ce[p], nslot, p); ret = chest_ce_slot_port(q, input, ce[p], nslot, p);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
} }
return LIBLTE_SUCCESS;
} }
int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports) { /* Computes channel estimates for each reference in a subframe for all ports.
*/
if (nof_ports > MAX_PORTS) { int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint32_t sf_idx) {
fprintf(stderr, "Error: Maximum ports %d\n", MAX_PORTS); int p, n, slotsz, ret;
return -1; slotsz = q->nof_symbols*q->nof_re;
for (p=0;p<q->nof_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;
}
}
} }
bzero(q, sizeof(chest_t)); return LIBLTE_SUCCESS;
}
q->nof_ports = nof_ports;
q->nof_symbols = CP_NSYMB(cp);
q->cp = cp;
q->nof_prb = nof_prb;
switch(interp) { int chest_init(chest_t *q, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_ports) {
case LINEAR: int ret = LIBLTE_ERROR_INVALID_INPUTS;
q->interp = interp_linear_offset;
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;
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) { int chest_init_LTEDL(chest_t *q, lte_cell_t cell) {
if (port < 0 || port > q->nof_ports) { int ret;
return -1; ret = chest_init(q, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports);
} if (ret != LIBLTE_SUCCESS) {
if (nslot < 0 || nslot > NSLOTS_X_FRAME) { return ret;
return -1; } else {
return chest_ref_LTEDL(q, cell);
} }
}
if (refsignal_init_LTEDL(&q->refsignal[port][nslot], port, nslot, cell_id, q->cp, q->nof_prb)) { int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_cell_t cell) {
fprintf(stderr, "Error initiating CRS port=%d, slot=%d\n", port, nslot); int ret = LIBLTE_ERROR_INVALID_INPUTS;
return -1;
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;
return 0;
} }
int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id) { int chest_ref_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) {
int p; int p, ret;
for (p=0;p<q->nof_ports;p++) { for (p=0;p<q->nof_ports;p++) {
if (chest_ref_LTEDL_slot_port(q, p, nslot, cell_id)) { ret = chest_ref_LTEDL_slot_port(q, nslot, p, cell);
return -1; if (ret != LIBLTE_SUCCESS) {
return ret;
} }
} }
return 0; return LIBLTE_SUCCESS;
} }
int chest_ref_LTEDL(chest_t *q, int cell_id) { int chest_ref_LTEDL(chest_t *q, lte_cell_t cell) {
int n; int n, ret;
for (n=0;n<NSLOTS_X_FRAME;n++) { for (n=0;n<NSLOTS_X_FRAME;n++) {
if (chest_ref_LTEDL_slot(q, n, cell_id)) { ret = chest_ref_LTEDL_slot(q, n, cell);
return -1; if (ret != LIBLTE_SUCCESS) {
return ret;
} }
} }
return 0; return LIBLTE_SUCCESS;
} }
void chest_free(chest_t *q) { void chest_free(chest_t *q) {
@ -232,12 +324,17 @@ void chest_free(chest_t *q) {
/* Fills l[2] with the symbols in the slot nslot that contain references. /* Fills l[2] with the symbols in the slot nslot that contain references.
* returns the number of symbols with references (in the slot) * returns the number of symbols with references (in the slot)
*/ */
int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]) { int chest_ref_symbols(chest_t *q, uint32_t port_id, uint32_t nslot, uint32_t l[2]) {
if (nslot < 0 || nslot > NSLOTS_X_FRAME) {
return -1; 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) { int chest_initialize(chest_hl* h) {
lte_cell_t cell;
if (!h->init.nof_symbols) { if (!h->init.nof_symbols) {
h->init.nof_symbols = CPNORM_NSYMB; // Normal CP h->init.nof_symbols = CPNORM_NSYMB; // Normal CP
} }
@ -252,37 +351,23 @@ int chest_initialize(chest_hl* h) {
h->init.nof_prb = 6; h->init.nof_prb = 6;
} }
if (chest_init(&h->obj, LINEAR, (h->init.nof_symbols==CPNORM_NSYMB)?CPNORM:CPEXT, cell.id = h->init.cell_id;
h->init.nof_prb, h->init.nof_ports)) { 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"); fprintf(stderr, "Error initializing equalizer\n");
return -1; 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; 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 chest_work(chest_hl* hl) {
int i;
chest_t *q = &hl->obj; chest_t *q = &hl->obj;
chest_ce_sf(q, hl->input, hl->output, hl->ctrl_in.sf_idx);
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;i<hl->init.nof_ports;i++) {
chest_ce_slot_port(q, hl->input, hl->output[i], 1, 0);
hl->out_len[i] = hl->in_len;
}
return 0; return 0;
} }

@ -40,7 +40,7 @@
#define idx(x, y) (l*nof_refs_x_symbol+i) #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; int v=-1;
switch(port_id) { switch(port_id) {
case 0: case 0:
@ -67,108 +67,121 @@ int refsignal_v(int port_id, int ns, int symbol_id) {
return v; 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); return 6*m+((v+(cell_id%6))%6);
} }
void refsignal_put(refsignal_t *q, cf_t *slot_symbols) { int refsignal_put(refsignal_t *q, cf_t *slot_symbols) {
int i; uint32_t i;
int fidx, tidx; uint32_t fidx, tidx;
for (i=0;i<q->nof_refs;i++) { if (q != NULL &&
fidx = q->refs[i].freq_idx; // reference frequency index slot_symbols != NULL)
tidx = q->refs[i].time_idx; // reference time index {
slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol; for (i=0;i<q->nof_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 /** 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 refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot,
int cell_id, lte_cp_t cp, int nof_prb) { lte_cell_t cell) {
unsigned int c_init; uint32_t c_init;
int ns, l, lp[2]; uint32_t ns, l, lp[2];
int N_cp; uint32_t N_cp;
int i; uint32_t i;
int ret = -1; int ret = LIBLTE_ERROR_INVALID_INPUTS;
sequence_t seq; sequence_t seq;
int v; int v;
int mp; uint32_t mp;
int nof_refs_x_symbol, nof_ref_symbols; uint32_t nof_refs_x_symbol, nof_ref_symbols;
bzero(q, sizeof(refsignal_t)); if (q != NULL &&
bzero(&seq, sizeof(sequence_t)); port_id < MAX_PORTS &&
nslot < NSLOTS_X_FRAME &&
if (CP_ISNORM(cp)) { lte_cell_isvalid(&cell))
N_cp = 1; {
} else {
N_cp = 0; bzero(q, sizeof(refsignal_t));
} bzero(&seq, sizeof(sequence_t));
if (port_id < 0 || port_id > (MAX_PORTS - 1)) { if (CP_ISNORM(cell.cp)) {
fprintf(stderr, "Invalid port id %d\n", port_id); N_cp = 1;
return -1; } else {
} N_cp = 0;
}
if (port_id < 2) { if (port_id < 2) {
nof_ref_symbols = 2; nof_ref_symbols = 2;
lp[0] = 0; lp[0] = 0;
lp[1] = CP_NSYMB(cp) - 3; lp[1] = CP_NSYMB(cell.cp) - 3;
} else { } else {
nof_ref_symbols = 1; nof_ref_symbols = 1;
lp[0] = 1; lp[0] = 1;
} }
nof_refs_x_symbol = 2 * nof_prb; nof_refs_x_symbol = 2 * 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->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->refs = vec_malloc(q->nof_refs * sizeof(ref_t)); q->symbols_ref = malloc(sizeof(uint32_t) * nof_ref_symbols);
if (!q->refs) { if (!q->symbols_ref) {
goto free_and_exit; perror("malloc");
} 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; memcpy(q->symbols_ref, lp, sizeof(uint32_t) * nof_ref_symbols);
for (l = 0; l < nof_ref_symbols; l++) {
c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell_id + 1) q->refs = vec_malloc(q->nof_refs * sizeof(ref_t));
+ 2 * cell_id + N_cp; if (!q->refs) {
if (sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init)) {
goto free_and_exit; 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++) {
v = refsignal_v(port_id, ns, lp[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;
}
for (i = 0; i < nof_refs_x_symbol; i++) { v = refsignal_v(port_id, ns, lp[l]);
mp = i + MAX_PRB - nof_prb;
/* generate signal */ for (i = 0; i < nof_refs_x_symbol; i++) {
__real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2); mp = i + MAX_PRB - cell.nof_prb;
__imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2);
/* mapping to resource elements */ /* generate signal */
q->refs[idx(l,i)].freq_idx = refsignal_k(i, v, cell_id); __real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2);
q->refs[idx(l,i)].time_idx = lp[l]; __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;
} }
ret = 0;
free_and_exit: free_and_exit:
sequence_free(&seq); if (ret != LIBLTE_ERROR_INVALID_INPUTS) {
if (ret == -1) { sequence_free(&seq);
}
if (ret == LIBLTE_ERROR) {
refsignal_free(q); refsignal_free(q);
} }
return ret; return ret;

@ -33,19 +33,22 @@
#include "liblte/phy/phy.h" #include "liblte/phy/phy.h"
int cell_id = -1; lte_cell_t cell = {
int nof_prb = 6; 6, // nof_prb
lte_cp_t cp = CPNORM; MAX_PORTS, // nof_ports
1000, // cell_id
CPNORM // cyclic prefix
};
char *output_matlab = NULL; char *output_matlab = NULL;
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [recov]\n", 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-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-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None");
printf("\t-v increase verbosity\n"); printf("\t-v increase verbosity\n");
@ -56,13 +59,13 @@ void parse_args(int argc, char **argv) {
while ((opt = getopt(argc, argv, "recov")) != -1) { while ((opt = getopt(argc, argv, "recov")) != -1) {
switch(opt) { switch(opt) {
case 'r': case 'r':
nof_prb = atoi(argv[optind]); cell.nof_prb = atoi(argv[optind]);
break; break;
case 'e': case 'e':
cp = CPEXT; cell.cp = CPEXT;
break; break;
case 'c': case 'c':
cell_id = atoi(argv[optind]); cell.id = atoi(argv[optind]);
break; break;
case 'o': case 'o':
output_matlab = argv[optind]; output_matlab = argv[optind];
@ -120,7 +123,7 @@ int main(int argc, char **argv) {
int max_cid; int max_cid;
FILE *fmatlab = NULL; FILE *fmatlab = NULL;
float mse_mag, mse_phase; float mse_mag, mse_phase;
parse_args(argc,argv); parse_args(argc,argv);
if (output_matlab) { 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)); input = malloc(num_re * sizeof(cf_t));
if (!input) { if (!input) {
@ -149,28 +152,25 @@ int main(int argc, char **argv) {
goto do_exit; goto do_exit;
} }
if (cell_id == -1) { if (cell.id == 1000) {
cid = 0; cid = 0;
max_cid = 504; max_cid = 504;
} else { } else {
cid = cell_id; cid = cell.id;
max_cid = cell_id; max_cid = cell.id;
} }
while(cid <= max_cid) { 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"); fprintf(stderr, "Error initializing equalizer\n");
goto do_exit; goto do_exit;
} }
if (chest_ref_LTEDL(&eq, cid)) {
fprintf(stderr, "Error initializing reference signal\n");
goto do_exit;
}
for (n_slot=0;n_slot<NSLOTS_X_FRAME;n_slot++) { for (n_slot=0;n_slot<NSLOTS_X_FRAME;n_slot++) {
for (n_port=0;n_port<MAX_PORTS;n_port++) { for (n_port=0;n_port<cell.nof_ports;n_port++) {
if (refsignal_init_LTEDL(&refs, n_port, n_slot, cid, cp, nof_prb)) { if (refsignal_init_LTEDL(&refs, n_port, n_slot, cell)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i); fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1; return -1;
} }
@ -185,13 +185,11 @@ int main(int argc, char **argv) {
refsignal_put(&refs, input); refsignal_put(&refs, input);
refsignal_free(&refs); for (i=0;i<CP_NSYMB(cell.cp);i++) {
for (j=0;j<cell.nof_prb * RE_X_RB;j++) {
for (i=0;i<CP_NSYMB(cp);i++) { float x = -1+(float) i/CP_NSYMB(cell.cp) + cosf(2 * M_PI * (float) j/cell.nof_prb/RE_X_RB);
for (j=0;j<nof_prb * RE_X_RB;j++) { h[i*cell.nof_prb * RE_X_RB+j] = (3+x) * cexpf(I * x);
float x = -1+(float) i/CP_NSYMB(cp) + cosf(2 * M_PI * (float) j/nof_prb/RE_X_RB); input[i*cell.nof_prb * RE_X_RB+j] *= h[i*cell.nof_prb * RE_X_RB+j];
h[i*nof_prb * RE_X_RB+j] = (3+x) * cexpf(I * x);
input[i*nof_prb * RE_X_RB+j] *= h[i*nof_prb * RE_X_RB+j];
} }
} }

@ -35,10 +35,10 @@
#include "liblte/phy/utils/debug.h" #include "liblte/phy/utils/debug.h"
#include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/vector.h"
int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) { int lte_fft_init_(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb, dft_dir_t dir) {
int symbol_sz = lte_symbol_sz(nof_prb); int symbol_sz = lte_symbol_sz(nof_prb);
if (symbol_sz == -1) { if (symbol_sz < 0) {
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
return -1; return -1;
} }
@ -46,7 +46,7 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) {
fprintf(stderr, "Error: Creating DFT plan\n"); fprintf(stderr, "Error: Creating DFT plan\n");
return -1; return -1;
} }
q->tmp = malloc(symbol_sz * sizeof(cf_t)); q->tmp = malloc((uint32_t) symbol_sz * sizeof(cf_t));
if (!q->tmp) { if (!q->tmp) {
perror("malloc"); perror("malloc");
return -1; 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_norm(&q->fft_plan, true);
dft_plan_set_dc(&q->fft_plan, true); dft_plan_set_dc(&q->fft_plan, true);
q->symbol_sz = symbol_sz; q->symbol_sz = (uint32_t) symbol_sz;
q->nof_symbols = CP_NSYMB(cp_type); q->nof_symbols = CP_NSYMB(cp);
q->cp_type = cp_type; q->cp = cp;
q->nof_re = nof_prb * RE_X_RB; q->nof_re = nof_prb * RE_X_RB;
q->nof_guards = ((symbol_sz - q->nof_re) / 2); 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, dir==FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols,
q->cp_type==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards); q->cp==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards);
return 0;
return LIBLTE_SUCCESS;
} }
void lte_fft_free_(lte_fft_t *q) { 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)); bzero(q, sizeof(lte_fft_t));
} }
int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) { int lte_fft_init(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb) {
return lte_fft_init_(q, cp_type, nof_prb, FORWARD); return lte_fft_init_(q, cp, nof_prb, FORWARD);
} }
void lte_fft_free(lte_fft_t *q) { void lte_fft_free(lte_fft_t *q) {
lte_fft_free_(q); lte_fft_free_(q);
} }
int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) { int lte_ifft_init(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb) {
int i; uint32_t i;
if (lte_fft_init_(q, cp_type, nof_prb, BACKWARD)) { int ret;
return -1;
ret = lte_fft_init_(q, cp, nof_prb, BACKWARD);
if (ret == LIBLTE_SUCCESS) {
/* set now zeros at CP */
for (i=0;i<q->nof_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 */ return ret;
for (i=0;i<q->nof_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;
} }
void lte_ifft_free(lte_fft_t *q) { 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. /* Transforms input samples into output OFDM symbols.
* Performs FFT on a each symbol and removes CP. * Performs FFT on a each symbol and removes CP.
*/ */
void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output) { void lte_fft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) {
int i; uint32_t i;
for (i=0;i<q->nof_symbols;i++) { for (i=0;i<q->nof_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); dft_run_c(&q->fft_plan, input, q->tmp);
memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t)); memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t));
input += q->symbol_sz; 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. /* Transforms input OFDM symbols into output samples.
* Performs FFT on a each symbol and adds CP. * Performs FFT on a each symbol and adds CP.
*/ */
void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output) { void lte_ifft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) {
int i, cp_len; uint32_t i, cp_len;
for (i=0;i<q->nof_symbols;i++) { for (i=0;i<q->nof_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)); memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t));
dft_run_c(&q->fft_plan, q->tmp, &output[cp_len]); dft_run_c(&q->fft_plan, q->tmp, &output[cp_len]);
input += q->nof_re; 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]);
}
}

@ -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, 4800, 4864, 4928, 4992, 5056, 5120, 5184, 5248, 5312, 5376, 5440, 5504,
5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144 }; 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 * Returns Turbo coder interleaver size for Table 5.1.3-3 (36.212) index
*/ */
int lte_cb_size(int index) { int lte_cb_size(uint32_t index) {
if (index >= 0 && index < NOF_TC_CB_SIZES) { if (index < NOF_TC_CB_SIZES) {
return tc_cb_sizes[index]; return tc_cb_sizes[index];
} else { } 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 * 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; int j = 0;
while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) { while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) {
j++; j++;
} }
if (j == NOF_TC_CB_SIZES) { if (j == NOF_TC_CB_SIZES) {
return -1; return LIBLTE_ERROR;
} else { } else {
return j; 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) { if (nof_prb<=0) {
return -1; return LIBLTE_ERROR;
} }
if (nof_prb<=6) { if (nof_prb<=6) {
return 128; return 128;
@ -94,10 +173,22 @@ const int lte_symbol_sz(int nof_prb) {
} else if (nof_prb<=100) { } else if (nof_prb<=100) {
return 2048; return 2048;
} }
return -1; return LIBLTE_ERROR;
}
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;
}
} }
int lte_voffset(int symbol_id, int cell_id, int nof_ports) { uint32_t lte_voffset(uint32_t symbol_id, uint32_t cell_id, uint32_t nof_ports) {
if (nof_ports == 1 && symbol_id==0) { if (nof_ports == 1 && symbol_id==0) {
return (cell_id+3) % 6; return (cell_id+3) % 6;
} else { } 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 */ /* 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 (symbol == 0) {
if (((ns % 2) == 0) || (ns == 1)) { if (((ns % 2) == 0) || (ns == 1)) {
return RE_X_RB - 4; 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 { struct lte_band {
int band; uint32_t band;
float fd_low_mhz; float fd_low_mhz;
int earfcn_offset; uint32_t earfcn_offset;
int earfcn_max; uint32_t earfcn_max;
enum band_geographical_area area; 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")) { } else if (!strcmp(mimo_type_str, "multiplex")) {
*type = SPATIAL_MULTIPLEX; *type = SPATIAL_MULTIPLEX;
} else { } else {
return -1; return LIBLTE_ERROR;
} }
return 0; return LIBLTE_SUCCESS;
} }
char *lte_mimotype2str(lte_mimo_type_t type) { char *lte_mimotype2str(lte_mimo_type_t type) {
@ -203,12 +294,16 @@ char *lte_mimotype2str(lte_mimo_type_t type) {
return NULL; return NULL;
} }
float get_fd(struct lte_band *band, int earfcn) { float get_fd(struct lte_band *band, uint32_t earfcn) {
return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset); 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) { float lte_band_fd(uint32_t earfcn) {
int i; uint32_t i;
i=0; i=0;
while(i < NOF_LTE_BANDS && lte_bands[i].earfcn_offset<earfcn) { while(i < NOF_LTE_BANDS && lte_bands[i].earfcn_offset<earfcn) {
i++; i++;
@ -220,27 +315,27 @@ float lte_band_fd(int earfcn) {
return get_fd(&lte_bands[i], earfcn); return get_fd(&lte_bands[i], earfcn);
} }
int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_elems) { int lte_band_get_fd_band_all(uint32_t band, lte_earfcn_t *earfcn, uint32_t max_elems) {
return lte_band_get_fd_band(band, earfcn, -1, -1, max_elems); return lte_band_get_fd_band(band, earfcn, -1, -1, max_elems);
} }
int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int start_earfcn, int end_earfcn, int max_elems) { int lte_band_get_fd_band(uint32_t band, lte_earfcn_t *earfcn, int start_earfcn, int end_earfcn, uint32_t max_elems) {
int i, j; uint32_t i, j;
int nof_earfcn; uint32_t nof_earfcn;
i=0; i=0;
while(i < NOF_LTE_BANDS && lte_bands[i].band != band) { while(i < NOF_LTE_BANDS && lte_bands[i].band != band) {
i++; i++;
} }
if (i == NOF_LTE_BANDS) { if (i == NOF_LTE_BANDS) {
fprintf(stderr, "Error: Invalid band %d\n", band); fprintf(stderr, "Error: Invalid band %d\n", band);
return -1; return LIBLTE_ERROR;
} }
if (end_earfcn == -1) { if (end_earfcn == -1) {
end_earfcn = lte_bands[i].earfcn_max; end_earfcn = lte_bands[i].earfcn_max;
} else { } else {
if (end_earfcn > lte_bands[i].earfcn_max) { if (end_earfcn > lte_bands[i].earfcn_max) {
fprintf(stderr, "Error: Invalid end earfcn %d. Max is %d\n", end_earfcn, 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) { 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 { } else {
if (start_earfcn < lte_bands[i].earfcn_offset) { 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); 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; 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].id = j + start_earfcn;
earfcn[j].fd = get_fd(&lte_bands[i], earfcn[j].id); earfcn[j].fd = get_fd(&lte_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 lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, uint32_t max_elems) {
int i; uint32_t i;
int n; int n;
int nof_fd = 0; int nof_fd = 0;
for (i=0;i<NOF_LTE_BANDS && max_elems > 0;i++) { for (i=0;i<NOF_LTE_BANDS && max_elems > 0;i++) {
@ -274,7 +369,7 @@ int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *ear
nof_fd += n; nof_fd += n;
max_elems -= n; max_elems -= n;
} else { } else {
return -1; return LIBLTE_ERROR;
} }
} }
} }

@ -41,17 +41,16 @@
* It follows the 3GPP Release 8 (LTE) 36.211 * It follows the 3GPP Release 8 (LTE) 36.211
* Section 7.2 * 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; int n;
unsigned int *x1; uint32_t *x1, *x2;
unsigned int *x2;
x1 = calloc(Nc + q->len + 31, sizeof(unsigned int)); x1 = calloc(Nc + q->len + 31, sizeof(uint32_t));
if (!x1) { if (!x1) {
perror("calloc"); perror("calloc");
return; return;
} }
x2 = calloc(Nc + q->len + 31, sizeof(unsigned int)); x2 = calloc(Nc + q->len + 31, sizeof(uint32_t));
if (!x2) { if (!x2) {
free(x1); free(x1);
perror("calloc"); perror("calloc");
@ -76,26 +75,26 @@ void generate_prs_c(sequence_t *q, unsigned int seed) {
free(x2); 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)) { if (sequence_init(q, len)) {
return -1; return LIBLTE_ERROR;
} }
q->len = len; q->len = len;
generate_prs_c(q, seed); 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)) { if (q->c && (q->len != len)) {
free(q->c); free(q->c);
} }
if (!q->c) { if (!q->c) {
q->c = malloc(len * sizeof(char)); q->c = malloc(len * sizeof(char));
if (!q->c) { if (!q->c) {
return -1; return LIBLTE_ERROR;
} }
} }
return 0; return LIBLTE_SUCCESS;
} }
void sequence_free(sequence_t *q) { void sequence_free(sequence_t *q) {

@ -111,8 +111,8 @@ int main(int argc, char **argv) {
input[i] = 100 * ((float) rand()/RAND_MAX + (float) I*rand()/RAND_MAX); input[i] = 100 * ((float) rand()/RAND_MAX + (float) I*rand()/RAND_MAX);
} }
lte_ifft_run(&ifft, input, outfft); lte_ifft_run_slot(&ifft, input, outfft);
lte_fft_run(&fft, outfft, outifft); lte_fft_run_slot(&fft, outfft, outifft);
/* compute MSE */ /* compute MSE */

@ -28,33 +28,41 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <math.h> #include <math.h>
#include "liblte/phy/fec/convcoder.h" #include "liblte/phy/fec/convcoder.h"
#include "parity.h" #include "parity.h"
int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length) { int convcoder_encode(convcoder_t *q, char *input, char *output, uint32_t frame_length) {
unsigned int sr; uint32_t sr;
int i,j; uint32_t i,j;
int len = q->tail_biting ? frame_length : (frame_length + q->K - 1); uint32_t len = q->tail_biting ? frame_length : (frame_length + q->K - 1);
if (q->tail_biting) { if (q != NULL &&
sr = 0; input != NULL &&
for (i=frame_length - q->K + 1; i<frame_length; i++) { output != NULL &&
sr = (sr << 1) | (input[i] & 1); frame_length > q->K + 1)
{
if (q->tail_biting) {
sr = 0;
for (i=frame_length - q->K + 1; i<frame_length; i++) {
sr = (sr << 1) | (input[i] & 1);
}
} else {
sr = 0;
} }
} else { for (i = 0; i < len; i++) {
sr = 0; char bit = (i < frame_length) ? (input[i] & 1) : 0;
} sr = (sr << 1) | bit;
for (i = 0; i < len; i++) { for (j=0;j<q->R;j++) {
int bit = (i < frame_length) ? (input[i] & 1) : 0; output[q->R * i + j] = parity(sr & q->poly[j]);
sr = (sr << 1) | bit; }
for (j=0;j<q->R;j++) {
output[q->R * i + j] = parity(sr & q->poly[j]);
} }
return q->R*len;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
} }
return q->R*len;
} }

@ -114,7 +114,7 @@ int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) {
return 0; 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; int i, k, len8, res8, a = 0;
unsigned int crc = 0; unsigned int crc = 0;
char *pter; char *pter;

@ -4,26 +4,27 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
unsigned char Partab[256]; uint8_t Partab[256];
int P_init; uint32_t P_init;
/* Create 256-entry odd-parity lookup table /* Create 256-entry odd-parity lookup table
* Needed only on non-ia32 machines * Needed only on non-ia32 machines
*/ */
void partab_init(void) { void partab_init(void) {
int i, cnt, ti; uint32_t i, cnt, ti;
/* Initialize parity lookup table */ /* Initialize parity lookup table */
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
cnt = 0; cnt = 0;
ti = i; ti = i;
while (ti) { while (ti) {
if (ti & 1) if (ti & 1)
cnt++; cnt++;
ti >>= 1; ti >>= 1;
} }
Partab[i] = cnt & 1; Partab[i] = cnt & 1;
} }
P_init = 1; P_init = 1;
} }

@ -10,16 +10,16 @@
/* Determine parity of argument: 1 = odd, 0 = even */ /* Determine parity of argument: 1 = odd, 0 = even */
#ifdef __i386__ #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)); __asm__ __volatile__ ("test %1,%1;setpo %0" : "=qhm" (x) : "qh" (x));
return x; return x;
} }
#else #else
void partab_init(); void partab_init();
static inline int parityb(unsigned char x){ static inline uint32_t parityb(uint8_t x){
extern unsigned char Partab[256]; extern uint8_t Partab[256];
extern int P_init; extern uint32_t P_init;
if(!P_init){ if(!P_init){
partab_init(); partab_init();
} }
@ -28,7 +28,7 @@ static inline int parityb(unsigned char x){
#endif #endif
static inline int parity(int x){ static inline uint32_t parity(int x){
/* Fold down to one byte */ /* Fold down to one byte */
x ^= (x >> 16); x ^= (x >> 16);
x ^= (x >> 8); x ^= (x >> 8);

@ -27,25 +27,27 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include "liblte/phy/fec/rm_conv.h" #include "liblte/phy/fec/rm_conv.h"
#define NCOLS 32 #define NCOLS 32
#define NROWS_MAX NCOLS #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 }; 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, { 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 }; 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]; char tmp[3 * NCOLS * NROWS_MAX];
int nrows, ndummy, K_p; int nrows, ndummy, K_p;
int i, j, k, s; 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) { if (nrows > NROWS_MAX) {
fprintf(stderr, "Input too large. Max input length is %d\n", fprintf(stderr, "Input too large. Max input length is %d\n",
3 * NCOLS * NROWS_MAX); 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. /* Undoes Convolutional Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.2 * 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 nrows, ndummy, K_p;
int i, j, k; 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]; 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) { if (nrows > NROWS_MAX) {
fprintf(stderr, "Output too large. Max output length is %d\n", fprintf(stderr, "Output too large. Max output length is %d\n",
3 * NCOLS * NROWS_MAX); 3 * NCOLS * NROWS_MAX);

@ -30,50 +30,43 @@
#include <math.h> #include <math.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#include "liblte/phy/fec/rm_turbo.h" #include "liblte/phy/fec/rm_turbo.h"
#define NCOLS 32 #define NCOLS 32
#define NROWS_MAX NCOLS #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 }; 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. /* Turbo Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.1 * 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 * 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 rm_turbo_tx(char *w_buff, uint32_t w_buff_len, char *input, uint32_t in_len, char *output,
int out_len, int rv_idx) { uint32_t out_len, uint32_t rv_idx) {
char *tmp = (char*) q->buffer; int ndummy, kidx;
int nrows, ndummy, K_p; 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; K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) { if (3 * K_p > w_buff_len) {
fprintf(stderr, fprintf(stderr,
"Input too large. Max input length including dummy bits is %d (3x%dx32, in_len %d)\n", "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; return -1;
} }
@ -82,47 +75,49 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output,
ndummy = 0; ndummy = 0;
} }
/* Sub-block interleaver (5.1.4.1.1) and bit collection */ if (rv_idx == 0) {
k = 0; /* Sub-block interleaver (5.1.4.1.1) and bit collection */
for (s = 0; s < 2; s++) { k = 0;
for (j = 0; j < NCOLS; j++) { for (s = 0; s < 2; s++) {
for (i = 0; i < nrows; i++) { for (j = 0; j < NCOLS; j++) {
if (s == 0) { for (i = 0; i < nrows; i++) {
kidx = k % K_p; if (s == 0) {
} else { kidx = k % K_p;
kidx = K_p + 2 * (k % K_p); } else {
} kidx = K_p + 2 * (k % K_p);
if (i * NCOLS + RM_PERM_TC[j] < ndummy) { }
tmp[kidx] = TX_NULL; if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
} else { w_buff[kidx] = TX_NULL;
tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s]; } else {
w_buff[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
}
k++;
} }
k++;
} }
} }
}
// d_k^(2) goes through special permutation // d_k^(2) goes through special permutation
for (k = 0; k < K_p; k++) { for (k = 0; k < K_p; k++) {
kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p; kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) { if ((kidx - ndummy) < 0) {
tmp[K_p + 2 * k + 1] = TX_NULL; w_buff[K_p + 2 * k + 1] = TX_NULL;
} else { } else {
tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2]; w_buff[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
}
} }
} }
/* Bit selection and transmission 5.1.4.1.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 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; k = 0;
j = 0; j = 0;
while (k < out_len) { while (k < out_len) {
if (tmp[(k0 + j) % N_cb] != TX_NULL) { if (w_buff[(k0 + j) % N_cb] != TX_NULL) {
output[k] = tmp[(k0 + j) % N_cb]; output[k] = w_buff[(k0 + j) % N_cb];
k++; k++;
} }
j++; 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. /* Undoes Turbo Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.1 * 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 rm_turbo_rx(float *w_buff, uint32_t w_buff_len, float *input, uint32_t in_len, float *output,
int out_len, int rv_idx) { uint32_t out_len, uint32_t rv_idx) {
int nrows, ndummy, K_p, k0, N_cb, jp, kidx; int nrows, ndummy, K_p, k0, N_cb, jp, kidx;
int i, j, k; int i, j, k;
int d_i, d_j; int d_i, d_j;
bool isdummy; bool isdummy;
float *tmp = (float*) q->buffer; nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1;
nrows = (int) (out_len / 3 - 1) / NCOLS + 1;
K_p = nrows * NCOLS; K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) { if (3 * K_p > w_buff_len) {
fprintf(stderr, fprintf(stderr,
"Input too large. Max output length including dummy bits is %d (3x%dx32, in_len %d)\n", "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; return -1;
} }
@ -157,14 +153,16 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
ndummy = 0; ndummy = 0;
} }
for (i = 0; i < 3 * K_p; i++) { if (rv_idx == 0) {
tmp[i] = RX_NULL; for (i = 0; i < 3 * K_p; i++) {
w_buff[i] = RX_NULL;
}
} }
/* Undo bit collection. Account for dummy bits */ /* 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 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; k = 0;
j = 0; j = 0;
@ -185,7 +183,7 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
isdummy = true; isdummy = true;
} }
} else { } 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; kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) { if ((kidx - ndummy) < 0) {
isdummy = true; isdummy = true;
@ -195,10 +193,10 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
} }
if (!isdummy) { if (!isdummy) {
if (tmp[jp] == RX_NULL) { if (w_buff[jp] == RX_NULL) {
tmp[jp] = input[k]; w_buff[jp] = input[k];
} else if (input[k] != RX_NULL) { } else if (input[k] != RX_NULL) {
tmp[jp] += input[k]; /* soft combine LLRs */ w_buff[jp] += input[k]; /* soft combine LLRs */
} }
k++; k++;
} }
@ -213,15 +211,14 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
if (j != 2) { if (j != 2) {
kidx = K_p * j + (j + 1) * (RM_PERM_TC[d_j] * nrows + d_i); kidx = K_p * j + (j + 1) * (RM_PERM_TC[d_j] * nrows + d_i);
} else { } else {
k = (i + ndummy - 1) % K_p; k = (i + ndummy - 1) % K_p;
if (k < 0) if (k < 0)
k += K_p; k += K_p;
kidx = (k / NCOLS + nrows * RM_PERM_TC[k % NCOLS]) % K_p; kidx = (k / NCOLS + nrows * RM_PERM_TC[k % NCOLS]) % K_p;
kidx = 2 * kidx + K_p + 1; kidx = 2 * kidx + K_p + 1;
} }
if (tmp[kidx] != RX_NULL) { if (w_buff[kidx] != RX_NULL) {
output[i * 3 + j] = tmp[kidx]; output[i * 3 + j] = w_buff[kidx];
} else { } else {
output[i * 3 + j] = 0; 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 */ /** High-level API */
int rm_turbo_initialize(rm_turbo_hl* h) { 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 */ /** This function can be called in a subframe (1ms) basis */
int rm_turbo_work(rm_turbo_hl* hl) { 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; return 0;
} }
int rm_turbo_stop(rm_turbo_hl* hl) { int rm_turbo_stop(rm_turbo_hl* hl) {
rm_turbo_free(&hl->q);
return 0; return 0;
} }

@ -27,6 +27,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#include "liblte/phy/common/phy_common.h" #include "liblte/phy/common/phy_common.h"
#include "liblte/phy/fec/tc_interl.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, 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, 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, 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, 39, 127, 39, 39, 31, 113, 41, 251, 43, 21, 43, 45, 45, 161, 89, 323, 47, 23,
47, 263 }; 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, 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, 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, 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, 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 }; 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 tc_interl_LTE_gen(tc_interl_t *h, uint32_t long_cb) {
int cb_table_idx, f1, f2; uint32_t cb_table_idx, f1, f2;
unsigned long long i, j; uint64_t i, j;
if (long_cb > h->max_long_cb) { if (long_cb > h->max_long_cb) {
fprintf(stderr, "Interleaver initiated for max_long_cb=%d\n", 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; h->reverse[0] = 0;
for (i = 1; i < long_cb; i++) { for (i = 1; i < long_cb; i++) {
j = (f1 * i + f2 * i * i) % (long_cb); j = (f1 * i + f2 * i * i) % (long_cb);
h->forward[i] = j; h->forward[i] = (uint32_t) j;
h->reverse[j] = i; h->reverse[j] = (uint32_t) i;
} }
return 0; return 0;

@ -28,13 +28,14 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <strings.h> #include <strings.h>
#include <stdint.h>
#include "liblte/phy/fec/tc_interl.h" #include "liblte/phy/fec/tc_interl.h"
#include "liblte/phy/fec/turbocoder.h" #include "liblte/phy/fec/turbocoder.h"
#define TURBO_RATE 3 #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, 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 }; 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; int ret = -1;
h->forward = malloc(sizeof(int) * max_long_cb); h->forward = malloc(sizeof(uint32_t) * max_long_cb);
if (!h->forward) { if (!h->forward) {
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
} }
h->reverse = malloc(sizeof(int) * max_long_cb); h->reverse = malloc(sizeof(uint32_t) * max_long_cb);
if (!h->reverse) { if (!h->reverse) {
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
@ -83,17 +84,17 @@ void tc_interl_free(tc_interl_t *h) {
bzero(h, sizeof(tc_interl_t)); 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; uint32_t i, j;
int res, prim, aux; uint32_t res, prim, aux;
int kp, k; uint32_t kp, k;
int *per, *desper; uint32_t *per, *desper;
unsigned char v; uint8_t v;
unsigned short p; uint16_t p;
unsigned short s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS]; uint16_t s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS];
unsigned short U[MAX_COLS * MAX_ROWS]; uint16_t U[MAX_COLS * MAX_ROWS];
int M_Rows, M_Cols, M_long; uint32_t M_Rows, M_Cols, M_long;
M_long = long_cb; 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) { uint32_t mcd(uint32_t x, uint32_t y) {
int r = 1; uint32_t r = 1;
while (r) { while (r) {
r = x % y; r = x % y;

@ -26,12 +26,14 @@
*/ */
#include "liblte/phy/fec/turbocoder.h"
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include "liblte/phy/fec/turbocoder.h"
#define NOF_REGS 3 #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)) { if (tc_interl_init(&h->interl, max_long_cb)) {
return -1; return -1;
@ -45,13 +47,13 @@ void tcod_free(tcod_t *h) {
h->max_long_cb = 0; 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; 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 bit;
char in, out; char in, out;
int *per; uint32_t *per;
if (long_cb > h->max_long_cb) { if (long_cb > h->max_long_cb) {
fprintf(stderr, "Turbo coder initiated for max_long_cb=%d\n", fprintf(stderr, "Turbo coder initiated for max_long_cb=%d\n",

@ -27,6 +27,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
@ -38,13 +39,13 @@
* Decoder * 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 m_b[8], new[8], old[8];
llr_t x, y, xy; llr_t x, y, xy;
int k; int k;
int end = long_cb + RATE; uint32_t end = long_cb + RATE;
llr_t *beta = s->beta; llr_t *beta = s->beta;
int i; uint32_t i;
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
old[i] = beta[8 * (end) + 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, 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 m_b[8], new[8], old[8], max1[8], max0[8];
llr_t m1, m0; llr_t m1, m0;
llr_t x, y, xy; llr_t x, y, xy;
llr_t out; llr_t out;
int k; uint32_t k;
int end = long_cb; uint32_t end = long_cb;
llr_t *beta = s->beta; llr_t *beta = s->beta;
int i; uint32_t i;
old[0] = 0; old[0] = 0;
for (i = 1; i < 8; i++) { 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, void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output,
int long_cb) { uint32_t long_cb) {
int k; uint32_t k;
h->beta[(long_cb + TAIL) * NUMSTATES] = 0; h->beta[(long_cb + TAIL) * NUMSTATES] = 0;
for (k = 1; k < NUMSTATES; k++) 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 * 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; int ret = -1;
bzero(h, sizeof(tdec_t)); 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; h->max_long_cb = max_long_cb;
@ -256,8 +257,8 @@ void tdec_free(tdec_t *h) {
bzero(h, sizeof(tdec_t)); bzero(h, sizeof(tdec_t));
} }
void tdec_iteration(tdec_t *h, llr_t *input, int long_cb) { void tdec_iteration(tdec_t *h, llr_t *input, uint32_t long_cb) {
int i; uint32_t i;
// Prepare systematic and parity bits for MAP DEC #1 // Prepare systematic and parity bits for MAP DEC #1
for (i = 0; i < long_cb; i++) { 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); memset(h->w, 0, sizeof(llr_t) * long_cb);
if (long_cb > h->max_long_cb) { if (long_cb > h->max_long_cb) {
fprintf(stderr, "TDEC was initialized for max_long_cb=%d\n", 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); return tc_interl_LTE_gen(&h->interleaver, long_cb);
} }
void tdec_decision(tdec_t *h, char *output, int long_cb) { void tdec_decision(tdec_t *h, char *output, uint32_t long_cb) {
int i; uint32_t i;
for (i = 0; i < long_cb; i++) { for (i = 0; i < long_cb; i++) {
output[i] = (h->llr2[h->interleaver.reverse[i]] > 0) ? 1 : 0; 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, void tdec_run_all(tdec_t *h, llr_t *input, char *output, uint32_t nof_iterations,
int long_cb) { uint32_t long_cb) {
int iter = 0; uint32_t iter = 0;
tdec_reset(h, long_cb); tdec_reset(h, long_cb);

@ -27,6 +27,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
@ -38,11 +40,11 @@
#define DEB 0 #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; viterbi_t *q = o;
int i; uint32_t i;
int best_state; uint32_t best_state;
if (frame_length > q->framebits) { if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n", 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; 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; viterbi_t *q = o;
if (frame_length > q->framebits) { if (frame_length > q->framebits) {
@ -113,7 +115,7 @@ void free39(void *o) {
delete_viterbi39_port(q->ptr); 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->K = 7;
q->R = 3; q->R = 3;
q->framebits = framebits; 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->K = 9;
q->R = 3; q->R = 3;
q->framebits = framebits; 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 viterbi_init(viterbi_t *q, viterbi_type_t type, uint32_t poly[3],
int max_frame_length, bool tail_bitting) { uint32_t max_frame_length, bool tail_bitting) {
switch (type) { switch (type) {
case viterbi_37: case viterbi_37:
return init37(q, poly, max_frame_length, tail_bitting); 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) { void viterbi_free(viterbi_t *q) {
q->free(q); if (q->free) {
q->free(q);
}
} }
/* symbols are real-valued */ /* symbols are real-valued */
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length) { int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, uint32_t frame_length) {
int len; uint32_t len;
if (frame_length > q->framebits) { if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n", fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits); 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); return q->decode(q, q->symbols_uc, data, frame_length);
} }
int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, int viterbi_decode_uc(viterbi_t *q, uint8_t *symbols, char *data,
int frame_length) { uint32_t frame_length) {
return q->decode(q, symbols, data, frame_length); return q->decode(q, symbols, data, frame_length);
} }
int viterbi_initialize(viterbi_hl* h) { int viterbi_initialize(viterbi_hl* h) {
int poly[3]; uint32_t poly[3];
viterbi_type_t type; viterbi_type_t type;
if (h->init.rate == 2) { if (h->init.rate == 2) {
if (h->init.constraint_length == 7) { if (h->init.constraint_length == 7) {
@ -241,7 +245,7 @@ int viterbi_initialize(viterbi_hl* h) {
poly[0] = h->init.generator_0; poly[0] = h->init.generator_0;
poly[1] = h->init.generator_1; poly[1] = h->init.generator_1;
poly[2] = h->init.generator_2; 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); h->init.tail_bitting ? true : false);
} }

@ -27,8 +27,20 @@
#include <stdbool.h> #include <stdbool.h>
void *create_viterbi37_port(int polys[3], int len); void *create_viterbi37_port(uint32_t polys[3],
int init_viterbi37_port(void *p, int starting_state); uint32_t len);
int chainback_viterbi37_port(void *p, char *data, unsigned int nbits, unsigned int endstate);
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); 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);

@ -4,6 +4,8 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#include <memory.h> #include <memory.h>
#include "viterbi37.h" #include "viterbi37.h"
#include "parity.h" #include "parity.h"
@ -30,9 +32,9 @@ struct v37 {
}; };
/* Initialize Viterbi decoder for start of new frame */ /* 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; struct v37 *vp = p;
int i; uint32_t i;
if (p == NULL) if (p == NULL)
return -1; return -1;
@ -48,8 +50,8 @@ int init_viterbi37_port(void *p, int starting_state) {
return 0; return 0;
} }
void set_viterbi37_polynomial_port(int polys[3]) { void set_viterbi37_polynomial_port(uint32_t polys[3]) {
int state; uint32_t state;
for (state = 0; state < 32; state++) { for (state = 0; state < 32; state++) {
Branchtab37[0].c[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 */ /* 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; struct v37 *vp;
set_viterbi37_polynomial_port(polys); set_viterbi37_polynomial_port(polys);
@ -82,8 +84,8 @@ void *create_viterbi37_port(int polys[3], int len) {
/* Viterbi chainback */ /* Viterbi chainback */
int chainback_viterbi37_port(void *p, char *data, /* Decoded output data */ int chainback_viterbi37_port(void *p, char *data, /* Decoded output data */
unsigned int nbits, /* Number of data bits */ uint32_t nbits, /* Number of data bits */
unsigned int endstate) { /* Terminal encoder state */ uint32_t endstate) { /* Terminal encoder state */
struct v37 *vp = p; struct v37 *vp = p;
decision_t *d; decision_t *d;
@ -145,18 +147,18 @@ unsigned int metric,m0,m1,decision;\
* of symbols! * 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; struct v37 *vp = p;
decision_t *d; decision_t *d;
if (p == NULL) if (p == NULL)
return -1; return -1;
int k=0; uint32_t k=0;
d = (decision_t *) vp->dp; d = (decision_t *) vp->dp;
while (nbits--) { while (nbits--) {
void *tmp; void *tmp;
unsigned char sym0, sym1, sym2; uint8_t sym0, sym1, sym2;
int i; uint32_t i;
d->w[0] = d->w[1] = 0; 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; vp->new_metrics = tmp;
} }
if (best_state) { if (best_state) {
int i, bst=0; uint32_t i, bst=0;
unsigned int minmetric=UINT_MAX; uint32_t minmetric=UINT_MAX;
for (i=0;i<64;i++) { for (i=0;i<64;i++) {
if (vp->old_metrics->w[i] < minmetric) { if (vp->old_metrics->w[i] < minmetric) {
bst = i; bst = i;

@ -27,10 +27,19 @@
#include <stdbool.h> #include <stdbool.h>
void *create_viterbi39_port(int polys[3], int len); void *create_viterbi39_port(uint32_t polys[3],
int init_viterbi39_port(void *p, int starting_state); uint32_t len);
int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */
unsigned int nbits, /* Number of data bits */ int init_viterbi39_port(void *p,
unsigned int endstate); 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); 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);

@ -4,6 +4,7 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#include <memory.h> #include <memory.h>
#include "viterbi39.h" #include "viterbi39.h"
#include "parity.h" #include "parity.h"
@ -29,9 +30,9 @@ struct v39 {
}; };
/* Initialize Viterbi decoder for start of new frame */ /* 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; struct v39 *vp = p;
int i; uint32_t i;
if (p == NULL) if (p == NULL)
return -1; return -1;
@ -45,8 +46,8 @@ int init_viterbi39_port(void *p, int starting_state) {
return 0; return 0;
} }
void set_viterbi39_polynomial_port(int polys[3]) { void set_viterbi39_polynomial_port(uint32_t polys[3]) {
int state; uint32_t state;
for (state = 0; state < 128; state++) { for (state = 0; state < 128; state++) {
Branchtab39[0].c[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 */ /* 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; struct v39 *vp;
set_viterbi39_polynomial_port(polys); set_viterbi39_polynomial_port(polys);
@ -79,8 +80,8 @@ void *create_viterbi39_port(int polys[3], int len) {
/* Viterbi chainback */ /* Viterbi chainback */
int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */ int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */
unsigned int nbits, /* Number of data bits */ uint32_t nbits, /* Number of data bits */
unsigned int endstate) { /* Terminal encoder state */ uint32_t endstate) { /* Terminal encoder state */
struct v39 *vp = p; struct v39 *vp = p;
decision_t *d; decision_t *d;
@ -140,7 +141,7 @@ unsigned int metric,m0,m1,decision;\
* of symbols! * 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; struct v39 *vp = p;
decision_t *d; decision_t *d;
@ -150,8 +151,8 @@ int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits) {
d = (decision_t *) vp->dp; d = (decision_t *) vp->dp;
while (nbits--) { while (nbits--) {
void *tmp; void *tmp;
unsigned char sym0, sym1, sym2; uint8_t sym0, sym1, sym2;
int i; uint32_t i;
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
d->w[i] = 0; d->w[i] = 0;

@ -73,10 +73,9 @@ void parse_args(int argc, char **argv) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
int i; int i;
char *bits, *rm_bits; char *bits, *rm_bits, *w_buff_c;
float *rm_symbols, *unrm_symbols; float *rm_symbols, *unrm_symbols, *w_buff_f;
int nof_errors; int nof_errors;
rm_turbo_t rm_turbo;
parse_args(argc, argv); parse_args(argc, argv);
@ -85,6 +84,11 @@ int main(int argc, char **argv) {
perror("malloc"); perror("malloc");
exit(-1); 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); rm_bits = malloc(sizeof(char) * nof_rx_bits);
if (!rm_bits) { if (!rm_bits) {
perror("malloc"); perror("malloc");
@ -95,6 +99,11 @@ int main(int argc, char **argv) {
perror("malloc"); perror("malloc");
exit(-1); 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); unrm_symbols = malloc(sizeof(float) * nof_tx_bits);
if (!unrm_symbols) { if (!unrm_symbols) {
perror("malloc"); perror("malloc");
@ -105,15 +114,13 @@ int main(int argc, char **argv) {
bits[i] = rand() % 2; bits[i] = rand() % 2;
} }
rm_turbo_init(&rm_turbo, 2000); rm_turbo_tx(w_buff_c, nof_tx_bits * 10, bits, nof_tx_bits, rm_bits, nof_rx_bits, rv_idx);
rm_turbo_tx(&rm_turbo, bits, nof_tx_bits, rm_bits, nof_rx_bits, rv_idx);
for (i = 0; i < nof_rx_bits; i++) { for (i = 0; i < nof_rx_bits; i++) {
rm_symbols[i] = (float) rm_bits[i] ? 1 : -1; 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); rv_idx);
nof_errors = 0; nof_errors = 0;
@ -123,8 +130,6 @@ int main(int argc, char **argv) {
} }
} }
rm_turbo_free(&rm_turbo);
free(bits); free(bits);
free(rm_bits); free(rm_bits);
free(rm_symbols); free(rm_symbols);

@ -41,9 +41,9 @@
typedef _Complex float cf_t; 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; float ebno_db = 100.0;
unsigned int seed = 0; uint32_t seed = 0;
int K = -1; int K = -1;
#define MAX_ITERATIONS 4 #define MAX_ITERATIONS 4
@ -51,9 +51,9 @@ int nof_iterations = MAX_ITERATIONS;
int test_known_data = 0; int test_known_data = 0;
int test_errors = 0; int test_errors = 0;
#define SNR_POINTS 8 #define SNR_POINTS 8
#define SNR_MIN 0.0 #define SNR_MIN 0.0
#define SNR_MAX 4.0 #define SNR_MAX 4.0
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [nlesv]\n", 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 main(int argc, char **argv) {
int frame_cnt; uint32_t frame_cnt;
float *llr; float *llr;
unsigned char *llr_c; unsigned char *llr_c;
char *data_tx, *data_rx, *symbols; char *data_tx, *data_rx, *symbols;
int i, j; uint32_t i, j;
float var[SNR_POINTS]; float var[SNR_POINTS];
int snr_points; uint32_t snr_points;
float ber[MAX_ITERATIONS][SNR_POINTS]; float ber[MAX_ITERATIONS][SNR_POINTS];
unsigned int errors[100]; uint32_t errors[100];
int coded_length; uint32_t coded_length;
struct timeval tdata[3]; struct timeval tdata[3];
float mean_usec; float mean_usec;
tdec_t tdec; tdec_t tdec;
@ -247,7 +247,7 @@ int main(int argc, char **argv) {
/* decoder */ /* decoder */
tdec_reset(&tdec, frame_length); tdec_reset(&tdec, frame_length);
int t; uint32_t t;
if (nof_iterations == -1) { if (nof_iterations == -1) {
t = MAX_ITERATIONS; t = MAX_ITERATIONS;
} else { } else {

@ -37,14 +37,14 @@ void demod_hard_init(demod_hard_t* q) {
bzero((void*) q, sizeof(demod_hard_t)); bzero((void*) q, sizeof(demod_hard_t));
} }
void demod_hard_table_set(demod_hard_t* q, enum modem_std table) { void demod_hard_table_set(demod_hard_t* q, lte_mod_t mod) {
q->table = table; 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; int nbits=-1;
switch(q->table) { switch(q->mod) {
case LTE_BPSK: case LTE_BPSK:
hard_bpsk_demod(symbols,bits,nsymbols); hard_bpsk_demod(symbols,bits,nsymbols);
nbits=nsymbols; nbits=nsymbols;

@ -69,7 +69,7 @@ int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int
/* High-Level API */ /* High-Level API */
int demod_soft_initialize(demod_soft_hl* hl) { int demod_soft_initialize(demod_soft_hl* hl) {
modem_table_init(&hl->table); 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; return -1;
} }
demod_soft_init(&hl->obj); demod_soft_init(&hl->obj);

@ -33,6 +33,7 @@
#include "liblte/phy/modem/demod_hard.h" #include "liblte/phy/modem/demod_hard.h"
#include "hard_demod_lte.h" #include "hard_demod_lte.h"
/** /**
* @ingroup Hard BPSK demodulator * @ingroup Hard BPSK demodulator
* *
@ -46,9 +47,9 @@
* \param N Number of input symbols * \param N Number of input symbols
* \param modulation Modulation type * \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<N; s++) { /* received symbols */ for (s=0; s<N; s++) { /* received symbols */
if (__real__ in[s] > 0) { if (__real__ in[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 N Number of input symbols
* \param modulation Modulation type * \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<N; s++) { for (s=0; s<N; s++) {
if (__real__ in[s] > 0) { if (__real__ in[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 N Number of input symbols
* \param modulation Modulation type * \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<N; s++) { for (s=0; s<N; s++) {
if (__real__ in[s] > 0) { if (__real__ in[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 N Number of input symbols
* \param modulation Modulation type * \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; s<N; s++) { for (s=0; s<N; s++) {
/* bits associated with/obtained from in-phase component: b0, b2, b4 */ /* bits associated with/obtained from in-phase component: b0, b2, b4 */

@ -25,7 +25,6 @@
* *
*/ */
/* Thresholds for Demodulation */ /* Thresholds for Demodulation */
/* Assume perfect amplitude and phase alignment. /* Assume perfect amplitude and phase alignment.
* Check threshold values for real case * Check threshold values for real case
@ -35,7 +34,18 @@
#define QAM64_THRESHOLD_2 4/sqrt(42) #define QAM64_THRESHOLD_2 4/sqrt(42)
#define QAM64_THRESHOLD_3 6/sqrt(42) #define QAM64_THRESHOLD_3 6/sqrt(42)
void hard_bpsk_demod(const cf_t* in, char* out, int N); void hard_bpsk_demod(const cf_t* in,
void hard_qpsk_demod(const cf_t* in, char* out, int N); char* out,
void hard_qam16_demod(const cf_t* in, char* out, int N); uint32_t N);
void hard_qam64_demod(const cf_t* in, char* out, int N);
void hard_qpsk_demod(const cf_t* in,
char* out,
uint32_t N);
void hard_qam16_demod(const cf_t* in,
char* out,
uint32_t N);
void hard_qam64_demod(const cf_t* in,
char* out,
uint32_t N);

@ -59,7 +59,7 @@ void set_BPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demo
* Set the QPSK modulation table */ * Set the QPSK modulation table */
void set_QPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod) void set_QPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{ {
int i,j; uint32_t i,j;
// LTE-QPSK constellation: // LTE-QPSK constellation:
// Q // Q
@ -97,7 +97,7 @@ void set_QPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demo
* Set the 16QAM modulation table */ * Set the 16QAM modulation table */
void set_16QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod) void set_16QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{ {
int i,j; uint32_t i,j;
// LTE-16QAM constellation: // LTE-16QAM constellation:
// Q // Q
// 1011 1001 | 0001 0011 // 1011 1001 | 0001 0011
@ -162,7 +162,7 @@ void set_16QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_dem
* Set the 64QAM modulation table */ * Set the 64QAM modulation table */
void set_64QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod) void set_64QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{ {
int i,j; uint32_t i,j;
// LTE-64QAM constellation: // LTE-64QAM constellation:
// see [3GPP TS 36.211 version 10.5.0 Release 10, Section 7.1.4] // see [3GPP TS 36.211 version 10.5.0 Release 10, Section 7.1.4]
table[0] = QAM64_LEVEL_2 + QAM64_LEVEL_2*_Complex_I; table[0] = QAM64_LEVEL_2 + QAM64_LEVEL_2*_Complex_I;

@ -45,7 +45,18 @@
void set_BPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod); void set_BPSKtable(cf_t* table,
void set_QPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod); soft_table_t *soft_table,
void set_16QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod); bool compute_soft_demod);
void set_64QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod);
void set_QPSKtable(cf_t* table,
soft_table_t *soft_table,
bool compute_soft_demod);
void set_16QAMtable(cf_t* table,
soft_table_t *soft_table,
bool compute_soft_demod);
void set_64QAMtable(cf_t* table,
soft_table_t *soft_table,
bool compute_soft_demod);

@ -35,14 +35,17 @@
/** Low-level API */ /** Low-level API */
int mod_modulate(modem_table_t* q, const char *bits, cf_t* symbols, int nbits) { int mod_modulate(modem_table_t* q, const char *bits, cf_t* symbols, uint32_t nbits) {
int i,j,idx; uint32_t i,j,idx;
char *b_ptr=(char*) bits; char *b_ptr=(char*) bits;
j=0; j=0;
for (i=0;i<nbits;i+=q->nbits_x_symbol) { for (i=0;i<nbits;i+=q->nbits_x_symbol) {
idx = bit_unpack(&b_ptr,q->nbits_x_symbol); idx = bit_unpack(&b_ptr,q->nbits_x_symbol);
assert(idx >= 0 && idx < q->nsymbols); if (idx < q->nsymbols) {
symbols[j] = q->symbol_table[idx]; symbols[j] = q->symbol_table[idx];
} else {
return LIBLTE_ERROR;
}
j++; j++;
} }
return 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 */ /* High-Level API */
int mod_initialize(mod_hl* hl) { int mod_initialize(mod_hl* hl) {
modem_table_init(&hl->obj); 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; return -1;
} }

@ -33,6 +33,7 @@
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include "liblte/phy/common/phy_common.h"
#include "liblte/phy/modem/modem_table.h" #include "liblte/phy/modem/modem_table.h"
#include "lte_tables.h" #include "lte_tables.h"
@ -56,27 +57,27 @@ void modem_table_reset(modem_table_t* q) {
modem_table_init(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) { if (q->nsymbols) {
return -1; return LIBLTE_ERROR;
} }
q->nsymbols = nsymbols; q->nsymbols = nsymbols;
if (table_create(q)) { if (table_create(q)) {
return -1; return LIBLTE_ERROR;
} }
memcpy(q->symbol_table,table,q->nsymbols*sizeof(cf_t)); memcpy(q->symbol_table,table,q->nsymbols*sizeof(cf_t));
memcpy(&q->soft_table,soft_table,sizeof(soft_table_t)); memcpy(&q->soft_table,soft_table,sizeof(soft_table_t));
q->nbits_x_symbol = nbits_x_symbol; 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) { int modem_table_lte(modem_table_t* q, lte_mod_t modulation, bool compute_soft_demod) {
switch(std) { switch(modulation) {
case LTE_BPSK: case LTE_BPSK:
q->nbits_x_symbol = 1; q->nbits_x_symbol = 1;
q->nsymbols = 2; q->nsymbols = 2;
if (table_create(q)) { if (table_create(q)) {
return -1; return LIBLTE_ERROR;
} }
set_BPSKtable(q->symbol_table, &q->soft_table, compute_soft_demod); set_BPSKtable(q->symbol_table, &q->soft_table, compute_soft_demod);
break; 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->nbits_x_symbol = 2;
q->nsymbols = 4; q->nsymbols = 4;
if (table_create(q)) { if (table_create(q)) {
return -1; return LIBLTE_ERROR;
} }
set_QPSKtable(q->symbol_table, &q->soft_table, compute_soft_demod); set_QPSKtable(q->symbol_table, &q->soft_table, compute_soft_demod);
break; 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->nbits_x_symbol = 4;
q->nsymbols = 16; q->nsymbols = 16;
if (table_create(q)) { if (table_create(q)) {
return -1; return LIBLTE_ERROR;
} }
set_16QAMtable(q->symbol_table, &q->soft_table, compute_soft_demod); set_16QAMtable(q->symbol_table, &q->soft_table, compute_soft_demod);
break; 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->nbits_x_symbol = 6;
q->nsymbols = 64; q->nsymbols = 64;
if (table_create(q)) { if (table_create(q)) {
return -1; return LIBLTE_ERROR;
} }
set_64QAMtable(q->symbol_table, &q->soft_table, compute_soft_demod); set_64QAMtable(q->symbol_table, &q->soft_table, compute_soft_demod);
break; break;
} }
return 0; return LIBLTE_SUCCESS;
} }

@ -51,7 +51,7 @@
* \param sigma2 Noise vatiance * \param sigma2 Noise vatiance
*/ */
void llr_approx(const _Complex float *in, float *out, int N, int M, int B, 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; int i, s, b;
float num, den; float num, den;
float new_num, new_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 * \param sigma2 Noise vatiance
*/ */
void llr_exact(const _Complex float *in, float *out, int N, int M, int B, 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; int i, s, b;
float num, den; float num, den;
float idiff0, qdiff0, idiff1, qdiff1; float idiff0, qdiff0, idiff1, qdiff1;

@ -26,8 +26,20 @@
*/ */
void llr_approx(const _Complex float *in, float *out, int N, int M, int B, void llr_approx(const _Complex float *in,
_Complex float *symbols, int (*S)[6][32], float sigma2); 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, void llr_exact(const _Complex float *in,
_Complex float *symbols, int (*S)[6][32], float sigma2); float *out,
int N,
int M,
int B,
_Complex float *symbols,
uint32_t (*S)[6][32],
float sigma2);

@ -37,7 +37,7 @@
#include "liblte/phy/phy.h" #include "liblte/phy/phy.h"
int num_bits = 1000; int num_bits = 1000;
enum modem_std modulation; lte_mod_t modulation;
bool soft_output = false, soft_exact = false; bool soft_output = false, soft_exact = false;
void usage(char *prog) { void usage(char *prog) {
@ -101,7 +101,7 @@ int main(int argc, char **argv) {
parse_args(argc, argv); parse_args(argc, argv);
/* initialize objects */ /* 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"); fprintf(stderr, "Error initializing modem table\n");
exit(-1); exit(-1);
} }

@ -40,52 +40,86 @@
#include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/vector.h"
#include "liblte/phy/utils/debug.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;
}
q->nof_dcis = 0;
q->max_dcis = max_dcis;
return 0;
}
void dci_free(dci_t *q) { int dci_msg_to_ra_dl(dci_msg_t *msg, uint16_t msg_rnti, uint16_t c_rnti,
if (q->msg) { lte_cell_t cell, uint32_t cfi,
free(q->msg); 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;
}
} }
return ret;
} }
void dci_candidate_fprint(FILE *f, dci_candidate_t *q) { int dci_location_set(dci_location_t *c, uint32_t L, uint32_t nCCE) {
fprintf(f, "L: %d, nCCE: %d, RNTI: 0x%x, nBits: %d\n", q->L, q->ncce, q->rnti, if (L <= 3) {
q->nof_bits); c->L = L;
}
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;
} else { } else {
fprintf(stderr, "Invalid L %d\n", L); fprintf(stderr, "Invalid L %d\n", L);
return -1; return LIBLTE_ERROR;
} }
if (nCCE >= 0 && nCCE <= 87) { if (nCCE <= 87) {
msg->location.ncce = (unsigned char) nCCE; c->ncce = nCCE;
} else { } else {
fprintf(stderr, "Invalid nCCE %d\n", nCCE); fprintf(stderr, "Invalid nCCE %d\n", nCCE);
return -1; return LIBLTE_ERROR;
}
return LIBLTE_SUCCESS;
}
bool dci_location_isvalid(dci_location_t *c) {
if (c->L <= 3 && c->ncce <= 87) {
return true;
} else {
return false;
} }
msg->location.rnti = rnti;
return 0;
} }
int riv_nbits(int nof_prb) { uint32_t riv_nbits(uint32_t nof_prb) {
return (int) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2)); return (uint32_t) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2));
} }
const int ambiguous_sizes[10] = { 12, 14, 16, 20, 24, 26, 32, 40, 44, 56 }; const uint32_t ambiguous_sizes[10] = { 12, 14, 16, 20, 24, 26, 32, 40, 44, 56 };
bool is_ambiguous_size(int size) { bool is_ambiguous_size(uint32_t size) {
int i; int i;
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
if (size == ambiguous_sizes[i]) { if (size == ambiguous_sizes[i]) {
@ -98,12 +132,12 @@ bool is_ambiguous_size(int size) {
/********************************** /**********************************
* PAYLOAD sizeof functions * 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; return 1 + 1 + riv_nbits(nof_prb) + 5 + 1 + 2 + 3 + 1;
} }
int dci_format1A_sizeof(int nof_prb) { uint32_t dci_format1A_sizeof(uint32_t nof_prb) {
int n; uint32_t n;
n = 1 + 1 + riv_nbits(nof_prb) + 5 + 3 + 1 + 2 + 2; n = 1 + 1 + riv_nbits(nof_prb) + 5 + 3 + 1 + 2 + 2;
while (n < dci_format0_sizeof_(nof_prb)) { while (n < dci_format0_sizeof_(nof_prb)) {
n++; n++;
@ -114,17 +148,17 @@ int dci_format1A_sizeof(int nof_prb) {
return n; return n;
} }
int dci_format0_sizeof(int nof_prb) { uint32_t dci_format0_sizeof(uint32_t nof_prb) {
int n = dci_format0_sizeof_(nof_prb); uint32_t n = dci_format0_sizeof_(nof_prb);
while (n < dci_format1A_sizeof(nof_prb)) { while (n < dci_format1A_sizeof(nof_prb)) {
n++; n++;
} }
return 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; + 2;
if (nof_prb > 10) { if (nof_prb > 10) {
n++; n++;
@ -136,17 +170,17 @@ int dci_format1_sizeof(int nof_prb) {
return n; return n;
} }
int dci_format1C_sizeof(int nof_prb) { uint32_t dci_format1C_sizeof(uint32_t nof_prb) {
int n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true); uint32_t n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true);
int n_step = ra_type2_n_rb_step(nof_prb); uint32_t n_step = ra_type2_n_rb_step(nof_prb);
int n = +riv_nbits((int) n_vrb_dl_gap1 / n_step) + 5; uint32_t n = riv_nbits((uint32_t) n_vrb_dl_gap1 / n_step) + 5;
if (nof_prb >= 50) { if (nof_prb >= 50) {
n++; n++;
} }
return 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) { switch (format) {
case Format0: case Format0:
return dci_format0_sizeof(nof_prb); return dci_format0_sizeof(nof_prb);
@ -157,7 +191,7 @@ int dci_format_sizeof(dci_format_t format, int nof_prb) {
case Format1C: case Format1C:
return dci_format1C_sizeof(nof_prb); return dci_format1C_sizeof(nof_prb);
default: 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 * 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 */ /* pack bits */
char *y = msg->data; char *y = msg->data;
int n_ul_hop; uint32_t n_ul_hop;
*y++ = 0; // format differentiation *y++ = 0; // format differentiation
if (data->freq_hop_fl == hop_disabled) { // frequency hopping 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); bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop);
/* pack MCS according to 8.6.1 of 36.213 */ /* pack MCS according to 8.6.1 of 36.213 */
uint32_t mcs; bit_pack(data->mcs_idx, &y, 5);
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);
*y++ = data->ndi; *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; *y++ = data->cqi_request;
// Padding with zeros // Padding with zeros
int n = dci_format0_sizeof(nof_prb); uint32_t n = dci_format0_sizeof(nof_prb);
while (y - msg->data < n) { while (y - msg->data < n) {
*y++ = 0; *y++ = 0;
} }
msg->location.nof_bits = (y - msg->data); msg->nof_bits = (y - msg->data);
return 0; return LIBLTE_SUCCESS;
} }
/* Unpacks DCI format 0 data and store result in msg according /* Unpacks DCI format 0 data and store result in msg according
* to 36.212 5.3.3.1.1 * to 36.212 5.3.3.1.1
* *
* TODO: TPC and cyclic shift for DM RS not implemented * 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 */ /* pack bits */
char *y = msg->data; char *y = msg->data;
int n_ul_hop; uint32_t n_ul_hop;
/* Make sure it's a Format0 message */ /* 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"); fprintf(stderr, "Invalid message length for format 0\n");
return -1; return LIBLTE_ERROR;
} }
if (*y++ != 0) { if (*y++ != 0) {
fprintf(stderr, fprintf(stderr,
"Invalid format differentiation field value. This is Format1A\n"); "Invalid format differentiation field value. This is Format1A\n");
return -1; return LIBLTE_ERROR;
} }
if (*y++ == 0) { if (*y++ == 0) {
data->freq_hop_fl = hop_disabled; 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); 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, ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start,
nof_prb, nof_prb); 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; data->type2_alloc.riv = riv;
/* unpack MCS according to 8.6 of 36.213 */ /* 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; 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; data->cqi_request = *y++ ? true : false;
// 8.6.2 First paragraph // 8.6.2 First paragraph
if (mcs <= 28) { if (data->mcs_idx <= 28) {
ra_mcs_from_idx_ul(mcs, &data->mcs); ra_mcs_from_idx_ul(data->mcs_idx, ra_nprb_ul(data, nof_prb), &data->mcs);
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, } else if (data->mcs_idx == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) {
ra_nprb_ul(data, nof_prb)); // 8.6.1 and 8.6.2 36.213 second paragraph
} data->mcs.mod = LTE_QPSK;
data->mcs.tbs = 0;
// 8.6.1 and 8.6.2 36.213 second paragraph } else if (data->mcs_idx >= 29) {
if (mcs == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) { // Else leave TBS and use the previously used PUSCH modulation
data->mcs.mod = QPSK; data->mcs.tbs = 0;
} data->rv_idx = data->mcs_idx - 28;
if (mcs > 29) { }
// Else leave MOD_NULL and use the previously used PUSCH modulation
data->mcs.mod = MOD_NULL; return LIBLTE_SUCCESS;
data->rv_idx = mcs - 28;
}
return 0;
} }
/* Packs DCI format 1 data to a sequence of bits and store them in msg according /* 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 * 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 */ /* pack bits */
char *y = msg->data; 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 */ /* Resource allocation: type0 or type 1 */
int P = ra_type0_P(nof_prb); uint32_t P = ra_type0_P(nof_prb);
int alloc_size = (int) ceilf((float) nof_prb / P); uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P);
switch (data->alloc_type) { switch (data->alloc_type) {
case alloc_type0: 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; break;
case alloc_type1: 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; *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); alloc_size - (int) ceilf(log2f(P)) - 1);
break; break;
default: default:
fprintf(stderr, fprintf(stderr,
"Format 1 accepts type0 or type1 resource allocation only\n"); "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 */ /* pack MCS */
uint32_t mcs; bit_pack(data->mcs_idx, &y, 5);
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);
/* harq process number */ /* harq process number */
bit_pack(data->harq_process, &y, 3); 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; *y++ = 0;
// Padding with zeros // Padding with zeros
int n = dci_format1_sizeof(nof_prb); uint32_t n = dci_format1_sizeof(nof_prb);
while (y - msg->data < n) { while (y - msg->data < n) {
*y++ = 0; *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 */ /* pack bits */
char *y = msg->data; char *y = msg->data;
/* Make sure it's a Format1 message */ /* 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"); fprintf(stderr, "Invalid message length for format 1\n");
return -1; return LIBLTE_ERROR;
} }
if (nof_prb > 10) { 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 */ /* Resource allocation: type0 or type 1 */
int P = ra_type0_P(nof_prb); uint32_t P = ra_type0_P(nof_prb);
int alloc_size = (int) ceilf((float) nof_prb / P); uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P);
switch (data->alloc_type) { switch (data->alloc_type) {
case alloc_type0: case alloc_type0:
data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size); 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); alloc_size - (int) ceilf(log2f(P)) - 1);
break; break;
default: default:
fprintf(stderr, fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n");
"Format 1 accepts type0 or type1 resource allocation only\n"); return LIBLTE_ERROR;
return -1;
} }
/* pack MCS according to 7.1.7 of 36.213 */ /* unpack MCS according to 7.1.7 of 36.213 */
uint32_t mcs = bit_unpack(&y, 5); data->mcs_idx = bit_unpack(&y, 5);
data->mcs.mcs_idx = mcs; if (ra_mcs_from_idx_dl(data->mcs_idx, ra_nprb_dl(data, nof_prb), &data->mcs)) {
ra_mcs_from_idx_dl(mcs, &data->mcs); fprintf(stderr, "Error getting MCS\n");
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_dl(data, nof_prb)); return LIBLTE_ERROR;
}
/* harq process number */ /* harq process number */
data->harq_process = bit_unpack(&y, 3); 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 // 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 /* 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 * 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) { bool crc_is_crnti) {
/* pack bits */ /* 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) { if (data->alloc_type != alloc_type2) {
fprintf(stderr, "Format 1A accepts type2 resource allocation only\n"); 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 *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) { if (data->type2_alloc.L_crb > nof_prb) {
fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n", fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n",
data->type2_alloc.L_crb); data->type2_alloc.L_crb);
return -1; return LIBLTE_ERROR;
} }
} else { } else {
int n_vrb_dl; uint32_t n_vrb_dl;
if (crc_is_crnti && nof_prb > 50) { if (crc_is_crnti && nof_prb > 50) {
n_vrb_dl = 16; n_vrb_dl = 16;
} else { } else {
@ -480,7 +479,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
fprintf(stderr, fprintf(stderr,
"L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n",
data->type2_alloc.L_crb, n_vrb_dl); data->type2_alloc.L_crb, n_vrb_dl);
return -1; return LIBLTE_ERROR;
} }
} }
/* pack RIV according to 7.1.6.3 of 36.213 */ /* 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 { } else {
riv = data->type2_alloc.riv; 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) { if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
nb_gap = 1; nb_gap = 1;
*y++ = data->type2_alloc.n_gap; *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); bit_pack(riv, &y, riv_nbits(nof_prb) - nb_gap);
// in format1A, MCS = TBS according to 7.1.7.2 of 36.213 // in format1A, MCS = TBS according to 7.1.7.2 of 36.213
uint32_t mcs; bit_pack(data->mcs_idx, &y, 5);
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->harq_process, &y, 3); 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 // Padding with zeros
int n = dci_format1A_sizeof(nof_prb); uint32_t n = dci_format1A_sizeof(nof_prb);
while (y - msg->data < n) { while (y - msg->data < n) {
*y++ = 0; *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 /* 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) { bool crc_is_crnti) {
/* pack bits */ /* pack bits */
char *y = msg->data; char *y = msg->data;
/* Make sure it's a Format0 message */ /* 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"); fprintf(stderr, "Invalid message length for format 1A\n");
return -1; return LIBLTE_ERROR;
} }
if (*y++ != 1) { if (*y++ != 1) {
fprintf(stderr, fprintf(stderr, "Invalid format differentiation field value. This is Format0\n");
"Invalid format differentiation field value. This is Format0\n"); return LIBLTE_ERROR;
return -1;
} }
data->alloc_type = alloc_type2; 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; data->type2_alloc.n_gap = t2_ng1;
/* unpack RIV according to 7.1.6.3 of 36.213 */ /* 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) { if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
nb_gap = 1; nb_gap = 1;
data->type2_alloc.n_gap = *y++; data->type2_alloc.n_gap = *y++;
} }
int nof_vrb; uint32_t nof_vrb;
if (data->type2_alloc.mode == t2_loc) { if (data->type2_alloc.mode == t2_loc) {
nof_vrb = nof_prb; nof_vrb = nof_prb;
} else { } 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; data->type2_alloc.riv = riv;
// unpack MCS // unpack MCS
data->mcs.mcs_idx = bit_unpack(&y, 5); data->mcs_idx = bit_unpack(&y, 5);
data->harq_process = bit_unpack(&y, 3); 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 y++; // MSB of TPC is reserved
data->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS 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) { if (crc_is_crnti) {
n_prb = ra_nprb_dl(data, nof_prb); n_prb = ra_nprb_dl(data, nof_prb);
} else { } else {
n_prb = data->type2_alloc.n_prb1a == nprb1a_2 ? 2 : 3; 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.tbs = ra_tbs_from_idx(data->mcs_idx, n_prb);
data->mcs.mod = QPSK; data->mcs.mod = LTE_QPSK;
return 0; return LIBLTE_SUCCESS;
} }
/* Format 1C for compact scheduling of PDSCH words /* 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 */ /* pack bits */
char *y = msg->data; 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) { if (data->alloc_type != alloc_type2 || data->type2_alloc.mode != t2_dist) {
fprintf(stderr, fprintf(stderr,
"Format 1C accepts distributed type2 resource allocation only\n"); "Format 1C accepts distributed type2 resource allocation only\n");
return -1; return LIBLTE_ERROR;
} }
if (nof_prb >= 50) { if (nof_prb >= 50) {
*y++ = data->type2_alloc.n_gap; *y++ = data->type2_alloc.n_gap;
} }
int n_step = ra_type2_n_rb_step(nof_prb); uint32_t 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_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) { if (data->type2_alloc.L_crb > ((uint32_t) n_vrb_dl / n_step) * n_step) {
fprintf(stderr, fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n",
"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);
data->type2_alloc.L_crb, ((int) n_vrb_dl / n_step) * n_step); return LIBLTE_ERROR;
return -1;
} }
if (data->type2_alloc.L_crb % n_step) { if (data->type2_alloc.L_crb % n_step) {
fprintf(stderr, "L_crb must be multiple of n_step\n"); fprintf(stderr, "L_crb must be multiple of n_step\n");
return -1; return LIBLTE_ERROR;
} }
if (data->type2_alloc.RB_start % n_step) { if (data->type2_alloc.RB_start % n_step) {
fprintf(stderr, "RB_start must be multiple of n_step\n"); 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; uint32_t L_p = data->type2_alloc.L_crb / n_step;
int RB_p = data->type2_alloc.RB_start / n_step; uint32_t RB_p = data->type2_alloc.RB_start / n_step;
int n_vrb_p = (int) n_vrb_dl / n_step; uint32_t n_vrb_p = (int) n_vrb_dl / n_step;
uint32_t riv; uint32_t riv;
if (data->type2_alloc.L_crb) { 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)); 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 // in format1C, MCS = TBS according to 7.1.7.2 of 36.213
uint32_t mcs; bit_pack(data->mcs_idx, &y, 5);
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);
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) { int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) {
uint16_t L_p, RB_p; uint32_t L_p, RB_p;
/* pack bits */ /* pack bits */
char *y = msg->data; 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"); fprintf(stderr, "Invalid message length for format 1C\n");
return -1; return LIBLTE_ERROR;
} }
data->alloc_type = alloc_type2; data->alloc_type = alloc_type2;
data->type2_alloc.mode = t2_dist; data->type2_alloc.mode = t2_dist;
if (nof_prb >= 50) { if (nof_prb >= 50) {
data->type2_alloc.n_gap = *y++; data->type2_alloc.n_gap = *y++;
} }
int n_step = ra_type2_n_rb_step(nof_prb); uint32_t 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_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)); 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); 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.L_crb = L_p * n_step;
data->type2_alloc.RB_start = RB_p * n_step; data->type2_alloc.RB_start = RB_p * n_step;
data->type2_alloc.riv = riv; data->type2_alloc.riv = riv;
data->mcs.mcs_idx = bit_unpack(&y, 5); data->mcs_idx = bit_unpack(&y, 5);
data->mcs.tbs_idx = data->mcs.mcs_idx; data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs_idx);
data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs.tbs_idx); data->mcs.mod = LTE_QPSK;
data->mcs.mod = 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 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) { switch (format) {
case Format1: case Format1:
return dci_format1_pack(data, msg, nof_prb); 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: default:
fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n", fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n",
dci_format_string(format)); 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) { 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); 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); 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); return dci_format1Cs_unpack(msg, data, nof_prb);
} else { } 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); 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); 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, int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint32_t nof_prb,
unsigned short crnti) { uint16_t msg_rnti, uint16_t crnti)
if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb) {
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]) { && !msg->data[0]) {
type->type = PUSCH_SCHED; type->type = PUSCH_SCHED;
type->format = Format0; type->format = Format0;
return 0; return LIBLTE_SUCCESS;
} else if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) { } else if (msg->nof_bits == dci_format_sizeof(Format1, nof_prb)) {
type->type = PDSCH_SCHED; // only these 2 types supported type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1; type->format = Format1;
return 0; return LIBLTE_SUCCESS;
} else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) { } else if (msg->nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
if (msg->location.rnti == crnti) { if (msg_rnti == crnti) {
type->type = RA_PROC_PDCCH; type->type = RA_PROC_PDCCH;
type->format = Format1A; type->format = Format1A;
} else { } else {
type->type = PDSCH_SCHED; // only these 2 types supported type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1A; type->format = Format1A;
} }
return 0; return LIBLTE_SUCCESS;
} else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) { } else if (msg->nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
if (msg->location.rnti == MRNTI) { if (msg_rnti == MRNTI) {
type->type = MCCH_CHANGE; type->type = MCCH_CHANGE;
type->format = Format1C; type->format = Format1C;
} else { } else {
type->type = PDSCH_SCHED; // only these 2 types supported type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1C; type->format = Format1C;
} }
return 0; return LIBLTE_SUCCESS;
} }
return -1; return LIBLTE_ERROR;
} }

@ -50,31 +50,45 @@ bool pbch_exists(int nframe, int nslot) {
return (!(nframe % 5) && nslot == 1); return (!(nframe % 5) && nslot == 1);
} }
int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, int pbch_cp(cf_t *input, cf_t *output, lte_cell_t cell, bool put) {
bool put) {
int i; int i;
cf_t *ptr; cf_t *ptr;
assert(cell_id >= 0);
if (put) { if (put) {
ptr = input; ptr = input;
output += nof_prb * RE_X_RB / 2 - 36; output += cell.nof_prb * RE_X_RB / 2 - 36;
} else { } else {
ptr = output; ptr = output;
input += nof_prb * RE_X_RB / 2 - 36; input += cell.nof_prb * RE_X_RB / 2 - 36;
} }
/* symbol 0 & 1 */ /* symbol 0 & 1 */
for (i = 0; i < 2; i++) { 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 */ /* symbols 2 & 3 */
if (CP_ISNORM(cp)) { if (CP_ISNORM(cell.cp)) {
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
prb_cp(&input, &output, 6); 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 { } else {
prb_cp(&input, &output, 6); 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) { if (put) {
return input - ptr; 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 * 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 pbch_put(cf_t *pbch, cf_t *slot1_data, lte_cell_t cell) {
int cell_id) { return pbch_cp(pbch, slot1_data, cell, true);
return pbch_cp(pbch, slot1_data, nof_prb, cp, cell_id, 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 * 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 pbch_get(cf_t *slot1_data, cf_t *pbch, lte_cell_t cell) {
int cell_id) { return pbch_cp(slot1_data, pbch, cell, false);
return pbch_cp(slot1_data, pbch, nof_prb, cp, cell_id, false);
} }
/** Initializes the PBCH transmitter and receiver */ /** Initializes the PBCH transmitter and receiver.
int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) { * At the receiver, the field nof_ports in the cell structure indicates the
int ret = -1; * maximum number of BS transmitter ports to look for.
if (cell_id < 0) { */
return -1; int pbch_init(pbch_t *q, lte_cell_t cell) {
} int ret = LIBLTE_ERROR_INVALID_INPUTS;
bzero(q, sizeof(pbch_t));
q->cell_id = cell_id;
q->cp = cp;
q->nof_prb = nof_prb;
if (modem_table_std(&q->mod, LTE_QPSK, true)) { if (q != NULL &&
goto clean; lte_cell_isvalid(&cell))
} {
demod_soft_init(&q->demod); ret = LIBLTE_ERROR;
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;
}
int poly[3] = { 0x6D, 0x4F, 0x57 }; bzero(q, sizeof(pbch_t));
if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) { q->cell = cell;
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->cp)) ? PBCH_RE_CPNORM : PBCH_RE_CPEXT; if (modem_table_lte(&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->cell.cp, q->cell.id)) {
goto clean;
}
q->pbch_d = malloc(sizeof(cf_t) * q->nof_symbols); uint32_t poly[3] = { 0x6D, 0x4F, 0x57 };
if (!q->pbch_d) { if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) {
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]) {
goto clean; goto clean;
} }
q->pbch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); if (crc_init(&q->crc, LTE_CRC16, 16)) {
if (!q->pbch_x[i]) {
goto clean; goto clean;
} }
q->pbch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); q->encoder.K = 7;
if (!q->pbch_symbols[i]) { 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; 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;
} }
q->pbch_llr = malloc(sizeof(float) * q->nof_symbols * 4 * 2); clean:
if (!q->pbch_llr) { if (ret == LIBLTE_ERROR) {
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) {
pbch_free(q); pbch_free(q);
} }
return ret; return ret;
@ -198,7 +215,7 @@ void pbch_free(pbch_t *q) {
free(q->pbch_d); free(q->pbch_d);
} }
int i; int i;
for (i = 0; i < MAX_PORTS_CTRL; i++) { for (i = 0; i < q->cell.nof_ports; i++) {
if (q->ce[i]) { if (q->ce[i]) {
free(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 * 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]; char data[40];
memcpy(data, bits, 40 * sizeof(char)); memcpy(data, bits, 40 * sizeof(char));
crc_set_mask(data, nof_ports); crc_set_mask(data, nof_ports);
return crc_checksum(&q->crc, data, 40); 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 pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, uint32_t src, uint32_t dst, uint32_t n,
int nof_bits, int nof_ports) { uint32_t nof_bits, uint32_t nof_ports) {
int j; int j;
memcpy(&q->temp[dst * nof_bits], &q->pbch_llr[src * nof_bits], 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 /* Decodes the PBCH channel
* *
* The PBCH spans in 40 ms. This function is called every 10 ms. It tries to decode the MIB * 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. * to help the decoding process.
* *
* Returns 1 if successfully decoded MIB, 0 if not and -1 on error * 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], int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mib) {
float ebno, pbch_mib_t *mib) { uint32_t src, dst, nb;
int src, dst, res, nb; uint32_t nant_[3] = { 1, 2, 4 };
int nant_[3] = { 1, 2, 4 }; uint32_t na, nant;
int na, nant; cf_t *slot1_symbols;
/* Set pointers for layermapping & precoding */
int i; int i;
int nof_bits = 2 * q->nof_symbols; int nof_bits;
cf_t *x[MAX_LAYERS]; 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;i<q->cell.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 */ /* Set pointers for layermapping & precoding */
for (i = 0; i < MAX_PORTS_CTRL; i++) { nof_bits = 2 * q->nof_symbols;
x[i] = q->pbch_x[i];
}
memset(&x[MAX_PORTS_CTRL], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS_CTRL));
/* 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 */ /* number of layers equals number of ports */
for (i = 0; i < MAX_PORTS_CTRL; i++) { for (i = 0; i < MAX_PORTS; i++) {
if (q->nof_symbols x[i] = q->pbch_x[i];
!= pbch_get(ce[i], q->ce[i], q->nof_prb, q->cp, q->cell_id)) { }
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"); fprintf(stderr, "There was an error getting the PBCH symbols\n");
return -1; return LIBLTE_ERROR;
} }
}
q->frame_idx++; /* extract channel estimates */
res = 0; 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;
}
}
/* Try decoding for 1 to 4 antennas */ q->frame_idx++;
for (na = 0; na < 3 && !res; na++) { ret = 0;
nant = nant_[na];
INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx); /* Try decoding for 1 to cell.nof_ports antennas */
for (na = 0; na < q->cell.nof_ports && !ret; na++) {
nant = nant_[na];
/* in conctrol channels, only diversity is supported */ INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx);
if (nant == 1) {
/* no need for layer demapping */ /* in conctrol channels, only diversity is supported */
predecoding_single_zf(q->pbch_symbols[0], q->ce[0], q->pbch_d, if (nant == 1) {
q->nof_symbols); /* no need for layer demapping */
} else { predecoding_single_zf(q->pbch_symbols[0], q->ce[0], q->pbch_d,
predecoding_diversity_zf(q->pbch_symbols[0], q->ce, x, nant, q->nof_symbols);
q->nof_symbols); } else {
layerdemap_diversity(x, q->pbch_d, nant, q->nof_symbols / nant); 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 */ /* demodulate symbols */
demod_soft_sigma_set(&q->demod, ebno); demod_soft_sigma_set(&q->demod, 1.0);
demod_soft_demodulate(&q->demod, q->pbch_d, demod_soft_demodulate(&q->demod, q->pbch_d,
&q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols); &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 /* 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. * 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234.
* We know they are ordered. * We know they are ordered.
* *
* FIXME: There are unnecessary checks because 2,3,4 have already been processed in the previous * FIXME: There are unnecessary checks because 2,3,4 have already been processed in the previous
* calls. * calls.
*/ */
for (nb = 0; nb < q->frame_idx && !res; nb++) { for (nb = 0; nb < q->frame_idx && !ret; nb++) {
for (dst = 0; (dst < 4 - nb) && !res; dst++) { for (dst = 0; (dst < 4 - nb) && !ret; dst++) {
for (src = 0; src < q->frame_idx - nb && !res; src++) { for (src = 0; src < q->frame_idx - nb && !ret; src++) {
DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n", DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n",
nb + 1, src, dst); nb + 1, src, dst);
res = pbch_decode_frame(q, mib, src, dst, nb + 1, nof_bits, nant); 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 not found, make room for the next packet of radio frame symbols */
if (q->frame_idx == 4) { if (q->frame_idx == 4) {
memmove(q->pbch_llr, &q->pbch_llr[nof_bits], nof_bits * 3 * sizeof(float)); memmove(q->pbch_llr, &q->pbch_llr[nof_bits], nof_bits * 3 * sizeof(float));
q->frame_idx = 3; q->frame_idx = 3;
}
} }
return res; return ret;
} }
/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission /** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission
*/ */
void pbch_encode(pbch_t *q, pbch_mib_t *mib, int pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *sf_symbols[MAX_PORTS]) {
cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports) {
int i; int i;
int nof_bits = 2 * q->nof_symbols; int nof_bits;
cf_t *slot1_symbols[MAX_PORTS];
assert(nof_ports <= MAX_PORTS_CTRL);
/* Set pointers for layermapping & precoding */
cf_t *x[MAX_LAYERS]; cf_t *x[MAX_LAYERS];
if (q != NULL &&
mib != NULL)
{
for (i=0;i<q->cell.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 */ /* number of layers equals number of ports */
for (i = 0; i < nof_ports; i++) { for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->pbch_x[i]; x[i] = q->pbch_x[i];
} }
memset(&x[nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - nof_ports)); 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) { /* encode & modulate */
/* pack MIB */ crc_attach(&q->crc, q->data, 24);
pbch_mib_pack(mib, q->data); crc_set_mask(q->data, q->cell.nof_ports);
/* encode & modulate */ convcoder_encode(&q->encoder, q->data, q->data_enc, 40);
crc_attach(&q->crc, q->data, 24);
crc_set_mask(q->data, nof_ports);
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], /* layer mapping & precoding */
q->frame_idx * nof_bits, nof_bits); if (q->cell.nof_ports > 1) {
mod_modulate(&q->mod, &q->pbch_rm_b[q->frame_idx * nof_bits], q->pbch_d, layermap_diversity(q->pbch_d, x, q->cell.nof_ports, q->nof_symbols);
nof_bits); 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 */ /* mapping to resource elements */
if (nof_ports > 1) { for (i = 0; i < q->cell.nof_ports; i++) {
layermap_diversity(q->pbch_d, x, nof_ports, q->nof_symbols); pbch_put(q->pbch_symbols[i], slot1_symbols[i], q->cell);
precoding_diversity(x, q->pbch_symbols, nof_ports, }
q->nof_symbols / nof_ports); q->frame_idx++;
if (q->frame_idx == 4) {
q->frame_idx = 0;
}
return LIBLTE_SUCCESS;
} else { } else {
memcpy(q->pbch_symbols[0], q->pbch_d, q->nof_symbols * sizeof(cf_t)); return LIBLTE_ERROR_INVALID_INPUTS;
}
/* 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;
} }
} }

@ -54,37 +54,42 @@ bool pcfich_exists(int nframe, int nslot) {
return true; return true;
} }
/** Initializes the pcfich channel receiver */ /** Initializes the pcfich channel receiver.
int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, * On error, returns -1 and frees the structrure
int nof_ports, lte_cp_t cp) { */
int ret = -1; int pcfich_init(pcfich_t *q, regs_t *regs, lte_cell_t cell) {
if (cell_id < 0) { int ret = LIBLTE_ERROR_INVALID_INPUTS;
return -1;
} if (q != NULL &&
bzero(q, sizeof(pcfich_t)); regs != NULL &&
q->cell_id = cell_id; lte_cell_isvalid(&cell))
q->cp = cp; {
q->regs = regs; ret = LIBLTE_ERROR;
q->nof_prb = nof_prb;
q->nof_ports = nof_ports; bzero(q, sizeof(pcfich_t));
q->cell = cell;
if (modem_table_std(&q->mod, LTE_QPSK, false)) { q->regs = regs;
goto clean;
} if (modem_table_lte(&q->mod, LTE_QPSK, false)) {
goto clean;
}
demod_hard_init(&q->demod); demod_hard_init(&q->demod);
demod_hard_table_set(&q->demod, LTE_QPSK); demod_hard_table_set(&q->demod, LTE_QPSK);
for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) { for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) {
if (sequence_pcfich(&q->seq_pcfich[nsf], 2 * nsf, q->cell_id)) { if (sequence_pcfich(&q->seq_pcfich[nsf], 2 * nsf, q->cell.id)) {
goto clean; goto clean;
}
} }
}
q->nof_symbols = PCFICH_RE; q->nof_symbols = PCFICH_RE;
ret = 0; ret = LIBLTE_SUCCESS;
clean: if (ret == -1) { }
clean:
if (ret == LIBLTE_ERROR) {
pcfich_free(q); pcfich_free(q);
} }
return ret; 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. /** 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. * 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 i, j;
int distance, index = -1; int distance, index = -1;
int min = 32; int min = 32;
@ -120,7 +125,6 @@ int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], int *cfi) {
*cfi = index + 1; *cfi = index + 1;
} }
return min; return min;
} }
/** Encodes the CFI producing a vector of 32 bits. /** 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]) { int pcfich_cfi_encode(int cfi, char bits[PCFICH_CFI_LEN]) {
if (cfi < 1 || cfi > 3) { if (cfi < 1 || cfi > 3) {
fprintf(stderr, "Invalid CFI %d\n", cfi); return LIBLTE_ERROR_INVALID_INPUTS;
return -1; } 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. /* 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 * 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 pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS],
int nsubframe, int *cfi, int *distance) { uint32_t nsubframe, uint32_t *cfi, uint32_t *distance) {
int dist; int dist;
/* Set pointers for layermapping & precoding */ /* 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 *x[MAX_LAYERS];
cf_t *ce_precoding[MAX_PORTS]; cf_t *ce_precoding[MAX_PORTS];
if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { if (q != NULL &&
fprintf(stderr, "Invalid nslot %d\n", nsubframe); slot_symbols != NULL &&
return -1; nsubframe < NSUBFRAMES_X_FRAME)
} {
/* number of layers equals number of ports */ /* 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->pcfich_x[i]; x[i] = q->pcfich_x[i];
} }
for (i = 0; i < MAX_PORTS; i++) { for (i = 0; i < MAX_PORTS; i++) {
ce_precoding[i] = q->ce[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 */ /* extract symbols */
for (i = 0; i < q->nof_ports; i++) { if (q->nof_symbols
if (q->nof_symbols != regs_pcfich_get(q->regs, ce[i], q->ce[i])) { != regs_pcfich_get(q->regs, slot_symbols, q->pcfich_symbols[0])) {
fprintf(stderr, "There was an error getting the PCFICH symbols\n"); fprintf(stderr, "There was an error getting the PCFICH symbols\n");
return -1; return LIBLTE_ERROR;
} }
}
/* in control channels, only diversity is supported */ /* extract channel estimates */
if (q->nof_ports == 1) { for (i = 0; i < q->cell.nof_ports; i++) {
/* no need for layer demapping */ if (q->nof_symbols != regs_pcfich_get(q->regs, ce[i], q->ce[i])) {
predecoding_single_zf(q->pcfich_symbols[0], q->ce[0], q->pcfich_d, fprintf(stderr, "There was an error getting the PCFICH symbols\n");
q->nof_symbols); return LIBLTE_ERROR;
} 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 */ /* in control channels, only diversity is supported */
demod_hard_demodulate(&q->demod, q->pcfich_d, q->data, q->nof_symbols); 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);
}
/* Scramble with the sequence for slot nslot */ /* demodulate symbols */
scrambling_b(&q->seq_pcfich[nsubframe], q->data); demod_hard_demodulate(&q->demod, q->pcfich_d, q->data, q->nof_symbols);
/* decode CFI */ /* Scramble with the sequence for slot nslot */
dist = pcfich_cfi_decode(q->data, cfi); scrambling_b(&q->seq_pcfich[nsubframe], q->data);
if (distance) {
*distance = dist; /* decode CFI */
} dist = pcfich_cfi_decode(q->data, cfi);
if (dist < PCFICH_MAX_DISTANCE) { if (distance) {
return 1; *distance = dist;
}
if (dist < PCFICH_MAX_DISTANCE) {
return 1;
} else {
return 0;
}
} else { } else {
return 0; return LIBLTE_ERROR_INVALID_INPUTS;
} }
} }
/** Encodes CFI and maps symbols to the slot /** Encodes CFI and maps symbols to the slot
*/ */
int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], int pcfich_encode(pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[MAX_PORTS],
int nsubframe) { uint32_t subframe) {
int i; int i;
if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { if (q != NULL &&
fprintf(stderr, "Invalid nslot %d\n", nsubframe); cfi < 3 &&
return -1; slot_symbols != NULL &&
} subframe < NSUBFRAMES_X_FRAME)
{
/* Set pointers for layermapping & precoding */ /* Set pointers for layermapping & precoding */
cf_t *x[MAX_LAYERS]; cf_t *x[MAX_LAYERS];
cf_t *symbols_precoding[MAX_PORTS]; cf_t *symbols_precoding[MAX_PORTS];
/* number of layers equals number of ports */ /* number of layers equals number of ports */
for (i = 0; i < q->nof_ports; i++) { for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->pcfich_x[i]; x[i] = q->pcfich_x[i];
} }
for (i = 0; i < MAX_PORTS; i++) { for (i = 0; i < MAX_PORTS; i++) {
symbols_precoding[i] = q->pcfich_symbols[i]; symbols_precoding[i] = q->pcfich_symbols[i];
} }
/* pack MIB */ /* pack CFI */
pcfich_cfi_encode(cfi, q->data); pcfich_cfi_encode(cfi, q->data);
/* scramble for slot sequence nslot */ /* scramble for slot sequence nslot */
scrambling_b(&q->seq_pcfich[nsubframe], q->data); scrambling_b(&q->seq_pcfich[subframe], q->data);
mod_modulate(&q->mod, q->data, q->pcfich_d, PCFICH_CFI_LEN); mod_modulate(&q->mod, q->data, q->pcfich_d, PCFICH_CFI_LEN);
/* layer mapping & precoding */ /* layer mapping & precoding */
if (q->nof_ports > 1) { if (q->cell.nof_ports > 1) {
layermap_diversity(q->pcfich_d, x, q->nof_ports, q->nof_symbols); layermap_diversity(q->pcfich_d, x, q->cell.nof_ports, q->nof_symbols);
precoding_diversity(x, symbols_precoding, q->nof_ports, precoding_diversity(x, symbols_precoding, q->cell.nof_ports,
q->nof_symbols / q->nof_ports); q->nof_symbols / q->cell.nof_ports);
} else { } else {
memcpy(q->pcfich_symbols[0], q->pcfich_d, q->nof_symbols * sizeof(cf_t)); memcpy(q->pcfich_symbols[0], q->pcfich_d, q->nof_symbols * sizeof(cf_t));
} }
/* mapping to resource elements */ /* mapping to resource elements */
for (i = 0; i < q->nof_ports; i++) { for (i = 0; i < q->cell.nof_ports; i++) {
if (regs_pcfich_put(q->regs, q->pcfich_symbols[i], slot_symbols[i]) < 0) { if (regs_pcfich_put(q->regs, q->pcfich_symbols[i], slot_symbols[i]) < 0) {
fprintf(stderr, "Error putting PCHICH resource elements\n"); fprintf(stderr, "Error putting PCHICH resource elements\n");
return -1; return LIBLTE_ERROR;
}
} }
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
} }
return 0;
} }

@ -31,7 +31,6 @@
#include <strings.h> #include <strings.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <assert.h>
#include <math.h> #include <math.h>
#include "liblte/phy/phch/dci.h" #include "liblte/phy/phch/dci.h"
@ -42,257 +41,115 @@
#include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/vector.h"
#include "liblte/phy/utils/debug.h" #include "liblte/phy/utils/debug.h"
#define PDCCH_NOF_FORMATS 4 #define PDCCH_NOF_FORMATS 4
#define PDCCH_FORMAT_NOF_CCE(i) (1<<i) #define PDCCH_FORMAT_NOF_CCE(i) (1<<i)
#define PDCCH_FORMAT_NOF_REGS(i) ((1<<i)*9) #define PDCCH_FORMAT_NOF_REGS(i) ((1<<i)*9)
#define PDCCH_FORMAT_NOF_BITS(i) ((1<<i)*72) #define PDCCH_FORMAT_NOF_BITS(i) ((1<<i)*72)
#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
#define MIN(a,b) ((a>b)?b:a) #define MIN(a,b) ((a>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
* 36.213 9.1 const dci_format_t common_formats[NOF_COMMON_FORMATS] = { Format1A, Format1C };
*/
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) { #define NOF_UE_FORMATS 2
int k, i; const dci_format_t ue_formats[NOF_UE_FORMATS] = { Format0, Format1 }; // 1A has the same payload as 0
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 static void set_cfi(pdcch_t *q, uint32_t cfi) {
* user-specific search space. Currently supported transmission Mode 1: if (cfi > 0 && cfi < 4) {
* DCI Format 1A and 1 + PUSCH scheduling format 0 q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9;
*/ q->nof_cce = q->nof_regs / 9;
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 */ /** Initializes the PDCCH transmitter and receiver */
int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) {
int cell_id, lte_cp_t cp) { int ret = LIBLTE_ERROR_INVALID_INPUTS;
int ret = -1; uint32_t i;
int i;
if (cell_id < 0) { if (q != NULL &&
return -1; regs != NULL &&
} lte_cell_isvalid(&cell))
if (nof_ports > MAX_PORTS_CTRL) { {
fprintf(stderr, "Invalid number of ports %d\n", nof_ports); ret = LIBLTE_ERROR;
return -1; bzero(q, sizeof(pdcch_t));
} q->cell = cell;
bzero(q, sizeof(pdcch_t)); q->regs = regs;
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;
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;
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);
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); /* Allocate memory for the largest aggregation level L=3 */
demod_soft_table_set(&q->demod, &q->mod); q->max_bits = PDCCH_FORMAT_NOF_BITS(3);
demod_soft_alg_set(&q->demod, APPROX);
for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { INFO("Init PDCCH: %d bits, %d symbols, %d ports\n", q->max_bits, q->max_bits/2, q->cell.nof_ports);
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;
}
if (crc_init(&q->crc, LTE_CRC16, 16)) {
goto clean; 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); demod_soft_init(&q->demod);
if (!q->pdcch_e) { demod_soft_table_set(&q->demod, &q->mod);
goto clean; demod_soft_alg_set(&q->demod, APPROX);
}
q->pdcch_llr = malloc(sizeof(float) * q->nof_bits); for (i = 0; i < NSUBFRAMES_X_FRAME; i++) {
if (!q->pdcch_llr) { // we need to pregenerate the sequence for the maximum number of bits, which is 8 times
goto clean; // 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;
}
}
q->pdcch_d = malloc(sizeof(cf_t) * q->nof_symbols); uint32_t poly[3] = { 0x6D, 0x4F, 0x57 };
if (!q->pdcch_d) { if (viterbi_init(&q->decoder, viterbi_37, poly, DCI_MAX_BITS + 16, true)) {
goto clean; goto clean;
} }
for (i = 0; i < MAX_PORTS_CTRL; i++) { q->pdcch_e = malloc(sizeof(char) * q->max_bits);
q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); if (!q->pdcch_e) {
if (!q->ce[i]) {
goto clean; goto clean;
} }
q->pdcch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->pdcch_x[i]) { q->pdcch_llr = malloc(sizeof(float) * q->max_bits);
if (!q->pdcch_llr) {
goto clean; goto clean;
} }
q->pdcch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->pdcch_symbols[i]) { q->pdcch_d = malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->pdcch_d) {
goto clean; 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:
clean: if (ret == -1) { if (ret == LIBLTE_ERROR) {
pdcch_free(q); pdcch_free(q);
} }
return ret; return ret;
} }
void pdcch_free(pdcch_t *q) { 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) { if (q->pdcch_e) {
free(q->pdcch_e); free(q->pdcch_e);
} }
@ -302,7 +159,7 @@ void pdcch_free(pdcch_t *q) {
if (q->pdcch_d) { if (q->pdcch_d) {
free(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]) { if (q->ce[i]) {
free(q->ce[i]); free(q->ce[i]);
} }
@ -322,189 +179,257 @@ void pdcch_free(pdcch_t *q) {
viterbi_free(&q->decoder); viterbi_free(&q->decoder);
} }
/** 36.212 5.3.3.2 to 5.3.3.4 /** 36.213 v9.1.1
* * Computes up to max_candidates UE-specific candidates for DCI messages and saves them
* Returns XOR between parity and remainder bits * in the structure pointed by c.
* * Returns the number of candidates saved in the array c.
* TODO: UE transmit antenna selection CRC mask
*/ */
unsigned short dci_decode(pdcch_t *q, float *e, char *data, int E, int nof_bits) { 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) {
float tmp[3 * (DCI_MAX_BITS + 16)];
unsigned short p_bits, crc_res; int l; // this must be int because of the for(;;--) loop
char *x; uint32_t i, k, L, m;
uint32_t Yk, ncce;
assert(nof_bits < DCI_MAX_BITS); const int S[4] = { 6, 12, 8, 16 };
/* unrate matching */ set_cfi(q, cfi);
rm_conv_rx(e, E, tmp, 3 * (nof_bits + 16));
DEBUG("Viterbi input: ", 0); // Compute Yk for this subframe
if (VERBOSE_ISDEBUG()) { Yk = rnti;
vec_fprint_f(stdout, tmp, 3 * (nof_bits + 16)); for (m = 0; m < nsubframe; m++) {
Yk = (39827 * Yk) % 65537;
} }
/* viterbi decoder */ k = 0;
viterbi_decode_f(&q->decoder, tmp, data, nof_bits + 16); // All aggregation levels from 8 to 1
for (l = 3; l >= 0; l--) {
if (VERBOSE_ISDEBUG()) { L = (1 << l);
bit_fprint(stdout, data, nof_bits + 16); // 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++;
}
}
} }
x = &data[nof_bits]; INFO("Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", k, rnti);
p_bits = (unsigned short) bit_unpack(&x, 16);
crc_res = ((unsigned short) crc_checksum(&q->crc, data, nof_bits) & 0xffff); return k;
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;
}
return 0;
}
int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
float *llr, int nsubframe, float ebno) {
/* Set pointers for layermapping & precoding */ /**
int i; * 36.213 9.1.1
cf_t *x[MAX_LAYERS]; * 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;
if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { set_cfi(q, cfi);
fprintf(stderr, "Invalid subframe %d\n", nsubframe);
return -1;
}
if (ebno == 0.0) { k = 0;
fprintf(stderr, "EbNo is Zero\n"); for (l = 3; l > 1; l--) {
return -1; 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;
}
/* 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(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->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->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); /** 36.212 5.3.3.2 to 5.3.3.4
if (VERBOSE_ISDEBUG()) { *
vec_fprint_f(stdout, q->pdcch_llr, q->nof_bits); * Returns XOR between parity and remainder bits
} *
* TODO: UE transmit antenna selection CRC mask
*/
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)];
uint16_t p_bits, crc_res;
char *x;
/* descramble */ if (q != NULL &&
scrambling_f_offset(&q->seq_pdcch[nsubframe], llr, 0, q->nof_bits); data != NULL &&
E <= q->max_bits &&
nof_bits <= DCI_MAX_BITS)
{
return 0; /* unrate matching */
} rm_conv_rx(e, E, tmp, 3 * (nof_bits + 16));
int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) { DEBUG("Viterbi input: ", 0);
int k, i; if (VERBOSE_ISDEBUG()) {
vec_fprint_f(stdout, tmp, 3 * (nof_bits + 16));
}
if (q->current_search_mode == SEARCH_UE) { /* viterbi decoder */
k = subframe; viterbi_decode_f(&q->decoder, tmp, data, nof_bits + 16);
} else {
k = 0;
}
for (i = 0; if (VERBOSE_ISDEBUG()) {
i < q->search_mode[q->current_search_mode].nof_candidates bit_fprint(stdout, data, nof_bits + 16);
&& 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++;
} }
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;
} }
return dci->nof_dcis;
} }
int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci) { /** Tries to decode a DCI message from the LLRs stored in the pdcch_t structure by the function
pdcch_set_search_si(q); * pdcch_extract_llr(). This function can be called multiple times.
return pdcch_decode_current_mode(q, llr, dci, 0); * The decoded message is stored in msg and the CRC remainder in crc_rem pointer
} *
int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci) { */
pdcch_set_search_ra(q); int pdcch_decode_msg(pdcch_t *q, dci_msg_t *msg, dci_format_t format, uint16_t *crc_rem)
return pdcch_decode_current_mode(q, llr, dci, 0); {
} int ret = LIBLTE_ERROR_INVALID_INPUTS;
int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe) { if (q != NULL &&
pdcch_set_search_ue(q); msg != NULL &&
return pdcch_decode_current_mode(q, llr, dci, nsubframe); 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 ret;
} }
/* Decodes PDCCH channels /** 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().
* dci->nof_dcis is the size of the dci->msg buffer (ie max number of messages) * 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
* Returns number of messages stored in dci
*/ */
int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS],
dci_t *dci, int nsubframe, float ebno) { dci_location_t location, uint32_t nsubframe, uint32_t cfi) {
if (pdcch_extract_llr(q, slot_symbols, ce, q->pdcch_llr, nsubframe, ebno)) { int ret = LIBLTE_ERROR_INVALID_INPUTS;
return -1;
} /* Set pointers for layermapping & precoding */
uint32_t i, nof_symbols;
cf_t *x[MAX_LAYERS];
if (q->current_search_mode != SEARCH_NONE) { if (q != NULL &&
return pdcch_decode_current_mode(q, q->pdcch_llr, dci, nsubframe); 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);
/* 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));
/* 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 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;
}
}
/* 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);
}
return 0; /* 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);
}
}
return ret;
} }
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 mask[16];
char *r = mask; 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 /** 36.212 5.3.3.2 to 5.3.3.4
* TODO: UE transmit antenna selection CRC mask * TODO: UE transmit antenna selection CRC mask
*/ */
void dci_encode(pdcch_t *q, char *data, char *e, int nof_bits, int E, static int dci_encode(pdcch_t *q, char *data, char *e, uint32_t nof_bits, uint32_t E,
unsigned short rnti) { uint16_t rnti) {
convcoder_t encoder; convcoder_t encoder;
char tmp[3 * (DCI_MAX_BITS + 16)]; char tmp[3 * (DCI_MAX_BITS + 16)];
if (q != NULL &&
data != NULL &&
e != NULL &&
nof_bits < DCI_MAX_BITS &&
E < q->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));
crc_attach(&q->crc, data, nof_bits);
crc_set_mask_rnti(&data[nof_bits], rnti);
convcoder_encode(&encoder, data, tmp, nof_bits + 16);
DEBUG("CConv output: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16));
}
assert(nof_bits < DCI_MAX_BITS); rm_conv_tx(tmp, 3 * (nof_bits + 16), e, E);
int poly[3] = { 0x6D, 0x4F, 0x57 }; return LIBLTE_SUCCESS;
encoder.K = 7; } else {
encoder.R = 3; return LIBLTE_ERROR_INVALID_INPUTS;
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);
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 /** 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_t *dci, cf_t *slot_symbols[MAX_PORTS_CTRL], int pdcch_encode(pdcch_t *q, dci_msg_t *msg, dci_location_t location, uint16_t rnti,
int nsubframe) { cf_t *sf_symbols[MAX_PORTS], uint32_t nsubframe, uint32_t cfi) {
int i;
/* Set pointers for layermapping & precoding */
cf_t *x[MAX_LAYERS];
if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { int ret = LIBLTE_ERROR_INVALID_INPUTS;
fprintf(stderr, "Invalid subframe %d\n", nsubframe); uint32_t i;
return -1; 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));
/* number of layers equals number of ports */ scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 72 * location.ncce, q->e_bits);
for (i = 0; i < q->nof_ports; i++) {
x[i] = q->pdcch_x[i]; DEBUG("Scrambling output: ", 0);
} if (VERBOSE_ISDEBUG()) {
memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports)); vec_fprint_b(stdout, q->pdcch_e, q->e_bits);
}
/* should add <NIL> elements? Or maybe random bits to facilitate power estimation */
bzero(q->pdcch_e, q->nof_bits); mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->e_bits);
/* Encode DCIs */ /* layer mapping & precoding */
for (i = 0; i < dci->nof_dcis; i++) { if (q->cell.nof_ports > 1) {
/* do some sanity checks */ layermap_diversity(q->pdcch_d, x, q->cell.nof_ports, nof_symbols);
if (dci->msg[i].location.ncce + PDCCH_FORMAT_NOF_CCE(dci->msg[i].location.L) precoding_diversity(x, q->pdcch_symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
> q->nof_cce || dci->msg[i].location.L > 3 } else {
|| dci->msg[i].location.nof_bits > DCI_MAX_BITS) { memcpy(q->pdcch_symbols[0], q->pdcch_d, nof_symbols * sizeof(cf_t));
fprintf(stderr, "Illegal DCI message %d\n", i); }
return -1;
/* 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);
} }
INFO("Encoding DCI %d: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", i, }
dci->msg[i].location.nof_bits, return ret;
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);
} else {
memcpy(q->pdcch_symbols[0], q->pdcch_d, q->nof_symbols * sizeof(cf_t));
}
/* 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;
} }

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save