Joseph Giovatto 7 years ago
commit dea80a5ea7

@ -1,6 +1,9 @@
Change Log for Releases
==============================
## 18.03
* Many bug-fixes and improved stability and performance in all parts
## 17.12
* Added support for MIMO 2x2 in srsENB (i.e. TM3/TM4)
* Added srsEPC, a light-weight core network implementation

@ -41,8 +41,6 @@ include(SRSLTEVersion) #sets version information
include(SRSLTEPackage) #setup cpack
include(CTest)
set(CTEST_MEMORYCHECK_COMMAND valgrind)
set(CTEST_MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full" )
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/CTestCustom.cmake.in"
@ -74,6 +72,7 @@ option(ENABLE_BLADERF "Enable BladeRF" ON)
option(BUILD_STATIC "Attempt to statically link external deps" OFF)
option(RPATH "Enable RPATH" OFF)
option(ENABLE_ASAN "Enable gcc address sanitizer" OFF)
option(USE_LTE_RATES "Use standard LTE sampling rates" OFF)
@ -170,7 +169,6 @@ if(ENABLE_SRSUE OR ENABLE_SRSENB OR ENABLE_SRSEPC)
set(BOOST_REQUIRED_COMPONENTS
program_options
system
)
if(UNIX AND EXISTS "/usr/lib64")
list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix
@ -228,13 +226,7 @@ macro(ADD_CXX_COMPILER_FLAG_IF_AVAILABLE flag have)
endmacro(ADD_CXX_COMPILER_FLAG_IF_AVAILABLE)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=${GCC_ARCH} -Wall -Wno-comment -Wno-reorder -Wno-unused-but-set-variable -Wno-unused-variable -std=c++03")
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -DDEBUG_MODE")
else(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
endif(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=${GCC_ARCH} -Wall -Wno-comment -Wno-reorder -Wno-unused-but-set-variable -Wno-unused-variable -Wformat -std=c++03")
find_package(SSE)
if (HAVE_AVX2)
@ -254,9 +246,16 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${GCC_ARCH} -Wall -Wno-comment -Wno-write-strings -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} -g -O0 -DDEBUG_MODE")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -O0 -DDEBUG_MODE -DBUILD_TYPE_DEBUG")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -O0 -DDEBUG_MODE -DBUILD_TYPE_DEBUG")
else(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
if(${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -DBUILD_TYPE_RELWITHDEBINFO")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -DBUILD_TYPE_RELWITHDEBINFO")
else(${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -DBUILD_TYPE_RELEASE")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -DBUILD_TYPE_RELEASE")
endif(${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo")
endif(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
if (USE_LTE_RATES)
@ -303,6 +302,10 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
if(NOT WIN32)
ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
endif(NOT WIN32)
if (ENABLE_ASAN)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
endif (ENABLE_ASAN)
endif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")

@ -11,3 +11,4 @@ set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "my.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=srsLTE")
set(CTEST_DROP_SITE_CDASH TRUE)
set(VALGRIND_COMMAND_OPTIONS "--trace-children=yes --leak-check=full --show-reachable=yes --vex-guest-max-insns=25")

@ -102,7 +102,7 @@ Build Instructions
For example, on Ubuntu 17.04, one can install the required libraries with:
```
sudo apt-get install cmake libfftw3-dev libmbedtls-dev libboost-program-options-dev libboost-thread-dev libconfig++-dev libsctp-dev
sudo apt-get install cmake libfftw3-dev libmbedtls-dev libboost-program-options-dev libconfig++-dev libsctp-dev
```
Note that depending on your flavor and version of Linux, the actual package names may be different.

@ -18,7 +18,7 @@
# and at http://www.gnu.org/licenses/.
#
SET(SRSLTE_VERSION_MAJOR 17)
SET(SRSLTE_VERSION_MINOR 12)
SET(SRSLTE_VERSION_MAJOR 18)
SET(SRSLTE_VERSION_MINOR 3)
SET(SRSLTE_VERSION_PATCH 0)
SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}")

@ -84,6 +84,8 @@ int mbsfn_area_id = -1;
char *rf_args = "";
float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000;
float output_file_snr = +INFINITY;
bool null_file_sink=false;
srslte_filesink_t fsink;
srslte_ofdm_t ifft[SRSLTE_MAX_PORTS];
@ -145,13 +147,14 @@ void usage(char *prog) {
printf("\t-w Number of codewords/layers (multiplex mode only)* [Default %d]\n", multiplex_nof_layers);
printf("\t-u listen TCP port for input data (-1 is random) [Default %d]\n", net_port);
printf("\t-v [set srslte_verbose to debug, default none]\n");
printf("\t-s output file SNR [Default %f]\n", output_file_snr);
printf("\n");
printf("\t*: See 3GPP 36.212 Table 5.3.3.1.5-4 for more information\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "aglfmoncpvutxbwM")) != -1) {
while ((opt = getopt(argc, argv, "aglfmoncpvutxbwMs")) != -1) {
switch (opt) {
case 'a':
@ -200,6 +203,9 @@ void parse_args(int argc, char **argv) {
case 'v':
srslte_verbose++;
break;
case 's':
output_file_snr = atof(argv[optind]);
break;
default:
usage(argv[0]);
exit(-1);
@ -989,6 +995,13 @@ int main(int argc, char **argv) {
/* send to file or usrp */
if (output_file_name) {
if (!null_file_sink) {
/* Apply AWGN */
if (output_file_snr != +INFINITY) {
float var = powf(10.0f, -(output_file_snr + 3.0f) / 20.0f);
for (int k = 0; k < cell.nof_ports; k++) {
srslte_ch_awgn_c(output_buffer[k], output_buffer[k], var, sf_n_samples);
}
}
srslte_filesink_write_multi(&fsink, (void**) output_buffer, sf_n_samples, cell.nof_ports);
}
usleep(1000);

@ -451,9 +451,6 @@ int main(int argc, char **argv) {
exit(0);
}
srslte_rf_stop_rx_stream(&rf);
srslte_rf_flush_buffer(&rf);
/* set sampling frequency */
int srate = srslte_sampling_freq_hz(cell.nof_prb);
if (srate != -1) {

@ -52,7 +52,6 @@ const uint8_t GTPC_V2 = 2;
* n+2 | Sequence |
* n+3 | Spare |
***************************************************************************/
typedef struct gtpc_header
{
uint8_t version;
@ -69,13 +68,14 @@ const uint8_t GTPC_V2 = 2;
*
* Union that hold the different structures for the possible message types.
***************************************************************************/
typedef union gtpc_msg_choice
{
struct gtpc_create_session_request create_session_request;
struct gtpc_create_session_response create_session_response;
struct gtpc_modify_bearer_request modify_bearer_request;
struct gtpc_modify_bearer_response modify_bearer_response;
struct gtpc_release_access_bearers_request release_access_bearers_request;
struct gtpc_release_access_bearers_response release_access_bearers_response;
struct gtpc_delete_session_request delete_session_request;
struct gtpc_delete_session_response delete_session_response;
}gtpc_msg_choice_t;
@ -88,15 +88,10 @@ typedef union gtpc_msg_choice
* of one GTP-C header and one union of structures, which can hold
* all the possible GTP-C messages
***************************************************************************/
typedef struct gtpc_pdu
{
struct gtpc_header header;
union gtpc_msg_choice choice;
}gtpc_pdu_t;
};
}//namespace
#endif

@ -400,7 +400,8 @@ enum gtpc_interface_type
S2B_U_PGW_GTP_U_INTERFACE
};
struct gtpc_f_teid_ie
typedef struct gtpc_f_teid_ie
{
bool ipv4_present;
bool ipv6_present;
@ -408,7 +409,7 @@ struct gtpc_f_teid_ie
uint32_t teid;
in_addr_t ipv4;
struct in6_addr ipv6; //FIXME
};
} gtp_fteid_t;
//TODO
//TODO IEs between 8.22 and 8.28 missing

@ -410,5 +410,36 @@ struct gtpc_delete_session_response
//Private extension
};
/****************************************************************************
*
* GTP-C v2 Release Access Bearers Request
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.21.1-1
*
***************************************************************************/
struct gtpc_release_access_bearers_request
{
bool list_of_rabs_present;
//Linked EPS Bearer ID
bool originating_node_present;
//Indication Flags
//Private Extension
};
/****************************************************************************
*
* GTP-C v2 Delete Session Response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.22.1-1
*
***************************************************************************/
struct gtpc_release_access_bearers_response
{
struct gtpc_cause_ie cause;
//Recovery
//Private extension
};
} //namespace
#endif //GTPC_V2_MSG_H

@ -175,6 +175,7 @@ typedef struct{
uint8 imsi[15];
uint8 imei[15];
uint8 imeisv[16];
uint32 tmsi;
}LIBLTE_MME_MOBILE_ID_STRUCT;
// Functions
LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mobile_id,

@ -32,10 +32,18 @@
extern "C" {
# endif
#ifdef NDEBUG
#ifdef BUILD_TYPE_RELEASE
static char build_mode[] = "Release";
#else
#ifdef BUILD_TYPE_DEBUG
static char build_mode[] = "Debug";
#else
#ifdef BUILD_TYPE_RELWITHDEBINFO
static char build_mode[] = "RelWithDebInfo";
#else
static char build_mode[] = "unknown";
#endif
#endif
#endif
// the configured build options for srsLTE

@ -30,6 +30,8 @@
#include <pthread.h>
#include <vector>
#include <stack>
#include <map>
#include <string>
#include <algorithm>
/*******************************************************************************
@ -70,14 +72,23 @@ public:
delete available.top();
available.pop();
}
for (uint32_t i = 0; i < used.size(); i++) {
delete used[i];
}
}
void print_all_buffers()
{
printf("%d buffers in queue\n", (int) used.size());
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
std::map<std::string, uint32_t> buffer_cnt;
for (uint32_t i=0;i<used.size();i++) {
printf("%s\n", strlen(used[i]->debug_name)?used[i]->debug_name:"Undefined");
buffer_cnt[strlen(used[i]->debug_name)?used[i]->debug_name:"Undefined"]++;
}
std::map<std::string, uint32_t>::iterator it;
for (it = buffer_cnt.begin(); it != buffer_cnt.end(); it++) {
printf(" - %dx %s\n", it->second, it->first.c_str());
}
#endif
}
@ -164,6 +175,10 @@ public:
}
b->reset();
pool->deallocate(b);
b = NULL;
}
void print_all_buffers() {
pool->print_all_buffers();
}
private:
buffer_pool<byte_buffer_t> *pool;

@ -63,7 +63,7 @@
#define SRSLTE_MAX_BUFFER_SIZE_BYTES 12756
#define SRSLTE_BUFFER_HEADER_OFFSET 1024
//#define SRSLTE_BUFFER_POOL_LOG_ENABLED
#define SRSLTE_BUFFER_POOL_LOG_ENABLED
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
#define pool_allocate (pool->allocate(__FUNCTION__))
@ -96,6 +96,8 @@ static const char error_text[ERROR_N_ITEMS][20] = { "None",
"Can't start",
"Already started"};
//#define ENABLE_TIMESTAMP
/******************************************************************************
* Byte and Bit buffers
*
@ -145,35 +147,34 @@ public:
{
return msg-buffer;
}
// Returns the remaining space from what is reported to be the length of msg
uint32_t get_tailroom()
{
return (sizeof(buffer) - (msg-buffer) - N_bytes);
}
long get_latency_us()
{
#ifdef ENABLE_TIMESTAMP
if(!timestamp_is_set)
return 0;
gettimeofday(&timestamp[2], NULL);
get_time_interval(timestamp);
return timestamp[0].tv_usec;
#else
return 0;
#endif
}
void set_timestamp()
{
#ifdef ENABLE_TIMESTAMP
gettimeofday(&timestamp[1], NULL);
timestamp_is_set = true;
#endif
}
private:
void get_time_interval(struct timeval * tdata) {
tdata[0].tv_sec = tdata[2].tv_sec - tdata[1].tv_sec;
tdata[0].tv_usec = tdata[2].tv_usec - tdata[1].tv_usec;
if (tdata[0].tv_usec < 0) {
tdata[0].tv_sec--;
tdata[0].tv_usec += 1000000;
}
}
struct timeval timestamp[3];
bool timestamp_is_set;
byte_buffer_t *next;
@ -215,15 +216,21 @@ struct bit_buffer_t{
}
long get_latency_us()
{
#ifdef ENABLE_TIMESTAMP
if(!timestamp_is_set)
return 0;
gettimeofday(&timestamp[2], NULL);
return timestamp[0].tv_usec;
#else
return 0;
#endif
}
void set_timestamp()
{
#ifdef ENABLE_TIMESTAMP
gettimeofday(&timestamp[1], NULL);
timestamp_is_set = true;
#endif
}
private:

@ -84,6 +84,8 @@ public:
level_text_short = true;
}
virtual ~log() {};
// This function shall be called at the start of every tti for printing tti
void step(uint32_t tti_) {
tti = tti_;
@ -120,11 +122,11 @@ public:
}
// Pure virtual methods for logging
virtual void console(std::string message, ...) = 0;
virtual void error(std::string message, ...) = 0;
virtual void warning(std::string message, ...) = 0;
virtual void info(std::string message, ...) = 0;
virtual void debug(std::string message, ...) = 0;
virtual void console(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
virtual void error(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
virtual void warning(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
virtual void info(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
virtual void debug(const char * message, ...) __attribute__ ((format (printf, 2, 3))) = 0;
// Same with hex dump
virtual void error_hex(uint8_t *hex, int size, std::string message, ...){error("error_hex not implemented.\n");}

@ -57,11 +57,11 @@ public:
void init(std::string layer, logger *logger_, bool tti=false);
void console(std::string message, ...);
void error(std::string message, ...);
void warning(std::string message, ...);
void info(std::string message, ...);
void debug(std::string message, ...);
void console(const char * message, ...);
void error(const char * message, ...);
void warning(const char * message, ...);
void info(const char * message, ...);
void debug(const char * message, ...);
void error_hex(uint8_t *hex, int size, std::string message, ...);
void warning_hex(uint8_t *hex, int size, std::string message, ...);

@ -42,7 +42,10 @@ namespace srslte {
{
public:
void log(std::string *msg) {
if (msg) {
fprintf(stdout, "%s", msg->c_str());
delete msg;
}
}
};

@ -56,6 +56,9 @@ public:
~msg_queue()
{
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&not_empty);
pthread_cond_destroy(&not_full);
delete [] buf;
}

@ -134,10 +134,14 @@ public:
void parse_packet(uint8_t *ptr) {
uint8_t *init_ptr = ptr;
nof_subheaders = 0;
while(subheaders[nof_subheaders].read_subheader(&ptr)) {
bool ret = false;
do {
if (nof_subheaders < (int)max_subheaders) {
ret = subheaders[nof_subheaders].read_subheader(&ptr);
nof_subheaders++;
}
nof_subheaders++;
} while (ret && (nof_subheaders + 1) < (int)max_subheaders);
for (int i=0;i<nof_subheaders;i++) {
subheaders[i].read_payload(&ptr);
}

@ -84,7 +84,6 @@ public:
}
void thread_func()
{
// substract time elapsed until now from timer duration
gettimeofday(&start_time[2], NULL);
get_time_interval(start_time);
@ -105,6 +104,14 @@ public:
return false;
}
}
int32_t get_msec_to_expire() {
if (running) {
gettimeofday(&start_time[2], NULL);
get_time_interval(start_time);
return (duration_msec*1000 - start_time[0].tv_usec)/1000;
}
return 0;
}
bool is_running()
{
return running;

@ -151,15 +151,16 @@ public:
fprintf(stderr, "Error getting unique timer id: no more timers available\n");
return 0;
} else {
while(used_timers[next_timer]) {
next_timer++;
if (next_timer >= nof_timers) {
next_timer=0;
for (uint32_t i=0;i<nof_timers;i++) {
if (!used_timers[i]) {
used_timers[i] = true;
nof_used_timers++;
return i;
}
}
used_timers[next_timer] = true;
nof_used_timers++;
return next_timer;
fprintf(stderr, "Error getting unique timer id: no more timers available but nof_used_timers=%d, nof_timers=%d\n",
nof_used_timers, nof_timers);
return 0;
}
}
private:

@ -119,7 +119,7 @@ public:
virtual uint32_t get_ul_count() = 0;
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0;
virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0;
virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0;
virtual bool plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0;
virtual void plmn_search_end() = 0;
};
@ -160,7 +160,7 @@ public:
virtual void in_sync() = 0;
virtual void out_of_sync() = 0;
virtual void earfcn_end() = 0;
virtual void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) = 0;
virtual void cell_camping(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp = NAN) = 0;
virtual void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn = -1, int pci = -1) = 0;
};
@ -173,7 +173,7 @@ public:
virtual uint16_t get_mnc() = 0;
virtual void enable_capabilities() = 0;
virtual void plmn_search() = 0;
virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0;
virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, bool connect_request = false) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
};
@ -475,6 +475,7 @@ typedef struct {
int cqi_fixed;
float snr_ema_coeff;
std::string snr_estim_alg;
bool cfo_is_doppler;
bool cfo_integer_enabled;
float cfo_correct_tol_hz;
float cfo_pss_ema;
@ -487,11 +488,14 @@ typedef struct {
uint32_t cfo_ref_mask;
bool average_subframe_enabled;
int time_correct_period;
bool sfo_correct_disable;
std::string sss_algorithm;
float estimator_fil_w;
bool rssi_sensor_enabled;
bool sic_pss_enabled;
float rx_gain_offset;
bool pdsch_csi_enabled;
uint32_t intra_freq_meas_len_ms;
uint32_t intra_freq_meas_period_ms;
} phy_args_t;
@ -579,9 +583,8 @@ public:
/* Cell search and selection procedures */
virtual void cell_search_start() = 0;
virtual void cell_search_stop() = 0;
virtual void cell_search_next() = 0;
virtual bool cell_select(uint32_t earfcn, srslte_cell_t cell) = 0;
virtual void cell_select(uint32_t earfcn, srslte_cell_t cell) = 0;
virtual bool cell_handover(srslte_cell_t cell) = 0;
/* Is the PHY downlink synchronized? */

@ -42,8 +42,8 @@
#include "srslte/config.h"
#define SRSLTE_AGC_DEFAULT_TARGET 0.7
#define SRSLTE_AGC_DEFAULT_BW (5e-1)
#define SRSLTE_AGC_DEFAULT_TARGET 0.3
#define SRSLTE_AGC_DEFAULT_BW 0.7
typedef enum SRSLTE_API {
SRSLTE_AGC_MODE_ENERGY = 0,

@ -83,9 +83,12 @@ typedef struct {
srslte_interp_lin_t srslte_interp_lin_mbsfn;
float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float rsrp_corr[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float cfo;
bool rsrp_neighbour;
bool cfo_estimate_enable;
uint32_t cfo_estimate_sf_mask;
@ -158,6 +161,9 @@ SRSLTE_API void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q,
SRSLTE_API void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q,
bool enable);
SRSLTE_API void srslte_chest_dl_set_rsrp_neighbour(srslte_chest_dl_t *q,
bool rsrp_for_neighbour);
SRSLTE_API float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q);
SRSLTE_API float srslte_chest_dl_get_cfo(srslte_chest_dl_t *q);
@ -185,4 +191,6 @@ SRSLTE_API float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q,
SRSLTE_API float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q);
SRSLTE_API float srslte_chest_dl_get_rsrp_neighbour(srslte_chest_dl_t *q);
#endif

@ -42,6 +42,9 @@
typedef struct SRSLTE_API {
uint32_t max_cb;
int16_t **buffer_f;
uint8_t **data;
bool *cb_crc;
bool tb_crc;
} srslte_softbuffer_rx_t;
typedef struct SRSLTE_API {

@ -79,6 +79,7 @@ SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS],
SRSLTE_API int srslte_predecoding_single(cf_t *y,
cf_t *h,
cf_t *x,
float *csi,
int nof_symbols,
float scaling,
float noise_estimate);
@ -86,6 +87,7 @@ SRSLTE_API int srslte_predecoding_single(cf_t *y,
SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x,
float *csi,
int nof_rxant,
int nof_symbols,
float scaling,
@ -111,6 +113,7 @@ SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo
SRSLTE_API int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],
float *csi,
int nof_rxant,
int nof_ports,
int nof_layers,

@ -76,6 +76,9 @@ typedef struct SRSLTE_API {
cf_t *d[SRSLTE_MAX_CODEWORDS]; /* Modulated/Demodulated codewords */
void *e[SRSLTE_MAX_CODEWORDS];
bool csi_enabled;
float *csi[SRSLTE_MAX_CODEWORDS]; /* Channel Strengh Indicator */
/* tx & rx objects */
srslte_modem_table_t mod[4];
@ -107,6 +110,9 @@ SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t *q,
SRSLTE_API void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q,
float rho_a);
SRSLTE_API int srslte_pdsch_enable_csi(srslte_pdsch_t *q,
bool enable);
SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t *q,
uint16_t rnti);

@ -60,6 +60,7 @@ typedef struct {
SRSLTE_RF_ERROR_LATE,
SRSLTE_RF_ERROR_UNDERFLOW,
SRSLTE_RF_ERROR_OVERFLOW,
SRSLTE_RF_ERROR_RX,
SRSLTE_RF_ERROR_OTHER
} type;
int opt;

@ -84,8 +84,6 @@ typedef struct SRSLTE_API {
srslte_ofdm_t fft_mbsfn;
srslte_chest_dl_t chest;
srslte_cfo_t sfo_correct;
srslte_pdsch_cfg_t pdsch_cfg;
srslte_pdsch_cfg_t pmch_cfg;
srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS];
@ -126,8 +124,6 @@ typedef struct SRSLTE_API {
srslte_dci_msg_t pending_ul_dci_msg;
uint16_t pending_ul_dci_rnti;
float sample_offset;
float last_phich_corr;
}srslte_ue_dl_t;
@ -195,9 +191,6 @@ SRSLTE_API int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q,
SRSLTE_API uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q);
SRSLTE_API void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q,
float sample_offset);
SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t *q,
uint8_t *data[SRSLTE_MAX_CODEWORDS],
uint32_t tm,

@ -28,6 +28,8 @@ SRSLTE_API void srslte_ringbuffer_reset(srslte_ringbuffer_t *q);
SRSLTE_API int srslte_ringbuffer_status(srslte_ringbuffer_t *q);
SRSLTE_API int srslte_ringbuffer_space(srslte_ringbuffer_t *q);
SRSLTE_API int srslte_ringbuffer_write(srslte_ringbuffer_t *q,
void *ptr,
int nof_bytes);

@ -705,6 +705,18 @@ static inline void srslte_simd_cf_storeu(float *re, float *im, simd_cf_t simdreg
#endif /* LV_HAVE_AVX512 */
}
static inline simd_f_t srslte_simd_cf_re(simd_cf_t in) {
simd_f_t out = in.re;
#ifndef LV_HAVE_AVX512
#ifdef LV_HAVE_AVX2
/* Permute for AVX registers (mis SSE registers) */
const __m256i idx = _mm256_setr_epi32(0, 2, 4, 6, 1, 3, 5, 7);
out = _mm256_permutevar8x32_ps(out, idx);
#endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */
return out;
}
static inline simd_cf_t srslte_simd_cf_set1 (cf_t x) {
simd_cf_t ret;
#ifdef LV_HAVE_AVX512

@ -73,7 +73,7 @@ SRSLTE_API void srslte_vec_fprint_byte(FILE *stream, uint8_t *x, const uint32_t
SRSLTE_API void srslte_vec_fprint_i(FILE *stream, int *x, const uint32_t len);
SRSLTE_API void srslte_vec_fprint_s(FILE *stream, short *x, const uint32_t len);
SRSLTE_API void srslte_vec_fprint_hex(FILE *stream, uint8_t *x, const uint32_t len);
SRSLTE_API void srslte_vec_sprint_hex(char *str, uint8_t *x, const uint32_t len);
SRSLTE_API void srslte_vec_sprint_hex(char *str, const uint32_t max_str_len, uint8_t *x, const uint32_t len);
/* Saves/loads a vector to a file */
SRSLTE_API void srslte_vec_save_file(char *filename, const void *buffer, const uint32_t len);

@ -120,6 +120,8 @@ SRSLTE_API void srslte_vec_abs_square_cf_simd(const cf_t *x, float *z, const int
/* Other Functions */
SRSLTE_API void srslte_vec_lut_sss_simd(const short *x, const unsigned short *lut, short *y, const int len);
SRSLTE_API void srslte_vec_convert_if_simd(const int16_t *x, float *z, const float scale, const int len);
SRSLTE_API void srslte_vec_convert_fi_simd(const float *x, int16_t *z, const float scale, const int len);
SRSLTE_API void srslte_vec_cp_simd(const cf_t *src, cf_t *dst, int len);

@ -72,6 +72,8 @@ namespace srslte {
trace_enabled = false;
tti = 0;
agc_enabled = false;
radio_is_streaming = false;
is_initialized = false;
};
bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1);
@ -119,13 +121,13 @@ namespace srslte {
void start_trace();
void write_trace(std::string filename);
void start_rx(bool now = false);
void stop_rx();
void set_tti(uint32_t tti);
bool is_first_of_burst();
bool is_init();
void register_error_handler(srslte_rf_error_handler_t h);
protected:
@ -168,6 +170,9 @@ namespace srslte {
uint32_t tti;
bool agc_enabled;
bool is_initialized = true;;
bool radio_is_streaming;
uint32_t saved_nof_channels;
char saved_args[128];
char saved_devname[128];

@ -71,6 +71,7 @@ class rlc_am
{
public:
rlc_am();
~rlc_am();
void init(log *rlc_entity_log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,

@ -50,6 +50,7 @@ class rlc_um
{
public:
rlc_um();
~rlc_um();
void init(log *rlc_entity_log_,
uint32_t lcid_,

@ -296,9 +296,10 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mob
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *id;
uint8 *id = NULL;
uint32 id32 = 0;
uint32 i;
uint8 length;
uint8 length = 0;
bool odd = false;
if(mobile_id != NULL &&
@ -317,6 +318,11 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mob
id = mobile_id->imeisv;
length = 9;
odd = false;
}else if(LIBLTE_MME_MOBILE_ID_TYPE_TMSI == mobile_id->type_of_id){
id32 = mobile_id->tmsi;
length = 4;
odd = false;
}
}else{
// FIXME: Not handling these IDs
return(err);
@ -325,7 +331,8 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mob
// Length
**ie_ptr = length;
*ie_ptr += 1;
if(LIBLTE_MME_MOBILE_ID_TYPE_TMSI != mobile_id->type_of_id)
{
// | Identity digit 1 | odd/even | Id type |
if(odd)
{
@ -335,6 +342,7 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mob
}
*ie_ptr += 1;
// | Identity digit p+1 | Identity digit p |
for(i=0; i<7; i++)
{
@ -349,6 +357,22 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mob
err = LIBLTE_SUCCESS;
}
else{
**ie_ptr = (0xFF << 4) | (0 << 3) | mobile_id->type_of_id;
*ie_ptr += 1;
//4-Byte based ids
**ie_ptr = (id32 >> 24) & 0xFF;
*ie_ptr += 1;
**ie_ptr = (id32 >> 16) & 0xFF;
*ie_ptr += 1;
**ie_ptr = (id32 >> 8) & 0xFF;
*ie_ptr += 1;
**ie_ptr = id32 & 0xFF;
*ie_ptr += 1;
err = LIBLTE_SUCCESS;
}
return(err);
}

@ -11771,7 +11771,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_rrc_connection_reject_msg(LIBLTE_RRC_CONNECTIO
liblte_value_2_bits(0, &msg_ptr, 1);
// Wait Time
liblte_value_2_bits(con_rej->wait_time, &msg_ptr, 4);
liblte_value_2_bits(con_rej->wait_time - 1, &msg_ptr, 4);
// Fill in the number of bits used
msg->N_bits = msg_ptr - msg->msg;
@ -11800,7 +11800,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_rrc_connection_reject_msg(LIBLTE_BIT_MSG_STR
liblte_rrc_warning_not_handled(liblte_bits_2_value(&msg_ptr, 1), __func__);;
// Wait Time
con_rej->wait_time = liblte_bits_2_value(&msg_ptr, 4);
con_rej->wait_time = liblte_bits_2_value(&msg_ptr, 4) + 1;
liblte_rrc_consume_noncrit_extension(ext, __func__, &msg_ptr);

@ -55,11 +55,4 @@ void byte_buffer_pool::cleanup(void)
pthread_mutex_unlock(&instance_mutex);
}
} // namespace srsue

@ -40,6 +40,7 @@ log_filter::log_filter()
do_tti = false;
time_src = NULL;
time_format = TIME;
logger_h = NULL;
}
log_filter::log_filter(std::string layer)
@ -134,55 +135,55 @@ void log_filter::all_log(srslte::LOG_LEVEL_ENUM level,
}
}
void log_filter::console(std::string message, ...) {
void log_filter::console(const char * message, ...) {
char *args_msg;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message.c_str(), args) > 0)
if(vasprintf(&args_msg, message, args) > 0)
printf("%s",args_msg); // Print directly to stdout
va_end(args);
free(args_msg);
}
void log_filter::error(std::string message, ...) {
void log_filter::error(const char * message, ...) {
if (level >= LOG_LEVEL_ERROR) {
char *args_msg;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message.c_str(), args) > 0)
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_ERROR, tti, args_msg);
va_end(args);
free(args_msg);
}
}
void log_filter::warning(std::string message, ...) {
void log_filter::warning(const char * message, ...) {
if (level >= LOG_LEVEL_WARNING) {
char *args_msg;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message.c_str(), args) > 0)
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_WARNING, tti, args_msg);
va_end(args);
free(args_msg);
}
}
void log_filter::info(std::string message, ...) {
void log_filter::info(const char * message, ...) {
if (level >= LOG_LEVEL_INFO) {
char *args_msg;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message.c_str(), args) > 0)
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_INFO, tti, args_msg);
va_end(args);
free(args_msg);
}
}
void log_filter::debug(std::string message, ...) {
void log_filter::debug(const char * message, ...) {
if (level >= LOG_LEVEL_DEBUG) {
char *args_msg;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message.c_str(), args) > 0)
if(vasprintf(&args_msg, message, args) > 0)
all_log(LOG_LEVEL_DEBUG, tti, args_msg);
va_end(args);
free(args_msg);

@ -35,6 +35,7 @@ namespace srslte{
logger_file::logger_file()
:inited(false)
,logfile(NULL)
,not_done(true)
,cur_length(0)
,max_length(0)
@ -46,9 +47,11 @@ logger_file::~logger_file() {
if(inited) {
wait_thread_finish();
flush();
if (logfile) {
fclose(logfile);
}
}
}
void logger_file::init(std::string file, int max_length_) {
pthread_mutex_init(&mutex, NULL);

@ -122,6 +122,11 @@ uint8_t* sch_pdu::write_packet(srslte::log *log_h)
sch_subh padding;
padding.set_padding();
if (nof_subheaders <= 0 && nof_subheaders < (int)max_subheaders) {
log_h->error("Trying to write packet with invalid number of subheaders (nof_subheaders=%d).\n", nof_subheaders);
return NULL;
}
if (init_rem_len < 0) {
log_h->error("init_rem_len=%d\n", init_rem_len);
return NULL;

@ -76,10 +76,14 @@ void pdu_queue::deallocate(uint8_t* pdu)
*/
void pdu_queue::push(uint8_t *ptr, uint32_t len, uint32_t tstamp)
{
if (ptr) {
pdu_t *pdu = (pdu_t*) ptr;
pdu->len = len;
pdu->tstamp = tstamp;
pdu_q.push(pdu);
} else {
log_h->warning("Error pushing pdu: ptr is empty\n");
}
}
bool pdu_queue::process_pdus()

@ -177,7 +177,7 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) {
gg = expf(-0.5*q->bandwidth*logf(q->y_out/q->target));
q->gain *= gg;
}
DEBUG("AGC gain: %.2f (%.2f) y_out=%.3f, y=%.3f target=%.1f gg=%.2f\n", gain_db, gain_uhd_db, q->y_out, y, q->target, gg);
INFO("AGC gain: %.2f (%.2f) y_out=%.3f, y=%.3f target=%.1f gg=%.2f\n", gain_db, gain_uhd_db, q->y_out, y, q->target, gg);
}
}
}

@ -88,7 +88,7 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
goto clean_exit;
}
q->mbsfn_refs = calloc(SRSLTE_MAX_MBSFN_AREA_IDS, sizeof(srslte_refsignal_t*));
q->mbsfn_refs = calloc(SRSLTE_MAX_MBSFN_AREA_IDS, sizeof(srslte_refsignal_t));
if (!q->mbsfn_refs) {
fprintf(stderr, "Calloc error initializing mbsfn_refs (%d)\n", ret);
goto clean_exit;
@ -153,6 +153,8 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
q->noise_alg = SRSLTE_NOISE_ALG_REFS;
q->rsrp_neighbour = false;
q->smooth_filter_len = 3;
srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1);
@ -169,14 +171,14 @@ clean_exit:
void srslte_chest_dl_free(srslte_chest_dl_t *q)
{
int i;
if(&q->csr_refs)
srslte_refsignal_free(&q->csr_refs);
if (q->mbsfn_refs) {
for (i=0; i<SRSLTE_MAX_MBSFN_AREA_IDS; i++) {
for (int i=0; i<SRSLTE_MAX_MBSFN_AREA_IDS; i++) {
if (q->mbsfn_refs[i]) {
srslte_refsignal_free(q->mbsfn_refs[i]);
free(q->mbsfn_refs[i]);
}
}
free(q->mbsfn_refs);
@ -206,6 +208,7 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q)
int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, uint16_t mbsfn_area_id){
if (mbsfn_area_id < SRSLTE_MAX_MBSFN_AREA_IDS) {
if(!q->mbsfn_refs[mbsfn_area_id]) {
q->mbsfn_refs[mbsfn_area_id] = calloc(1, sizeof(srslte_refsignal_t));
}
@ -216,6 +219,8 @@ int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, uint16_t mbsfn_area_
}
return SRSLTE_SUCCESS;
}
return SRSLTE_ERROR;
}
int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell)
{
@ -291,7 +296,7 @@ static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id, srslt
norm /= norm3;
}
}
float power = norm*q->cell.nof_ports*srslte_vec_avg_power_cf(q->tmp_noise, nref);
float power = norm*srslte_vec_avg_power_cf(q->tmp_noise, nref);
return power;
}
@ -540,27 +545,32 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui
}
}
}
/* Compute RSRP for the channel estimates in this port */
uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
q->rsrp[rxant_id][port_id] = __real__ srslte_vec_dot_prod_conj_ccc(q->pilot_estimates, q->pilot_estimates, npilots) / npilots;
q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id);
}
int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id)
{
uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
/* Get references from the input signal */
srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal);
/* Use the known CSR signal to compute Least-squares estimates */
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx],
q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
q->pilot_estimates, npilots);
/* Compute RSRP for the channel estimates in this port */
if (q->rsrp_neighbour) {
double energy = cabs(srslte_vec_acc_cc(q->pilot_estimates, npilots)/npilots);
q->rsrp_corr[rxant_id][port_id] = energy*energy;
}
q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, npilots);
q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id);
chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_NORM);
return 0;
}
int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, uint16_t mbsfn_area_id)
{
@ -619,6 +629,10 @@ int srslte_chest_dl_estimate_multi_mbsfn(srslte_chest_dl_t *q, cf_t *input[SRSLT
return SRSLTE_SUCCESS;
}
void srslte_chest_dl_set_rsrp_neighbour(srslte_chest_dl_t *q, bool rsrp_for_neighbour) {
q->rsrp_neighbour = rsrp_for_neighbour;
}
void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q, bool enable)
{
q->average_subframe = enable;
@ -639,7 +653,10 @@ float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q) {
for (int i=0;i<q->last_nof_antennas;i++) {
n += srslte_vec_acc_ff(q->noise_estimate[i], q->cell.nof_ports)/q->cell.nof_ports;
}
return n/q->last_nof_antennas;
if (q->last_nof_antennas) {
n /= q->last_nof_antennas;
}
return n;
}
float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) {
@ -691,14 +708,49 @@ float srslte_chest_dl_get_rsrp_ant_port(srslte_chest_dl_t *q, uint32_t ant_idx,
}
float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, uint32_t port) {
float n = 0;
for (int i = 0; i < q->last_nof_antennas; i++) {
n += q->rsrp[i][port];
float sum = 0.0f;
for (int j = 0; j < q->cell.nof_ports; ++j) {
sum +=q->rsrp[port][j];
}
return n / q->last_nof_antennas;
if (q->cell.nof_ports) {
sum /= q->cell.nof_ports;
}
return sum;
}
float srslte_chest_dl_get_rsrp_neighbour_port(srslte_chest_dl_t *q, uint32_t port) {
float sum = 0.0f;
for (int j = 0; j < q->cell.nof_ports; ++j) {
sum +=q->rsrp_corr[port][j];
}
if (q->cell.nof_ports) {
sum /= q->cell.nof_ports;
}
return sum;
}
float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) {
// Note: use only port 0 but average across antennas
return srslte_chest_dl_get_rsrp_port(q, 0);
float max = -1e9;
for (int i = 0; i < q->last_nof_antennas; ++i) {
float v = srslte_chest_dl_get_rsrp_port(q, i);
if (v > max) {
max = v;
}
}
return max;
}
float srslte_chest_dl_get_rsrp_neighbour(srslte_chest_dl_t *q) {
float max = -1e9;
for (int i = 0; i < q->last_nof_antennas; ++i) {
float v = srslte_chest_dl_get_rsrp_neighbour_port(q, i);
if (v > max) {
max = v;
}
}
return max;
}

