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")
INCLUDE(libLTEPackage) #setup cpack
INCLUDE(libLTEPackage) #setup cpack
include(CTest)
set( CTEST_MEMORYCHECK_COMMAND valgrind )
@ -78,6 +78,9 @@ ENDIF(CMAKE_COMPILER_IS_GNUCXX)
IF(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE")
# IF(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wno-error=implicit-function-declaration -Wno-error=unused-but-set-variable")
# ENDIF(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
IF(NOT WIN32)
ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
ENDIF(NOT WIN32)

@ -5,7 +5,7 @@ FIND_PATH(
VOLK_INCLUDE_DIRS
NAMES volk.h
HINTS $ENV{VOLK_DIR}/include/volk
${CMAKE_INSTALL_PREFIX}/include/volk
${CMAKE_INSTALL_PREFIX}/include/volk
${PC_VOLK_INCLUDE_DIR}
PATHS /usr/local/include/volk
/usr/include/volk
@ -15,9 +15,9 @@ FIND_LIBRARY(
VOLK_LIBRARIES
NAMES volk
HINTS $ENV{VOLK_DIR}/lib
${CMAKE_INSTALL_PREFIX}/lib
${CMAKE_INSTALL_PREFIX}/lib64
${PC_VOLK_LIBDIR}
${CMAKE_INSTALL_PREFIX}/lib
${CMAKE_INSTALL_PREFIX}/lib64
${PC_VOLK_LIBDIR}
PATHS /usr/local/lib
/usr/local/lib64
/usr/lib
@ -25,35 +25,79 @@ FIND_LIBRARY(
)
# Some functions are not defined in old volk versions
SET(CMAKE_REQUIRED_LIBRARIES volk m)
SET(CMAKE_REQUIRED_LIBRARIES ${VOLK_LIBRARIES} m)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_index_max_16u HAVE_VOLK_MAX_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_accumulator_s32f HAVE_VOLK_ACC_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32fc_multiply_32fc HAVE_VOLK_MULT_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_conjugate_32fc HAVE_VOLK_CONJ_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_32fc HAVE_VOLK_MULT2_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_conjugate_32fc HAVE_VOLK_MULT2_CONJ_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_multiply_32fc HAVE_VOLK_MULT_REAL_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_multiply_32f HAVE_VOLK_MULT_FLOAT_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_32f HAVE_VOLK_MAG_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_divide_32f HAVE_VOLK_DIVIDE_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_dot_prod_32fc HAVE_VOLK_DOTPROD_FC_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_conjugate_dot_prod_32fc HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_dot_prod_32f HAVE_VOLK_DOTPROD_F_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32f_atan2_32f HAVE_VOLK_ATAN_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_convert_16i HAVE_VOLK_CONVERT_FI_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_32f_x2 HAVE_VOLK_DEINTERLEAVE_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION)
SET(VOLK_DEFINITIONS "HAVE_VOLK")
IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_SUB_FLOAT_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SUB_FLOAT_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MULT2_CONJ_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_CONJ_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_CONVERT_FI_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_FI_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MAX_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION")
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_ACC_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ACC_FUNCTION")
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ACC_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MULT_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FUNCTION")
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_CONJ_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONJ_FUNCTION")
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONJ_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MULT2_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_FUNCTION")
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MULT_FLOAT_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FLOAT_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MULT_REAL_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_REAL_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MAG_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_FUNCTION")
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_DIVIDE_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DIVIDE_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_DOTPROD_FC_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_FC_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_DOTPROD_F_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_F_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_ATAN_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ATAN_FUNCTION")
ENDIF()
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS)
MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_DEFINITIONS)

@ -31,26 +31,63 @@
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include "liblte/config.h"
#include "liblte/cuhd/cuhd_utils.h"
LIBLTE_API int cuhd_open(char *args, void **handler);
LIBLTE_API int cuhd_open(char *args,
void **handler);
LIBLTE_API int cuhd_close(void *h);
LIBLTE_API int cuhd_start_rx_stream(void *h);
LIBLTE_API int cuhd_start_rx_stream_nsamples(void *h, int nsamples);
LIBLTE_API int cuhd_start_rx_stream_nsamples(void *h,
uint32_t nsamples);
LIBLTE_API int cuhd_stop_rx_stream(void *h);
LIBLTE_API bool cuhd_rx_wait_lo_locked(void *h);
LIBLTE_API double cuhd_set_rx_srate(void *h, double freq);
LIBLTE_API double cuhd_set_rx_gain(void *h, double gain);
LIBLTE_API double cuhd_set_rx_freq(void *h, double freq);
LIBLTE_API int cuhd_recv(void *h, void *data, int nsamples, int blocking);
LIBLTE_API double cuhd_set_tx_srate(void *h, double freq);
LIBLTE_API double cuhd_set_tx_gain(void *h, double gain);
LIBLTE_API double cuhd_set_tx_freq(void *h, double freq);
LIBLTE_API int cuhd_send(void *h, void *data, int nsamples, int blocking);
LIBLTE_API double cuhd_set_rx_srate(void *h,
double freq);
LIBLTE_API double cuhd_set_rx_gain(void *h,
double gain);
LIBLTE_API double cuhd_set_rx_freq(void *h,
double freq);
LIBLTE_API double cuhd_set_rx_freq_offset(void *h,
double freq,
double off);
LIBLTE_API int cuhd_recv(void *h,
void *data,
uint32_t nsamples,
bool blocking);
LIBLTE_API int cuhd_recv_timed(void *h,
void *data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs);
LIBLTE_API double cuhd_set_tx_srate(void *h,
double freq);
LIBLTE_API double cuhd_set_tx_gain(void *h,
double gain);
LIBLTE_API double cuhd_set_tx_freq(void *h,
double freq);
LIBLTE_API int cuhd_send(void *h,
void *data,
uint32_t nsamples,
bool blocking);
#ifdef __cplusplus

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

@ -35,8 +35,9 @@
#include "liblte/cuhd/cuhd.h"
void my_handler(uhd::msg::type_t type, const std::string &msg){
//handle the message...
void my_handler(uhd::msg::type_t type, const std::string & msg)
{
//handle the message...
}
typedef _Complex float complex_t;
@ -45,161 +46,216 @@ typedef _Complex float complex_t;
bool isLocked(void *h)
{
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
std::vector<std::string> mb_sensors = handler->usrp->get_mboard_sensor_names();
std::vector<std::string> rx_sensors = handler->usrp->get_rx_sensor_names(0);
if(std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") != rx_sensors.end()) {
return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool();
}
else if(std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") != mb_sensors.end()) {
return handler->usrp->get_mboard_sensor("ref_locked", 0).to_bool();
}
else {
usleep(500);
return true;
}
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
std::vector < std::string > mb_sensors =
handler->usrp->get_mboard_sensor_names();
std::vector < std::string > rx_sensors =
handler->usrp->get_rx_sensor_names(0);
if (std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") !=
rx_sensors.end()) {
return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool();
} else if (std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") !=
mb_sensors.end()) {
return handler->usrp->get_mboard_sensor("ref_locked", 0).to_bool();
} else {
usleep(500);
return true;
}
}
bool cuhd_rx_wait_lo_locked(void *h)
{
double report = 0.0;
while(isLocked(h) && report < 3.0)
{
report += 0.1;
usleep(1000);
}
return isLocked(h);
double report = 0.0;
while (isLocked(h) && report < 3.0) {
report += 0.1;
usleep(1000);
}
return isLocked(h);
}
int cuhd_start_rx_stream(void *h)
{
cuhd_handler *handler = static_cast < 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) {
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;
double cuhd_set_rx_gain(void *h, double gain)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
handler->usrp->set_rx_gain(gain);
return handler->usrp->get_rx_gain();
}
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;
double cuhd_set_rx_freq(void *h, double freq)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
handler->usrp->set_rx_freq(freq);
return handler->usrp->get_rx_freq();
}
int cuhd_start_rx_stream_nsamples(void *h, int 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;
double cuhd_set_rx_freq_offset(void *h, double freq, double off) {
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
handler->usrp->set_rx_freq(uhd::tune_request_t(freq,off));
return handler->usrp->get_rx_freq();
}
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);
// Try to set LTE clock
handler->usrp->set_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;
}
double cuhd_set_rx_gain(void *h, double gain) {
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
handler->usrp->set_rx_gain(gain);
return handler->usrp->get_rx_gain();
}
double cuhd_set_rx_freq(void *h, double freq) {
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
handler->usrp->set_rx_freq(freq);
return handler->usrp->get_rx_freq();
}
int cuhd_recv(void *h, void *data, int nsamples, int blocking) {
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
uhd::rx_metadata_t md;
if (blocking) {
int n=0,p;
complex_t *data_c = (complex_t*) data;
do {
p=handler->rx_stream->recv(&data_c[n], nsamples-n, md);
if (p == -1) {
return -1;
}
n+=p;
} while(n<nsamples);
return nsamples;
} else {
return handler->rx_stream->recv(data, nsamples, md, 0.0);
}
}
double cuhd_set_tx_gain(void *h, double gain) {
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
handler->usrp->set_tx_gain(gain);
return handler->usrp->get_tx_gain();
}
double cuhd_set_tx_srate(void *h, double freq) {
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
handler->usrp->set_tx_rate(freq);
return handler->usrp->get_tx_rate();
}
double cuhd_set_tx_freq(void *h, double freq) {
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
handler->usrp->set_tx_freq(freq);
return handler->usrp->get_tx_freq();
}
int cuhd_send(void *h, void *data, int nsamples, int blocking) {
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
uhd::tx_metadata_t md;
if (blocking) {
int n=0,p;
complex_t *data_c = (complex_t*) data;
do {
p=handler->tx_stream->send(&data_c[n], nsamples-n, md);
if (p == -1) {
return -1;
}
n+=p;
} while(n<nsamples);
return nsamples;
} else {
return handler->tx_stream->send(data, nsamples, md, 0.0);
}
int cuhd_recv(void *h, void *data, uint32_t nsamples, bool blocking)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
uhd::rx_metadata_t md;
if (blocking) {
int n = 0, p;
complex_t *data_c = (complex_t *) data;
do {
p = handler->rx_stream->recv(&data_c[n], nsamples - n, md);
if (p == -1) {
return -1;
}
n += p;
if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) {
std::cout << "\nError code: " << md.to_pp_string() << "\n\n";
}
} while (n < nsamples);
return nsamples;
} else {
return handler->rx_stream->recv(data, nsamples, md, 0.0);
}
}
int cuhd_recv_timed(void *h,
void *data,
uint32_t nsamples,
int blocking,
time_t *secs,
double *frac_secs) {
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
uhd::rx_metadata_t md;
*secs = -1;
*frac_secs = -1;
int p;
if (blocking) {
int n=0;
complex_t *data_c = (complex_t*) data;
do {
p=handler->rx_stream->recv(&data_c[n], nsamples-n, md);
if (p == -1) {
return -1;
}
if(*secs < 0){
*secs = md.time_spec.get_full_secs();
*frac_secs = md.time_spec.get_frac_secs();
}
n+=p;
} while(n<nsamples);
return n;
} else {
p = handler->rx_stream->recv(data, nsamples, md, 0.0);
*secs = md.time_spec.get_full_secs();
*frac_secs = md.time_spec.get_frac_secs();
return p;
}
}
double cuhd_set_tx_gain(void *h, double gain)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
handler->usrp->set_tx_gain(gain);
return handler->usrp->get_tx_gain();
}
double cuhd_set_tx_srate(void *h, double freq)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
handler->usrp->set_tx_rate(freq);
return handler->usrp->get_tx_rate();
}
double cuhd_set_tx_freq(void *h, double freq)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
handler->usrp->set_tx_freq(freq);
return handler->usrp->get_tx_freq();
}
int cuhd_send(void *h, void *data, uint32_t nsamples, bool blocking)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
uhd::tx_metadata_t md;
if (blocking) {
int n = 0, p;
complex_t *data_c = (complex_t *) data;
do {
p = handler->tx_stream->send(&data_c[n], nsamples - n, md);
if (p == -1) {
return -1;
}
n += p;
} while (n < nsamples);
return nsamples;
} else {
return handler->tx_stream->send(data, nsamples, md, 0.0);
}
}

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

@ -51,26 +51,26 @@ LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND)
# These two can be compiled without UHD or graphics support
#################################################################
add_executable(pbch_ue pbch_ue.c)
target_link_libraries(pbch_ue lte_phy)
add_executable(pdsch_ue pdsch_ue.c iodev.c)
target_link_libraries(pdsch_ue lte_phy)
add_executable(pbch_enodeb pbch_enodeb.c)
target_link_libraries(pbch_enodeb lte_phy)
add_executable(pdsch_enodeb pdsch_enodeb.c)
target_link_libraries(pdsch_enodeb lte_phy)
IF(${CUHD_FIND} EQUAL -1)
SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
ELSE(${CUHD_FIND} EQUAL -1)
target_link_libraries(pbch_ue cuhd)
target_link_libraries(pbch_enodeb cuhd)
target_link_libraries(pdsch_ue cuhd)
target_link_libraries(pdsch_enodeb cuhd)
ENDIF(${CUHD_FIND} EQUAL -1)
IF(${GRAPHICS_FIND} EQUAL -1)
SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
ELSE(${GRAPHICS_FIND} EQUAL -1)
target_link_libraries(pbch_ue graphics)
target_link_libraries(pbch_enodeb graphics)
target_link_libraries(pdsch_ue graphics)
target_link_libraries(pdsch_enodeb graphics)
ENDIF(${GRAPHICS_FIND} EQUAL -1)
@ -81,17 +81,17 @@ ENDIF(${GRAPHICS_FIND} EQUAL -1)
IF(${CUHD_FIND} GREATER -1)
add_executable(scan_rssi scan_rssi.c)
target_link_libraries(scan_rssi lte_phy cuhd )
add_executable(scan_rssi scan_rssi.c)
target_link_libraries(scan_rssi lte_phy cuhd )
add_executable(scan_pss scan_pss.c)
target_link_libraries(scan_pss lte_phy cuhd )
add_executable(scan_pss scan_pss.c)
target_link_libraries(scan_pss lte_phy cuhd )
add_executable(scan_mib scan_mib.c)
target_link_libraries(scan_mib lte_phy cuhd )
add_executable(scan_mib scan_mib.c)
target_link_libraries(scan_mib lte_phy cuhd )
MESSAGE(STATUS " UHD examples will be installed.")
MESSAGE(STATUS " UHD examples will be installed.")
ELSE(${CUHD_FIND} GREATER -1)
MESSAGE(STATUS " UHD examples NOT INSTALLED: CUHD library not compiled.")
MESSAGE(STATUS " UHD examples NOT INSTALLED: CUHD library not compiled.")
ENDIF(${CUHD_FIND} GREATER -1)

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

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

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

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

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

@ -34,8 +34,16 @@
typedef _Complex float cf_t;
LIBLTE_API void ch_awgn_c(const cf_t* input, cf_t* output, float variance, int buff_sz);
LIBLTE_API void ch_awgn_f(const float* x, float* y, float variance, int buff_sz);
LIBLTE_API void ch_awgn_c(const cf_t* input,
cf_t* output,
float variance,
int buff_sz);
LIBLTE_API void ch_awgn_f(const float* x,
float* y,
float variance,
int buff_sz);
/* High-level API */

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

