mirror of https://github.com/PentHertz/srsLTE.git
Merge pull request #37 from ismagom/master
Changed data types and introduced lte_cell_t structure. Fixed some bugs with PDSCH.
This commit is contained in:
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_stop_rx_stream(void *h);
|
||||
LIBLTE_API bool cuhd_rx_wait_lo_locked(void *h);
|
||||
LIBLTE_API double cuhd_set_rx_srate(void *h, double freq);
|
||||
LIBLTE_API double cuhd_set_rx_gain(void *h, double gain);
|
||||
LIBLTE_API double cuhd_set_rx_freq(void *h, double freq);
|
||||
LIBLTE_API int cuhd_recv(void *h, void *data, int nsamples, int blocking);
|
||||
|
||||
LIBLTE_API double cuhd_set_tx_srate(void *h, double freq);
|
||||
LIBLTE_API double cuhd_set_tx_gain(void *h, double gain);
|
||||
LIBLTE_API double cuhd_set_tx_freq(void *h, double freq);
|
||||
LIBLTE_API int cuhd_send(void *h, void *data, int nsamples, int blocking);
|
||||
LIBLTE_API int cuhd_start_rx_stream_nsamples(void *h,
|
||||
uint32_t nsamples);
|
||||
|
||||
LIBLTE_API int cuhd_stop_rx_stream(void *h);
|
||||
|
||||
LIBLTE_API bool cuhd_rx_wait_lo_locked(void *h);
|
||||
|
||||
LIBLTE_API double cuhd_set_rx_srate(void *h,
|
||||
double freq);
|
||||
|
||||
LIBLTE_API double cuhd_set_rx_gain(void *h,
|
||||
double gain);
|
||||
|
||||
LIBLTE_API double cuhd_set_rx_freq(void *h,
|
||||
double freq);
|
||||
|
||||
LIBLTE_API double cuhd_set_rx_freq_offset(void *h,
|
||||
double freq,
|
||||
double off);
|
||||
|
||||
LIBLTE_API int cuhd_recv(void *h,
|
||||
void *data,
|
||||
uint32_t nsamples,
|
||||
bool blocking);
|
||||
|
||||
LIBLTE_API int cuhd_recv_timed(void *h,
|
||||
void *data,
|
||||
uint32_t nsamples,
|
||||
bool blocking,
|
||||
time_t *secs,
|
||||
double *frac_secs);
|
||||
|
||||
LIBLTE_API double cuhd_set_tx_srate(void *h,
|
||||
double freq);
|
||||
|
||||
LIBLTE_API double cuhd_set_tx_gain(void *h,
|
||||
double gain);
|
||||
|
||||
LIBLTE_API double cuhd_set_tx_freq(void *h,
|
||||
double freq);
|
||||
|
||||
LIBLTE_API int cuhd_send(void *h,
|
||||
void *data,
|
||||
uint32_t nsamples,
|
||||
bool blocking);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -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_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_stop_rx_stream(void *h)
|
||||
{
|
||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
||||
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
|
||||
cmd.time_spec = handler->usrp->get_time_now();
|
||||
cmd.stream_now = true;
|
||||
handler->usrp->issue_stream_cmd(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cuhd_start_rx_stream_nsamples(void *h, int nsamples) {
|
||||
cuhd_handler* handler = static_cast<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_start_rx_stream_nsamples(void *h, uint32_t nsamples)
|
||||
{
|
||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
||||
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE);
|
||||
cmd.time_spec = handler->usrp->get_time_now();
|
||||
cmd.stream_now = true;
|
||||
cmd.num_samps = nsamples;
|
||||
handler->usrp->issue_stream_cmd(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cuhd_open(char *args, void **h) {
|
||||
cuhd_handler* handler = new cuhd_handler();
|
||||
std::string _args=std::string(args);
|
||||
handler->usrp = uhd::usrp::multi_usrp::make(_args);
|
||||
int cuhd_open(char *args, void **h)
|
||||
{
|
||||
cuhd_handler *handler = new cuhd_handler();
|
||||
std::string _args = std::string(args);
|
||||
handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=30720000");
|
||||
|
||||
// Try to set LTE clock
|
||||
handler->usrp->set_master_clock_rate(30720000);
|
||||
handler->usrp->set_clock_source("internal");
|
||||
|
||||
handler->usrp->set_clock_source("internal");
|
||||
std::string otw, cpu;
|
||||
otw = "sc16";
|
||||
cpu = "fc32";
|
||||
uhd::stream_args_t stream_args(cpu, otw);
|
||||
handler->rx_stream = handler->usrp->get_rx_stream(stream_args);
|
||||
handler->tx_stream = handler->usrp->get_tx_stream(stream_args);
|
||||
|
||||
std::string otw, cpu;
|
||||
otw="sc16";
|
||||
cpu="fc32";
|
||||
uhd::stream_args_t stream_args(cpu, otw);
|
||||
handler->rx_stream = handler->usrp->get_rx_stream(stream_args);
|
||||
handler->tx_stream = handler->usrp->get_tx_stream(stream_args);
|
||||
*h = handler;
|
||||
|
||||
*h = handler;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cuhd_close(void *h) {
|
||||
cuhd_stop_rx_stream(h);
|
||||
/** Something else to close the USRP?? */
|
||||
return 0;
|
||||
int cuhd_close(void *h)
|
||||
{
|
||||
cuhd_stop_rx_stream(h);
|
||||
/** Something else to close the USRP?? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
double cuhd_set_rx_srate(void *h, double freq) {
|
||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
||||
handler->usrp->set_rx_rate(freq);
|
||||
double ret = handler->usrp->get_rx_rate();
|
||||
return ret;
|
||||
double cuhd_set_rx_srate(void *h, double freq)
|
||||
{
|
||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
||||
handler->usrp->set_rx_rate(freq);
|
||||
double ret = handler->usrp->get_rx_rate();
|
||||
return ret;
|
||||
}
|
||||
|
||||
double cuhd_set_rx_gain(void *h, double gain) {
|
||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
||||
handler->usrp->set_rx_gain(gain);
|
||||
return handler->usrp->get_rx_gain();
|
||||
double cuhd_set_rx_gain(void *h, double gain)
|
||||
{
|
||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
||||
handler->usrp->set_rx_gain(gain);
|
||||
return handler->usrp->get_rx_gain();
|
||||
}
|
||||
|
||||
double cuhd_set_rx_freq(void *h, double freq) {
|
||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
||||
handler->usrp->set_rx_freq(freq);
|
||||
return handler->usrp->get_rx_freq();
|
||||
double cuhd_set_rx_freq(void *h, double freq)
|
||||
{
|
||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
||||
handler->usrp->set_rx_freq(freq);
|
||||
return handler->usrp->get_rx_freq();
|
||||
}
|
||||
|
||||
int cuhd_recv(void *h, void *data, int nsamples, int blocking) {
|
||||
cuhd_handler* handler = static_cast<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_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();
|
||||
}
|
||||
|
||||
double cuhd_set_tx_gain(void *h, double gain) {
|
||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
||||
handler->usrp->set_tx_gain(gain);
|
||||
return handler->usrp->get_tx_gain();
|
||||
int cuhd_recv(void *h, void *data, uint32_t nsamples, bool blocking)
|
||||
{
|
||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
||||
uhd::rx_metadata_t md;
|
||||
if (blocking) {
|
||||
int n = 0, p;
|
||||
complex_t *data_c = (complex_t *) data;
|
||||
do {
|
||||
p = handler->rx_stream->recv(&data_c[n], nsamples - n, md);
|
||||
if (p == -1) {
|
||||
return -1;
|
||||
}
|
||||
n += p;
|
||||
if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) {
|
||||
std::cout << "\nError code: " << md.to_pp_string() << "\n\n";
|
||||
}
|
||||
} while (n < nsamples);
|
||||
return nsamples;
|
||||
} else {
|
||||
return handler->rx_stream->recv(data, nsamples, md, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
double cuhd_set_tx_srate(void *h, double freq) {
|
||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
||||
handler->usrp->set_tx_rate(freq);
|
||||
return handler->usrp->get_tx_rate();
|
||||
int cuhd_recv_timed(void *h,
|
||||
void *data,
|
||||
uint32_t nsamples,
|
||||
int blocking,
|
||||
time_t *secs,
|
||||
double *frac_secs) {
|
||||
cuhd_handler* handler = static_cast<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_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();
|
||||
|
||||
double cuhd_set_tx_gain(void *h, double gain)
|
||||
{
|
||||
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
|
||||
handler->usrp->set_tx_gain(gain);
|
||||
return handler->usrp->get_tx_gain();
|
||||
}
|
||||
|
||||
int cuhd_send(void *h, void *data, int nsamples, int blocking) {
|
||||
cuhd_handler* handler = static_cast<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);
|
||||
}
|
||||
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(®s, R_1, PHICH_NORM, cell)) {
|
||||
fprintf(stderr, "Error initiating regs\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (pcfich_init(&pcfich, ®s, cell)) {
|
||||
fprintf(stderr, "Error creating PBCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (regs_set_cfi(®s, cfi)) {
|
||||
fprintf(stderr, "Error setting CFI\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (pdcch_init(&pdcch, ®s, cell)) {
|
||||
fprintf(stderr, "Error creating PDCCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (pdsch_init(&pdsch, cell)) {
|
||||
fprintf(stderr, "Error creating PDSCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
pdsch_set_rnti(&pdsch, 1234);
|
||||
|
||||
if (pdsch_harq_init(&harq_process, &pdsch)) {
|
||||
fprintf(stderr, "Error initiating HARQ process\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void base_free() {
|
||||
|
||||
pdsch_harq_free(&harq_process);
|
||||
pdsch_free(&pdsch);
|
||||
pdcch_free(&pdcch);
|
||||
regs_free(®s);
|
||||
pbch_free(&pbch);
|
||||
|
||||
lte_ifft_free(&ifft);
|
||||
|
||||
if (sf_buffer) {
|
||||
free(sf_buffer);
|
||||
}
|
||||
if (output_buffer) {
|
||||
free(output_buffer);
|
||||
}
|
||||
if (output_file_name) {
|
||||
filesink_free(&fsink);
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_close(&uhd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int nf, sf_idx, N_id_2;
|
||||
cf_t pss_signal[PSS_LEN];
|
||||
float sss_signal0[SSS_LEN]; // for subframe 0
|
||||
float sss_signal5[SSS_LEN]; // for subframe 5
|
||||
pbch_mib_t mib;
|
||||
ra_pdsch_t ra_dl;
|
||||
ra_prb_t prb_alloc;
|
||||
refsignal_t refs[NSLOTS_X_FRAME];
|
||||
int i, n;
|
||||
char *data;
|
||||
cf_t *sf_symbols[MAX_PORTS];
|
||||
dci_msg_t dci_msg;
|
||||
dci_location_t locations[NSUBFRAMES_X_FRAME][10];
|
||||
|
||||
#ifdef DISABLE_UHD
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
N_id_2 = cell.id % 3;
|
||||
sf_n_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB;
|
||||
sf_n_samples = 2 * SLOT_LEN_CPNORM(lte_symbol_sz(cell.nof_prb));
|
||||
|
||||
/* this *must* be called after setting slot_len_* */
|
||||
base_init();
|
||||
|
||||
/* Generate PSS/SSS signals */
|
||||
pss_generate(pss_signal, N_id_2);
|
||||
sss_generate(sss_signal0, sss_signal5, cell.id);
|
||||
|
||||
/* Generate CRS signals */
|
||||
for (i = 0; i < NSLOTS_X_FRAME; i++) {
|
||||
if (refsignal_init_LTEDL(&refs[i], 0, i, cell)) {
|
||||
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
mib.nof_ports = cell.nof_ports;
|
||||
mib.nof_prb = cell.nof_prb;
|
||||
mib.phich_length = PHICH_NORM;
|
||||
mib.phich_resources = R_1;
|
||||
mib.sfn = 0;
|
||||
|
||||
for (i = 0; i < MAX_PORTS; i++) { // now there's only 1 port
|
||||
sf_symbols[i] = sf_buffer;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
if (!output_file_name) {
|
||||
printf("Set TX rate: %.2f MHz\n",
|
||||
cuhd_set_tx_srate(uhd, lte_sampling_freq_hz(cell.nof_prb)) / 1000000);
|
||||
printf("Set TX gain: %.1f dB\n", cuhd_set_tx_gain(uhd, uhd_gain));
|
||||
printf("Set TX freq: %.2f MHz\n",
|
||||
cuhd_set_tx_freq(uhd, uhd_freq) / 1000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
bzero(&ra_dl, sizeof(ra_pdsch_t));
|
||||
ra_dl.harq_process = 0;
|
||||
ra_dl.mcs_idx = mcs_idx;
|
||||
ra_dl.ndi = 0;
|
||||
ra_dl.rv_idx = 0;
|
||||
ra_dl.alloc_type = alloc_type0;
|
||||
ra_dl.type0_alloc.rbg_bitmask = 0xffffffff;
|
||||
|
||||
dci_msg_pack_pdsch(&ra_dl, &dci_msg, Format1, cell.nof_prb, false);
|
||||
|
||||
ra_prb_get_dl(&prb_alloc, &ra_dl, cell.nof_prb);
|
||||
ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, 1, cell.nof_prb<10?(cfi+1):cfi, CPNORM);
|
||||
ra_mcs_from_idx_dl(mcs_idx, cell.nof_prb, &ra_dl.mcs);
|
||||
|
||||
ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb);
|
||||
|
||||
/* Initiate valid DCI locations */
|
||||
for (i=0;i<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 int chest_init(chest_t *q,
|
||||
uint32_t nof_re,
|
||||
uint32_t nof_symbols,
|
||||
uint32_t nof_ports);
|
||||
|
||||
LIBLTE_API void chest_free(chest_t *q);
|
||||
|
||||
LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id);
|
||||
LIBLTE_API int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id);
|
||||
LIBLTE_API int chest_ref_LTEDL(chest_t *q, int cell_id);
|
||||
LIBLTE_API int chest_set_nof_ports(chest_t *q,
|
||||
uint32_t nof_ports);
|
||||
|
||||
LIBLTE_API void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref);
|
||||
LIBLTE_API void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_id);
|
||||
LIBLTE_API void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot);
|
||||
LIBLTE_API int chest_init_LTEDL(chest_t *q,
|
||||
lte_cell_t cell);
|
||||
|
||||
LIBLTE_API void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id);
|
||||
LIBLTE_API void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id);
|
||||
LIBLTE_API void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id);
|
||||
LIBLTE_API void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id);
|
||||
LIBLTE_API int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]);
|
||||
LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q,
|
||||
uint32_t nslot,
|
||||
uint32_t port_id,
|
||||
lte_cell_t cell);
|
||||
|
||||
LIBLTE_API int chest_ref_LTEDL_slot(chest_t *q,
|
||||
uint32_t nslot,
|
||||
lte_cell_t cell);
|
||||
|
||||
LIBLTE_API int chest_ref_LTEDL(chest_t *q,
|
||||
lte_cell_t cell);
|
||||
|
||||
LIBLTE_API int chest_ce_ref(chest_t *q,
|
||||
cf_t *input,
|
||||
uint32_t nslot,
|
||||
uint32_t port_id,
|
||||
uint32_t nref);
|
||||
|
||||
LIBLTE_API int chest_ce_slot_port(chest_t *q,
|
||||
cf_t *input,
|
||||
cf_t *ce,
|
||||
uint32_t nslot,
|
||||
uint32_t port_id);
|
||||
|
||||
LIBLTE_API int chest_ce_sf_port(chest_t *q,
|
||||
cf_t *input,
|
||||
cf_t *ce,
|
||||
uint32_t sf_idx,
|
||||
uint32_t port_id);
|
||||
|
||||
LIBLTE_API int chest_ce_slot(chest_t *q,
|
||||
cf_t *input,
|
||||
cf_t *ce[MAX_PORTS],
|
||||
uint32_t nslot);
|
||||
|
||||
LIBLTE_API int chest_ce_sf(chest_t *q,
|
||||
cf_t *input,
|
||||
cf_t *ce[MAX_PORTS],
|
||||
uint32_t sf_idx);
|
||||
|
||||
LIBLTE_API void chest_fprint(chest_t *q,
|
||||
FILE *stream,
|
||||
uint32_t nslot,
|
||||
uint32_t port_id);
|
||||
|
||||
LIBLTE_API void chest_ref_fprint(chest_t *q,
|
||||
FILE *stream,
|
||||
uint32_t nslot,
|
||||
uint32_t port_id);
|
||||
|
||||
LIBLTE_API void chest_recvsig_fprint(chest_t *q,
|
||||
FILE *stream,
|
||||
uint32_t nslot,
|
||||
uint32_t port_id);
|
||||
|
||||
LIBLTE_API void chest_ce_fprint(chest_t *q,
|
||||
FILE *stream,
|
||||
uint32_t nslot,
|
||||
uint32_t port_id);
|
||||
|
||||
LIBLTE_API int chest_ref_symbols(chest_t *q,
|
||||
uint32_t port_id,
|
||||
uint32_t nslot,
|
||||
uint32_t l[2]);
|
||||
|
||||
/* High-level API */
|
||||
|
||||
|
@ -91,8 +159,7 @@ typedef struct LIBLTE_API{
|
|||
cf_t *input;
|
||||
int in_len;
|
||||
struct chest_ctrl_in {
|
||||
int slot_id; // slot id in the 10ms frame
|
||||
int cell_id;
|
||||
int sf_idx; // subframe id in the 10ms frame
|
||||
} ctrl_in;
|
||||
cf_t *output[MAX_PORTS];
|
||||
int out_len[MAX_PORTS];
|
||||
|
@ -105,3 +172,11 @@ LIBLTE_API int chest_work(chest_hl* hl);
|
|||
LIBLTE_API int chest_stop(chest_hl* hl);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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 void lte_fft_free(lte_fft_t *q);
|
||||
LIBLTE_API void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output);
|
||||
LIBLTE_API int lte_fft_init(lte_fft_t *q,
|
||||
lte_cp_t cp_type,
|
||||
uint32_t nof_prb);
|
||||
|
||||
LIBLTE_API void lte_fft_free(lte_fft_t *q);
|
||||
|
||||
LIBLTE_API void lte_fft_run_slot(lte_fft_t *q,
|
||||
cf_t *input,
|
||||
cf_t *output);
|
||||
|
||||
LIBLTE_API void lte_fft_run_sf(lte_fft_t *q,
|
||||
cf_t *input,
|
||||
cf_t *output);
|
||||
|
||||
LIBLTE_API int lte_ifft_init(lte_fft_t *q,
|
||||
lte_cp_t cp_type,
|
||||
uint32_t nof_prb);
|
||||
|
||||
LIBLTE_API int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb);
|
||||
LIBLTE_API void lte_ifft_free(lte_fft_t *q);
|
||||
LIBLTE_API void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output);
|
||||
|
||||
LIBLTE_API void lte_ifft_run_slot(lte_fft_t *q,
|
||||
cf_t *input,
|
||||
cf_t *output);
|
||||
|
||||
LIBLTE_API void lte_ifft_run_sf(lte_fft_t *q,
|
||||
cf_t *input,
|
||||
cf_t *output);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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 float lte_band_fd(int earfcn);
|
||||
LIBLTE_API int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int earfcn_start, int earfcn_end, int max_elems);
|
||||
LIBLTE_API int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_nelems);
|
||||
LIBLTE_API int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems);
|
||||
LIBLTE_API bool lte_N_id_2_isvalid(uint32_t N_id_2);
|
||||
|
||||
LIBLTE_API bool lte_N_id_1_isvalid(uint32_t N_id_1);
|
||||
|
||||
LIBLTE_API bool lte_symbol_sz_isvalid(uint32_t symbol_sz);
|
||||
|
||||
LIBLTE_API int lte_symbol_sz(uint32_t nof_prb);
|
||||
|
||||
|
||||
LIBLTE_API int lte_sampling_freq_hz(uint32_t nof_prb);
|
||||
|
||||
LIBLTE_API uint32_t lte_re_x_prb(uint32_t ns,
|
||||
uint32_t symbol,
|
||||
uint32_t nof_ports,
|
||||
uint32_t nof_symbols);
|
||||
|
||||
LIBLTE_API uint32_t lte_voffset(uint32_t symbol_id,
|
||||
uint32_t cell_id,
|
||||
uint32_t nof_ports);
|
||||
|
||||
LIBLTE_API int lte_cb_size(uint32_t index);
|
||||
|
||||
LIBLTE_API char *lte_cp_string(lte_cp_t cp);
|
||||
|
||||
LIBLTE_API char *lte_mod_string(lte_mod_t mod);
|
||||
|
||||
LIBLTE_API uint32_t lte_mod_bits_x_symbol(lte_mod_t mod);
|
||||
|
||||
LIBLTE_API int lte_find_cb_index(uint32_t long_cb);
|
||||
|
||||
LIBLTE_API float lte_band_fd(uint32_t earfcn);
|
||||
|
||||
LIBLTE_API int lte_band_get_fd_band(uint32_t band,
|
||||
lte_earfcn_t *earfcn,
|
||||
int earfcn_start,
|
||||
int earfcn_end,
|
||||
uint32_t max_elems);
|
||||
|
||||
LIBLTE_API int lte_band_get_fd_band_all(uint32_t band,
|
||||
lte_earfcn_t *earfcn,
|
||||
uint32_t max_nelems);
|
||||
|
||||
LIBLTE_API int lte_band_get_fd_region(enum band_geographical_area region,
|
||||
lte_earfcn_t *earfcn,
|
||||
uint32_t max_elems);
|
||||
|
||||
LIBLTE_API int lte_str2mimotype(char *mimo_type_str,
|
||||
lte_mimo_type_t *type);
|
||||
|
||||
LIBLTE_API int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type);
|
||||
LIBLTE_API char *lte_mimotype2str(lte_mimo_type_t type);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,19 +33,39 @@
|
|||
|
||||
typedef struct LIBLTE_API {
|
||||
char *c;
|
||||
int len;
|
||||
uint32_t len;
|
||||
} sequence_t;
|
||||
|
||||
LIBLTE_API int sequence_init(sequence_t *q, int len);
|
||||
LIBLTE_API int sequence_init(sequence_t *q, uint32_t len);
|
||||
|
||||
LIBLTE_API void sequence_free(sequence_t *q);
|
||||
|
||||
LIBLTE_API int sequence_LTEPRS(sequence_t *q, int len, int seed);
|
||||
LIBLTE_API int sequence_LTEPRS(sequence_t *q,
|
||||
uint32_t len,
|
||||
uint32_t seed);
|
||||
|
||||
LIBLTE_API int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id);
|
||||
LIBLTE_API int sequence_pcfich(sequence_t *seq, int nslot, int cell_id);
|
||||
LIBLTE_API int sequence_phich(sequence_t *seq, int nslot, int cell_id);
|
||||
LIBLTE_API int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len);
|
||||
LIBLTE_API int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q,
|
||||
int nslot, int cell_id, int len);
|
||||
LIBLTE_API int sequence_pbch(sequence_t *seq,
|
||||
lte_cp_t cp,
|
||||
uint32_t cell_id);
|
||||
|
||||
LIBLTE_API int sequence_pcfich(sequence_t *seq,
|
||||
uint32_t nslot,
|
||||
uint32_t cell_id);
|
||||
|
||||
LIBLTE_API int sequence_phich(sequence_t *seq,
|
||||
uint32_t nslot,
|
||||
uint32_t cell_id);
|
||||
|
||||
LIBLTE_API int sequence_pdcch(sequence_t *seq,
|
||||
uint32_t nslot,
|
||||
uint32_t cell_id,
|
||||
uint32_t len);
|
||||
|
||||
LIBLTE_API int sequence_pdsch(sequence_t *seq,
|
||||
unsigned short rnti,
|
||||
int q,
|
||||
uint32_t nslot,
|
||||
uint32_t cell_id,
|
||||
uint32_t len);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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_init(tdec_t * h,
|
||||
uint32_t max_long_cb);
|
||||
|
||||
LIBLTE_API int tdec_reset(tdec_t *h, int long_cb);
|
||||
LIBLTE_API void tdec_iteration(tdec_t *h, llr_t *input, int long_cb);
|
||||
LIBLTE_API void tdec_decision(tdec_t *h, char *output, int long_cb);
|
||||
LIBLTE_API void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations,
|
||||
int long_cb);
|
||||
LIBLTE_API void tdec_free(tdec_t * h);
|
||||
|
||||
LIBLTE_API int tdec_reset(tdec_t * h, uint32_t long_cb);
|
||||
|
||||
LIBLTE_API void tdec_iteration(tdec_t * h,
|
||||
llr_t * input,
|
||||
uint32_t long_cb);
|
||||
|
||||
LIBLTE_API void tdec_decision(tdec_t * h,
|
||||
char *output,
|
||||
uint32_t long_cb);
|
||||
|
||||
LIBLTE_API void tdec_run_all(tdec_t * h,
|
||||
llr_t * input,
|
||||
char *output,
|
||||
uint32_t nof_iterations,
|
||||
uint32_t long_cb);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
/* Converts a received PDSCH DL scheduling DCI message
|
||||
* to ra structures ready to be passed to the harq setup function
|
||||
*/
|
||||
LIBLTE_API int dci_msg_to_ra_dl(dci_msg_t *msg,
|
||||
uint16_t msg_rnti,
|
||||
uint16_t c_rnti,
|
||||
lte_cell_t cell,
|
||||
uint32_t cfi,
|
||||
ra_pdsch_t *ra_dl);
|
||||
|
||||
LIBLTE_API int dci_init(dci_t *q, int max_dci);
|
||||
LIBLTE_API void dci_free(dci_t *q);
|
||||
/* TODO
|
||||
LIBLTE_API int dci_msg_to_ra_ul(dci_msg_t *msg,
|
||||
uint16_t msg_rnti,
|
||||
uint16_t c_rnti,
|
||||
lte_cell_t cell,
|
||||
uint32_t cfi,
|
||||
ra_pusch_t *ra_ul);
|
||||
*/
|
||||
LIBLTE_API char* dci_format_string(dci_format_t format);
|
||||
|
||||
LIBLTE_API int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti);
|
||||
LIBLTE_API void dci_candidate_fprint(FILE *f, dci_candidate_t *q);
|
||||
LIBLTE_API int dci_location_set(dci_location_t *c,
|
||||
uint32_t L,
|
||||
uint32_t nCCE);
|
||||
|
||||
LIBLTE_API int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti);
|
||||
LIBLTE_API void dci_msg_type_fprint(FILE *f, dci_msg_type_t type);
|
||||
LIBLTE_API bool dci_location_isvalid(dci_location_t *c);
|
||||
|
||||
LIBLTE_API int dci_msg_get_type(dci_msg_t *msg,
|
||||
dci_msg_type_t *type,
|
||||
uint32_t nof_prb,
|
||||
uint16_t msg_rnti,
|
||||
uint16_t crnti);
|
||||
|
||||
LIBLTE_API void dci_msg_type_fprint(FILE *f,
|
||||
dci_msg_type_t type);
|
||||
|
||||
// For dci_msg_type_t = PUSCH_SCHED
|
||||
LIBLTE_API int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb);
|
||||
LIBLTE_API int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb);
|
||||
LIBLTE_API int dci_msg_pack_pusch(ra_pusch_t *data,
|
||||
dci_msg_t *msg,
|
||||
uint32_t nof_prb);
|
||||
|
||||
LIBLTE_API int dci_msg_unpack_pusch(dci_msg_t *msg,
|
||||
ra_pusch_t *data,
|
||||
uint32_t nof_prb);
|
||||
|
||||
// For dci_msg_type_t = PDSCH_SCHED
|
||||
LIBLTE_API int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti);
|
||||
LIBLTE_API int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti);
|
||||
LIBLTE_API int dci_msg_pack_pdsch(ra_pdsch_t *data,
|
||||
dci_msg_t *msg,
|
||||
dci_format_t format,
|
||||
uint32_t nof_prb,
|
||||
bool crc_is_crnti);
|
||||
|
||||
LIBLTE_API int dci_format_sizeof(dci_format_t format, int nof_prb);
|
||||
LIBLTE_API int dci_msg_unpack_pdsch(dci_msg_t *msg,
|
||||
ra_pdsch_t *data,
|
||||
uint32_t nof_prb,
|
||||
bool crc_is_crnti);
|
||||
|
||||
LIBLTE_API uint32_t dci_format_sizeof(dci_format_t format,
|
||||
uint32_t nof_prb);
|
||||
|
||||
#endif // DCI_
|
||||
|
|
|
@ -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 void pcfich_free(pcfich_t *q);
|
||||
LIBLTE_API int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
|
||||
int nsubframe, int *cfi, int *distance);
|
||||
LIBLTE_API int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL],
|
||||
int nsubframe);
|
||||
LIBLTE_API int pcfich_init(pcfich_t *q,
|
||||
regs_t *regs,
|
||||
lte_cell_t cell);
|
||||
|
||||
LIBLTE_API bool pcfich_exists(int nframe, int nslot);
|
||||
LIBLTE_API int pcfich_put(regs_t *h, cf_t *pcfich, cf_t *slot_data);
|
||||
LIBLTE_API int pcfich_get(regs_t *h, cf_t *pcfich, cf_t *slot_data);
|
||||
LIBLTE_API void pcfich_free(pcfich_t *q);
|
||||
|
||||
LIBLTE_API int pcfich_decode(pcfich_t *q,
|
||||
cf_t *sf_symbols,
|
||||
cf_t *ce[MAX_PORTS],
|
||||
uint32_t subframe,
|
||||
uint32_t *cfi,
|
||||
uint32_t *distance);
|
||||
|
||||
LIBLTE_API int pcfich_encode(pcfich_t *q,
|
||||
uint32_t cfi,
|
||||
cf_t *sf_symbols[MAX_PORTS],
|
||||
uint32_t subframe);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -44,41 +44,26 @@
|
|||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
#define PDCCH_NOF_SEARCH_MODES 3
|
||||
|
||||
typedef enum LIBLTE_API {
|
||||
SEARCH_NONE = 3, SEARCH_SI = 0, SEARCH_RA = 1, SEARCH_UE = 2
|
||||
SEARCH_UE, SEARCH_COMMON
|
||||
} pdcch_search_mode_t;
|
||||
|
||||
/*
|
||||
* A search mode is indicated by higher layers to look for SI/C/RA-RNTI
|
||||
* DCI messages as defined in Section 7.1 of 36.213
|
||||
*/
|
||||
typedef struct LIBLTE_API {
|
||||
int nof_candidates;
|
||||
dci_candidate_t *candidates[NSUBFRAMES_X_FRAME];
|
||||
} pdcch_search_t;
|
||||
|
||||
/* PDCCH object */
|
||||
typedef struct LIBLTE_API {
|
||||
int cell_id;
|
||||
lte_cp_t cp;
|
||||
int nof_prb;
|
||||
int nof_bits;
|
||||
int nof_symbols;
|
||||
int nof_ports;
|
||||
int nof_regs;
|
||||
int nof_cce;
|
||||
|
||||
pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES];
|
||||
pdcch_search_mode_t current_search_mode;
|
||||
lte_cell_t cell;
|
||||
uint32_t e_bits;
|
||||
uint32_t nof_regs;
|
||||
uint32_t nof_cce;
|
||||
uint32_t max_bits;
|
||||
|
||||
regs_t *regs;
|
||||
|
||||
/* buffers */
|
||||
cf_t *ce[MAX_PORTS_CTRL];
|
||||
cf_t *pdcch_symbols[MAX_PORTS_CTRL];
|
||||
cf_t *pdcch_x[MAX_PORTS_CTRL];
|
||||
cf_t *ce[MAX_PORTS];
|
||||
cf_t *pdcch_symbols[MAX_PORTS];
|
||||
cf_t *pdcch_x[MAX_PORTS];
|
||||
cf_t *pdcch_d;
|
||||
char *pdcch_e;
|
||||
float *pdcch_llr;
|
||||
|
@ -91,36 +76,48 @@ typedef struct LIBLTE_API {
|
|||
crc_t crc;
|
||||
} pdcch_t;
|
||||
|
||||
LIBLTE_API int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports,
|
||||
int cell_id, lte_cp_t cp);
|
||||
LIBLTE_API int pdcch_init(pdcch_t *q,
|
||||
regs_t *regs,
|
||||
lte_cell_t cell);
|
||||
|
||||
LIBLTE_API void pdcch_free(pdcch_t *q);
|
||||
|
||||
/* Encoding functions */
|
||||
LIBLTE_API int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS_CTRL],
|
||||
int nsubframe);
|
||||
|
||||
/* Decoding functions */
|
||||
/* Encoding function */
|
||||
LIBLTE_API int pdcch_encode(pdcch_t *q,
|
||||
dci_msg_t *msg,
|
||||
dci_location_t location,
|
||||
uint16_t rnti,
|
||||
cf_t *sf_symbols[MAX_PORTS],
|
||||
uint32_t nsubframe,
|
||||
uint32_t cfi);
|
||||
|
||||
/* There are two ways to decode the DCI messages:
|
||||
* a) call pdcch_set_search_si/ue/ra and then call pdcch_decode()
|
||||
* b) call pdcch_extract_llr() and then call pdcch_decode_si/ue/ra
|
||||
*/
|
||||
/* Decoding functions: Extract the LLRs and save them in the pdcch_t object */
|
||||
LIBLTE_API int pdcch_extract_llr(pdcch_t *q,
|
||||
cf_t *sf_symbols,
|
||||
cf_t *ce[MAX_PORTS],
|
||||
dci_location_t location,
|
||||
uint32_t nsubframe,
|
||||
uint32_t cfi);
|
||||
|
||||
LIBLTE_API int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
|
||||
dci_t *dci, int nsubframe, float ebno);
|
||||
LIBLTE_API int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
|
||||
float *llr, int nsubframe, float ebno);
|
||||
/* Decoding functions: Try to decode a DCI message after calling pdcch_extract_llr */
|
||||
LIBLTE_API int pdcch_decode_msg(pdcch_t *q,
|
||||
dci_msg_t *msg,
|
||||
dci_format_t format,
|
||||
uint16_t *crc_rem);
|
||||
|
||||
LIBLTE_API void pdcch_init_search_si(pdcch_t *q);
|
||||
LIBLTE_API void pdcch_set_search_si(pdcch_t *q);
|
||||
LIBLTE_API int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci);
|
||||
/* Function for generation of UE-specific search space DCI locations */
|
||||
LIBLTE_API uint32_t pdcch_ue_locations(pdcch_t *q,
|
||||
dci_location_t *locations,
|
||||
uint32_t max_locations,
|
||||
uint32_t nsubframe,
|
||||
uint32_t cfi,
|
||||
uint16_t rnti);
|
||||
|
||||
LIBLTE_API void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti);
|
||||
LIBLTE_API void pdcch_set_search_ue(pdcch_t *q);
|
||||
LIBLTE_API int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe);
|
||||
|
||||
LIBLTE_API void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti);
|
||||
LIBLTE_API void pdcch_set_search_ra(pdcch_t *q);
|
||||
LIBLTE_API int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci);
|
||||
/* Function for generation of common search space DCI locations */
|
||||
LIBLTE_API uint32_t pdcch_common_locations(pdcch_t *q,
|
||||
dci_location_t *locations,
|
||||
uint32_t max_locations,
|
||||
uint32_t cfi);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,49 +43,95 @@
|
|||
#include "liblte/phy/phch/dci.h"
|
||||
#include "liblte/phy/phch/regs.h"
|
||||
|
||||
#define TDEC_ITERATIONS 1
|
||||
#define TDEC_ITERATIONS 6
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
ra_mcs_t mcs;
|
||||
ra_prb_t prb_alloc;
|
||||
lte_cell_t cell;
|
||||
|
||||
uint32_t max_cb;
|
||||
uint32_t w_buff_size;
|
||||
float **pdsch_w_buff_f;
|
||||
char **pdsch_w_buff_c;
|
||||
|
||||
struct cb_segm {
|
||||
uint32_t F;
|
||||
uint32_t C;
|
||||
uint32_t K1;
|
||||
uint32_t K2;
|
||||
uint32_t C1;
|
||||
uint32_t C2;
|
||||
} cb_segm;
|
||||
|
||||
} pdsch_harq_t;
|
||||
|
||||
/* PDSCH object */
|
||||
typedef struct LIBLTE_API {
|
||||
int cell_id;
|
||||
lte_cp_t cp;
|
||||
int nof_prb;
|
||||
int nof_ports;
|
||||
int max_symbols;
|
||||
unsigned short rnti;
|
||||
lte_cell_t cell;
|
||||
|
||||
uint32_t max_symbols;
|
||||
bool rnti_is_set;
|
||||
uint16_t rnti;
|
||||
|
||||
/* buffers */
|
||||
// void buffers are shared for tx and rx
|
||||
cf_t *ce[MAX_PORTS];
|
||||
cf_t *pdsch_symbols[MAX_PORTS];
|
||||
cf_t *pdsch_x[MAX_PORTS];
|
||||
cf_t *pdsch_d;
|
||||
char *cb_in;
|
||||
void *cb_out;
|
||||
void *pdsch_e;
|
||||
|
||||
/* buffers */
|
||||
cf_t *ce[MAX_PORTS];
|
||||
cf_t *pdsch_symbols[MAX_PORTS];
|
||||
cf_t *pdsch_x[MAX_PORTS];
|
||||
cf_t *pdsch_d;
|
||||
char *pdsch_e_bits;
|
||||
char *cb_in_b;
|
||||
char *cb_out_b;
|
||||
float *pdsch_llr;
|
||||
float *pdsch_rm_f;
|
||||
|
||||
/* tx & rx objects */
|
||||
modem_table_t mod[4];
|
||||
demod_soft_t demod;
|
||||
sequence_t seq_pdsch[NSUBFRAMES_X_FRAME];
|
||||
tcod_t encoder;
|
||||
tdec_t decoder;
|
||||
rm_turbo_t rm_turbo;
|
||||
crc_t crc_tb;
|
||||
crc_t crc_cb;
|
||||
/* tx & rx objects */
|
||||
modem_table_t mod[4];
|
||||
demod_soft_t demod;
|
||||
sequence_t seq_pdsch[NSUBFRAMES_X_FRAME];
|
||||
tcod_t encoder;
|
||||
tdec_t decoder;
|
||||
crc_t crc_tb;
|
||||
crc_t crc_cb;
|
||||
}pdsch_t;
|
||||
|
||||
LIBLTE_API int pdsch_init(pdsch_t *q, unsigned short user_rnti, int nof_prb,
|
||||
int nof_ports, int cell_id, lte_cp_t cp);
|
||||
LIBLTE_API int pdsch_init(pdsch_t *q,
|
||||
lte_cell_t cell);
|
||||
|
||||
LIBLTE_API void pdsch_free(pdsch_t *q);
|
||||
|
||||
LIBLTE_API int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS],
|
||||
int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc);
|
||||
LIBLTE_API int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS],
|
||||
char *data, int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc);
|
||||
LIBLTE_API int pdsch_set_rnti(pdsch_t *q,
|
||||
uint16_t rnti);
|
||||
|
||||
LIBLTE_API int pdsch_harq_init(pdsch_harq_t *p,
|
||||
pdsch_t *pdsch);
|
||||
|
||||
LIBLTE_API int pdsch_harq_setup(pdsch_harq_t *p,
|
||||
ra_mcs_t mcs,
|
||||
ra_prb_t *prb_alloc);
|
||||
|
||||
LIBLTE_API void pdsch_harq_free(pdsch_harq_t *p);
|
||||
|
||||
LIBLTE_API int pdsch_encode(pdsch_t *q,
|
||||
char *data,
|
||||
cf_t *sf_symbols[MAX_PORTS],
|
||||
uint32_t nsubframe,
|
||||
pdsch_harq_t *harq_process,
|
||||
uint32_t rv_idx);
|
||||
|
||||
LIBLTE_API int pdsch_decode(pdsch_t *q,
|
||||
cf_t *sf_symbols,
|
||||
cf_t *ce[MAX_PORTS],
|
||||
char *data,
|
||||
uint32_t nsubframe,
|
||||
pdsch_harq_t *harq_process,
|
||||
uint32_t rv_idx);
|
||||
|
||||
LIBLTE_API int pdsch_get(pdsch_t *q,
|
||||
cf_t *sf_symbols,
|
||||
cf_t *pdsch_symbols,
|
||||
ra_prb_t *prb_alloc,
|
||||
uint32_t subframe);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -55,17 +55,15 @@ typedef _Complex float cf_t;
|
|||
|
||||
/* phich object */
|
||||
typedef struct LIBLTE_API {
|
||||
lte_cp_t cp;
|
||||
int nof_prb;
|
||||
int nof_tx_ports;
|
||||
|
||||
lte_cell_t cell;
|
||||
|
||||
/* handler to REGs resource mapper */
|
||||
regs_t *regs;
|
||||
|
||||
/* buffers */
|
||||
cf_t ce[MAX_PORTS_CTRL][PHICH_MAX_NSYMB];
|
||||
cf_t phich_symbols[MAX_PORTS_CTRL][PHICH_MAX_NSYMB];
|
||||
cf_t phich_x[MAX_PORTS_CTRL][PHICH_MAX_NSYMB];
|
||||
cf_t ce[MAX_PORTS][PHICH_MAX_NSYMB];
|
||||
cf_t phich_symbols[MAX_PORTS][PHICH_MAX_NSYMB];
|
||||
cf_t phich_x[MAX_PORTS][PHICH_MAX_NSYMB];
|
||||
cf_t phich_d[PHICH_MAX_NSYMB];
|
||||
cf_t phich_d0[PHICH_MAX_NSYMB];
|
||||
cf_t phich_z[PHICH_NBITS];
|
||||
|
@ -80,18 +78,31 @@ typedef struct LIBLTE_API {
|
|||
|
||||
}phich_t;
|
||||
|
||||
LIBLTE_API int phich_init(phich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp);
|
||||
LIBLTE_API int phich_init(phich_t *q,
|
||||
regs_t *regs,
|
||||
lte_cell_t cell);
|
||||
|
||||
LIBLTE_API void phich_free(phich_t *q);
|
||||
LIBLTE_API int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
|
||||
int ngroup, int nseq, int nsubframe, char *ack, int *distance);
|
||||
LIBLTE_API int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe,
|
||||
cf_t *slot_symbols[MAX_PORTS_CTRL]);
|
||||
|
||||
LIBLTE_API int phich_decode(phich_t *q,
|
||||
cf_t *slot_symbols,
|
||||
cf_t *ce[MAX_PORTS],
|
||||
uint32_t ngroup,
|
||||
uint32_t nseq,
|
||||
uint32_t nsubframe,
|
||||
char *ack,
|
||||
uint32_t *distance);
|
||||
|
||||
LIBLTE_API void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS_CTRL]);
|
||||
LIBLTE_API int phich_ngroups(phich_t *q);
|
||||
LIBLTE_API bool phich_exists(int nframe, int nslot);
|
||||
LIBLTE_API int phich_put(regs_t *h, cf_t *phich, cf_t *slot_data);
|
||||
LIBLTE_API int phich_get(regs_t *h, cf_t *phich, cf_t *slot_data);
|
||||
LIBLTE_API int phich_encode(phich_t *q,
|
||||
char ack,
|
||||
uint32_t ngroup,
|
||||
uint32_t nseq,
|
||||
uint32_t nsubframe,
|
||||
cf_t *slot_symbols[MAX_PORTS]);
|
||||
|
||||
LIBLTE_API void phich_reset(phich_t *q,
|
||||
cf_t *slot_symbols[MAX_PORTS]);
|
||||
|
||||
LIBLTE_API uint32_t phich_ngroups(phich_t *q);
|
||||
|
||||
#endif // PHICH_
|
||||
|
|
|
@ -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 void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb);
|
||||
LIBLTE_API int ra_prb_get_ul(ra_prb_slot_t *prb,
|
||||
ra_pusch_t *ra,
|
||||
uint32_t nof_prb);
|
||||
|
||||
LIBLTE_API int ra_prb_get_dl(ra_prb_t *prb, ra_pdsch_t *ra, int nof_prb);
|
||||
LIBLTE_API int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb);
|
||||
LIBLTE_API void ra_prb_get_re(ra_prb_t *prb_dist, int nof_prb, int nof_ports,
|
||||
int nof_ctrl_symbols, lte_cp_t cp);
|
||||
LIBLTE_API void ra_prb_get_re_dl(ra_prb_t *prb_dist,
|
||||
uint32_t nof_prb,
|
||||
uint32_t nof_ports,
|
||||
uint32_t nof_ctrl_symbols,
|
||||
lte_cp_t cp);
|
||||
|
||||
LIBLTE_API int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb);
|
||||
LIBLTE_API int ra_nprb_ul(ra_pusch_t *ra, int nof_prb);
|
||||
LIBLTE_API int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb,
|
||||
int nof_ports, int nof_ctrl_symbols, lte_cp_t cp);
|
||||
LIBLTE_API uint32_t ra_nprb_dl(ra_pdsch_t *ra,
|
||||
uint32_t nof_prb);
|
||||
|
||||
LIBLTE_API uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs);
|
||||
LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs);
|
||||
LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs);
|
||||
LIBLTE_API int ra_tbs_from_idx_format1c(uint8_t tbs_idx);
|
||||
LIBLTE_API int ra_tbs_to_table_idx_format1c(int tbs);
|
||||
LIBLTE_API int ra_tbs_from_idx(uint8_t tbs_idx, int n_prb);
|
||||
LIBLTE_API int ra_tbs_to_table_idx(int tbs, int n_prb);
|
||||
LIBLTE_API uint32_t ra_nprb_ul(ra_pusch_t *ra,
|
||||
uint32_t nof_prb);
|
||||
|
||||
LIBLTE_API uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs);
|
||||
LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs);
|
||||
LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs);
|
||||
LIBLTE_API int ra_mcs_from_idx_dl(uint32_t mcs_idx,
|
||||
uint32_t nof_prb,
|
||||
ra_mcs_t *mcs);
|
||||
|
||||
LIBLTE_API char *ra_mod_string(ra_mod_t mod);
|
||||
LIBLTE_API int ra_mcs_from_idx_ul(uint32_t mcs_idx,
|
||||
uint32_t nof_prb,
|
||||
ra_mcs_t *mcs);
|
||||
|
||||
LIBLTE_API int ra_type0_P(int nof_prb);
|
||||
LIBLTE_API int ra_tbs_from_idx_format1c(uint32_t tbs_idx);
|
||||
|
||||
LIBLTE_API uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb);
|
||||
LIBLTE_API void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start,
|
||||
int nof_prb, int nof_vrb);
|
||||
LIBLTE_API int ra_type2_n_vrb_dl(int nof_prb, bool ngap_is_1);
|
||||
LIBLTE_API int ra_type2_n_rb_step(int nof_prb);
|
||||
LIBLTE_API int ra_type2_ngap(int nof_prb, bool ngap_is_1);
|
||||
LIBLTE_API int ra_type1_N_rb(int nof_prb);
|
||||
LIBLTE_API int ra_tbs_from_idx(uint32_t tbs_idx,
|
||||
uint32_t n_prb);
|
||||
|
||||
LIBLTE_API void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint8_t mcs_idx);
|
||||
LIBLTE_API void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx);
|
||||
LIBLTE_API void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb);
|
||||
LIBLTE_API void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, int nof_prb);
|
||||
LIBLTE_API int ra_tbs_to_table_idx(uint32_t tbs,
|
||||
uint32_t n_prb);
|
||||
|
||||
LIBLTE_API uint32_t ra_type0_P(uint32_t nof_prb);
|
||||
|
||||
LIBLTE_API uint32_t ra_type2_to_riv(uint32_t L_crb,
|
||||
uint32_t RB_start,
|
||||
uint32_t nof_prb);
|
||||
|
||||
LIBLTE_API void ra_type2_from_riv(uint32_t riv,
|
||||
uint32_t *L_crb,
|
||||
uint32_t *RB_start,
|
||||
uint32_t nof_prb,
|
||||
uint32_t nof_vrb);
|
||||
|
||||
LIBLTE_API uint32_t ra_type2_n_vrb_dl(uint32_t nof_prb,
|
||||
bool ngap_is_1);
|
||||
|
||||
LIBLTE_API uint32_t ra_type2_n_rb_step(uint32_t nof_prb);
|
||||
|
||||
LIBLTE_API uint32_t ra_type2_ngap(uint32_t nof_prb,
|
||||
bool ngap_is_1);
|
||||
|
||||
LIBLTE_API uint32_t ra_type1_N_rb(uint32_t nof_prb);
|
||||
|
||||
LIBLTE_API void ra_pdsch_fprint(FILE *f,
|
||||
ra_pdsch_t *ra,
|
||||
uint32_t nof_prb);
|
||||
|
||||
LIBLTE_API void ra_pusch_fprint(FILE *f,
|
||||
ra_pusch_t *ra,
|
||||
uint32_t nof_prb);
|
||||
|
||||
#endif /* RB_ALLOC_H_ */
|
||||
|
|
|
@ -45,57 +45,91 @@
|
|||
typedef _Complex float cf_t;
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
int k[4];
|
||||
int k0;
|
||||
int l;
|
||||
uint32_t k[4];
|
||||
uint32_t k0;
|
||||
uint32_t l;
|
||||
bool assigned;
|
||||
}regs_reg_t;
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
int nof_regs;
|
||||
uint32_t nof_regs;
|
||||
regs_reg_t **regs;
|
||||
}regs_ch_t;
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
int cell_id;
|
||||
int nof_prb;
|
||||
int max_ctrl_symbols;
|
||||
int cfi;
|
||||
int ngroups_phich;
|
||||
int nof_ports;
|
||||
lte_cp_t cp;
|
||||
lte_cell_t cell;
|
||||
uint32_t max_ctrl_symbols;
|
||||
uint32_t cfi;
|
||||
bool cfi_initiated;
|
||||
uint32_t ngroups_phich;
|
||||
|
||||
phich_resources_t phich_res;
|
||||
phich_length_t phich_len;
|
||||
|
||||
regs_ch_t pcfich;
|
||||
regs_ch_t *phich; // there are several phich
|
||||
regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for
|
||||
the three possible CFI value */
|
||||
int nof_regs;
|
||||
|
||||
uint32_t nof_regs;
|
||||
regs_reg_t *regs;
|
||||
}regs_t;
|
||||
|
||||
LIBLTE_API int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports,
|
||||
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp);
|
||||
LIBLTE_API int regs_init(regs_t *h,
|
||||
phich_resources_t phich_res,
|
||||
phich_length_t phich_len,
|
||||
lte_cell_t cell);
|
||||
|
||||
LIBLTE_API void regs_free(regs_t *h);
|
||||
LIBLTE_API int regs_set_cfi(regs_t *h, int nof_ctrl_symbols);
|
||||
LIBLTE_API int regs_set_cfi(regs_t *h,
|
||||
uint32_t nof_ctrl_symbols);
|
||||
|
||||
LIBLTE_API int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
|
||||
LIBLTE_API int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
|
||||
LIBLTE_API int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb);
|
||||
LIBLTE_API int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb);
|
||||
|
||||
LIBLTE_API int regs_pcfich_nregs(regs_t *h);
|
||||
LIBLTE_API int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols);
|
||||
LIBLTE_API int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t pcfich_symbols[REGS_PCFICH_NSYM]);
|
||||
LIBLTE_API uint32_t regs_pcfich_nregs(regs_t *h);
|
||||
LIBLTE_API int regs_pcfich_put(regs_t *h,
|
||||
cf_t pcfich_symbols[REGS_PCFICH_NSYM],
|
||||
cf_t *slot_symbols);
|
||||
|
||||
LIBLTE_API int regs_phich_nregs(regs_t *h);
|
||||
LIBLTE_API int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, cf_t *slot_symbols);
|
||||
LIBLTE_API int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup);
|
||||
LIBLTE_API int regs_phich_ngroups(regs_t *h);
|
||||
LIBLTE_API int regs_phich_reset(regs_t *h, cf_t *slot_symbols);
|
||||
LIBLTE_API int regs_pcfich_get(regs_t *h,
|
||||
cf_t *slot_symbols,
|
||||
cf_t pcfich_symbols[REGS_PCFICH_NSYM]);
|
||||
|
||||
LIBLTE_API int regs_pdcch_nregs(regs_t *h);
|
||||
LIBLTE_API int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols);
|
||||
LIBLTE_API int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols);
|
||||
LIBLTE_API uint32_t regs_phich_nregs(regs_t *h);
|
||||
LIBLTE_API int regs_phich_add(regs_t *h,
|
||||
cf_t phich_symbols[REGS_PHICH_NSYM],
|
||||
uint32_t ngroup,
|
||||
cf_t *slot_symbols);
|
||||
|
||||
LIBLTE_API int regs_phich_get(regs_t *h,
|
||||
cf_t *slot_symbols,
|
||||
cf_t phich_symbols[REGS_PHICH_NSYM],
|
||||
uint32_t ngroup);
|
||||
|
||||
LIBLTE_API uint32_t regs_phich_ngroups(regs_t *h);
|
||||
LIBLTE_API int regs_phich_reset(regs_t *h,
|
||||
cf_t *slot_symbols);
|
||||
|
||||
LIBLTE_API int regs_pdcch_nregs(regs_t *h, uint32_t cfi);
|
||||
LIBLTE_API int regs_pdcch_put(regs_t *h,
|
||||
cf_t *pdcch_symbols,
|
||||
cf_t *slot_symbols);
|
||||
|
||||
LIBLTE_API int regs_pdcch_put_offset(regs_t *h,
|
||||
cf_t *pdcch_symbols,
|
||||
cf_t *slot_symbols,
|
||||
uint32_t start_reg,
|
||||
uint32_t nof_regs);
|
||||
|
||||
LIBLTE_API int regs_pdcch_get(regs_t *h,
|
||||
cf_t *slot_symbols,
|
||||
cf_t *pdcch_symbols);
|
||||
|
||||
LIBLTE_API int regs_pdcch_get_offset(regs_t *h,
|
||||
cf_t *slot_symbols,
|
||||
cf_t *pdcch_symbols,
|
||||
uint32_t start_reg,
|
||||
uint32_t nof_regs);
|
||||
|
||||
#endif // REGS_H_
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
LIBLTE_API void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end);
|
||||
LIBLTE_API void interp_linear(cf_t *input, cf_t *output, int M, int len);
|
||||
LIBLTE_API void interp_linear_f(float *input, float *output, int M, int len);
|
||||
typedef struct LIBLTE_API {
|
||||
interp_type_t type;
|
||||
|
||||
float *in_mag;
|
||||
float *in_arg;
|
||||
float *in_mag0;
|
||||
float *in_arg0;
|
||||
float *in_mag1;
|
||||
float *in_arg1;
|
||||
|
||||
float *out_mag;
|
||||
float *out_arg;
|
||||
float *out_arg2;
|
||||
int16_t *table_idx;
|
||||
|
||||
cf_t *out_cexp;
|
||||
cf_t *out_prod;
|
||||
|
||||
cf_t *cexptable;
|
||||
|
||||
uint32_t len;
|
||||
uint32_t M;
|
||||
|
||||
}interp_t;
|
||||
|
||||
LIBLTE_API int interp_init(interp_t *q,
|
||||
interp_type_t type,
|
||||
uint32_t len,
|
||||
uint32_t M);
|
||||
|
||||
LIBLTE_API void interp_free(interp_t *q);
|
||||
|
||||
LIBLTE_API void interp_run(interp_t *q,
|
||||
cf_t *input,
|
||||
cf_t *output);
|
||||
|
||||
LIBLTE_API void interp_run_offset(interp_t *q,
|
||||
cf_t *input,
|
||||
cf_t *output,
|
||||
uint32_t off_st,
|
||||
uint32_t off_end);
|
||||
|
||||
LIBLTE_API void interp_linear_offset(cf_t *input,
|
||||
cf_t *output,
|
||||
uint32_t M,
|
||||
uint32_t len,
|
||||
uint32_t off_st,
|
||||
uint32_t off_end);
|
||||
|
||||
LIBLTE_API void interp_linear_c(cf_t *input,
|
||||
cf_t *output,
|
||||
uint32_t M,
|
||||
uint32_t len);
|
||||
|
||||
LIBLTE_API void interp_linear_f(float *input,
|
||||
float *output,
|
||||
uint32_t M,
|
||||
uint32_t len);
|
||||
|
||||
#endif // INTERP_H
|
||||
|
|
|
@ -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;
|
||||
uint32_t frame_size;
|
||||
uint32_t N_id_2;
|
||||
uint32_t fft_size;
|
||||
|
||||
cf_t *pss_signal_freq;
|
||||
cf_t *pss_signal_freq[3]; // One sequence for each N_id_2
|
||||
cf_t *tmp_input;
|
||||
float *conv_abs;
|
||||
cf_t *frame_buffer;
|
||||
cf_t *conv_output;
|
||||
cf_t *tmp_nco;
|
||||
|
||||
}pss_synch_t;
|
||||
|
||||
typedef enum { PSS_TX, PSS_RX } pss_direction_t;
|
||||
|
||||
/* Basic functionality */
|
||||
LIBLTE_API int pss_synch_init(pss_synch_t *q, int frame_size);
|
||||
LIBLTE_API int pss_synch_init_fft(pss_synch_t *q,
|
||||
uint32_t frame_size,
|
||||
uint32_t fft_size);
|
||||
|
||||
LIBLTE_API int pss_synch_init(pss_synch_t *q,
|
||||
uint32_t frame_size);
|
||||
|
||||
LIBLTE_API void pss_synch_free(pss_synch_t *q);
|
||||
LIBLTE_API int pss_generate(cf_t *signal, int N_id_2);
|
||||
LIBLTE_API void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp);
|
||||
|
||||
LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2);
|
||||
LIBLTE_API int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, float *corr_mean_value);
|
||||
LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv);
|
||||
LIBLTE_API int pss_generate(cf_t *signal,
|
||||
uint32_t N_id_2);
|
||||
|
||||
LIBLTE_API void pss_put_slot(cf_t *pss_signal,
|
||||
cf_t *slot,
|
||||
uint32_t nof_prb,
|
||||
lte_cp_t cp);
|
||||
|
||||
/* Automatic frame management functions (for periodic calling) */
|
||||
LIBLTE_API int pss_synch_periodic(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples);
|
||||
LIBLTE_API void pss_synch_set_timeout(pss_synch_t *q, int nof_frames);
|
||||
LIBLTE_API void pss_synch_set_threshold(pss_synch_t *q, float threshold);
|
||||
LIBLTE_API void pss_synch_set_cfo_mode(pss_synch_t *q, bool cfo_auto);
|
||||
LIBLTE_API float pss_synch_get_cfo(pss_synch_t *q);
|
||||
LIBLTE_API int pss_synch_get_frame_start_idx(pss_synch_t *q);
|
||||
LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q,
|
||||
uint32_t N_id_2);
|
||||
|
||||
LIBLTE_API int pss_synch_find_pss(pss_synch_t *q,
|
||||
cf_t *input,
|
||||
float *corr_peak_value,
|
||||
float *corr_mean_value);
|
||||
|
||||
LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q,
|
||||
cf_t *pss_recv);
|
||||
|
||||
|
||||
/* High-level API */
|
||||
|
|
|
@ -38,26 +38,20 @@
|
|||
|
||||
typedef _Complex float cf_t; /* this is only a shortcut */
|
||||
|
||||
/** gives the beginning of the SSS symbol (to be passed to sss_synch_m0m1).
|
||||
* subframe_sz is the length of the subframe, e.g. 1920 for the 1.9 MHz
|
||||
* symbol_sz is the OFDM symbol size (including CP), e.g. 137 for the 1.9 MHz
|
||||
*/
|
||||
#define SSS_SYMBOL_ST(subframe_sz, symbol_sz) (subframe_sz/2-2*symbol_sz)
|
||||
#define SSS_POS_SYMBOL 33
|
||||
|
||||
#define SSS_DFT_LEN 128
|
||||
#define N_SSS 31
|
||||
#define N_SSS 31
|
||||
#define SSS_LEN 2*N_SSS
|
||||
|
||||
#define SSS_MAX_FFT_LEN 2048
|
||||
|
||||
struct sss_tables{
|
||||
int z1[N_SSS][N_SSS];
|
||||
int c[2][N_SSS];
|
||||
int s[N_SSS][N_SSS];
|
||||
int N_id_2;
|
||||
};
|
||||
|
||||
/* Allocate 32 complex to make it multiple of 32-byte AVX instructions alignment requirement.
|
||||
* Should use vect_malloc() to make it platform agnostic.
|
||||
* Should use vec_malloc() to make it platform agnostic.
|
||||
*/
|
||||
struct fc_tables{
|
||||
cf_t z1[N_SSS+1][N_SSS+1];
|
||||
|
@ -70,34 +64,68 @@ struct fc_tables{
|
|||
typedef struct LIBLTE_API {
|
||||
|
||||
dft_plan_t dftp_input;
|
||||
|
||||
uint32_t fft_size;
|
||||
|
||||
float corr_peak_threshold;
|
||||
int symbol_sz;
|
||||
int subframe_sz;
|
||||
|
||||
int N_id_1_table[30][30];
|
||||
struct fc_tables fc_tables;
|
||||
uint32_t symbol_sz;
|
||||
uint32_t subframe_sz;
|
||||
uint32_t N_id_2;
|
||||
|
||||
uint32_t N_id_1_table[30][30];
|
||||
struct fc_tables fc_tables[3]; // one for each N_id_2
|
||||
|
||||
}sss_synch_t;
|
||||
|
||||
|
||||
/* Basic functionality */
|
||||
LIBLTE_API int sss_synch_init(sss_synch_t *q);
|
||||
LIBLTE_API int sss_synch_init(sss_synch_t *q,
|
||||
uint32_t fft_size);
|
||||
|
||||
LIBLTE_API int sss_synch_realloc(sss_synch_t *q,
|
||||
uint32_t fft_size);
|
||||
|
||||
LIBLTE_API void sss_synch_free(sss_synch_t *q);
|
||||
LIBLTE_API void sss_generate(float *signal0, float *signal5, int cell_id);
|
||||
LIBLTE_API void sss_put_slot(float *sss, cf_t *symbol, int nof_prb, lte_cp_t cp);
|
||||
|
||||
LIBLTE_API int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2);
|
||||
LIBLTE_API void sss_generate(float *signal0,
|
||||
float *signal5,
|
||||
uint32_t cell_id);
|
||||
|
||||
LIBLTE_API void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value,
|
||||
int *m1, float *m1_value);
|
||||
LIBLTE_API int sss_synch_subframe(int m0, int m1);
|
||||
LIBLTE_API int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1);
|
||||
LIBLTE_API void sss_put_slot(float *sss,
|
||||
cf_t *symbol,
|
||||
uint32_t nof_prb,
|
||||
lte_cp_t cp);
|
||||
|
||||
LIBLTE_API int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx, int *N_id_1);
|
||||
LIBLTE_API void sss_synch_set_threshold(sss_synch_t *q, float threshold);
|
||||
LIBLTE_API void sss_synch_set_symbol_sz(sss_synch_t *q, int symbol_sz);
|
||||
LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz);
|
||||
LIBLTE_API int sss_synch_set_N_id_2(sss_synch_t *q,
|
||||
uint32_t N_id_2);
|
||||
|
||||
LIBLTE_API int sss_synch_m0m1(sss_synch_t *q,
|
||||
cf_t *input,
|
||||
uint32_t *m0,
|
||||
float *m0_value,
|
||||
uint32_t *m1,
|
||||
float *m1_value);
|
||||
|
||||
LIBLTE_API uint32_t sss_synch_subframe(uint32_t m0,
|
||||
uint32_t m1);
|
||||
|
||||
LIBLTE_API int sss_synch_N_id_1(sss_synch_t *q,
|
||||
uint32_t m0,
|
||||
uint32_t m1);
|
||||
|
||||
LIBLTE_API int sss_synch_frame(sss_synch_t *q,
|
||||
cf_t *input,
|
||||
uint32_t *subframe_idx,
|
||||
uint32_t *N_id_1);
|
||||
|
||||
LIBLTE_API void sss_synch_set_threshold(sss_synch_t *q,
|
||||
float threshold);
|
||||
|
||||
LIBLTE_API void sss_synch_set_symbol_sz(sss_synch_t *q,
|
||||
uint32_t symbol_sz);
|
||||
|
||||
LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q,
|
||||
uint32_t subframe_sz);
|
||||
|
||||
|
||||
/* High-level API */
|
||||
|
@ -105,18 +133,18 @@ LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz);
|
|||
typedef struct LIBLTE_API {
|
||||
sss_synch_t obj;
|
||||
struct sss_synch_init {
|
||||
int N_id_2;
|
||||
uint32_t N_id_2;
|
||||
} init;
|
||||
cf_t *input;
|
||||
int in_len;
|
||||
uint32_t in_len;
|
||||
struct sss_synch_ctrl_in {
|
||||
int symbol_sz;
|
||||
int subframe_sz;
|
||||
int correlation_threshold;
|
||||
uint32_t symbol_sz;
|
||||
uint32_t subframe_sz;
|
||||
uint32_t correlation_threshold;
|
||||
} ctrl_in;
|
||||
struct sss_synch_ctrl_out {
|
||||
int subframe_idx;
|
||||
int N_id_1;
|
||||
uint32_t subframe_idx;
|
||||
uint32_t N_id_1;
|
||||
} ctrl_out;
|
||||
}sss_synch_hl;
|
||||
|
||||
|
|
|
@ -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 int conv_cc(_Complex float *input, _Complex float *filter, _Complex float *output, int input_len, int filter_len);
|
||||
LIBLTE_API void conv_fft_cc_free(conv_fft_cc_t *q);
|
||||
|
||||
LIBLTE_API uint32_t conv_fft_cc_run(conv_fft_cc_t *q,
|
||||
cf_t *input,
|
||||
cf_t *filter,
|
||||
cf_t *output);
|
||||
|
||||
LIBLTE_API uint32_t conv_cc(cf_t *input,
|
||||
cf_t *filter,
|
||||
cf_t *output,
|
||||
uint32_t input_len,
|
||||
uint32_t filter_len);
|
||||
|
||||
#endif // CONVOLUTION_H_
|
||||
|
|
|
@ -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;
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
input != NULL &&
|
||||
nslot < NSLOTS_X_FRAME &&
|
||||
port_id < q->nof_ports)
|
||||
{
|
||||
if (nref < q->refsignal[port_id][nslot].nof_refs) {
|
||||
|
||||
fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index
|
||||
tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index
|
||||
known_ref = q->refsignal[port_id][nslot].refs[nref].simbol;
|
||||
channel_ref = input[SAMPLE_IDX(q->nof_prb, tidx, fidx)];
|
||||
q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref;
|
||||
fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index
|
||||
tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index
|
||||
|
||||
DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, SAMPLE_IDX(q->nof_prb, tidx, fidx),
|
||||
10*log10f(cabsf(channel_ref/known_ref)),
|
||||
cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,cargf(channel_ref/known_ref)/M_PI);
|
||||
known_ref = q->refsignal[port_id][nslot].refs[nref].simbol;
|
||||
channel_ref = input[tidx * q->nof_re + fidx];
|
||||
q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref;
|
||||
|
||||
/* FIXME: compare with threshold */
|
||||
if (channel_ref != 0) {
|
||||
q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref;
|
||||
} else {
|
||||
q->refsignal[port_id][nslot].ch_est[nref] = 0;
|
||||
DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, tidx * q->nof_re + fidx,
|
||||
10*log10f(cabsf(channel_ref/known_ref)),
|
||||
cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,
|
||||
cargf(channel_ref/known_ref)/M_PI);
|
||||
|
||||
/* FIXME: compare with threshold */
|
||||
if (channel_ref != 0) {
|
||||
q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref;
|
||||
} else {
|
||||
q->refsignal[port_id][nslot].ch_est[nref] = 0;
|
||||
}
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Computes channel estimates for each reference in a slot and port.
|
||||
* Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce
|
||||
*/
|
||||
void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_id) {
|
||||
int i, j;
|
||||
int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32_t port_id) {
|
||||
uint32_t i, j;
|
||||
cf_t x[2], y[MAX_NSYMB];
|
||||
|
||||
assert(nslot >= 0 && nslot < NSLOTS_X_FRAME);
|
||||
assert(port_id >= 0 && port_id < q->nof_ports);
|
||||
assert(q->refsignal[port_id][nslot].nsymbols <= 2);
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
input != NULL &&
|
||||
nslot < NSLOTS_X_FRAME &&
|
||||
port_id < q->nof_ports)
|
||||
{
|
||||
if (q->refsignal[port_id][nslot].nsymbols <= 2) {
|
||||
refsignal_t *r = &q->refsignal[port_id][nslot];
|
||||
|
||||
refsignal_t *r = &q->refsignal[port_id][nslot];
|
||||
INFO("Estimating channel slot=%d port=%d using %d reference signals\n",
|
||||
nslot, port_id, r->nof_refs);
|
||||
|
||||
INFO("Estimating channel slot=%d port=%d using %d reference signals\n",
|
||||
nslot, port_id, r->nof_refs);
|
||||
|
||||
for (i=0;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);
|
||||
|
||||
}
|
||||
/* 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];
|
||||
for (i=0;i<r->nof_refs;i++) {
|
||||
chest_ce_ref(q, input, nslot, port_id, i);
|
||||
}
|
||||
interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0],
|
||||
2, r->symbols_ref[0], 3);
|
||||
} else {
|
||||
for (j=0;j<MAX_NSYMB;j++) {
|
||||
y[j] = ce[r->symbols_ref[0] * 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
|
||||
}
|
||||
}
|
||||
for (j=0;j<q->nof_symbols;j++) {
|
||||
ce[j * q->nof_prb * RE_X_RB + i] = y[j];
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Computes channel estimates for each reference in a slot.
|
||||
* Saves the result for the p-th port to the pointer ce[p]
|
||||
|
||||
/* Computes channel estimates for each reference in a subframe and port id.
|
||||
*/
|
||||
void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot) {
|
||||
int p;
|
||||
for (p=0;p<q->nof_ports;p++) {
|
||||
chest_ce_slot_port(q, input, ce[p], nslot, p);
|
||||
}
|
||||
}
|
||||
|
||||
int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports) {
|
||||
|
||||
if (nof_ports > MAX_PORTS) {
|
||||
fprintf(stderr, "Error: Maximum ports %d\n", MAX_PORTS);
|
||||
return -1;
|
||||
}
|
||||
bzero(q, sizeof(chest_t));
|
||||
|
||||
q->nof_ports = nof_ports;
|
||||
q->nof_symbols = CP_NSYMB(cp);
|
||||
q->cp = cp;
|
||||
q->nof_prb = nof_prb;
|
||||
|
||||
switch(interp) {
|
||||
case LINEAR:
|
||||
q->interp = interp_linear_offset;
|
||||
}
|
||||
|
||||
INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n",
|
||||
q->nof_symbols, nof_prb, nof_ports);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id) {
|
||||
if (port < 0 || port > q->nof_ports) {
|
||||
return -1;
|
||||
}
|
||||
if (nslot < 0 || nslot > NSLOTS_X_FRAME) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (refsignal_init_LTEDL(&q->refsignal[port][nslot], port, nslot, cell_id, q->cp, q->nof_prb)) {
|
||||
fprintf(stderr, "Error initiating CRS port=%d, slot=%d\n", port, nslot);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id) {
|
||||
int p;
|
||||
for (p=0;p<q->nof_ports;p++) {
|
||||
if (chest_ref_LTEDL_slot_port(q, p, nslot, cell_id)) {
|
||||
return -1;
|
||||
int chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id) {
|
||||
int n, slotsz, ret;
|
||||
slotsz = q->nof_symbols*q->nof_re;
|
||||
for (n=0;n<2;n++) {
|
||||
ret = chest_ce_slot_port(q, &input[n*slotsz], &ce[n*slotsz], 2*sf_idx+n, port_id);
|
||||
if (ret != LIBLTE_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int chest_ref_LTEDL(chest_t *q, int cell_id) {
|
||||
int n;
|
||||
/* Computes channel estimates for each reference in a slot for all ports.
|
||||
*/
|
||||
int chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, uint32_t nslot) {
|
||||
int p, ret;
|
||||
for (p=0;p<q->nof_ports;p++) {
|
||||
ret = chest_ce_slot_port(q, input, ce[p], nslot, p);
|
||||
if (ret != LIBLTE_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
/* Computes channel estimates for each reference in a subframe for all ports.
|
||||
*/
|
||||
int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint32_t sf_idx) {
|
||||
int p, n, slotsz, ret;
|
||||
slotsz = q->nof_symbols*q->nof_re;
|
||||
for (p=0;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;
|
||||
}
|
||||
}
|
||||
}
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int chest_init(chest_t *q, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_ports) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
nof_ports <= MAX_PORTS)
|
||||
{
|
||||
bzero(q, sizeof(chest_t));
|
||||
|
||||
q->nof_ports = nof_ports;
|
||||
q->nof_symbols = nof_symbols;
|
||||
q->nof_re = nof_re;
|
||||
|
||||
INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n",
|
||||
q->nof_symbols, q->nof_re, nof_ports);
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int chest_init_LTEDL(chest_t *q, lte_cell_t cell) {
|
||||
int ret;
|
||||
ret = chest_init(q, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports);
|
||||
if (ret != LIBLTE_SUCCESS) {
|
||||
return ret;
|
||||
} else {
|
||||
return chest_ref_LTEDL(q, cell);
|
||||
}
|
||||
}
|
||||
|
||||
int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_cell_t cell) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
port_id < MAX_PORTS &&
|
||||
nslot < NSLOTS_X_FRAME)
|
||||
{
|
||||
ret = refsignal_init_LTEDL(&q->refsignal[port_id][nslot], port_id, nslot, cell);
|
||||
|
||||
if (ret == LIBLTE_SUCCESS) {
|
||||
if (nslot == 0) {
|
||||
ret = interp_init(&q->interp_freq[port_id], LINEAR, q->refsignal[port_id][nslot].nof_refs/2, RE_X_RB/2);
|
||||
if (ret == LIBLTE_SUCCESS) {
|
||||
ret = interp_init(&q->interp_time[port_id], LINEAR, 2,
|
||||
q->refsignal[port_id][nslot].symbols_ref[1] - q->refsignal[port_id][nslot].symbols_ref[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int chest_ref_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) {
|
||||
int p, ret;
|
||||
for (p=0;p<q->nof_ports;p++) {
|
||||
ret = chest_ref_LTEDL_slot_port(q, nslot, p, cell);
|
||||
if (ret != LIBLTE_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int chest_ref_LTEDL(chest_t *q, lte_cell_t cell) {
|
||||
int n, ret;
|
||||
for (n=0;n<NSLOTS_X_FRAME;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) {
|
||||
int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot,
|
||||
lte_cell_t cell) {
|
||||
|
||||
unsigned int c_init;
|
||||
int ns, l, lp[2];
|
||||
int N_cp;
|
||||
int i;
|
||||
int ret = -1;
|
||||
uint32_t c_init;
|
||||
uint32_t ns, l, lp[2];
|
||||
uint32_t N_cp;
|
||||
uint32_t i;
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
sequence_t seq;
|
||||
int v;
|
||||
int mp;
|
||||
int nof_refs_x_symbol, nof_ref_symbols;
|
||||
uint32_t mp;
|
||||
uint32_t nof_refs_x_symbol, nof_ref_symbols;
|
||||
|
||||
bzero(q, sizeof(refsignal_t));
|
||||
bzero(&seq, sizeof(sequence_t));
|
||||
if (q != NULL &&
|
||||
port_id < MAX_PORTS &&
|
||||
nslot < NSLOTS_X_FRAME &&
|
||||
lte_cell_isvalid(&cell))
|
||||
{
|
||||
|
||||
bzero(q, sizeof(refsignal_t));
|
||||
bzero(&seq, sizeof(sequence_t));
|
||||
|
||||
if (CP_ISNORM(cp)) {
|
||||
N_cp = 1;
|
||||
} else {
|
||||
N_cp = 0;
|
||||
}
|
||||
if (CP_ISNORM(cell.cp)) {
|
||||
N_cp = 1;
|
||||
} else {
|
||||
N_cp = 0;
|
||||
}
|
||||
|
||||
if (port_id < 0 || port_id > (MAX_PORTS - 1)) {
|
||||
fprintf(stderr, "Invalid port id %d\n", port_id);
|
||||
return -1;
|
||||
}
|
||||
if (port_id < 2) {
|
||||
nof_ref_symbols = 2;
|
||||
lp[0] = 0;
|
||||
lp[1] = CP_NSYMB(cell.cp) - 3;
|
||||
} else {
|
||||
nof_ref_symbols = 1;
|
||||
lp[0] = 1;
|
||||
}
|
||||
nof_refs_x_symbol = 2 * cell.nof_prb;
|
||||
|
||||
if (port_id < 2) {
|
||||
nof_ref_symbols = 2;
|
||||
lp[0] = 0;
|
||||
lp[1] = CP_NSYMB(cp) - 3;
|
||||
} else {
|
||||
nof_ref_symbols = 1;
|
||||
lp[0] = 1;
|
||||
}
|
||||
nof_refs_x_symbol = 2 * nof_prb;
|
||||
q->nof_refs = nof_refs_x_symbol * nof_ref_symbols;
|
||||
q->nsymbols = nof_ref_symbols;
|
||||
q->voffset = cell.id%6;
|
||||
q->nof_prb = cell.nof_prb;
|
||||
|
||||
q->nof_refs = nof_refs_x_symbol * nof_ref_symbols;
|
||||
q->nsymbols = nof_ref_symbols;
|
||||
q->symbols_ref = malloc(sizeof(int) * nof_ref_symbols);
|
||||
q->voffset = cell_id%6;
|
||||
q->nof_prb = nof_prb;
|
||||
if (!q->symbols_ref) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(q->symbols_ref, lp, sizeof(int) * nof_ref_symbols);
|
||||
|
||||
q->refs = vec_malloc(q->nof_refs * sizeof(ref_t));
|
||||
if (!q->refs) {
|
||||
goto free_and_exit;
|
||||
}
|
||||
q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t));
|
||||
if (!q->ch_est) {
|
||||
goto free_and_exit;
|
||||
}
|
||||
|
||||
ns = nslot;
|
||||
for (l = 0; l < nof_ref_symbols; l++) {
|
||||
|
||||
c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell_id + 1)
|
||||
+ 2 * cell_id + N_cp;
|
||||
if (sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init)) {
|
||||
q->symbols_ref = malloc(sizeof(uint32_t) * nof_ref_symbols);
|
||||
if (!q->symbols_ref) {
|
||||
perror("malloc");
|
||||
goto free_and_exit;
|
||||
}
|
||||
|
||||
v = refsignal_v(port_id, ns, lp[l]);
|
||||
memcpy(q->symbols_ref, lp, sizeof(uint32_t) * nof_ref_symbols);
|
||||
|
||||
for (i = 0; i < nof_refs_x_symbol; i++) {
|
||||
mp = i + MAX_PRB - nof_prb;
|
||||
|
||||
/* generate signal */
|
||||
__real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2);
|
||||
__imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2);
|
||||
|
||||
/* mapping to resource elements */
|
||||
q->refs[idx(l,i)].freq_idx = refsignal_k(i, v, cell_id);
|
||||
q->refs[idx(l,i)].time_idx = lp[l];
|
||||
q->refs = vec_malloc(q->nof_refs * sizeof(ref_t));
|
||||
if (!q->refs) {
|
||||
goto free_and_exit;
|
||||
}
|
||||
q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t));
|
||||
if (!q->ch_est) {
|
||||
goto free_and_exit;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
ns = nslot;
|
||||
for (l = 0; l < nof_ref_symbols; l++) {
|
||||
|
||||
c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell.id + 1)
|
||||
+ 2 * cell.id + N_cp;
|
||||
ret = sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init);
|
||||
if (ret != LIBLTE_SUCCESS) {
|
||||
goto free_and_exit;
|
||||
}
|
||||
|
||||
v = refsignal_v(port_id, ns, lp[l]);
|
||||
|
||||
for (i = 0; i < nof_refs_x_symbol; i++) {
|
||||
mp = i + MAX_PRB - cell.nof_prb;
|
||||
|
||||
/* generate signal */
|
||||
__real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2);
|
||||
__imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2);
|
||||
|
||||
/* mapping to resource elements */
|
||||
q->refs[idx(l,i)].freq_idx = refsignal_k(i, (uint32_t) v, cell.id);
|
||||
q->refs[idx(l,i)].time_idx = lp[l];
|
||||
}
|
||||
}
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
free_and_exit:
|
||||
sequence_free(&seq);
|
||||
if (ret == -1) {
|
||||
if (ret != LIBLTE_ERROR_INVALID_INPUTS) {
|
||||
sequence_free(&seq);
|
||||
}
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
refsignal_free(q);
|
||||
}
|
||||
return ret;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
int lte_voffset(int symbol_id, int cell_id, int nof_ports) {
|
||||
bool lte_symbol_sz_isvalid(uint32_t symbol_sz) {
|
||||
if (symbol_sz == 128 ||
|
||||
symbol_sz == 256 ||
|
||||
symbol_sz == 512 ||
|
||||
symbol_sz == 1024 ||
|
||||
symbol_sz == 2048) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t lte_voffset(uint32_t symbol_id, uint32_t cell_id, uint32_t nof_ports) {
|
||||
if (nof_ports == 1 && symbol_id==0) {
|
||||
return (cell_id+3) % 6;
|
||||
} else {
|
||||
|
@ -106,7 +197,7 @@ int lte_voffset(int symbol_id, int cell_id, int nof_ports) {
|
|||
}
|
||||
|
||||
/* Returns the number of available RE per PRB */
|
||||
int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) {
|
||||
uint32_t lte_re_x_prb(uint32_t ns, uint32_t symbol, uint32_t nof_ports, uint32_t nof_symbols) {
|
||||
if (symbol == 0) {
|
||||
if (((ns % 2) == 0) || (ns == 1)) {
|
||||
return RE_X_RB - 4;
|
||||
|
@ -138,10 +229,10 @@ int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) {
|
|||
|
||||
|
||||
struct lte_band {
|
||||
int band;
|
||||
uint32_t band;
|
||||
float fd_low_mhz;
|
||||
int earfcn_offset;
|
||||
int earfcn_max;
|
||||
uint32_t earfcn_offset;
|
||||
uint32_t earfcn_max;
|
||||
enum band_geographical_area area;
|
||||
};
|
||||
|
||||
|
@ -186,9 +277,9 @@ int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type) {
|
|||
} else if (!strcmp(mimo_type_str, "multiplex")) {
|
||||
*type = SPATIAL_MULTIPLEX;
|
||||
} else {
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
return 0;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
char *lte_mimotype2str(lte_mimo_type_t type) {
|
||||
|
@ -203,12 +294,16 @@ char *lte_mimotype2str(lte_mimo_type_t type) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
float get_fd(struct lte_band *band, int earfcn) {
|
||||
return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset);
|
||||
float get_fd(struct lte_band *band, uint32_t earfcn) {
|
||||
if (earfcn > band->earfcn_offset) {
|
||||
return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset);
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
float lte_band_fd(int earfcn) {
|
||||
int i;
|
||||
float lte_band_fd(uint32_t earfcn) {
|
||||
uint32_t i;
|
||||
i=0;
|
||||
while(i < NOF_LTE_BANDS && lte_bands[i].earfcn_offset<earfcn) {
|
||||
i++;
|
||||
|
@ -220,27 +315,27 @@ float lte_band_fd(int earfcn) {
|
|||
return get_fd(<e_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(<e_bands[i], earfcn[j].id);
|
||||
}
|
||||
return j;
|
||||
return (int) j;
|
||||
}
|
||||
|
||||
int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems) {
|
||||
int i;
|
||||
int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, uint32_t max_elems) {
|
||||
uint32_t i;
|
||||
int n;
|
||||
int nof_fd = 0;
|
||||
for (i=0;i<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;
|
||||
}
|
||||
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 {
|
||||
sr = 0;
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
int bit = (i < frame_length) ? (input[i] & 1) : 0;
|
||||
sr = (sr << 1) | bit;
|
||||
for (j=0;j<q->R;j++) {
|
||||
output[q->R * i + j] = parity(sr & q->poly[j]);
|
||||
}
|
||||
}
|
||||
|
||||
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 (rv_idx == 0) {
|
||||
/* Sub-block interleaver (5.1.4.1.1) and bit collection */
|
||||
k = 0;
|
||||
for (s = 0; s < 2; s++) {
|
||||
for (j = 0; j < NCOLS; j++) {
|
||||
for (i = 0; i < nrows; i++) {
|
||||
if (s == 0) {
|
||||
kidx = k % K_p;
|
||||
} else {
|
||||
kidx = K_p + 2 * (k % K_p);
|
||||
}
|
||||
if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
|
||||
w_buff[kidx] = TX_NULL;
|
||||
} else {
|
||||
w_buff[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
|
||||
}
|
||||
k++;
|
||||
}
|
||||
if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
|
||||
tmp[kidx] = TX_NULL;
|
||||
} else {
|
||||
tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// d_k^(2) goes through special permutation
|
||||
for (k = 0; k < K_p; k++) {
|
||||
kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p;
|
||||
if ((kidx - ndummy) < 0) {
|
||||
w_buff[K_p + 2 * k + 1] = TX_NULL;
|
||||
} else {
|
||||
w_buff[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// d_k^(2) goes through special permutation
|
||||
for (k = 0; k < K_p; k++) {
|
||||
kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p;
|
||||
if ((kidx - ndummy) < 0) {
|
||||
tmp[K_p + 2 * k + 1] = TX_NULL;
|
||||
} else {
|
||||
tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
|
||||
}
|
||||
}
|
||||
|
||||
/* Bit selection and transmission 5.1.4.1.2 */
|
||||
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
|
||||
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
|
||||
|
||||
k0 = nrows
|
||||
* (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2);
|
||||
* (2 * (uint32_t) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2);
|
||||
k = 0;
|
||||
j = 0;
|
||||
|
||||
while (k < out_len) {
|
||||
if (tmp[(k0 + j) % N_cb] != TX_NULL) {
|
||||
output[k] = tmp[(k0 + j) % N_cb];
|
||||
if (w_buff[(k0 + j) % N_cb] != TX_NULL) {
|
||||
output[k] = w_buff[(k0 + j) % N_cb];
|
||||
k++;
|
||||
}
|
||||
j++;
|
||||
|
@ -132,23 +127,24 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output,
|
|||
|
||||
/* Undoes Turbo Code Rate Matching.
|
||||
* 3GPP TS 36.212 v10.1.0 section 5.1.4.1
|
||||
*
|
||||
* If rv_idx==0, the w_buff circular buffer is initialized. Every subsequent call
|
||||
* with rv_idx!=0 will soft-combine the LLRs from input with w_buff
|
||||
*/
|
||||
int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
|
||||
int out_len, int rv_idx) {
|
||||
int rm_turbo_rx(float *w_buff, uint32_t w_buff_len, float *input, uint32_t in_len, float *output,
|
||||
uint32_t out_len, uint32_t rv_idx) {
|
||||
|
||||
int nrows, ndummy, K_p, k0, N_cb, jp, kidx;
|
||||
int i, j, k;
|
||||
int d_i, d_j;
|
||||
bool isdummy;
|
||||
|
||||
float *tmp = (float*) q->buffer;
|
||||
|
||||
nrows = (int) (out_len / 3 - 1) / NCOLS + 1;
|
||||
nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1;
|
||||
K_p = nrows * NCOLS;
|
||||
if (3 * K_p > q->buffer_len) {
|
||||
if (3 * K_p > w_buff_len) {
|
||||
fprintf(stderr,
|
||||
"Input too large. Max output length including dummy bits is %d (3x%dx32, in_len %d)\n",
|
||||
q->buffer_len, nrows, out_len);
|
||||
w_buff_len, nrows, out_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -157,14 +153,16 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
|
|||
ndummy = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3 * K_p; i++) {
|
||||
tmp[i] = RX_NULL;
|
||||
if (rv_idx == 0) {
|
||||
for (i = 0; i < 3 * K_p; i++) {
|
||||
w_buff[i] = RX_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Undo bit collection. Account for dummy bits */
|
||||
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
|
||||
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
|
||||
k0 = nrows
|
||||
* (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2);
|
||||
* (2 * (uint32_t) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2);
|
||||
|
||||
k = 0;
|
||||
j = 0;
|
||||
|
@ -185,7 +183,7 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
|
|||
isdummy = true;
|
||||
}
|
||||
} else {
|
||||
int jpp = (jp - K_p - 1) / 2;
|
||||
uint32_t jpp = (jp - K_p - 1) / 2;
|
||||
kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p;
|
||||
if ((kidx - ndummy) < 0) {
|
||||
isdummy = true;
|
||||
|
@ -195,10 +193,10 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
|
|||
}
|
||||
|
||||
if (!isdummy) {
|
||||
if (tmp[jp] == RX_NULL) {
|
||||
tmp[jp] = input[k];
|
||||
if (w_buff[jp] == RX_NULL) {
|
||||
w_buff[jp] = input[k];
|
||||
} else if (input[k] != RX_NULL) {
|
||||
tmp[jp] += input[k]; /* soft combine LLRs */
|
||||
w_buff[jp] += input[k]; /* soft combine LLRs */
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
@ -213,15 +211,14 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
|
|||
if (j != 2) {
|
||||
kidx = K_p * j + (j + 1) * (RM_PERM_TC[d_j] * nrows + d_i);
|
||||
} else {
|
||||
|
||||
k = (i + ndummy - 1) % K_p;
|
||||
if (k < 0)
|
||||
k += K_p;
|
||||
kidx = (k / NCOLS + nrows * RM_PERM_TC[k % NCOLS]) % K_p;
|
||||
kidx = 2 * kidx + K_p + 1;
|
||||
}
|
||||
if (tmp[kidx] != RX_NULL) {
|
||||
output[i * 3 + j] = tmp[kidx];
|
||||
if (w_buff[kidx] != RX_NULL) {
|
||||
output[i * 3 + j] = w_buff[kidx];
|
||||
} else {
|
||||
output[i * 3 + j] = 0;
|
||||
}
|
||||
|
@ -233,25 +230,15 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
|
|||
/** High-level API */
|
||||
|
||||
int rm_turbo_initialize(rm_turbo_hl* h) {
|
||||
return rm_turbo_init(&h->q, 7000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** This function can be called in a subframe (1ms) basis */
|
||||
int rm_turbo_work(rm_turbo_hl* hl) {
|
||||
if (hl->init.direction) {
|
||||
rm_turbo_tx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.E,
|
||||
hl->ctrl_in.rv_idx);
|
||||
hl->out_len = hl->ctrl_in.E;
|
||||
} else {
|
||||
rm_turbo_rx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.S,
|
||||
hl->ctrl_in.rv_idx);
|
||||
hl->out_len = hl->ctrl_in.S;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rm_turbo_stop(rm_turbo_hl* hl) {
|
||||
rm_turbo_free(&hl->q);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
int dci_msg_to_ra_dl(dci_msg_t *msg, uint16_t msg_rnti, uint16_t c_rnti,
|
||||
lte_cell_t cell, uint32_t cfi,
|
||||
ra_pdsch_t *ra_dl)
|
||||
{
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (msg != NULL &&
|
||||
ra_dl != NULL &&
|
||||
lte_cell_isvalid(&cell) &&
|
||||
cfi > 0 &&
|
||||
cfi < 4)
|
||||
{
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
dci_msg_type_t type;
|
||||
if (dci_msg_get_type(msg, &type, cell.nof_prb, msg_rnti, c_rnti)) {
|
||||
fprintf(stderr, "Can't get DCI message type\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
dci_msg_type_fprint(stdout, type);
|
||||
}
|
||||
if (type.type == PDSCH_SCHED) {
|
||||
bzero(ra_dl, sizeof(ra_pdsch_t));
|
||||
|
||||
if (dci_msg_unpack_pdsch(msg, ra_dl, cell.nof_prb, msg_rnti != SIRNTI)) {
|
||||
fprintf(stderr, "Can't unpack PDSCH message\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
ra_pdsch_fprint(stdout, ra_dl, cell.nof_prb);
|
||||
}
|
||||
|
||||
if (ra_prb_get_dl(&ra_dl->prb_alloc, ra_dl, cell.nof_prb)) {
|
||||
fprintf(stderr, "Error computing resource allocation\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ra_prb_get_re_dl(&ra_dl->prb_alloc, cell.nof_prb, cell.nof_ports, cell.nof_prb<10?(cfi+1):cfi, cell.cp);
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
}
|
||||
q->nof_dcis = 0;
|
||||
q->max_dcis = max_dcis;
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dci_free(dci_t *q) {
|
||||
if (q->msg) {
|
||||
free(q->msg);
|
||||
}
|
||||
}
|
||||
|
||||
void dci_candidate_fprint(FILE *f, dci_candidate_t *q) {
|
||||
fprintf(f, "L: %d, nCCE: %d, RNTI: 0x%x, nBits: %d\n", q->L, q->ncce, q->rnti,
|
||||
q->nof_bits);
|
||||
}
|
||||
|
||||
int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti) {
|
||||
if (L >= 0 && L <= 3) {
|
||||
msg->location.L = (unsigned char) L;
|
||||
int dci_location_set(dci_location_t *c, uint32_t L, uint32_t nCCE) {
|
||||
if (L <= 3) {
|
||||
c->L = L;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid L %d\n", L);
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
if (nCCE >= 0 && nCCE <= 87) {
|
||||
msg->location.ncce = (unsigned char) nCCE;
|
||||
if (nCCE <= 87) {
|
||||
c->ncce = nCCE;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid nCCE %d\n", nCCE);
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
msg->location.rnti = rnti;
|
||||
return 0;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int riv_nbits(int nof_prb) {
|
||||
return (int) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2));
|
||||
bool dci_location_isvalid(dci_location_t *c) {
|
||||
if (c->L <= 3 && c->ncce <= 87) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const int ambiguous_sizes[10] = { 12, 14, 16, 20, 24, 26, 32, 40, 44, 56 };
|
||||
uint32_t riv_nbits(uint32_t nof_prb) {
|
||||
return (uint32_t) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2));
|
||||
}
|
||||
|
||||
bool is_ambiguous_size(int size) {
|
||||
const uint32_t ambiguous_sizes[10] = { 12, 14, 16, 20, 24, 26, 32, 40, 44, 56 };
|
||||
|
||||
bool is_ambiguous_size(uint32_t size) {
|
||||
int i;
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (size == ambiguous_sizes[i]) {
|
||||
|
@ -98,12 +132,12 @@ bool is_ambiguous_size(int size) {
|
|||
/**********************************
|
||||
* PAYLOAD sizeof functions
|
||||
* ********************************/
|
||||
int dci_format0_sizeof_(int nof_prb) {
|
||||
uint32_t dci_format0_sizeof_(uint32_t nof_prb) {
|
||||
return 1 + 1 + riv_nbits(nof_prb) + 5 + 1 + 2 + 3 + 1;
|
||||
}
|
||||
|
||||
int dci_format1A_sizeof(int nof_prb) {
|
||||
int n;
|
||||
uint32_t dci_format1A_sizeof(uint32_t nof_prb) {
|
||||
uint32_t n;
|
||||
n = 1 + 1 + riv_nbits(nof_prb) + 5 + 3 + 1 + 2 + 2;
|
||||
while (n < dci_format0_sizeof_(nof_prb)) {
|
||||
n++;
|
||||
|
@ -114,17 +148,17 @@ int dci_format1A_sizeof(int nof_prb) {
|
|||
return n;
|
||||
}
|
||||
|
||||
int dci_format0_sizeof(int nof_prb) {
|
||||
int n = dci_format0_sizeof_(nof_prb);
|
||||
uint32_t dci_format0_sizeof(uint32_t nof_prb) {
|
||||
uint32_t n = dci_format0_sizeof_(nof_prb);
|
||||
while (n < dci_format1A_sizeof(nof_prb)) {
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int dci_format1_sizeof(int nof_prb) {
|
||||
uint32_t dci_format1_sizeof(uint32_t nof_prb) {
|
||||
|
||||
int n = (int) ceilf((float) nof_prb / ra_type0_P(nof_prb)) + 5 + 3 + 1 + 2
|
||||
uint32_t n = (uint32_t) ceilf((float) nof_prb / ra_type0_P(nof_prb)) + 5 + 3 + 1 + 2
|
||||
+ 2;
|
||||
if (nof_prb > 10) {
|
||||
n++;
|
||||
|
@ -136,17 +170,17 @@ int dci_format1_sizeof(int nof_prb) {
|
|||
return n;
|
||||
}
|
||||
|
||||
int dci_format1C_sizeof(int nof_prb) {
|
||||
int n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true);
|
||||
int n_step = ra_type2_n_rb_step(nof_prb);
|
||||
int n = +riv_nbits((int) n_vrb_dl_gap1 / n_step) + 5;
|
||||
uint32_t dci_format1C_sizeof(uint32_t nof_prb) {
|
||||
uint32_t n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true);
|
||||
uint32_t n_step = ra_type2_n_rb_step(nof_prb);
|
||||
uint32_t n = riv_nbits((uint32_t) n_vrb_dl_gap1 / n_step) + 5;
|
||||
if (nof_prb >= 50) {
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int dci_format_sizeof(dci_format_t format, int nof_prb) {
|
||||
uint32_t dci_format_sizeof(dci_format_t format, uint32_t nof_prb) {
|
||||
switch (format) {
|
||||
case Format0:
|
||||
return dci_format0_sizeof(nof_prb);
|
||||
|
@ -157,7 +191,7 @@ int dci_format_sizeof(dci_format_t format, int nof_prb) {
|
|||
case Format1C:
|
||||
return dci_format1C_sizeof(nof_prb);
|
||||
default:
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,11 +204,11 @@ int dci_format_sizeof(dci_format_t format, int nof_prb) {
|
|||
*
|
||||
* TODO: TPC and cyclic shift for DM RS not implemented
|
||||
*/
|
||||
int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
|
||||
int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint32_t nof_prb) {
|
||||
|
||||
/* pack bits */
|
||||
char *y = msg->data;
|
||||
int n_ul_hop;
|
||||
uint32_t n_ul_hop;
|
||||
|
||||
*y++ = 0; // format differentiation
|
||||
if (data->freq_hop_fl == hop_disabled) { // frequency hopping
|
||||
|
@ -203,28 +237,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
|
|||
bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop);
|
||||
|
||||
/* pack MCS according to 8.6.1 of 36.213 */
|
||||
uint32_t mcs;
|
||||
if (data->cqi_request) {
|
||||
mcs = 29;
|
||||
} else {
|
||||
if (data->rv_idx) {
|
||||
mcs = 28 + data->rv_idx;
|
||||
} else {
|
||||
if (data->mcs.mod == MOD_NULL) {
|
||||
mcs = data->mcs.mcs_idx;
|
||||
} else {
|
||||
if (data->mcs.tbs) {
|
||||
if (data->mcs.tbs) {
|
||||
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs,
|
||||
ra_nprb_ul(data, nof_prb));
|
||||
}
|
||||
}
|
||||
mcs = ra_mcs_to_table_idx(&data->mcs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bit_pack(mcs, &y, 5);
|
||||
bit_pack(data->mcs_idx, &y, 5);
|
||||
|
||||
*y++ = data->ndi;
|
||||
|
||||
|
@ -241,33 +254,33 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
|
|||
*y++ = data->cqi_request;
|
||||
|
||||
// Padding with zeros
|
||||
int n = dci_format0_sizeof(nof_prb);
|
||||
uint32_t n = dci_format0_sizeof(nof_prb);
|
||||
while (y - msg->data < n) {
|
||||
*y++ = 0;
|
||||
}
|
||||
msg->location.nof_bits = (y - msg->data);
|
||||
return 0;
|
||||
msg->nof_bits = (y - msg->data);
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
/* Unpacks DCI format 0 data and store result in msg according
|
||||
* to 36.212 5.3.3.1.1
|
||||
*
|
||||
* TODO: TPC and cyclic shift for DM RS not implemented
|
||||
*/
|
||||
int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
|
||||
int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint32_t nof_prb) {
|
||||
|
||||
/* pack bits */
|
||||
char *y = msg->data;
|
||||
int n_ul_hop;
|
||||
uint32_t n_ul_hop;
|
||||
|
||||
/* Make sure it's a Format0 message */
|
||||
if (msg->location.nof_bits != dci_format_sizeof(Format0, nof_prb)) {
|
||||
if (msg->nof_bits != dci_format_sizeof(Format0, nof_prb)) {
|
||||
fprintf(stderr, "Invalid message length for format 0\n");
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
if (*y++ != 0) {
|
||||
fprintf(stderr,
|
||||
"Invalid format differentiation field value. This is Format1A\n");
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
if (*y++ == 0) {
|
||||
data->freq_hop_fl = hop_disabled;
|
||||
|
@ -286,11 +299,11 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
|
|||
uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - n_ul_hop);
|
||||
ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start,
|
||||
nof_prb, nof_prb);
|
||||
bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop);
|
||||
bit_pack((uint32_t) riv, &y, riv_nbits(nof_prb) - n_ul_hop);
|
||||
data->type2_alloc.riv = riv;
|
||||
|
||||
/* unpack MCS according to 8.6 of 36.213 */
|
||||
uint32_t mcs = bit_unpack(&y, 5);
|
||||
data->mcs_idx = bit_unpack(&y, 5);
|
||||
|
||||
data->ndi = *y++ ? true : false;
|
||||
|
||||
|
@ -301,23 +314,19 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
|
|||
data->cqi_request = *y++ ? true : false;
|
||||
|
||||
// 8.6.2 First paragraph
|
||||
if (mcs <= 28) {
|
||||
ra_mcs_from_idx_ul(mcs, &data->mcs);
|
||||
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx,
|
||||
ra_nprb_ul(data, nof_prb));
|
||||
if (data->mcs_idx <= 28) {
|
||||
ra_mcs_from_idx_ul(data->mcs_idx, ra_nprb_ul(data, nof_prb), &data->mcs);
|
||||
} else if (data->mcs_idx == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) {
|
||||
// 8.6.1 and 8.6.2 36.213 second paragraph
|
||||
data->mcs.mod = LTE_QPSK;
|
||||
data->mcs.tbs = 0;
|
||||
} else if (data->mcs_idx >= 29) {
|
||||
// Else leave TBS and use the previously used PUSCH modulation
|
||||
data->mcs.tbs = 0;
|
||||
data->rv_idx = data->mcs_idx - 28;
|
||||
}
|
||||
|
||||
// 8.6.1 and 8.6.2 36.213 second paragraph
|
||||
if (mcs == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) {
|
||||
data->mcs.mod = QPSK;
|
||||
}
|
||||
if (mcs > 29) {
|
||||
// Else leave MOD_NULL and use the previously used PUSCH modulation
|
||||
data->mcs.mod = MOD_NULL;
|
||||
data->rv_idx = mcs - 28;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
/* Packs DCI format 1 data to a sequence of bits and store them in msg according
|
||||
|
@ -326,7 +335,7 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
|
|||
* TODO: TPC commands
|
||||
*/
|
||||
|
||||
int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
|
||||
int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) {
|
||||
|
||||
/* pack bits */
|
||||
char *y = msg->data;
|
||||
|
@ -336,36 +345,26 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
|
|||
}
|
||||
|
||||
/* Resource allocation: type0 or type 1 */
|
||||
int P = ra_type0_P(nof_prb);
|
||||
int alloc_size = (int) ceilf((float) nof_prb / P);
|
||||
uint32_t P = ra_type0_P(nof_prb);
|
||||
uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P);
|
||||
switch (data->alloc_type) {
|
||||
case alloc_type0:
|
||||
bit_pack(data->type0_alloc.rbg_bitmask, &y, alloc_size);
|
||||
bit_pack((uint32_t) data->type0_alloc.rbg_bitmask, &y, alloc_size);
|
||||
break;
|
||||
case alloc_type1:
|
||||
bit_pack(data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P)));
|
||||
bit_pack((uint32_t) data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P)));
|
||||
*y++ = data->type1_alloc.shift ? 1 : 0;
|
||||
bit_pack(data->type1_alloc.vrb_bitmask, &y,
|
||||
bit_pack((uint32_t) data->type1_alloc.vrb_bitmask, &y,
|
||||
alloc_size - (int) ceilf(log2f(P)) - 1);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"Format 1 accepts type0 or type1 resource allocation only\n");
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
|
||||
}
|
||||
/* pack MCS according to 7.1.7 of 36.213 */
|
||||
uint32_t mcs;
|
||||
if (data->mcs.mod == MOD_NULL) {
|
||||
mcs = data->mcs.mcs_idx;
|
||||
} else {
|
||||
if (data->mcs.tbs) {
|
||||
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs,
|
||||
ra_nprb_dl(data, nof_prb));
|
||||
}
|
||||
mcs = ra_mcs_to_table_idx(&data->mcs);
|
||||
}
|
||||
bit_pack(mcs, &y, 5);
|
||||
/* pack MCS */
|
||||
bit_pack(data->mcs_idx, &y, 5);
|
||||
|
||||
/* harq process number */
|
||||
bit_pack(data->harq_process, &y, 3);
|
||||
|
@ -380,24 +379,24 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
|
|||
*y++ = 0;
|
||||
|
||||
// Padding with zeros
|
||||
int n = dci_format1_sizeof(nof_prb);
|
||||
uint32_t n = dci_format1_sizeof(nof_prb);
|
||||
while (y - msg->data < n) {
|
||||
*y++ = 0;
|
||||
}
|
||||
msg->location.nof_bits = (y - msg->data);
|
||||
msg->nof_bits = (y - msg->data);
|
||||
|
||||
return 0;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
|
||||
int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) {
|
||||
|
||||
/* pack bits */
|
||||
char *y = msg->data;
|
||||
|
||||
/* Make sure it's a Format1 message */
|
||||
if (msg->location.nof_bits != dci_format_sizeof(Format1, nof_prb)) {
|
||||
if (msg->nof_bits != dci_format_sizeof(Format1, nof_prb)) {
|
||||
fprintf(stderr, "Invalid message length for format 1\n");
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
if (nof_prb > 10) {
|
||||
|
@ -407,8 +406,8 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
|
|||
}
|
||||
|
||||
/* Resource allocation: type0 or type 1 */
|
||||
int P = ra_type0_P(nof_prb);
|
||||
int alloc_size = (int) ceilf((float) nof_prb / P);
|
||||
uint32_t P = ra_type0_P(nof_prb);
|
||||
uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P);
|
||||
switch (data->alloc_type) {
|
||||
case alloc_type0:
|
||||
data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size);
|
||||
|
@ -420,17 +419,17 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
|
|||
alloc_size - (int) ceilf(log2f(P)) - 1);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"Format 1 accepts type0 or type1 resource allocation only\n");
|
||||
return -1;
|
||||
fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n");
|
||||
return LIBLTE_ERROR;
|
||||
|
||||
}
|
||||
/* pack MCS according to 7.1.7 of 36.213 */
|
||||
uint32_t mcs = bit_unpack(&y, 5);
|
||||
data->mcs.mcs_idx = mcs;
|
||||
ra_mcs_from_idx_dl(mcs, &data->mcs);
|
||||
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_dl(data, nof_prb));
|
||||
|
||||
/* unpack MCS according to 7.1.7 of 36.213 */
|
||||
data->mcs_idx = bit_unpack(&y, 5);
|
||||
if (ra_mcs_from_idx_dl(data->mcs_idx, ra_nprb_dl(data, nof_prb), &data->mcs)) {
|
||||
fprintf(stderr, "Error getting MCS\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
/* harq process number */
|
||||
data->harq_process = bit_unpack(&y, 3);
|
||||
|
||||
|
@ -441,14 +440,14 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
|
|||
|
||||
// TPC not implemented
|
||||
|
||||
return 0;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
/* Packs DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
|
||||
*
|
||||
* TODO: RA procedure initiated by PDCCH, TPC commands
|
||||
*/
|
||||
int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
|
||||
int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb,
|
||||
bool crc_is_crnti) {
|
||||
|
||||
/* pack bits */
|
||||
|
@ -458,7 +457,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
|
|||
|
||||
if (data->alloc_type != alloc_type2) {
|
||||
fprintf(stderr, "Format 1A accepts type2 resource allocation only\n");
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
*y++ = data->type2_alloc.mode; // localized or distributed VRB assignment
|
||||
|
@ -467,10 +466,10 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
|
|||
if (data->type2_alloc.L_crb > nof_prb) {
|
||||
fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n",
|
||||
data->type2_alloc.L_crb);
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
} else {
|
||||
int n_vrb_dl;
|
||||
uint32_t n_vrb_dl;
|
||||
if (crc_is_crnti && nof_prb > 50) {
|
||||
n_vrb_dl = 16;
|
||||
} else {
|
||||
|
@ -480,7 +479,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
|
|||
fprintf(stderr,
|
||||
"L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n",
|
||||
data->type2_alloc.L_crb, n_vrb_dl);
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
/* pack RIV according to 7.1.6.3 of 36.213 */
|
||||
|
@ -491,7 +490,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
|
|||
} else {
|
||||
riv = data->type2_alloc.riv;
|
||||
}
|
||||
int nb_gap = 0;
|
||||
uint32_t nb_gap = 0;
|
||||
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
|
||||
nb_gap = 1;
|
||||
*y++ = data->type2_alloc.n_gap;
|
||||
|
@ -499,23 +498,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
|
|||
bit_pack(riv, &y, riv_nbits(nof_prb) - nb_gap);
|
||||
|
||||
// in format1A, MCS = TBS according to 7.1.7.2 of 36.213
|
||||
uint32_t mcs;
|
||||
if (data->mcs.mod == MOD_NULL) {
|
||||
mcs = data->mcs.mcs_idx;
|
||||
} else {
|
||||
if (data->mcs.tbs) {
|
||||
// In format 1A, n_prb_1a is 2 or 3 if crc is not scrambled with C-RNTI
|
||||
int n_prb;
|
||||
if (!crc_is_crnti) {
|
||||
n_prb = ra_nprb_dl(data, nof_prb);
|
||||
} else {
|
||||
n_prb = data->type2_alloc.n_prb1a == nprb1a_2 ? 2 : 3;
|
||||
}
|
||||
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, n_prb);
|
||||
}
|
||||
mcs = data->mcs.tbs_idx;
|
||||
}
|
||||
bit_pack(mcs, &y, 5);
|
||||
bit_pack(data->mcs_idx, &y, 5);
|
||||
|
||||
bit_pack(data->harq_process, &y, 3);
|
||||
|
||||
|
@ -538,34 +521,33 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb,
|
|||
}
|
||||
|
||||
// Padding with zeros
|
||||
int n = dci_format1A_sizeof(nof_prb);
|
||||
uint32_t n = dci_format1A_sizeof(nof_prb);
|
||||
while (y - msg->data < n) {
|
||||
*y++ = 0;
|
||||
}
|
||||
msg->location.nof_bits = (y - msg->data);
|
||||
msg->nof_bits = (y - msg->data);
|
||||
|
||||
return 0;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
/* Unpacks DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
|
||||
*
|
||||
*/
|
||||
int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb,
|
||||
int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb,
|
||||
bool crc_is_crnti) {
|
||||
|
||||
/* pack bits */
|
||||
char *y = msg->data;
|
||||
|
||||
/* Make sure it's a Format0 message */
|
||||
if (msg->location.nof_bits != dci_format_sizeof(Format1A, nof_prb)) {
|
||||
if (msg->nof_bits != dci_format_sizeof(Format1A, nof_prb)) {
|
||||
fprintf(stderr, "Invalid message length for format 1A\n");
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
if (*y++ != 1) {
|
||||
fprintf(stderr,
|
||||
"Invalid format differentiation field value. This is Format0\n");
|
||||
return -1;
|
||||
fprintf(stderr, "Invalid format differentiation field value. This is Format0\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
data->alloc_type = alloc_type2;
|
||||
|
@ -575,12 +557,12 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb,
|
|||
data->type2_alloc.n_gap = t2_ng1;
|
||||
|
||||
/* unpack RIV according to 7.1.6.3 of 36.213 */
|
||||
int nb_gap = 0;
|
||||
uint32_t nb_gap = 0;
|
||||
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
|
||||
nb_gap = 1;
|
||||
data->type2_alloc.n_gap = *y++;
|
||||
}
|
||||
int nof_vrb;
|
||||
uint32_t nof_vrb;
|
||||
if (data->type2_alloc.mode == t2_loc) {
|
||||
nof_vrb = nof_prb;
|
||||
} else {
|
||||
|
@ -592,7 +574,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb,
|
|||
data->type2_alloc.riv = riv;
|
||||
|
||||
// unpack MCS
|
||||
data->mcs.mcs_idx = bit_unpack(&y, 5);
|
||||
data->mcs_idx = bit_unpack(&y, 5);
|
||||
|
||||
data->harq_process = bit_unpack(&y, 3);
|
||||
|
||||
|
@ -613,23 +595,23 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb,
|
|||
y++; // MSB of TPC is reserved
|
||||
data->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS
|
||||
}
|
||||
data->mcs.tbs_idx = data->mcs.mcs_idx;
|
||||
int n_prb;
|
||||
|
||||
uint32_t n_prb;
|
||||
if (crc_is_crnti) {
|
||||
n_prb = ra_nprb_dl(data, nof_prb);
|
||||
} else {
|
||||
n_prb = data->type2_alloc.n_prb1a == nprb1a_2 ? 2 : 3;
|
||||
}
|
||||
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, n_prb);
|
||||
data->mcs.mod = QPSK;
|
||||
data->mcs.tbs = ra_tbs_from_idx(data->mcs_idx, n_prb);
|
||||
data->mcs.mod = LTE_QPSK;
|
||||
|
||||
return 0;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
/* Format 1C for compact scheduling of PDSCH words
|
||||
*
|
||||
*/
|
||||
int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
|
||||
int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) {
|
||||
|
||||
/* pack bits */
|
||||
char *y = msg->data;
|
||||
|
@ -637,32 +619,31 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
|
|||
if (data->alloc_type != alloc_type2 || data->type2_alloc.mode != t2_dist) {
|
||||
fprintf(stderr,
|
||||
"Format 1C accepts distributed type2 resource allocation only\n");
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
if (nof_prb >= 50) {
|
||||
*y++ = data->type2_alloc.n_gap;
|
||||
}
|
||||
int n_step = ra_type2_n_rb_step(nof_prb);
|
||||
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
|
||||
uint32_t n_step = ra_type2_n_rb_step(nof_prb);
|
||||
uint32_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
|
||||
|
||||
if (data->type2_alloc.L_crb > ((int) n_vrb_dl / n_step) * n_step) {
|
||||
fprintf(stderr,
|
||||
"L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n",
|
||||
data->type2_alloc.L_crb, ((int) n_vrb_dl / n_step) * n_step);
|
||||
return -1;
|
||||
if (data->type2_alloc.L_crb > ((uint32_t) n_vrb_dl / n_step) * n_step) {
|
||||
fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n",
|
||||
data->type2_alloc.L_crb, ((uint32_t) n_vrb_dl / n_step) * n_step);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
if (data->type2_alloc.L_crb % n_step) {
|
||||
fprintf(stderr, "L_crb must be multiple of n_step\n");
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
if (data->type2_alloc.RB_start % n_step) {
|
||||
fprintf(stderr, "RB_start must be multiple of n_step\n");
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
int L_p = data->type2_alloc.L_crb / n_step;
|
||||
int RB_p = data->type2_alloc.RB_start / n_step;
|
||||
int n_vrb_p = (int) n_vrb_dl / n_step;
|
||||
uint32_t L_p = data->type2_alloc.L_crb / n_step;
|
||||
uint32_t RB_p = data->type2_alloc.RB_start / n_step;
|
||||
uint32_t n_vrb_p = (int) n_vrb_dl / n_step;
|
||||
|
||||
uint32_t riv;
|
||||
if (data->type2_alloc.L_crb) {
|
||||
|
@ -673,60 +654,50 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
|
|||
bit_pack(riv, &y, riv_nbits((int) n_vrb_dl / n_step));
|
||||
|
||||
// in format1C, MCS = TBS according to 7.1.7.2 of 36.213
|
||||
uint32_t mcs;
|
||||
if (data->mcs.mod == MOD_NULL) {
|
||||
mcs = data->mcs.mcs_idx;
|
||||
} else {
|
||||
if (data->mcs.tbs) {
|
||||
data->mcs.tbs_idx = ra_tbs_to_table_idx_format1c(data->mcs.tbs);
|
||||
}
|
||||
mcs = data->mcs.tbs_idx;
|
||||
}
|
||||
bit_pack(mcs, &y, 5);
|
||||
bit_pack(data->mcs_idx, &y, 5);
|
||||
|
||||
msg->location.nof_bits = (y - msg->data);
|
||||
msg->nof_bits = (y - msg->data);
|
||||
|
||||
return 0;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
|
||||
uint16_t L_p, RB_p;
|
||||
int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) {
|
||||
uint32_t L_p, RB_p;
|
||||
|
||||
/* pack bits */
|
||||
char *y = msg->data;
|
||||
|
||||
if (msg->location.nof_bits != dci_format_sizeof(Format1C, nof_prb)) {
|
||||
if (msg->nof_bits != dci_format_sizeof(Format1C, nof_prb)) {
|
||||
fprintf(stderr, "Invalid message length for format 1C\n");
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
data->alloc_type = alloc_type2;
|
||||
data->type2_alloc.mode = t2_dist;
|
||||
if (nof_prb >= 50) {
|
||||
data->type2_alloc.n_gap = *y++;
|
||||
}
|
||||
int n_step = ra_type2_n_rb_step(nof_prb);
|
||||
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
|
||||
uint32_t n_step = ra_type2_n_rb_step(nof_prb);
|
||||
uint32_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
|
||||
|
||||
uint32_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl / n_step));
|
||||
int n_vrb_p = (int) n_vrb_dl / n_step;
|
||||
uint32_t n_vrb_p = (uint32_t) n_vrb_dl / n_step;
|
||||
|
||||
ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p);
|
||||
data->type2_alloc.L_crb = L_p * n_step;
|
||||
data->type2_alloc.RB_start = RB_p * n_step;
|
||||
data->type2_alloc.riv = riv;
|
||||
|
||||
data->mcs.mcs_idx = bit_unpack(&y, 5);
|
||||
data->mcs.tbs_idx = data->mcs.mcs_idx;
|
||||
data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs.tbs_idx);
|
||||
data->mcs.mod = QPSK;
|
||||
data->mcs_idx = bit_unpack(&y, 5);
|
||||
data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs_idx);
|
||||
data->mcs.mod = LTE_QPSK;
|
||||
|
||||
msg->location.nof_bits = (y - msg->data);
|
||||
msg->nof_bits = (y - msg->data);
|
||||
|
||||
return 0;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format,
|
||||
int nof_prb, bool crc_is_crnti) {
|
||||
uint32_t nof_prb, bool crc_is_crnti) {
|
||||
switch (format) {
|
||||
case Format1:
|
||||
return dci_format1_pack(data, msg, nof_prb);
|
||||
|
@ -737,28 +708,28 @@ int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format,
|
|||
default:
|
||||
fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n",
|
||||
dci_format_string(format));
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb,
|
||||
int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb,
|
||||
bool crc_is_crnti) {
|
||||
if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) {
|
||||
if (msg->nof_bits == dci_format_sizeof(Format1, nof_prb)) {
|
||||
return dci_format1_unpack(msg, data, nof_prb);
|
||||
} else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
|
||||
} else if (msg->nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
|
||||
return dci_format1As_unpack(msg, data, nof_prb, crc_is_crnti);
|
||||
} else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
|
||||
} else if (msg->nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
|
||||
return dci_format1Cs_unpack(msg, data, nof_prb);
|
||||
} else {
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
|
||||
int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, uint32_t nof_prb) {
|
||||
return dci_format0_pack(data, msg, nof_prb);
|
||||
}
|
||||
|
||||
int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
|
||||
int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, uint32_t nof_prb) {
|
||||
return dci_format0_unpack(msg, data, nof_prb);
|
||||
}
|
||||
|
||||
|
@ -798,36 +769,38 @@ void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) {
|
|||
}
|
||||
}
|
||||
|
||||
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb,
|
||||
unsigned short crnti) {
|
||||
if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb)
|
||||
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint32_t nof_prb,
|
||||
uint16_t msg_rnti, uint16_t crnti)
|
||||
{
|
||||
DEBUG("Get message type: nof_bits=%d, msg_rnti=0x%x, crnti=0x%x\n", msg->nof_bits, msg_rnti, crnti);
|
||||
if (msg->nof_bits == dci_format_sizeof(Format0, nof_prb)
|
||||
&& !msg->data[0]) {
|
||||
type->type = PUSCH_SCHED;
|
||||
type->format = Format0;
|
||||
return 0;
|
||||
} else if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) {
|
||||
return LIBLTE_SUCCESS;
|
||||
} else if (msg->nof_bits == dci_format_sizeof(Format1, nof_prb)) {
|
||||
type->type = PDSCH_SCHED; // only these 2 types supported
|
||||
type->format = Format1;
|
||||
return 0;
|
||||
} else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
|
||||
if (msg->location.rnti == crnti) {
|
||||
return LIBLTE_SUCCESS;
|
||||
} else if (msg->nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
|
||||
if (msg_rnti == crnti) {
|
||||
type->type = RA_PROC_PDCCH;
|
||||
type->format = Format1A;
|
||||
} else {
|
||||
type->type = PDSCH_SCHED; // only these 2 types supported
|
||||
type->format = Format1A;
|
||||
}
|
||||
return 0;
|
||||
} else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
|
||||
if (msg->location.rnti == MRNTI) {
|
||||
return LIBLTE_SUCCESS;
|
||||
} else if (msg->nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
|
||||
if (msg_rnti == MRNTI) {
|
||||
type->type = MCCH_CHANGE;
|
||||
type->format = Format1C;
|
||||
} else {
|
||||
type->type = PDSCH_SCHED; // only these 2 types supported
|
||||
type->format = Format1C;
|
||||
}
|
||||
return 0;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
return -1;
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,31 +50,45 @@ bool pbch_exists(int nframe, int nslot) {
|
|||
return (!(nframe % 5) && nslot == 1);
|
||||
}
|
||||
|
||||
int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id,
|
||||
bool put) {
|
||||
int pbch_cp(cf_t *input, cf_t *output, lte_cell_t cell, bool put) {
|
||||
int i;
|
||||
cf_t *ptr;
|
||||
assert(cell_id >= 0);
|
||||
|
||||
if (put) {
|
||||
ptr = input;
|
||||
output += nof_prb * RE_X_RB / 2 - 36;
|
||||
output += cell.nof_prb * RE_X_RB / 2 - 36;
|
||||
} else {
|
||||
ptr = output;
|
||||
input += nof_prb * RE_X_RB / 2 - 36;
|
||||
input += cell.nof_prb * RE_X_RB / 2 - 36;
|
||||
}
|
||||
|
||||
|
||||
/* symbol 0 & 1 */
|
||||
for (i = 0; i < 2; i++) {
|
||||
prb_cp_ref(&input, &output, cell_id % 3, 4, 6, put);
|
||||
prb_cp_ref(&input, &output, cell.id % 3, 4, 4*6, put);
|
||||
if (put) {
|
||||
output += cell.nof_prb * RE_X_RB - 2*36;
|
||||
} else {
|
||||
input += cell.nof_prb * RE_X_RB - 2*36;
|
||||
}
|
||||
}
|
||||
/* symbols 2 & 3 */
|
||||
if (CP_ISNORM(cp)) {
|
||||
if (CP_ISNORM(cell.cp)) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
prb_cp(&input, &output, 6);
|
||||
if (put) {
|
||||
output += cell.nof_prb * RE_X_RB - 2*36;
|
||||
} else {
|
||||
input += cell.nof_prb * RE_X_RB - 2*36;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
prb_cp(&input, &output, 6);
|
||||
prb_cp_ref(&input, &output, cell_id % 3, 4, 6, put);
|
||||
if (put) {
|
||||
output += cell.nof_prb * RE_X_RB - 2*36;
|
||||
} else {
|
||||
input += cell.nof_prb * RE_X_RB - 2*36;
|
||||
}
|
||||
prb_cp_ref(&input, &output, cell.id % 3, 4, 4*6, put);
|
||||
}
|
||||
if (put) {
|
||||
return input - ptr;
|
||||
|
@ -90,9 +104,8 @@ int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id,
|
|||
*
|
||||
* 36.211 10.3 section 6.6.4
|
||||
*/
|
||||
int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp,
|
||||
int cell_id) {
|
||||
return pbch_cp(pbch, slot1_data, nof_prb, cp, cell_id, true);
|
||||
int pbch_put(cf_t *pbch, cf_t *slot1_data, lte_cell_t cell) {
|
||||
return pbch_cp(pbch, slot1_data, cell, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,92 +115,96 @@ int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp,
|
|||
*
|
||||
* 36.211 10.3 section 6.6.4
|
||||
*/
|
||||
int pbch_get(cf_t *slot1_data, cf_t *pbch, int nof_prb, lte_cp_t cp,
|
||||
int cell_id) {
|
||||
return pbch_cp(slot1_data, pbch, nof_prb, cp, cell_id, false);
|
||||
int pbch_get(cf_t *slot1_data, cf_t *pbch, lte_cell_t cell) {
|
||||
return pbch_cp(slot1_data, pbch, cell, false);
|
||||
}
|
||||
|
||||
/** Initializes the PBCH transmitter and receiver */
|
||||
int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) {
|
||||
int ret = -1;
|
||||
if (cell_id < 0) {
|
||||
return -1;
|
||||
}
|
||||
bzero(q, sizeof(pbch_t));
|
||||
q->cell_id = cell_id;
|
||||
q->cp = cp;
|
||||
q->nof_prb = nof_prb;
|
||||
/** Initializes the PBCH transmitter and receiver.
|
||||
* At the receiver, the field nof_ports in the cell structure indicates the
|
||||
* maximum number of BS transmitter ports to look for.
|
||||
*/
|
||||
int pbch_init(pbch_t *q, lte_cell_t cell) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (modem_table_std(&q->mod, LTE_QPSK, true)) {
|
||||
goto clean;
|
||||
}
|
||||
demod_soft_init(&q->demod);
|
||||
demod_soft_table_set(&q->demod, &q->mod);
|
||||
demod_soft_alg_set(&q->demod, APPROX);
|
||||
if (sequence_pbch(&q->seq_pbch, q->cp, q->cell_id)) {
|
||||
goto clean;
|
||||
}
|
||||
if (q != NULL &&
|
||||
lte_cell_isvalid(&cell))
|
||||
{
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
int poly[3] = { 0x6D, 0x4F, 0x57 };
|
||||
if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) {
|
||||
goto clean;
|
||||
}
|
||||
if (crc_init(&q->crc, LTE_CRC16, 16)) {
|
||||
goto clean;
|
||||
}
|
||||
q->encoder.K = 7;
|
||||
q->encoder.R = 3;
|
||||
q->encoder.tail_biting = true;
|
||||
memcpy(q->encoder.poly, poly, 3 * sizeof(int));
|
||||
bzero(q, sizeof(pbch_t));
|
||||
q->cell = cell;
|
||||
|
||||
q->nof_symbols = (CP_ISNORM(q->cp)) ? PBCH_RE_CPNORM : PBCH_RE_CPEXT;
|
||||
|
||||
q->pbch_d = malloc(sizeof(cf_t) * q->nof_symbols);
|
||||
if (!q->pbch_d) {
|
||||
goto clean;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < MAX_PORTS_CTRL; i++) {
|
||||
q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols);
|
||||
if (!q->ce[i]) {
|
||||
if (modem_table_lte(&q->mod, LTE_QPSK, true)) {
|
||||
goto clean;
|
||||
}
|
||||
q->pbch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols);
|
||||
if (!q->pbch_x[i]) {
|
||||
demod_soft_init(&q->demod);
|
||||
demod_soft_table_set(&q->demod, &q->mod);
|
||||
demod_soft_alg_set(&q->demod, APPROX);
|
||||
if (sequence_pbch(&q->seq_pbch, q->cell.cp, q->cell.id)) {
|
||||
goto clean;
|
||||
}
|
||||
q->pbch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols);
|
||||
if (!q->pbch_symbols[i]) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
q->pbch_llr = malloc(sizeof(float) * q->nof_symbols * 4 * 2);
|
||||
if (!q->pbch_llr) {
|
||||
goto clean;
|
||||
}
|
||||
q->temp = malloc(sizeof(float) * q->nof_symbols * 4 * 2);
|
||||
if (!q->temp) {
|
||||
goto clean;
|
||||
}
|
||||
q->pbch_rm_f = malloc(sizeof(float) * 120);
|
||||
if (!q->pbch_rm_f) {
|
||||
goto clean;
|
||||
}
|
||||
q->pbch_rm_b = malloc(sizeof(float) * q->nof_symbols * 4 * 2);
|
||||
if (!q->pbch_rm_b) {
|
||||
goto clean;
|
||||
}
|
||||
q->data = malloc(sizeof(char) * 40);
|
||||
if (!q->data) {
|
||||
goto clean;
|
||||
}
|
||||
q->data_enc = malloc(sizeof(char) * 120);
|
||||
if (!q->data_enc) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
clean: if (ret == -1) {
|
||||
uint32_t poly[3] = { 0x6D, 0x4F, 0x57 };
|
||||
if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) {
|
||||
goto clean;
|
||||
}
|
||||
if (crc_init(&q->crc, LTE_CRC16, 16)) {
|
||||
goto clean;
|
||||
}
|
||||
q->encoder.K = 7;
|
||||
q->encoder.R = 3;
|
||||
q->encoder.tail_biting = true;
|
||||
memcpy(q->encoder.poly, poly, 3 * sizeof(int));
|
||||
|
||||
q->nof_symbols = (CP_ISNORM(q->cell.cp)) ? PBCH_RE_CPNORM : PBCH_RE_CPEXT;
|
||||
|
||||
q->pbch_d = malloc(sizeof(cf_t) * q->nof_symbols);
|
||||
if (!q->pbch_d) {
|
||||
goto clean;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols);
|
||||
if (!q->ce[i]) {
|
||||
goto clean;
|
||||
}
|
||||
q->pbch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols);
|
||||
if (!q->pbch_x[i]) {
|
||||
goto clean;
|
||||
}
|
||||
q->pbch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols);
|
||||
if (!q->pbch_symbols[i]) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
q->pbch_llr = malloc(sizeof(float) * q->nof_symbols * 4 * 2);
|
||||
if (!q->pbch_llr) {
|
||||
goto clean;
|
||||
}
|
||||
q->temp = malloc(sizeof(float) * q->nof_symbols * 4 * 2);
|
||||
if (!q->temp) {
|
||||
goto clean;
|
||||
}
|
||||
q->pbch_rm_f = malloc(sizeof(float) * 120);
|
||||
if (!q->pbch_rm_f) {
|
||||
goto clean;
|
||||
}
|
||||
q->pbch_rm_b = malloc(sizeof(float) * q->nof_symbols * 4 * 2);
|
||||
if (!q->pbch_rm_b) {
|
||||
goto clean;
|
||||
}
|
||||
q->data = malloc(sizeof(char) * 40);
|
||||
if (!q->data) {
|
||||
goto clean;
|
||||
}
|
||||
q->data_enc = malloc(sizeof(char) * 120);
|
||||
if (!q->data_enc) {
|
||||
goto clean;
|
||||
}
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
clean:
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
pbch_free(q);
|
||||
}
|
||||
return ret;
|
||||
|
@ -198,7 +215,7 @@ void pbch_free(pbch_t *q) {
|
|||
free(q->pbch_d);
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < MAX_PORTS_CTRL; i++) {
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
if (q->ce[i]) {
|
||||
free(q->ce[i]);
|
||||
}
|
||||
|
@ -355,15 +372,15 @@ void crc_set_mask(char *data, int nof_ports) {
|
|||
*
|
||||
* Returns 0 if the data is correct, -1 otherwise
|
||||
*/
|
||||
int pbch_crc_check(pbch_t *q, char *bits, int nof_ports) {
|
||||
uint32_t pbch_crc_check(pbch_t *q, char *bits, uint32_t nof_ports) {
|
||||
char data[40];
|
||||
memcpy(data, bits, 40 * sizeof(char));
|
||||
crc_set_mask(data, nof_ports);
|
||||
return crc_checksum(&q->crc, data, 40);
|
||||
}
|
||||
|
||||
int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n,
|
||||
int nof_bits, int nof_ports) {
|
||||
int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, uint32_t src, uint32_t dst, uint32_t n,
|
||||
uint32_t nof_bits, uint32_t nof_ports) {
|
||||
int j;
|
||||
|
||||
memcpy(&q->temp[dst * nof_bits], &q->pbch_llr[src * nof_bits],
|
||||
|
@ -417,150 +434,178 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n,
|
|||
/* Decodes the PBCH channel
|
||||
*
|
||||
* The PBCH spans in 40 ms. This function is called every 10 ms. It tries to decode the MIB
|
||||
* given the symbols of the slot #1 of each radio frame. Successive calls will use more frames
|
||||
* given the symbols of a subframe (1 ms). Successive calls will use more subframes
|
||||
* to help the decoding process.
|
||||
*
|
||||
* Returns 1 if successfully decoded MIB, 0 if not and -1 on error
|
||||
*/
|
||||
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
|
||||
float ebno, pbch_mib_t *mib) {
|
||||
int src, dst, res, nb;
|
||||
int nant_[3] = { 1, 2, 4 };
|
||||
int na, nant;
|
||||
|
||||
/* Set pointers for layermapping & precoding */
|
||||
int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mib) {
|
||||
uint32_t src, dst, nb;
|
||||
uint32_t nant_[3] = { 1, 2, 4 };
|
||||
uint32_t na, nant;
|
||||
cf_t *slot1_symbols;
|
||||
int i;
|
||||
int nof_bits = 2 * q->nof_symbols;
|
||||
int nof_bits;
|
||||
cf_t *x[MAX_LAYERS];
|
||||
cf_t *ce_slot[MAX_PORTS];
|
||||
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
sf_symbols != NULL &&
|
||||
mib != NULL)
|
||||
{
|
||||
for (i=0;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));
|
||||
/* Set pointers for layermapping & precoding */
|
||||
nof_bits = 2 * q->nof_symbols;
|
||||
|
||||
/* extract symbols */
|
||||
if (q->nof_symbols
|
||||
!= pbch_get(slot1_symbols, q->pbch_symbols[0], q->nof_prb, q->cp,
|
||||
q->cell_id)) {
|
||||
fprintf(stderr, "There was an error getting the PBCH symbols\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* extract channel estimates */
|
||||
for (i = 0; i < MAX_PORTS_CTRL; i++) {
|
||||
if (q->nof_symbols
|
||||
!= pbch_get(ce[i], q->ce[i], q->nof_prb, q->cp, q->cell_id)) {
|
||||
/* number of layers equals number of ports */
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
x[i] = q->pbch_x[i];
|
||||
}
|
||||
memset(&x[MAX_PORTS], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS));
|
||||
|
||||
/* extract symbols */
|
||||
if (q->nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols[0], q->cell)) {
|
||||
fprintf(stderr, "There was an error getting the PBCH symbols\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
q->frame_idx++;
|
||||
res = 0;
|
||||
|
||||
/* Try decoding for 1 to 4 antennas */
|
||||
for (na = 0; na < 3 && !res; na++) {
|
||||
nant = nant_[na];
|
||||
|
||||
INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx);
|
||||
|
||||
/* in conctrol channels, only diversity is supported */
|
||||
if (nant == 1) {
|
||||
/* no need for layer demapping */
|
||||
predecoding_single_zf(q->pbch_symbols[0], q->ce[0], q->pbch_d,
|
||||
q->nof_symbols);
|
||||
} else {
|
||||
predecoding_diversity_zf(q->pbch_symbols[0], q->ce, x, nant,
|
||||
q->nof_symbols);
|
||||
layerdemap_diversity(x, q->pbch_d, nant, q->nof_symbols / nant);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
/* demodulate symbols */
|
||||
demod_soft_sigma_set(&q->demod, ebno);
|
||||
demod_soft_demodulate(&q->demod, q->pbch_d,
|
||||
&q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols);
|
||||
/* extract channel estimates */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
if (q->nof_symbols != pbch_get(ce_slot[i], q->ce[i], q->cell)) {
|
||||
fprintf(stderr, "There was an error getting the PBCH symbols\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received
|
||||
* 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234.
|
||||
* We know they are ordered.
|
||||
*
|
||||
* FIXME: There are unnecessary checks because 2,3,4 have already been processed in the previous
|
||||
* calls.
|
||||
*/
|
||||
for (nb = 0; nb < q->frame_idx && !res; nb++) {
|
||||
for (dst = 0; (dst < 4 - nb) && !res; dst++) {
|
||||
for (src = 0; src < q->frame_idx - nb && !res; src++) {
|
||||
DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n",
|
||||
nb + 1, src, dst);
|
||||
res = pbch_decode_frame(q, mib, src, dst, nb + 1, nof_bits, nant);
|
||||
q->frame_idx++;
|
||||
ret = 0;
|
||||
|
||||
/* Try decoding for 1 to cell.nof_ports antennas */
|
||||
for (na = 0; na < q->cell.nof_ports && !ret; na++) {
|
||||
nant = nant_[na];
|
||||
|
||||
INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx);
|
||||
|
||||
/* in conctrol channels, only diversity is supported */
|
||||
if (nant == 1) {
|
||||
/* no need for layer demapping */
|
||||
predecoding_single_zf(q->pbch_symbols[0], q->ce[0], q->pbch_d,
|
||||
q->nof_symbols);
|
||||
} else {
|
||||
predecoding_diversity_zf(q->pbch_symbols[0], q->ce, x, nant,
|
||||
q->nof_symbols);
|
||||
layerdemap_diversity(x, q->pbch_d, nant, q->nof_symbols / nant);
|
||||
}
|
||||
|
||||
/* demodulate symbols */
|
||||
demod_soft_sigma_set(&q->demod, 1.0);
|
||||
demod_soft_demodulate(&q->demod, q->pbch_d,
|
||||
&q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols);
|
||||
|
||||
/* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received
|
||||
* 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234.
|
||||
* We know they are ordered.
|
||||
*
|
||||
* FIXME: There are unnecessary checks because 2,3,4 have already been processed in the previous
|
||||
* calls.
|
||||
*/
|
||||
for (nb = 0; nb < q->frame_idx && !ret; nb++) {
|
||||
for (dst = 0; (dst < 4 - nb) && !ret; dst++) {
|
||||
for (src = 0; src < q->frame_idx - nb && !ret; src++) {
|
||||
DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n",
|
||||
nb + 1, src, dst);
|
||||
ret = pbch_decode_frame(q, mib, src, dst, nb + 1, nof_bits, nant);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If not found, make room for the next packet of radio frame symbols */
|
||||
if (q->frame_idx == 4) {
|
||||
memmove(q->pbch_llr, &q->pbch_llr[nof_bits], nof_bits * 3 * sizeof(float));
|
||||
q->frame_idx = 3;
|
||||
/* If not found, make room for the next packet of radio frame symbols */
|
||||
if (q->frame_idx == 4) {
|
||||
memmove(q->pbch_llr, &q->pbch_llr[nof_bits], nof_bits * 3 * sizeof(float));
|
||||
q->frame_idx = 3;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission
|
||||
*/
|
||||
void pbch_encode(pbch_t *q, pbch_mib_t *mib,
|
||||
cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports) {
|
||||
int pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *sf_symbols[MAX_PORTS]) {
|
||||
int i;
|
||||
int nof_bits = 2 * q->nof_symbols;
|
||||
|
||||
assert(nof_ports <= MAX_PORTS_CTRL);
|
||||
|
||||
/* Set pointers for layermapping & precoding */
|
||||
int nof_bits;
|
||||
cf_t *slot1_symbols[MAX_PORTS];
|
||||
cf_t *x[MAX_LAYERS];
|
||||
|
||||
if (q != NULL &&
|
||||
mib != NULL)
|
||||
{
|
||||
for (i=0;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;
|
||||
/** Initializes the pcfich channel receiver.
|
||||
* On error, returns -1 and frees the structrure
|
||||
*/
|
||||
int pcfich_init(pcfich_t *q, regs_t *regs, lte_cell_t cell) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
regs != NULL &&
|
||||
lte_cell_isvalid(&cell))
|
||||
{
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
bzero(q, sizeof(pcfich_t));
|
||||
q->cell = cell;
|
||||
q->regs = regs;
|
||||
|
||||
if (modem_table_std(&q->mod, LTE_QPSK, false)) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
demod_hard_init(&q->demod);
|
||||
demod_hard_table_set(&q->demod, LTE_QPSK);
|
||||
|
||||
for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) {
|
||||
if (sequence_pcfich(&q->seq_pcfich[nsf], 2 * nsf, q->cell_id)) {
|
||||
if (modem_table_lte(&q->mod, LTE_QPSK, false)) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
demod_hard_init(&q->demod);
|
||||
demod_hard_table_set(&q->demod, LTE_QPSK);
|
||||
|
||||
for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) {
|
||||
if (sequence_pcfich(&q->seq_pcfich[nsf], 2 * nsf, q->cell.id)) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
q->nof_symbols = PCFICH_RE;
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
q->nof_symbols = PCFICH_RE;
|
||||
|
||||
ret = 0;
|
||||
clean: if (ret == -1) {
|
||||
|
||||
clean:
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
pcfich_free(q);
|
||||
}
|
||||
return ret;
|
||||
|
@ -100,7 +105,7 @@ void pcfich_free(pcfich_t *q) {
|
|||
/** Finds the CFI with minimum distance with the vector of received 32 bits.
|
||||
* Saves the CFI value in the cfi pointer and returns the distance.
|
||||
*/
|
||||
int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], int *cfi) {
|
||||
int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], uint32_t *cfi) {
|
||||
int i, j;
|
||||
int distance, index = -1;
|
||||
int min = 32;
|
||||
|
@ -120,7 +125,6 @@ int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], int *cfi) {
|
|||
*cfi = index + 1;
|
||||
}
|
||||
return min;
|
||||
|
||||
}
|
||||
|
||||
/** Encodes the CFI producing a vector of 32 bits.
|
||||
|
@ -128,19 +132,19 @@ int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], int *cfi) {
|
|||
*/
|
||||
int pcfich_cfi_encode(int cfi, char bits[PCFICH_CFI_LEN]) {
|
||||
if (cfi < 1 || cfi > 3) {
|
||||
fprintf(stderr, "Invalid CFI %d\n", cfi);
|
||||
return -1;
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
} else{
|
||||
memcpy(bits, cfi_table[cfi - 1], PCFICH_CFI_LEN * sizeof(char));
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
memcpy(bits, cfi_table[cfi - 1], PCFICH_CFI_LEN * sizeof(char));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Decodes the PCFICH channel and saves the CFI in the cfi pointer.
|
||||
*
|
||||
* Returns 1 if successfully decoded the CFI, 0 if not and -1 on error
|
||||
*/
|
||||
int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
|
||||
int nsubframe, int *cfi, int *distance) {
|
||||
int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS],
|
||||
uint32_t nsubframe, uint32_t *cfi, uint32_t *distance) {
|
||||
int dist;
|
||||
|
||||
/* Set pointers for layermapping & precoding */
|
||||
|
@ -148,112 +152,120 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
|
|||
cf_t *x[MAX_LAYERS];
|
||||
cf_t *ce_precoding[MAX_PORTS];
|
||||
|
||||
if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) {
|
||||
fprintf(stderr, "Invalid nslot %d\n", nsubframe);
|
||||
return -1;
|
||||
}
|
||||
if (q != NULL &&
|
||||
slot_symbols != NULL &&
|
||||
nsubframe < NSUBFRAMES_X_FRAME)
|
||||
{
|
||||
|
||||
/* number of layers equals number of ports */
|
||||
for (i = 0; i < MAX_PORTS_CTRL; i++) {
|
||||
x[i] = q->pcfich_x[i];
|
||||
}
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
ce_precoding[i] = q->ce[i];
|
||||
}
|
||||
|
||||
/* extract symbols */
|
||||
if (q->nof_symbols
|
||||
!= regs_pcfich_get(q->regs, slot_symbols, q->pcfich_symbols[0])) {
|
||||
fprintf(stderr, "There was an error getting the PCFICH symbols\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* extract channel estimates */
|
||||
for (i = 0; i < q->nof_ports; i++) {
|
||||
if (q->nof_symbols != regs_pcfich_get(q->regs, ce[i], q->ce[i])) {
|
||||
fprintf(stderr, "There was an error getting the PCFICH symbols\n");
|
||||
return -1;
|
||||
/* number of layers equals number of ports */
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
x[i] = q->pcfich_x[i];
|
||||
}
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
ce_precoding[i] = q->ce[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* in control channels, only diversity is supported */
|
||||
if (q->nof_ports == 1) {
|
||||
/* no need for layer demapping */
|
||||
predecoding_single_zf(q->pcfich_symbols[0], q->ce[0], q->pcfich_d,
|
||||
q->nof_symbols);
|
||||
/* extract symbols */
|
||||
if (q->nof_symbols
|
||||
!= regs_pcfich_get(q->regs, slot_symbols, q->pcfich_symbols[0])) {
|
||||
fprintf(stderr, "There was an error getting the PCFICH symbols\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
/* extract channel estimates */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
if (q->nof_symbols != regs_pcfich_get(q->regs, ce[i], q->ce[i])) {
|
||||
fprintf(stderr, "There was an error getting the PCFICH symbols\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* in control channels, only diversity is supported */
|
||||
if (q->cell.nof_ports == 1) {
|
||||
/* no need for layer demapping */
|
||||
predecoding_single_zf(q->pcfich_symbols[0], q->ce[0], q->pcfich_d,
|
||||
q->nof_symbols);
|
||||
} else {
|
||||
predecoding_diversity_zf(q->pcfich_symbols[0], ce_precoding, x,
|
||||
q->cell.nof_ports, q->nof_symbols);
|
||||
layerdemap_diversity(x, q->pcfich_d, q->cell.nof_ports,
|
||||
q->nof_symbols / q->cell.nof_ports);
|
||||
}
|
||||
|
||||
/* demodulate symbols */
|
||||
demod_hard_demodulate(&q->demod, q->pcfich_d, q->data, q->nof_symbols);
|
||||
|
||||
/* Scramble with the sequence for slot nslot */
|
||||
scrambling_b(&q->seq_pcfich[nsubframe], q->data);
|
||||
|
||||
/* decode CFI */
|
||||
dist = pcfich_cfi_decode(q->data, cfi);
|
||||
if (distance) {
|
||||
*distance = dist;
|
||||
}
|
||||
if (dist < PCFICH_MAX_DISTANCE) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
predecoding_diversity_zf(q->pcfich_symbols[0], ce_precoding, x,
|
||||
q->nof_ports, q->nof_symbols);
|
||||
layerdemap_diversity(x, q->pcfich_d, q->nof_ports,
|
||||
q->nof_symbols / q->nof_ports);
|
||||
}
|
||||
|
||||
/* demodulate symbols */
|
||||
demod_hard_demodulate(&q->demod, q->pcfich_d, q->data, q->nof_symbols);
|
||||
|
||||
/* Scramble with the sequence for slot nslot */
|
||||
scrambling_b(&q->seq_pcfich[nsubframe], q->data);
|
||||
|
||||
/* decode CFI */
|
||||
dist = pcfich_cfi_decode(q->data, cfi);
|
||||
if (distance) {
|
||||
*distance = dist;
|
||||
}
|
||||
if (dist < PCFICH_MAX_DISTANCE) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Encodes CFI and maps symbols to the slot
|
||||
*/
|
||||
int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL],
|
||||
int nsubframe) {
|
||||
int pcfich_encode(pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[MAX_PORTS],
|
||||
uint32_t subframe) {
|
||||
int i;
|
||||
|
||||
if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) {
|
||||
fprintf(stderr, "Invalid nslot %d\n", nsubframe);
|
||||
return -1;
|
||||
}
|
||||
if (q != NULL &&
|
||||
cfi < 3 &&
|
||||
slot_symbols != NULL &&
|
||||
subframe < NSUBFRAMES_X_FRAME)
|
||||
{
|
||||
|
||||
/* Set pointers for layermapping & precoding */
|
||||
cf_t *x[MAX_LAYERS];
|
||||
cf_t *symbols_precoding[MAX_PORTS];
|
||||
/* Set pointers for layermapping & precoding */
|
||||
cf_t *x[MAX_LAYERS];
|
||||
cf_t *symbols_precoding[MAX_PORTS];
|
||||
|
||||
/* number of layers equals number of ports */
|
||||
for (i = 0; i < q->nof_ports; i++) {
|
||||
x[i] = q->pcfich_x[i];
|
||||
}
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
symbols_precoding[i] = q->pcfich_symbols[i];
|
||||
}
|
||||
|
||||
/* pack MIB */
|
||||
pcfich_cfi_encode(cfi, q->data);
|
||||
|
||||
/* scramble for slot sequence nslot */
|
||||
scrambling_b(&q->seq_pcfich[nsubframe], q->data);
|
||||
|
||||
mod_modulate(&q->mod, q->data, q->pcfich_d, PCFICH_CFI_LEN);
|
||||
|
||||
/* layer mapping & precoding */
|
||||
if (q->nof_ports > 1) {
|
||||
layermap_diversity(q->pcfich_d, x, q->nof_ports, q->nof_symbols);
|
||||
precoding_diversity(x, symbols_precoding, q->nof_ports,
|
||||
q->nof_symbols / q->nof_ports);
|
||||
} else {
|
||||
memcpy(q->pcfich_symbols[0], q->pcfich_d, q->nof_symbols * sizeof(cf_t));
|
||||
}
|
||||
|
||||
/* mapping to resource elements */
|
||||
for (i = 0; i < q->nof_ports; i++) {
|
||||
if (regs_pcfich_put(q->regs, q->pcfich_symbols[i], slot_symbols[i]) < 0) {
|
||||
fprintf(stderr, "Error putting PCHICH resource elements\n");
|
||||
return -1;
|
||||
/* number of layers equals number of ports */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
x[i] = q->pcfich_x[i];
|
||||
}
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
symbols_precoding[i] = q->pcfich_symbols[i];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* pack CFI */
|
||||
pcfich_cfi_encode(cfi, q->data);
|
||||
|
||||
/* scramble for slot sequence nslot */
|
||||
scrambling_b(&q->seq_pcfich[subframe], q->data);
|
||||
|
||||
mod_modulate(&q->mod, q->data, q->pcfich_d, PCFICH_CFI_LEN);
|
||||
|
||||
/* layer mapping & precoding */
|
||||
if (q->cell.nof_ports > 1) {
|
||||
layermap_diversity(q->pcfich_d, x, q->cell.nof_ports, q->nof_symbols);
|
||||
precoding_diversity(x, symbols_precoding, q->cell.nof_ports,
|
||||
q->nof_symbols / q->cell.nof_ports);
|
||||
} else {
|
||||
memcpy(q->pcfich_symbols[0], q->pcfich_d, q->nof_symbols * sizeof(cf_t));
|
||||
}
|
||||
|
||||
/* mapping to resource elements */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
if (regs_pcfich_put(q->regs, q->pcfich_symbols[i], slot_symbols[i]) < 0) {
|
||||
fprintf(stderr, "Error putting PCHICH resource elements\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
return LIBLTE_SUCCESS;
|
||||
} else {
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
#define NOF_COMMON_FORMATS 2
|
||||
const dci_format_t common_formats[NOF_COMMON_FORMATS] = { Format1A, Format1C };
|
||||
|
||||
#define NOF_UE_FORMATS 2
|
||||
const dci_format_t ue_formats[NOF_UE_FORMATS] = { Format0, Format1 }; // 1A has the same payload as 0
|
||||
|
||||
|
||||
static void set_cfi(pdcch_t *q, uint32_t cfi) {
|
||||
if (cfi > 0 && cfi < 4) {
|
||||
q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9;
|
||||
q->nof_cce = q->nof_regs / 9;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 36.213 9.1
|
||||
*/
|
||||
int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits,
|
||||
unsigned short rnti, int subframe) {
|
||||
int i, l, L, k, m;
|
||||
unsigned int Yk;
|
||||
const int S[4] = { 6, 12, 8, 16 };
|
||||
k = 0;
|
||||
if (!subframe) {
|
||||
INFO("UE-specific candidates for RNTI: 0x%x, NofBits: %d, NofCCE: %d\n",
|
||||
rnti, nof_bits, nof_cce);
|
||||
if (VERBOSE_ISINFO())
|
||||
printf("[INFO]: ");
|
||||
}
|
||||
for (l = 3; l >= 0; l--) {
|
||||
L = (1 << l);
|
||||
for (i = 0; i < MIN(nof_cce / L, 16 / S[l]); i++) {
|
||||
c[k].L = l;
|
||||
c[k].nof_bits = nof_bits;
|
||||
c[k].rnti = rnti;
|
||||
Yk = rnti;
|
||||
for (m = 0; m < subframe; m++) {
|
||||
Yk = (39827 * Yk) % 65537;
|
||||
}
|
||||
c[k].ncce = L * ((Yk + i) % (nof_cce / L));
|
||||
if (!subframe) {
|
||||
if (VERBOSE_ISINFO()) {
|
||||
printf("(%d, %d), ", c[k].ncce, c[k].L);
|
||||
}
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
if (!subframe) {
|
||||
if (VERBOSE_ISINFO())
|
||||
printf("\n");
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
void pdcch_init_common(pdcch_t *q, pdcch_search_t *s, unsigned short rnti) {
|
||||
int k, i;
|
||||
s->nof_candidates = NOF_COMMON_FORMATS
|
||||
* (MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8);
|
||||
if (s->nof_candidates) {
|
||||
s->candidates[0] = malloc(sizeof(dci_candidate_t) * s->nof_candidates);
|
||||
dci_candidate_t *c = s->candidates[0];
|
||||
s->nof_candidates = 0;
|
||||
if (c) {
|
||||
// Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16
|
||||
k = 0;
|
||||
for (i = 0; i < NOF_COMMON_FORMATS; i++) {
|
||||
k += gen_common_search(&c[k], q->nof_cce,
|
||||
dci_format_sizeof(common_formats[i], q->nof_prb), SIRNTI);
|
||||
s->nof_candidates++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 36.213 v9.3 Table 7.1-1: System Information DCI messages
|
||||
* Expect DCI formats 1C and 1A in the common search space
|
||||
*/
|
||||
void pdcch_init_search_si(pdcch_t *q) {
|
||||
pdcch_init_common(q, &q->search_mode[SEARCH_SI], SIRNTI);
|
||||
q->current_search_mode = SEARCH_SI;
|
||||
}
|
||||
|
||||
/** 36.213 v9.3 Table 7.1-5
|
||||
* user-specific search space. Currently supported transmission Mode 1:
|
||||
* DCI Format 1A and 1 + PUSCH scheduling format 0
|
||||
*/
|
||||
void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) {
|
||||
int l, n, k, i;
|
||||
pdcch_search_t *s = &q->search_mode[SEARCH_UE];
|
||||
s->nof_candidates = 0;
|
||||
for (l = 0; l < 3; l++) {
|
||||
s->nof_candidates += NOF_UE_FORMATS * (MIN(q->nof_cce,16) / (1 << l));
|
||||
}
|
||||
INFO(
|
||||
"Initiating %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n",
|
||||
s->nof_candidates, c_rnti);
|
||||
if (s->nof_candidates) {
|
||||
for (n = 0; n < NSUBFRAMES_X_FRAME; n++) {
|
||||
s->candidates[n] = malloc(sizeof(dci_candidate_t) * s->nof_candidates);
|
||||
dci_candidate_t *c = s->candidates[n];
|
||||
|
||||
if (c) {
|
||||
// Expect Formats 1, 1A, 0
|
||||
k = 0;
|
||||
for (i = 0; i < NOF_UE_FORMATS; i++) {
|
||||
k += gen_ue_search(&c[k], q->nof_cce,
|
||||
dci_format_sizeof(ue_formats[i], q->nof_prb), c_rnti, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
q->current_search_mode = SEARCH_UE;
|
||||
}
|
||||
|
||||
/** 36.213 v9.3 Table 7.1-3
|
||||
* Expect DCI formats 1C and 1A in the common search space
|
||||
*/
|
||||
void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti) {
|
||||
pdcch_init_common(q, &q->search_mode[SEARCH_RA], ra_rnti);
|
||||
q->current_search_mode = SEARCH_RA;
|
||||
}
|
||||
|
||||
void pdcch_set_search_si(pdcch_t *q) {
|
||||
q->current_search_mode = SEARCH_SI;
|
||||
}
|
||||
void pdcch_set_search_ue(pdcch_t *q) {
|
||||
q->current_search_mode = SEARCH_UE;
|
||||
}
|
||||
void pdcch_set_search_ra(pdcch_t *q) {
|
||||
q->current_search_mode = SEARCH_RA;
|
||||
}
|
||||
|
||||
/** Initializes the PDCCH transmitter and receiver */
|
||||
int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports,
|
||||
int cell_id, lte_cp_t cp) {
|
||||
int ret = -1;
|
||||
int i;
|
||||
int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
uint32_t i;
|
||||
|
||||
if (cell_id < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (nof_ports > MAX_PORTS_CTRL) {
|
||||
fprintf(stderr, "Invalid number of ports %d\n", nof_ports);
|
||||
return -1;
|
||||
}
|
||||
bzero(q, sizeof(pdcch_t));
|
||||
q->cell_id = cell_id;
|
||||
q->cp = cp;
|
||||
q->regs = regs;
|
||||
q->nof_ports = nof_ports;
|
||||
q->nof_prb = nof_prb;
|
||||
q->current_search_mode = SEARCH_NONE;
|
||||
if (q != NULL &&
|
||||
regs != NULL &&
|
||||
lte_cell_isvalid(&cell))
|
||||
{
|
||||
ret = LIBLTE_ERROR;
|
||||
bzero(q, sizeof(pdcch_t));
|
||||
q->cell = cell;
|
||||
q->regs = regs;
|
||||
|
||||
q->nof_regs = (regs_pdcch_nregs(q->regs) / 9) * 9;
|
||||
q->nof_cce = q->nof_regs / 9;
|
||||
q->nof_symbols = 4 * q->nof_regs;
|
||||
q->nof_bits = 2 * q->nof_symbols;
|
||||
/* Allocate memory for the largest aggregation level L=3 */
|
||||
q->max_bits = PDCCH_FORMAT_NOF_BITS(3);
|
||||
|
||||
INFO("Init PDCCH: %d CCEs (%d REGs), %d bits, %d symbols, %d ports\n",
|
||||
q->nof_cce, q->nof_regs, q->nof_bits, q->nof_symbols, q->nof_ports);
|
||||
INFO("Init PDCCH: %d bits, %d symbols, %d ports\n", q->max_bits, q->max_bits/2, q->cell.nof_ports);
|
||||
|
||||
if (modem_table_std(&q->mod, LTE_QPSK, true)) {
|
||||
goto clean;
|
||||
}
|
||||
if (crc_init(&q->crc, LTE_CRC16, 16)) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
demod_soft_init(&q->demod);
|
||||
demod_soft_table_set(&q->demod, &q->mod);
|
||||
demod_soft_alg_set(&q->demod, APPROX);
|
||||
|
||||
for (i = 0; i < NSUBFRAMES_X_FRAME; i++) {
|
||||
if (sequence_pdcch(&q->seq_pdcch[i], 2 * i, q->cell_id, q->nof_bits)) {
|
||||
if (modem_table_lte(&q->mod, LTE_QPSK, true)) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
int poly[3] = { 0x6D, 0x4F, 0x57 };
|
||||
if (viterbi_init(&q->decoder, viterbi_37, poly, DCI_MAX_BITS + 16, true)) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
q->pdcch_e = malloc(sizeof(char) * q->nof_bits);
|
||||
if (!q->pdcch_e) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
q->pdcch_llr = malloc(sizeof(float) * q->nof_bits);
|
||||
if (!q->pdcch_llr) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
q->pdcch_d = malloc(sizeof(cf_t) * q->nof_symbols);
|
||||
if (!q->pdcch_d) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_PORTS_CTRL; i++) {
|
||||
q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols);
|
||||
if (!q->ce[i]) {
|
||||
if (crc_init(&q->crc, LTE_CRC16, 16)) {
|
||||
goto clean;
|
||||
}
|
||||
q->pdcch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols);
|
||||
if (!q->pdcch_x[i]) {
|
||||
|
||||
demod_soft_init(&q->demod);
|
||||
demod_soft_table_set(&q->demod, &q->mod);
|
||||
demod_soft_alg_set(&q->demod, APPROX);
|
||||
|
||||
for (i = 0; i < NSUBFRAMES_X_FRAME; i++) {
|
||||
// we need to pregenerate the sequence for the maximum number of bits, which is 8 times
|
||||
// the maximum number of REGs (for CFI=3)
|
||||
if (sequence_pdcch(&q->seq_pdcch[i], 2 * i, q->cell.id, 8*regs_pdcch_nregs(q->regs, 3))) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t poly[3] = { 0x6D, 0x4F, 0x57 };
|
||||
if (viterbi_init(&q->decoder, viterbi_37, poly, DCI_MAX_BITS + 16, true)) {
|
||||
goto clean;
|
||||
}
|
||||
q->pdcch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols);
|
||||
if (!q->pdcch_symbols[i]) {
|
||||
|
||||
q->pdcch_e = malloc(sizeof(char) * q->max_bits);
|
||||
if (!q->pdcch_e) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
q->pdcch_llr = malloc(sizeof(float) * q->max_bits);
|
||||
if (!q->pdcch_llr) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
q->pdcch_d = malloc(sizeof(cf_t) * q->max_bits / 2);
|
||||
if (!q->pdcch_d) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
q->ce[i] = malloc(sizeof(cf_t) * q->max_bits / 2);
|
||||
if (!q->ce[i]) {
|
||||
goto clean;
|
||||
}
|
||||
q->pdcch_x[i] = malloc(sizeof(cf_t) * q->max_bits / 2);
|
||||
if (!q->pdcch_x[i]) {
|
||||
goto clean;
|
||||
}
|
||||
q->pdcch_symbols[i] = malloc(sizeof(cf_t) * q->max_bits / 2);
|
||||
if (!q->pdcch_symbols[i]) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
ret = 0;
|
||||
clean: if (ret == -1) {
|
||||
clean:
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
pdcch_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void pdcch_free(pdcch_t *q) {
|
||||
int i, j;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PDCCH_NOF_SEARCH_MODES; i++) {
|
||||
for (j = 0; j < NSUBFRAMES_X_FRAME; j++) {
|
||||
if (q->search_mode[i].candidates[j]) {
|
||||
free(q->search_mode[i].candidates[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (q->pdcch_e) {
|
||||
free(q->pdcch_e);
|
||||
}
|
||||
|
@ -302,7 +159,7 @@ void pdcch_free(pdcch_t *q) {
|
|||
if (q->pdcch_d) {
|
||||
free(q->pdcch_d);
|
||||
}
|
||||
for (i = 0; i < MAX_PORTS_CTRL; i++) {
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
if (q->ce[i]) {
|
||||
free(q->ce[i]);
|
||||
}
|
||||
|
@ -322,189 +179,257 @@ void pdcch_free(pdcch_t *q) {
|
|||
viterbi_free(&q->decoder);
|
||||
}
|
||||
|
||||
/** 36.213 v9.1.1
|
||||
* Computes up to max_candidates UE-specific candidates for DCI messages and saves them
|
||||
* in the structure pointed by c.
|
||||
* Returns the number of candidates saved in the array c.
|
||||
*/
|
||||
uint32_t pdcch_ue_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidates,
|
||||
uint32_t nsubframe, uint32_t cfi, uint16_t rnti) {
|
||||
|
||||
int l; // this must be int because of the for(;;--) loop
|
||||
uint32_t i, k, L, m;
|
||||
uint32_t Yk, ncce;
|
||||
const int S[4] = { 6, 12, 8, 16 };
|
||||
|
||||
set_cfi(q, cfi);
|
||||
|
||||
// Compute Yk for this subframe
|
||||
Yk = rnti;
|
||||
for (m = 0; m < nsubframe; m++) {
|
||||
Yk = (39827 * Yk) % 65537;
|
||||
}
|
||||
|
||||
k = 0;
|
||||
// All aggregation levels from 8 to 1
|
||||
for (l = 3; l >= 0; l--) {
|
||||
L = (1 << l);
|
||||
// For all possible ncce offset
|
||||
for (i = 0; i < MIN(q->nof_cce / L, 16 / S[l]); i++) {
|
||||
ncce = L * ((Yk + i) % (q->nof_cce / L));
|
||||
if (k < max_candidates &&
|
||||
ncce + PDCCH_FORMAT_NOF_CCE(l) <= q->nof_cce)
|
||||
{
|
||||
c[k].L = l;
|
||||
c[k].ncce = ncce;
|
||||
|
||||
DEBUG("UE-specific SS Candidate %d: nCCE: %d, L: %d\n",
|
||||
k, c[k].ncce, c[k].L);
|
||||
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INFO("Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", k, rnti);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 36.213 9.1.1
|
||||
* Computes up to max_candidates candidates in the common search space
|
||||
* for DCI messages and saves them in the structure pointed by c.
|
||||
* Returns the number of candidates saved in the array c.
|
||||
*/
|
||||
uint32_t pdcch_common_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidates,
|
||||
uint32_t cfi)
|
||||
{
|
||||
uint32_t i, l, L, k;
|
||||
|
||||
set_cfi(q, cfi);
|
||||
|
||||
k = 0;
|
||||
for (l = 3; l > 1; l--) {
|
||||
L = (1 << l);
|
||||
for (i = 0; i < MIN(q->nof_cce, 16) / (L); i++) {
|
||||
if (k < max_candidates) {
|
||||
c[k].L = l;
|
||||
c[k].ncce = (L) * (i % (q->nof_cce / (L)));
|
||||
DEBUG("Common SS Candidate %d: nCCE: %d, L: %d\n",
|
||||
k, c[k].ncce, c[k].L);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INFO("Initiated %d candidate(s) in the Common search space\n", k);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** 36.212 5.3.3.2 to 5.3.3.4
|
||||
*
|
||||
* Returns XOR between parity and remainder bits
|
||||
*
|
||||
* TODO: UE transmit antenna selection CRC mask
|
||||
*/
|
||||
unsigned short dci_decode(pdcch_t *q, float *e, char *data, int E, int nof_bits) {
|
||||
static int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof_bits, uint16_t *crc) {
|
||||
|
||||
float tmp[3 * (DCI_MAX_BITS + 16)];
|
||||
unsigned short p_bits, crc_res;
|
||||
uint16_t p_bits, crc_res;
|
||||
char *x;
|
||||
|
||||
assert(nof_bits < DCI_MAX_BITS);
|
||||
if (q != NULL &&
|
||||
data != NULL &&
|
||||
E <= q->max_bits &&
|
||||
nof_bits <= DCI_MAX_BITS)
|
||||
{
|
||||
|
||||
/* unrate matching */
|
||||
rm_conv_rx(e, E, tmp, 3 * (nof_bits + 16));
|
||||
/* unrate matching */
|
||||
rm_conv_rx(e, E, tmp, 3 * (nof_bits + 16));
|
||||
|
||||
DEBUG("Viterbi input: ", 0);
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
vec_fprint_f(stdout, tmp, 3 * (nof_bits + 16));
|
||||
DEBUG("Viterbi input: ", 0);
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
vec_fprint_f(stdout, tmp, 3 * (nof_bits + 16));
|
||||
}
|
||||
|
||||
/* viterbi decoder */
|
||||
viterbi_decode_f(&q->decoder, tmp, data, nof_bits + 16);
|
||||
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
bit_fprint(stdout, data, nof_bits + 16);
|
||||
}
|
||||
|
||||
x = &data[nof_bits];
|
||||
p_bits = (uint16_t) bit_unpack(&x, 16);
|
||||
crc_res = ((uint16_t) crc_checksum(&q->crc, data, nof_bits) & 0xffff);
|
||||
DEBUG("p_bits: 0x%x, crc_checksum: 0x%x, crc_rem: 0x%x\n", p_bits, crc_res,
|
||||
p_bits ^ crc_res);
|
||||
|
||||
if (crc) {
|
||||
*crc = p_bits ^ crc_res;
|
||||
}
|
||||
return LIBLTE_SUCCESS;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid parameters: E: %d, max_bits: %d, nof_bits: %d\n", E, q->max_bits, nof_bits);
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
/* viterbi decoder */
|
||||
viterbi_decode_f(&q->decoder, tmp, data, nof_bits + 16);
|
||||
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
bit_fprint(stdout, data, nof_bits + 16);
|
||||
}
|
||||
|
||||
x = &data[nof_bits];
|
||||
p_bits = (unsigned short) bit_unpack(&x, 16);
|
||||
crc_res = ((unsigned short) crc_checksum(&q->crc, data, nof_bits) & 0xffff);
|
||||
DEBUG("p_bits: 0x%x, crc_res: 0x%x, tot: 0x%x\n", p_bits, crc_res,
|
||||
p_bits ^ crc_res);
|
||||
return (p_bits ^ crc_res);
|
||||
}
|
||||
|
||||
int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c,
|
||||
dci_msg_t *msg) {
|
||||
unsigned short crc_res;
|
||||
DEBUG("Trying Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
|
||||
c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L, c->rnti);
|
||||
crc_res = dci_decode(q, &llr[72 * c->ncce], msg->data,
|
||||
PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits);
|
||||
|
||||
if (c->rnti == crc_res) {
|
||||
memcpy(&msg->location, c, sizeof(dci_candidate_t));
|
||||
INFO("FOUND Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
|
||||
c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L, c->rnti);
|
||||
return 1;
|
||||
/** Tries to decode a DCI message from the LLRs stored in the pdcch_t structure by the function
|
||||
* pdcch_extract_llr(). This function can be called multiple times.
|
||||
* The decoded message is stored in msg and the CRC remainder in crc_rem pointer
|
||||
*
|
||||
*/
|
||||
int pdcch_decode_msg(pdcch_t *q, dci_msg_t *msg, dci_format_t format, uint16_t *crc_rem)
|
||||
{
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
if (q != NULL &&
|
||||
msg != NULL &&
|
||||
crc_rem != NULL)
|
||||
{
|
||||
uint32_t nof_bits = dci_format_sizeof(format, q->cell.nof_prb);
|
||||
|
||||
ret = dci_decode(q, q->pdcch_llr, msg->data, q->e_bits, nof_bits, crc_rem);
|
||||
if (ret == LIBLTE_SUCCESS) {
|
||||
msg->nof_bits = nof_bits;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
|
||||
float *llr, int nsubframe, float ebno) {
|
||||
/** Extracts the LLRs from dci_location_t location of the subframe and stores them in the pdcch_t structure.
|
||||
* DCI messages can be extracted from this location calling the function pdcch_decode_msg().
|
||||
* Every time this function is called (with a different location), the last demodulated symbols are overwritten and
|
||||
* new messages from other locations can be decoded
|
||||
*/
|
||||
int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS],
|
||||
dci_location_t location, uint32_t nsubframe, uint32_t cfi) {
|
||||
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
/* Set pointers for layermapping & precoding */
|
||||
int i;
|
||||
uint32_t i, nof_symbols;
|
||||
cf_t *x[MAX_LAYERS];
|
||||
|
||||
if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) {
|
||||
fprintf(stderr, "Invalid subframe %d\n", nsubframe);
|
||||
return -1;
|
||||
}
|
||||
if (q != NULL &&
|
||||
nsubframe < 10 &&
|
||||
cfi > 0 &&
|
||||
cfi < 4 &&
|
||||
dci_location_isvalid(&location))
|
||||
{
|
||||
set_cfi(q, cfi);
|
||||
|
||||
q->e_bits = PDCCH_FORMAT_NOF_BITS(location.L);
|
||||
nof_symbols = q->e_bits/2;
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
if (location.ncce + PDCCH_FORMAT_NOF_CCE(location.L) <= q->nof_cce) {
|
||||
|
||||
INFO("Extracting LLRs: E: %d, nCCE: %d, L: %d, SF: %d, CFI: %d\n",
|
||||
q->e_bits, location.ncce, location.L, nsubframe, cfi);
|
||||
|
||||
if (ebno == 0.0) {
|
||||
fprintf(stderr, "EbNo is Zero\n");
|
||||
return -1;
|
||||
}
|
||||
/* number of layers equals number of ports */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
x[i] = q->pdcch_x[i];
|
||||
}
|
||||
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
|
||||
|
||||
/* number of layers equals number of ports */
|
||||
for (i = 0; i < q->nof_ports; i++) {
|
||||
x[i] = q->pdcch_x[i];
|
||||
}
|
||||
memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports));
|
||||
/* extract symbols */
|
||||
int n = regs_pdcch_get_offset(q->regs, sf_symbols, q->pdcch_symbols[0],
|
||||
location.ncce * 9, PDCCH_FORMAT_NOF_REGS(location.L));
|
||||
if (nof_symbols != n) {
|
||||
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* extract symbols */
|
||||
int n = regs_pdcch_get(q->regs, slot_symbols, q->pdcch_symbols[0]);
|
||||
if (q->nof_symbols != n) {
|
||||
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n",
|
||||
q->nof_symbols, n);
|
||||
return -1;
|
||||
}
|
||||
/* extract channel estimates */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
n = regs_pdcch_get_offset(q->regs, ce[i], q->ce[i],
|
||||
location.ncce * 9, PDCCH_FORMAT_NOF_REGS(location.L));
|
||||
if (nof_symbols != n) {
|
||||
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* extract channel estimates */
|
||||
for (i = 0; i < q->nof_ports; i++) {
|
||||
n = regs_pdcch_get(q->regs, ce[i], q->ce[i]);
|
||||
if (q->nof_symbols != n) {
|
||||
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n",
|
||||
q->nof_symbols, n);
|
||||
return -1;
|
||||
/* in control channels, only diversity is supported */
|
||||
if (q->cell.nof_ports == 1) {
|
||||
/* no need for layer demapping */
|
||||
predecoding_single_zf(q->pdcch_symbols[0], q->ce[0], q->pdcch_d, nof_symbols);
|
||||
} else {
|
||||
predecoding_diversity_zf(q->pdcch_symbols[0], q->ce, x, q->cell.nof_ports, nof_symbols);
|
||||
layerdemap_diversity(x, q->pdcch_d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
|
||||
}
|
||||
|
||||
DEBUG("pdcch d symbols: ", 0);
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
vec_fprint_c(stdout, q->pdcch_d, nof_symbols);
|
||||
}
|
||||
|
||||
/* demodulate symbols */
|
||||
demod_soft_sigma_set(&q->demod, 1.0);
|
||||
demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, nof_symbols);
|
||||
|
||||
DEBUG("llr: ", 0);
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
vec_fprint_f(stdout, q->pdcch_llr, q->e_bits);
|
||||
}
|
||||
|
||||
/* descramble */
|
||||
scrambling_f_offset(&q->seq_pdcch[nsubframe], q->pdcch_llr, 72 * location.ncce, q->e_bits);
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
} else {
|
||||
fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d\n", location.ncce, location.L, q->nof_cce);
|
||||
}
|
||||
}
|
||||
|
||||
/* in control channels, only diversity is supported */
|
||||
if (q->nof_ports == 1) {
|
||||
/* no need for layer demapping */
|
||||
predecoding_single_zf(q->pdcch_symbols[0], q->ce[0], q->pdcch_d,
|
||||
q->nof_symbols);
|
||||
} else {
|
||||
predecoding_diversity_zf(q->pdcch_symbols[0], q->ce, x, q->nof_ports,
|
||||
q->nof_symbols);
|
||||
layerdemap_diversity(x, q->pdcch_d, q->nof_ports,
|
||||
q->nof_symbols / q->nof_ports);
|
||||
}
|
||||
|
||||
DEBUG("pdcch d symbols: ", 0);
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
vec_fprint_c(stdout, q->pdcch_d, q->nof_symbols);
|
||||
}
|
||||
|
||||
/* demodulate symbols */
|
||||
demod_soft_sigma_set(&q->demod, ebno);
|
||||
demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, q->nof_symbols);
|
||||
|
||||
DEBUG("llr: ", 0);
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
vec_fprint_f(stdout, q->pdcch_llr, q->nof_bits);
|
||||
}
|
||||
|
||||
/* descramble */
|
||||
scrambling_f_offset(&q->seq_pdcch[nsubframe], llr, 0, q->nof_bits);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) {
|
||||
int k, i;
|
||||
|
||||
if (q->current_search_mode == SEARCH_UE) {
|
||||
k = subframe;
|
||||
} else {
|
||||
k = 0;
|
||||
}
|
||||
|
||||
for (i = 0;
|
||||
i < q->search_mode[q->current_search_mode].nof_candidates
|
||||
&& dci->nof_dcis < dci->max_dcis; i++) {
|
||||
if (pdcch_decode_candidate(q, q->pdcch_llr,
|
||||
&q->search_mode[q->current_search_mode].candidates[k][i],
|
||||
&dci->msg[dci->nof_dcis])) {
|
||||
dci->nof_dcis++;
|
||||
}
|
||||
}
|
||||
return dci->nof_dcis;
|
||||
}
|
||||
|
||||
int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci) {
|
||||
pdcch_set_search_si(q);
|
||||
return pdcch_decode_current_mode(q, llr, dci, 0);
|
||||
}
|
||||
int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci) {
|
||||
pdcch_set_search_ra(q);
|
||||
return pdcch_decode_current_mode(q, llr, dci, 0);
|
||||
}
|
||||
int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe) {
|
||||
pdcch_set_search_ue(q);
|
||||
return pdcch_decode_current_mode(q, llr, dci, nsubframe);
|
||||
}
|
||||
|
||||
/* Decodes PDCCH channels
|
||||
*
|
||||
* dci->nof_dcis is the size of the dci->msg buffer (ie max number of messages)
|
||||
*
|
||||
* Returns number of messages stored in dci
|
||||
*/
|
||||
int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
|
||||
dci_t *dci, int nsubframe, float ebno) {
|
||||
|
||||
if (pdcch_extract_llr(q, slot_symbols, ce, q->pdcch_llr, nsubframe, ebno)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (q->current_search_mode != SEARCH_NONE) {
|
||||
return pdcch_decode_current_mode(q, q->pdcch_llr, dci, nsubframe);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crc_set_mask_rnti(char *crc, unsigned short rnti) {
|
||||
int i;
|
||||
static void crc_set_mask_rnti(char *crc, uint16_t rnti) {
|
||||
uint32_t i;
|
||||
char mask[16];
|
||||
char *r = mask;
|
||||
|
||||
|
@ -519,92 +444,115 @@ void crc_set_mask_rnti(char *crc, unsigned short rnti) {
|
|||
/** 36.212 5.3.3.2 to 5.3.3.4
|
||||
* TODO: UE transmit antenna selection CRC mask
|
||||
*/
|
||||
void dci_encode(pdcch_t *q, char *data, char *e, int nof_bits, int E,
|
||||
unsigned short rnti) {
|
||||
static int dci_encode(pdcch_t *q, char *data, char *e, uint32_t nof_bits, uint32_t E,
|
||||
uint16_t rnti) {
|
||||
convcoder_t encoder;
|
||||
char tmp[3 * (DCI_MAX_BITS + 16)];
|
||||
|
||||
if (q != NULL &&
|
||||
data != NULL &&
|
||||
e != NULL &&
|
||||
nof_bits < DCI_MAX_BITS &&
|
||||
E < q->max_bits)
|
||||
{
|
||||
|
||||
assert(nof_bits < DCI_MAX_BITS);
|
||||
int poly[3] = { 0x6D, 0x4F, 0x57 };
|
||||
encoder.K = 7;
|
||||
encoder.R = 3;
|
||||
encoder.tail_biting = true;
|
||||
memcpy(encoder.poly, poly, 3 * sizeof(int));
|
||||
|
||||
int poly[3] = { 0x6D, 0x4F, 0x57 };
|
||||
encoder.K = 7;
|
||||
encoder.R = 3;
|
||||
encoder.tail_biting = true;
|
||||
memcpy(encoder.poly, poly, 3 * sizeof(int));
|
||||
crc_attach(&q->crc, data, nof_bits);
|
||||
crc_set_mask_rnti(&data[nof_bits], rnti);
|
||||
|
||||
crc_attach(&q->crc, data, nof_bits);
|
||||
crc_set_mask_rnti(&data[nof_bits], rnti);
|
||||
convcoder_encode(&encoder, data, tmp, nof_bits + 16);
|
||||
|
||||
convcoder_encode(&encoder, data, tmp, nof_bits + 16);
|
||||
|
||||
DEBUG("CConv output: ", 0);
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16));
|
||||
}
|
||||
|
||||
rm_conv_tx(tmp, 3 * (nof_bits + 16), e, E);
|
||||
}
|
||||
|
||||
/** Converts the set of DCI messages to symbols mapped to the slot ready for transmission
|
||||
*/
|
||||
int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS_CTRL],
|
||||
int nsubframe) {
|
||||
int i;
|
||||
/* Set pointers for layermapping & precoding */
|
||||
cf_t *x[MAX_LAYERS];
|
||||
|
||||
if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) {
|
||||
fprintf(stderr, "Invalid subframe %d\n", nsubframe);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* number of layers equals number of ports */
|
||||
for (i = 0; i < q->nof_ports; i++) {
|
||||
x[i] = q->pdcch_x[i];
|
||||
}
|
||||
memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports));
|
||||
|
||||
/* should add <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;
|
||||
DEBUG("CConv output: ", 0);
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16));
|
||||
}
|
||||
INFO("Encoding DCI %d: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", i,
|
||||
dci->msg[i].location.nof_bits,
|
||||
PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L),
|
||||
dci->msg[i].location.ncce, dci->msg[i].location.L,
|
||||
dci->msg[i].location.rnti);
|
||||
|
||||
dci_encode(q, dci->msg[i].data, &q->pdcch_e[72 * dci->msg[i].location.ncce],
|
||||
dci->msg[i].location.nof_bits,
|
||||
PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L),
|
||||
dci->msg[i].location.rnti);
|
||||
}
|
||||
|
||||
scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 0, q->nof_bits);
|
||||
|
||||
mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->nof_bits);
|
||||
|
||||
/* layer mapping & precoding */
|
||||
if (q->nof_ports > 1) {
|
||||
layermap_diversity(q->pdcch_d, x, q->nof_ports, q->nof_symbols);
|
||||
precoding_diversity(x, q->pdcch_symbols, q->nof_ports,
|
||||
q->nof_symbols / q->nof_ports);
|
||||
rm_conv_tx(tmp, 3 * (nof_bits + 16), e, E);
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
} else {
|
||||
memcpy(q->pdcch_symbols[0], q->pdcch_d, q->nof_symbols * sizeof(cf_t));
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
/* mapping to resource elements */
|
||||
for (i = 0; i < q->nof_ports; i++) {
|
||||
regs_pdcch_put(q->regs, q->pdcch_symbols[i], slot_symbols[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Encodes ONE DCI message and allocates the encoded bits to the dci_location_t indicated by
|
||||
* the parameter location. The CRC is scrambled with the RNTI parameter.
|
||||
* This function can be called multiple times and encoded DCI messages will be allocated to the
|
||||
* sf_symbols buffer ready for transmission.
|
||||
* If the same location is provided in multiple messages, the encoded bits will be overwritten.
|
||||
*
|
||||
* @TODO: Use a bitmask and CFI to ensure message locations are valid and old messages are not overwritten.
|
||||
*/
|
||||
int pdcch_encode(pdcch_t *q, dci_msg_t *msg, dci_location_t location, uint16_t rnti,
|
||||
cf_t *sf_symbols[MAX_PORTS], uint32_t nsubframe, uint32_t cfi) {
|
||||
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
uint32_t i;
|
||||
cf_t *x[MAX_LAYERS];
|
||||
uint32_t nof_symbols;
|
||||
|
||||
if (q != NULL &&
|
||||
sf_symbols != NULL &&
|
||||
nsubframe < 10 &&
|
||||
cfi > 0 &&
|
||||
cfi < 4 &&
|
||||
dci_location_isvalid(&location))
|
||||
{
|
||||
|
||||
set_cfi(q, cfi);
|
||||
|
||||
q->e_bits = PDCCH_FORMAT_NOF_BITS(location.L);
|
||||
nof_symbols = q->e_bits/2;
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
if (location.ncce + PDCCH_FORMAT_NOF_CCE(location.L) <= q->nof_cce &&
|
||||
msg->nof_bits < DCI_MAX_BITS)
|
||||
{
|
||||
INFO("Encoding DCI: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
|
||||
msg->nof_bits, q->e_bits, location.ncce, location.L, rnti);
|
||||
|
||||
dci_encode(q, msg->data, q->pdcch_e, msg->nof_bits, q->e_bits, rnti);
|
||||
|
||||
/* number of layers equals number of ports */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
x[i] = q->pdcch_x[i];
|
||||
}
|
||||
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
|
||||
|
||||
scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 72 * location.ncce, q->e_bits);
|
||||
|
||||
DEBUG("Scrambling output: ", 0);
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
vec_fprint_b(stdout, q->pdcch_e, q->e_bits);
|
||||
}
|
||||
|
||||
mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->e_bits);
|
||||
|
||||
/* layer mapping & precoding */
|
||||
if (q->cell.nof_ports > 1) {
|
||||
layermap_diversity(q->pdcch_d, x, q->cell.nof_ports, nof_symbols);
|
||||
precoding_diversity(x, q->pdcch_symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
|
||||
} else {
|
||||
memcpy(q->pdcch_symbols[0], q->pdcch_d, nof_symbols * sizeof(cf_t));
|
||||
}
|
||||
|
||||
/* mapping to resource elements */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
regs_pdcch_put_offset(q->regs, q->pdcch_symbols[i], sf_symbols[i],
|
||||
location.ncce * 9, PDCCH_FORMAT_NOF_REGS(location.L));
|
||||
}
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d\n", location.ncce, location.L, q->nof_cce);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
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…
Reference in New Issue