@ -173,7 +173,7 @@ int main(int argc, char **argv) {
gettimeofday(&t[1], NULL);
for (int j=0;j<100;j++) {
srslte_predecoding_single(input, ce, output, num_re, 1.0f, 0);
srslte_predecoding_single(input, ce, output, NULL, num_re, 1.0f, 0);
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
@ -188,7 +188,7 @@ int main(int argc, char **argv) {
gettimeofday(&t[1], NULL);
for (int j=0;j<100;j++) {
srslte_predecoding_single(input, ce, output, num_re, 1.0f, srslte_chest_dl_get_noise_estimate(&est));
srslte_predecoding_single(input, ce, output, NULL, num_re, 1.0f, srslte_chest_dl_get_noise_estimate(&est));
}
gettimeofday(&t[2], NULL);
get_time_interval(t);

@ -45,6 +45,7 @@
#define FFTW_TYPE 0
#endif
pthread_mutex_t fft_mutex = PTHREAD_MUTEX_INITIALIZER;
void srslte_dft_load() {
#ifdef FFTW_WISDOM_FILE
@ -58,10 +59,12 @@ void srslte_dft_exit() {
#ifdef FFTW_WISDOM_FILE
fftwf_export_wisdom_to_filename(FFTW_WISDOM_FILE);
#endif
fftwf_cleanup();
}
int srslte_dft_plan(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir,
srslte_dft_mode_t mode) {
bzero(plan, sizeof(srslte_dft_plan_t));
if(mode == SRSLTE_DFT_COMPLEX){
return srslte_dft_plan_c(plan,dft_points,dir);
} else {
@ -99,10 +102,15 @@ int srslte_dft_replan_guru_c(srslte_dft_plan_t *plan, const int new_dft_points,
const fftwf_iodim iodim = {new_dft_points, istride, ostride};
const fftwf_iodim howmany_dims = {how_many, idist, odist};
pthread_mutex_lock(&fft_mutex);
/* Destroy current plan */
fftwf_destroy_plan(plan->p);
plan->p = fftwf_plan_guru_dft(1, &iodim, 1, &howmany_dims, in_buffer, out_buffer, sign, FFTW_TYPE);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) {
return -1;
}
@ -114,11 +122,15 @@ int srslte_dft_replan_guru_c(srslte_dft_plan_t *plan, const int new_dft_points,
int srslte_dft_replan_c(srslte_dft_plan_t *plan, const int new_dft_points) {
int sign = (plan->dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD;
pthread_mutex_lock(&fft_mutex);
if (plan->p) {
fftwf_destroy_plan(plan->p);
plan->p = NULL;
}
plan->p = fftwf_plan_dft_1d(new_dft_points, plan->in, plan->out, sign, FFTW_TYPE);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) {
return -1;
}
@ -134,10 +146,14 @@ int srslte_dft_plan_guru_c(srslte_dft_plan_t *plan, const int dft_points, srslte
const fftwf_iodim iodim = {dft_points, istride, ostride};
const fftwf_iodim howmany_dims = {how_many, idist, odist};
pthread_mutex_lock(&fft_mutex);
plan->p = fftwf_plan_guru_dft(1, &iodim, 1, &howmany_dims, in_buffer, out_buffer, sign, FFTW_TYPE);
if (!plan->p) {
return -1;
}
pthread_mutex_unlock(&fft_mutex);
plan->size = dft_points;
plan->init_size = plan->size;
plan->mode = SRSLTE_DFT_COMPLEX;
@ -154,8 +170,14 @@ int srslte_dft_plan_guru_c(srslte_dft_plan_t *plan, const int dft_points, srslte
int srslte_dft_plan_c(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir) {
allocate(plan,sizeof(fftwf_complex),sizeof(fftwf_complex), dft_points);
pthread_mutex_lock(&fft_mutex);
int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD;
plan->p = fftwf_plan_dft_1d(dft_points, plan->in, plan->out, sign, FFTW_TYPE);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) {
return -1;
}
@ -175,11 +197,15 @@ int srslte_dft_plan_c(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_
int srslte_dft_replan_r(srslte_dft_plan_t *plan, const int new_dft_points) {
int sign = (plan->dir == SRSLTE_DFT_FORWARD) ? FFTW_R2HC : FFTW_HC2R;
pthread_mutex_lock(&fft_mutex);
if (plan->p) {
fftwf_destroy_plan(plan->p);
plan->p = NULL;
}
plan->p = fftwf_plan_r2r_1d(new_dft_points, plan->in, plan->out, sign, FFTW_TYPE);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) {
return -1;
}
@ -190,7 +216,11 @@ int srslte_dft_replan_r(srslte_dft_plan_t *plan, const int new_dft_points) {
int srslte_dft_plan_r(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir) {
allocate(plan,sizeof(float),sizeof(float), dft_points);
int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_R2HC : FFTW_HC2R;
pthread_mutex_lock(&fft_mutex);
plan->p = fftwf_plan_r2r_1d(dft_points, plan->in, plan->out, sign, FFTW_TYPE);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) {
return -1;
}
@ -309,11 +339,15 @@ void srslte_dft_run_r(srslte_dft_plan_t *plan, const float *in, float *out) {
void srslte_dft_plan_free(srslte_dft_plan_t *plan) {
if (!plan) return;
if (!plan->size) return;
pthread_mutex_lock(&fft_mutex);
if (!plan->is_guru) {
if (plan->in) fftwf_free(plan->in);
if (plan->out) fftwf_free(plan->out);
}
if (plan->p) fftwf_destroy_plan(plan->p);
pthread_mutex_unlock(&fft_mutex);
bzero(plan, sizeof(srslte_dft_plan_t));
}

@ -128,6 +128,8 @@ int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, c
if (sf_type == SRSLTE_SF_MBSFN) {
q->mbsfn_subframe = true;
q->non_mbsfn_region = 2; // default set to 2
} else {
q->mbsfn_subframe = false;
}
return SRSLTE_SUCCESS;

@ -171,5 +171,8 @@ int main(int argc, char **argv) {
n_prb++;
}
srslte_dft_exit();
exit(0);
}

@ -47,32 +47,56 @@ int srslte_softbuffer_rx_init(srslte_softbuffer_rx_t *q, uint32_t nof_prb) {
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL) {
ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_softbuffer_rx_t));
ret = srslte_ra_tbs_from_idx(26, nof_prb);
if (ret != SRSLTE_ERROR) {
q->max_cb = (uint32_t) ret / (SRSLTE_TCOD_MAX_LEN_CB - 24) + 1;
ret = SRSLTE_ERROR;
q->buffer_f = srslte_vec_malloc(sizeof(int16_t*) * q->max_cb);
if (!q->buffer_f) {
perror("malloc");
return SRSLTE_ERROR;
goto clean_exit;
}
q->data = srslte_vec_malloc(sizeof(uint8_t*) * q->max_cb);
if (!q->data) {
perror("malloc");
goto clean_exit;
}
q->cb_crc = srslte_vec_malloc(sizeof(bool) * q->max_cb);
if (!q->cb_crc) {
perror("malloc");
goto clean_exit;
}
bzero(q->cb_crc, sizeof(bool) * q->max_cb);
// FIXME: Use HARQ buffer limitation based on UE category
for (uint32_t i=0;i<q->max_cb;i++) {
q->buffer_f[i] = srslte_vec_malloc(sizeof(int16_t) * SOFTBUFFER_SIZE);
if (!q->buffer_f[i]) {
perror("malloc");
return SRSLTE_ERROR;
goto clean_exit;
}
q->data[i] = srslte_vec_malloc(sizeof(uint8_t) * 6144/8);
if (!q->data[i]) {
perror("malloc");
goto clean_exit;
}
}
//srslte_softbuffer_rx_reset(q);
ret = SRSLTE_SUCCESS;
}
}
clean_exit:
if (ret != SRSLTE_SUCCESS) {
srslte_softbuffer_rx_free(q);
}
return ret;
}
@ -86,6 +110,17 @@ void srslte_softbuffer_rx_free(srslte_softbuffer_rx_t *q) {
}
free(q->buffer_f);
}
if (q->data) {
for (uint32_t i=0;i<q->max_cb;i++) {
if (q->data[i]) {
free(q->data[i]);
}
}
free(q->data);
}
if (q->cb_crc) {
free(q->cb_crc);
}
bzero(q, sizeof(srslte_softbuffer_rx_t));
}
}
@ -110,6 +145,9 @@ void srslte_softbuffer_rx_reset_cb(srslte_softbuffer_rx_t *q, uint32_t nof_cb) {
}
}
}
if (q->cb_crc) {
bzero(q->cb_crc, sizeof(bool) * q->max_cb);
}
}

@ -198,6 +198,8 @@ int main(int argc, char **argv) {
}
srslte_rm_turbo_free_tables();
free(rm_bits_s);
free(rm_bits_f);
free(rm_bits);
free(rm_bits2);
free(rm_bits2_bytes);

@ -71,8 +71,6 @@ int main(int argc, char **argv) {
parse_args(argc, argv);
srslte_tcod_gentable();
srslte_tcod_t tcod;
srslte_tcod_init(&tcod, 6144);

@ -279,6 +279,7 @@ int main(int argc, char **argv) {
free(llr);
free(llr_c);
free(data_rx);
free(data_rx2);
if (snr_points == 1) {
int expected_errors = get_expected_errors(nof_frames, seed, frame_length, tail_biting, ebno_db);

@ -166,9 +166,15 @@ void free37_avx2_16bit(void *o) {
if (q->symbols_uc) {
free(q->symbols_uc);
}
if (q->symbols_us) {
free(q->symbols_us);
}
if (q->tmp) {
free(q->tmp);
}
if (q->tmp_s) {
free(q->tmp_s);
}
delete_viterbi37_avx2_16bit(q->ptr);
}

@ -34,6 +34,7 @@
#include "srslte/phy/utils/vector.h"
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/mat.h"
#include "srslte/phy/utils/simd.h"
#ifdef LV_HAVE_SSE
#include <immintrin.h>
@ -252,8 +253,49 @@ int srslte_predecoding_single_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
return nof_symbols;
}
int srslte_predecoding_single_csi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, float *csi, int nof_rxant, int nof_symbols, float scaling, float noise_estimate) {
int i = 0;
#if SRSLTE_SIMD_CF_SIZE
const simd_f_t _noise = srslte_simd_f_set1(noise_estimate);
const simd_f_t _scaling = srslte_simd_f_set1(1.0f / scaling);
for (; i < nof_symbols - SRSLTE_SIMD_CF_SIZE + 1; i += SRSLTE_SIMD_CF_SIZE) {
simd_cf_t _r = srslte_simd_cf_zero();
simd_f_t _hh = srslte_simd_f_zero();
for (int p = 0; p < nof_rxant; p++) {
simd_cf_t _y = srslte_simd_cfi_load(&y[p][i]);
simd_cf_t _h = srslte_simd_cfi_load(&h[p][i]);
_r = srslte_simd_cf_add(_r, srslte_simd_cf_conjprod(_y, _h));
_hh = srslte_simd_f_add(_hh, srslte_simd_cf_re(srslte_simd_cf_conjprod(_h, _h)));
}
simd_f_t _csi = srslte_simd_f_add(_hh, _noise);
simd_cf_t _x = srslte_simd_cf_mul(srslte_simd_cf_mul(_r, _scaling), srslte_simd_f_rcp(_csi));
srslte_simd_f_store(&csi[i], _csi);
srslte_simd_cfi_store(&x[i], _x);
}
#endif
for (; i < nof_symbols; i++) {
cf_t r = 0;
float hh = 0;
float _scaling = 1.0f / scaling;
for (int p = 0; p < nof_rxant; p++) {
r += y[p][i] * conj(h[p][i]);
hh += (__real__ h[p][i] * __real__ h[p][i]) + (__imag__ h[p][i] * __imag__ h[p][i]);
}
csi[i] = hh + noise_estimate;
x[i] = r * _scaling / csi[i];
}
return nof_symbols;
}
/* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/
int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, float scaling, float noise_estimate) {
int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, float *csi, int nof_symbols, float scaling, float noise_estimate) {
cf_t *y[SRSLTE_MAX_PORTS];
cf_t *h[SRSLTE_MAX_PORTS];
@ -261,6 +303,10 @@ int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, floa
h[0] = h_;
int nof_rxant = 1;
if (csi) {
return srslte_predecoding_single_csi(y, h, x, csi, nof_rxant, nof_symbols, scaling, noise_estimate);
}
#ifdef LV_HAVE_AVX
if (nof_symbols > 32 && nof_rxant <= 2) {
return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
@ -281,8 +327,12 @@ int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, floa
}
/* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/
int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x,
int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, float *csi,
int nof_rxant, int nof_symbols, float scaling, float noise_estimate) {
if (csi) {
return srslte_predecoding_single_csi(y, h, x, csi, nof_rxant, nof_symbols, scaling, noise_estimate);
}
#ifdef LV_HAVE_AVX
if (nof_symbols > 32) {
return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
@ -1418,7 +1468,7 @@ void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder) {
/* 36.211 v10.3.0 Section 6.3.4 */
int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_ports, int nof_layers,
cf_t *x[SRSLTE_MAX_LAYERS], float *csi, int nof_rxant, int nof_ports, int nof_layers,
int codebook_idx, int nof_symbols, srslte_mimo_type_t type, float scaling,
float noise_estimate) {
@ -1451,7 +1501,7 @@ int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS]
return -1;
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) {
return srslte_predecoding_single_multi(y, h[0], x[0], nof_rxant, nof_symbols, scaling, noise_estimate);
return srslte_predecoding_single_multi(y, h[0], x[0], csi, nof_rxant, nof_symbols, scaling, noise_estimate);
} else {
fprintf(stderr,
"Number of ports and layers must be 1 for transmission on single antenna ports (%d, %d)\n", nof_ports, nof_layers);

@ -291,7 +291,7 @@ int main(int argc, char **argv) {
/* predecoding / equalization */
struct timeval t[3];
gettimeofday(&t[1], NULL);
srslte_predecoding_type(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers,
srslte_predecoding_type(r, h, xr, NULL, nof_rx_ports, nof_tx_ports, nof_layers,
codebook_idx, nof_re, type, scaling, powf(10, -snr_db / 10));
gettimeofday(&t[2], NULL);
get_time_interval(t);

@ -197,6 +197,7 @@ int main(int argc, char **argv) {
}
}
free(llr2);
free(llr);
free(symbols);
free(symbols_bytes);

@ -407,7 +407,7 @@ float srslte_cqi_to_coderate(uint32_t cqi) {
* Table III.
*/
// From paper
static float cqi_to_snr_table[15] = { 1.95, 4, 6, 8, 10, 11.95, 14.05, 16, 17.9, 19.9, 21.5, 23.45, 25.0, 27.30, 29};
static float cqi_to_snr_table[15] = { 1.95, 4, 6, 8, 10, 11.95, 14.05, 16, 17.9, 20.9, 22.5, 24.75, 25.5, 27.30, 29};
// From experimental measurements @ 5 MHz
//static float cqi_to_snr_table[15] = { 1, 1.75, 3, 4, 5, 6, 7.5, 9, 11.5, 13.0, 15.0, 18, 20, 22.5, 26.5};

@ -400,6 +400,7 @@ int decode_frame(srslte_pbch_t *q, uint32_t src, uint32_t dst, uint32_t n,
uint32_t nof_bits, uint32_t nof_ports) {
int j;
if (dst + n <= 4 && src + n <= 4) {
memcpy(&q->temp[dst * nof_bits], &q->llr[src * nof_bits],
n * nof_bits * sizeof(float));
@ -428,6 +429,11 @@ int decode_frame(srslte_pbch_t *q, uint32_t src, uint32_t dst, uint32_t n,
} else {
return SRSLTE_SUCCESS;
}
} else {
fprintf(stderr, "Error in PBCH decoder: Invalid frame pointers dst=%d, src=%d, n=%d\n", src, dst, n);
return -1;
}
}
/* Decodes the PBCH channel
@ -483,6 +489,8 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
q->frame_idx++;
ret = 0;
uint32_t frame_idx = q->frame_idx;
/* Try decoding for 1 to cell.nof_ports antennas */
if (q->search_all_ports) {
nant = 1;
@ -492,12 +500,12 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
do {
if (nant != 3) {
DEBUG("Trying %d TX antennas with %d frames\n", nant, q->frame_idx);
DEBUG("Trying %d TX antennas with %d frames\n", nant, frame_idx);
/* in control channels, only diversity is supported */
if (nant == 1) {
/* no need for layer demapping */
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, 1.0f, noise_estimate);
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, NULL, q->nof_symbols, 1.0f, noise_estimate);
} else {
srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant,
q->nof_symbols, 1.0f);
@ -505,19 +513,19 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
}
/* demodulate symbols */
srslte_demod_soft_demodulate(SRSLTE_MOD_QPSK, q->d, &q->llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols);
srslte_demod_soft_demodulate(SRSLTE_MOD_QPSK, q->d, &q->llr[nof_bits * (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.
*/
for (nb = 0; nb < q->frame_idx; nb++) {
for (nb = 0; nb < frame_idx; nb++) {
for (dst = 0; (dst < 4 - nb); dst++) {
for (src = 0; src < q->frame_idx - nb; src++) {
for (src = 0; src < frame_idx - nb; src++) {
ret = decode_frame(q, src, dst, nb + 1, nof_bits, nant);
if (ret == 1) {
if (sfn_offset) {
*sfn_offset = (int) dst - src + q->frame_idx - 1;
*sfn_offset = (int) dst - src + frame_idx - 1;
}
if (nof_tx_ports) {
*nof_tx_ports = nant;
@ -525,7 +533,8 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
if (bch_payload) {
memcpy(bch_payload, q->data, sizeof(uint8_t) * SRSLTE_BCH_PAYLOAD_LEN);
}
INFO("Decoded PBCH: src=%d, dst=%d, nb=%d, sfn_offset=%d\n", src, dst, nb+1, (int) dst - src + q->frame_idx - 1);
INFO("Decoded PBCH: src=%d, dst=%d, nb=%d, sfn_offset=%d\n", src, dst, nb+1, (int) dst - src + frame_idx - 1);
srslte_pbch_decode_reset(q);
return 1;
}
}

@ -219,7 +219,7 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P
/* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) {
/* no need for layer demapping */
srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, q->nof_rx_antennas, q->nof_symbols, 1.0f, noise_estimate);
srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, NULL, q->nof_rx_antennas, q->nof_symbols, 1.0f, noise_estimate);
} else {
srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols, 1.0f);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports);

@ -490,7 +490,7 @@ int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MA
/* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) {
/* no need for layer demapping */
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, nof_symbols, 1.0f, noise_estimate/2);
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, NULL, q->nof_rx_antennas, nof_symbols, 1.0f, noise_estimate/2);
} else {
srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols, 1.0f);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);

@ -294,6 +294,10 @@ void srslte_pdsch_free(srslte_pdsch_t *q) {
if (q->d[i]) {
free(q->d[i]);
}
if (q->csi[i]) {
free(q->csi[i]);
}
}
/* Free sch objects */
@ -394,6 +398,22 @@ void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q, float rho_a) {
}
}
int srslte_pdsch_enable_csi(srslte_pdsch_t *q, bool enable) {
if (enable) {
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (!q->csi[i]) {
q->csi[i] = srslte_vec_malloc(sizeof(float) * q->max_re);
if (!q->csi[i]) {
return SRSLTE_ERROR;
}
}
}
}
q->csi_enabled = enable;
return SRSLTE_SUCCESS;
}
void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti)
{
uint32_t rnti_idx = q->is_ue?0:rnti;
@ -617,6 +637,41 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c
/* Bit scrambling */
srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, nbits->nof_bits);
uint32_t qm = nbits->nof_bits/nbits->nof_re;
switch(cfg->grant.mcs[tb_idx].mod) {
case SRSLTE_MOD_BPSK:
qm = 1;
break;
case SRSLTE_MOD_QPSK:
qm = 2;
break;
case SRSLTE_MOD_16QAM:
qm = 4;
break;
case SRSLTE_MOD_64QAM:
qm = 6;
break;
default:
ERROR("No modulation");
}
int16_t *e = q->e[codeword_idx];
if (q->csi_enabled) {
const uint32_t csi_max_idx = srslte_vec_max_fi(q->csi[codeword_idx], nbits->nof_bits / qm);
float csi_max = 1.0f;
if (csi_max_idx < nbits->nof_bits / qm) {
csi_max = q->csi[codeword_idx][csi_max_idx];
}
for (int i = 0; i < nbits->nof_bits / qm; i++) {
const float csi = q->csi[codeword_idx][i] / csi_max;
for (int k = 0; k < qm; k++) {
e[qm * i + k] = (int16_t) ((float) e[qm * i + k] * csi);
}
}
}
/* Return */
ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, tb_idx);
@ -702,7 +757,7 @@ int srslte_pdsch_decode(srslte_pdsch_t *q,
}
// Pre-decoder
if (srslte_predecoding_type(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers,
if (srslte_predecoding_type(q->symbols, q->ce, x, q->csi[0], q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers,
cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, pdsch_scaling, noise_estimate)<0) {
DEBUG("Error predecoding\n");
return SRSLTE_ERROR;

@ -239,7 +239,7 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS],
/* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) {
/* no need for layer demapping */
srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, 1.0f, noise_estimate);
srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, NULL, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, 1.0f, noise_estimate);
} else {
srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB, 1.0f);
srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports);