@ -29,44 +29,50 @@
#ifndef _LTEBASE_
#define _LTEBASE_
#include <stdint.h>
#include <stdbool.h>
#include "liblte/config.h"
#define NSUBFRAMES_X_FRAME 10
#define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME)
#define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME)
#define LTE_NSOFT_BITS 250368 // Soft buffer size for Category 1 UE
#define LTE_NULL_BIT 0
#define LTE_NULL_BIT 0
#define LTE_NULL_SYMBOL 2
#define LTE_NIL_SYMBOL 2
#define MAX_PORTS 4
#define MAX_PORTS_CTRL 4
#define MAX_PORTS 4
#define MAX_LAYERS 8
#define MAX_CODEWORDS 2
#define LTE_CRC24A 0x1864CFB
#define LTE_CRC24B 0X1800063
#define LTE_CRC16 0x11021
#define LTE_CRC8 0x19B
#define LTE_CRC16 0x11021
#define LTE_CRC8 0x19B
typedef enum {CPNORM, CPEXT} lte_cp_t;
#define SIRNTI 0xFFFF
#define SIRNTI 0xFFFF
#define PRNTI 0xFFFE
#define MRNTI 0xFFFD
#define MAX_NSYMB 7
#define MAX_NSYMB 7
#define CPNORM_NSYMB 7
#define MAX_PRB 110
#define RE_X_RB 12
#define SYMBOL_SZ_MAX 2048
#define CPNORM_NSYMB 7
#define CPNORM_SF_NSYMB 2*CPNORM_NSYMB
#define CPNORM_0_LEN 160
#define CPNORM_LEN 144
#define CPNORM_0_LEN 160
#define CPNORM_LEN 144
#define CPEXT_NSYMB 6
#define CPEXT_NSYMB 6
#define CPEXT_SF_NSYMB 2*CPEXT_NSYMB
#define CPEXT_LEN 512
#define CPEXT_7_5_LEN 1024
#define CPEXT_LEN 512
#define CPEXT_7_5_LEN 1024
#define CP_ISNORM(cp) (cp==CPNORM)
#define CP_ISEXT(cp) (cp==CPEXT)
@ -78,33 +84,40 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#define SLOT_LEN_CPNORM(symbol_sz) (symbol_sz+CP(symbol_sz,CPNORM_0_LEN)+(CPNORM_NSYMB-1)*(symbol_sz+CP(symbol_sz,CPNORM_LEN)))
#define SLOT_LEN_CPEXT(symbol_sz) (CPEXT_NSYMB*(symbol_sz+CP(symbol_sz, CPEXT_LEN)))
#define SLOT_LEN(symbol_sz, cp) CP_ISNORM(cp)?SLOT_LEN_CPNORM(symbol_sz):SLOT_LEN_CPEXT(symbol_sz)
#define SLOT_LEN(symbol_sz, cp) (CP_ISNORM(cp)?SLOT_LEN_CPNORM(symbol_sz):SLOT_LEN_CPEXT(symbol_sz))
#define SF_LEN_CPNORM(symbol_sz) 2*SLOT_LEN_CPNORM(symbol_sz)
#define SF_LEN_CPEXT(symbol_sz) 2*SLOT_LEN_CPEXT(symbol_sz)
#define SF_LEN(symbol_sz, cp) 2*SLOT_LEN(cp, symbol_sz)
#define SF_LEN_CPNORM(symbol_sz) (2*SLOT_LEN_CPNORM(symbol_sz))
#define SF_LEN_CPEXT(symbol_sz) (2*SLOT_LEN_CPEXT(symbol_sz))
#define SF_LEN(symbol_sz, cp) (2*SLOT_LEN(symbol_sz, cp))
#define SF_LEN_MAX SF_LEN(SYMBOL_SZ_MAX, CPNORM)
#define SLOT_LEN_RE(nof_prb, cp) (nof_prb*RE_X_RB*CP_NSYMB(cp))
#define SF_LEN_RE(nof_prb, cp) (2*SLOT_LEN_RE(nof_prb, cp))
#define SLOT_IDX_CPNORM(idx, symbol_sz) (idx==0?(CP(symbol_sz, CPNORM_0_LEN)):(CP(symbol_sz, CPNORM_0_LEN)+idx*(symbol_sz+CP(symbol_sz, CPNORM_LEN))))
#define SLOT_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN)))
#define SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) (symbol_idx*nof_prb*RE_X_RB + sample_idx)
#define MAX_PRB 110
#define RE_X_RB 12
#define RS_VSHIFT(cell_id) (cell_id%6)
#define GUARD_RE(nof_prb) ((lte_symbol_sz(nof_prb)-nof_prb*RE_X_RB)/2)
#define SYMBOL_HAS_REF(l, cp, nof_ports) ((l == 1 && nof_ports == 4) \
|| l == 0 \
|| l == CP_NSYMB(cp) - 3)
LIBLTE_API const int lte_symbol_sz(int nof_prb);
LIBLTE_API int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols);
LIBLTE_API int lte_voffset(int symbol_id, int cell_id, int nof_ports);
#define NOF_LTE_BANDS 29
#define NOF_TC_CB_SIZES 188
typedef struct LIBLTE_API {
uint32_t nof_prb;
uint32_t nof_ports;
uint32_t id;
lte_cp_t cp;
}lte_cell_t;
typedef enum LIBLTE_API {
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX
@ -113,6 +126,10 @@ typedef enum LIBLTE_API {
typedef enum LIBLTE_API { PHICH_NORM, PHICH_EXT} phich_length_t;
typedef enum LIBLTE_API { R_1_6, R_1_2, R_1, R_2} phich_resources_t;
typedef enum LIBLTE_API {
LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6
} lte_mod_t;
typedef struct LIBLTE_API {
int id;
@ -123,16 +140,59 @@ LIBLTE_API enum band_geographical_area {
ALL, NAR, APAC, EMEA, JAPAN, CALA, NA
};
LIBLTE_API int lte_cb_size(int index);
LIBLTE_API int lte_find_cb_index(int long_cb);
LIBLTE_API bool lte_cell_isvalid(lte_cell_t *cell);
LIBLTE_API 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);
#endif

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

@ -34,13 +34,13 @@
#include "liblte/config.h"
typedef struct LIBLTE_API {
int R;
int K;
int poly[3];
uint32_t R;
uint32_t K;
uint32_t poly[3];
bool tail_biting;
}convcoder_t;
LIBLTE_API int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length);
LIBLTE_API int convcoder_encode(convcoder_t *q, char *input, char *output, uint32_t frame_length);
/* High-level API */

@ -30,6 +30,7 @@
#define CRC_
#include "liblte/config.h"
#include <stdint.h>
typedef struct LIBLTE_API {
unsigned long table[256];
@ -45,6 +46,6 @@ typedef struct LIBLTE_API {
LIBLTE_API int crc_init(crc_t *h, unsigned int crc_poly, int crc_order);
LIBLTE_API int crc_set_init(crc_t *h, unsigned long crc_init_value);
LIBLTE_API void crc_attach(crc_t *h, char *data, int len);
LIBLTE_API unsigned int crc_checksum(crc_t *h, char *data, int len);
LIBLTE_API uint32_t crc_checksum(crc_t *h, char *data, int len);
#endif

@ -33,8 +33,15 @@
#define RX_NULL 10000
#define TX_NULL 80
LIBLTE_API int rm_conv_tx(char *input, int in_len, char *output, int out_len);
LIBLTE_API int rm_conv_rx(float *input, int in_len, float *output, int out_len);
LIBLTE_API int rm_conv_tx(char *input,
uint32_t in_len,
char *output,
uint32_t out_len);
LIBLTE_API int rm_conv_rx(float *input,
uint32_t in_len,
float *output,
uint32_t out_len);
/* High-level API */
typedef struct

@ -40,25 +40,30 @@
#include "liblte/config.h"
typedef struct LIBLTE_API {
int buffer_len;
char *buffer;
} rm_turbo_t;
LIBLTE_API int rm_turbo_init(rm_turbo_t *q, int max_codeblock_len);
LIBLTE_API void rm_turbo_free(rm_turbo_t *q);
LIBLTE_API int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output,
int out_len, int rv_idx);
LIBLTE_API int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len,
float *output, int out_len, int rv_idx);
LIBLTE_API int rm_turbo_tx(char *w_buff,
uint32_t buff_len,
char *input,
uint32_t in_len,
char *output,
uint32_t out_len,
uint32_t rv_idx);
LIBLTE_API int rm_turbo_rx(float *w_buff,
uint32_t buff_len,
float *input,
uint32_t in_len,
float *output,
uint32_t out_len,
uint32_t rv_idx);
/* High-level API */
typedef struct LIBLTE_API {
rm_turbo_t q;
struct rm_turbo_init {
int direction;
} init;
void *input; // input type may be char or float depending on hard
void *input; // input type may be char or float depending on hard
int in_len;
struct rm_turbo_ctrl_in {
int E;

@ -31,15 +31,15 @@
#include "liblte/config.h"
typedef struct LIBLTE_API {
int *forward;
int *reverse;
int max_long_cb;
uint32_t *forward;
uint32_t *reverse;
uint32_t max_long_cb;
} tc_interl_t;
LIBLTE_API int tc_interl_LTE_gen(tc_interl_t *h, int long_cb);
LIBLTE_API int tc_interl_UMTS_gen(tc_interl_t *h, int long_cb);
LIBLTE_API int tc_interl_LTE_gen(tc_interl_t *h, uint32_t long_cb);
LIBLTE_API int tc_interl_UMTS_gen(tc_interl_t *h, uint32_t long_cb);
LIBLTE_API int tc_interl_init(tc_interl_t *h, int max_long_cb);
LIBLTE_API int tc_interl_init(tc_interl_t *h, uint32_t max_long_cb);
LIBLTE_API void tc_interl_free(tc_interl_t *h);
#endif

@ -37,13 +37,13 @@
#define TOTALTAIL 12
typedef struct LIBLTE_API {
int max_long_cb;
uint32_t max_long_cb;
tc_interl_t interl;
} tcod_t;
LIBLTE_API int tcod_init(tcod_t *h, int max_long_cb);
LIBLTE_API int tcod_init(tcod_t *h, uint32_t max_long_cb);
LIBLTE_API void tcod_free(tcod_t *h);
LIBLTE_API int tcod_encode(tcod_t *h, char *input, char *output, int long_cb);
LIBLTE_API int tcod_encode(tcod_t *h, char *input, char *output, uint32_t long_cb);
#endif

@ -68,13 +68,25 @@ typedef struct LIBLTE_API {
tc_interl_t interleaver;
} tdec_t;
LIBLTE_API int tdec_init(tdec_t *h, int max_long_cb);
LIBLTE_API void tdec_free(tdec_t *h);
LIBLTE_API int tdec_reset(tdec_t *h, int long_cb);
LIBLTE_API void tdec_iteration(tdec_t *h, llr_t *input, int long_cb);
LIBLTE_API void tdec_decision(tdec_t *h, char *output, int long_cb);
LIBLTE_API void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations,
int long_cb);
LIBLTE_API int tdec_init(tdec_t * h,
uint32_t max_long_cb);
LIBLTE_API void tdec_free(tdec_t * h);
LIBLTE_API int tdec_reset(tdec_t * h, uint32_t long_cb);
LIBLTE_API void tdec_iteration(tdec_t * h,
llr_t * input,
uint32_t long_cb);
LIBLTE_API void tdec_decision(tdec_t * h,
char *output,
uint32_t long_cb);
LIBLTE_API void tdec_run_all(tdec_t * h,
llr_t * input,
char *output,
uint32_t nof_iterations,
uint32_t long_cb);
#endif

@ -38,21 +38,34 @@ typedef enum {
typedef struct LIBLTE_API{
void *ptr;
int R;
int K;
uint32_t R;
uint32_t K;
unsigned int framebits;
bool tail_biting;
int poly[3];
int (*decode) (void*, unsigned char*, char*, int);
uint32_t poly[3];
int (*decode) (void*, uint8_t*, char*, uint32_t);
void (*free) (void*);
unsigned char *tmp;
unsigned char *symbols_uc;
}viterbi_t;
LIBLTE_API int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int max_frame_length, bool tail_bitting);
LIBLTE_API int viterbi_init(viterbi_t *q,
viterbi_type_t type,
uint32_t poly[3],
uint32_t max_frame_length,
bool tail_bitting);
LIBLTE_API void viterbi_free(viterbi_t *q);
LIBLTE_API int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length);
LIBLTE_API int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, int frame_length);
LIBLTE_API int viterbi_decode_f(viterbi_t *q,
float *symbols,
char *data,
uint32_t frame_length);
LIBLTE_API int viterbi_decode_uc(viterbi_t *q,
uint8_t *symbols,
char *data,
uint32_t frame_length);
/* High-level API */

@ -38,13 +38,13 @@
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
enum modem_std table; /* In this implementation, mapping table is hard-coded */
lte_mod_t mod; /* In this implementation, mapping table is hard-coded */
}demod_hard_t;
LIBLTE_API void demod_hard_init(demod_hard_t* q);
LIBLTE_API void demod_hard_table_set(demod_hard_t* q, enum modem_std table);
LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, int nsymbols);
LIBLTE_API void demod_hard_table_set(demod_hard_t* q, lte_mod_t mod);
LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, uint32_t nsymbols);
@ -52,7 +52,7 @@ LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits,
typedef struct LIBLTE_API {
demod_hard_t obj;
struct demod_hard_init {
enum modem_std std; // Symbol mapping standard (see modem_table.h)
lte_mod_t std; // Symbol mapping standard (see modem_table.h)
} init;
cf_t* input;

@ -56,7 +56,7 @@ typedef struct LIBLTE_API {
modem_table_t table;
struct demod_soft_init{
enum modem_std std; // symbol mapping standard (see modem_table.h)
lte_mod_t std; // symbol mapping standard (see modem_table.h)
} init;
const cf_t* input;

@ -37,13 +37,13 @@
typedef _Complex float cf_t;
LIBLTE_API int mod_modulate(modem_table_t* table, const char *bits, cf_t* symbols, int nbits);
LIBLTE_API int mod_modulate(modem_table_t* table, const char *bits, cf_t* symbols, uint32_t nbits);
/* High-level API */
typedef struct LIBLTE_API {
modem_table_t obj;
struct mod_init {
enum modem_std std; // symbol mapping standard (see modem_table.h)
lte_mod_t std; // symbol mapping standard (see modem_table.h)
} init;
const char* input;

@ -34,30 +34,36 @@
#include <complex.h>
#include <stdint.h>
#include "liblte/phy/common/phy_common.h"
#include "liblte/config.h"
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
int idx[2][6][32];
uint32_t idx[2][6][32];
}soft_table_t;
typedef struct LIBLTE_API {
cf_t* symbol_table; // bit-to-symbol mapping
soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating)
int nsymbols; // number of modulation symbols
int nbits_x_symbol; // number of bits per symbol
uint32_t nsymbols; // number of modulation symbols
uint32_t nbits_x_symbol; // number of bits per symbol
}modem_table_t;
// Modulation standards
enum modem_std {
LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6
};
LIBLTE_API void modem_table_init(modem_table_t* q);
LIBLTE_API void modem_table_free(modem_table_t* q);
LIBLTE_API void modem_table_reset(modem_table_t* q);
LIBLTE_API int modem_table_set(modem_table_t* q, cf_t* table, soft_table_t *soft_table, int nsymbols, int nbits_x_symbol);
LIBLTE_API int modem_table_std(modem_table_t* q, enum modem_std table, bool compute_soft_demod);
LIBLTE_API int modem_table_set(modem_table_t* q,
cf_t* table,
soft_table_t *soft_table,
uint32_t nsymbols,
uint32_t nbits_x_symbol);
LIBLTE_API int modem_table_lte(modem_table_t* q,
lte_mod_t modulation,
bool compute_soft_demod);
#endif // MODEM_TABLE_

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

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

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

@ -44,41 +44,26 @@
typedef _Complex float cf_t;
#define PDCCH_NOF_SEARCH_MODES 3
typedef enum LIBLTE_API {
SEARCH_NONE = 3, SEARCH_SI = 0, SEARCH_RA = 1, SEARCH_UE = 2
SEARCH_UE, SEARCH_COMMON
} pdcch_search_mode_t;
/*
* A search mode is indicated by higher layers to look for SI/C/RA-RNTI
* DCI messages as defined in Section 7.1 of 36.213
*/
typedef struct LIBLTE_API {
int nof_candidates;
dci_candidate_t *candidates[NSUBFRAMES_X_FRAME];
} pdcch_search_t;
/* PDCCH object */
typedef struct LIBLTE_API {
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_bits;
int nof_symbols;
int nof_ports;
int nof_regs;
int nof_cce;
pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES];
pdcch_search_mode_t current_search_mode;
lte_cell_t cell;
uint32_t e_bits;
uint32_t nof_regs;
uint32_t nof_cce;
uint32_t max_bits;
regs_t *regs;
/* buffers */
cf_t *ce[MAX_PORTS_CTRL];
cf_t *pdcch_symbols[MAX_PORTS_CTRL];
cf_t *pdcch_x[MAX_PORTS_CTRL];
cf_t *ce[MAX_PORTS];
cf_t *pdcch_symbols[MAX_PORTS];
cf_t *pdcch_x[MAX_PORTS];
cf_t *pdcch_d;
char *pdcch_e;
float *pdcch_llr;
@ -91,36 +76,48 @@ typedef struct LIBLTE_API {
crc_t crc;
} pdcch_t;
LIBLTE_API int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports,
int cell_id, lte_cp_t cp);
LIBLTE_API void pdcch_free(pdcch_t *q);
/* Encoding functions */
LIBLTE_API int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS_CTRL],
int nsubframe);
/* Decoding functions */
LIBLTE_API int pdcch_init(pdcch_t *q,
regs_t *regs,
lte_cell_t cell);
/* There are two ways to decode the DCI messages:
* a) call pdcch_set_search_si/ue/ra and then call pdcch_decode()
* b) call pdcch_extract_llr() and then call pdcch_decode_si/ue/ra
*/
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_free(pdcch_t *q);
LIBLTE_API void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti);
LIBLTE_API void pdcch_set_search_ue(pdcch_t *q);
LIBLTE_API int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe);
LIBLTE_API void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti);
LIBLTE_API void pdcch_set_search_ra(pdcch_t *q);
LIBLTE_API int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci);
/* Encoding function */
LIBLTE_API int pdcch_encode(pdcch_t *q,
dci_msg_t *msg,
dci_location_t location,
uint16_t rnti,
cf_t *sf_symbols[MAX_PORTS],
uint32_t nsubframe,
uint32_t cfi);
/* 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

@ -43,49 +43,95 @@
#include "liblte/phy/phch/dci.h"
#include "liblte/phy/phch/regs.h"
#define TDEC_ITERATIONS 1
#define TDEC_ITERATIONS 6
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
ra_mcs_t mcs;
ra_prb_t prb_alloc;
lte_cell_t cell;
uint32_t max_cb;
uint32_t w_buff_size;
float **pdsch_w_buff_f;
char **pdsch_w_buff_c;
struct cb_segm {
uint32_t F;
uint32_t C;
uint32_t K1;
uint32_t K2;
uint32_t C1;
uint32_t C2;
} cb_segm;
} pdsch_harq_t;
/* PDSCH object */
typedef struct LIBLTE_API {
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_ports;
int max_symbols;
unsigned short rnti;
/* buffers */
cf_t *ce[MAX_PORTS];
cf_t *pdsch_symbols[MAX_PORTS];
cf_t *pdsch_x[MAX_PORTS];
cf_t *pdsch_d;
char *pdsch_e_bits;
char *cb_in_b;
char *cb_out_b;
float *pdsch_llr;
float *pdsch_rm_f;
/* tx & rx objects */
modem_table_t mod[4];
demod_soft_t demod;
sequence_t seq_pdsch[NSUBFRAMES_X_FRAME];
tcod_t encoder;
tdec_t decoder;
rm_turbo_t rm_turbo;
crc_t crc_tb;
crc_t crc_cb;
lte_cell_t cell;
uint32_t max_symbols;
bool rnti_is_set;
uint16_t rnti;
/* buffers */
// void buffers are shared for tx and rx
cf_t *ce[MAX_PORTS];
cf_t *pdsch_symbols[MAX_PORTS];
cf_t *pdsch_x[MAX_PORTS];
cf_t *pdsch_d;
char *cb_in;
void *cb_out;
void *pdsch_e;
/* tx & rx objects */
modem_table_t mod[4];
demod_soft_t demod;
sequence_t seq_pdsch[NSUBFRAMES_X_FRAME];
tcod_t encoder;
tdec_t decoder;
crc_t crc_tb;
crc_t crc_cb;
}pdsch_t;
LIBLTE_API int pdsch_init(pdsch_t *q, unsigned short user_rnti, int nof_prb,
int nof_ports, int cell_id, lte_cp_t cp);
LIBLTE_API int pdsch_init(pdsch_t *q,
lte_cell_t cell);
LIBLTE_API void pdsch_free(pdsch_t *q);
LIBLTE_API int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS],
int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc);
LIBLTE_API int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS],
char *data, int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc);
LIBLTE_API int pdsch_set_rnti(pdsch_t *q,
uint16_t rnti);
LIBLTE_API int pdsch_harq_init(pdsch_harq_t *p,
pdsch_t *pdsch);
LIBLTE_API int pdsch_harq_setup(pdsch_harq_t *p,
ra_mcs_t mcs,
ra_prb_t *prb_alloc);
LIBLTE_API void pdsch_harq_free(pdsch_harq_t *p);
LIBLTE_API int pdsch_encode(pdsch_t *q,
char *data,
cf_t *sf_symbols[MAX_PORTS],
uint32_t nsubframe,
pdsch_harq_t *harq_process,
uint32_t rv_idx);
LIBLTE_API int pdsch_decode(pdsch_t *q,
cf_t *sf_symbols,
cf_t *ce[MAX_PORTS],
char *data,
uint32_t nsubframe,
pdsch_harq_t *harq_process,
uint32_t rv_idx);
LIBLTE_API int pdsch_get(pdsch_t *q,
cf_t *sf_symbols,
cf_t *pdsch_symbols,
ra_prb_t *prb_alloc,
uint32_t subframe);
#endif

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

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

@ -37,17 +37,9 @@
* allocation.
*/
typedef enum LIBLTE_API {
MOD_NULL = 0, BPSK = 1, QPSK = 2, QAM16 = 3, QAM64 = 4
} ra_mod_t;
typedef struct LIBLTE_API {
ra_mod_t mod; // By default, mod = MOD_NULL and the mcs_idx value is taken by the packing functions
// otherwise mod + tbs values are used to generate the mcs_idx automatically.
uint8_t tbs_idx;
uint8_t mcs_idx;
int tbs;// If tbs<=0, the tbs_idx value is taken by the packing functions to generate the DCI
// message. Otherwise the tbs_idx corresponding to the lower nearest TBS is taken.
lte_mod_t mod;
uint32_t tbs;
} ra_mcs_t;
typedef enum LIBLTE_API {
@ -60,13 +52,14 @@ typedef struct LIBLTE_API {
typedef struct LIBLTE_API {
uint32_t vrb_bitmask;
uint8_t rbg_subset;bool shift;
uint32_t rbg_subset;
bool shift;
} ra_type1_t;
typedef struct LIBLTE_API {
uint32_t riv; // if L_crb==0, DCI message packer will take this value directly
uint16_t L_crb;
uint16_t RB_start;
uint32_t L_crb;
uint32_t RB_start;
enum {
nprb1a_2 = 0, nprb1a_3 = 1
} n_prb1a;
@ -79,20 +72,34 @@ typedef struct LIBLTE_API {
} ra_type2_t;
typedef struct LIBLTE_API {
unsigned short rnti;
uint32_t prb_idx[MAX_PRB];
uint32_t nof_prb;
} ra_prb_slot_t;
typedef struct LIBLTE_API {
ra_prb_slot_t slot[2];
uint32_t lstart;
uint32_t re_sf[NSUBFRAMES_X_FRAME];
} ra_prb_t;
typedef struct LIBLTE_API {
uint16_t rnti;
ra_type_t alloc_type;
union {
ra_type0_t type0_alloc;
ra_type1_t type1_alloc;
ra_type2_t type2_alloc;
};
ra_prb_t prb_alloc;
uint32_t mcs_idx;
ra_mcs_t mcs;
uint8_t harq_process;
uint8_t rv_idx;bool ndi;
uint32_t harq_process;
uint32_t rv_idx;
bool ndi;
} ra_pdsch_t;
typedef struct LIBLTE_API {
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh.
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mhz.
* hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz.
*/
enum {
@ -103,64 +110,85 @@ typedef struct LIBLTE_API {
hop_type_2 = 3
} freq_hop_fl;
ra_prb_t prb_alloc;
ra_type2_t type2_alloc;
uint32_t mcs_idx;
ra_mcs_t mcs;
uint8_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation
uint32_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation
// than before (Format0 message, see also 8.6.1 in 36.2313).
bool ndi;bool cqi_request;
bool ndi;
bool cqi_request;
} ra_pusch_t;
typedef struct LIBLTE_API {
uint8_t prb_idx[110];
int nof_prb;
} ra_prb_slot_t;
LIBLTE_API void ra_prb_fprint(FILE *f,
ra_prb_slot_t *prb);
typedef struct LIBLTE_API {
ra_prb_slot_t slot[2];
int lstart;
int re_sf[NSUBFRAMES_X_FRAME];
} ra_prb_t;
LIBLTE_API int ra_prb_get_dl(ra_prb_t *prb,
ra_pdsch_t *ra,
uint32_t nof_prb);
LIBLTE_API 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 int ra_prb_get_dl(ra_prb_t *prb, ra_pdsch_t *ra, int nof_prb);
LIBLTE_API int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb);
LIBLTE_API void ra_prb_get_re(ra_prb_t *prb_dist, int nof_prb, int nof_ports,
int nof_ctrl_symbols, lte_cp_t cp);
LIBLTE_API 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);
LIBLTE_API void ra_pusch_fprint(FILE *f,
ra_pusch_t *ra,
uint32_t nof_prb);
#endif /* RB_ALLOC_H_ */

@ -45,57 +45,91 @@
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
int k[4];
int k0;
int l;
uint32_t k[4];
uint32_t k0;
uint32_t l;
bool assigned;
}regs_reg_t;
typedef struct LIBLTE_API {
int nof_regs;
uint32_t nof_regs;
regs_reg_t **regs;
}regs_ch_t;
typedef struct LIBLTE_API {
int cell_id;
int nof_prb;
int max_ctrl_symbols;
int cfi;
int ngroups_phich;
int nof_ports;
lte_cp_t cp;
lte_cell_t cell;
uint32_t max_ctrl_symbols;
uint32_t cfi;
bool cfi_initiated;
uint32_t ngroups_phich;
phich_resources_t phich_res;
phich_length_t phich_len;
regs_ch_t pcfich;
regs_ch_t *phich; // there are several phich
regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for
the three possible CFI value */
int nof_regs;
uint32_t nof_regs;
regs_reg_t *regs;
}regs_t;
LIBLTE_API int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports,
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp);
LIBLTE_API void regs_free(regs_t *h);
LIBLTE_API int regs_set_cfi(regs_t *h, int nof_ctrl_symbols);
LIBLTE_API int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
LIBLTE_API int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
LIBLTE_API int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb);
LIBLTE_API int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb);
LIBLTE_API int regs_init(regs_t *h,
phich_resources_t phich_res,
phich_length_t phich_len,
lte_cell_t cell);
LIBLTE_API int regs_pcfich_nregs(regs_t *h);
LIBLTE_API int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols);
LIBLTE_API int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t pcfich_symbols[REGS_PCFICH_NSYM]);
LIBLTE_API void regs_free(regs_t *h);
LIBLTE_API int regs_set_cfi(regs_t *h,
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);
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);
#endif // REGS_H_
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/fft.h"
#include "liblte/phy/common/sequence.h"
#include "liblte/phy/ch_estimation/chest.h"
#include "liblte/phy/ch_estimation/refsignal.h"
#include "liblte/phy/resampling/interp.h"
#include "liblte/phy/resampling/decim.h"
#include "liblte/phy/resampling/resample_arb.h"
#include "liblte/phy/channel/ch_awgn.h"
#include "liblte/phy/fec/viterbi.h"
@ -89,11 +92,11 @@
#include "liblte/phy/phch/pbch.h"
#include "liblte/phy/phch/pcfich.h"
#include "liblte/phy/phch/phich.h"
#include "liblte/phy/phch/ue_sync.h"
#include "liblte/phy/phch/ue_dl.h"
#include "liblte/phy/scrambling/scrambling.h"
#include "liblte/phy/resampling/interp.h"
#include "liblte/phy/sync/pss.h"
#include "liblte/phy/sync/sfo.h"
#include "liblte/phy/sync/sss.h"

@ -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
#define INTERP_H_
#define INTERP_H
#include <stdint.h>
#include "liblte/config.h"
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(cf_t *input, cf_t *output, int M, int len);
LIBLTE_API void interp_linear_f(float *input, float *output, int M, int len);
LIBLTE_API void interp_linear_f(float *input,
float *output,
uint32_t M,
uint32_t len);
#endif // INTERP_H

@ -32,6 +32,7 @@
#include <complex.h>
#include "liblte/config.h"
#include "liblte/phy/utils/cexptab.h"
typedef _Complex float cf_t;
@ -48,10 +49,20 @@ typedef struct LIBLTE_API {
cf_t *cur_cexp;
}cfo_t;
LIBLTE_API int cfo_init(cfo_t *h, int nsamples);
LIBLTE_API int cfo_init(cfo_t *h,
uint32_t nsamples);
LIBLTE_API void cfo_free(cfo_t *h);
LIBLTE_API void cfo_set_tol(cfo_t *h, float tol);
LIBLTE_API void cfo_correct(cfo_t *h, cf_t *x, float freq);
LIBLTE_API int cfo_realloc(cfo_t *h,
uint32_t samples);
LIBLTE_API void cfo_set_tol(cfo_t *h,
float tol);
LIBLTE_API void cfo_correct(cfo_t *h,
cf_t *input,
cf_t *output,
float freq);
#endif // CFO_