@ -152,7 +152,6 @@ int srslte_pmch_init(srslte_pmch_t *q, uint32_t max_prb)
int srslte_pmch_init_multi(srslte_pmch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
int i;
if (q != NULL &&
nof_rx_antennas <= SRSLTE_MAX_PORTS)
@ -169,7 +168,7 @@ int srslte_pmch_init_multi(srslte_pmch_t *q, uint32_t max_prb, uint32_t nof_rx_a
INFO("Init PMCH: %d PRBs, max_symbols: %d\n",
max_prb, q->max_re);
for (i = 0; i < 4; i++) {
for (int i = 0; i < 4; i++) {
if (srslte_modem_table_lte(&q->mod[i], modulations[i])) {
goto clean;
}
@ -189,7 +188,7 @@ int srslte_pmch_init_multi(srslte_pmch_t *q, uint32_t max_prb, uint32_t nof_rx_a
goto clean;
}
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->x[i]) {
goto clean;
@ -232,7 +231,7 @@ void srslte_pmch_free(srslte_pmch_t *q) {
if (q->d) {
free(q->d);
}
for (i = 0; i < q->cell.nof_ports; i++) {
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
if (q->x[i]) {
free(q->x[i]);
}
@ -378,7 +377,7 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q,
}
// No tx diversity in MBSFN
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits[0].nof_re, 1.0f, noise_estimate);
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, NULL, q->nof_rx_antennas, cfg->nbits[0].nof_re, 1.0f, noise_estimate);
if (SRSLTE_VERBOSE_ISDEBUG()) {
DEBUG("SAVED FILE subframe.dat: received subframe symbols\n");

@ -158,7 +158,6 @@ uint32_t prach_zc_roots_format4[138] = {
61, 78, 62, 77, 63, 76, 64, 75, 65, 74, 66, 73,
67, 72, 68, 71, 69, 70};
srslte_prach_sf_config_t prach_sf_config[16] = {
{1, {1, 0, 0, 0, 0}},
{1, {4, 0, 0, 0, 0}},
@ -192,8 +191,7 @@ srslte_prach_sfn_t srslte_prach_get_sfn(uint32_t config_idx) {
/* Returns true if current_tti is a valid opportunity for PRACH transmission and the is an allowed subframe,
* or allowed_subframe == -1
*/
bool srslte_prach_tti_opportunity(srslte_prach_t *p, uint32_t current_tti, int allowed_subframe)
{
bool srslte_prach_tti_opportunity(srslte_prach_t *p, uint32_t current_tti, int allowed_subframe) {
uint32_t config_idx = p->config_idx;
// Get SFN and sf_idx from the PRACH configuration index
srslte_prach_sfn_t prach_sfn = srslte_prach_get_sfn(config_idx);
@ -204,14 +202,12 @@ bool srslte_prach_tti_opportunity(srslte_prach_t *p, uint32_t current_tti, int a
}
if ((prach_sfn == SRSLTE_PRACH_SFN_EVEN && ((current_tti / 10) % 2) == 0) ||
prach_sfn == SRSLTE_PRACH_SFN_ANY)
{
prach_sfn == SRSLTE_PRACH_SFN_ANY) {
srslte_prach_sf_config_t sf_config;
srslte_prach_sf_config(config_idx, &sf_config);
for (int i = 0; i < sf_config.nof_sf; i++) {
if (((current_tti % 10) == sf_config.sf[i] && allowed_subframe == -1) ||
((current_tti%10) == sf_config.sf[i] && (current_tti%10) == allowed_subframe))
{
((current_tti % 10) == sf_config.sf[i] && (current_tti % 10) == allowed_subframe)) {
return true;
}
}
@ -219,23 +215,19 @@ bool srslte_prach_tti_opportunity(srslte_prach_t *p, uint32_t current_tti, int a
return false;
}
void srslte_prach_sf_config(uint32_t config_idx, srslte_prach_sf_config_t *sf_config) {
memcpy(sf_config, &prach_sf_config[config_idx % 16], sizeof(srslte_prach_sf_config_t));
}
// For debug use only
void print(void *d, uint32_t size, uint32_t len, char* file_str)
{
void print(void *d, uint32_t size, uint32_t len, char *file_str) {
FILE *f;
f = fopen(file_str, "wb");
fwrite(d, size, len, f);
fclose(f);
}
int srslte_prach_gen_seqs(srslte_prach_t *p)
{
int srslte_prach_gen_seqs(srslte_prach_t *p) {
uint32_t u = 0;
uint32_t v = 1;
int v_max = 0;
@ -281,18 +273,24 @@ int srslte_prach_gen_seqs(srslte_prach_t *p)
N_shift = d_u / p->N_cs;
d_start = 2 * d_u + N_shift * p->N_cs;
N_group = p->N_zc / d_start;
if (p->N_zc > 2 * d_u + N_group * d_start) {
N_neg_shift = (p->N_zc - 2 * d_u - N_group * d_start) / p->N_cs;
if(N_neg_shift < 0)
N_neg_shift = 0;
} else {
N_neg_shift = 0;
}
} else if (p->N_zc / 3 <= d_u && d_u <= (p->N_zc - p->N_cs) / 2) {
N_shift = (p->N_zc - 2 * d_u) / p->N_cs;
d_start = p->N_zc - 2 * d_u + N_shift * p->N_cs;
N_group = d_u / d_start;
if (d_u > N_group * d_start) {
N_neg_shift = (d_u - N_group * d_start) / p->N_cs;
if(N_neg_shift < 0)
} else {
N_neg_shift = 0;
}
if (N_neg_shift > N_shift)
N_neg_shift = N_shift;
} else {
N_shift = 0;
}
v_max = N_shift * N_group + N_neg_shift - 1;
if (v_max < 0) {
@ -329,8 +327,7 @@ int srslte_prach_gen_seqs(srslte_prach_t *p)
return 0;
}
int srslte_prach_init_cfg(srslte_prach_t *p, srslte_prach_cfg_t *cfg, uint32_t nof_prb)
{
int srslte_prach_init_cfg(srslte_prach_t *p, srslte_prach_cfg_t *cfg, uint32_t nof_prb) {
if (srslte_prach_init(p, srslte_symbol_sz(nof_prb))) {
return -1;
}
@ -342,12 +339,10 @@ int srslte_prach_init_cfg(srslte_prach_t *p, srslte_prach_cfg_t *cfg, uint32_t n
cfg->zero_corr_zone);
}
int srslte_prach_init(srslte_prach_t *p, uint32_t max_N_ifft_ul)
{
int srslte_prach_init(srslte_prach_t *p, uint32_t max_N_ifft_ul) {
int ret = SRSLTE_ERROR;
if (p != NULL &&
max_N_ifft_ul < 2049)
{
max_N_ifft_ul < 2049) {
bzero(p, sizeof(srslte_prach_t));
p->max_N_ifft_ul = max_N_ifft_ul;
@ -403,20 +398,17 @@ int srslte_prach_init(srslte_prach_t *p, uint32_t max_N_ifft_ul)
return ret;
}
int srslte_prach_set_cell(srslte_prach_t *p,
uint32_t N_ifft_ul,
uint32_t config_idx,
uint32_t root_seq_index,
bool high_speed_flag,
uint32_t zero_corr_zone_config)
{
uint32_t zero_corr_zone_config) {
int ret = SRSLTE_ERROR;
if (p != NULL &&
N_ifft_ul < 2049 &&
config_idx < 64 &&
root_seq_index < MAX_ROOTS)
{
root_seq_index < MAX_ROOTS) {
if (N_ifft_ul > p->max_N_ifft_ul) {
fprintf(stderr, "PRACH: Error in set_cell(): N_ifft_ul must be lower or equal max_N_ifft_ul in init()\n");
return -1;
@ -521,13 +513,11 @@ int srslte_prach_set_cell(srslte_prach_t *p,
int srslte_prach_gen(srslte_prach_t *p,
uint32_t seq_index,
uint32_t freq_offset,
cf_t *signal)
{
cf_t *signal) {
int ret = SRSLTE_ERROR;
if (p != NULL &&
seq_index < N_SEQS &&
signal != NULL)
{
signal != NULL) {
// Calculate parameters
uint32_t N_rb_ul = srslte_nof_prb(p->N_ifft_ul);
uint32_t k_0 = freq_offset * N_RB_SC - N_rb_ul * N_RB_SC / 2 + p->N_ifft_ul / 2;
@ -572,8 +562,7 @@ int srslte_prach_detect(srslte_prach_t *p,
cf_t *signal,
uint32_t sig_len,
uint32_t *indices,
uint32_t *n_indices)
{
uint32_t *n_indices) {
return srslte_prach_detect_offset(p, freq_offset, signal, sig_len, indices, NULL, NULL, n_indices);
}
@ -584,14 +573,12 @@ int srslte_prach_detect_offset(srslte_prach_t *p,
uint32_t *indices,
float *t_offsets,
float *peak_to_avg,
uint32_t *n_indices)
{
uint32_t *n_indices) {
int ret = SRSLTE_ERROR;
if (p != NULL &&
signal != NULL &&
sig_len > 0 &&
indices != NULL)
{
indices != NULL) {
if (sig_len < p->N_ifft_prach) {
fprintf(stderr, "srslte_prach_detect: Signal length is %d and should be %d\n", sig_len, p->N_ifft_prach);
@ -651,8 +638,7 @@ int srslte_prach_detect_offset(srslte_prach_t *p,
}
if (max_peak > p->detect_factor * corr_ave) {
for (int j = 0; j < n_wins; j++) {
if(p->peak_values[j] > p->detect_factor*corr_ave)
{
if (p->peak_values[j] > p->detect_factor * corr_ave) {
//printf("saving prach correlation\n");
//memcpy(save_corr, p->corr, p->N_zc*sizeof(float));
if (indices) {
@ -695,10 +681,8 @@ int srslte_prach_free(srslte_prach_t *p) {
return 0;
}
int srslte_prach_print_seqs(srslte_prach_t *p)
{
for(int i=0; i<N_SEQS;i++)
{
int srslte_prach_print_seqs(srslte_prach_t *p) {
for (int i = 0; i < N_SEQS; i++) {
FILE *f;
char str[32];
sprintf(str, "prach_seq_%d.bin", i);
@ -706,8 +690,7 @@ int srslte_prach_print_seqs(srslte_prach_t *p)
fwrite(p->seqs[i], sizeof(cf_t), p->N_zc, f);
fclose(f);
}
for(int i=0; i<N_SEQS;i++)
{
for (int i = 0; i < N_SEQS; i++) {
FILE *f;
char str[32];
sprintf(str, "prach_dft_seq_%d.bin", i);
@ -715,8 +698,7 @@ int srslte_prach_print_seqs(srslte_prach_t *p)
fwrite(p->dft_seqs[i], sizeof(cf_t), p->N_zc, f);
fclose(f);
}
for(int i=0;i<p->N_roots;i++)
{
for (int i = 0; i < p->N_roots; i++) {
FILE *f;
char str[32];
sprintf(str, "prach_root_seq_%d.bin", i);

@ -787,7 +787,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
}
// Equalization
srslte_predecoding_single(q->z_tmp, q->ce, q->z, nof_re, 1.0f, noise_estimate);
srslte_predecoding_single(q->z_tmp, q->ce, q->z, NULL, nof_re, 1.0f, noise_estimate);
// Perform ML-decoding
float corr=0, corr_max=-1e9;

@ -596,7 +596,7 @@ int srslte_pusch_decode(srslte_pusch_t *q,
}
// Equalization
srslte_predecoding_single(q->d, q->ce, q->z, cfg->nbits.nof_re, 1.0f, noise_estimate);
srslte_predecoding_single(q->d, q->ce, q->z, NULL, cfg->nbits.nof_re, 1.0f, noise_estimate);
// DFT predecoding
srslte_dft_precoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb);

@ -336,14 +336,17 @@ bool decode_tb_cb(srslte_sch_t *q,
decoder_input[i] = NULL;
}
uint32_t remaining_cb = 0;
for (int i=0;i<nof_cb;i++) {
cb_map[i] = false;
/* Do not process blocks with CRC Ok */
cb_map[i] = softbuffer->cb_crc[i];
if (softbuffer->cb_crc[i] == false) {
remaining_cb ++;
}
}
srslte_tdec_reset(&q->decoder, cb_len);
uint32_t remaining_cb = nof_cb;
q->nof_iterations = 0;
while(remaining_cb>0) {
@ -401,7 +404,8 @@ bool decode_tb_cb(srslte_sch_t *q,
// CRC is OK
if (!srslte_crc_checksum_byte(crc_ptr, q->cb_in, len_crc)) {
memcpy(&data[(cb_idx[i]*rlen)/8], q->cb_in, rlen/8 * sizeof(uint8_t));
memcpy(softbuffer->data[cb_idx[i]], q->cb_in, rlen/8 * sizeof(uint8_t));
softbuffer->cb_crc[cb_idx[i]] = true;
q->nof_iterations += srslte_tdec_get_nof_iterations_cb(&q->decoder, i);
@ -418,15 +422,28 @@ bool decode_tb_cb(srslte_sch_t *q,
cb_idx[i], remaining_cb, i, first_cb, nof_cb);
q->nof_iterations += q->max_iterations;
q->nof_iterations /= (nof_cb-remaining_cb+1);
return false;
srslte_tdec_reset_cb(&q->decoder, i);
remaining_cb--;
decoder_input[i] = NULL;
cb_idx[i] = 0;
}
}
}
}
softbuffer->tb_crc = true;
for (int i = 0; i < nof_cb && softbuffer->tb_crc; i++) {
/* If one CB failed return false */
softbuffer->tb_crc = softbuffer->cb_crc[i];
}
if (softbuffer->tb_crc) {
for (int i = 0; i < nof_cb; i++) {
memcpy(&data[i * rlen / 8], softbuffer->data[i], rlen/8 * sizeof(uint8_t));
}
}
q->nof_iterations /= nof_cb;
return true;
return softbuffer->tb_crc;
}
/**

@ -157,6 +157,7 @@ int main(int argc, char **argv) {
bzero(ce, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
bzero(tx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
bzero(t, 3 * sizeof(struct timeval));
cell.nof_ports = 1;
@ -469,5 +470,8 @@ quit:
} else {
printf("Ok\n");
}
srslte_dft_exit();
exit(ret);
}

@ -35,6 +35,8 @@
#include "srslte/phy/rf/rf.h"
#include "uhd_c_api.h"
#define HAVE_ASYNC_THREAD 0
typedef struct {
char *devname;
uhd_usrp_handle usrp;
@ -80,13 +82,14 @@ static void log_overflow(rf_uhd_handler_t *h) {
static void log_late(rf_uhd_handler_t *h, bool is_rx) {
if (h->uhd_error_handler) {
srslte_rf_error_t error;
error.opt = is_rx?1:0;
bzero(&error, sizeof(srslte_rf_error_t));
error.opt = is_rx?1:0;
error.type = SRSLTE_RF_ERROR_LATE;
h->uhd_error_handler(error);
}
}
#if HAVE_ASYNC_THREAD
static void log_underflow(rf_uhd_handler_t *h) {
if (h->uhd_error_handler) {
srslte_rf_error_t error;
@ -95,7 +98,22 @@ static void log_underflow(rf_uhd_handler_t *h) {
h->uhd_error_handler(error);
}
}
#endif
static void log_rx_error(rf_uhd_handler_t *h) {
if (h->uhd_error_handler) {
char error_string[512];
uhd_usrp_last_error(h->usrp, error_string, 512);
fprintf(stderr, "USRP reported the following error: %s\n", error_string);
srslte_rf_error_t error;
bzero(&error, sizeof(srslte_rf_error_t));
error.type = SRSLTE_RF_ERROR_RX;
h->uhd_error_handler(error);
}
}
#if HAVE_ASYNC_THREAD
static void* async_thread(void *h) {
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
uhd_async_metadata_handle md;
@ -122,6 +140,7 @@ static void* async_thread(void *h) {
uhd_async_metadata_free(&md);
return NULL;
}
#endif
void rf_uhd_suppress_stdout(void *h) {
rf_uhd_register_msg_handler_c(suppress_handler);
@ -334,6 +353,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
perror("malloc");
return -1;
}
bzero(handler, sizeof(rf_uhd_handler_t));
*h = handler;
/* Set priority to UHD threads */
@ -556,12 +576,14 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
rf_uhd_set_rx_gain(handler, max_gain*0.7);
uhd_meta_range_free(&gain_range);
#if HAVE_ASYNC_THREAD
// Start low priority thread to receive async commands
handler->async_thread_running = true;
if (pthread_create(&handler->async_thread, NULL, async_thread, handler)) {
perror("pthread_create");
return -1;
}
#endif
/* Restore priorities */
uhd_set_thread_priority(0, false);
@ -738,6 +760,7 @@ int rf_uhd_recv_with_time_multi(void *h,
num_rx_samples, md, 1.0, false, &rxd_samples);
if (error) {
fprintf(stderr, "Error receiving from UHD: %d\n", error);
log_rx_error(handler);
return -1;
}
@ -760,8 +783,12 @@ int rf_uhd_recv_with_time_multi(void *h,
}
}
} else {
return uhd_rx_streamer_recv(handler->rx_stream, data,
nsamples, md, 0.0, false, &rxd_samples);
uhd_error error = uhd_rx_streamer_recv(handler->rx_stream, data, nsamples, md, 0.0, false, &rxd_samples);
if (error) {
fprintf(stderr, "Error receiving from UHD: %d\n", error);
log_rx_error(handler);
return -1;
}
}
if (secs && frac_secs) {
uhd_rx_metadata_time_spec(handler->rx_md_first, secs, frac_secs);

@ -186,9 +186,11 @@ int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas,
ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell);
}
if (ret < 0) {
srslte_rf_stop_rx_stream(rf);
fprintf(stderr, "Error searching cell\n");
return SRSLTE_ERROR;
} else if (ret == 0) {
srslte_rf_stop_rx_stream(rf);
fprintf(stderr, "Could not find any cell in this frequency\n");
return SRSLTE_SUCCESS;
}

@ -71,7 +71,7 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o
q->N_id_1 = 1000;
q->cfo_ema_alpha = CFO_EMA_ALPHA;
q->sss_alg = SSS_PARTIAL_3;
q->sss_alg = SSS_FULL;
q->detect_cp = true;
q->sss_en = true;
@ -152,21 +152,19 @@ clean_exit:
void srslte_sync_free(srslte_sync_t *q)
{
if (q) {
srslte_pss_free(&q->pss);
srslte_sss_free(&q->sss);
srslte_cfo_free(&q->cfo_corr_frame);
srslte_cfo_free(&q->cfo_corr_symbol);
srslte_cp_synch_free(&q->cp_synch);
if (q->cfo_i_initiated) {
for (int i = 0; i < 2; i++) {
if (q->cfo_i_corr[i]) {
free(q->cfo_i_corr[i]);
}
srslte_pss_free(&q->pss_i[i]);
}
}
if (q->temp) {
free(q->temp);
}

@ -74,7 +74,7 @@ void usage(char *prog) {
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "adgetvsfil")) != -1) {
while ((opt = getopt(argc, argv, "adgetvnsfil")) != -1) {
switch (opt) {
case 'a':
rf_args = argv[optind];

@ -71,7 +71,6 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
q->pmch_pkt_errors = 0;
q->pmch_pkts_total = 0;
q->pending_ul_dci_rnti = 0;
q->sample_offset = 0;
q->nof_rx_antennas = nof_rx_antennas;
for (int j = 0; j < SRSLTE_MAX_PORTS; j++) {
@ -147,11 +146,6 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
goto clean_exit;
}
}
if (srslte_cfo_init(&q->sfo_correct, max_prb*SRSLTE_NRE)) {
fprintf(stderr, "Error initiating SFO correct\n");
goto clean_exit;
}
srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft[0].symbol_sz);
ret = SRSLTE_SUCCESS;
} else {
@ -178,7 +172,6 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) {
srslte_pdcch_free(&q->pdcch);
srslte_pdsch_free(&q->pdsch);
srslte_pmch_free(&q->pmch);
srslte_cfo_free(&q->sfo_correct);
for (int i = 0; i < SRSLTE_MAX_TB; i++) {
srslte_softbuffer_rx_free(q->softbuffers[i]);
if (q->softbuffers[i]) {
@ -209,7 +202,6 @@ int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell)
q->pkt_errors = 0;
q->pkts_total = 0;
q->pending_ul_dci_rnti = 0;
q->sample_offset = 0;
if (q->cell.id != cell.id || q->cell.nof_prb == 0) {
if (q->cell.nof_prb != 0) {
@ -220,11 +212,6 @@ int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell)
fprintf(stderr, "Error resizing REGs\n");
return SRSLTE_ERROR;
}
if (srslte_cfo_resize(&q->sfo_correct, q->cell.nof_prb*SRSLTE_NRE)) {
fprintf(stderr, "Error resizing SFO correct\n");
return SRSLTE_ERROR;
}
srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft[0].symbol_sz);
for (int port = 0; port < q->nof_rx_antennas; port++) {
if (srslte_ofdm_rx_set_prb(&q->fft[port], q->cell.cp, q->cell.nof_prb)) {
fprintf(stderr, "Error resizing FFT\n");
@ -348,10 +335,6 @@ void srslte_ue_dl_reset(srslte_ue_dl_t *q) {
bzero(&q->pdsch_cfg, sizeof(srslte_pdsch_cfg_t));
}
void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) {
q->sample_offset = sample_offset;
}
/** Applies the following operations to a subframe of synchronized samples:
* - OFDM demodulation
* - Channel estimation
@ -395,17 +378,6 @@ int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q, cf_t *input[SRSLT
/* Run FFT for all subframe data */
for (int j=0;j<q->nof_rx_antennas;j++) {
srslte_ofdm_rx_sf_ng(&q->fft[j], input[j], q->sf_symbols_m[j]);
/* Correct SFO multiplying by complex exponential in the time domain */
if (q->sample_offset) {
int nsym = SRSLTE_CP_NSYMB(q->cell.cp);
for (int i=0;i<2*nsym;i++) {
srslte_cfo_correct(&q->sfo_correct,
&q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE],
&q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE],
q->sample_offset / q->fft[j].symbol_sz);
}
}
}
return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM);
} else {
@ -460,15 +432,15 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3
pmi = grant->pinfo - 1;
} else {
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
return SRSLTE_ERROR;
pmi = grant->pinfo % 4;
}
} else {
if (grant->pinfo < 2) {
pmi = grant->pinfo;
} else {
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
return SRSLTE_ERROR;
if (grant->pinfo == 2) {
ERROR("Not implemented codebook index (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
} else if (grant->pinfo > 2) {
ERROR("Reserved codebook index (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
}
pmi = grant->pinfo % 2;
}
}
if(SRSLTE_SF_MBSFN == grant->sf_type) {

@ -144,18 +144,11 @@ void srslte_ue_sync_reset(srslte_ue_sync_t *q) {
int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, double (set_gain_callback)(void*, double), float init_gain_value) {
uint32_t nframes;
if (q->nof_recv_sf == 1) {
nframes = 10;
} else {
nframes = 0;
}
int n = srslte_agc_init_uhd(&q->agc, SRSLTE_AGC_MODE_PEAK_AMPLITUDE, nframes, set_gain_callback, q->stream);
int n = srslte_agc_init_uhd(&q->agc, SRSLTE_AGC_MODE_PEAK_AMPLITUDE, 0, set_gain_callback, q->stream);
q->do_agc = n==0?true:false;
if (q->do_agc) {
srslte_agc_set_gain(&q->agc, init_gain_value);
srslte_agc_set_target(&q->agc, 0.3);
srslte_agc_set_bandwidth(&q->agc, 0.8);
srslte_ue_sync_set_agc_period(q, 4);
}
return n;
}
@ -329,7 +322,6 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell)
memcpy(&q->cell, &cell, sizeof(srslte_cell_t));
q->fft_size = srslte_symbol_sz(q->cell.nof_prb);
q->sf_len = SRSLTE_SF_LEN(q->fft_size);
q->agc_period = 0;
if (cell.id == 1000) {
@ -764,6 +756,8 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
srslte_agc_process(&q->agc, input_buffer[0], q->sf_len);
}
INFO("SYNC FIND: sf_idx=%d, ret=%d, next_state=%d\n", q->sf_idx, ret, q->state);
break;
case SF_TRACK:
@ -825,6 +819,9 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
q->frame_total_cnt++;
}
INFO("SYNC TRACK: sf_idx=%d, ret=%d, next_state=%d\n", q->sf_idx, ret, q->state);
break;
}
}

@ -355,7 +355,7 @@ int srslte_ue_ul_pucch_encode(srslte_ue_ul_t *q, srslte_uci_data_t uci_data,
}
if (q->normalize_en) {
float norm_factor = (float) 0.8*q->cell.nof_prb/5;
float norm_factor = (float) q->cell.nof_prb/15/10;
srslte_vec_sc_prod_cfc(output_signal, norm_factor, output_signal, SRSLTE_SF_LEN_PRB(q->cell.nof_prb));
}
ret = SRSLTE_SUCCESS;

@ -13,10 +13,9 @@ int srslte_ringbuffer_init(srslte_ringbuffer_t *q, int capacity)
}
q->active = true;
q->capacity = capacity;
srslte_ringbuffer_reset(q);
pthread_mutex_init(&q->mutex, NULL);
pthread_cond_init(&q->cvar, NULL);
srslte_ringbuffer_reset(q);
return 0;
}
@ -48,6 +47,11 @@ int srslte_ringbuffer_status(srslte_ringbuffer_t *q)
return q->count;
}
int srslte_ringbuffer_space(srslte_ringbuffer_t *q)
{
return q->capacity - q->count;
}
int srslte_ringbuffer_write(srslte_ringbuffer_t *q, void *p, int nof_bytes)
{
uint8_t *ptr = (uint8_t*) p;

@ -157,6 +157,8 @@ int main(int argc, char **argv) {
if(test_dft(in) != 0)
return -1;
srslte_dft_exit();
free(in);
printf("Done\n");
exit(0);

@ -265,6 +265,7 @@ TEST(srslte_vec_sum_fff,
free(x);
free(y);
free(z);
)
TEST(srslte_vec_sub_fff,
@ -287,6 +288,7 @@ TEST(srslte_vec_sub_fff,
free(x);
free(y);
free(z);
)
TEST(srslte_vec_dot_prod_ccc,
@ -354,6 +356,7 @@ TEST(srslte_vec_prod_ccc,
}
free(x);
free(y);
free(z);
)
@ -407,6 +410,7 @@ TEST(srslte_vec_prod_conj_ccc,
}
free(x);
free(y);
free(z);
)
@ -452,6 +456,28 @@ TEST(srslte_vec_convert_fi,
free(z);
)
TEST(srslte_vec_convert_if,
MALLOC(int16_t, x);
MALLOC(float, z);
float scale = 1000.0f;
float gold;
float k = 1.0f/scale;
for (int i = 0; i < block_size; i++) {
x[i] = (int16_t) RANDOM_S();
}
TEST_CALL(srslte_vec_convert_if(x, scale, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = ((float)x[i]) * k;
mse += fabsf(gold - z[i]);
}
free(x);
free(z);
)
TEST(srslte_vec_prod_fff,
MALLOC(float, x);
MALLOC(float, y);
@ -596,7 +622,7 @@ TEST(srslte_vec_div_ccc,
for (int i = 0; i < block_size; i++) {
gold = x[i] / y[i];
mse += cabsf(gold - z[i]);
mse += cabsf(gold - z[i]) / cabsf(gold);
}
mse /= block_size;
@ -614,7 +640,7 @@ TEST(srslte_vec_div_cfc,
cf_t gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
y[i] = RANDOM_F();
y[i] = RANDOM_F() + 0.0001f;
}
TEST_CALL(srslte_vec_div_cfc(x, y, z, block_size))
@ -638,15 +664,15 @@ TEST(srslte_vec_div_fff,
cf_t gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_F() + 0.0001;
y[i] = RANDOM_F()+ 0.0001;
x[i] = RANDOM_F();
y[i] = RANDOM_F() + 0.0001f;
}
TEST_CALL(srslte_vec_div_fff(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] / y[i];
mse += cabsf(gold - z[i]);
mse += cabsf(gold - z[i]) / cabsf(gold);
}
mse /= block_size;
@ -753,6 +779,9 @@ int main(int argc, char **argv) {
passed[func_count][size_count] = test_srslte_vec_convert_fi(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_convert_if(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_prod_fff(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;

@ -93,10 +93,7 @@ void srslte_vec_sc_prod_ccc(const cf_t *x, const cf_t h, cf_t *z, const uint32_t
// Used in turbo decoder
void srslte_vec_convert_if(const int16_t *x, const float scale, float *z, const uint32_t len) {
int i;
for (i=0;i<len;i++) {
z[i] = ((float) x[i])/scale;
}
srslte_vec_convert_if_simd(x, z, scale, len);
}
void srslte_vec_convert_fi(const float *x, const float scale, int16_t *z, const uint32_t len) {
@ -203,10 +200,16 @@ void srslte_vec_fprint_hex(FILE *stream, uint8_t *x, const uint32_t len) {
fprintf(stream, "];\n");
}
void srslte_vec_sprint_hex(char *str, uint8_t *x, const uint32_t len) {
void srslte_vec_sprint_hex(char *str, const uint32_t max_str_len, uint8_t *x, const uint32_t len) {
uint32_t i, nbytes;
uint8_t byte;
nbytes = len/8;
// check that hex string fits in buffer (every byte takes 3 characters, plus brackets)
if ((3*(len/8 + ((len%8)?1:0))) + 2 >= max_str_len) {
fprintf(stderr, "Buffer too small for printing hex string (max_str_len=%d, payload_len=%d).\n", max_str_len, len);
return;
}
int n=0;
n+=sprintf(&str[n], "[");
for (i=0;i<nbytes;i++) {
@ -218,6 +221,7 @@ void srslte_vec_sprint_hex(char *str, uint8_t *x, const uint32_t len) {
n+=sprintf(&str[n], "%02x ", byte);
}
n+=sprintf(&str[n], "]");
str[max_str_len-1] = 0;
}
void srslte_vec_save_file(char *filename, const void *buffer, const uint32_t len) {

@ -228,6 +228,36 @@ void srslte_vec_lut_sss_simd(const short *x, const unsigned short *lut, short *y
}
}
void srslte_vec_convert_if_simd(const int16_t *x, float *z, const float scale, const int len) {
int i = 0;
const float gain = 1.0f / scale;
#ifdef LV_HAVE_SSE
__m128 s = _mm_set1_ps(gain);
if (SRSLTE_IS_ALIGNED(z)) {
for (; i < len - 3; i += 4) {
__m64 *ptr = (__m64 *) &x[i];
__m128 fl = _mm_cvtpi16_ps(*ptr);
__m128 v = _mm_mul_ps(fl, s);
_mm_store_ps(&z[i], v);
}
} else {
for (; i < len - 3; i += 4) {
__m64 *ptr = (__m64 *) &x[i];
__m128 fl = _mm_cvtpi16_ps(*ptr);
__m128 v = _mm_mul_ps(fl, s);
_mm_storeu_ps(&z[i], v);
}
}
#endif /* LV_HAVE_SSE */
for (; i < len; i++) {
z[i] = ((float) x[i]) * gain;
}
}
void srslte_vec_convert_fi_simd(const float *x, int16_t *z, const float scale, const int len) {
int i = 0;

@ -71,9 +71,14 @@ bool radio::init(char *args, char *devname, uint32_t nof_channels)
}
saved_nof_channels = nof_channels;
is_initialized = true;
return true;
}
bool radio::is_init() {
return is_initialized;
}
void radio::stop()
{
srslte_rf_close(&rf_device);
@ -82,11 +87,8 @@ void radio::stop()
void radio::reset()
{
printf("Resetting Radio...\n");
srslte_rf_close(&rf_device);
sleep(3);
if (srslte_rf_open_devname(&rf_device, saved_devname, saved_args, saved_nof_channels)) {
fprintf(stderr, "Error opening RF device\n");
}
srslte_rf_stop_rx_stream(&rf_device);
radio_is_streaming = false;
}
void radio::set_manual_calibration(rf_cal_t* calibration)
@ -141,6 +143,10 @@ bool radio::rx_at(void* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time
bool radio::rx_now(void* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time)
{
if (!radio_is_streaming) {
srslte_rf_start_rx_stream(&rf_device, false);
radio_is_streaming = true;
}
if (srslte_rf_recv_with_time_multi(&rf_device, buffer, nof_samples, true,
rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) {
return true;
@ -446,16 +452,6 @@ void radio::set_tx_srate(double srate)
tx_adv_sec = nsamples/cur_tx_srate;
}
void radio::start_rx(bool now)
{
srslte_rf_start_rx_stream(&rf_device, now);
}
void radio::stop_rx()
{
srslte_rf_stop_rx_stream(&rf_device);
}
void radio::register_error_handler(srslte_rf_error_handler_t h)
{
srslte_rf_register_error_handler(&rf_device, h);

@ -37,6 +37,7 @@ bool radio_multi::init_multi(uint32_t nof_rx_antennas, char* args, char* devname
strncpy(saved_devname, devname, 127);
}
is_initialized = true;
return true;
}
@ -46,6 +47,10 @@ bool radio_multi::rx_now(cf_t *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, s
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
ptr[i] = buffer[i];
}
if (!radio_is_streaming) {
srslte_rf_start_rx_stream(&rf_device, false);
radio_is_streaming = true;
}
if (srslte_rf_recv_with_time_multi(&rf_device, ptr, nof_samples, true,
rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) {
return true;

@ -92,8 +92,12 @@ bool pdcp::is_drb_enabled(uint32_t lcid)
void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
{
if(valid_lcid(lcid))
if(valid_lcid(lcid)) {
pdcp_array[lcid].write_sdu(sdu);
} else {
pdcp_log->warning("Writing sdu: lcid=%d. Deallocating sdu\n", lcid);
byte_buffer_pool::get_instance()->deallocate(sdu);
}
}
void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg)
@ -149,8 +153,12 @@ void pdcp::enable_encryption(uint32_t lcid)
*******************************************************************************/
void pdcp::write_pdu(uint32_t lcid, byte_buffer_t *pdu)
{
if(valid_lcid(lcid))
if(valid_lcid(lcid)) {
pdcp_array[lcid].write_pdu(pdu);
} else {
pdcp_log->warning("Writing pdu: lcid=%d. Deallocating pdu\n", lcid);
byte_buffer_pool::get_instance()->deallocate(pdu);
}
}
void pdcp::write_pdu_bcch_bch(byte_buffer_t *sdu)

@ -187,10 +187,14 @@ void rlc::write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes)
rlc_log->info_hex(payload, nof_bytes, "BCCH BCH message received.");
dl_tput_bytes[0] += nof_bytes;
byte_buffer_t *buf = pool_allocate;
if (buf) {
memcpy(buf->msg, payload, nof_bytes);
buf->N_bytes = nof_bytes;
buf->set_timestamp();
pdcp->write_pdu_bcch_bch(buf);
} else {
rlc_log->error("Fatal error: Out of buffers from the pool in write_pdu_bcch_bch()\n");
}
}
void rlc::write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes)
@ -198,10 +202,14 @@ void rlc::write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes)
rlc_log->info_hex(payload, nof_bytes, "BCCH TXSCH message received.");
dl_tput_bytes[0] += nof_bytes;
byte_buffer_t *buf = pool_allocate;
if (buf) {
memcpy(buf->msg, payload, nof_bytes);
buf->N_bytes = nof_bytes;
buf->set_timestamp();
pdcp->write_pdu_bcch_dlsch(buf);
} else {
rlc_log->error("Fatal error: Out of buffers from the pool in write_pdu_bcch_dlsch()\n");
}
}
void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes)
@ -209,10 +217,14 @@ void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes)
rlc_log->info_hex(payload, nof_bytes, "PCCH message received.");
dl_tput_bytes[0] += nof_bytes;
byte_buffer_t *buf = pool_allocate;
if (buf) {
memcpy(buf->msg, payload, nof_bytes);
buf->N_bytes = nof_bytes;
buf->set_timestamp();
pdcp->write_pdu_pcch(buf);
} else {
rlc_log->error("Fatal error: Out of buffers from the pool in write_pdu_pcch()\n");
}
}
/*******************************************************************************
@ -281,6 +293,7 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg)
bool rlc::valid_lcid(uint32_t lcid)
{
if(lcid >= SRSLTE_N_RADIO_BEARERS) {
rlc_log->warning("Invalid LCID=%d\n", lcid);
return false;
} else if(!rlc_array[lcid].active()) {
return false;

@ -68,6 +68,20 @@ rlc_am::rlc_am() : tx_sdu_queue(16)
do_status = false;
}
rlc_am::~rlc_am()
{
// reset RLC and dealloc SDUs
stop();
if(rx_sdu) {
pool->deallocate(rx_sdu);
}
if(tx_sdu) {
pool->deallocate(tx_sdu);
}
}
void rlc_am::init(srslte::log *log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
@ -112,10 +126,12 @@ void rlc_am::reset()
pthread_mutex_lock(&mutex);
reordering_timeout.reset();
if(tx_sdu)
tx_sdu->reset();
if(rx_sdu)
rx_sdu->reset();
if(tx_sdu) {
pool->deallocate(tx_sdu);
}
if(rx_sdu) {
pool->deallocate(rx_sdu);
}
vt_a = 0;
vt_ms = RLC_AM_WINDOW_SIZE;
@ -182,7 +198,7 @@ uint32_t rlc_am::get_bearer()
void rlc_am::write_sdu(byte_buffer_t *sdu)
{
tx_sdu_queue.write(sdu);
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU, tx_sdu_len=%d", rrc->get_rb_name(lcid).c_str(), tx_sdu_queue.size());
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU (%d B, tx_sdu_queue_len=%d)", rrc->get_rb_name(lcid).c_str(), sdu->N_bytes, tx_sdu_queue.size());
}
/****************************************************************************
@ -257,6 +273,27 @@ uint32_t rlc_am::get_buffer_state()
goto unlock_and_return;
}
// check if pollRetx timer expired (Section 5.2.2.3 in TS 36.322)
if (poll_retx()) {
// if both tx and retx buffer are empty, retransmit next PDU to be ack'ed
log->info("Poll reTx timer expired (lcid=%d)\n", lcid);
if ((tx_window.size() > 0 && retx_queue.size() == 0 && tx_sdu_queue.size() == 0)) {
std::map<uint32_t, rlc_amd_tx_pdu_t>::iterator it = tx_window.find(vt_s - 1);
if (it != tx_window.end()) {
log->info("Schedule last PDU (SN=%d) for reTx.\n", vt_s - 1);
rlc_amd_retx_t retx;
retx.is_segment = false;
retx.so_start = 0;
retx.so_end = tx_window[vt_s - 1].buf->N_bytes;
retx.sn = vt_s - 1;
retx_queue.push_back(retx);
} else {
log->error("Found invalid PDU in tx_window.\n");
}
poll_retx_timeout.start(cfg.t_poll_retx);
}
}
// Bytes needed for retx
if(retx_queue.size() > 0) {
rlc_amd_retx_t retx = retx_queue.front();
@ -305,7 +342,7 @@ int rlc_am::read_pdu(uint8_t *payload, uint32_t nof_bytes)
pthread_mutex_lock(&mutex);
log->debug("MAC opportunity - %d bytes\n", nof_bytes);
log->debug("tx_window size - %d PDUs\n", tx_window.size());
log->debug("tx_window size - %zu PDUs\n", tx_window.size());
// Tx STATUS if requested
if(do_status && !status_prohibited()) {
@ -587,7 +624,8 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r
rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len);
return 0;
}
pdu_space = nof_bytes-head_len-2;
pdu_space = nof_bytes-head_len;
if(pdu_space < (retx.so_end-retx.so_start))
retx.so_end = retx.so_start+pdu_space;
@ -603,10 +641,13 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r
if(lower >= retx.so_end)
break;
if(pdu_space <= 2)
break;
upper += old_header.li[i];
head_len = rlc_am_packed_length(&new_header);
pdu_space = nof_bytes-head_len-2;
pdu_space = nof_bytes-head_len;
if(pdu_space < (retx.so_end-retx.so_start))
retx.so_end = retx.so_start+pdu_space;
@ -657,7 +698,7 @@ int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t r
if(pdu_len > (int)nof_bytes) {
log->error("%s Retx PDU segment length error. Available: %d, Used: %d\n",
rrc->get_rb_name(lcid).c_str(), nof_bytes, pdu_len);
log->debug("%s Retx PDU segment length error. Header len: %d, Payload len: %d, N_li: %d\n",
log->debug("%s Retx PDU segment length error. Header len: %ld, Payload len: %d, N_li: %d\n",
rrc->get_rb_name(lcid).c_str(), (ptr-payload), len, new_header.N_li);
}
return pdu_len;
@ -786,6 +827,12 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
rrc->get_rb_name(lcid).c_str(), to_move, pdu_space, head_len);
}
// Make sure, at least one SDU (segment) has been added until this point
if (pdu->N_bytes == 0) {
log->error("Generated empty RLC PDU.\n");
return 0;
}
if(tx_sdu)
header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU
@ -807,7 +854,6 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
// Set SN
header.sn = vt_s;
vt_s = (vt_s + 1)%MOD;
log->info("%s PDU scheduled for tx. SN: %d\n", rrc->get_rb_name(lcid).c_str(), header.sn);
// Place PDU in tx_window, write header and TX
tx_window[header.sn].buf = pdu;
@ -818,6 +864,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
uint8_t *ptr = payload;
rlc_am_write_data_pdu_header(&header, &ptr);
memcpy(ptr, pdu->msg, pdu->N_bytes);
log->info_hex(payload, pdu->N_bytes, "%s PDU scheduled for tx. SN: %d (%d B)\n", rrc->get_rb_name(lcid).c_str(), header.sn, pdu->N_bytes);
debug_state();
return (ptr-payload) + pdu->N_bytes;
@ -827,8 +874,8 @@ void rlc_am::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes, rlc_amd_pdu_h
{
std::map<uint32_t, rlc_amd_rx_pdu_t>::iterator it;
log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d",
rrc->get_rb_name(lcid).c_str(), header.sn);
log->info_hex(payload, nof_bytes, "%s Rx data PDU SN: %d (%d B), %s",
rrc->get_rb_name(lcid).c_str(), header.sn, nof_bytes, rlc_fi_field_text[header.fi]);
if(!inside_rx_window(header.sn)) {
if(header.p) {
@ -1116,20 +1163,23 @@ void rlc_am::reassemble_rx_sdus()
#endif
}
}
// Iterate through rx_window, assembling and delivering SDUs
while(rx_window.end() != rx_window.find(vr_r))
{
// Handle any SDU segments
for(uint32_t i=0; i<rx_window[vr_r].header.N_li; i++)
{
int len = rx_window[vr_r].header.li[i];
uint32_t len = rx_window[vr_r].header.li[i];
if (rx_sdu->get_tailroom() >= len) {
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_r].buf->msg, len);
rx_sdu->N_bytes += len;
rx_window[vr_r].buf->msg += len;
rx_window[vr_r].buf->N_bytes -= len;
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str());
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", rrc->get_rb_name(lcid).c_str(), rx_sdu->N_bytes);
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate;
if (!rx_sdu) {
#ifdef RLC_AM_BUFFER_DEBUG
@ -1140,14 +1190,28 @@ void rlc_am::reassemble_rx_sdus()
return;
#endif
}
} else {
log->error("Cannot fit RLC PDU in SDU buffer, dropping both.\n");
pool->deallocate(rx_sdu);
pool->deallocate(rx_window[vr_r].buf);
rx_window.erase(vr_r);
}
}
// Handle last segment
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_r].buf->msg, rx_window[vr_r].buf->N_bytes);
uint32_t len = rx_window[vr_r].buf->N_bytes;
if (rx_sdu->get_tailroom() >= len) {
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_r].buf->msg, len);
rx_sdu->N_bytes += rx_window[vr_r].buf->N_bytes;
if(rlc_am_end_aligned(rx_window[vr_r].header.fi))
{
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rrc->get_rb_name(lcid).c_str());
} else {
log->error("Cannot fit RLC PDU in SDU buffer, dropping both.\n");
pool->deallocate(rx_sdu);
pool->deallocate(rx_window[vr_r].buf);
rx_window.erase(vr_r);
}
if(rlc_am_end_aligned(rx_window[vr_r].header.fi)) {
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", rrc->get_rb_name(lcid).c_str(), rx_sdu->N_bytes);
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate;
@ -1209,7 +1273,7 @@ void rlc_am::print_rx_segments()
for(it=rx_segments.begin();it!=rx_segments.end();it++) {
std::list<rlc_amd_rx_pdu_t>::iterator segit;
for(segit = it->second.segments.begin(); segit != it->second.segments.end(); segit++) {
ss << " SN:" << segit->header.sn << " SO:" << segit->header.so << " N:" << segit->buf->N_bytes << std::endl;
ss << " SN:" << segit->header.sn << " SO:" << segit->header.so << " N:" << segit->buf->N_bytes << " N_li: " << segit->header.N_li << std::endl;
}
}
log->debug("%s\n", ss.str().c_str());
@ -1217,15 +1281,33 @@ void rlc_am::print_rx_segments()
bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pdu_t *segment)
{
// Ordered insert
std::list<rlc_amd_rx_pdu_t>::iterator tmpit;
std::list<rlc_amd_rx_pdu_t>::iterator it = pdu->segments.begin();
while(it != pdu->segments.end() && it->header.so < segment->header.so)
it++;
pdu->segments.insert(it, *segment);
// Check for first segment
if(0 == segment->header.so) {
std::list<rlc_amd_rx_pdu_t>::iterator it;
for(it = pdu->segments.begin(); it != pdu->segments.end(); it++) {
pool->deallocate(it->buf);
}
pdu->segments.clear();
pdu->segments.push_back(*segment);
return false;
}
// Check segment offset
uint32_t n = 0;
if(!pdu->segments.empty()) {
rlc_amd_rx_pdu_t &back = pdu->segments.back();
n = back.header.so + back.buf->N_bytes;
}
if(segment->header.so != n) {
pool->deallocate(segment->buf);
return false;
} else {
pdu->segments.push_back(*segment);
}
// Check for complete
uint32_t so = 0;
std::list<rlc_amd_rx_pdu_t>::iterator it, tmpit;
for(it = pdu->segments.begin(); it != pdu->segments.end(); it++) {
if(so != it->header.so)
return false;
@ -1287,6 +1369,7 @@ bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pd
}
handle_data_pdu(full_pdu->msg, full_pdu->N_bytes, header);
pool->deallocate(full_pdu);
return true;
}

@ -125,10 +125,14 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes)
void rlc_tm::write_pdu(uint8_t *payload, uint32_t nof_bytes)
{
byte_buffer_t *buf = pool_allocate;
if (buf) {
memcpy(buf->msg, payload, nof_bytes);
buf->N_bytes = nof_bytes;
buf->set_timestamp();
pdcp->write_pdu(lcid, buf);
} else {
log->error("Fatal Error: Couldn't allocate buffer in rlc_tm::write_pdu().\n");
}
}
} // namespace srsue

@ -59,6 +59,11 @@ rlc_um::rlc_um() : tx_sdu_queue(16)
pdu_lost = false;
}
rlc_um::~rlc_um()
{
stop();
}
void rlc_um::init(srslte::log *log_,
uint32_t lcid_,
srsue::pdcp_interface_rlc *pdcp_,
@ -114,12 +119,13 @@ void rlc_um::empty_queue() {
void rlc_um::stop()
{
reset();
if (mac_timers) {
mac_timers->timer_release_id(reordering_timer_id);
}
}
void rlc_um::reset()
{
// Empty tx_sdu_queue before locking the mutex
empty_queue();
@ -129,12 +135,17 @@ void rlc_um::reset()
vr_ux = 0;
vr_uh = 0;
pdu_lost = false;
if(rx_sdu)
rx_sdu->reset();
if(tx_sdu)
tx_sdu->reset();
if(mac_timers)
if(rx_sdu) {
pool->deallocate(rx_sdu);
}
if(tx_sdu) {
pool->deallocate(tx_sdu);
}
if(mac_timers) {
reordering_timer->stop();
}
// Drop all messages in RX window
std::map<uint32_t, rlc_umd_pdu_t>::iterator it;
@ -162,7 +173,7 @@ uint32_t rlc_um::get_bearer()
void rlc_um::write_sdu(byte_buffer_t *sdu)
{
tx_sdu_queue.write(sdu);
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU, tx_sdu_len=%d", rrc->get_rb_name(lcid).c_str(), tx_sdu_queue.size());
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU (%d B ,tx_sdu_queue_len=%d)", rrc->get_rb_name(lcid).c_str(), sdu->N_bytes, tx_sdu_queue.size());
}
/****************************************************************************
@ -437,8 +448,13 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
void rlc_um::reassemble_rx_sdus()
{
if(!rx_sdu)
if(!rx_sdu) {
rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
return;
}
}
// First catch up with lower edge of reordering window
while(!inside_reordering_window(vr_ur))
@ -463,6 +479,10 @@ void rlc_um::reassemble_rx_sdus()
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
return;
}
}
pdu_lost = false;
}
@ -483,6 +503,10 @@ void rlc_um::reassemble_rx_sdus()
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
return;
}
}
pdu_lost = false;
}
@ -517,6 +541,10 @@ void rlc_um::reassemble_rx_sdus()
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
return;
}
}
pdu_lost = false;
}
@ -546,6 +574,10 @@ void rlc_um::reassemble_rx_sdus()
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
return;
}
}
pdu_lost = false;
}

@ -64,7 +64,43 @@ private:
pthread_mutex_t mutex;
};
int main(int argc, char **argv) {
int timer_thread_test()
{
bool result;
uint32_t id = 0;
uint32_t duration_msec = 5;
uint32_t result_tolerance = 1;
callback c;
timeout t;
gettimeofday(&c.start_time[1], NULL);
t.start(duration_msec);
while (t.is_running() && !t.expired()) {
printf("time to expire=%dms\n", t.get_msec_to_expire());
usleep(1000);
}
gettimeofday(&c.start_time[2], NULL);
get_time_interval(c.start_time);
uint32_t diff_ms = c.start_time[0].tv_usec*1e-3;
printf("Target duration: %dms, started: %ld:%ld, ended: %ld:%ld, actual duration %dms\n",
duration_msec, c.start_time[1].tv_sec, c.start_time[1].tv_usec, c.start_time[2].tv_sec, c.start_time[2].tv_usec, diff_ms);
result = ((duration_msec - result_tolerance) < diff_ms || diff_ms < (duration_msec + result_tolerance));
if(result) {
printf("Timer thread test passed\n");
return 0;
}else{
return -1;
}
}
int single_thread_test()
{
bool result;
uint32_t id = 0;
uint32_t duration_msec = 5;
@ -84,10 +120,25 @@ int main(int argc, char **argv) {
result = (diff_ms == duration_msec);
if(result) {
printf("Passed\n");
exit(0);
printf("Single thread test passed\n");
return 0;
}else{
printf("Failed\n;");
exit(1);
return -1;
}
}
int main(int argc, char **argv)
{
if (single_thread_test()) {
printf("Single thread test failed.\n");
return -1;
}
if (timer_thread_test()) {
printf("Timer thread test failed.\n");
return -1;
}
return 0;
}

@ -31,7 +31,8 @@ target_link_libraries(rlc_am_test srslte_upper srslte_phy srslte_common)
add_test(rlc_am_test rlc_am_test)
add_executable(rlc_am_stress_test rlc_am_stress_test.cc)
target_link_libraries(rlc_am_stress_test srslte_upper srslte_phy srslte_common)
target_link_libraries(rlc_am_stress_test srslte_upper srslte_phy srslte_common ${Boost_LIBRARIES})
add_test(rlc_am_stress_test rlc_am_stress_test --duration 10)
add_executable(rlc_um_data_test rlc_um_data_test.cc)
target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common)

@ -31,23 +31,77 @@
#include "srslte/common/logger_stdout.h"
#include "srslte/common/threads.h"
#include "srslte/upper/rlc.h"
#include <boost/program_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <assert.h>
#define NBUFS 5
using namespace std;
using namespace srsue;
using namespace srslte;
namespace bpo = boost::program_options;
typedef struct {
uint32_t test_duration_sec;
float error_rate;
uint32_t sdu_gen_delay_usec;
uint32_t pdu_tx_delay_usec;
bool reestablish;
uint32_t log_level;
} stress_test_args_t;
void parse_args(stress_test_args_t *args, int argc, char *argv[]) {
// Command line only options
bpo::options_description general("General options");
general.add_options()
("help,h", "Produce help message")
("version,v", "Print version information and exit");
// Command line or config file options
bpo::options_description common("Configuration options");
common.add_options()
("duration", bpo::value<uint32_t>(&args->test_duration_sec)->default_value(10), "Duration (sec)")
("sdu_gen_delay", bpo::value<uint32_t>(&args->sdu_gen_delay_usec)->default_value(10), "SDU generation delay (usec)")
("pdu_tx_delay", bpo::value<uint32_t>(&args->pdu_tx_delay_usec)->default_value(10), "Delay in MAC for transfering PDU from tx'ing RLC to rx'ing RLC (usec)")
("error_rate", bpo::value<float>(&args->error_rate)->default_value(0.1), "Rate at which RLC PDUs are dropped")
("reestablish", bpo::value<bool>(&args->reestablish)->default_value(false), "Mimic RLC reestablish during execution")
("loglevel", bpo::value<uint32_t>(&args->log_level)->default_value(srslte::LOG_LEVEL_DEBUG), "Log level (1=Error,2=Warning,3=Info,4=Debug");
// these options are allowed on the command line
bpo::options_description cmdline_options;
cmdline_options.add(common).add(general);
// parse the command line and store result in vm
bpo::variables_map vm;
bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).run(), vm);
bpo::notify(vm);
// help option was given - print usage and exit
if (vm.count("help")) {
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
cout << common << endl << general << endl;
exit(0);
}
if (args->log_level > 4) {
args->log_level = 4;
printf("Set log level to %d (%s)\n", args->log_level, srslte::log_level_text[args->log_level]);
}
}
class mac_reader
:public thread
{
public:
mac_reader(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_)
mac_reader(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, uint32_t pdu_tx_delay_usec_)
{
rlc1 = rlc1_;
rlc2 = rlc2_;
fail_rate = fail_rate_;
run_enable = true;
running = false;
pdu_tx_delay_usec = pdu_tx_delay_usec_;
}
void stop()
@ -82,14 +136,16 @@ private:
if(((float)rand()/RAND_MAX > fail_rate) && read>0) {
rlc2->write_pdu(1, pdu->msg, opp_size);
}
usleep(1000);
usleep(pdu_tx_delay_usec);
}
running = false;
byte_buffer_pool::get_instance()->deallocate(pdu);
}
rlc_interface_mac *rlc1;
rlc_interface_mac *rlc2;
float fail_rate;
uint32_t pdu_tx_delay_usec;
bool run_enable;
bool running;
@ -99,9 +155,9 @@ class mac_dummy
:public srslte::mac_interface_timers
{
public:
mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_)
:r1(rlc1_, rlc2_, fail_rate_)
,r2(rlc2_, rlc1_, fail_rate_)
mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, uint32_t pdu_tx_delay)
:r1(rlc1_, rlc2_, fail_rate_, pdu_tx_delay)
,r2(rlc2_, rlc1_, fail_rate_, pdu_tx_delay)
{
}
@ -139,10 +195,13 @@ class rlc_am_tester
,public thread
{
public:
rlc_am_tester(rlc_interface_pdcp *rlc_){
rlc_am_tester(rlc_interface_pdcp *rlc_, std::string name_, uint32_t sdu_gen_delay_usec_){
rlc = rlc_;
run_enable = true;
running = false;
rx_pdus = 0;
name = name_;
sdu_gen_delay_usec = sdu_gen_delay_usec_;
}
void stop()
@ -164,6 +223,7 @@ public:
{
assert(lcid == 1);
byte_buffer_pool::get_instance()->deallocate(sdu);
std::cout << "rlc_am_tester " << name << " received " << rx_pdus++ << " PDUs" << std::endl;
}
void write_pdu_bcch_bch(byte_buffer_t *sdu) {}
void write_pdu_bcch_dlsch(byte_buffer_t *sdu) {}
@ -187,38 +247,41 @@ private:
pdu->N_bytes = 1500;
pdu->msg[0] = sn++;
rlc->write_sdu(1, pdu);
usleep(1000);
usleep(sdu_gen_delay_usec);
}
running = false;
}
bool run_enable;
bool running;
long rx_pdus;
std::string name;
uint32_t sdu_gen_delay_usec;
rlc_interface_pdcp *rlc;
};
void stress_test()
void stress_test(stress_test_args_t args)
{
srslte::log_filter log1("RLC_AM_1");
srslte::log_filter log2("RLC_AM_2");
log1.set_level(srslte::LOG_LEVEL_DEBUG);
log2.set_level(srslte::LOG_LEVEL_DEBUG);
log1.set_level((LOG_LEVEL_ENUM)args.log_level);
log2.set_level((LOG_LEVEL_ENUM)args.log_level);
log1.set_hex_limit(-1);
log2.set_hex_limit(-1);
float fail_rate = 0.1;
rlc rlc1;
rlc rlc2;
rlc_am_tester tester1(&rlc1);
rlc_am_tester tester2(&rlc2);
mac_dummy mac(&rlc1, &rlc2, fail_rate);
rlc_am_tester tester1(&rlc1, "tester1", args.sdu_gen_delay_usec);
rlc_am_tester tester2(&rlc2, "tester2", args.sdu_gen_delay_usec);
mac_dummy mac(&rlc1, &rlc2, args.error_rate, args.pdu_tx_delay_usec);
ue_interface ue;
rlc1.init(&tester1, &tester1, &ue, &log1, &mac, 0);
rlc2.init(&tester1, &tester1, &ue, &log2, &mac, 0);
rlc2.init(&tester2, &tester2, &ue, &log2, &mac, 0);
LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg;
cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM;
@ -235,10 +298,17 @@ void stress_test()
rlc2.add_bearer(1, cnfg_);
tester1.start(7);
//tester2.start(7);
tester2.start(7);
mac.start();
usleep(100e6);
for (uint32_t i = 0; i < args.test_duration_sec; i++) {
// if enabled, mimic reestablishment every second
if (args.reestablish) {
rlc1.reestablish();
rlc2.reestablish();
}
usleep(1e6);
}
tester1.stop();
tester2.stop();
@ -247,6 +317,9 @@ void stress_test()
int main(int argc, char **argv) {
stress_test();
stress_test_args_t args;
parse_args(&args, argc, argv);
stress_test(args);
byte_buffer_pool::get_instance()->cleanup();
}

@ -59,6 +59,14 @@ public:
n_sdus = 0;
}
~rlc_am_tester(){
for (uint32_t i = 0; i < 10; i++) {
if (sdus[i] != NULL) {
byte_buffer_pool::get_instance()->deallocate(sdus[i]);
}
}
}
// PDCP interface
void write_pdu(uint32_t lcid, byte_buffer_t *sdu)
{
@ -482,17 +490,17 @@ void resegment_test_1()
// Read the retx PDU from RLC1 and force resegmentation
byte_buffer_t retx1;
len = rlc1.read_pdu(retx1.msg, 11); // 4 byte header + 5 data
len = rlc1.read_pdu(retx1.msg, 9); // 4 byte header + 5 data
retx1.N_bytes = len;
// Write the retx PDU to RLC2
rlc2.write_pdu(retx1.msg, retx1.N_bytes);
assert(9 == rlc1.get_buffer_state()); // 4 byte header + 5 data
assert(9 == rlc1.get_buffer_state());
// Read the remaining segment
byte_buffer_t retx2;
len = rlc1.read_pdu(retx2.msg, 11); // 4 byte header + 5 data
len = rlc1.read_pdu(retx2.msg, 9); // 4 byte header + 5 data
retx2.N_bytes = len;
// Write the retx PDU to RLC2
@ -591,16 +599,16 @@ void resegment_test_2()
// Read the retx PDU from RLC1 and force resegmentation
byte_buffer_t retx1;
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 18); // 6 byte header + 10 data
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 16); // 6 byte header + 10 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx1.msg, retx1.N_bytes);
assert(16 == rlc1.get_buffer_state()); // 6 byte header + 10 data
assert(16 == rlc1.get_buffer_state());
// Read the remaining segment
byte_buffer_t retx2;
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 18); // 6 byte header + 10 data
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 16); // 6 byte header + 10 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx2.msg, retx2.N_bytes);
@ -696,14 +704,14 @@ void resegment_test_3()
// Read the retx PDU from RLC1 and force resegmentation
byte_buffer_t retx1;
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 16); // 4 byte header + 10 data
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 14); // 4 byte header + 10 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx1.msg, retx1.N_bytes);
// Read the remaining segment
byte_buffer_t retx2;
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 16); // 4 byte header + 10 data
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 14); // 4 byte header + 10 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx2.msg, retx2.N_bytes);
@ -799,14 +807,14 @@ void resegment_test_4()
// Read the retx PDU from RLC1 and force resegmentation
byte_buffer_t retx1;
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 23); // 6 byte header + 15 data
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 21); // 6 byte header + 15 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx1.msg, retx1.N_bytes);
// Read the remaining segment
byte_buffer_t retx2;
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 23); // 6 byte header + 15 data
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 21); // 6 byte header + 15 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx2.msg, retx2.N_bytes);
@ -902,14 +910,14 @@ void resegment_test_5()
// Read the retx PDU from RLC1 and force resegmentation
byte_buffer_t retx1;
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 29); // 7 byte header + 20 data
retx1.N_bytes = rlc1.read_pdu(retx1.msg, 27); // 7 byte header + 20 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx1.msg, retx1.N_bytes);
// Read the remaining segment
byte_buffer_t retx2;
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 29); // 7 byte header + 20 data
retx2.N_bytes = rlc1.read_pdu(retx2.msg, 27); // 7 byte header + 20 data
// Write the retx PDU to RLC2
rlc2.write_pdu(retx2.msg, retx2.N_bytes);
@ -1023,11 +1031,11 @@ void resegment_test_6()
// Write the retx PDU to RLC2
rlc2.write_pdu(retx1.msg, retx1.N_bytes);
assert(157 == rlc1.get_buffer_state());
assert(155 == rlc1.get_buffer_state());
// Read the remaining segment
byte_buffer_t retx2;
len = rlc1.read_pdu(retx2.msg, 159);
len = rlc1.read_pdu(retx2.msg, 157);
retx2.N_bytes = len;
// Write the retx PDU to RLC2
@ -1048,24 +1056,91 @@ void resegment_test_6()
}
}
void reset_test()
{
srslte::log_filter log1("RLC_AM_1");
srslte::log_filter log2("RLC_AM_2");
log1.set_level(srslte::LOG_LEVEL_DEBUG);
log2.set_level(srslte::LOG_LEVEL_DEBUG);
log1.set_hex_limit(-1);
log2.set_hex_limit(-1);
rlc_am_tester tester;
mac_dummy_timers timers;
rlc_am rlc1;
int len;
log1.set_level(srslte::LOG_LEVEL_DEBUG);
rlc1.init(&log1, 1, &tester, &tester, &timers);
LIBLTE_RRC_RLC_CONFIG_STRUCT cnfg;
cnfg.rlc_mode = LIBLTE_RRC_RLC_MODE_AM;
cnfg.dl_am_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS5;
cnfg.dl_am_rlc.t_status_prohibit = LIBLTE_RRC_T_STATUS_PROHIBIT_MS5;
cnfg.ul_am_rlc.max_retx_thresh = LIBLTE_RRC_MAX_RETX_THRESHOLD_T4;
cnfg.ul_am_rlc.poll_byte = LIBLTE_RRC_POLL_BYTE_KB25;
cnfg.ul_am_rlc.poll_pdu = LIBLTE_RRC_POLL_PDU_P4;
cnfg.ul_am_rlc.t_poll_retx = LIBLTE_RRC_T_POLL_RETRANSMIT_MS5;
rlc1.configure(&cnfg);
// Push 1 SDU of size 10 into RLC1
byte_buffer_t sdu_buf;
*sdu_buf.msg = 1; // Write the index into the buffer
sdu_buf.N_bytes = 100;
rlc1.write_sdu(&sdu_buf);
// read 1 PDU from RLC1 and force segmentation
byte_buffer_t pdu_bufs;
len = rlc1.read_pdu(pdu_bufs.msg, 4);
pdu_bufs.N_bytes = len;
// reset RLC1
rlc1.reset();
// read another PDU segment from RLC1
len = rlc1.read_pdu(pdu_bufs.msg, 4);
pdu_bufs.N_bytes = len;
// now empty RLC buffer
len = rlc1.read_pdu(pdu_bufs.msg, 100);
pdu_bufs.N_bytes = len;
assert(0 == rlc1.get_buffer_state());
}
int main(int argc, char **argv) {
basic_test();
byte_buffer_pool::get_instance()->cleanup();
concat_test();
byte_buffer_pool::get_instance()->cleanup();
segment_test();
byte_buffer_pool::get_instance()->cleanup();
retx_test();
byte_buffer_pool::get_instance()->cleanup();
resegment_test_1();
byte_buffer_pool::get_instance()->cleanup();
resegment_test_2();
byte_buffer_pool::get_instance()->cleanup();
resegment_test_3();
byte_buffer_pool::get_instance()->cleanup();
resegment_test_4();
byte_buffer_pool::get_instance()->cleanup();
resegment_test_5();
byte_buffer_pool::get_instance()->cleanup();
resegment_test_6();
byte_buffer_pool::get_instance()->cleanup();
reset_test();
byte_buffer_pool::get_instance()->cleanup();
}

@ -62,6 +62,14 @@ public:
n_sdus = 0;
}
~rlc_um_tester(){
for (uint32_t i = 0; i < NBUFS; i++) {
if (sdus[i] != NULL) {
byte_buffer_pool::get_instance()->deallocate(sdus[i]);
}
}
}
// PDCP interface
void write_pdu(uint32_t lcid, byte_buffer_t *sdu)
{

@ -13,6 +13,8 @@
# mme_addr: IP address of MME for S1 connnection
# gtp_bind_addr: Local IP address to bind for GTP connection
# n_prb: Number of Physical Resource Blocks (6,15,25,50,75,100)
# tm: Transmission mode 1-4 (TM1 default)
# nof_ports: Number of Tx ports (1 port default, set to 2 for TM2/3/4)
#
#####################################################################
[enb]
@ -25,6 +27,9 @@ mnc = 01
mme_addr = 127.0.1.100
gtp_bind_addr = 127.0.0.1
n_prb = 50
#tm = 4
#nof_ports = 2
#####################################################################
# eNB configuration files

@ -188,7 +188,7 @@ private:
srslte::logger *logger;
srslte::log_filter rf_log;
std::vector<void*> phy_log;
std::vector<srslte::log_filter*> phy_log;
srslte::log_filter mac_log;
srslte::log_filter rlc_log;
srslte::log_filter pdcp_log;

@ -217,7 +217,7 @@ private:
bool configured;
pthread_mutex_t mutex;
pthread_mutex_t mutex, mutex2;
};

@ -28,6 +28,7 @@
#define ENBPHY_H
#include "srslte/common/log.h"
#include "srslte/common/log_filter.h"
#include "phy/txrx.h"
#include "phy/phch_worker.h"
#include "phy/phch_common.h"
@ -54,8 +55,8 @@ class phy : public phy_interface_mac,
public:
phy();
bool init(phy_args_t *args, phy_cfg_t *common_cfg, srslte::radio *radio_handler, mac_interface_phy *mac, srslte::log* log_h);
bool init(phy_args_t *args, phy_cfg_t *common_cfg, srslte::radio *radio_handler, mac_interface_phy *mac, std::vector<void*> log_vec);
bool init(phy_args_t *args, phy_cfg_t *common_cfg, srslte::radio *radio_handler, mac_interface_phy *mac, srslte::log_filter* log_h);
bool init(phy_args_t *args, phy_cfg_t *common_cfg, srslte::radio *radio_handler, mac_interface_phy *mac, std::vector<srslte::log_filter *> log_vec);
void stop();
/* MAC->PHY interface */

@ -25,33 +25,33 @@
*/
#include <boost/algorithm/string.hpp>
#include <boost/thread/mutex.hpp>
#include <enb.h>
#include "enb.h"
namespace srsenb {
enb* enb::instance = NULL;
boost::mutex enb_instance_mutex;
pthread_mutex_t enb_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
enb* enb::get_instance(void)
{
boost::mutex::scoped_lock lock(enb_instance_mutex);
pthread_mutex_lock(&enb_instance_mutex);
if(NULL == instance) {
instance = new enb();
}
pthread_mutex_unlock(&enb_instance_mutex);
return(instance);
}
void enb::cleanup(void)
{
srslte_dft_exit();
srslte::byte_buffer_pool::cleanup();
boost::mutex::scoped_lock lock(enb_instance_mutex);
pthread_mutex_lock(&enb_instance_mutex);
if(NULL != instance) {
delete instance;
instance = NULL;
}
pthread_mutex_unlock(&enb_instance_mutex);
}
enb::enb() : started(false) {
@ -66,6 +66,9 @@ enb::enb() : started(false) {
enb::~enb()
{
for (uint32_t i = 0; i < phy_log.size(); i++) {
delete (phy_log[i]);
}
}
bool enb::init(all_args_t *args_)
@ -88,7 +91,7 @@ bool enb::init(all_args_t *args_)
char tmp[16];
sprintf(tmp, "PHY%d",i);
mylog->init(tmp, logger, true);
phy_log.push_back((void*) mylog);
phy_log.push_back(mylog);
}
mac_log.init("MAC ", logger, true);
rlc_log.init("RLC ", logger);
@ -294,7 +297,7 @@ void enb::handle_rf_msg(srslte_rf_error_t error)
str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
str.erase(std::remove(str.begin(), str.end(), '\r'), str.end());
str.push_back('\n');
rf_log.info(str);
rf_log.info(str.c_str());
}
}

@ -1072,7 +1072,9 @@ int field_qci::parse(libconfig::Setting &root)
parser::field_enum_num<LIBLTE_RRC_SN_FIELD_LENGTH_ENUM,uint8> sn_field_len
("sn_field_length", &rlc_cfg->sn_field_len,
liblte_rrc_sn_field_length_num, LIBLTE_RRC_SN_FIELD_LENGTH_N_ITEMS);
sn_field_len.parse(q["rlc_config"]["ul_um"]);
if (sn_field_len.parse(q["rlc_config"]["ul_um"])) {
fprintf(stderr, "Error can't find sn_field_length in section ul_um\n");
}
}
if (q["rlc_config"].exists("dl_um")) {
@ -1085,12 +1087,16 @@ int field_qci::parse(libconfig::Setting &root)
parser::field_enum_num<LIBLTE_RRC_SN_FIELD_LENGTH_ENUM,uint8> sn_field_len
("sn_field_length", &rlc_cfg->sn_field_len,
liblte_rrc_sn_field_length_num, LIBLTE_RRC_SN_FIELD_LENGTH_N_ITEMS);
sn_field_len.parse(q["rlc_config"]["dl_um"]);
if (sn_field_len.parse(q["rlc_config"]["dl_um"])) {
fprintf(stderr, "Error can't find sn_field_length in section dl_um\n");
}
parser::field_enum_num<LIBLTE_RRC_T_REORDERING_ENUM,int32> t_reordering
("t_reordering", &rlc_cfg->t_reordering,
liblte_rrc_t_reordering_num, LIBLTE_RRC_T_REORDERING_N_ITEMS);
t_reordering.parse(q["rlc_config"]["dl_um"]);
if (t_reordering.parse(q["rlc_config"]["dl_um"])) {
fprintf(stderr, "Error can't find t_reordering in section dl_um\n");
}
}
// Parse RLC-AM section
@ -1100,22 +1106,30 @@ int field_qci::parse(libconfig::Setting &root)
parser::field_enum_num<LIBLTE_RRC_T_POLL_RETRANSMIT_ENUM,int32> t_poll_retx
("t_poll_retx", &rlc_cfg->t_poll_retx,
liblte_rrc_t_poll_retransmit_num, LIBLTE_RRC_T_POLL_RETRANSMIT_N_ITEMS);
t_poll_retx.parse(q["rlc_config"]["ul_am"]);
if (t_poll_retx.parse(q["rlc_config"]["ul_am"])) {
fprintf(stderr, "Error can't find t_poll_retx in section ul_am\n");
}
parser::field_enum_num<LIBLTE_RRC_POLL_PDU_ENUM,int32> poll_pdu
("poll_pdu", &rlc_cfg->poll_pdu,
liblte_rrc_poll_pdu_num, LIBLTE_RRC_POLL_PDU_N_ITEMS);
poll_pdu.parse(q["rlc_config"]["ul_am"]);
if (poll_pdu.parse(q["rlc_config"]["ul_am"])) {
fprintf(stderr, "Error can't find poll_pdu in section ul_am\n");
}
parser::field_enum_num<LIBLTE_RRC_POLL_BYTE_ENUM,int32> poll_byte
("poll_byte", &rlc_cfg->poll_byte,
liblte_rrc_poll_byte_num, LIBLTE_RRC_POLL_BYTE_N_ITEMS);
poll_byte.parse(q["rlc_config"]["ul_am"]);
if (poll_byte.parse(q["rlc_config"]["ul_am"])) {
fprintf(stderr, "Error can't find poll_byte in section ul_am\n");
}
parser::field_enum_num<LIBLTE_RRC_MAX_RETX_THRESHOLD_ENUM,uint32_t> max_retx_thresh
("max_retx_thresh", &rlc_cfg->max_retx_thresh,
liblte_rrc_max_retx_threshold_num, LIBLTE_RRC_MAX_RETX_THRESHOLD_N_ITEMS);
max_retx_thresh.parse(q["rlc_config"]["ul_am"]);
if (max_retx_thresh.parse(q["rlc_config"]["ul_am"])) {
fprintf(stderr, "Error can't find max_retx_thresh in section ul_am\n");
}
}
if (q["rlc_config"].exists("dl_am")) {
@ -1124,12 +1138,16 @@ int field_qci::parse(libconfig::Setting &root)
parser::field_enum_num<LIBLTE_RRC_T_REORDERING_ENUM,int32> t_reordering
("t_reordering", &rlc_cfg->t_reordering,
liblte_rrc_t_reordering_num, LIBLTE_RRC_T_REORDERING_N_ITEMS);
t_reordering.parse(q["rlc_config"]["dl_am"]);
if (t_reordering.parse(q["rlc_config"]["dl_am"])) {
fprintf(stderr, "Error can't find t_reordering in section dl_am\n");
}
parser::field_enum_num<LIBLTE_RRC_T_STATUS_PROHIBIT_ENUM,int32> t_status_prohibit
("t_status_prohibit", &rlc_cfg->t_status_prohibit,
liblte_rrc_t_status_prohibit_num, LIBLTE_RRC_T_STATUS_PROHIBIT_N_ITEMS);
t_status_prohibit.parse(q["rlc_config"]["dl_am"]);
if (t_status_prohibit.parse(q["rlc_config"]["dl_am"])) {
fprintf(stderr, "Error can't find t_status_prohibit in section dl_am\n");
}
}
@ -1141,17 +1159,23 @@ int field_qci::parse(libconfig::Setting &root)
LIBLTE_RRC_UL_SPECIFIC_PARAMETERS_STRUCT *lc_cfg = &cfg[qci].lc_cfg;
parser::field<uint8> priority ("priority", &lc_cfg->priority);
priority.parse(q["logical_channel_config"]);
if (priority.parse(q["logical_channel_config"])) {
fprintf(stderr, "Error can't find logical_channel_config in section priority\n");
}
parser::field_enum_num<LIBLTE_RRC_PRIORITIZED_BIT_RATE_ENUM,int32> prioritized_bit_rate
("prioritized_bit_rate", &lc_cfg->prioritized_bit_rate,
liblte_rrc_prioritized_bit_rate_num, LIBLTE_RRC_PRIORITIZED_BIT_RATE_N_ITEMS);
prioritized_bit_rate.parse(q["logical_channel_config"]);
if (prioritized_bit_rate.parse(q["logical_channel_config"])) {
fprintf(stderr, "Error can't find prioritized_bit_rate in section logical_channel_config\n");
}
parser::field_enum_num<LIBLTE_RRC_BUCKET_SIZE_DURATION_ENUM,int16> bucket_size_duration
("bucket_size_duration", &lc_cfg->bucket_size_duration,
liblte_rrc_bucket_size_duration_num, LIBLTE_RRC_BUCKET_SIZE_DURATION_N_ITEMS);
bucket_size_duration.parse(q["logical_channel_config"]);
if (bucket_size_duration.parse(q["logical_channel_config"])) {
fprintf(stderr, "Error can't find bucket_size_duration in section logical_channel_config\n");
}
parser::field<uint8> log_chan_group ("log_chan_group", &lc_cfg->log_chan_group);
if (log_chan_group.parse(q["logical_channel_config"])) {

@ -1,3 +1,28 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <string.h>
@ -39,6 +64,7 @@ sched::sched() : bc_aggr_level(0), rar_aggr_level(0), avail_rbg(0), P(0), start_
}
pthread_mutex_init(&mutex, NULL);
pthread_mutex_init(&mutex2, NULL);
reset();
}
@ -46,6 +72,7 @@ sched::~sched()
{
srslte_regs_free(&regs);
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&mutex2);
}
void sched::init(rrc_interface_mac *rrc_, srslte::log* log)
@ -148,6 +175,7 @@ int sched::ue_cfg(uint16_t rnti, sched_interface::ue_cfg_t *ue_cfg)
int sched::ue_rem(uint16_t rnti)
{
pthread_mutex_lock(&mutex);
pthread_mutex_lock(&mutex2);
int ret = 0;
if (ue_db.count(rnti)) {
ue_db.erase(rnti);
@ -155,6 +183,7 @@ int sched::ue_rem(uint16_t rnti)
Error("User rnti=0x%x not found\n", rnti);
ret = -1;
}
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex);
return ret;
}
@ -192,6 +221,7 @@ int sched::bearer_ue_cfg(uint16_t rnti, uint32_t lc_id, sched_interface::ue_bear
int sched::bearer_ue_rem(uint16_t rnti, uint32_t lc_id)
{
pthread_mutex_lock(&mutex);
pthread_mutex_lock(&mutex2);
int ret = 0;
if (ue_db.count(rnti)) {
ue_db[rnti].rem_bearer(lc_id);
@ -199,6 +229,7 @@ int sched::bearer_ue_rem(uint16_t rnti, uint32_t lc_id)
Error("User rnti=0x%x not found\n", rnti);
ret = -1;
}
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex);
return ret;
}
@ -229,9 +260,18 @@ uint32_t sched::get_ul_buffer(uint16_t rnti)
return ret;
}
/* \Warning: This function is not mutexed because it can produce late changes on the buffer state while
* the scheduler is already allocating data, resulting in empty grants.
* Ideally we would like the scheduler to query the RLC for buffer states in order to get the most updated
* buffer state with the minimum overhead. However, the current architecture is designed to be compliant
* with the FAPI interface
*
* We add a new mutex used only in ue_rem to avoid the UE being removed in between the access to
* ue_db.count() and the access to the std::map.
*/
int sched::dl_rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue)
{
pthread_mutex_lock(&mutex);
pthread_mutex_lock(&mutex2);
int ret = 0;
if (ue_db.count(rnti)) {
ue_db[rnti].dl_buffer_state(lc_id, tx_queue, retx_queue);
@ -239,13 +279,14 @@ int sched::dl_rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue,
Error("User rnti=0x%x not found\n", rnti);
ret = -1;
}
pthread_mutex_unlock(&mutex);
pthread_mutex_unlock(&mutex2);
return ret;
}
/* \Warning Read comment in dl_rlc_buffer_state() */
int sched::dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code)
{
pthread_mutex_lock(&mutex);
pthread_mutex_lock(&mutex2);
int ret = 0;
if (ue_db.count(rnti)) {
ue_db[rnti].mac_buffer_state(ce_code);
@ -253,7 +294,7 @@ int sched::dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code)
Error("User rnti=0x%x not found\n", rnti);
ret = -1;
}
pthread_mutex_unlock(&mutex);
pthread_mutex_unlock(&mutex2);
return ret;
}
@ -654,6 +695,7 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST])
sched_ue *user = (sched_ue*) &iter->second;
uint16_t rnti = (uint16_t) iter->first;
uint32_t data_before = user->get_pending_dl_new_data(current_tti);
dl_harq_proc *h = dl_metric->get_user_allocation(user);
srslte_dci_format_t dci_format = user->get_dci_format();
data[nof_data_elems].dci_format = dci_format;
@ -681,10 +723,12 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST])
Error("DCI format (%d) not implemented\n", dci_format);
}
if (tbs > 0) {
log_h->info("SCHED: DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, n_rtx=%d, tbs=%d, buffer=%d, tb_en={%s,%s}\n",
log_h->info("SCHED: DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, n_rtx=%d, tbs=%d, buffer=%d/%d, tb_en={%s,%s}\n",
!is_newtx?"retx":"tx", rnti, h->get_id(), h->get_rbgmask(),
data[nof_data_elems].dci_location.L, data[nof_data_elems].dci_location.ncce, h->nof_retx(0) + h->nof_retx(1),
tbs, user->get_pending_dl_new_data(current_tti), data[nof_data_elems].dci.tb_en[0]?"y":"n",
tbs,
data_before, user->get_pending_dl_new_data(current_tti),
data[nof_data_elems].dci.tb_en[0]?"y":"n",
data[nof_data_elems].dci.tb_en[1]?"y":"n");
nof_data_elems++;
} else {

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

Loading…
Cancel
Save