@ -42,8 +42,7 @@ typedef _Complex float cf_t; /* this is only a shortcut */
#define DEFAULT_CORRELATION_TH 10000
#define DEFAULT_NOSYNC_TIMEOUT 5
#define PSS_LEN_FREQ 129 // FFT-based convolution removes 1 leaving it in 128
#define PSS_LEN 62
#define PSS_LEN 62
#define PSS_RE 6*12
@ -67,45 +66,47 @@ typedef struct LIBLTE_API {
conv_fft_cc_t conv_fft;
#endif
int frame_size;
int N_id_2;
float current_cfo;
bool cfo_auto; // default true
int nof_nosync_frames;
int nosync_timeout_frames; // default 5
float correlation_threshold; // default 10000
int frame_start_idx;
int fb_wp;
cf_t *pss_signal_freq;
uint32_t frame_size;
uint32_t N_id_2;
uint32_t fft_size;
cf_t *pss_signal_freq[3]; // One sequence for each N_id_2
cf_t *tmp_input;
float *conv_abs;
cf_t *frame_buffer;
cf_t *conv_output;
cf_t *tmp_nco;
}pss_synch_t;
typedef enum { PSS_TX, PSS_RX } pss_direction_t;
/* Basic functionality */
LIBLTE_API int pss_synch_init(pss_synch_t *q, int frame_size);
LIBLTE_API int pss_synch_init_fft(pss_synch_t *q,
uint32_t frame_size,
uint32_t fft_size);
LIBLTE_API int pss_synch_init(pss_synch_t *q,
uint32_t frame_size);
LIBLTE_API void pss_synch_free(pss_synch_t *q);
LIBLTE_API int pss_generate(cf_t *signal, int N_id_2);
LIBLTE_API void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp);
LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2);
LIBLTE_API int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, float *corr_mean_value);
LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv);
LIBLTE_API int pss_generate(cf_t *signal,
uint32_t N_id_2);
LIBLTE_API void pss_put_slot(cf_t *pss_signal,
cf_t *slot,
uint32_t nof_prb,
lte_cp_t cp);
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_periodic(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples);
LIBLTE_API void pss_synch_set_timeout(pss_synch_t *q, int nof_frames);
LIBLTE_API void pss_synch_set_threshold(pss_synch_t *q, float threshold);
LIBLTE_API void pss_synch_set_cfo_mode(pss_synch_t *q, bool cfo_auto);
LIBLTE_API float pss_synch_get_cfo(pss_synch_t *q);
LIBLTE_API int pss_synch_get_frame_start_idx(pss_synch_t *q);
LIBLTE_API int pss_synch_find_pss(pss_synch_t *q,
cf_t *input,
float *corr_peak_value,
float *corr_mean_value);
LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q,
cf_t *pss_recv);
/* High-level API */

@ -38,26 +38,20 @@
typedef _Complex float cf_t; /* this is only a shortcut */
/** gives the beginning of the SSS symbol (to be passed to sss_synch_m0m1).
* subframe_sz is the length of the subframe, e.g. 1920 for the 1.9 MHz
* symbol_sz is the OFDM symbol size (including CP), e.g. 137 for the 1.9 MHz
*/
#define SSS_SYMBOL_ST(subframe_sz, symbol_sz) (subframe_sz/2-2*symbol_sz)
#define SSS_POS_SYMBOL 33
#define SSS_DFT_LEN 128
#define N_SSS 31
#define N_SSS 31
#define SSS_LEN 2*N_SSS
#define SSS_MAX_FFT_LEN 2048
struct sss_tables{
int z1[N_SSS][N_SSS];
int c[2][N_SSS];
int s[N_SSS][N_SSS];
int N_id_2;
};
/* Allocate 32 complex to make it multiple of 32-byte AVX instructions alignment requirement.
* Should use vect_malloc() to make it platform agnostic.
* Should use vec_malloc() to make it platform agnostic.
*/
struct fc_tables{
cf_t z1[N_SSS+1][N_SSS+1];
@ -70,34 +64,68 @@ struct fc_tables{
typedef struct LIBLTE_API {
dft_plan_t dftp_input;
uint32_t fft_size;
float corr_peak_threshold;
int symbol_sz;
int subframe_sz;
int N_id_1_table[30][30];
struct fc_tables fc_tables;
uint32_t symbol_sz;
uint32_t subframe_sz;
uint32_t N_id_2;
uint32_t N_id_1_table[30][30];
struct fc_tables fc_tables[3]; // one for each N_id_2
}sss_synch_t;
/* Basic functionality */
LIBLTE_API int sss_synch_init(sss_synch_t *q);
LIBLTE_API int sss_synch_init(sss_synch_t *q,
uint32_t fft_size);
LIBLTE_API int sss_synch_realloc(sss_synch_t *q,
uint32_t fft_size);
LIBLTE_API void sss_synch_free(sss_synch_t *q);
LIBLTE_API void sss_generate(float *signal0, float *signal5, int cell_id);
LIBLTE_API void sss_put_slot(float *sss, cf_t *symbol, int nof_prb, lte_cp_t cp);
LIBLTE_API int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2);
LIBLTE_API void sss_generate(float *signal0,
float *signal5,
uint32_t cell_id);
LIBLTE_API void sss_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,
int *m1, float *m1_value);
LIBLTE_API int sss_synch_subframe(int m0, int m1);
LIBLTE_API int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1);
LIBLTE_API void sss_synch_set_symbol_sz(sss_synch_t *q,
uint32_t symbol_sz);
LIBLTE_API int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx, int *N_id_1);
LIBLTE_API void sss_synch_set_threshold(sss_synch_t *q, float threshold);
LIBLTE_API void sss_synch_set_symbol_sz(sss_synch_t *q, int symbol_sz);
LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz);
LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q,
uint32_t subframe_sz);
/* High-level API */
@ -105,18 +133,18 @@ LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz);
typedef struct LIBLTE_API {
sss_synch_t obj;
struct sss_synch_init {
int N_id_2;
uint32_t N_id_2;
} init;
cf_t *input;
int in_len;
uint32_t in_len;
struct sss_synch_ctrl_in {
int symbol_sz;
int subframe_sz;
int correlation_threshold;
uint32_t symbol_sz;
uint32_t subframe_sz;
uint32_t correlation_threshold;
} ctrl_in;
struct sss_synch_ctrl_out {
int subframe_idx;
int N_id_1;
uint32_t subframe_idx;
uint32_t N_id_1;
} ctrl_out;
}sss_synch_hl;

@ -30,15 +30,19 @@
#define SYNC_
#include <stdbool.h>
#include <math.h>
#include "liblte/config.h"
#include "pss.h"
#include "sss.h"
#include "sfo.h"
#include "liblte/phy/sync/pss.h"
#include "liblte/phy/sync/sss.h"
#define FFT_SIZE_MIN 64
#define FFT_SIZE_MAX 2048
/**
*
* This object performs time and frequency synchronization using the PSS and SSS signals.
*
* The object is designed to work with signals sampled at 1.92 Mhz centered at the carrier frequency.
* Thus, downsampling is required if the signal is sampled at higher frequencies.
*
@ -50,57 +54,91 @@
enum sync_pss_det { ABSOLUTE, PEAK_MEAN};
typedef struct LIBLTE_API {
pss_synch_t pss[3]; // One for each N_id_2
sss_synch_t sss[3]; // One for each N_id_2
pss_synch_t pss_find;
pss_synch_t pss_track;
sss_synch_t sss;
enum sync_pss_det pss_mode;
float threshold;
float peak_to_avg;
int force_N_id_2;
int N_id_2;
int N_id_1;
int slot_id;
float find_threshold;
float track_threshold;
float peak_value;
uint32_t N_id_2;
uint32_t N_id_1;
uint32_t slot_id;
uint32_t fft_size;
uint32_t find_frame_size;
float cfo;
lte_cp_t cp;
bool detect_cp;
bool sss_en;
lte_cp_t cp;
}sync_t;
LIBLTE_API int sync_init(sync_t *q, int frame_size);
LIBLTE_API int sync_init(sync_t *q,
uint32_t find_frame_size,
uint32_t track_frame_size,
uint32_t fft_size);
LIBLTE_API void sync_free(sync_t *q);
/* Runs the synchronization algorithm. input signal must be sampled at 1.92 MHz and should be frame_size long at least */
LIBLTE_API int sync_run(sync_t *q, cf_t *input);
LIBLTE_API int sync_realloc(sync_t *q,
uint32_t find_frame_size,
uint32_t track_frame_size,
uint32_t fft_size);
/* Finds a correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be
subframe_size long at least */
LIBLTE_API int sync_find(sync_t *q,
cf_t *input,
uint32_t *peak_position);
/* Tracks the correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be
TRACK_LEN long at least */
LIBLTE_API int sync_track(sync_t *q,
cf_t *input,
uint32_t offset,
uint32_t *peak_position);
/* Sets the threshold for peak comparison */
LIBLTE_API void sync_set_threshold(sync_t *q, float threshold);
LIBLTE_API void sync_set_threshold(sync_t *q,
float find_threshold,
float track_threshold);
/* Set peak comparison to absolute value */
LIBLTE_API void sync_pss_det_absolute(sync_t *q);
/* Set peak comparison to relative to the mean */
LIBLTE_API void sync_pss_det_peak_to_avg(sync_t *q);
/* Forces the synchronizer to check one N_id_2 PSS sequence only (useful for tracking mode) */
LIBLTE_API void sync_force_N_id_2(sync_t *q, int force_N_id_2);
/* Forces the synchronizer to skip CP detection (useful for tracking mode) */
LIBLTE_API void sync_force_cp(sync_t *q, lte_cp_t cp);
/* Enables/Disables SSS detection (useful for tracking mode) */
LIBLTE_API void sync_sss_en(sync_t *q, bool enabled);
/* Gets the slot id (0 or 10) */
LIBLTE_API int sync_get_slot_id(sync_t *q);
LIBLTE_API uint32_t sync_get_slot_id(sync_t *q);
/* Gets the last peak-to-average ratio */
LIBLTE_API float sync_get_peak_to_avg(sync_t *q);
LIBLTE_API float sync_get_peak_value(sync_t *q);
/* Gets the N_id_2 from the last call to synch_run() */
LIBLTE_API int sync_get_N_id_2(sync_t *q);
LIBLTE_API uint32_t sync_get_N_id_2(sync_t *q);
/* Gets the N_id_1 from the last call to synch_run() */
LIBLTE_API int sync_get_N_id_1(sync_t *q);
LIBLTE_API uint32_t sync_get_N_id_1(sync_t *q);
/* Gets the Physical CellId from the last call to synch_run() */
LIBLTE_API int sync_get_cell_id(sync_t *q);
/* Gets the CFO estimation from the last call to synch_run() */
LIBLTE_API float sync_get_cfo(sync_t *q);
/* Gets the CP length estimation from the last call to synch_run() */
LIBLTE_API lte_cp_t sync_get_cp(sync_t *q);
/* Enables/Disables SSS detection */
LIBLTE_API void sync_sss_en(sync_t *q,
bool enabled);
LIBLTE_API bool sync_sss_detected(sync_t *q);
/* Enables/Disables CP detection */
LIBLTE_API void sync_cp_en(sync_t *q,
bool enabled);
#endif // SYNC_

@ -38,7 +38,7 @@ LIBLTE_API uint32_t bit_unpack(char **bits, int nof_bits);
LIBLTE_API void bit_pack(uint32_t value, char **bits, int nof_bits);
LIBLTE_API void bit_fprint(FILE *stream, char *bits, int nof_bits);
LIBLTE_API unsigned int bit_diff(char *x, char *y, int nbits);
LIBLTE_API int bit_count(unsigned int n);
LIBLTE_API uint32_t bit_count(uint32_t n);
#endif // BIT_

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

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

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

@ -30,51 +30,79 @@
#define VECTOR_
#include <stdio.h>
#include <stdint.h>
#include "liblte/config.h"
typedef _Complex float cf_t;
/** Return the sum of all the elements */
LIBLTE_API int vec_acc_ii(int *x, int len);
LIBLTE_API float vec_acc_ff(float *x, int len);
LIBLTE_API cf_t vec_acc_cc(cf_t *x, int len);
LIBLTE_API int vec_acc_ii(int *x, uint32_t len);
LIBLTE_API float vec_acc_ff(float *x, uint32_t len);
LIBLTE_API cf_t vec_acc_cc(cf_t *x, uint32_t len);
LIBLTE_API void *vec_malloc(int size);
LIBLTE_API void *vec_malloc(uint32_t size);
LIBLTE_API void *vec_realloc(void *ptr, uint32_t old_size, uint32_t new_size);
/* print vectors */
LIBLTE_API void vec_fprint_c(FILE *stream, cf_t *x, int len);
LIBLTE_API void vec_fprint_f(FILE *stream, float *x, int len);
LIBLTE_API void vec_fprint_b(FILE *stream, char *x, int len);
LIBLTE_API void vec_fprint_i(FILE *stream, int *x, int len);
LIBLTE_API void vec_fprint_c(FILE *stream, cf_t *x, uint32_t len);
LIBLTE_API void vec_fprint_f(FILE *stream, float *x, uint32_t len);
LIBLTE_API void vec_fprint_b(FILE *stream, char *x, uint32_t len);
LIBLTE_API void vec_fprint_i(FILE *stream, int *x, uint32_t len);
LIBLTE_API void vec_fprint_hex(FILE *stream, char *x, uint32_t len);
/* Saves a vector to a file */
LIBLTE_API void vec_save_file(char *filename, void *buffer, uint32_t len);
/* sum two vectors */
LIBLTE_API void vec_sum_ch(char *z, char *x, char *y, int len);
LIBLTE_API void vec_sum_ccc(cf_t *z, cf_t *x, cf_t *y, int len);
LIBLTE_API void vec_sum_ch(char *x, char *y, char *z, uint32_t len);
LIBLTE_API void vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
/* substract two vectors z=x-y */
LIBLTE_API void vec_sub_fff(float *x, float *y, float *z, uint32_t len);
/* scalar product */
LIBLTE_API void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, int len);
LIBLTE_API void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, int len);
LIBLTE_API void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len);
LIBLTE_API void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len);
LIBLTE_API void vec_sc_prod_fff(float *x, float h, float *z, uint32_t len);
LIBLTE_API void vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len);
LIBLTE_API void vec_deinterleave_cf(cf_t *x, float *real, float *imag, uint32_t len);
/* vector product (element-wise) */
LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, int len);
LIBLTE_API void vec_prod_ccc_unalign(cf_t *x, cf_t *y, cf_t *z, int len);
LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
/* vector product (element-wise) */
LIBLTE_API void vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len);
/* conjugate vector product (element-wise) */
LIBLTE_API void vec_prod_conj_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
/* Dot-product */
LIBLTE_API cf_t vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len);
LIBLTE_API cf_t vec_dot_prod_conj_ccc(cf_t *x, cf_t *y, uint32_t len);
LIBLTE_API float vec_dot_prod_fff(float *x, float *y, uint32_t len);
/* z=x/y vector division (element-wise) */
LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, int len);
LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
/* conjugate */
LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, int len);
LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, uint32_t len);
/* average vector power */
LIBLTE_API float vec_avg_power_cf(cf_t *x, int len);
LIBLTE_API float vec_avg_power_cf(cf_t *x, uint32_t len);
/* return the index of the maximum value in the vector */
LIBLTE_API int vec_max_fi(float *x, int len);
LIBLTE_API uint32_t vec_max_fi(float *x, uint32_t len);
/* quantify vector of floats and convert to unsigned char */
LIBLTE_API void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, int len);
LIBLTE_API void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, uint32_t len);
/* magnitude of each vector element */
LIBLTE_API void vec_abs_cf(cf_t *x, float *abs, int len);
LIBLTE_API void vec_abs_cf(cf_t *x, float *abs, uint32_t len);
/* argument of each vector element */
LIBLTE_API void vec_arg_cf(cf_t *x, float *arg, uint32_t len);
#endif // VECTOR_

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

@ -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 <string.h>
#include <complex.h>
#include <assert.h>
#include <math.h>
#include "liblte/phy/ch_estimation/chest.h"
#include "liblte/phy/resampling/interp.h"
#include "liblte/phy/utils/vector.h"
#include "liblte/phy/utils/debug.h"
#define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz)
#define SF_SZ(q) (2 * SLOT_SZ(q))
void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
//#define VOLK_INTERP
void chest_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) {
chest_ref_fprint(q, stream, nslot, port_id);
chest_recvsig_fprint(q, stream, nslot, port_id);
chest_ce_fprint(q, stream, nslot, port_id);
}
void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
/* Sets the number of ports to estimate. nof_ports must be smaler than nof_ports
* used during the call to chest_init().
*/
int chest_set_nof_ports(chest_t *q, uint32_t nof_ports) {
if (nof_ports < q->nof_ports) {
q->nof_ports = nof_ports;
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
void chest_ref_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) {
int i;
fprintf(stream, "refs%d=[",port_id);
for (i=0;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");
}
void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
void chest_recvsig_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) {
int i;
fprintf(stream, "recvsig%d=[",port_id);
for (i=0;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");
}
void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
void chest_ce_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) {
int i;
fprintf(stream, "mag%d=[",port_id);
for (i=0;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");
}
void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref) {
int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint32_t nref) {
int fidx, tidx;
cf_t known_ref, channel_ref;
fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index
tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index
known_ref = q->refsignal[port_id][nslot].refs[nref].simbol;
channel_ref = input[SAMPLE_IDX(q->nof_prb, tidx, fidx)];
q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref;
DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, SAMPLE_IDX(q->nof_prb, tidx, fidx),
10*log10f(cabsf(channel_ref/known_ref)),
cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,cargf(channel_ref/known_ref)/M_PI);
/* 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;
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
input != NULL &&
nslot < NSLOTS_X_FRAME &&
port_id < q->nof_ports)
{
if (nref < q->refsignal[port_id][nslot].nof_refs) {
fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index
tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index
known_ref = q->refsignal[port_id][nslot].refs[nref].simbol;
channel_ref = input[tidx * q->nof_re + fidx];
q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref;
DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, tidx * q->nof_re + fidx,
10*log10f(cabsf(channel_ref/known_ref)),
cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,
cargf(channel_ref/known_ref)/M_PI);
/* FIXME: compare with threshold */
if (channel_ref != 0) {
q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref;
} else {
q->refsignal[port_id][nslot].ch_est[nref] = 0;
}
ret = LIBLTE_SUCCESS;
}
}
return ret;
}
/* Computes channel estimates for each reference in a slot and port.
* Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce
*/
void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_id) {
int i, j;
int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32_t port_id) {
uint32_t i, j;
cf_t x[2], y[MAX_NSYMB];
assert(nslot >= 0 && nslot < NSLOTS_X_FRAME);
assert(port_id >= 0 && port_id < q->nof_ports);
assert(q->refsignal[port_id][nslot].nsymbols <= 2);
refsignal_t *r = &q->refsignal[port_id][nslot];
INFO("Estimating channel slot=%d port=%d using %d reference signals\n",
nslot, port_id, r->nof_refs);
for (i=0;i<r->nof_refs;i++) {
chest_ce_ref(q, input, nslot, port_id, i);
}
/* interpolate the symbols with references
* in the freq domain */
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);
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
input != NULL &&
nslot < NSLOTS_X_FRAME &&
port_id < q->nof_ports)
{
if (q->refsignal[port_id][nslot].nsymbols <= 2) {
refsignal_t *r = &q->refsignal[port_id][nslot];
INFO("Estimating channel slot=%d port=%d using %d reference signals\n",
nslot, port_id, r->nof_refs);
for (i=0;i<r->nof_refs;i++) {
chest_ce_ref(q, input, nslot, port_id, i);
}
}
/* now interpolate in the time domain */
for (i=0;i<q->nof_prb * RE_X_RB; i++) {
if (r->nsymbols > 1) {
for (j=0;j<r->nsymbols;j++) {
x[j] = ce[r->symbols_ref[j] * q->nof_prb * RE_X_RB + i];
/* interpolate the symbols with references
* in the freq domain */
for (i=0;i<r->nsymbols;i++) {
#ifdef VOLK_INTERP
interp_run_offset(&q->interp_freq[port_id],
&r->ch_est[i * r->nof_refs/2], &ce[r->symbols_ref[i] * q->nof_re],
r->voffset, RE_X_RB/2-r->voffset);
#else
interp_linear_offset(&r->ch_est[i * r->nof_refs/2],
&ce[r->symbols_ref[i] * q->nof_re], RE_X_RB/2,
r->nof_refs/2, r->voffset, RE_X_RB/2-r->voffset);
#endif
}
interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0],
2, r->symbols_ref[0], 3);
} else {
for (j=0;j<MAX_NSYMB;j++) {
y[j] = ce[r->symbols_ref[0] * q->nof_prb * RE_X_RB + i];
/* now interpolate in the time domain */
for (i=0;i<q->nof_re; i++) {
if (r->nsymbols > 1) {
for (j=0;j<r->nsymbols;j++) {
x[j] = ce[r->symbols_ref[j] * q->nof_re + i];
}
#ifdef VOLK_INTERP
interp_run_offset(&q->interp_time[port_id], x, y,
r->symbols_ref[0], 3);
#else
interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0],
2, r->symbols_ref[0], 3);
#endif
} else {
for (j=0;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.
* Saves the result for the p-th port to the pointer ce[p]
/* Computes channel estimates for each reference in a slot for all ports.
*/
void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot) {
int p;
int chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, uint32_t nslot) {
int p, ret;
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) {
if (nof_ports > MAX_PORTS) {
fprintf(stderr, "Error: Maximum ports %d\n", MAX_PORTS);
return -1;
/* Computes channel estimates for each reference in a subframe for all ports.
*/
int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint32_t sf_idx) {
int p, n, slotsz, ret;
slotsz = q->nof_symbols*q->nof_re;
for (p=0;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));
q->nof_ports = nof_ports;
q->nof_symbols = CP_NSYMB(cp);
q->cp = cp;
q->nof_prb = nof_prb;
return LIBLTE_SUCCESS;
}
switch(interp) {
case LINEAR:
q->interp = interp_linear_offset;
int chest_init(chest_t *q, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_ports) {
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
nof_ports <= MAX_PORTS)
{
bzero(q, sizeof(chest_t));
q->nof_ports = nof_ports;
q->nof_symbols = nof_symbols;
q->nof_re = nof_re;
INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n",
q->nof_symbols, q->nof_re, nof_ports);
ret = LIBLTE_SUCCESS;
}
INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n",
q->nof_symbols, nof_prb, nof_ports);
return 0;
return ret;
}
int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id) {
if (port < 0 || port > q->nof_ports) {
return -1;
}
if (nslot < 0 || nslot > NSLOTS_X_FRAME) {
return -1;
int chest_init_LTEDL(chest_t *q, lte_cell_t cell) {
int ret;
ret = chest_init(q, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports);
if (ret != LIBLTE_SUCCESS) {
return ret;
} else {
return chest_ref_LTEDL(q, cell);
}
}
if (refsignal_init_LTEDL(&q->refsignal[port][nslot], port, nslot, cell_id, q->cp, q->nof_prb)) {
fprintf(stderr, "Error initiating CRS port=%d, slot=%d\n", port, nslot);
return -1;
int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_cell_t cell) {
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
port_id < MAX_PORTS &&
nslot < NSLOTS_X_FRAME)
{
ret = refsignal_init_LTEDL(&q->refsignal[port_id][nslot], port_id, nslot, cell);
if (ret == LIBLTE_SUCCESS) {
if (nslot == 0) {
ret = interp_init(&q->interp_freq[port_id], LINEAR, q->refsignal[port_id][nslot].nof_refs/2, RE_X_RB/2);
if (ret == LIBLTE_SUCCESS) {
ret = interp_init(&q->interp_time[port_id], LINEAR, 2,
q->refsignal[port_id][nslot].symbols_ref[1] - q->refsignal[port_id][nslot].symbols_ref[0]);
}
}
}
}
return 0;
return ret;
}
int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id) {
int p;
int chest_ref_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) {
int p, ret;
for (p=0;p<q->nof_ports;p++) {
if (chest_ref_LTEDL_slot_port(q, p, nslot, cell_id)) {
return -1;
ret = chest_ref_LTEDL_slot_port(q, nslot, p, cell);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
}
return 0;
return LIBLTE_SUCCESS;
}
int chest_ref_LTEDL(chest_t *q, int cell_id) {
int n;
int chest_ref_LTEDL(chest_t *q, lte_cell_t cell) {
int n, ret;
for (n=0;n<NSLOTS_X_FRAME;n++) {
if (chest_ref_LTEDL_slot(q, n, cell_id)) {
return -1;
ret = chest_ref_LTEDL_slot(q, n, cell);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
}
return 0;
return LIBLTE_SUCCESS;
}
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.
* 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]) {
if (nslot < 0 || nslot > NSLOTS_X_FRAME) {
return -1;
int chest_ref_symbols(chest_t *q, uint32_t port_id, uint32_t nslot, uint32_t l[2]) {
if (q != NULL &&
port_id < MAX_PORTS &&
nslot < NSLOTS_X_FRAME)
{
memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(uint32_t) * q->refsignal[port_id][nslot].nsymbols);
return q->refsignal[port_id][nslot].nsymbols;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(int) * q->refsignal[port_id][nslot].nsymbols);
return q->refsignal[port_id][nslot].nsymbols;
}
@ -245,6 +342,8 @@ int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]) {
*/
int chest_initialize(chest_hl* h) {
lte_cell_t cell;
if (!h->init.nof_symbols) {
h->init.nof_symbols = CPNORM_NSYMB; // Normal CP
}
@ -252,37 +351,23 @@ int chest_initialize(chest_hl* h) {
h->init.nof_prb = 6;
}
if (chest_init(&h->obj, LINEAR, (h->init.nof_symbols==CPNORM_NSYMB)?CPNORM:CPEXT,
h->init.nof_prb, h->init.nof_ports)) {
cell.id = h->init.cell_id;
cell.nof_ports = h->init.nof_ports;
cell.nof_prb = h->init.nof_prb;
cell.cp = h->init.nof_symbols == CPNORM_NSYMB ? CPNORM : CPEXT;
if (chest_init_LTEDL(&h->obj, cell)) {
fprintf(stderr, "Error initializing equalizer\n");
return -1;
}
if (h->init.cell_id != -1) {
if (chest_ref_LTEDL(&h->obj, h->init.cell_id)) {
fprintf(stderr, "Error initializing reference signal\n");
return -1;
}
}
return 0;
}
/** This function must be called in an slot basis (0.5ms) for LTE */
/** This function must be called in an subframe basis (1ms) for LTE */
int chest_work(chest_hl* hl) {
int i;
chest_t *q = &hl->obj;
if (hl->init.cell_id != hl->ctrl_in.cell_id) {
if (chest_ref_LTEDL(q, hl->init.cell_id)) {
fprintf(stderr, "Error initializing reference signal\n");
return -1;
}
}
for (i=0;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;
}
chest_ce_sf(q, hl->input, hl->output, hl->ctrl_in.sf_idx);
return 0;
}

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

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

@ -35,10 +35,10 @@
#include "liblte/phy/utils/debug.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);
if (symbol_sz == -1) {
if (symbol_sz < 0) {
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
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");
return -1;
}
q->tmp = malloc(symbol_sz * sizeof(cf_t));
q->tmp = malloc((uint32_t) symbol_sz * sizeof(cf_t));
if (!q->tmp) {
perror("malloc");
return -1;
@ -56,15 +56,18 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) {
dft_plan_set_norm(&q->fft_plan, true);
dft_plan_set_dc(&q->fft_plan, true);
q->symbol_sz = symbol_sz;
q->nof_symbols = CP_NSYMB(cp_type);
q->cp_type = cp_type;
q->symbol_sz = (uint32_t) symbol_sz;
q->nof_symbols = CP_NSYMB(cp);
q->cp = cp;
q->nof_re = nof_prb * RE_X_RB;
q->nof_guards = ((symbol_sz - q->nof_re) / 2);
DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp_type=%s, nof_re=%d, nof_guards=%d\n",
q->slot_sz = SLOT_LEN(symbol_sz, cp);
DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp=%s, nof_re=%d, nof_guards=%d\n",
dir==FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols,
q->cp_type==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards);
return 0;
q->cp==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards);
return LIBLTE_SUCCESS;
}
void lte_fft_free_(lte_fft_t *q) {
@ -75,25 +78,28 @@ void lte_fft_free_(lte_fft_t *q) {
bzero(q, sizeof(lte_fft_t));
}
int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) {
return lte_fft_init_(q, cp_type, nof_prb, FORWARD);
int lte_fft_init(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb) {
return lte_fft_init_(q, cp, nof_prb, FORWARD);
}
void lte_fft_free(lte_fft_t *q) {
lte_fft_free_(q);
}
int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) {
int i;
if (lte_fft_init_(q, cp_type, nof_prb, BACKWARD)) {
return -1;
int lte_ifft_init(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb) {
uint32_t i;
int ret;
ret = lte_fft_init_(q, cp, nof_prb, BACKWARD);
if (ret == LIBLTE_SUCCESS) {
/* set now zeros at CP */
for (i=0;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 */
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;
return ret;
}
void lte_ifft_free(lte_fft_t *q) {
@ -103,10 +109,10 @@ void lte_ifft_free(lte_fft_t *q) {
/* Transforms input samples into output OFDM symbols.
* Performs FFT on a each symbol and removes CP.
*/
void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output) {
int i;
void lte_fft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) {
uint32_t i;
for (i=0;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);
memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t));
input += q->symbol_sz;
@ -114,13 +120,20 @@ void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output) {
}
}
void lte_fft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output) {
uint32_t n;
for (n=0;n<2;n++) {
lte_fft_run_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]);
}
}
/* Transforms input OFDM symbols into output samples.
* Performs FFT on a each symbol and adds CP.
*/
void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output) {
int i, cp_len;
void lte_ifft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) {
uint32_t i, cp_len;
for (i=0;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));
dft_run_c(&q->fft_plan, q->tmp, &output[cp_len]);
input += q->nof_re;
@ -130,3 +143,9 @@ void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output) {
}
}
void lte_ifft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output) {
uint32_t n;
for (n=0;n<2;n++) {
lte_ifft_run_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]);
}
}

@ -50,36 +50,115 @@ const int tc_cb_sizes[NOF_TC_CB_SIZES] = { 40, 48, 56, 64, 72, 80, 88, 96, 104,
4800, 4864, 4928, 4992, 5056, 5120, 5184, 5248, 5312, 5376, 5440, 5504,
5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144 };
/* Returns true if the structure pointed by cell has valid parameters
*/
bool lte_cell_isvalid(lte_cell_t *cell) {
if (cell->id < 504 &&
cell->nof_ports > 0 &&
cell->nof_ports < MAX_PORTS+1 &&
cell->nof_prb > 5 &&
cell->nof_prb < MAX_PRB+1
) {
return true;
} else {
return false;
}
}
bool lte_N_id_2_isvalid(uint32_t N_id_2) {
if (N_id_2 < 3) {
return true;
} else {
return false;
}
}
bool lte_N_id_1_isvalid(uint32_t N_id_1) {
if (N_id_1 < 169) {
return true;
} else {
return false;
}
}
/*
* Returns Turbo coder interleaver size for Table 5.1.3-3 (36.212) index
*/
int lte_cb_size(int index) {
if (index >= 0 && index < NOF_TC_CB_SIZES) {
int lte_cb_size(uint32_t index) {
if (index < NOF_TC_CB_SIZES) {
return tc_cb_sizes[index];
} else {
return -1;
return LIBLTE_ERROR;
}
}
char *lte_mod_string(lte_mod_t mod) {
switch (mod) {
case LTE_BPSK:
return "BPSK";
case LTE_QPSK:
return "QPSK";
case LTE_QAM16:
return "QAM16";
case LTE_QAM64:
return "QAM64";
default:
return "N/A";
}
}
uint32_t lte_mod_bits_x_symbol(lte_mod_t mod) {
switch (mod) {
case LTE_BPSK:
return 1;
case LTE_QPSK:
return 2;
case LTE_QAM16:
return 4;
case LTE_QAM64:
return 6;
default:
return 0;
}
}
char *lte_cp_string(lte_cp_t cp) {
if (cp == CPNORM) {
return "Normal";
} else {
return "Extended";
}
}
/*
* Finds index of minimum K>=long_cb in Table 5.1.3-3 of 36.212
*/
int lte_find_cb_index(int long_cb) {
int lte_find_cb_index(uint32_t long_cb) {
int j = 0;
while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) {
j++;
}
if (j == NOF_TC_CB_SIZES) {
return -1;
return LIBLTE_ERROR;
} else {
return j;
}
}
const int lte_symbol_sz(int nof_prb) {
int lte_sampling_freq_hz(uint32_t nof_prb) {
int n = lte_symbol_sz(nof_prb);
if (n == -1) {
return LIBLTE_ERROR;
} else {
return 15000 * n;
}
}
int lte_symbol_sz(uint32_t nof_prb) {
if (nof_prb<=0) {
return -1;
return LIBLTE_ERROR;
}
if (nof_prb<=6) {
return 128;
@ -94,10 +173,22 @@ const int lte_symbol_sz(int nof_prb) {
} else if (nof_prb<=100) {
return 2048;
}
return -1;
return LIBLTE_ERROR;
}
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) {
return (cell_id+3) % 6;
} else {
@ -106,7 +197,7 @@ int lte_voffset(int symbol_id, int cell_id, int nof_ports) {
}
/* Returns the number of available RE per PRB */
int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) {
uint32_t lte_re_x_prb(uint32_t ns, uint32_t symbol, uint32_t nof_ports, uint32_t nof_symbols) {
if (symbol == 0) {
if (((ns % 2) == 0) || (ns == 1)) {
return RE_X_RB - 4;
@ -138,10 +229,10 @@ int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) {
struct lte_band {
int band;
uint32_t band;
float fd_low_mhz;
int earfcn_offset;
int earfcn_max;
uint32_t earfcn_offset;
uint32_t earfcn_max;
enum band_geographical_area area;
};
@ -186,9 +277,9 @@ int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type) {
} else if (!strcmp(mimo_type_str, "multiplex")) {
*type = SPATIAL_MULTIPLEX;
} else {
return -1;
return LIBLTE_ERROR;
}
return 0;
return LIBLTE_SUCCESS;
}
char *lte_mimotype2str(lte_mimo_type_t type) {
@ -203,12 +294,16 @@ char *lte_mimotype2str(lte_mimo_type_t type) {
return NULL;
}
float get_fd(struct lte_band *band, int earfcn) {
return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset);
float get_fd(struct lte_band *band, uint32_t earfcn) {
if (earfcn > band->earfcn_offset) {
return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset);
} else {
return 0.0;
}
}
float lte_band_fd(int earfcn) {
int i;
float lte_band_fd(uint32_t earfcn) {
uint32_t i;
i=0;
while(i < NOF_LTE_BANDS && lte_bands[i].earfcn_offset<earfcn) {
i++;
@ -220,27 +315,27 @@ float lte_band_fd(int 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);
}
int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int start_earfcn, int end_earfcn, int max_elems) {
int i, j;
int nof_earfcn;
int lte_band_get_fd_band(uint32_t band, lte_earfcn_t *earfcn, int start_earfcn, int end_earfcn, uint32_t max_elems) {
uint32_t i, j;
uint32_t nof_earfcn;
i=0;
while(i < NOF_LTE_BANDS && lte_bands[i].band != band) {
i++;
}
if (i == NOF_LTE_BANDS) {
fprintf(stderr, "Error: Invalid band %d\n", band);
return -1;
return LIBLTE_ERROR;
}
if (end_earfcn == -1) {
end_earfcn = lte_bands[i].earfcn_max;
} else {
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);
return -1;
return LIBLTE_ERROR;
}
}
if (start_earfcn == -1) {
@ -248,7 +343,7 @@ int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int start_earfcn, int e
} else {
if (start_earfcn < lte_bands[i].earfcn_offset) {
fprintf(stderr, "Error: Invalid start earfcn %d. Min is %d\n", start_earfcn, lte_bands[i].earfcn_offset);
return -1;
return LIBLTE_ERROR;
}
}
nof_earfcn = end_earfcn - start_earfcn;
@ -260,11 +355,11 @@ int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int start_earfcn, int e
earfcn[j].id = j + start_earfcn;
earfcn[j].fd = get_fd(&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 i;
int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, uint32_t max_elems) {
uint32_t i;
int n;
int nof_fd = 0;
for (i=0;i<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;
max_elems -= n;
} else {
return -1;
return LIBLTE_ERROR;
}
}
}

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

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

@ -28,33 +28,41 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include "liblte/phy/fec/convcoder.h"
#include "parity.h"
int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length) {
unsigned int sr;
int i,j;
int len = q->tail_biting ? frame_length : (frame_length + q->K - 1);
int convcoder_encode(convcoder_t *q, char *input, char *output, uint32_t frame_length) {
uint32_t sr;
uint32_t i,j;
uint32_t len = q->tail_biting ? frame_length : (frame_length + q->K - 1);
if (q->tail_biting) {
sr = 0;
for (i=frame_length - q->K + 1; i<frame_length; i++) {
sr = (sr << 1) | (input[i] & 1);
if (q != NULL &&
input != NULL &&
output != NULL &&
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 {
sr = 0;
}
for (i = 0; i < len; i++) {
int bit = (i < frame_length) ? (input[i] & 1) : 0;
sr = (sr << 1) | bit;
for (j=0;j<q->R;j++) {
output[q->R * i + j] = parity(sr & q->poly[j]);
for (i = 0; i < len; i++) {
char bit = (i < frame_length) ? (input[i] & 1) : 0;
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;
}
unsigned int crc_checksum(crc_t *h, char *data, int len) {
uint32_t crc_checksum(crc_t *h, char *data, int len) {
int i, k, len8, res8, a = 0;
unsigned int crc = 0;
char *pter;

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

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

@ -27,25 +27,27 @@
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include "liblte/phy/fec/rm_conv.h"
#define NCOLS 32
#define NROWS_MAX NCOLS
unsigned char RM_PERM_CC[NCOLS] = { 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27,
uint8_t RM_PERM_CC[NCOLS] = { 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27,
7, 23, 15, 31, 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30 };
unsigned char RM_PERM_CC_INV[NCOLS] =
uint8_t RM_PERM_CC_INV[NCOLS] =
{ 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26, 10, 22, 6, 30, 14, 17, 1, 25, 9,
21, 5, 29, 13, 19, 3, 27, 11, 23, 7, 31, 15 };
int rm_conv_tx(char *input, int in_len, char *output, int out_len) {
int rm_conv_tx(char *input, uint32_t in_len, char *output, uint32_t out_len) {
char tmp[3 * NCOLS * NROWS_MAX];
int nrows, ndummy, K_p;
int i, j, k, s;
nrows = (int) (in_len / 3 - 1) / NCOLS + 1;
nrows = (uint32_t) (in_len / 3 - 1) / NCOLS + 1;
if (nrows > NROWS_MAX) {
fprintf(stderr, "Input too large. Max input length is %d\n",
3 * NCOLS * NROWS_MAX);
@ -89,7 +91,7 @@ int rm_conv_tx(char *input, int in_len, char *output, int out_len) {
/* Undoes Convolutional Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.2
*/
int rm_conv_rx(float *input, int in_len, float *output, int out_len) {
int rm_conv_rx(float *input, uint32_t in_len, float *output, uint32_t out_len) {
int nrows, ndummy, K_p;
int i, j, k;
@ -97,7 +99,7 @@ int rm_conv_rx(float *input, int in_len, float *output, int out_len) {
float tmp[3 * NCOLS * NROWS_MAX];
nrows = (int) (out_len / 3 - 1) / NCOLS + 1;
nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1;
if (nrows > NROWS_MAX) {
fprintf(stderr, "Output too large. Max output length is %d\n",
3 * NCOLS * NROWS_MAX);

@ -30,50 +30,43 @@
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "liblte/phy/fec/rm_turbo.h"
#define NCOLS 32
#define NROWS_MAX NCOLS
unsigned char RM_PERM_TC[NCOLS] = { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26,
uint8_t RM_PERM_TC[NCOLS] = { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26,
6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 };
int rm_turbo_init(rm_turbo_t *q, int buffer_len) {
q->buffer_len = buffer_len;
q->buffer = malloc(buffer_len * sizeof(float));
if (!q->buffer) {
perror("malloc");
return -1;
}
return 0;
}
void rm_turbo_free(rm_turbo_t *q) {
if (q->buffer) {
free(q->buffer);
}
}
/* Turbo Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.1
*
* If rv_idx==0, the circular buffer w_buff is filled with all redundancy versions and
* the corresponding version of length out_len is saved in the output buffer.
* Otherwise, the corresponding version is directly obtained from w_buff and saved into output.
*
* Note that calling this function with rv_idx!=0 without having called it first with rv_idx=0
* will produce unwanted results.
*
* TODO: Soft buffer size limitation according to UE category
*/
int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output,
int out_len, int rv_idx) {
int rm_turbo_tx(char *w_buff, uint32_t w_buff_len, char *input, uint32_t in_len, char *output,
uint32_t out_len, uint32_t rv_idx) {
char *tmp = (char*) q->buffer;
int nrows, ndummy, K_p;
int ndummy, kidx;
int nrows, K_p;
int i, j, k, s, kidx, N_cb, k0;
int i, j, k, s, N_cb, k0;
nrows = (int) (in_len / 3 - 1) / NCOLS + 1;
nrows = (uint32_t) (in_len / 3 - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
if (3 * K_p > w_buff_len) {
fprintf(stderr,
"Input too large. Max input length including dummy bits is %d (3x%dx32, in_len %d)\n",
q->buffer_len, nrows, in_len);
w_buff_len, nrows, in_len);
return -1;
}
@ -82,47 +75,49 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output,
ndummy = 0;
}
/* Sub-block interleaver (5.1.4.1.1) and bit collection */
k = 0;
for (s = 0; s < 2; s++) {
for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) {
if (s == 0) {
kidx = k % K_p;
} else {
kidx = K_p + 2 * (k % K_p);
}
if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
tmp[kidx] = TX_NULL;
} else {
tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
if (rv_idx == 0) {
/* Sub-block interleaver (5.1.4.1.1) and bit collection */
k = 0;
for (s = 0; s < 2; s++) {
for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) {
if (s == 0) {
kidx = k % K_p;
} else {
kidx = K_p + 2 * (k % K_p);
}
if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
w_buff[kidx] = TX_NULL;
} else {
w_buff[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
}
k++;
}
k++;
}
}
}
// d_k^(2) goes through special permutation
for (k = 0; k < K_p; k++) {
kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) {
tmp[K_p + 2 * k + 1] = TX_NULL;
} else {
tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
// d_k^(2) goes through special permutation
for (k = 0; k < K_p; k++) {
kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) {
w_buff[K_p + 2 * k + 1] = TX_NULL;
} else {
w_buff[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
}
}
}
/* Bit selection and transmission 5.1.4.1.2 */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows
* (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2);
* (2 * (uint32_t) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2);
k = 0;
j = 0;
while (k < out_len) {
if (tmp[(k0 + j) % N_cb] != TX_NULL) {
output[k] = tmp[(k0 + j) % N_cb];
if (w_buff[(k0 + j) % N_cb] != TX_NULL) {
output[k] = w_buff[(k0 + j) % N_cb];
k++;
}
j++;
@ -132,23 +127,24 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output,
/* Undoes Turbo Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.1
*
* If rv_idx==0, the w_buff circular buffer is initialized. Every subsequent call
* with rv_idx!=0 will soft-combine the LLRs from input with w_buff
*/
int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
int out_len, int rv_idx) {
int rm_turbo_rx(float *w_buff, uint32_t w_buff_len, float *input, uint32_t in_len, float *output,
uint32_t out_len, uint32_t rv_idx) {
int nrows, ndummy, K_p, k0, N_cb, jp, kidx;
int i, j, k;
int d_i, d_j;
bool isdummy;
float *tmp = (float*) q->buffer;
nrows = (int) (out_len / 3 - 1) / NCOLS + 1;
nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
if (3 * K_p > w_buff_len) {
fprintf(stderr,
"Input too large. Max output length including dummy bits is %d (3x%dx32, in_len %d)\n",
q->buffer_len, nrows, out_len);
w_buff_len, nrows, out_len);
return -1;
}
@ -157,14 +153,16 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
ndummy = 0;
}
for (i = 0; i < 3 * K_p; i++) {
tmp[i] = RX_NULL;
if (rv_idx == 0) {
for (i = 0; i < 3 * K_p; i++) {
w_buff[i] = RX_NULL;
}
}
/* Undo bit collection. Account for dummy bits */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows
* (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2);
* (2 * (uint32_t) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2);
k = 0;
j = 0;
@ -185,7 +183,7 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
isdummy = true;
}
} else {
int jpp = (jp - K_p - 1) / 2;
uint32_t jpp = (jp - K_p - 1) / 2;
kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) {
isdummy = true;
@ -195,10 +193,10 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
}
if (!isdummy) {
if (tmp[jp] == RX_NULL) {
tmp[jp] = input[k];
if (w_buff[jp] == RX_NULL) {
w_buff[jp] = input[k];
} else if (input[k] != RX_NULL) {
tmp[jp] += input[k]; /* soft combine LLRs */
w_buff[jp] += input[k]; /* soft combine LLRs */
}
k++;
}
@ -213,15 +211,14 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
if (j != 2) {
kidx = K_p * j + (j + 1) * (RM_PERM_TC[d_j] * nrows + d_i);
} else {
k = (i + ndummy - 1) % K_p;
if (k < 0)
k += K_p;
kidx = (k / NCOLS + nrows * RM_PERM_TC[k % NCOLS]) % K_p;
kidx = 2 * kidx + K_p + 1;
}
if (tmp[kidx] != RX_NULL) {
output[i * 3 + j] = tmp[kidx];
if (w_buff[kidx] != RX_NULL) {
output[i * 3 + j] = w_buff[kidx];
} else {
output[i * 3 + j] = 0;
}
@ -233,25 +230,15 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
/** High-level API */
int rm_turbo_initialize(rm_turbo_hl* h) {
return rm_turbo_init(&h->q, 7000);
return 0;
}
/** This function can be called in a subframe (1ms) basis */
int rm_turbo_work(rm_turbo_hl* hl) {
if (hl->init.direction) {
rm_turbo_tx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.E,
hl->ctrl_in.rv_idx);
hl->out_len = hl->ctrl_in.E;
} else {
rm_turbo_rx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.S,
hl->ctrl_in.rv_idx);
hl->out_len = hl->ctrl_in.S;
}
return 0;
}
int rm_turbo_stop(rm_turbo_hl* hl) {
rm_turbo_free(&hl->q);
return 0;
}

@ -27,6 +27,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "liblte/phy/common/phy_common.h"
#include "liblte/phy/fec/tc_interl.h"
@ -39,7 +40,7 @@
*
************************************************/
const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103,
const uint32_t f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103,
15, 9, 17, 9, 21, 101, 21, 57, 23, 13, 27, 11, 27, 85, 29, 33, 15, 17, 33,
103, 19, 19, 37, 19, 21, 21, 115, 193, 21, 133, 81, 45, 23, 243, 151, 155,
25, 51, 47, 91, 29, 29, 247, 29, 89, 91, 157, 55, 31, 17, 35, 227, 65, 19,
@ -52,7 +53,7 @@ const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103,
39, 127, 39, 39, 31, 113, 41, 251, 43, 21, 43, 45, 45, 161, 89, 323, 47, 23,
47, 263 };
const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84,
const uint32_t f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84,
90, 32, 34, 108, 38, 120, 84, 44, 46, 48, 50, 52, 36, 56, 58, 60, 62, 32,
198, 68, 210, 36, 74, 76, 78, 120, 82, 84, 86, 44, 90, 46, 94, 48, 98, 40,
102, 52, 106, 72, 110, 168, 114, 58, 118, 180, 122, 62, 84, 64, 66, 68, 420,
@ -65,9 +66,9 @@ const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84,
280, 142, 480, 146, 444, 120, 152, 462, 234, 158, 80, 96, 902, 166, 336,
170, 86, 174, 176, 178, 120, 182, 184, 186, 94, 190, 480 };
int tc_interl_LTE_gen(tc_interl_t *h, int long_cb) {
int cb_table_idx, f1, f2;
unsigned long long i, j;
int tc_interl_LTE_gen(tc_interl_t *h, uint32_t long_cb) {
uint32_t cb_table_idx, f1, f2;
uint64_t i, j;
if (long_cb > h->max_long_cb) {
fprintf(stderr, "Interleaver initiated for max_long_cb=%d\n",
@ -90,8 +91,8 @@ int tc_interl_LTE_gen(tc_interl_t *h, int long_cb) {
h->reverse[0] = 0;
for (i = 1; i < long_cb; i++) {
j = (f1 * i + f2 * i * i) % (long_cb);
h->forward[i] = j;
h->reverse[j] = i;
h->forward[i] = (uint32_t) j;
h->reverse[j] = (uint32_t) i;
}
return 0;

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

@ -26,12 +26,14 @@
*/
#include "liblte/phy/fec/turbocoder.h"
#include <stdio.h>
#include <stdint.h>
#include "liblte/phy/fec/turbocoder.h"
#define NOF_REGS 3
int tcod_init(tcod_t *h, int max_long_cb) {
int tcod_init(tcod_t *h, uint32_t max_long_cb) {
if (tc_interl_init(&h->interl, max_long_cb)) {
return -1;
@ -45,13 +47,13 @@ void tcod_free(tcod_t *h) {
h->max_long_cb = 0;
}
int tcod_encode(tcod_t *h, char *input, char *output, int long_cb) {
int tcod_encode(tcod_t *h, char *input, char *output, uint32_t long_cb) {
char reg1_0, reg1_1, reg1_2, reg2_0, reg2_1, reg2_2;
int i, k = 0, j;
uint32_t i, k = 0, j;
char bit;
char in, out;
int *per;
uint32_t *per;
if (long_cb > h->max_long_cb) {
fprintf(stderr, "Turbo coder initiated for max_long_cb=%d\n",

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

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

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

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

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

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

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

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

@ -37,14 +37,14 @@ void demod_hard_init(demod_hard_t* q) {
bzero((void*) q, sizeof(demod_hard_t));
}
void demod_hard_table_set(demod_hard_t* q, enum modem_std table) {
q->table = table;
void demod_hard_table_set(demod_hard_t* q, lte_mod_t mod) {
q->mod = mod;
}
int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, int nsymbols) {
int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, uint32_t nsymbols) {
int nbits=-1;
switch(q->table) {
switch(q->mod) {
case LTE_BPSK:
hard_bpsk_demod(symbols,bits,nsymbols);
nbits=nsymbols;

@ -69,7 +69,7 @@ int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int
/* High-Level API */
int demod_soft_initialize(demod_soft_hl* hl) {
modem_table_init(&hl->table);
if (modem_table_std(&hl->table,hl->init.std,true)) {
if (modem_table_lte(&hl->table,hl->init.std,true)) {
return -1;
}
demod_soft_init(&hl->obj);

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

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

@ -45,7 +45,18 @@
void set_BPSKtable(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);
void set_BPSKtable(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 */
int mod_modulate(modem_table_t* q, const char *bits, cf_t* symbols, int nbits) {
int i,j,idx;
int mod_modulate(modem_table_t* q, const char *bits, cf_t* symbols, uint32_t nbits) {
uint32_t i,j,idx;
char *b_ptr=(char*) bits;
j=0;
for (i=0;i<nbits;i+=q->nbits_x_symbol) {
idx = bit_unpack(&b_ptr,q->nbits_x_symbol);
assert(idx >= 0 && idx < q->nsymbols);
symbols[j] = q->symbol_table[idx];
if (idx < q->nsymbols) {
symbols[j] = q->symbol_table[idx];
} else {
return LIBLTE_ERROR;
}
j++;
}
return j;
@ -52,7 +55,7 @@ int mod_modulate(modem_table_t* q, const char *bits, cf_t* symbols, int nbits) {
/* High-Level API */
int mod_initialize(mod_hl* hl) {
modem_table_init(&hl->obj);
if (modem_table_std(&hl->obj,hl->init.std,false)) {
if (modem_table_lte(&hl->obj,hl->init.std,false)) {
return -1;
}

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

@ -51,7 +51,7 @@
* \param sigma2 Noise vatiance
*/
void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
_Complex float *symbols, int (*S)[6][32], float sigma2) {
_Complex float *symbols, uint32_t (*S)[6][32], float sigma2) {
int i, s, b;
float num, den;
float new_num, new_den;
@ -112,7 +112,7 @@ void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
* \param sigma2 Noise vatiance
*/
void llr_exact(const _Complex float *in, float *out, int N, int M, int B,
_Complex float *symbols, int (*S)[6][32], float sigma2) {
_Complex float *symbols, uint32_t (*S)[6][32], float sigma2) {
int i, s, b;
float num, den;
float idiff0, qdiff0, idiff1, qdiff1;

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

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

@ -40,52 +40,86 @@
#include "liblte/phy/utils/vector.h"
#include "liblte/phy/utils/debug.h"
int dci_init(dci_t *q, int max_dcis) {
q->msg = calloc(sizeof(dci_msg_t), max_dcis);
if (!q->msg) {
perror("malloc");
return -1;
}
q->nof_dcis = 0;
q->max_dcis = max_dcis;
return 0;
}
void dci_free(dci_t *q) {
if (q->msg) {
free(q->msg);
int dci_msg_to_ra_dl(dci_msg_t *msg, uint16_t msg_rnti, uint16_t c_rnti,
lte_cell_t cell, uint32_t cfi,
ra_pdsch_t *ra_dl)
{
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (msg != NULL &&
ra_dl != NULL &&
lte_cell_isvalid(&cell) &&
cfi > 0 &&
cfi < 4)
{
ret = LIBLTE_ERROR;
dci_msg_type_t type;
if (dci_msg_get_type(msg, &type, cell.nof_prb, msg_rnti, c_rnti)) {
fprintf(stderr, "Can't get DCI message type\n");
return ret;
}
if (VERBOSE_ISDEBUG()) {
dci_msg_type_fprint(stdout, type);
}
if (type.type == PDSCH_SCHED) {
bzero(ra_dl, sizeof(ra_pdsch_t));
if (dci_msg_unpack_pdsch(msg, ra_dl, cell.nof_prb, msg_rnti != SIRNTI)) {
fprintf(stderr, "Can't unpack PDSCH message\n");
return ret;
}
if (VERBOSE_ISDEBUG()) {
ra_pdsch_fprint(stdout, ra_dl, cell.nof_prb);
}
if (ra_prb_get_dl(&ra_dl->prb_alloc, ra_dl, cell.nof_prb)) {
fprintf(stderr, "Error computing resource allocation\n");
return ret;
}
ra_prb_get_re_dl(&ra_dl->prb_alloc, cell.nof_prb, cell.nof_ports, cell.nof_prb<10?(cfi+1):cfi, cell.cp);
ret = LIBLTE_SUCCESS;
}
}
return ret;
}
void dci_candidate_fprint(FILE *f, dci_candidate_t *q) {
fprintf(f, "L: %d, nCCE: %d, RNTI: 0x%x, nBits: %d\n", q->L, q->ncce, q->rnti,
q->nof_bits);
}
int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti) {
if (L >= 0 && L <= 3) {
msg->location.L = (unsigned char) L;
int dci_location_set(dci_location_t *c, uint32_t L, uint32_t nCCE) {
if (L <= 3) {
c->L = L;
} else {
fprintf(stderr, "Invalid L %d\n", L);
return -1;
return LIBLTE_ERROR;
}
if (nCCE >= 0 && nCCE <= 87) {
msg->location.ncce = (unsigned char) nCCE;
if (nCCE <= 87) {
c->ncce = nCCE;
} else {
fprintf(stderr, "Invalid nCCE %d\n", nCCE);
return -1;
return LIBLTE_ERROR;
}
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) {
return (int) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2));
uint32_t riv_nbits(uint32_t nof_prb) {
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;
for (i = 0; i < 10; i++) {
if (size == ambiguous_sizes[i]) {
@ -98,12 +132,12 @@ bool is_ambiguous_size(int size) {
/**********************************
* PAYLOAD sizeof functions
* ********************************/
int dci_format0_sizeof_(int nof_prb) {
uint32_t dci_format0_sizeof_(uint32_t nof_prb) {
return 1 + 1 + riv_nbits(nof_prb) + 5 + 1 + 2 + 3 + 1;
}
int dci_format1A_sizeof(int nof_prb) {
int n;
uint32_t dci_format1A_sizeof(uint32_t nof_prb) {
uint32_t n;
n = 1 + 1 + riv_nbits(nof_prb) + 5 + 3 + 1 + 2 + 2;
while (n < dci_format0_sizeof_(nof_prb)) {
n++;
@ -114,17 +148,17 @@ int dci_format1A_sizeof(int nof_prb) {
return n;
}
int dci_format0_sizeof(int nof_prb) {
int n = dci_format0_sizeof_(nof_prb);
uint32_t dci_format0_sizeof(uint32_t nof_prb) {
uint32_t n = dci_format0_sizeof_(nof_prb);
while (n < dci_format1A_sizeof(nof_prb)) {
n++;
}
return n;
}
int dci_format1_sizeof(int nof_prb) {
uint32_t dci_format1_sizeof(uint32_t nof_prb) {
int n = (int) ceilf((float) nof_prb / ra_type0_P(nof_prb)) + 5 + 3 + 1 + 2
uint32_t n = (uint32_t) ceilf((float) nof_prb / ra_type0_P(nof_prb)) + 5 + 3 + 1 + 2
+ 2;
if (nof_prb > 10) {
n++;
@ -136,17 +170,17 @@ int dci_format1_sizeof(int nof_prb) {
return n;
}
int dci_format1C_sizeof(int nof_prb) {
int n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true);
int n_step = ra_type2_n_rb_step(nof_prb);
int n = +riv_nbits((int) n_vrb_dl_gap1 / n_step) + 5;
uint32_t dci_format1C_sizeof(uint32_t nof_prb) {
uint32_t n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true);
uint32_t n_step = ra_type2_n_rb_step(nof_prb);
uint32_t n = riv_nbits((uint32_t) n_vrb_dl_gap1 / n_step) + 5;
if (nof_prb >= 50) {
n++;
}
return n;
}
int dci_format_sizeof(dci_format_t format, int nof_prb) {
uint32_t dci_format_sizeof(dci_format_t format, uint32_t nof_prb) {
switch (format) {
case Format0:
return dci_format0_sizeof(nof_prb);
@ -157,7 +191,7 @@ int dci_format_sizeof(dci_format_t format, int nof_prb) {
case Format1C:
return dci_format1C_sizeof(nof_prb);
default:
return -1;
return LIBLTE_ERROR;
}
}
@ -170,11 +204,11 @@ int dci_format_sizeof(dci_format_t format, int nof_prb) {
*
* TODO: TPC and cyclic shift for DM RS not implemented
*/
int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint32_t nof_prb) {
/* pack bits */
char *y = msg->data;
int n_ul_hop;
uint32_t n_ul_hop;
*y++ = 0; // format differentiation
if (data->freq_hop_fl == hop_disabled) { // frequency hopping
@ -203,28 +237,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop);
/* pack MCS according to 8.6.1 of 36.213 */
uint32_t mcs;
if (data->cqi_request) {
mcs = 29;
} else {
if (data->rv_idx) {
mcs = 28 + data->rv_idx;
} else {
if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx;
} else {
if (data->mcs.tbs) {
if (data->mcs.tbs) {
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs,
ra_nprb_ul(data, nof_prb));
}
}
mcs = ra_mcs_to_table_idx(&data->mcs);
}
}
}
bit_pack(mcs, &y, 5);
bit_pack(data->mcs_idx, &y, 5);
*y++ = data->ndi;
@ -241,33 +254,33 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
*y++ = data->cqi_request;
// Padding with zeros
int n = dci_format0_sizeof(nof_prb);
uint32_t n = dci_format0_sizeof(nof_prb);
while (y - msg->data < n) {
*y++ = 0;
}
msg->location.nof_bits = (y - msg->data);
return 0;
msg->nof_bits = (y - msg->data);
return LIBLTE_SUCCESS;
}
/* Unpacks DCI format 0 data and store result in msg according
* to 36.212 5.3.3.1.1
*
* TODO: TPC and cyclic shift for DM RS not implemented
*/
int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint32_t nof_prb) {
/* pack bits */
char *y = msg->data;
int n_ul_hop;
uint32_t n_ul_hop;
/* Make sure it's a Format0 message */
if (msg->location.nof_bits != dci_format_sizeof(Format0, nof_prb)) {
if (msg->nof_bits != dci_format_sizeof(Format0, nof_prb)) {
fprintf(stderr, "Invalid message length for format 0\n");
return -1;
return LIBLTE_ERROR;
}
if (*y++ != 0) {
fprintf(stderr,
"Invalid format differentiation field value. This is Format1A\n");
return -1;
return LIBLTE_ERROR;
}
if (*y++ == 0) {
data->freq_hop_fl = hop_disabled;
@ -286,11 +299,11 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - n_ul_hop);
ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start,
nof_prb, nof_prb);
bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop);
bit_pack((uint32_t) riv, &y, riv_nbits(nof_prb) - n_ul_hop);
data->type2_alloc.riv = riv;
/* unpack MCS according to 8.6 of 36.213 */
uint32_t mcs = bit_unpack(&y, 5);
data->mcs_idx = bit_unpack(&y, 5);
data->ndi = *y++ ? true : false;
@ -301,23 +314,19 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
data->cqi_request = *y++ ? true : false;
// 8.6.2 First paragraph
if (mcs <= 28) {
ra_mcs_from_idx_ul(mcs, &data->mcs);
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx,
ra_nprb_ul(data, nof_prb));
}
// 8.6.1 and 8.6.2 36.213 second paragraph
if (mcs == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) {
data->mcs.mod = QPSK;
}
if (mcs > 29) {
// Else leave MOD_NULL and use the previously used PUSCH modulation
data->mcs.mod = MOD_NULL;
data->rv_idx = mcs - 28;
}
return 0;
if (data->mcs_idx <= 28) {
ra_mcs_from_idx_ul(data->mcs_idx, ra_nprb_ul(data, nof_prb), &data->mcs);
} else if (data->mcs_idx == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) {
// 8.6.1 and 8.6.2 36.213 second paragraph
data->mcs.mod = LTE_QPSK;
data->mcs.tbs = 0;
} else if (data->mcs_idx >= 29) {
// Else leave TBS and use the previously used PUSCH modulation
data->mcs.tbs = 0;
data->rv_idx = data->mcs_idx - 28;
}
return LIBLTE_SUCCESS;
}
/* Packs DCI format 1 data to a sequence of bits and store them in msg according
@ -326,7 +335,7 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
* TODO: TPC commands
*/
int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) {
/* pack bits */
char *y = msg->data;
@ -336,36 +345,26 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
}
/* Resource allocation: type0 or type 1 */
int P = ra_type0_P(nof_prb);
int alloc_size = (int) ceilf((float) nof_prb / P);
uint32_t P = ra_type0_P(nof_prb);
uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P);
switch (data->alloc_type) {
case alloc_type0:
bit_pack(data->type0_alloc.rbg_bitmask, &y, alloc_size);
bit_pack((uint32_t) data->type0_alloc.rbg_bitmask, &y, alloc_size);
break;
case alloc_type1:
bit_pack(data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P)));
bit_pack((uint32_t) data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P)));
*y++ = data->type1_alloc.shift ? 1 : 0;
bit_pack(data->type1_alloc.vrb_bitmask, &y,
bit_pack((uint32_t) data->type1_alloc.vrb_bitmask, &y,
alloc_size - (int) ceilf(log2f(P)) - 1);
break;
default:
fprintf(stderr,
"Format 1 accepts type0 or type1 resource allocation only\n");
return -1;
return LIBLTE_ERROR;
}
/* pack MCS according to 7.1.7 of 36.213 */
uint32_t mcs;
if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx;
} else {
if (data->mcs.tbs) {
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs,
ra_nprb_dl(data, nof_prb));
}
mcs = ra_mcs_to_table_idx(&data->mcs);
}
bit_pack(mcs, &y, 5);
/* pack MCS */
bit_pack(data->mcs_idx, &y, 5);
/* harq process number */
bit_pack(data->harq_process, &y, 3);
@ -380,24 +379,24 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
*y++ = 0;
// Padding with zeros
int n = dci_format1_sizeof(nof_prb);
uint32_t n = dci_format1_sizeof(nof_prb);
while (y - msg->data < n) {
*y++ = 0;
}
msg->location.nof_bits = (y - msg->data);
msg->nof_bits = (y - msg->data);
return 0;
return LIBLTE_SUCCESS;
}
int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) {
/* pack bits */
char *y = msg->data;
/* Make sure it's a Format1 message */
if (msg->location.nof_bits != dci_format_sizeof(Format1, nof_prb)) {
if (msg->nof_bits != dci_format_sizeof(Format1, nof_prb)) {
fprintf(stderr, "Invalid message length for format 1\n");
return -1;
return LIBLTE_ERROR;
}
if (nof_prb > 10) {
@ -407,8 +406,8 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
}
/* Resource allocation: type0 or type 1 */
int P = ra_type0_P(nof_prb);
int alloc_size = (int) ceilf((float) nof_prb / P);
uint32_t P = ra_type0_P(nof_prb);
uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P);
switch (data->alloc_type) {
case alloc_type0:
data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size);
@ -420,17 +419,17 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
alloc_size - (int) ceilf(log2f(P)) - 1);
break;
default:
fprintf(stderr,
"Format 1 accepts type0 or type1 resource allocation only\n");
return -1;
fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n");
return LIBLTE_ERROR;
}
/* pack MCS according to 7.1.7 of 36.213 */
uint32_t mcs = bit_unpack(&y, 5);
data->mcs.mcs_idx = mcs;
ra_mcs_from_idx_dl(mcs, &data->mcs);
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_dl(data, nof_prb));
/* unpack MCS according to 7.1.7 of 36.213 */
data->mcs_idx = bit_unpack(&y, 5);
if (ra_mcs_from_idx_dl(data->mcs_idx, ra_nprb_dl(data, nof_prb), &data->mcs)) {
fprintf(stderr, "Error getting MCS\n");
return LIBLTE_ERROR;
}
/* harq process number */
data->harq_process = bit_unpack(&y, 3);
@ -441,14 +440,14 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
// TPC not implemented
return 0;
return LIBLTE_SUCCESS;
}
/* Packs DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
*
* TODO: RA procedure initiated by PDCCH, TPC commands
*/
int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb,
bool crc_is_crnti) {
/* pack bits */
@ -458,7 +457,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
if (data->alloc_type != alloc_type2) {
fprintf(stderr, "Format 1A accepts type2 resource allocation only\n");
return -1;
return LIBLTE_ERROR;
}
*y++ = data->type2_alloc.mode; // localized or distributed VRB assignment
@ -467,10 +466,10 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
if (data->type2_alloc.L_crb > nof_prb) {
fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n",
data->type2_alloc.L_crb);
return -1;
return LIBLTE_ERROR;
}
} else {
int n_vrb_dl;
uint32_t n_vrb_dl;
if (crc_is_crnti && nof_prb > 50) {
n_vrb_dl = 16;
} else {
@ -480,7 +479,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
fprintf(stderr,
"L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n",
data->type2_alloc.L_crb, n_vrb_dl);
return -1;
return LIBLTE_ERROR;
}
}
/* pack RIV according to 7.1.6.3 of 36.213 */
@ -491,7 +490,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
} else {
riv = data->type2_alloc.riv;
}
int nb_gap = 0;
uint32_t nb_gap = 0;
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
nb_gap = 1;
*y++ = data->type2_alloc.n_gap;
@ -499,23 +498,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
bit_pack(riv, &y, riv_nbits(nof_prb) - nb_gap);
// in format1A, MCS = TBS according to 7.1.7.2 of 36.213
uint32_t mcs;
if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx;
} else {
if (data->mcs.tbs) {
// In format 1A, n_prb_1a is 2 or 3 if crc is not scrambled with C-RNTI
int n_prb;
if (!crc_is_crnti) {
n_prb = ra_nprb_dl(data, nof_prb);
} else {
n_prb = data->type2_alloc.n_prb1a == nprb1a_2 ? 2 : 3;
}
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, n_prb);
}
mcs = data->mcs.tbs_idx;
}
bit_pack(mcs, &y, 5);
bit_pack(data->mcs_idx, &y, 5);
bit_pack(data->harq_process, &y, 3);
@ -538,34 +521,33 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
}
// Padding with zeros
int n = dci_format1A_sizeof(nof_prb);
uint32_t n = dci_format1A_sizeof(nof_prb);
while (y - msg->data < n) {
*y++ = 0;
}
msg->location.nof_bits = (y - msg->data);
msg->nof_bits = (y - msg->data);
return 0;
return LIBLTE_SUCCESS;
}
/* Unpacks DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
*
*/
int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb,
int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb,
bool crc_is_crnti) {
/* pack bits */
char *y = msg->data;
/* Make sure it's a Format0 message */
if (msg->location.nof_bits != dci_format_sizeof(Format1A, nof_prb)) {
if (msg->nof_bits != dci_format_sizeof(Format1A, nof_prb)) {
fprintf(stderr, "Invalid message length for format 1A\n");
return -1;
return LIBLTE_ERROR;
}
if (*y++ != 1) {
fprintf(stderr,
"Invalid format differentiation field value. This is Format0\n");
return -1;
fprintf(stderr, "Invalid format differentiation field value. This is Format0\n");
return LIBLTE_ERROR;
}
data->alloc_type = alloc_type2;
@ -575,12 +557,12 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb,
data->type2_alloc.n_gap = t2_ng1;
/* unpack RIV according to 7.1.6.3 of 36.213 */
int nb_gap = 0;
uint32_t nb_gap = 0;
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
nb_gap = 1;
data->type2_alloc.n_gap = *y++;
}
int nof_vrb;
uint32_t nof_vrb;
if (data->type2_alloc.mode == t2_loc) {
nof_vrb = nof_prb;
} else {
@ -592,7 +574,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb,
data->type2_alloc.riv = riv;
// unpack MCS
data->mcs.mcs_idx = bit_unpack(&y, 5);
data->mcs_idx = bit_unpack(&y, 5);
data->harq_process = bit_unpack(&y, 3);
@ -613,23 +595,23 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb,
y++; // MSB of TPC is reserved
data->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS
}
data->mcs.tbs_idx = data->mcs.mcs_idx;
int n_prb;
uint32_t n_prb;
if (crc_is_crnti) {
n_prb = ra_nprb_dl(data, nof_prb);
} else {
n_prb = data->type2_alloc.n_prb1a == nprb1a_2 ? 2 : 3;
}
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, n_prb);
data->mcs.mod = QPSK;
data->mcs.tbs = ra_tbs_from_idx(data->mcs_idx, n_prb);
data->mcs.mod = LTE_QPSK;
return 0;
return LIBLTE_SUCCESS;
}
/* Format 1C for compact scheduling of PDSCH words
*
*/
int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) {
/* pack bits */
char *y = msg->data;
@ -637,32 +619,31 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
if (data->alloc_type != alloc_type2 || data->type2_alloc.mode != t2_dist) {
fprintf(stderr,
"Format 1C accepts distributed type2 resource allocation only\n");
return -1;
return LIBLTE_ERROR;
}
if (nof_prb >= 50) {
*y++ = data->type2_alloc.n_gap;
}
int n_step = ra_type2_n_rb_step(nof_prb);
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
uint32_t n_step = ra_type2_n_rb_step(nof_prb);
uint32_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
if (data->type2_alloc.L_crb > ((int) n_vrb_dl / n_step) * n_step) {
fprintf(stderr,
"L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n",
data->type2_alloc.L_crb, ((int) n_vrb_dl / n_step) * n_step);
return -1;
if (data->type2_alloc.L_crb > ((uint32_t) n_vrb_dl / n_step) * n_step) {
fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n",
data->type2_alloc.L_crb, ((uint32_t) n_vrb_dl / n_step) * n_step);
return LIBLTE_ERROR;
}
if (data->type2_alloc.L_crb % n_step) {
fprintf(stderr, "L_crb must be multiple of n_step\n");
return -1;
return LIBLTE_ERROR;
}
if (data->type2_alloc.RB_start % n_step) {
fprintf(stderr, "RB_start must be multiple of n_step\n");
return -1;
return LIBLTE_ERROR;
}
int L_p = data->type2_alloc.L_crb / n_step;
int RB_p = data->type2_alloc.RB_start / n_step;
int n_vrb_p = (int) n_vrb_dl / n_step;
uint32_t L_p = data->type2_alloc.L_crb / n_step;
uint32_t RB_p = data->type2_alloc.RB_start / n_step;
uint32_t n_vrb_p = (int) n_vrb_dl / n_step;
uint32_t riv;
if (data->type2_alloc.L_crb) {
@ -673,60 +654,50 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
bit_pack(riv, &y, riv_nbits((int) n_vrb_dl / n_step));
// in format1C, MCS = TBS according to 7.1.7.2 of 36.213
uint32_t mcs;
if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx;
} else {
if (data->mcs.tbs) {
data->mcs.tbs_idx = ra_tbs_to_table_idx_format1c(data->mcs.tbs);
}
mcs = data->mcs.tbs_idx;
}
bit_pack(mcs, &y, 5);
bit_pack(data->mcs_idx, &y, 5);
msg->location.nof_bits = (y - msg->data);
msg->nof_bits = (y - msg->data);
return 0;
return LIBLTE_SUCCESS;
}
int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
uint16_t L_p, RB_p;
int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) {
uint32_t L_p, RB_p;
/* pack bits */
char *y = msg->data;
if (msg->location.nof_bits != dci_format_sizeof(Format1C, nof_prb)) {
if (msg->nof_bits != dci_format_sizeof(Format1C, nof_prb)) {
fprintf(stderr, "Invalid message length for format 1C\n");
return -1;
return LIBLTE_ERROR;
}
data->alloc_type = alloc_type2;
data->type2_alloc.mode = t2_dist;
if (nof_prb >= 50) {
data->type2_alloc.n_gap = *y++;
}
int n_step = ra_type2_n_rb_step(nof_prb);
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
uint32_t n_step = ra_type2_n_rb_step(nof_prb);
uint32_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
uint32_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl / n_step));
int n_vrb_p = (int) n_vrb_dl / n_step;
uint32_t n_vrb_p = (uint32_t) n_vrb_dl / n_step;
ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p);
data->type2_alloc.L_crb = L_p * n_step;
data->type2_alloc.RB_start = RB_p * n_step;
data->type2_alloc.riv = riv;
data->mcs.mcs_idx = bit_unpack(&y, 5);
data->mcs.tbs_idx = data->mcs.mcs_idx;
data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs.tbs_idx);
data->mcs.mod = QPSK;
data->mcs_idx = bit_unpack(&y, 5);
data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs_idx);
data->mcs.mod = LTE_QPSK;
msg->location.nof_bits = (y - msg->data);
msg->nof_bits = (y - msg->data);
return 0;
return LIBLTE_SUCCESS;
}
int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format,
int nof_prb, bool crc_is_crnti) {
uint32_t nof_prb, bool crc_is_crnti) {
switch (format) {
case Format1:
return dci_format1_pack(data, msg, nof_prb);
@ -737,28 +708,28 @@ int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format,
default:
fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n",
dci_format_string(format));
return -1;
return LIBLTE_ERROR;
}
}
int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb,
int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb,
bool crc_is_crnti) {
if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) {
if (msg->nof_bits == dci_format_sizeof(Format1, nof_prb)) {
return dci_format1_unpack(msg, data, nof_prb);
} else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
} else if (msg->nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
return dci_format1As_unpack(msg, data, nof_prb, crc_is_crnti);
} else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
} else if (msg->nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
return dci_format1Cs_unpack(msg, data, nof_prb);
} else {
return -1;
return LIBLTE_ERROR;
}
}
int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, uint32_t nof_prb) {
return dci_format0_pack(data, msg, nof_prb);
}
int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, uint32_t nof_prb) {
return dci_format0_unpack(msg, data, nof_prb);
}
@ -798,36 +769,38 @@ void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) {
}
}
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb,
unsigned short crnti) {
if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb)
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint32_t nof_prb,
uint16_t msg_rnti, uint16_t crnti)
{
DEBUG("Get message type: nof_bits=%d, msg_rnti=0x%x, crnti=0x%x\n", msg->nof_bits, msg_rnti, crnti);
if (msg->nof_bits == dci_format_sizeof(Format0, nof_prb)
&& !msg->data[0]) {
type->type = PUSCH_SCHED;
type->format = Format0;
return 0;
} else if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) {
return LIBLTE_SUCCESS;
} else if (msg->nof_bits == dci_format_sizeof(Format1, nof_prb)) {
type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1;
return 0;
} else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
if (msg->location.rnti == crnti) {
return LIBLTE_SUCCESS;
} else if (msg->nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
if (msg_rnti == crnti) {
type->type = RA_PROC_PDCCH;
type->format = Format1A;
} else {
type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1A;
}
return 0;
} else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
if (msg->location.rnti == MRNTI) {
return LIBLTE_SUCCESS;
} else if (msg->nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
if (msg_rnti == MRNTI) {
type->type = MCCH_CHANGE;
type->format = Format1C;
} else {
type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1C;
}
return 0;
return LIBLTE_SUCCESS;
}
return -1;
return LIBLTE_ERROR;
}

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

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

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

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