Merge branch 'next_novolk' into mobility

master
Ismael Gomez 7 years ago
commit 72446fb9ef

@ -1,6 +1,11 @@
Change Log for Releases Change Log for Releases
============================== ==============================
## 17.09
* Added MIMO 2x2 in the PHY layer and srsUE (i.e. TM3/TM4)
* eMBMS support in the PHY layer
* Many bug-fixes and improved stability and performance in srsUE/srsENB
## 002.000.000 ## 002.000.000
* Added fully functional srsENB to srsLTE code * Added fully functional srsENB to srsLTE code
* Merged srsUE code into srsLTE and reestructured PHY code * Merged srsUE code into srsLTE and reestructured PHY code

@ -282,6 +282,11 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
endif(HAVE_AVX) endif(HAVE_AVX)
endif (HAVE_AVX2) endif (HAVE_AVX2)
if (HAVE_AVX512)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx512f -mavx512cd -DLV_HAVE_AVX512")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx512f -mavx512cd -DLV_HAVE_AVX512")
endif(HAVE_AVX512)
if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
if(HAVE_SSE) if(HAVE_SSE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Ofast -funroll-loops") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Ofast -funroll-loops")

@ -15,12 +15,13 @@ srsLTE is released under the AGPLv3 license and uses software from the OpenLTE p
Common Features Common Features
--------------- ---------------
* LTE Release 8 compliant * LTE Release 8 compliant (with selected features of Release 9)
* FDD configuration * FDD configuration
* Tested bandwidths: 1.4, 3, 5, 10, 15 and 20 MHz * Tested bandwidths: 1.4, 3, 5, 10, 15 and 20 MHz
* Transmission mode 1 (single antenna) and 2 (transmit diversity) * Transmission mode 1 (single antenna), 2 (transmit diversity), 3 (CCD) and 4 (closed-loop spatial multiplexing)
* Frequency-based ZF and MMSE equalizer * Frequency-based ZF and MMSE equalizer
* Highly optimized Turbo Decoder available in Intel SSE4.1/AVX (+100 Mbps) and standard C (+25 Mbps) * Evolved multimedia broadcast and multicast service (eMBMS)
* Highly optimized Turbo Decoder available in Intel SSE4.1/AVX2 (+100 Mbps) and standard C (+25 Mbps)
* MAC, RLC, PDCP, RRC, NAS, S1AP and GW layers * MAC, RLC, PDCP, RRC, NAS, S1AP and GW layers
* Detailed log system with per-layer log levels and hex dumps * Detailed log system with per-layer log levels and hex dumps
* MAC layer wireshark packet capture * MAC layer wireshark packet capture
@ -33,6 +34,7 @@ srsUE Features
* Cell search and synchronization procedure for the UE * Cell search and synchronization procedure for the UE
* Soft USIM supporting Milenage and XOR authentication * Soft USIM supporting Milenage and XOR authentication
* Virtual network interface *tun_srsue* created upon network attach * Virtual network interface *tun_srsue* created upon network attach
* +100 Mbps DL in 20 MHz MIMO TM4 configuration in i7 Quad-Core CPU.
* 75 Mbps DL in 20 MHz SISO configuration in i7 Quad-Core CPU. * 75 Mbps DL in 20 MHz SISO configuration in i7 Quad-Core CPU.
* 36 Mbps DL in 10 MHz SISO configuration in i5 Dual-Core CPU. * 36 Mbps DL in 10 MHz SISO configuration in i5 Dual-Core CPU.
@ -55,6 +57,8 @@ srsENB has been tested and validated with the following handsets:
* LG Nexus 5 * LG Nexus 5
* LG Nexus 4 * LG Nexus 4
* Motorola Moto G4 plus * Motorola Moto G4 plus
* Huawei P9/P9lite
* Huawei dongles: E3276 and E398
Hardware Hardware
-------- --------
@ -65,7 +69,7 @@ We have tested the following hardware:
* USRP B210 * USRP B210
* USRP X300 * USRP X300
* bladeRF * bladeRF
* limeSDR * limeSDR (currently, only the PHY-layer examples, i.e., pdsch_enodeb/ue are supported)
Build Instructions Build Instructions
------------------ ------------------

@ -8,6 +8,7 @@ option(ENABLE_SSE "Enable compile-time SSE4.1 support." ON)
option(ENABLE_AVX "Enable compile-time AVX support." ON) option(ENABLE_AVX "Enable compile-time AVX support." ON)
option(ENABLE_AVX2 "Enable compile-time AVX2 support." ON) option(ENABLE_AVX2 "Enable compile-time AVX2 support." ON)
option(ENABLE_FMA "Enable compile-time FMA support." ON) option(ENABLE_FMA "Enable compile-time FMA support." ON)
option(ENABLE_AVX512 "Enable compile-time AVX512 support." ON)
if (ENABLE_SSE) if (ENABLE_SSE)
# #
@ -135,6 +136,41 @@ if (ENABLE_SSE)
endif() endif()
endif() endif()
if (ENABLE_AVX512)
#
# Check compiler for AVX intrinsics
#
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG )
set(CMAKE_REQUIRED_FLAGS "-mavx512f")
check_c_source_runs("
#include <immintrin.h>
int main()
{
__m512i a, b, c;
const int src[16] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 , 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF};
int dst[16];
a = _mm512_loadu_si512( (__m512i*)src );
b = _mm512_loadu_si512( (__m512i*)src );
c = _mm512_add_epi32( a, b );
_mm512_storeu_si512( (__m512i*)dst, c );
int i = 0;
for( i = 0; i < 16; i++ ){
if( ( src[i] + src[i] ) != dst[i] ){
return -1;
}
}
return 0;
}"
HAVE_AVX512)
endif()
if (HAVE_AVX512)
message(STATUS "AVX512 is enabled - target CPU must support it")
endif()
endif()
endif() endif()
mark_as_advanced(HAVE_SSE, HAVE_AVX, HAVE_AVX2, HAVE_FMA) mark_as_advanced(HAVE_SSE, HAVE_AVX, HAVE_AVX2, HAVE_FMA, HAVE_AVX512)

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

@ -320,9 +320,9 @@ void base_init() {
exit(-1); exit(-1);
} }
srslte_ofdm_set_non_mbsfn_region(&ifft_mbsfn, 2); srslte_ofdm_set_non_mbsfn_region(&ifft_mbsfn, 2);
srslte_ofdm_set_normalize(&ifft, true);
srslte_ofdm_set_normalize(&ifft_mbsfn, true); srslte_ofdm_set_normalize(&ifft_mbsfn, true);
srslte_ofdm_set_normalize(&ifft, true);
if (srslte_pbch_init(&pbch)) { if (srslte_pbch_init(&pbch)) {
fprintf(stderr, "Error creating PBCH object\n"); fprintf(stderr, "Error creating PBCH object\n");

@ -99,7 +99,7 @@ typedef struct {
int net_port_signal; int net_port_signal;
char *net_address_signal; char *net_address_signal;
int decimate; int decimate;
int mbsfn_area_id; int32_t mbsfn_area_id;
uint8_t non_mbsfn_region; uint8_t non_mbsfn_region;
int verbose; int verbose;
}prog_args_t; }prog_args_t;
@ -171,8 +171,8 @@ void usage(prog_args_t *args, char *prog) {
printf("\t-S remote UDP address to send input signal [Default %s]\n", args->net_address_signal); printf("\t-S remote UDP address to send input signal [Default %s]\n", args->net_address_signal);
printf("\t-u remote TCP port to send data (-1 does nothing with it) [Default %d]\n", args->net_port); printf("\t-u remote TCP port to send data (-1 does nothing with it) [Default %d]\n", args->net_port);
printf("\t-U remote TCP address to send data [Default %s]\n", args->net_address); printf("\t-U remote TCP address to send data [Default %s]\n", args->net_address);
printf("\t-M MBSFN area id [Default %s]\n", args->mbsfn_area_id); printf("\t-M MBSFN area id [Default %d]\n", args->mbsfn_area_id);
printf("\t-N Non-MBSFN region [Default %s]\n", args->non_mbsfn_region); printf("\t-N Non-MBSFN region [Default %d]\n", args->non_mbsfn_region);
printf("\t-v [set srslte_verbose to debug, default none]\n"); printf("\t-v [set srslte_verbose to debug, default none]\n");
} }

@ -113,7 +113,7 @@ inline bool mnc_to_string(uint16_t mnc, std::string *str)
*str += (mnc & 0x000F) + '0'; *str += (mnc & 0x000F) + '0';
return true; return true;
} }
inline std::string plmn_id_to_c_str(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { inline std::string plmn_id_to_string(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
std::string mcc_str, mnc_str; std::string mcc_str, mnc_str;
mnc_to_string(plmn_id.mnc, &mnc_str); mnc_to_string(plmn_id.mnc, &mnc_str);
mcc_to_string(plmn_id.mcc, &mcc_str); mcc_to_string(plmn_id.mcc, &mcc_str);

@ -44,6 +44,16 @@
#define SRSLTE_N_DRB 8 #define SRSLTE_N_DRB 8
#define SRSLTE_N_RADIO_BEARERS 11 #define SRSLTE_N_RADIO_BEARERS 11
#define HARQ_DELAY_MS 4
#define MSG3_DELAY_MS 2 // Delay added to HARQ_DELAY_MS
#define TTI_TX(tti) ((tti+HARQ_DELAY_MS)%10240)
#define TTI_RX_ACK(tti) ((tti+(2*HARQ_DELAY_MS))%10240)
#define TTIMOD_SZ (((2*HARQ_DELAY_MS) < 10)?10:20)
#define TTIMOD(tti) (tti%TTIMOD_SZ)
#define ASYNC_DL_SCHED (HARQ_DELAY_MS <= 4)
// Cat 3 UE - Max number of DL-SCH transport block bits received within a TTI // Cat 3 UE - Max number of DL-SCH transport block bits received within a TTI
// 3GPP 36.306 Table 4.1.1 // 3GPP 36.306 Table 4.1.1
#define SRSLTE_MAX_BUFFER_SIZE_BITS 102048 #define SRSLTE_MAX_BUFFER_SIZE_BITS 102048

@ -59,5 +59,6 @@
// cf_t definition // cf_t definition
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef _Complex short int c16_t;
#endif // CONFIG_H #endif // CONFIG_H

@ -244,7 +244,7 @@ public:
class gtpu_interface_rrc class gtpu_interface_rrc
{ {
public: public:
virtual void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in) = 0; virtual void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in) = 0;
virtual void rem_bearer(uint16_t rnti, uint32_t lcid) = 0; virtual void rem_bearer(uint16_t rnti, uint32_t lcid) = 0;
virtual void rem_user(uint16_t rnti) = 0; virtual void rem_user(uint16_t rnti) = 0;
}; };

@ -54,6 +54,7 @@ class usim_interface_nas
public: public:
virtual void get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; virtual void get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0;
virtual void get_imei_vec(uint8_t* imei_, uint32_t n) = 0; virtual void get_imei_vec(uint8_t* imei_, uint32_t n) = 0;
virtual int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0;
virtual void generate_authentication_response(uint8_t *rand, virtual void generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
@ -104,6 +105,7 @@ public:
virtual uint32_t get_ul_count() = 0; virtual uint32_t get_ul_count() = 0;
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0; virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0;
virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0; virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0;
virtual void plmn_search_end() = 0;
}; };
// NAS interface for UE // NAS interface for UE
@ -140,6 +142,7 @@ class rrc_interface_phy
public: public:
virtual void in_sync() = 0; virtual void in_sync() = 0;
virtual void out_of_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_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) = 0;
}; };

@ -27,14 +27,8 @@
#ifndef SRSLTE_MAT_H #ifndef SRSLTE_MAT_H
#define SRSLTE_MAT_H #define SRSLTE_MAT_H
#include "srslte/phy/utils/simd.h"
#include "srslte/config.h" #include "srslte/config.h"
#include "srslte/phy/utils/simd.h"
/*
* Generic Macros
*/
#define RANDOM_CF() (((float)rand())/((float)RAND_MAX) + _Complex_I*((float)rand())/((float)RAND_MAX))
/* Generic implementation for complex reciprocal */ /* Generic implementation for complex reciprocal */
SRSLTE_API cf_t srslte_mat_cf_recip_gen(cf_t a); SRSLTE_API cf_t srslte_mat_cf_recip_gen(cf_t a);
@ -66,7 +60,6 @@ SRSLTE_API float srslte_mat_2x2_cn(cf_t h00,
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
#include <smmintrin.h>
/* SSE implementation for complex reciprocal */ /* SSE implementation for complex reciprocal */
SRSLTE_API __m128 srslte_mat_cf_recip_sse(__m128 a); SRSLTE_API __m128 srslte_mat_cf_recip_sse(__m128 a);
@ -90,8 +83,6 @@ SRSLTE_API void srslte_mat_2x2_mmse_sse(__m128 y0, __m128 y1,
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
#include <immintrin.h>
/* AVX implementation for complex reciprocal */ /* AVX implementation for complex reciprocal */
SRSLTE_API __m256 srslte_mat_cf_recip_avx(__m256 a); SRSLTE_API __m256 srslte_mat_cf_recip_avx(__m256 a);

File diff suppressed because it is too large Load Diff

@ -54,7 +54,6 @@ extern "C" {
#define SRSLTE_VEC_EMA(data, average, alpha) ((alpha)*(data)+(1-alpha)*(average)) #define SRSLTE_VEC_EMA(data, average, alpha) ((alpha)*(data)+(1-alpha)*(average))
/** Return the sum of all the elements */ /** Return the sum of all the elements */
SRSLTE_API int srslte_vec_acc_ii(int *x, uint32_t len);
SRSLTE_API float srslte_vec_acc_ff(float *x, uint32_t len); SRSLTE_API float srslte_vec_acc_ff(float *x, uint32_t len);
SRSLTE_API cf_t srslte_vec_acc_cc(cf_t *x, uint32_t len); SRSLTE_API cf_t srslte_vec_acc_cc(cf_t *x, uint32_t len);
@ -77,52 +76,29 @@ SRSLTE_API void srslte_vec_save_file(char *filename, void *buffer, uint32_t len)
SRSLTE_API void srslte_vec_load_file(char *filename, void *buffer, uint32_t len); SRSLTE_API void srslte_vec_load_file(char *filename, void *buffer, uint32_t len);
/* sum two vectors */ /* sum two vectors */
SRSLTE_API void srslte_vec_sum_ch(uint8_t *x, uint8_t *y, char *z, uint32_t len);
SRSLTE_API void srslte_vec_sum_fff(float *x, float *y, float *z, uint32_t len); SRSLTE_API void srslte_vec_sum_fff(float *x, float *y, float *z, uint32_t len);
SRSLTE_API void srslte_vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); SRSLTE_API void srslte_vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
SRSLTE_API void srslte_vec_sub_sss(short *x, short *y, short *z, uint32_t len); SRSLTE_API void srslte_vec_sub_sss(int16_t *x, int16_t *y, int16_t *z, uint32_t len);
SRSLTE_API void srslte_vec_sum_sss(short *x, short *y, short *z, uint32_t len); SRSLTE_API void srslte_vec_sum_sss(int16_t *x, int16_t *y, int16_t *z, uint32_t len);
/* substract two vectors z=x-y */ /* substract two vectors z=x-y */
SRSLTE_API void srslte_vec_sub_fff(float *x, float *y, float *z, uint32_t len); SRSLTE_API void srslte_vec_sub_fff(float *x, float *y, float *z, uint32_t len);
SRSLTE_API void srslte_vec_sub_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); SRSLTE_API void srslte_vec_sub_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
/* EMA filter: output=coeff*new_data + (1-coeff)*average */
SRSLTE_API void srslte_vec_ema_filter(cf_t *new_data, cf_t *average, cf_t *output, float coeff, uint32_t len);
/* Square distance */
SRSLTE_API void srslte_vec_square_dist(cf_t symbol, cf_t *points, float *distance, uint32_t npoints);
/* scalar addition */
SRSLTE_API void srslte_vec_sc_add_fff(float *x, float h, float *z, uint32_t len);
SRSLTE_API void srslte_vec_sc_add_cfc(cf_t *x, float h, cf_t *z, uint32_t len);
SRSLTE_API void srslte_vec_sc_add_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len);
SRSLTE_API void srslte_vec_sc_add_sss(int16_t *x, int16_t h, int16_t *z, uint32_t len);
/* scalar product */ /* scalar product */
SRSLTE_API void srslte_vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len); SRSLTE_API void srslte_vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len);
SRSLTE_API void srslte_vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len); SRSLTE_API void srslte_vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len);
SRSLTE_API void srslte_vec_sc_prod_fff(float *x, float h, float *z, uint32_t len); SRSLTE_API void srslte_vec_sc_prod_fff(float *x, float h, float *z, uint32_t len);
SRSLTE_API void srslte_vec_sc_prod_sfs(short *x, float h, short *z, uint32_t len);
SRSLTE_API void srslte_vec_sc_div2_sss(short *x, int pow2_div, short *z, uint32_t len);
/* Normalization */
SRSLTE_API void srslte_vec_norm_cfc(cf_t *x, float amplitude, cf_t *y, uint32_t len);
SRSLTE_API void srslte_vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len); SRSLTE_API void srslte_vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len);
SRSLTE_API void srslte_vec_convert_if(int16_t *x, float *z, float scale, uint32_t len); SRSLTE_API void srslte_vec_convert_if(int16_t *x, float *z, float scale, uint32_t len);
SRSLTE_API void srslte_vec_convert_ci(int8_t *x, int16_t *z, uint32_t len);
SRSLTE_API void srslte_vec_lut_fuf(float *x, uint32_t *lut, float *y, uint32_t len);
SRSLTE_API void srslte_vec_lut_sss(short *x, unsigned short *lut, short *y, uint32_t len); SRSLTE_API void srslte_vec_lut_sss(short *x, unsigned short *lut, short *y, uint32_t len);
SRSLTE_API void srslte_vec_deinterleave_cf(cf_t *x, float *real, float *imag, uint32_t len);
SRSLTE_API void srslte_vec_deinterleave_real_cf(cf_t *x, float *real, uint32_t len);
SRSLTE_API void srslte_vec_interleave_cf(float *real, float *imag, cf_t *x, uint32_t len);
/* vector product (element-wise) */ /* vector product (element-wise) */
SRSLTE_API void srslte_vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); SRSLTE_API void srslte_vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
SRSLTE_API void srslte_vec_prod_ccc_split(float *x_re, float *x_im, float *y_re, float *y_im, float *z_re, float *z_im, uint32_t len);
/* vector product (element-wise) */ /* vector product (element-wise) */
SRSLTE_API void srslte_vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len); SRSLTE_API void srslte_vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len);
@ -132,7 +108,7 @@ SRSLTE_API void srslte_vec_prod_conj_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len
/* real vector product (element-wise) */ /* real vector product (element-wise) */
SRSLTE_API void srslte_vec_prod_fff(float *x, float *y, float *z, uint32_t len); SRSLTE_API void srslte_vec_prod_fff(float *x, float *y, float *z, uint32_t len);
SRSLTE_API void srslte_vec_prod_sss(short *x, short *y, short *z, uint32_t len); SRSLTE_API void srslte_vec_prod_sss(int16_t *x, int16_t *y, int16_t *z, uint32_t len);
/* Dot-product */ /* Dot-product */
SRSLTE_API cf_t srslte_vec_dot_prod_cfc(cf_t *x, float *y, uint32_t len); SRSLTE_API cf_t srslte_vec_dot_prod_cfc(cf_t *x, float *y, uint32_t len);
@ -142,8 +118,8 @@ SRSLTE_API float srslte_vec_dot_prod_fff(float *x, float *y, uint32_t len);
SRSLTE_API int32_t srslte_vec_dot_prod_sss(int16_t *x, int16_t *y, uint32_t len); SRSLTE_API int32_t srslte_vec_dot_prod_sss(int16_t *x, int16_t *y, uint32_t len);
/* z=x/y vector division (element-wise) */ /* z=x/y vector division (element-wise) */
SRSLTE_API void srslte_vec_div_ccc(cf_t *x, cf_t *y, float *y_mod, cf_t *z, float *z_real, float *z_imag, uint32_t len); SRSLTE_API void srslte_vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
void srslte_vec_div_cfc(cf_t *x, float *y, cf_t *z, float *z_real, float *z_imag, uint32_t len); SRSLTE_API void srslte_vec_div_cfc(cf_t *x, float *y, cf_t *z, uint32_t len);
SRSLTE_API void srslte_vec_div_fff(float *x, float *y, float *z, uint32_t len); SRSLTE_API void srslte_vec_div_fff(float *x, float *y, float *z, uint32_t len);
/* conjugate */ /* conjugate */
@ -158,11 +134,6 @@ SRSLTE_API float srslte_vec_corr_ccc(cf_t *x, cf_t *y, uint32_t len);
/* return the index of the maximum value in the vector */ /* return the index of the maximum value in the vector */
SRSLTE_API uint32_t srslte_vec_max_fi(float *x, uint32_t len); SRSLTE_API uint32_t srslte_vec_max_fi(float *x, uint32_t len);
SRSLTE_API uint32_t srslte_vec_max_abs_ci(cf_t *x, uint32_t len); SRSLTE_API uint32_t srslte_vec_max_abs_ci(cf_t *x, uint32_t len);
SRSLTE_API int16_t srslte_vec_max_star_si(int16_t *x, uint32_t len);
SRSLTE_API int16_t srslte_vec_max_abs_star_si(int16_t *x, uint32_t len);
/* maximum between two vectors */
SRSLTE_API void srslte_vec_max_fff(float *x, float *y, float *z, uint32_t len);
/* quantify vector of floats or int16 and convert to uint8_t */ /* quantify vector of floats or int16 and convert to uint8_t */
SRSLTE_API void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, float clip, uint32_t len); SRSLTE_API void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, float clip, uint32_t len);
@ -172,9 +143,6 @@ SRSLTE_API void srslte_vec_quant_suc(int16_t *in, uint8_t *out, float gain, int1
SRSLTE_API void srslte_vec_abs_cf(cf_t *x, float *abs, uint32_t len); SRSLTE_API void srslte_vec_abs_cf(cf_t *x, float *abs, uint32_t len);
SRSLTE_API void srslte_vec_abs_square_cf(cf_t *x, float *abs_square, uint32_t len); SRSLTE_API void srslte_vec_abs_square_cf(cf_t *x, float *abs_square, uint32_t len);
/* argument of each vector element */
SRSLTE_API void srslte_vec_arg_cf(cf_t *x, float *arg, uint32_t len);
/* Copy 256 bit aligned vector */ /* Copy 256 bit aligned vector */
SRSLTE_API void srs_vec_cf_cpy(cf_t *src, cf_t *dst, int len); SRSLTE_API void srs_vec_cf_cpy(cf_t *src, cf_t *dst, int len);

@ -35,65 +35,93 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
#include "srslte/config.h" #include "srslte/config.h"
SRSLTE_API int srslte_vec_dot_prod_sss_sse(short *x, short *y, uint32_t len); #ifdef LV_HAVE_AVX512
#define SRSLTE_SIMD_BIT_ALIGN 512
#define SRSLTE_IS_ALIGNED(PTR) (((size_t)(PTR) & 0x3F) == 0)
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX
#define SRSLTE_SIMD_BIT_ALIGN 256
#define SRSLTE_IS_ALIGNED(PTR) (((size_t)(PTR) & 0x1F) == 0)
#else /* LV_HAVE_AVX */
#ifdef LV_HAVE_SSE
#define SRSLTE_SIMD_BIT_ALIGN 128
#define SRSLTE_IS_ALIGNED(PTR) (((size_t)(PTR) & 0x0F) == 0)
#else /* LV_HAVE_SSE */
#define SRSLTE_SIMD_BIT_ALIGN 64
#define SRSLTE_IS_ALIGNED(PTR) (1)
#endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */
#endif /* LV_HAVE_AVX512 */
SRSLTE_API int srslte_vec_dot_prod_sss_avx2(short *x, short *y, uint32_t len); /* SIMD Basic vector math */
SRSLTE_API void srslte_vec_sum_sss_simd(int16_t *x, int16_t *y, int16_t *z, int len);
SRSLTE_API void srslte_vec_sum_sss_sse(short *x, short *y, short *z, uint32_t len); SRSLTE_API void srslte_vec_sub_sss_simd(int16_t *x, int16_t *y, int16_t *z, int len);
SRSLTE_API void srslte_vec_sum_sss_avx2(short *x, short *y, short *z, uint32_t len); SRSLTE_API float srslte_vec_acc_ff_simd(float *x, int len);
SRSLTE_API void srslte_vec_sub_sss_sse(short *x, short *y, short *z, uint32_t len); SRSLTE_API cf_t srslte_vec_acc_cc_simd(cf_t *x, int len);
SRSLTE_API void srslte_vec_sub_sss_avx2(short *x, short *y, short *z, uint32_t len); SRSLTE_API void srslte_vec_add_fff_simd(float *x, float *y, float *z, int len);
SRSLTE_API void srslte_vec_sum_fff_sse(float *x, float *y, float *z, uint32_t len); SRSLTE_API void srslte_vec_sub_fff_simd(float *x, float *y, float *z, int len);
SRSLTE_API void srslte_vec_sum_fff_avx(float *x, float *y, float *z, uint32_t len); /* SIMD Vector Scalar Product */
SRSLTE_API void srslte_vec_sc_prod_cfc_simd(const cf_t *x,const float h,cf_t *y,const int len);
SRSLTE_API void srslte_vec_sub_fff_sse(float *x, float *y, float *z, uint32_t len); SRSLTE_API void srslte_vec_sc_prod_fff_simd(float *x, float h, float *z, int len);
SRSLTE_API void srslte_vec_sub_fff_avx(float *x, float *y, float *z, uint32_t len); SRSLTE_API void srslte_vec_sc_prod_ccc_simd(cf_t *x, cf_t h, cf_t *z, int len);
SRSLTE_API void srslte_vec_sc_prod_fff_sse(float *x, float h, float *z, uint32_t len); /* SIMD Vector Product */
SRSLTE_API void srslte_vec_prod_ccc_split_simd(float *a_re, float *a_im, float *b_re, float *b_im, float *r_re, float *r_im, int len);
SRSLTE_API void srslte_vec_sc_prod_ccc_sse(cf_t *x, cf_t h, cf_t *z, uint32_t len); SRSLTE_API void srslte_vec_prod_ccc_c16_simd(int16_t *a_re, int16_t *a_im, int16_t *b_re, int16_t *b_im, int16_t *r_re,
int16_t *r_im, int len);
SRSLTE_API void srslte_vec_prod_ccc_sse(cf_t *x,cf_t *y, cf_t *z, uint32_t len); SRSLTE_API void srslte_vec_prod_sss_simd(int16_t *x, int16_t *y, int16_t *z, int len);
SRSLTE_API void srslte_vec_prod_sss_sse(short *x, short *y, short *z, uint32_t len); SRSLTE_API void srslte_vec_prod_cfc_simd(cf_t *x, float *y, cf_t *z, int len);
SRSLTE_API void srslte_vec_prod_sss_avx2(short *x, short *y, short *z, uint32_t len); SRSLTE_API void srslte_vec_prod_fff_simd(float *x, float *y, float *z, int len);
SRSLTE_API cf_t srslte_vec_dot_prod_conj_ccc_sse(cf_t *x, cf_t *y, uint32_t len); SRSLTE_API void srslte_vec_prod_ccc_simd(cf_t *x,cf_t *y, cf_t *z, int len);
SRSLTE_API void srslte_vec_prod_conj_ccc_sse(cf_t *x,cf_t *y, cf_t *z, uint32_t len); SRSLTE_API void srslte_vec_prod_conj_ccc_simd(cf_t *x,cf_t *y, cf_t *z, int len);
SRSLTE_API cf_t srslte_vec_dot_prod_ccc_sse(cf_t *x, cf_t *y, uint32_t len); /* SIMD Division */
SRSLTE_API void srslte_vec_div_ccc_simd(cf_t *x,cf_t *y, cf_t *z, int len);
SRSLTE_API void srslte_vec_sc_div2_sss_avx2(short *x, int k, short *z, uint32_t len); SRSLTE_API void srslte_vec_div_cfc_simd(cf_t *x, float *y, cf_t *z, int len);
SRSLTE_API void srslte_vec_abs_square_cf_sse(cf_t *x, float *z, uint32_t len); SRSLTE_API void srslte_vec_div_fff_simd(float *x, float *y, float *z, int len);
SRSLTE_API void srslte_vec_prod_sss_sse(short *x, short *y, short *z, uint32_t len); /* SIMD Dot product */
SRSLTE_API cf_t srslte_vec_dot_prod_conj_ccc_simd(cf_t *x, cf_t *y, int len);
SRSLTE_API void srslte_vec_prod_sss_avx(short *x, short *y, short *z, uint32_t len); SRSLTE_API cf_t srslte_vec_dot_prod_ccc_simd(cf_t *x, cf_t *y, int len);
SRSLTE_API void srslte_vec_sc_div2_sss_sse(short *x, int n_rightshift, short *z, uint32_t len); SRSLTE_API c16_t srslte_vec_dot_prod_ccc_c16i_simd(c16_t *x, c16_t *y, int len);
SRSLTE_API void srslte_vec_sc_div2_sss_avx(short *x, int k, short *z, uint32_t len); SRSLTE_API int srslte_vec_dot_prod_sss_simd(int16_t *x, int16_t *y, int len);
SRSLTE_API void srslte_vec_lut_sss_sse(short *x, unsigned short *lut, short *y, uint32_t len); /* SIMD Modulus functions */
SRSLTE_API void srslte_vec_abs_cf_simd(cf_t *x, float *z, int len);
SRSLTE_API void srslte_vec_convert_fi_sse(float *x, int16_t *z, float scale, uint32_t len); SRSLTE_API void srslte_vec_abs_square_cf_simd(cf_t *x, float *z, int len);
SRSLTE_API void srslte_vec_mult_scalar_cf_f_avx( cf_t *z,const cf_t *x,const float h,const uint32_t len); /* Other Functions */
SRSLTE_API void srslte_vec_lut_sss_simd(short *x, unsigned short *lut, short *y, int len);
SRSLTE_API void srslte_vec_lut_sss_sse(short *x, unsigned short *lut, short *y, uint32_t len); SRSLTE_API void srslte_vec_convert_fi_simd(float *x, int16_t *z, float scale, int len);
SRSLTE_API void srslte_vec_convert_fi_sse(float *x, int16_t *z, float scale, uint32_t len); SRSLTE_API void srslte_vec_cp_simd(cf_t *src, cf_t *dst, int len);
SRSLTE_API void srslte_vec_sc_prod_cfc_avx(const cf_t *x,const float h,cf_t *y,const uint32_t len);
/* SIMD Find Max functions */
SRSLTE_API uint32_t srslte_vec_max_fi_simd(float *x, int len);
SRSLTE_API uint32_t srslte_vec_max_ci_simd(cf_t *x, int len);
#ifdef __cplusplus #ifdef __cplusplus
} }

@ -66,7 +66,7 @@ uint8_t* pdu_queue::request(uint32_t len)
void pdu_queue::deallocate(uint8_t* pdu) void pdu_queue::deallocate(uint8_t* pdu)
{ {
if (!pool.deallocate((pdu_t*) pdu)) { if (!pool.deallocate((pdu_t*) pdu)) {
log_h->warning("Error deallocating from buffer pool: buffer not created in this pool.\n"); log_h->warning("Error deallocating from buffer pool in deallocate(): buffer not created in this pool.\n");
} }
} }
@ -92,7 +92,7 @@ bool pdu_queue::process_pdus()
callback->process_pdu(pdu->ptr, pdu->len, pdu->tstamp); callback->process_pdu(pdu->ptr, pdu->len, pdu->tstamp);
} }
if (!pool.deallocate(pdu)) { if (!pool.deallocate(pdu)) {
log_h->warning("Error deallocating from buffer pool: buffer not created in this pool.\n"); log_h->warning("Error deallocating from buffer pool in process_pdus(): buffer not created in this pool.\n");
} }
cnt++; cnt++;
have_data = true; have_data = true;

@ -467,6 +467,8 @@ int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t
srslte_vec_prod_conj_ccc(q->pilot_recv_signal+(2*q->cell.nof_prb), q->mbsfn_refs[mbsfn_area_id]->pilots[port_id/2][sf_idx], srslte_vec_prod_conj_ccc(q->pilot_recv_signal+(2*q->cell.nof_prb), q->mbsfn_refs[mbsfn_area_id]->pilots[port_id/2][sf_idx],
q->pilot_estimates+(2*q->cell.nof_prb), SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id)-(2*q->cell.nof_prb)); q->pilot_estimates+(2*q->cell.nof_prb), SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id)-(2*q->cell.nof_prb));
chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_MBSFN); chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_MBSFN);
return 0; return 0;

@ -229,6 +229,7 @@ int srslte_refsignal_cs_init(srslte_refsignal_t * q, uint32_t max_prb)
if (q != NULL) if (q != NULL)
{ {
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_refsignal_t));
for (int p=0;p<2;p++) { for (int p=0;p<2;p++) {
for (int i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) { for (int i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) {
q->pilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(max_prb, 2*p)); q->pilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(max_prb, 2*p));

@ -33,6 +33,7 @@
#include "srslte/phy/mimo/precoding.h" #include "srslte/phy/mimo/precoding.h"
#include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/vector.h"
#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/mat.h"
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
#include <immintrin.h> #include <immintrin.h>
@ -46,7 +47,6 @@ int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
#endif #endif
#include "srslte/phy/utils/mat.h" #include "srslte/phy/utils/mat.h"
static srslte_mimo_decoder_t mimo_decoder = SRSLTE_MIMO_DECODER_MMSE; static srslte_mimo_decoder_t mimo_decoder = SRSLTE_MIMO_DECODER_MMSE;
/************************************************ /************************************************

@ -394,6 +394,8 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q,
* thus we don't need tot set it in thde LLRs normalization * thus we don't need tot set it in thde LLRs normalization
*/ */
srslte_demod_soft_demodulate_s(cfg->grant.mcs[0].mod, q->d, q->e, cfg->nbits[0].nof_re); srslte_demod_soft_demodulate_s(cfg->grant.mcs[0].mod, q->d, q->e, cfg->nbits[0].nof_re);
/* descramble */ /* descramble */

@ -466,6 +466,7 @@ int srslte_dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) {
tbs = 0; tbs = 0;
i_tbs = 0; i_tbs = 0;
} }
if (tbs == -1) { if (tbs == -1) {
tbs = srslte_ra_tbs_from_idx(i_tbs, nprb); tbs = srslte_ra_tbs_from_idx(i_tbs, nprb);
if (tbs >= 0) { if (tbs >= 0) {

@ -159,6 +159,19 @@ add_test(pdsch_test_multiplex2cw_p1_50 pdsch_test -x multiplex -a 2 -t 0 -p 1 -
add_test(pdsch_test_multiplex2cw_p1_75 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 75) add_test(pdsch_test_multiplex2cw_p1_75 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 75)
add_test(pdsch_test_multiplex2cw_p1_100 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 100) add_test(pdsch_test_multiplex2cw_p1_100 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 100)
########################################################################
# PMCH TEST
########################################################################
add_executable(pmch_test pmch_test.c)
target_link_libraries(pmch_test srslte_phy)
add_test(pmch_test_qpsk pmch_test -m 6 -n 50)
add_test(pmch_test_qam16 pmch_test -m 15 -n 100)
add_test(pmch_test_qam64 pmch_test -m 25 -n 100)
######################################################################## ########################################################################
# FILE TEST # FILE TEST
######################################################################## ########################################################################
@ -178,11 +191,15 @@ target_link_libraries(pdcch_file_test srslte_phy)
add_executable(pdsch_pdcch_file_test pdsch_pdcch_file_test.c) add_executable(pdsch_pdcch_file_test pdsch_pdcch_file_test.c)
target_link_libraries(pdsch_pdcch_file_test srslte_phy) target_link_libraries(pdsch_pdcch_file_test srslte_phy)
add_executable(pmch_file_test pmch_file_test.c)
target_link_libraries(pmch_file_test srslte_phy)
add_test(pbch_file_test pbch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.dat) add_test(pbch_file_test pbch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.dat)
add_test(pcfich_file_test pcfich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat) add_test(pcfich_file_test pcfich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat)
add_test(phich_file_test phich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat) add_test(phich_file_test phich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat)
add_test(pdcch_file_test pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat) add_test(pdcch_file_test pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat)
add_test(pdsch_pdcch_file_test pdsch_pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat) add_test(pdsch_pdcch_file_test pdsch_pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat)
add_test(pmch_file_test pmch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/pmch_100prbs_MCS2_SR0.bin)
######################################################################## ########################################################################
# PUSCH TEST # PUSCH TEST

@ -0,0 +1,204 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE 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.
*
* srsLTE 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "srslte/srslte.h"
char *input_file_name = NULL;
srslte_cell_t cell = {
100, // nof_prb
1, // nof_ports
1, // cell_id
SRSLTE_CP_EXT, // cyclic prefix
SRSLTE_PHICH_R_1, // PHICH resources
SRSLTE_PHICH_NORM // PHICH length
};
int flen;
uint32_t cfi = 2;
uint16_t rnti = SRSLTE_SIRNTI;
int max_frames = 150;
uint32_t sf_idx = 1;
uint8_t non_mbsfn_region = 2;
int mbsfn_area_id = 1;
srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1A;
srslte_filesource_t fsrc;
srslte_ue_dl_t ue_dl;
cf_t *input_buffer[SRSLTE_MAX_PORTS];
void usage(char *prog) {
printf("Usage: %s [rovfcenmps] -i input_file\n", prog);
printf("\t-o DCI format [Default %s]\n", srslte_dci_format_string(dci_format));
printf("\t-c cell.id [Default %d]\n", cell.id);
printf("\t-s Start subframe_idx [Default %d]\n", sf_idx);
printf("\t-f cfi [Default %d]\n", cfi);
printf("\t-r rnti [Default 0x%x]\n",rnti);
printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports);
printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-M mbsfn_area_id [Default %d]\n", mbsfn_area_id);
printf("\t-e Set extended prefix [Default Normal]\n");
printf("\t-v [set srslte_verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "irovfcenmps")) != -1) {
switch(opt) {
case 'i':
input_file_name = argv[optind];
break;
case 'c':
cell.id = atoi(argv[optind]);
break;
case 's':
sf_idx = atoi(argv[optind]);
break;
case 'r':
rnti = strtoul(argv[optind], NULL, 0);
break;
case 'f':
cfi = atoi(argv[optind]);
break;
case 'n':
cell.nof_prb = atoi(argv[optind]);
break;
case 'p':
cell.nof_ports = atoi(argv[optind]);
break;
case 'M':
mbsfn_area_id = atoi(argv[optind]);
break;
case 'o':
dci_format = srslte_dci_format_from_string(argv[optind]);
if (dci_format == SRSLTE_DCI_NOF_FORMATS) {
fprintf(stderr, "Error unsupported format %s\n", argv[optind]);
exit(-1);
}
break;
case 'v':
srslte_verbose++;
break;
case 'e':
cell.cp = SRSLTE_CP_EXT;
break;
default:
usage(argv[0]);
exit(-1);
}
}
if (!input_file_name) {
usage(argv[0]);
exit(-1);
}
}
int base_init() {
if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", input_file_name);
exit(-1);
}
flen = 2 * (SRSLTE_SLOT_LEN(srslte_symbol_sz(cell.nof_prb)));
input_buffer[0] = malloc(flen * sizeof(cf_t));
if (!input_buffer[0]) {
perror("malloc");
exit(-1);
}
if (srslte_ue_dl_init(&ue_dl, cell.nof_prb, 1)) {
fprintf(stderr, "Error initializing UE DL\n");
return -1;
}
if (srslte_ue_dl_set_cell(&ue_dl, cell)) {
fprintf(stderr, "Error initializing UE DL\n");
return -1;
}
srslte_ue_dl_set_rnti(&ue_dl, rnti);
srslte_ue_dl_set_mbsfn_area_id(&ue_dl, mbsfn_area_id);
srslte_ue_dl_set_non_mbsfn_region(&ue_dl, non_mbsfn_region);
DEBUG("Memory init OK\n",0);
return 0;
}
void base_free() {
srslte_filesource_free(&fsrc);
srslte_ue_dl_free(&ue_dl);
free(input_buffer[0]);
}
int main(int argc, char **argv) {
int ret;
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
parse_args(argc,argv);
if (base_init()) {
fprintf(stderr, "Error initializing memory\n");
exit(-1);
}
uint8_t *data[] = {malloc(100000)};
ret = -1;
srslte_filesource_read(&fsrc, input_buffer[0], flen);
INFO("Reading %d samples sub-frame %d\n", flen, sf_idx);
ret = srslte_ue_dl_decode_mbsfn(&ue_dl, input_buffer, data[0], sf_idx);
if(ret > 0) {
printf("PMCH Decoded OK!\n");
} else if (ret < 0) {
printf("Error decoding PMCH\n");
}
base_free();
free(data[0]);
if (ret > 0) {
exit(0);
} else {
exit(-1);
}
}

@ -0,0 +1,469 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE 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.
*
* srsLTE 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <srslte/phy/phch/ra.h>
#include "srslte/srslte.h"
// Enable to measure execution time
#define DO_OFDM
#ifdef DO_OFDM
#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_PRB(cell.nof_prb)
#else
#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)
#endif
srslte_cell_t cell = {
100, // nof_prb
1, // nof_ports
1, // cell_id
SRSLTE_CP_EXT, // cyclic prefix
SRSLTE_PHICH_NORM, // PHICH length
SRSLTE_PHICH_R_1_6 // PHICH resources
};
char mimo_type_str [32] = "single";
srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
uint32_t cfi = 2;
uint32_t mcs_idx = 2;
uint32_t subframe = 1;
int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1};
uint16_t rnti = 1234;
uint32_t nof_rx_antennas = 1;
uint32_t pmi = 0;
char *input_file = NULL;
uint32_t mbsfn_area_id = 1;
uint32_t non_mbsfn_region = 2;
void usage(char *prog) {
printf("Usage: %s [fmMcsrtRFpnwav] \n", prog);
printf("\t-f read signal from file [Default generate it with pdsch_encode()]\n");
printf("\t-m MCS [Default %d]\n", mcs_idx);
printf("\t-M mbsfn area id [Default %d]\n", mbsfn_area_id);
printf("\t-N non mbsfn region [Default %d]\n", non_mbsfn_region);
printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-s subframe [Default %d]\n", subframe);
printf("\t-r rv_idx [Default %d]\n", rv_idx[0]);
printf("\t-R rnti [Default %d]\n", rnti);
printf("\t-F cfi [Default %d]\n", cfi);
printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-a nof_rx_antennas [Default %d]\n", nof_rx_antennas);
printf("\t-v [set srslte_verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "fmMcsrtRFpnavx")) != -1) {
switch(opt) {
case 'f':
input_file = argv[optind];
break;
case 'm':
mcs_idx = (uint32_t) atoi(argv[optind]);
break;
case 's':
subframe = atoi(argv[optind]);
break;
case 'r':
rv_idx[0] = (uint32_t) atoi(argv[optind]);
break;
case 'R':
rnti = atoi(argv[optind]);
break;
case 'F':
cfi = atoi(argv[optind]);
break;
case 'x':
strncpy(mimo_type_str, argv[optind], 32);
break;
case 'p':
pmi = (uint32_t) atoi(argv[optind]);
break;
case 'n':
cell.nof_prb = atoi(argv[optind]);
break;
case 'c':
cell.id = atoi(argv[optind]);
break;
case 'a':
nof_rx_antennas = (uint32_t) atoi(argv[optind]);
break;
case 'v':
srslte_verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
static uint8_t *data_tx[SRSLTE_MAX_CODEWORDS] = {NULL};
static uint8_t *data_rx[SRSLTE_MAX_CODEWORDS] = {NULL};
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
srslte_softbuffer_rx_t *softbuffers_rx[SRSLTE_MAX_CODEWORDS];
srslte_ra_dl_grant_t grant;
#ifdef DO_OFDM
cf_t *tx_sf_symbols[SRSLTE_MAX_PORTS];
cf_t *rx_sf_symbols[SRSLTE_MAX_PORTS];
#endif /* DO_OFDM */
cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS];
cf_t *rx_slot_symbols[SRSLTE_MAX_PORTS];
srslte_pmch_t pmch_tx, pmch_rx;
srslte_pdsch_cfg_t pmch_cfg;
srslte_ofdm_t ifft_mbsfn, fft_mbsfn;
int main(int argc, char **argv) {
uint32_t i, j, k;
int ret = -1;
struct timeval t[3];
srslte_softbuffer_tx_t *softbuffers_tx[SRSLTE_MAX_CODEWORDS];
int M=1;
parse_args(argc,argv);
/* Initialise to zeros */
bzero(&pmch_tx, sizeof(srslte_pmch_t));
bzero(&pmch_rx, sizeof(srslte_pmch_t));
bzero(&pmch_cfg, sizeof(srslte_pdsch_cfg_t));
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);
cell.nof_ports = 1;
srslte_ra_dl_dci_t dci;
bzero(&dci, sizeof(srslte_ra_dl_dci_t));
dci.type0_alloc.rbg_bitmask = 0xffffffff;
/* If transport block 0 is enabled */
grant.tb_en[0] = true;
grant.tb_en[1] = false;
grant.nof_tb = 1;
grant.mcs[0].idx = mcs_idx;
grant.nof_prb = cell.nof_prb;
grant.sf_type = SRSLTE_SF_MBSFN;
srslte_dl_fill_ra_mcs(&grant.mcs[0], cell.nof_prb);
grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod);
for(int i = 0; i < 2; i++){
for(int j = 0; j < grant.nof_prb; j++){
grant.prb_idx[i][j] = true;
}
}
#ifdef DO_OFDM
if (srslte_ofdm_tx_init_mbsfn(&ifft_mbsfn, SRSLTE_CP_EXT, cell.nof_prb)) {
fprintf(stderr, "Error creating iFFT object\n");
exit(-1);
}
if (srslte_ofdm_rx_init_mbsfn(&fft_mbsfn, SRSLTE_CP_EXT, cell.nof_prb)) {
fprintf(stderr, "Error creating iFFT object\n");
exit(-1);
}
srslte_ofdm_set_non_mbsfn_region(&ifft_mbsfn, non_mbsfn_region);
srslte_ofdm_set_non_mbsfn_region(&fft_mbsfn, non_mbsfn_region);
srslte_ofdm_set_normalize(&ifft_mbsfn, true);
srslte_ofdm_set_normalize(&fft_mbsfn, true);
for (i = 0; i < cell.nof_ports; i++) {
tx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
}
for (i = 0; i < nof_rx_antennas; i++) {
rx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
}
#endif /* DO_OFDM */
/* Configure PDSCH */
if (srslte_pmch_cfg(&pmch_cfg, cell, &grant, cfi, subframe)) {
fprintf(stderr, "Error configuring PMCH\n");
exit(-1);
}
/* init memory */
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * NOF_CE_SYMBOLS);
if (!ce[i]) {
perror("srslte_vec_malloc");
goto quit;
}
for (k = 0; k < NOF_CE_SYMBOLS; k++) {
ce[i][j][k] = (i == j) ? 1.0f : 0.0f;
}
}
rx_slot_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
if (!rx_slot_symbols[i]) {
perror("srslte_vec_malloc");
goto quit;
}
}
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (grant.tb_en[i]) {
data_tx[i] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs[i].tbs);
if (!data_tx[i]) {
perror("srslte_vec_malloc");
goto quit;
}
bzero(data_tx[i], sizeof(uint8_t) * grant.mcs[i].tbs);
data_rx[i] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs[i].tbs);
if (!data_rx[i]) {
perror("srslte_vec_malloc");
goto quit;
}
bzero(data_rx[i], sizeof(uint8_t) * grant.mcs[i].tbs);
}
}
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
softbuffers_rx[i] = calloc(sizeof(srslte_softbuffer_rx_t), 1);
if (!softbuffers_rx[i]) {
fprintf(stderr, "Error allocating RX soft buffer\n");
goto quit;
}
if (srslte_softbuffer_rx_init(softbuffers_rx[i], cell.nof_prb)) {
fprintf(stderr, "Error initiating RX soft buffer\n");
goto quit;
}
}
if (srslte_pmch_cfg(&pmch_cfg, cell, &grant, cfi, subframe)) {
fprintf(stderr, "Error configuring PMCH\n");
exit(-1);
}
INFO(" Global:\n");
INFO(" nof_prb=%d\n", cell.nof_prb);
INFO(" nof_ports=%d\n", cell.nof_ports);
INFO(" id=%d\n", cell.id);
INFO(" cp=%s\n", srslte_cp_string(cell.cp));
INFO(" phich_length=%d\n", (int) cell.phich_length);
INFO(" phich_resources=%d\n", (int) cell.phich_resources);
INFO(" nof_prb=%d\n", pmch_cfg.grant.nof_prb);
INFO(" sf_idx=%d\n", pmch_cfg.sf_idx);
INFO(" mimo_type=%s\n", srslte_mimotype2str(pmch_cfg.mimo_type));
INFO(" nof_layers=%d\n", pmch_cfg.nof_layers);
INFO(" nof_tb=%d\n", SRSLTE_RA_DL_GRANT_NOF_TB(&pmch_cfg.grant));
INFO(" Qm=%d\n", pmch_cfg.grant.Qm[0]);
INFO(" mcs.idx=0x%X\n", pmch_cfg.grant.mcs[0].idx);
INFO(" mcs.tbs=%d\n", pmch_cfg.grant.mcs[0].tbs);
INFO(" mcs.mod=%s\n", srslte_mod_string(pmch_cfg.grant.mcs[0].mod));
INFO(" rv=%d\n", pmch_cfg.rv[0]);
INFO(" lstart=%d\n", pmch_cfg.nbits[0].lstart);
INFO(" nof_bits=%d\n", pmch_cfg.nbits[0].nof_bits);
INFO(" nof_re=%d\n", pmch_cfg.nbits[0].nof_re);
INFO(" nof_symb=%d\n", pmch_cfg.nbits[0].nof_symb);
if (srslte_pmch_init(&pmch_tx, cell.nof_prb)) {
fprintf(stderr, "Error creating PMCH object\n");
}
srslte_pmch_set_area_id(&pmch_tx, mbsfn_area_id);
if (srslte_pmch_init(&pmch_rx, cell.nof_prb)) {
fprintf(stderr, "Error creating PMCH object\n");
}
srslte_pmch_set_area_id(&pmch_rx, mbsfn_area_id);
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
softbuffers_tx[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1);
if (!softbuffers_tx[i]) {
fprintf(stderr, "Error allocating TX soft buffer\n");
}
if (srslte_softbuffer_tx_init(softbuffers_tx[i], cell.nof_prb)) {
fprintf(stderr, "Error initiating TX soft buffer\n");
goto quit;
}
}
for (i = 0; i < cell.nof_ports; i++) {
tx_slot_symbols[i] = calloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), sizeof(cf_t));
if (!tx_slot_symbols[i]) {
perror("srslte_vec_malloc");
goto quit;
}
}
for (int tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
if (grant.tb_en[tb]) {
for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) {
data_tx[tb][byte] = (uint8_t) (rand() % 256);
}
}
}
if (srslte_pmch_encode(&pmch_tx, &pmch_cfg, softbuffers_tx[0], data_tx[0], mbsfn_area_id, tx_slot_symbols)) {
fprintf(stderr, "Error encoding PDSCH\n");
exit(-1);
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("ENCODED in %.2f (PHY bitrate=%.2f Mbps. Processing bitrate=%.2f Mbps)\n",
(float) t[0].tv_usec/M, (float) (grant.mcs[0].tbs + grant.mcs[1].tbs)/1000.0f,
(float) (grant.mcs[0].tbs + grant.mcs[1].tbs)*M/t[0].tv_usec);
#ifdef DO_OFDM
for (i = 0; i < cell.nof_ports; i++) {
/* For each Tx antenna modulate OFDM */
srslte_ofdm_tx_sf(&ifft_mbsfn, tx_slot_symbols[i], tx_sf_symbols[i]);
}
/* combine outputs */
for (j = 0; j < nof_rx_antennas; j++) {
for (k = 0; k < NOF_CE_SYMBOLS; k++) {
rx_sf_symbols[j][k] = 0.0f;
for (i = 0; i < cell.nof_ports; i++) {
rx_sf_symbols[j][k] += tx_sf_symbols[i][k] * ce[i][j][k];
}
}
}
#else
/* combine outputs */
for (j = 0; j < nof_rx_antennas; j++) {
for (k = 0; k < SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); k++) {
rx_slot_symbols[j][k] = 0.0f;
for (i = 0; i < cell.nof_ports; i++) {
rx_slot_symbols[j][k] += tx_slot_symbols[i][k] * ce[i][j][k];
}
}
}
#endif
int r=0;
gettimeofday(&t[1], NULL);
#ifdef DO_OFDM
/* For each Rx antenna demodulate OFDM */
for (i = 0; i < nof_rx_antennas; i++) {
srslte_ofdm_rx_sf(&fft_mbsfn, tx_sf_symbols[i], rx_slot_symbols[i]);
}
#endif
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (grant.tb_en[i]) {
srslte_softbuffer_rx_reset_tbs(softbuffers_rx[i], (uint32_t) grant.mcs[i].tbs);
}
}
r = srslte_pmch_decode(&pmch_rx, &pmch_cfg, softbuffers_rx[0],rx_slot_symbols[0], ce[0],0,mbsfn_area_id, data_rx[0]);
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("DECODED %s in %.2f (PHY bitrate=%.2f Mbps. Processing bitrate=%.2f Mbps)\n", r?"Error":"OK",
(float) t[0].tv_usec/M, (float) (grant.mcs[0].tbs + grant.mcs[1].tbs)/1000.0f,
(float) (grant.mcs[0].tbs + grant.mcs[1].tbs)*M/t[0].tv_usec);
/* If there is an error in PDSCH decode */
if (r) {
ret = -1;
goto quit;
}
/* Check Tx and Rx bytes */
for (int tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
if (grant.tb_en[tb]) {
for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) {
if (data_tx[tb][byte] != data_rx[tb][byte]) {
ERROR("Found BYTE error in TB %d (%02X != %02X), quiting...", tb, data_tx[tb][byte], data_rx[tb][byte]);
ret = SRSLTE_ERROR;
goto quit;
}
}
}
}
ret = SRSLTE_SUCCESS;
quit:
srslte_pmch_free(&pmch_tx);
srslte_pmch_free(&pmch_rx);
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
srslte_softbuffer_tx_free(softbuffers_tx[i]);
if (softbuffers_tx[i]) {
free(softbuffers_tx[i]);
}
srslte_softbuffer_rx_free(softbuffers_rx[i]);
if (softbuffers_rx[i]) {
free(softbuffers_rx[i]);
}
if (data_tx[i]) {
free(data_tx[i]);
}
if (data_rx[i]) {
free(data_rx[i]);
}
}
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
if (ce[i][j]) {
free(ce[i][j]);
}
}
if (tx_slot_symbols[i]) {
free(tx_slot_symbols[i]);
}
if (rx_slot_symbols[i]) {
free(rx_slot_symbols[i]);
}
}
if (ret) {
printf("Error\n");
} else {
printf("Ok\n");
}
exit(ret);
}

@ -232,6 +232,7 @@ int main(int argc, char **argv) {
srslte_vec_save_file(output_filename,buffer,11*flen*sizeof(cf_t)); srslte_vec_save_file(output_filename,buffer,11*flen*sizeof(cf_t));
srslte_rf_close(&rf);
srslte_prach_free(p); srslte_prach_free(p);
free(p); free(p);

@ -177,7 +177,7 @@ static rf_dev_t dev_soapy = {
rf_soapy_recv_with_time, rf_soapy_recv_with_time,
rf_soapy_recv_with_time_multi, rf_soapy_recv_with_time_multi,
rf_soapy_send_timed, rf_soapy_send_timed,
.srslte_rf_send_timed_multi = /* FIXME: Implement srslte_rf_send_timed_multi for Soapy SDR */ NULL, .srslte_rf_send_timed_multi = rf_soapy_send_timed_multi,
rf_soapy_set_tx_cal, rf_soapy_set_tx_cal,
rf_soapy_set_rx_cal rf_soapy_set_rx_cal
}; };

@ -88,12 +88,12 @@ void rf_soapy_register_error_handler(void *notused, srslte_rf_error_handler_t ne
} }
char* rf_soapy_devname(void* h) char* rf_soapy_devname(void* h)
{ {
return "soapy"; return "soapy";
} }
bool rf_soapy_rx_wait_lo_locked(void *h) bool rf_soapy_rx_wait_lo_locked(void *h)
{ {
printf("TODO: implement rf_soapy_rx_wait_lo_locked()\n"); printf("TODO: implement rf_soapy_rx_wait_lo_locked()\n");
@ -155,7 +155,6 @@ int rf_soapy_stop_tx_stream(void *h)
if(SoapySDRDevice_deactivateStream(handler->device, handler->txStream, 0, 0) != 0) if(SoapySDRDevice_deactivateStream(handler->device, handler->txStream, 0, 0) != 0)
return SRSLTE_ERROR; return SRSLTE_ERROR;
handler->tx_stream_active = false; handler->tx_stream_active = false;
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -175,7 +174,7 @@ void rf_soapy_flush_buffer(void *h)
bool rf_soapy_has_rssi(void *h) bool rf_soapy_has_rssi(void *h)
{ {
printf("TODO: implement rf_soapy_has_rssi()\n"); // TODO: implement rf_soapy_has_rssi()
return false; return false;
} }
@ -199,9 +198,8 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
} }
for (size_t i = 0; i < length; i++) { for (size_t i = 0; i < length; i++) {
printf("Soapy Has Found device #%d: ", (int)i); printf("Soapy has Found device #%d: ", (int)i);
for (size_t j = 0; j < soapy_args[i].size; j++) for (size_t j = 0; j < soapy_args[i].size; j++) {
{
printf("%s=%s, ", soapy_args[i].keys[j], soapy_args[i].vals[j]); printf("%s=%s, ", soapy_args[i].keys[j], soapy_args[i].vals[j]);
} }
printf("\n"); printf("\n");
@ -221,7 +219,6 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
handler->tx_stream_active = false; handler->tx_stream_active = false;
handler->rx_stream_active = false; handler->rx_stream_active = false;
if(SoapySDRDevice_getNumChannels(handler->device,SOAPY_SDR_RX) > 0){ if(SoapySDRDevice_getNumChannels(handler->device,SOAPY_SDR_RX) > 0){
printf("setting up RX stream\n"); printf("setting up RX stream\n");
if(SoapySDRDevice_setupStream(handler->device, &(handler->rxStream), SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) { if(SoapySDRDevice_setupStream(handler->device, &(handler->rxStream), SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL) != 0) {
@ -251,12 +248,12 @@ int rf_soapy_open(char *args, void **h)
int rf_soapy_close(void *h) int rf_soapy_close(void *h)
{ {
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (handler->txStream) { if (handler->tx_stream_active) {
rf_soapy_stop_tx_stream(handler); rf_soapy_stop_tx_stream(handler);
SoapySDRDevice_closeStream(handler->device, handler->txStream); SoapySDRDevice_closeStream(handler->device, handler->txStream);
} }
if (handler->rxStream) { if (handler->rx_stream_active) {
rf_soapy_stop_rx_stream(handler); rf_soapy_stop_rx_stream(handler);
SoapySDRDevice_closeStream(handler->device, handler->rxStream); SoapySDRDevice_closeStream(handler->device, handler->rxStream);
} }
@ -285,9 +282,15 @@ double rf_soapy_set_rx_srate(void *h, double rate)
{ {
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_RX, 0, rate) != 0) { if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_RX, 0, rate) != 0) {
printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError()); printf("setSampleRate Rx fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
if (SoapySDRDevice_setBandwidth(handler->device, SOAPY_SDR_RX, 0, rate) != 0) {
printf("setBandwidth Rx failed: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_RX,0); return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_RX,0);
} }
@ -295,9 +298,15 @@ double rf_soapy_set_tx_srate(void *h, double rate)
{ {
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_TX, 0, rate) != 0) { if (SoapySDRDevice_setSampleRate(handler->device, SOAPY_SDR_TX, 0, rate) != 0) {
printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError()); printf("setSampleRate Tx fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR;
}
if (SoapySDRDevice_setBandwidth(handler->device, SOAPY_SDR_TX, 0, rate) != 0) {
printf("setBandwidth Tx failed: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_TX,0); return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_TX,0);
} }
@ -349,6 +358,14 @@ double rf_soapy_set_rx_freq(void *h, double freq)
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Todo: expose antenna setting
if (SoapySDRDevice_setAntenna(handler->device, SOAPY_SDR_RX, 0, "LNAH") != 0) {
fprintf(stderr, "Failed to set Rx antenna.\n");
}
char *ant = SoapySDRDevice_getAntenna(handler->device, SOAPY_SDR_RX, 0);
printf("Rx antenna set to %s\n", ant);
return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0); return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0);
} }
@ -360,14 +377,25 @@ double rf_soapy_set_tx_freq(void *h, double freq)
printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); printf("setFrequency fail: %s\n", SoapySDRDevice_lastError());
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Todo: expose antenna name in arguments
if (SoapySDRDevice_setAntenna(handler->device, SOAPY_SDR_TX, 0, "BAND1") != 0) {
fprintf(stderr, "Failed to set Tx antenna.\n");
}
char *ant = SoapySDRDevice_getAntenna(handler->device, SOAPY_SDR_TX, 0);
printf("Tx antenna set to %s\n", ant);
return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_TX, 0); return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_TX, 0);
} }
void rf_soapy_get_time(void *h, time_t *secs, double *frac_secs) { void rf_soapy_get_time(void *h, time_t *secs, double *frac_secs)
{
printf("Todo: implement rf_soapy_get_time()\n");
} }
//TODO: add multi-channel support //TODO: add multi-channel support
int rf_soapy_recv_with_time_multi(void *h, int rf_soapy_recv_with_time_multi(void *h,
void **data, void **data,
@ -395,7 +423,7 @@ int rf_soapy_recv_with_time_multi(void *h,
cf_t *data_c = (cf_t*) data[i]; cf_t *data_c = (cf_t*) data[i];
buffs_ptr[i] = &data_c[n]; buffs_ptr[i] = &data_c[n];
} }
ret = SoapySDRDevice_readStream(handler->device, handler->rxStream, buffs_ptr , rx_samples, &flags, &timeNs, 1000000); ret = SoapySDRDevice_readStream(handler->device, handler->rxStream, buffs_ptr, rx_samples, &flags, &timeNs, 10000);
if(ret < 0) { if(ret < 0) {
// continue when getting overflows // continue when getting overflows
if (ret == SOAPY_SDR_OVERFLOW) { if (ret == SOAPY_SDR_OVERFLOW) {
@ -407,17 +435,23 @@ int rf_soapy_recv_with_time_multi(void *h,
} }
} }
// update rx time
if (secs != NULL && frac_secs != NULL) {
*secs = timeNs / 1e9;
*frac_secs = (timeNs % 1000000000)/1e9;
//printf("rx_time: secs=%d, frac_secs=%lf timeNs=%lld\n", *secs, *frac_secs, timeNs);
}
n += ret; n += ret;
trials++; trials++;
} while (n < nsamples && trials < 100); } while (n < nsamples && trials < 100);
//*secs = timeNs / 1000000000;
//*frac_secs = (timeNs % 1000000000)/1000000000;
// printf("ret=%d, flags=%d, timeNs=%lld\n", ret, flags, timeNs);
return n; return n;
} }
int rf_soapy_recv_with_time(void *h, int rf_soapy_recv_with_time(void *h,
void *data, void *data,
uint32_t nsamples, uint32_t nsamples,
@ -439,40 +473,83 @@ int rf_soapy_send_timed(void *h,
bool is_start_of_burst, bool is_start_of_burst,
bool is_end_of_burst) bool is_end_of_burst)
{ {
void *_data[SRSLTE_MAX_PORTS]= {data, zero_mem, zero_mem, zero_mem};
return rf_soapy_send_timed_multi(h, _data, nsamples, secs, frac_secs, has_time_spec, blocking, is_start_of_burst, is_end_of_burst);
}
int flags;
long long timeNs; // Todo: Check correct handling of flags, use RF metrics API, fix timed transmissions
int rf_soapy_send_timed_multi(void *h,
void *data[SRSLTE_MAX_PORTS],
int nsamples,
time_t secs,
double frac_secs,
bool has_time_spec,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst)
{
rf_soapy_handler_t *handler = (rf_soapy_handler_t *) h;
int flags = 0;
const long timeoutUs = 2000; // arbitrarily chosen
long long timeNs = 0;
int trials = 0; int trials = 0;
int ret = 0; int ret = 0;
rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
timeNs = secs * 1000000000;
timeNs = timeNs + (frac_secs * 1000000000);
int n = 0; int n = 0;
if(!handler->tx_stream_active){
if (!handler->tx_stream_active) {
rf_soapy_start_tx_stream(h); rf_soapy_start_tx_stream(h);
} }
if (is_start_of_burst && is_end_of_burst) {
flags |= SOAPY_SDR_ONE_PACKET;
}
if (is_end_of_burst) {
flags |= SOAPY_SDR_END_BURST;
}
if (has_time_spec) {
flags |= SOAPY_SDR_HAS_TIME;
timeNs = secs * 1000000000;
timeNs = timeNs + (frac_secs * 1000000000);
//printf("time_spec: secs=%d, frac_secs=%lf timeNs=%lld\n", secs, frac_secs, timeNs);
}
cf_t *data_c = (cf_t*) data; do {
do{
size_t tx_samples = nsamples; size_t tx_samples = nsamples;
if (tx_samples > nsamples - n) { if (tx_samples > nsamples - n) {
tx_samples = nsamples - n; tx_samples = nsamples - n;
} }
void *buff = (void*) &data_c[n];
const void *buffs_ptr[1] = {buff}; ret = SoapySDRDevice_writeStream(handler->device, handler->txStream, (const void *)data, tx_samples, &flags, timeNs, timeoutUs);
ret = SoapySDRDevice_writeStream(handler->device, handler->txStream, buffs_ptr, tx_samples, &flags, timeNs, 10000); if (ret == SOAPY_SDR_TIMEOUT) {
if(ret < 0) printf("L");
continue;
}
if (ret == SOAPY_SDR_OVERFLOW) {
printf("O");
continue;
}
if (ret == SOAPY_SDR_UNDERFLOW) {
printf("U");
continue;
}
if (ret < 0) {
fprintf(stderr, "Error during writeStream\n");
exit(-1);
return SRSLTE_ERROR; return SRSLTE_ERROR;
}
n += ret; n += ret;
trials++; trials++;
}while (n < nsamples && trials < 100); } while (n < nsamples && trials < 100);
if(ret != nsamples) if (n != nsamples) {
fprintf(stderr, "Couldn't write all samples.\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
}
return ret; return ret;
} }

@ -116,3 +116,12 @@ SRSLTE_API int rf_soapy_send_timed(void *h,
bool is_start_of_burst, bool is_start_of_burst,
bool is_end_of_burst); bool is_end_of_burst);
int rf_soapy_send_timed_multi(void *h,
void *data[4],
int nsamples,
time_t secs,
double frac_secs,
bool has_time_spec,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst);

@ -70,14 +70,12 @@ static void corr_all_sz_partial(cf_t z[SRSLTE_SSS_N], float s[SRSLTE_SSS_N][SRSL
static void extract_pair_sss(srslte_sss_synch_t *q, cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) { static void extract_pair_sss(srslte_sss_synch_t *q, cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) {
cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX];
float ce_mod[2*SRSLTE_SSS_N], z_real[2*SRSLTE_SSS_N], z_imag[2*SRSLTE_SSS_N];
srslte_dft_run_c(&q->dftp_input, input, input_fft); srslte_dft_run_c(&q->dftp_input, input, input_fft);
if (ce) { if (ce) {
srslte_vec_div_ccc(&input_fft[q->fft_size/2-SRSLTE_SSS_N], ce, ce_mod, srslte_vec_div_ccc(&input_fft[q->fft_size/2-SRSLTE_SSS_N], ce,
&input_fft[q->fft_size/2-SRSLTE_SSS_N], z_real, z_imag, &input_fft[q->fft_size/2-SRSLTE_SSS_N], 2*SRSLTE_SSS_N);
2*SRSLTE_SSS_N);
} }
for (int i = 0; i < SRSLTE_SSS_N; i++) { for (int i = 0; i < SRSLTE_SSS_N; i++) {

@ -631,8 +631,7 @@ int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q,
fprintf(stderr, "Error calling srslte_pmch_decode()\n"); fprintf(stderr, "Error calling srslte_pmch_decode()\n");
} }
} }
printf("q->pmch_pkts_total %d \n", q->pmch_pkts_total);
printf("qq->pmch_pkt_errors %d \n", q->pmch_pkt_errors);
q->pmch_pkts_total++; q->pmch_pkts_total++;
if (ret == SRSLTE_SUCCESS) { if (ret == SRSLTE_SUCCESS) {

@ -27,6 +27,7 @@
#include <complex.h> #include <complex.h>
#include <math.h> #include <math.h>
#include <srslte/config.h>
#include "srslte/phy/utils/mat.h" #include "srslte/phy/utils/mat.h"

@ -42,3 +42,7 @@ target_link_libraries(algebra_test srslte_phy)
add_test(algebra_2x2_zf_solver_test algebra_test -z) add_test(algebra_2x2_zf_solver_test algebra_test -z)
add_test(algebra_2x2_mmse_solver_test algebra_test -m) add_test(algebra_2x2_mmse_solver_test algebra_test -m)
add_executable(vector_test vector_test.c)
target_link_libraries(vector_test srslte_phy)
add_test(vector_test vector_test)

@ -29,16 +29,21 @@
#include <unistd.h> #include <unistd.h>
#include <complex.h> #include <complex.h>
#include <stdbool.h> #include <stdbool.h>
#include <immintrin.h>
#include <sys/time.h> #include <sys/time.h>
#include "srslte/phy/utils/mat.h" #include "srslte/phy/utils/mat.h"
#include "srslte/phy/utils/simd.h"
#include "srslte/phy/utils/vector.h"
bool zf_solver = false; bool zf_solver = false;
bool mmse_solver = false; bool mmse_solver = false;
bool verbose = false; bool verbose = false;
#define RANDOM_F() ((float)rand())/((float)RAND_MAX)
#define RANDOM_S() ((int16_t)(rand() && 0x800F))
#define RANDOM_CF() (RANDOM_F() + _Complex_I*RANDOM_F())
double elapsed_us(struct timeval *ts_start, struct timeval *ts_end) { double elapsed_us(struct timeval *ts_start, struct timeval *ts_end) {
if (ts_end->tv_usec > ts_start->tv_usec) { if (ts_end->tv_usec > ts_start->tv_usec) {
return ((double) ts_end->tv_sec - (double) ts_start->tv_sec) * 1000000 + return ((double) ts_end->tv_sec - (double) ts_start->tv_sec) * 1000000 +
@ -49,16 +54,16 @@ double elapsed_us(struct timeval *ts_start, struct timeval *ts_end) {
} }
} }
#define NOF_REPETITIONS 1000 #define BLOCK_SIZE 1000
#define RUN_TEST(FUNCTION) /*TYPE NAME (void)*/ { \ #define RUN_TEST(FUNCTION) /*TYPE NAME (void)*/ { \
int i;\ int i;\
struct timeval start, end;\ struct timeval start, end;\
gettimeofday(&start, NULL); \ gettimeofday(&start, NULL); \
bool ret = true; \ bool ret = true; \
for (i = 0; i < NOF_REPETITIONS; i++) {ret &= FUNCTION ();}\ for (i = 0; i < BLOCK_SIZE; i++) {ret &= FUNCTION ();}\
gettimeofday(&end, NULL);\ gettimeofday(&end, NULL);\
if (verbose) printf("%32s: %s ... %6.2f us/call\n", #FUNCTION, (ret)?"Pass":"Fail", \ if (verbose) printf("%32s: %s ... %6.2f us/call\n", #FUNCTION, (ret)?"Pass":"Fail", \
elapsed_us(&start, &end)/NOF_REPETITIONS);\ elapsed_us(&start, &end)/BLOCK_SIZE);\
passed &= ret;\ passed &= ret;\
} }
@ -373,6 +378,24 @@ bool test_mmse_solver_avx(void) {
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
bool test_vec_dot_prod_ccc(void) {
__attribute__((aligned(256))) cf_t a[14];
__attribute__((aligned(256))) cf_t b[14];
cf_t res = 0, gold = 0;
for (int i = 0; i < 14; i++) {
a[i] = RANDOM_CF();
b[i] = RANDOM_CF();
}
res = srslte_vec_dot_prod_ccc(a, b, 14);
for (int i=0;i<14;i++) {
gold += a[i]*b[i];
}
return (cabsf(res - gold) < 1e-3);
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
bool passed = true; bool passed = true;
@ -405,6 +428,8 @@ int main(int argc, char **argv) {
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
} }
RUN_TEST(test_vec_dot_prod_ccc);
printf("%s!\n", (passed) ? "Ok" : "Failed"); printf("%s!\n", (passed) ? "Ok" : "Failed");
if (!passed) { if (!passed) {

@ -0,0 +1,800 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE 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.
*
* srsLTE 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <complex.h>
#include <stdbool.h>
#include <sys/time.h>
#include <memory.h>
#include <math.h>
#include "srslte/phy/utils/mat.h"
#include "srslte/phy/utils/simd.h"
#include "srslte/phy/utils/vector.h"
bool zf_solver = false;
bool mmse_solver = false;
bool verbose = false;
#define MAX_MSE (1e-3)
#define NOF_REPETITIONS (1024)
#define MAX_FUNCTIONS (64)
#define MAX_BLOCKS (16)
#define RANDOM_F() ((float)rand())/((float)RAND_MAX)
#define RANDOM_S() ((int16_t)(rand() && 0x800F))
#define RANDOM_CF() (RANDOM_F() + _Complex_I*RANDOM_F())
#define TEST_CALL(TEST_CODE) gettimeofday(&start, NULL);\
for (int i = 0; i < NOF_REPETITIONS; i++){TEST_CODE;}\
gettimeofday(&end, NULL); \
*timing = elapsed_us(&start, &end);
#define TEST(X, CODE) static bool test_##X (char *func_name, double *timing, uint32_t block_size) {\
struct timeval start, end;\
float mse = 0.0f;\
bool passed;\
strncpy(func_name, #X, 32);\
CODE;\
passed = (mse < MAX_MSE);\
printf("%32s (%5d) ... %7.1f MSamp/s ... %3s Passed\n", func_name, block_size, \
(double) block_size*NOF_REPETITIONS/ *timing, passed?"":"Not");\
return passed;\
}
#define MALLOC(TYPE, NAME) TYPE *NAME = malloc(sizeof(TYPE)*block_size)
static double elapsed_us(struct timeval *ts_start, struct timeval *ts_end) {
if (ts_end->tv_usec > ts_start->tv_usec) {
return ((double) ts_end->tv_sec - (double) ts_start->tv_sec) * 1000000 +
(double) ts_end->tv_usec - (double) ts_start->tv_usec;
} else {
return ((double) ts_end->tv_sec - (double) ts_start->tv_sec - 1) * 1000000 +
((double) ts_end->tv_usec + 1000000) - (double) ts_start->tv_usec;
}
}
float squared_error (cf_t a, cf_t b) {
float diff_re = __real__ a - __real__ b;
float diff_im = __imag__ a - __imag__ b;
return diff_re*diff_re + diff_im*diff_im;
}
TEST(srslte_vec_acc_ff,
MALLOC(float, x);
float z;
cf_t gold = 0.0f;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_F();
}
TEST_CALL(z = srslte_vec_acc_ff(x, block_size))
for (int i = 0; i < block_size; i++) {
gold += x[i];
}
mse += fabs(gold - z) / gold;
free(x);
)
TEST(srslte_vec_dot_prod_sss,
MALLOC(int16_t, x);
MALLOC(int16_t, y);
int16_t z;
cf_t gold = 0.0f;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_S();
y[i] = RANDOM_S();
}
TEST_CALL(z = srslte_vec_dot_prod_sss(x, y, block_size))
for (int i = 0; i < block_size; i++) {
gold += x[i] * y[i];
}
mse += cabsf(gold - z) / cabsf(gold);
free(x);
free(y);
)
TEST(srslte_vec_sum_sss,
MALLOC(int16_t, x);
MALLOC(int16_t, y);
MALLOC(int16_t, z);
cf_t gold = 0.0f;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_S();
y[i] = RANDOM_S();
}
TEST_CALL(srslte_vec_sum_sss(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] + y[i];
mse += cabsf(gold - z[i]);
}
free(x);
free(y);
free(z);
)
TEST(srslte_vec_sub_sss,
MALLOC(int16_t, x);
MALLOC(int16_t, y);
MALLOC(int16_t, z);
cf_t gold = 0.0f;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_S();
y[i] = RANDOM_S();
}
TEST_CALL(srslte_vec_sub_sss(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] - y[i];
mse += cabsf(gold - z[i]);
}
free(x);
free(y);
free(z);
)
TEST(srslte_vec_prod_sss,
MALLOC(int16_t, x);
MALLOC(int16_t, y);
MALLOC(int16_t, z);
cf_t gold = 0.0f;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_S();
y[i] = RANDOM_S();
}
TEST_CALL(srslte_vec_prod_sss(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] * y[i];
mse += cabsf(gold - z[i]);
}
free(x);
free(y);
free(z);
)
TEST(srslte_vec_acc_cc,
MALLOC(cf_t, x);
cf_t z;
cf_t gold = 0.0f;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_F();
}
TEST_CALL(z = srslte_vec_acc_cc(x, block_size))
for (int i = 0; i < block_size; i++) {
gold += x[i];
}
mse += cabsf(gold - z)/cabsf(gold);
free(x);
)
TEST(srslte_vec_sum_fff,
MALLOC(float, x);
MALLOC(float, y);
MALLOC(float, z);
cf_t gold = 0.0f;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_F();
y[i] = RANDOM_F();
}
TEST_CALL(srslte_vec_sum_fff(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] + y[i];
mse += cabsf(gold - z[i]);
}
free(x);
free(y);
)
TEST(srslte_vec_sub_fff,
MALLOC(float, x);
MALLOC(float, y);
MALLOC(float, z);
cf_t gold = 0.0f;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_F();
y[i] = RANDOM_F();
}
TEST_CALL(srslte_vec_sub_fff(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] - y[i];
mse += cabsf(gold - z[i]);
}
free(x);
free(y);
)
TEST(srslte_vec_dot_prod_ccc,
MALLOC(cf_t, x);
MALLOC(cf_t, y);
cf_t z;
cf_t gold = 0.0f;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
y[i] = RANDOM_CF();
}
TEST_CALL(z = srslte_vec_dot_prod_ccc(x, y, block_size))
for (int i = 0; i < block_size; i++) {
gold += x[i] * y[i];
}
mse = cabsf(gold - z) / cabsf(gold);
free(x);
free(y);
)
TEST(srslte_vec_dot_prod_conj_ccc,
MALLOC(cf_t, x);
MALLOC(cf_t, y);
cf_t z;
cf_t gold = 0.0f;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
y[i] = RANDOM_CF();
}
TEST_CALL(z = srslte_vec_dot_prod_conj_ccc(x, y, block_size))
for (int i = 0; i < block_size; i++) {
gold += x[i] * conjf(y[i]);
}
mse = cabsf(gold - z) / cabsf(gold);
free(x);
free(y);
)
TEST(srslte_vec_prod_ccc,
MALLOC(cf_t, x);
MALLOC(cf_t, y);
MALLOC(cf_t, z);
cf_t gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
y[i] = RANDOM_CF();
}
TEST_CALL(srslte_vec_prod_ccc(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] * y[i];
mse += cabsf(gold - z[i]);
}
free(x);
free(z);
)
TEST(srslte_vec_prod_ccc_split,
MALLOC(float, x_re);
MALLOC(float, x_im);
MALLOC(float, y_re);
MALLOC(float, y_im);
MALLOC(float, z_re);
MALLOC(float, z_im);
cf_t gold;
for (int i = 0; i < block_size; i++) {
x_re[i] = RANDOM_F();
x_im[i] = RANDOM_F();
y_re[i] = RANDOM_F();
y_im[i] = RANDOM_F();
}
TEST_CALL(srslte_vec_prod_ccc_split(x_re, x_im, y_re, y_im, z_re, z_im, block_size))
for (int i = 0; i < block_size; i++) {
gold = (x_re[i] + I * x_im[i]) * (y_re[i] + I * y_im[i]);
mse += cabsf(gold - (z_re[i] + I*z_im[i]));
}
free(x_re);
free(x_im);
free(y_re);
free(y_im);
free(z_re);
free(z_im);
)
TEST(srslte_vec_prod_conj_ccc,
MALLOC(cf_t, x);
MALLOC(cf_t, y);
MALLOC(cf_t, z);
cf_t gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
y[i] = RANDOM_CF();
}
TEST_CALL(srslte_vec_prod_conj_ccc(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] * conjf(y[i]);
mse += cabsf(gold - z[i]);
}
free(x);
free(z);
)
TEST(srslte_vec_sc_prod_ccc,
MALLOC(cf_t, x);
MALLOC(cf_t, z);
cf_t y = RANDOM_CF();
cf_t gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
}
TEST_CALL(srslte_vec_sc_prod_ccc(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] * y;
mse += cabsf(gold - z[i]);
}
free(x);
free(z);
)
TEST(srslte_vec_convert_fi,
MALLOC(float, x);
MALLOC(short, z);
float scale = 1000.0f;
short gold;
for (int i = 0; i < block_size; i++) {
x[i] = (float) RANDOM_F();
}
TEST_CALL(srslte_vec_convert_fi(x, z, scale, block_size))
for (int i = 0; i < block_size; i++) {
gold = (short) ((x[i] * scale));
mse += cabsf((float)gold - (float) z[i]);
}
free(x);
free(z);
)
TEST(srslte_vec_prod_fff,
MALLOC(float, x);
MALLOC(float, y);
MALLOC(float, z);
cf_t gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
y[i] = RANDOM_CF();
}
TEST_CALL(srslte_vec_prod_fff(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] * y[i];
mse += cabsf(gold - z[i]);
}
free(x);
free(y);
free(z);
)
TEST(srslte_vec_prod_cfc,
MALLOC(cf_t, x);
MALLOC(float, y);
MALLOC(cf_t, z);
cf_t gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
y[i] = RANDOM_F();
}
TEST_CALL(srslte_vec_prod_cfc(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] * y[i];
mse += cabsf(gold - z[i]);
}
free(x);
free(y);
free(z);
)
TEST(srslte_vec_sc_prod_fff,
MALLOC(float, x);
MALLOC(float, z);
float y = RANDOM_F();
float gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
}
TEST_CALL(srslte_vec_sc_prod_fff(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] * y;
mse += cabsf(gold - z[i]);
}
free(x);
free(z);
)
TEST(srslte_vec_abs_cf,
MALLOC(cf_t, x);
MALLOC(float, z);
float gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
}
TEST_CALL(srslte_vec_abs_cf(x, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = sqrtf(crealf(x[i]) * crealf(x[i]) + cimagf(x[i])*cimagf(x[i]));
mse += cabsf(gold - z[i]);
}
free(x);
free(z);
)
TEST(srslte_vec_abs_square_cf,
MALLOC(cf_t, x);
MALLOC(float, z);
float gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
}
TEST_CALL(srslte_vec_abs_square_cf(x, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = crealf(x[i]) * crealf(x[i]) + cimagf(x[i])*cimagf(x[i]);
mse += cabsf(gold - z[i]);
}
free(x);
free(z);
)
TEST(srslte_vec_sc_prod_cfc,
MALLOC(cf_t, x);
MALLOC(cf_t, z);
cf_t gold;
float h = RANDOM_F();
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
}
TEST_CALL(srslte_vec_sc_prod_cfc(x, h, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] * h;
mse += cabsf(gold - z[i]);
}
free(x);
free(z);
)
TEST(srslte_vec_div_ccc,
MALLOC(cf_t, x);
MALLOC(cf_t, y);
MALLOC(cf_t, z);
cf_t gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
y[i] = RANDOM_CF();
}
TEST_CALL(srslte_vec_div_ccc(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] / y[i];
mse += cabsf(gold - z[i]);
}
mse /= block_size;
free(x);
free(y);
free(z);
)
TEST(srslte_vec_div_cfc,
MALLOC(cf_t, x);
MALLOC(float, y);
MALLOC(cf_t, z);
cf_t gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
y[i] = RANDOM_F();
}
TEST_CALL(srslte_vec_div_cfc(x, y, z, block_size))
for (int i = 0; i < block_size; i++) {
gold = x[i] / y[i];
mse += cabsf(gold - z[i])/cabsf(gold);
}
mse /= block_size;
free(x);
free(y);
free(z);
)
TEST(srslte_vec_div_fff,
MALLOC(float, x);
MALLOC(float, y);
MALLOC(float, z);
cf_t gold;
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_F();
y[i] = RANDOM_F();
}
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 /= block_size;
free(x);
free(y);
free(z);
)
TEST(srslte_vec_max_fi,
MALLOC(float, x);
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_F();
}
uint32_t max_index = 0;
TEST_CALL(max_index = srslte_vec_max_fi(x, block_size);)
float gold_value = -INFINITY;
uint32_t gold_index = 0;
for (int i = 0; i < block_size; i++) {
if (gold_value < x[i]) {
gold_value = x[i];
gold_index = i;
}
}
mse = (gold_index != max_index) ? 1:0;
free(x);
)
TEST(srslte_vec_max_abs_ci,
MALLOC(cf_t, x);
for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF();
}
uint32_t max_index = 0;
TEST_CALL(max_index = srslte_vec_max_abs_ci(x, block_size);)
float gold_value = -INFINITY;
uint32_t gold_index = 0;
for (int i = 0; i < block_size; i++) {
cf_t a = x[i];
float abs2 = __real__ a * __real__ a + __imag__ a * __imag__ a;
if (abs2 > gold_value) {
gold_value = abs2;
gold_index = (uint32_t)i;
}
}
mse = (gold_index != max_index) ? 1:0;
free(x);
)
int main(int argc, char **argv) {
char func_names[MAX_FUNCTIONS][32];
double timmings[MAX_FUNCTIONS][MAX_BLOCKS];
uint32_t sizes[32];
uint32_t size_count = 0;
uint32_t func_count = 0;
bool passed[MAX_FUNCTIONS][MAX_BLOCKS];
bool all_passed = true;
for (uint32_t block_size = 1; block_size <= 1024*8; block_size *= 2) {
func_count = 0;
passed[func_count][size_count] = test_srslte_vec_acc_ff(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_dot_prod_sss(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_sum_sss(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_sub_sss(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_prod_sss(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_acc_cc(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_sum_fff(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_sub_fff(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_dot_prod_ccc(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_dot_prod_conj_ccc(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
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_prod_fff(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_prod_cfc(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_prod_ccc(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_prod_ccc_split(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_prod_conj_ccc(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_sc_prod_ccc(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_sc_prod_fff(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_abs_cf(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_abs_square_cf(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_sc_prod_cfc(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_div_ccc(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_div_cfc(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_div_fff(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_max_fi(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
passed[func_count][size_count] = test_srslte_vec_max_abs_ci(func_names[func_count], &timmings[func_count][size_count], block_size);
func_count++;
sizes[size_count] = block_size;
size_count++;
}
printf("\n");
printf("%32s |", "Subroutine/MSps");
for (int i = 0; i < size_count; i++) {
printf(" %7d", sizes[i]);
}
printf(" |\n");
for (int j = 0; j < 32; j++) {
printf("-");
}
printf("-+-");
for (int j = 0; j < size_count; j++) {
printf("--------");
}
printf("-|\n");
for (int i = 0; i < func_count; i++) {
printf("%32s | ", func_names[i]);
for (int j = 0; j < size_count; j++) {
printf(" %s%7.1f\x1b[0m", (passed[i][j])?"":"\x1B[31m", (double) NOF_REPETITIONS*(double)sizes[j]/timmings[i][j]);
all_passed &= passed[i][j];
}
printf(" |\n");
}
return (all_passed)?SRSLTE_SUCCESS:SRSLTE_ERROR;
}

@ -36,49 +36,10 @@
#include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/bit.h"
#ifdef LV_HAVE_SSE
#include <smmintrin.h>
#endif
#ifdef LV_HAVE_AVX
#include <immintrin.h>
#endif
#ifdef HAVE_VOLK
#include "volk/volk.h"
#endif
#ifdef DEBUG_MODE
#warning FIXME: Disabling SSE/AVX vector code
#undef LV_HAVE_SSE
#undef LV_HAVE_AVX
#endif
int srslte_vec_acc_ii(int *x, uint32_t len) {
int i;
int z=0;
for (i=0;i<len;i++) {
z+=x[i];
}
return z;
}
// Used in PRACH detector, AGC and chest_dl for noise averaging // Used in PRACH detector, AGC and chest_dl for noise averaging
float srslte_vec_acc_ff(float *x, uint32_t len) { float srslte_vec_acc_ff(float *x, uint32_t len) {
#ifdef HAVE_VOLK_ACC_FUNCTION return srslte_vec_acc_ff_simd(x, len);
float result;
volk_32f_accumulator_s32f(&result,x,len);
return result;
#else
int i;
float z=0;
for (i=0;i<len;i++) {
z+=x[i];
}
return z;
#endif
} }
void srslte_vec_ema_filter(cf_t *new_data, cf_t *average, cf_t *output, float coeff, uint32_t len) { void srslte_vec_ema_filter(cf_t *new_data, cf_t *average, cf_t *output, float coeff, uint32_t len) {
@ -88,51 +49,15 @@ void srslte_vec_ema_filter(cf_t *new_data, cf_t *average, cf_t *output, float co
} }
cf_t srslte_vec_acc_cc(cf_t *x, uint32_t len) { cf_t srslte_vec_acc_cc(cf_t *x, uint32_t len) {
int i; return srslte_vec_acc_cc_simd(x, len);
cf_t z=0;
for (i=0;i<len;i++) {
z+=x[i];
}
return z;
}
void srslte_vec_square_dist(cf_t symbol, cf_t *points, float *distance, uint32_t npoints) {
uint32_t i;
cf_t diff;
for (i=0;i<npoints;i++) {
diff = symbol - points[i];
distance[i] = crealf(diff) * crealf(diff) + cimagf(diff) * cimagf(diff);
}
} }
void srslte_vec_sub_fff(float *x, float *y, float *z, uint32_t len) { void srslte_vec_sub_fff(float *x, float *y, float *z, uint32_t len) {
#ifndef LV_HAVE_SSE srslte_vec_sub_fff_simd(x, y, z, len);
int i;
for (i=0;i<len;i++) {
z[i] = x[i]-y[i];
}
#else
#ifdef LV_HAVE_AVX
srslte_vec_sub_fff_avx(x, y, z, len);
#else
srslte_vec_sub_fff_sse(x, y, z, len);
#endif
#endif
} }
void srslte_vec_sub_sss(short *x, short *y, short *z, uint32_t len) { void srslte_vec_sub_sss(int16_t *x, int16_t *y, int16_t *z, uint32_t len) {
#ifdef LV_HAVE_AVX2 srslte_vec_sub_sss_simd(x, y, z, len);
srslte_vec_sub_sss_avx2(x, y, z, len);
#else
#ifdef LV_HAVE_SSE
srslte_vec_sub_sss_sse(x, y, z, len);
#else
int i;
for (i=0;i<len;i++) {
z[i] = x[i]-y[i];
}
#endif
#endif
} }
// Noise estimation in chest_dl, interpolation // Noise estimation in chest_dl, interpolation
@ -142,142 +67,30 @@ void srslte_vec_sub_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len) {
// Used in PSS/SSS and sum_ccc // Used in PSS/SSS and sum_ccc
void srslte_vec_sum_fff(float *x, float *y, float *z, uint32_t len) { void srslte_vec_sum_fff(float *x, float *y, float *z, uint32_t len) {
#ifndef LV_HAVE_SSE srslte_vec_add_fff_simd(x, y, z, len);
int i;
for (i=0;i<len;i++) {
z[i] = x[i]+y[i];
}
#else
#ifdef LV_HAVE_AVX
srslte_vec_sum_fff_avx(x, y, z, len);
#else
srslte_vec_sum_fff_sse(x, y, z, len);
#endif
#endif
} }
void srslte_vec_sum_sss(short *x, short *y, short *z, uint32_t len) { void srslte_vec_sum_sss(int16_t *x, int16_t *y, int16_t *z, uint32_t len) {
#ifdef LV_HAVE_AVX2 srslte_vec_sum_sss_simd(x, y, z, len);
srslte_vec_sum_sss_avx2(x, y, z, len);
#else
#ifdef LV_HAVE_SSE
srslte_vec_sum_sss_sse(x, y, z, len);
#else
int i;
for (i=0;i<len;i++) {
z[i] = x[i]+y[i];
}
#endif
#endif
} }
void srslte_vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len) { void srslte_vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len) {
srslte_vec_sum_fff((float*) x,(float*) y,(float*) z,2*len); srslte_vec_sum_fff((float*) x,(float*) y,(float*) z,2*len);
} }
void srslte_vec_sum_bbb(uint8_t *x, uint8_t *y, uint8_t *z, uint32_t len) {
int i;
for (i=0;i<len;i++) {
z[i] = x[i]+y[i];
}
}
void srslte_vec_sc_add_fff(float *x, float h, float *z, uint32_t len) {
int i;
for (i=0;i<len;i++) {
z[i] = x[i]+h;
}
}
void srslte_vec_sc_add_cfc(cf_t *x, float h, cf_t *z, uint32_t len) {
int i;
for (i=0;i<len;i++) {
z[i] = x[i]+ h;
}
}
void srslte_vec_sc_add_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len) {
int i;
for (i=0;i<len;i++) {
z[i] = x[i]+ h;
}
}
void srslte_vec_sc_add_sss(int16_t *x, int16_t h, int16_t *z, uint32_t len) {
int i;
for (i=0;i<len;i++) {
z[i] = x[i]+ h;
}
}
// PSS, PBCH, DEMOD, FFTW, etc. // PSS, PBCH, DEMOD, FFTW, etc.
void srslte_vec_sc_prod_fff(float *x, float h, float *z, uint32_t len) { void srslte_vec_sc_prod_fff(float *x, float h, float *z, uint32_t len) {
#ifndef LV_HAVE_SSE srslte_vec_sc_prod_fff_simd(x, h, z, len);
int i;
for (i=0;i<len;i++) {
z[i] = x[i]*h;
}
#else
srslte_vec_sc_prod_fff_sse(x, h, z, len);
#endif
}
void srslte_vec_sc_prod_sfs(short *x, float h, short *z, uint32_t len) {
int i;
for (i=0;i<len;i++) {
z[i] = x[i]*h;
}
}
void srslte_vec_sc_div2_sss(short *x, int n_rightshift, short *z, uint32_t len) {
#ifdef LV_HAVE_AVX2
srslte_vec_sc_div2_sss_avx2(x, n_rightshift, z, len);
#else
#ifdef LV_HAVE_SSE
srslte_vec_sc_div2_sss_sse(x, n_rightshift, z, len);
#else
int i;
int pow2_div = 1<<n_rightshift;
for (i=0;i<len;i++) {
z[i] = x[i]/pow2_div;
}
#endif
#endif
}
// TODO: Improve this implementation
void srslte_vec_norm_cfc(cf_t *x, float amplitude, cf_t *y, uint32_t len) {
// We should use fabs() here but is statistically should be similar
float *xp = (float*) x;
uint32_t idx = srslte_vec_max_fi(xp, 2*len);
float max = xp[idx];
// Normalize before TX
srslte_vec_sc_prod_cfc(x, amplitude/max, y, len);
} }
// Used throughout // Used throughout
void srslte_vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len) { void srslte_vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len) {
#ifdef LV_HAVE_AVX srslte_vec_sc_prod_cfc_simd(x,h,z,len);
srslte_vec_sc_prod_cfc_avx(x,h,z,len);
#else
int i;
for (i=0;i<len;i++) {
z[i] = x[i]*h;
}
#endif
} }
// Chest UL // Chest UL
void srslte_vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len) { void srslte_vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len) {
#ifndef LV_HAVE_SSE srslte_vec_sc_prod_ccc_simd(x,h,z,len);
int i;
for (i=0;i<len;i++) {
z[i] = x[i]*h;
}
#else
srslte_vec_sc_prod_ccc_sse(x,h,z,len);
#endif
} }
// Used in turbo decoder // Used in turbo decoder
@ -288,79 +101,17 @@ void srslte_vec_convert_if(int16_t *x, float *z, float scale, uint32_t len) {
} }
} }
void srslte_vec_convert_ci(int8_t *x, int16_t *z, uint32_t len) {
int i;
for (i=0;i<len;i++) {
z[i] = ((int16_t) x[i]);
}
}
void srslte_vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len) { void srslte_vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len) {
#ifndef LV_HAVE_SSE srslte_vec_convert_fi_simd(x, z, scale, len);
int i;
for (i=0;i<len;i++) {
z[i] = (int16_t) (x[i]*scale);
}
#else
srslte_vec_convert_fi_sse(x, z, scale, len);
#endif
}
void srslte_vec_lut_fuf(float *x, uint32_t *lut, float *y, uint32_t len) {
for (int i=0;i<len;i++) {
y[lut[i]] = x[i];
}
} }
void srslte_vec_lut_sss(short *x, unsigned short *lut, short *y, uint32_t len) { void srslte_vec_lut_sss(short *x, unsigned short *lut, short *y, uint32_t len) {
#ifndef LV_HAVE_SSE srslte_vec_lut_sss_simd(x, lut, y, len);
for (int i=0;i<len;i++) {
y[lut[i]] = x[i];
}
#else
srslte_vec_lut_sss_sse(x, lut, y, len);
#endif
}
void srslte_vec_interleave_cf(float *real, float *imag, cf_t *x, uint32_t len) {
#ifdef HAVE_VOLK_INTERLEAVE_FUNCTION
volk_32f_x2_interleave_32fc(x, real, imag, len);
#else
int i;
for (i=0;i<len;i++) {
x[i] = real[i] + _Complex_I*imag[i];
}
#endif
} }
void srslte_vec_deinterleave_cf(cf_t *x, float *real, float *imag, uint32_t len) {
#ifdef HAVE_VOLK_DEINTERLEAVE_FUNCTION
volk_32fc_deinterleave_32f_x2(real, imag, x, len);
#else
int i;
for (i=0;i<len;i++) {
real[i] = __real__ x[i];
imag[i] = __imag__ x[i];
}
#endif
}
void srslte_vec_deinterleave_real_cf(cf_t *x, float *real, uint32_t len) {
int i;
for (i=0;i<len;i++) {
real[i] = __real__ x[i];
}
}
/* Note: We align memory to 32 bytes (for AVX2 compatibility)
* because in some cases volk can incorrectly detect the architecture.
* This could be inefficient for SSE or non-SIMD platforms but shouldn't
* be a huge problem.
*/
void *srslte_vec_malloc(uint32_t size) { void *srslte_vec_malloc(uint32_t size) {
void *ptr; void *ptr;
if (posix_memalign(&ptr,256,size)) { if (posix_memalign(&ptr, SRSLTE_SIMD_BIT_ALIGN, size)) {
return NULL; return NULL;
} else { } else {
return ptr; return ptr;
@ -372,7 +123,7 @@ void *srslte_vec_realloc(void *ptr, uint32_t old_size, uint32_t new_size) {
return realloc(ptr, new_size); return realloc(ptr, new_size);
#else #else
void *new_ptr; void *new_ptr;
if (posix_memalign(&new_ptr,256,new_size)) { if (posix_memalign(&new_ptr, SRSLTE_SIMD_BIT_ALIGN, new_size)) {
return NULL; return NULL;
} else { } else {
memcpy(new_ptr, ptr, old_size); memcpy(new_ptr, ptr, old_size);
@ -495,6 +246,7 @@ void srslte_vec_load_file(char *filename, void *buffer, uint32_t len) {
// Used in PSS // Used in PSS
void srslte_vec_conj_cc(cf_t *x, cf_t *y, uint32_t len) { void srslte_vec_conj_cc(cf_t *x, cf_t *y, uint32_t len) {
/* This function is used in initialisation only, then no optimisation is required */
int i; int i;
for (i=0;i<len;i++) { for (i=0;i<len;i++) {
y[i] = conjf(x[i]); y[i] = conjf(x[i]);
@ -503,111 +255,52 @@ void srslte_vec_conj_cc(cf_t *x, cf_t *y, uint32_t len) {
// Used in scrambling complex // Used in scrambling complex
void srslte_vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len) { void srslte_vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len) {
int i; srslte_vec_prod_cfc_simd(x, y, z, len);
for (i=0;i<len;i++) {
z[i] = x[i]*y[i];
}
} }
// Used in scrambling float // Used in scrambling float
void srslte_vec_prod_fff(float *x, float *y, float *z, uint32_t len) { void srslte_vec_prod_fff(float *x, float *y, float *z, uint32_t len) {
int i; srslte_vec_prod_fff_simd(x, y, z, len);
for (i=0;i<len;i++) {
z[i] = x[i]*y[i];
}
} }
// Scrambling Short // Scrambling Short
void srslte_vec_prod_sss(short *x, short *y, short *z, uint32_t len) { void srslte_vec_prod_sss(int16_t *x, int16_t *y, int16_t *z, uint32_t len) {
#ifdef LV_HAVE_AVX2 srslte_vec_prod_sss_simd(x,y,z,len);
srslte_vec_prod_sss_avx2(x,y,z,len);
#else
#ifdef LV_HAVE_SSE
srslte_vec_prod_sss_sse(x,y,z,len);
#else
int i;
for (i=0;i<len;i++) {
z[i] = x[i]*y[i];
}
#endif
#endif
} }
// CFO and OFDM processing // CFO and OFDM processing
void srslte_vec_prod_ccc(cf_t *x,cf_t *y, cf_t *z, uint32_t len) { void srslte_vec_prod_ccc(cf_t *x,cf_t *y, cf_t *z, uint32_t len) {
#ifndef LV_HAVE_SSE srslte_vec_prod_ccc_simd(x,y,z,len);
int i; }
for (i=0;i<len;i++) {
z[i] = x[i]*y[i]; void srslte_vec_prod_ccc_split(float *x_re, float *x_im, float *y_re, float *y_im, float *z_re, float *z_im, uint32_t len) {
} srslte_vec_prod_ccc_split_simd(x_re, x_im, y_re , y_im, z_re,z_im, len);
#else
srslte_vec_prod_ccc_sse(x,y,z,len);
#endif
} }
// PRACH, CHEST UL, etc. // PRACH, CHEST UL, etc.
void srslte_vec_prod_conj_ccc(cf_t *x,cf_t *y, cf_t *z, uint32_t len) { void srslte_vec_prod_conj_ccc(cf_t *x,cf_t *y, cf_t *z, uint32_t len) {
#ifndef LV_HAVE_SSE srslte_vec_prod_conj_ccc_simd(x,y,z,len);
int i;
for (i=0;i<len;i++) {
z[i] = x[i]*conjf(y[i]);
}
#else
srslte_vec_prod_conj_ccc_sse(x,y,z,len);
#endif
} }
//#define DIV_USE_VEC //#define DIV_USE_VEC
// Used in SSS // Used in SSS
/* Complex division is conjugate multiplication + real division */ void srslte_vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len) {
void srslte_vec_div_ccc(cf_t *x, cf_t *y, float *y_mod, cf_t *z, float *z_real, float *z_imag, uint32_t len) { srslte_vec_div_ccc_simd(x, y, z, len);
#ifdef DIV_USE_VEC
srslte_vec_prod_conj_ccc(x,y,z,len);
srslte_vec_abs_square_cf(y,y_mod,len);
srslte_vec_div_cfc(z,y_mod,z,z_real,z_imag,len);
#else
int i;
for (i=0;i<len;i++) {
z[i] = x[i] / y[i];
}
#endif
} }
/* Complex division by float z=x/y */ /* Complex division by float z=x/y */
void srslte_vec_div_cfc(cf_t *x, float *y, cf_t *z, float *z_real, float *z_imag, uint32_t len) { void srslte_vec_div_cfc(cf_t *x, float *y, cf_t *z, uint32_t len) {
#ifdef DIV_USE_VEC srslte_vec_div_cfc_simd(x, y, z, len);
srslte_vec_deinterleave_cf(x, z_real, z_imag, len);
srslte_vec_div_fff(z_real, y, z_real, len);
srslte_vec_div_fff(z_imag, y, z_imag, len);
srslte_vec_interleave_cf(z_real, z_imag, z, len);
#else
int i;
for (i=0;i<len;i++) {
z[i] = x[i] / y[i];
}
#endif
} }
void srslte_vec_div_fff(float *x, float *y, float *z, uint32_t len) { void srslte_vec_div_fff(float *x, float *y, float *z, uint32_t len) {
int i; srslte_vec_div_fff_simd(x, y, z, len);
for (i=0;i<len;i++) {
z[i] = x[i] / y[i];
}
} }
// PSS. convolution // PSS. convolution
cf_t srslte_vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len) { cf_t srslte_vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len) {
#ifndef LV_HAVE_SSE return srslte_vec_dot_prod_ccc_simd(x, y, len);
uint32_t i;
cf_t res = 0;
for (i=0;i<len;i++) {
res += x[i]*y[i];
}
return res;
#else
return srslte_vec_dot_prod_ccc_sse(x, y, len);
#endif
} }
// Convolution filter and in SSS search // Convolution filter and in SSS search
@ -622,17 +315,7 @@ cf_t srslte_vec_dot_prod_cfc(cf_t *x, float *y, uint32_t len) {
// SYNC // SYNC
cf_t srslte_vec_dot_prod_conj_ccc(cf_t *x, cf_t *y, uint32_t len) { cf_t srslte_vec_dot_prod_conj_ccc(cf_t *x, cf_t *y, uint32_t len) {
#ifndef LV_HAVE_SSE return srslte_vec_dot_prod_conj_ccc_simd(x, y, len);
uint32_t i;
cf_t res = 0;
for (i=0;i<len;i++) {
res += x[i]*conjf(y[i]);
}
return res;
#else
return srslte_vec_dot_prod_conj_ccc_sse(x, y, len);
#endif
} }
// PHICH // PHICH
@ -646,20 +329,7 @@ float srslte_vec_dot_prod_fff(float *x, float *y, uint32_t len) {
} }
int32_t srslte_vec_dot_prod_sss(int16_t *x, int16_t *y, uint32_t len) { int32_t srslte_vec_dot_prod_sss(int16_t *x, int16_t *y, uint32_t len) {
#ifdef LV_HAVE_AVX2 return srslte_vec_dot_prod_sss_simd(x, y, len);
return srslte_vec_dot_prod_sss_avx2(x, y, len);
#else
#ifdef LV_HAVE_SSE
return srslte_vec_dot_prod_sss_sse(x, y, len);
#else
uint32_t i;
int32_t res = 0;
for (i=0;i<len;i++) {
res += x[i]*y[i];
}
return res;
#endif
#endif
} }
float srslte_vec_avg_power_cf(cf_t *x, uint32_t len) { float srslte_vec_avg_power_cf(cf_t *x, uint32_t len) {
@ -672,124 +342,26 @@ float srslte_vec_corr_ccc(cf_t *x, cf_t *y, uint32_t len) {
float s_x = crealf(srslte_vec_dot_prod_conj_ccc(x, x, len))/len; float s_x = crealf(srslte_vec_dot_prod_conj_ccc(x, x, len))/len;
float s_y = crealf(srslte_vec_dot_prod_conj_ccc(y, y, len))/len; float s_y = crealf(srslte_vec_dot_prod_conj_ccc(y, y, len))/len;
float cov = crealf(srslte_vec_dot_prod_conj_ccc(x, y, len))/len; float cov = crealf(srslte_vec_dot_prod_conj_ccc(x, y, len))/len;
return cov/(sqrt(s_x*s_y)); return cov/(sqrtf(s_x*s_y));
} }
// PSS (disabled and using abs_square ) // PSS (disabled and using abs_square )
void srslte_vec_abs_cf(cf_t *x, float *abs, uint32_t len) { void srslte_vec_abs_cf(cf_t *x, float *abs, uint32_t len) {
int i; srslte_vec_abs_cf_simd(x, abs, len);
for (i=0;i<len;i++) {
abs[i] = cabsf(x[i]);
}
} }
// PRACH // PRACH
void srslte_vec_abs_square_cf(cf_t *x, float *abs_square, uint32_t len) { void srslte_vec_abs_square_cf(cf_t *x, float *abs_square, uint32_t len) {
#ifndef LV_HAVE_SSE srslte_vec_abs_square_cf_simd(x,abs_square,len);
int i;
for (i=0;i<len;i++) {
abs_square[i] = crealf(x[i])*crealf(x[i])+cimagf(x[i])*cimagf(x[i]);
}
#else
srslte_vec_abs_square_cf_sse(x,abs_square,len);
#endif
}
void srslte_vec_arg_cf(cf_t *x, float *arg, uint32_t len) {
int i;
for (i=0;i<len;i++) {
arg[i] = cargf(x[i]);
}
} }
uint32_t srslte_vec_max_fi(float *x, uint32_t len) { uint32_t srslte_vec_max_fi(float *x, uint32_t len) {
return srslte_vec_max_fi_simd(x, len);
// This is to solve an issue with incorrect type of 1st parameter in version 1.2 of volk
#ifdef HAVE_VOLK_MAX_FUNCTION_32
uint32_t target=0;
volk_32f_index_max_32u(&target,x,len);
return target;
#else
#ifdef HAVE_VOLK_MAX_FUNCTION_16
uint32_t target=0;
volk_32f_index_max_16u(&target,x,len);
return target;
#else
uint32_t i;
float m=-FLT_MAX;
uint32_t p=0;
for (i=0;i<len;i++) {
if (x[i]>m) {
m=x[i];
p=i;
}
}
return p;
#endif
#endif
} }
int16_t srslte_vec_max_star_si(int16_t *x, uint32_t len) {
uint32_t i;
int16_t m=-INT16_MIN;
for (i=0;i<len;i++) {
if (x[i]>m) {
m=x[i];
}
}
return m;
}
int16_t srslte_vec_max_abs_star_si(int16_t *x, uint32_t len) {
uint32_t i;
int16_t m=-INT16_MIN;
for (i=0;i<len;i++) {
if (abs(x[i])>m) {
m=abs(x[i]);
}
}
return m;
}
void srslte_vec_max_fff(float *x, float *y, float *z, uint32_t len) {
uint32_t i;
for (i=0;i<len;i++) {
if (x[i] > y[i]) {
z[i] = x[i];
} else {
z[i] = y[i];
}
}
}
// CP autocorr // CP autocorr
uint32_t srslte_vec_max_abs_ci(cf_t *x, uint32_t len) { uint32_t srslte_vec_max_abs_ci(cf_t *x, uint32_t len) {
#ifdef HAVE_VOLK_MAX_ABS_FUNCTION_32 return srslte_vec_max_ci_simd(x, len);
uint32_t target=0;
volk_32fc_index_max_32u(&target,x,len);
return target;
#else
#ifdef HAVE_VOLK_MAX_ABS_FUNCTION_16
uint32_t target=0;
volk_32fc_index_max_16u(&target,x,len);
return target;
#else
uint32_t i;
float m=-FLT_MAX;
uint32_t p=0;
float tmp;
for (i=0;i<len;i++) {
tmp = crealf(x[i])*crealf(x[i]) + cimagf(x[i])*cimagf(x[i]);
if (tmp>m) {
m=tmp;
p=i;
}
}
return p;
#endif
#endif
} }
void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, float clip, uint32_t len) { void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, float clip, uint32_t len) {
@ -821,23 +393,5 @@ void srslte_vec_quant_suc(int16_t *in, uint8_t *out, float gain, int16_t offset,
} }
void srs_vec_cf_cpy(cf_t *dst, cf_t *src, int len) { void srs_vec_cf_cpy(cf_t *dst, cf_t *src, int len) {
int i = 0; srslte_vec_cp_simd(dst, src, len);
#ifdef LV_HAVE_AVX
for (; i < len - 3; i += 4) {
_mm256_store_ps((float *) &dst[i], _mm256_load_ps((float *) &src[i]));
}
#endif /* LV_HAVE_AVX */
#ifdef LV_HAVE_SSE
for (; i < len - 1; i += 2) {
_mm_store_ps((float *) &dst[i], _mm_load_ps((float *) &src[i]));
}
for (; i < len; i++) {
((__m64*) dst)[i] = ((__m64*) src)[i];
}
#else
for (; i < len; i++) {
dst[i] = src[i];
}
#endif /* LV_HAVE_SSE */
} }

File diff suppressed because it is too large Load Diff

@ -358,24 +358,8 @@ void radio::set_tx_srate(double srate)
} }
} else if (!strcmp(srslte_rf_name(&rf_device), "uhd_x300")) { } else if (!strcmp(srslte_rf_name(&rf_device), "uhd_x300")) {
double srate_khz = round(cur_tx_srate/1e3); // In X300 TX/RX offset is independent of sampling rate
if (srate_khz == 1.92e3) { nsamples = 45;
nsamples = 50;
} else if (srate_khz == 3.84e3) {
nsamples = 65;
} else if (srate_khz == 5.76e3) {
nsamples = 75;
} else if (srate_khz == 11.52e3) {
nsamples = 89;
} else if (srate_khz == 15.36e3) {
nsamples = 86;
} else if (srate_khz == 23.04e3) {
nsamples = 110;
} else {
/* Interpolate from known values */
printf("\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", cur_tx_srate);
nsamples = cur_tx_srate*(uhd_default_tx_adv_samples * (1/cur_tx_srate) + uhd_default_tx_adv_offset_sec);
}
} else if (!strcmp(srslte_rf_name(&rf_device), "bladerf")) { } else if (!strcmp(srslte_rf_name(&rf_device), "bladerf")) {
double srate_khz = round(cur_tx_srate/1e3); double srate_khz = round(cur_tx_srate/1e3);

@ -513,10 +513,10 @@ void rlc_um::reassemble_rx_sdus()
} }
// Handle last segment // Handle last segment
// Handle last segment if (rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES &&
if (rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES || rx_window[vr_ur].buf->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES &&
rx_window[vr_ur].buf->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES || rx_window[vr_ur].buf->N_bytes + rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES)
rx_window[vr_ur].buf->N_bytes + rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES) { {
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes);
rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes;

@ -46,6 +46,8 @@ drb_config = drb.conf
# rx_gain: Optional receive gain (dB). If disabled, AGC if enabled # rx_gain: Optional receive gain (dB). If disabled, AGC if enabled
# #
# Optional parameters: # Optional parameters:
# dl_freq: Override DL frequency corresponding to dl_earfcn
# ul_freq: Override UL frequency corresponding to dl_earfcn (must be set if dl_freq is set)
# device_name: Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF" # device_name: Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF"
# device_args: Arguments for the device driver. Options are "auto" or any string. # device_args: Arguments for the device driver. Options are "auto" or any string.
# Default for UHD: "recv_frame_size=9232,send_frame_size=9232" # Default for UHD: "recv_frame_size=9232,send_frame_size=9232"
@ -100,7 +102,7 @@ filename = /tmp/enb.pcap
# #
# filename: File path to use for log output. Can be set to stdout # filename: File path to use for log output. Can be set to stdout
# to print logs to standard output # to print logs to standard output
git c##################################################################### #####################################################################
[log] [log]
all_level = info all_level = info
all_hex_limit = 32 all_hex_limit = 32
@ -123,8 +125,8 @@ enable = false
#pdsch_mcs = -1 #pdsch_mcs = -1
#pdsch_max_mcs = -1 #pdsch_max_mcs = -1
#pusch_mcs = -1 #pusch_mcs = -1
#pusch_max_mcs = -1 pusch_max_mcs = 16
nof_ctrl_symbols = 2 nof_ctrl_symbols = 3
##################################################################### #####################################################################
# Expert configuration options # Expert configuration options

@ -113,9 +113,6 @@ public:
private: private:
void log_step_ul(uint32_t tti);
void log_step_dl(uint32_t tti);
static const int MAX_LOCATIONS = 20; static const int MAX_LOCATIONS = 20;
static const uint32_t cfi = 3; static const uint32_t cfi = 3;
srslte_dci_location_t locations[MAX_LOCATIONS]; srslte_dci_location_t locations[MAX_LOCATIONS];

@ -42,7 +42,6 @@ public:
// used by sched_metric // used by sched_metric
uint32_t ue_idx; uint32_t ue_idx;
bool has_pusch;
bool has_pucch; bool has_pucch;
typedef struct { typedef struct {
@ -116,7 +115,7 @@ public:
bool needs_cqi(uint32_t tti, bool will_send = false); bool needs_cqi(uint32_t tti, bool will_send = false);
uint32_t get_max_retx(); uint32_t get_max_retx();
bool get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32_t *L); bool get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2]);
bool pucch_sr_collision(uint32_t current_tti, uint32_t n_cce); bool pucch_sr_collision(uint32_t current_tti, uint32_t n_cce);
uint32_t get_pending_ul_old_data(); uint32_t get_pending_ul_old_data();
@ -173,7 +172,7 @@ private:
// Allowed DCI locations per CFI and per subframe // Allowed DCI locations per CFI and per subframe
sched_dci_cce_t dci_locations[3][10]; sched_dci_cce_t dci_locations[3][10];
const static int SCHED_MAX_HARQ_PROC = 8; const static int SCHED_MAX_HARQ_PROC = 2*HARQ_DELAY_MS;
dl_harq_proc dl_harq[SCHED_MAX_HARQ_PROC]; dl_harq_proc dl_harq[SCHED_MAX_HARQ_PROC];
ul_harq_proc ul_harq[SCHED_MAX_HARQ_PROC]; ul_harq_proc ul_harq[SCHED_MAX_HARQ_PROC];

@ -120,7 +120,7 @@ private:
uint32_t nof_failures; uint32_t nof_failures;
const static int NOF_HARQ_PROCESSES = 8; const static int NOF_HARQ_PROCESSES = 2*HARQ_DELAY_MS;
srslte_softbuffer_tx_t softbuffer_tx[NOF_HARQ_PROCESSES]; srslte_softbuffer_tx_t softbuffer_tx[NOF_HARQ_PROCESSES];
srslte_softbuffer_rx_t softbuffer_rx[NOF_HARQ_PROCESSES]; srslte_softbuffer_rx_t softbuffer_rx[NOF_HARQ_PROCESSES];

@ -78,13 +78,13 @@ public:
mac_interface_phy *mac; mac_interface_phy *mac;
// Common objects for schedulign grants // Common objects for schedulign grants
mac_interface_phy::ul_sched_t ul_grants[10]; mac_interface_phy::ul_sched_t ul_grants[TTIMOD_SZ];
mac_interface_phy::dl_sched_t dl_grants[10]; mac_interface_phy::dl_sched_t dl_grants[TTIMOD_SZ];
// Map of pending ACKs for each user // Map of pending ACKs for each user
typedef struct { typedef struct {
bool is_pending[10]; bool is_pending[TTIMOD_SZ];
uint16_t n_pdcch[10]; uint16_t n_pdcch[TTIMOD_SZ];
} pending_ack_t; } pending_ack_t;
std::map<uint16_t,pending_ack_t> pending_ack; std::map<uint16_t,pending_ack_t> pending_ack;

@ -73,12 +73,12 @@ private:
void work_imp(); void work_imp();
int encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants, uint32_t sf_idx); int encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants);
int decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch, uint32_t tti_rx); int decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch);
int encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks, uint32_t sf_idx); int encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks);
int encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants, uint32_t sf_idx); int encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants);
int encode_pdcch_ul(srslte_enb_ul_pusch_t *grants, uint32_t nof_grants, uint32_t sf_idx); int encode_pdcch_ul(srslte_enb_ul_pusch_t *grants, uint32_t nof_grants);
int decode_pucch(uint32_t tti_rx); int decode_pucch();
/* Common objects */ /* Common objects */
@ -89,8 +89,9 @@ private:
cf_t *signal_buffer_rx; cf_t *signal_buffer_rx;
cf_t *signal_buffer_tx; cf_t *signal_buffer_tx;
uint32_t tti_rx, tti_tx, tti_sched_ul, sf_rx, sf_tx, sf_sched_ul, tx_mutex_cnt; uint32_t tti_rx, tti_tx_dl, tti_tx_ul;
uint32_t sf_rx, sf_tx, tx_mutex_cnt;
uint32_t t_rx, t_tx_dl, t_tx_ul;
srslte_enb_dl_t enb_dl; srslte_enb_dl_t enb_dl;
srslte_enb_ul_t enb_ul; srslte_enb_ul_t enb_ul;

@ -75,7 +75,7 @@ public:
void stop(); void stop();
// gtpu_interface_rrc // gtpu_interface_rrc
void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in); void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in);
void rem_bearer(uint16_t rnti, uint32_t lcid); void rem_bearer(uint16_t rnti, uint32_t lcid);
void rem_user(uint16_t rnti); void rem_user(uint16_t rnti);
@ -98,11 +98,13 @@ private:
typedef struct{ typedef struct{
uint32_t teids_in[SRSENB_N_RADIO_BEARERS]; uint32_t teids_in[SRSENB_N_RADIO_BEARERS];
uint32_t teids_out[SRSENB_N_RADIO_BEARERS]; uint32_t teids_out[SRSENB_N_RADIO_BEARERS];
uint32_t spgw_addrs[SRSENB_N_RADIO_BEARERS];
}bearer_map; }bearer_map;
std::map<uint16_t, bearer_map> rnti_bearers; std::map<uint16_t, bearer_map> rnti_bearers;
srslte_netsink_t snk; // Socket file descriptors
srslte_netsource_t src; int snk_fd;
int src_fd;
void run_thread(); void run_thread();

@ -195,6 +195,9 @@ public:
bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e); bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e);
bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e); bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e);
void setup_erab(uint8_t id, LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *qos,
LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *addr, uint32_t teid_out,
LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu);
bool release_erabs(); bool release_erabs();
void notify_s1ap_ue_ctxt_setup_complete(); void notify_s1ap_ue_ctxt_setup_complete();

@ -403,7 +403,7 @@ int mac::rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv)
int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
{ {
log_step_dl(tti); log_h->step(tti);
if (!started) { if (!started) {
return 0; return 0;
@ -545,7 +545,7 @@ uint8_t* mac::assemble_si(uint32_t index)
int mac::get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res) int mac::get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res)
{ {
log_step_ul(tti); log_h->step(tti);
if (!started) { if (!started) {
return 0; return 0;
@ -602,24 +602,6 @@ int mac::get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res)
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
void mac::log_step_ul(uint32_t tti)
{
int tti_ul = tti-8;
if (tti_ul < 0) {
tti_ul += 10240;
}
log_h->step(tti_ul);
}
void mac::log_step_dl(uint32_t tti)
{
int tti_dl = tti-4;
if (tti_dl < 0) {
tti_dl += 10240;
}
log_h->step(tti_dl);
}
void mac::tti_clock() void mac::tti_clock()
{ {
timers_thread.tti_clock(); timers_thread.tti_clock();

@ -541,7 +541,7 @@ int sched::dl_sched_rar(dl_sched_rar_t rar[MAX_RAR_LIST])
pending_rar[j].rar_tti = 0; pending_rar[j].rar_tti = 0;
// Save UL resources // Save UL resources
uint32_t pending_tti=(current_tti+6)%10; uint32_t pending_tti=(current_tti+MSG3_DELAY_MS+HARQ_DELAY_MS)%10;
pending_msg3[pending_tti].enabled = true; pending_msg3[pending_tti].enabled = true;
pending_msg3[pending_tti].rnti = pending_rar[j].rnti; pending_msg3[pending_tti].rnti = pending_rar[j].rnti;
pending_msg3[pending_tti].L = L_prb; pending_msg3[pending_tti].L = L_prb;
@ -619,6 +619,7 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST])
tbs, user->get_pending_dl_new_data(current_tti)); tbs, user->get_pending_dl_new_data(current_tti));
} }
} else { } else {
h->reset();
Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d\n", rnti, h->get_id()); Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d\n", rnti, h->get_id());
} }
} }
@ -677,17 +678,17 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
/* If dl_sched() not yet called this tti (this tti is +4ms advanced), reset CCE state */ /* If dl_sched() not yet called this tti (this tti is +4ms advanced), reset CCE state */
if ((current_tti+4)%10240 != tti) { if (TTI_TX(current_tti) != tti) {
bzero(used_cce, MAX_CCE*sizeof(bool)); bzero(used_cce, MAX_CCE*sizeof(bool));
} }
/* Initialize variables */ /* Initialize variables */
current_tti = tti; current_tti = tti;
sfn = tti/10; sfn = tti/10;
if (tti > 4) { if (tti > HARQ_DELAY_MS) {
sf_idx = (tti-4)%10; sf_idx = (tti-HARQ_DELAY_MS)%10;
} else { } else {
sf_idx = (tti+10240-4)%10; sf_idx = (tti+10240-HARQ_DELAY_MS)%10;
} }
int nof_dci_elems = 0; int nof_dci_elems = 0;
int nof_phich_elems = 0; int nof_phich_elems = 0;
@ -700,7 +701,6 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
sched_ue *user = (sched_ue*) &iter->second; sched_ue *user = (sched_ue*) &iter->second;
uint16_t rnti = (uint16_t) iter->first; uint16_t rnti = (uint16_t) iter->first;
user->has_pusch = false;
user->has_pucch = false; user->has_pucch = false;
ul_harq_proc *h = user->get_ul_harq(current_tti); ul_harq_proc *h = user->get_ul_harq(current_tti);
@ -726,18 +726,15 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
sched_ue *user = (sched_ue*) &iter->second; sched_ue *user = (sched_ue*) &iter->second;
uint16_t rnti = (uint16_t) iter->first; uint16_t rnti = (uint16_t) iter->first;
uint32_t prb_idx[2] = {0, 0}; uint32_t prb_idx[2] = {0, 0};
uint32_t L = 0; if (user->get_pucch_sched(current_tti, prb_idx)) {
if (user->get_pucch_sched(current_tti, prb_idx, &L)) {
user->has_pucch = true; user->has_pucch = true;
// allocate PUCCH if no PUSCH for user // allocate PUCCH
if (!user->has_pusch) {
for (int i=0;i<2;i++) { for (int i=0;i<2;i++) {
ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], L}; ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], 1};
ul_metric->update_allocation(pucch); ul_metric->update_allocation(pucch);
} }
} }
} }
}
// Now allocate PUSCH // Now allocate PUSCH
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
@ -786,6 +783,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
user->get_locations(current_cfi, sf_idx), user->get_locations(current_cfi, sf_idx),
aggr_level)) aggr_level))
{ {
h->reset();
log_h->warning("SCHED: Could not schedule UL DCI rnti=0x%x, pid=%d, L=%d\n", log_h->warning("SCHED: Could not schedule UL DCI rnti=0x%x, pid=%d, L=%d\n",
rnti, h->get_id(), aggr_level); rnti, h->get_id(), aggr_level);
sched_result->pusch[nof_dci_elems].needs_pdcch = false; sched_result->pusch[nof_dci_elems].needs_pdcch = false;
@ -807,22 +805,22 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
user->unset_sr(); user->unset_sr();
} }
log_h->info("SCHED: %s %s rnti=0x%x, pid=%d, dci=%d,%d, grant=%d,%d, n_rtx=%d, tbs=%d, bsr=%d (%d-%d)\n", log_h->info("SCHED: %s %s rnti=0x%x, pid=%d, dci=%d,%d, grant=(%d,%d), n_rtx=%d, tbs=%d, bsr=%d (%d-%d)\n",
is_rar?"RAR":"UL", is_rar?"RAR":"UL",
is_newtx?"tx":"retx", is_newtx?"tx":"retx",
rnti, h->get_id(), rnti, h->get_id(),
sched_result->pusch[nof_dci_elems].dci_location.L, sched_result->pusch[nof_dci_elems].dci_location.ncce, sched_result->pusch[nof_dci_elems].dci_location.L, sched_result->pusch[nof_dci_elems].dci_location.ncce,
alloc.RB_start, alloc.L, h->nof_retx(), sched_result->pusch[nof_dci_elems].tbs, alloc.RB_start, alloc.RB_start+alloc.L, h->nof_retx(), sched_result->pusch[nof_dci_elems].tbs,
user->get_pending_ul_new_data(current_tti),pending_data_before, user->get_pending_ul_old_data()); user->get_pending_ul_new_data(current_tti),pending_data_before, user->get_pending_ul_old_data());
nof_dci_elems++; nof_dci_elems++;
} else { } else {
log_h->warning("SCHED: Error %s %s rnti=0x%x, pid=%d, dci=%d,%d, grant=%d,%d, tbs=%d, bsr=%d\n", log_h->warning("SCHED: Error %s %s rnti=0x%x, pid=%d, dci=%d,%d, grant=(%d,%d), tbs=%d, bsr=%d\n",
is_rar?"RAR":"UL", is_rar?"RAR":"UL",
is_newtx?"tx":"retx", is_newtx?"tx":"retx",
rnti, h->get_id(), rnti, h->get_id(),
sched_result->pusch[nof_dci_elems].dci_location.L, sched_result->pusch[nof_dci_elems].dci_location.ncce, sched_result->pusch[nof_dci_elems].dci_location.L, sched_result->pusch[nof_dci_elems].dci_location.ncce,
alloc.RB_start, alloc.L, sched_result->pusch[nof_dci_elems].tbs, alloc.RB_start, alloc.RB_start+alloc.L, sched_result->pusch[nof_dci_elems].tbs,
user->get_pending_ul_new_data(current_tti)); user->get_pending_ul_new_data(current_tti));
} }
} }

@ -177,7 +177,7 @@ void dl_harq_proc::set_rbgmask(uint32_t new_mask)
bool dl_harq_proc::has_pending_retx(uint32_t current_tti) bool dl_harq_proc::has_pending_retx(uint32_t current_tti)
{ {
return srslte_tti_interval(current_tti, tti) >= 8 && has_pending_retx_common(); return srslte_tti_interval(current_tti, tti) >= (2*HARQ_DELAY_MS) && has_pending_retx_common();
} }
int dl_harq_proc::get_tbs() int dl_harq_proc::get_tbs()

@ -25,8 +25,7 @@
*/ */
#include <string.h> #include <string.h>
#include "mac/scheduler_harq.h"
#include "srslte/srslte.h"
#include "mac/scheduler_metric.h" #include "mac/scheduler_metric.h"
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) #define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
@ -143,7 +142,11 @@ dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user)
dl_harq_proc *h = user->get_pending_dl_harq(current_tti); dl_harq_proc *h = user->get_pending_dl_harq(current_tti);
// Time-domain RR scheduling // Time-domain RR scheduling
#if ASYNC_DL_SCHED
if (pending_data || h) { if (pending_data || h) {
#else
if (pending_data || (h && !h->is_empty())) {
#endif
if (nof_users_with_data) { if (nof_users_with_data) {
if (nof_users_with_data == 2) { if (nof_users_with_data == 2) {
} }
@ -154,7 +157,11 @@ dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user)
} }
// Schedule retx if we have space // Schedule retx if we have space
#if ASYNC_DL_SCHED
if (h) { if (h) {
#else
if (h && !h->is_empty()) {
#endif
uint32_t retx_mask = h->get_rbgmask(); uint32_t retx_mask = h->get_rbgmask();
// If can schedule the same mask, do it // If can schedule the same mask, do it
if (!allocation_is_valid(retx_mask)) { if (!allocation_is_valid(retx_mask)) {
@ -172,8 +179,12 @@ dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user)
} }
} }
// If could not schedule the reTx, or there wasn't any pending retx, find an empty PID // If could not schedule the reTx, or there wasn't any pending retx, find an empty PID
#if ASYNC_DL_SCHED
h = user->get_empty_dl_harq(); h = user->get_empty_dl_harq();
if (h) { if (h) {
#else
if (h && h->is_empty()) {
#endif
// Allocate resources based on pending data // Allocate resources based on pending data
if (pending_data) { if (pending_data) {
uint32_t pending_rb = user->get_required_prb_dl(pending_data, nof_ctrl_symbols); uint32_t pending_rb = user->get_required_prb_dl(pending_data, nof_ctrl_symbols);
@ -215,7 +226,6 @@ void ul_metric_rr::new_tti(std::map<uint16_t,sched_ue> &ue_db, uint32_t nof_rb_,
sched_ue *user = (sched_ue*) &iter->second; sched_ue *user = (sched_ue*) &iter->second;
if (user->get_pending_ul_new_data(current_tti) || !user->get_ul_harq(current_tti)->is_empty()) { if (user->get_pending_ul_new_data(current_tti) || !user->get_ul_harq(current_tti)->is_empty()) {
user->ue_idx = nof_users_with_data; user->ue_idx = nof_users_with_data;
user->has_pusch = true;
nof_users_with_data++; nof_users_with_data++;
} }
} }

@ -28,6 +28,8 @@
#include <boost/concept_check.hpp> #include <boost/concept_check.hpp>
#include <srslte/interfaces/sched_interface.h> #include <srslte/interfaces/sched_interface.h>
#include <srslte/phy/phch/pucch.h> #include <srslte/phy/phch/pucch.h>
#include <srslte/srslte.h>
#include <srslte/phy/common/phy_common.h>
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include "srslte/common/pdu.h" #include "srslte/common/pdu.h"
@ -232,7 +234,7 @@ bool sched_ue::pucch_sr_collision(uint32_t current_tti, uint32_t n_cce)
} }
} }
bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32_t *L) bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2])
{ {
if (!phy_config_dedicated_enabled) { if (!phy_config_dedicated_enabled) {
return false; return false;
@ -247,17 +249,15 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32
// First check if it has pending ACKs // First check if it has pending ACKs
for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) { for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) {
if (((dl_harq[i].get_tti()+4)%10240) == current_tti) { if (TTI_TX(dl_harq[i].get_tti()) == current_tti) {
uint32_t n_pucch = srslte_pucch_get_npucch(dl_harq[i].get_n_cce(), SRSLTE_PUCCH_FORMAT_1A, has_sr, &pucch_sched); uint32_t n_pucch = srslte_pucch_get_npucch(dl_harq[i].get_n_cce(), SRSLTE_PUCCH_FORMAT_1A, has_sr, &pucch_sched);
if (prb_idx) { if (prb_idx) {
for (int i=0;i<2;i++) { for (int i=0;i<2;i++) {
prb_idx[i] = srslte_pucch_n_prb(&cfg.pucch_cfg, SRSLTE_PUCCH_FORMAT_1A, n_pucch, cell.nof_prb, cell.cp, i); prb_idx[i] = srslte_pucch_n_prb(&cfg.pucch_cfg, SRSLTE_PUCCH_FORMAT_1A, n_pucch, cell.nof_prb, cell.cp, i);
} }
} }
if (L) { Debug("SCHED: Reserved Format1A PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d, ncce=%d, has_sr=%d, n_pucch_1=%d\n",
*L = 1; rnti, prb_idx[0], prb_idx[1], n_pucch, dl_harq[i].get_n_cce(), has_sr, pucch_sched.N_pucch_1);
}
Debug("SCHED: Reserved Format1A PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], n_pucch);
return true; return true;
} }
} }
@ -268,9 +268,6 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32
prb_idx[i] = srslte_pucch_n_prb(&cfg.pucch_cfg, SRSLTE_PUCCH_FORMAT_1, cfg.sr_N_pucch, cell.nof_prb, cell.cp, i); prb_idx[i] = srslte_pucch_n_prb(&cfg.pucch_cfg, SRSLTE_PUCCH_FORMAT_1, cfg.sr_N_pucch, cell.nof_prb, cell.cp, i);
} }
} }
if (L) {
*L = 1;
}
Debug("SCHED: Reserved Format1 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], cfg.sr_N_pucch); Debug("SCHED: Reserved Format1 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], cfg.sr_N_pucch);
return true; return true;
} }
@ -281,9 +278,6 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32
prb_idx[i] = srslte_pucch_n_prb(&cfg.pucch_cfg, SRSLTE_PUCCH_FORMAT_2, cfg.cqi_pucch, cell.nof_prb, cell.cp, i); prb_idx[i] = srslte_pucch_n_prb(&cfg.pucch_cfg, SRSLTE_PUCCH_FORMAT_2, cfg.cqi_pucch, cell.nof_prb, cell.cp, i);
} }
} }
if(L) {
*L = 2;
}
Debug("SCHED: Reserved Format2 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d, pmi_idx=%d\n", Debug("SCHED: Reserved Format2 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d, pmi_idx=%d\n",
rnti, prb_idx[0], prb_idx[1], cfg.cqi_pucch, cfg.cqi_idx); rnti, prb_idx[0], prb_idx[1], cfg.cqi_pucch, cfg.cqi_idx);
return true; return true;
@ -295,7 +289,7 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32
int sched_ue::set_ack_info(uint32_t tti, bool ack) int sched_ue::set_ack_info(uint32_t tti, bool ack)
{ {
for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) { for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) {
if (((dl_harq[i].get_tti()+4)%10240) == tti) { if (TTI_TX(dl_harq[i].get_tti()) == tti) {
Debug("SCHED: Set ACK=%d for rnti=0x%x, pid=%d, tti=%d\n", ack, rnti, i, tti); Debug("SCHED: Set ACK=%d for rnti=0x%x, pid=%d, tti=%d\n", ack, rnti, i, tti);
dl_harq[i].set_ack(ack); dl_harq[i].set_ack(ack);
return dl_harq[i].get_tbs(); return dl_harq[i].get_tbs();
@ -663,6 +657,7 @@ bool sched_ue::is_sr_triggered()
/* Gets HARQ process with oldest pending retx */ /* Gets HARQ process with oldest pending retx */
dl_harq_proc* sched_ue::get_pending_dl_harq(uint32_t tti) dl_harq_proc* sched_ue::get_pending_dl_harq(uint32_t tti)
{ {
#if ASYNC_DL_SCHED
int oldest_idx=-1; int oldest_idx=-1;
uint32_t oldest_tti = 0; uint32_t oldest_tti = 0;
for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) { for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) {
@ -679,6 +674,9 @@ dl_harq_proc* sched_ue::get_pending_dl_harq(uint32_t tti)
} else { } else {
return NULL; return NULL;
} }
#else
return &dl_harq[tti%SCHED_MAX_HARQ_PROC];
#endif
} }
dl_harq_proc* sched_ue::get_empty_dl_harq() dl_harq_proc* sched_ue::get_empty_dl_harq()
@ -702,10 +700,16 @@ uint32_t sched_ue::get_aggr_level(uint32_t nof_bits)
uint32_t l=0; uint32_t l=0;
float max_coderate = srslte_cqi_to_coderate(dl_cqi); float max_coderate = srslte_cqi_to_coderate(dl_cqi);
float coderate = 99; float coderate = 99;
float factor=1.5;
uint32_t l_max = 3;
if (cell.nof_prb == 6) {
factor = 1.0;
l_max = 2;
}
do { do {
coderate = srslte_pdcch_coderate(nof_bits, l); coderate = srslte_pdcch_coderate(nof_bits, l);
l++; l++;
} while(l<3 && 1.5*coderate > max_coderate); } while(l<l_max && factor*coderate > max_coderate);
Debug("SCHED: CQI=%d, l=%d, nof_bits=%d, coderate=%.2f, max_coderate=%.2f\n", dl_cqi, l, nof_bits, coderate, max_coderate); Debug("SCHED: CQI=%d, l=%d, nof_bits=%d, coderate=%.2f, max_coderate=%.2f\n", dl_cqi, l, nof_bits, coderate, max_coderate);
return l; return l;
} }

@ -130,9 +130,9 @@ void metrics_stdout::print_metrics()
cout << float_to_string(0, 2); cout << float_to_string(0, 2);
} }
if (metrics.mac[i].tx_pkts > 0 && metrics.mac[i].tx_errors) { if (metrics.mac[i].tx_pkts > 0 && metrics.mac[i].tx_errors) {
cout << float_to_string((float) 100*metrics.mac[i].tx_errors/metrics.mac[i].tx_pkts, 2) << "%"; cout << float_to_string((float) 100*metrics.mac[i].tx_errors/metrics.mac[i].tx_pkts, 1) << "%";
} else { } else {
cout << float_to_string(0, 2) << "%"; cout << float_to_string(0, 1) << "%";
} }
cout << float_to_string(metrics.phy[i].ul.sinr, 2); cout << float_to_string(metrics.phy[i].ul.sinr, 2);
cout << float_to_string(metrics.mac[i].phr, 2); cout << float_to_string(metrics.mac[i].phr, 2);
@ -143,9 +143,9 @@ void metrics_stdout::print_metrics()
cout << float_to_string(0, 2); cout << float_to_string(0, 2);
} }
if (metrics.mac[i].rx_pkts > 0 && metrics.mac[i].rx_errors > 0) { if (metrics.mac[i].rx_pkts > 0 && metrics.mac[i].rx_errors > 0) {
cout << float_to_string((float) 100*metrics.mac[i].rx_errors/metrics.mac[i].rx_pkts, 2) << "%"; cout << float_to_string((float) 100*metrics.mac[i].rx_errors/metrics.mac[i].rx_pkts, 1) << "%";
} else { } else {
cout << float_to_string(0, 2) << "%"; cout << float_to_string(0, 1) << "%";
} }
cout << float_to_eng_string(metrics.mac[i].ul_buffer, 2); cout << float_to_eng_string(metrics.mac[i].ul_buffer, 2);
cout << endl; cout << endl;

@ -48,8 +48,8 @@ void phch_common::set_nof_mutex(uint32_t nof_mutex_) {
} }
void phch_common::reset() { void phch_common::reset() {
bzero(ul_grants, sizeof(mac_interface_phy::ul_sched_t)*10); bzero(ul_grants, sizeof(mac_interface_phy::ul_sched_t)*TTIMOD_SZ);
bzero(dl_grants, sizeof(mac_interface_phy::dl_sched_t)*10); bzero(dl_grants, sizeof(mac_interface_phy::dl_sched_t)*TTIMOD_SZ);
} }
bool phch_common::init(srslte_cell_t *cell_, srslte::radio* radio_h_, mac_interface_phy *mac_) bool phch_common::init(srslte_cell_t *cell_, srslte::radio* radio_h_, mac_interface_phy *mac_)
@ -104,7 +104,7 @@ void phch_common::ack_clear(uint32_t sf_idx)
void phch_common::ack_add_rnti(uint16_t rnti) void phch_common::ack_add_rnti(uint16_t rnti)
{ {
for (int sf_idx=0;sf_idx<10;sf_idx++) { for (int sf_idx=0;sf_idx<TTIMOD_SZ;sf_idx++) {
pending_ack[rnti].is_pending[sf_idx] = false; pending_ack[rnti].is_pending[sf_idx] = false;
} }
} }

@ -176,11 +176,16 @@ cf_t* phch_worker::get_buffer_rx()
void phch_worker::set_time(uint32_t tti_, uint32_t tx_mutex_cnt_, srslte_timestamp_t tx_time_) void phch_worker::set_time(uint32_t tti_, uint32_t tx_mutex_cnt_, srslte_timestamp_t tx_time_)
{ {
tti_rx = tti_; tti_rx = tti_;
tti_tx = (tti_ + 4)%10240; tti_tx_dl = TTI_TX(tti_rx);
tti_sched_ul = (tti_ + 8)%10240; tti_tx_ul = TTI_RX_ACK(tti_rx);
sf_rx = tti_rx%10; sf_rx = tti_rx%10;
sf_tx = tti_tx%10; sf_tx = tti_tx_dl%10;
sf_sched_ul = tti_sched_ul%10;
t_tx_dl = TTIMOD(tti_tx_dl);
t_rx = TTIMOD(tti_rx);
t_tx_ul = TTIMOD(tti_tx_ul);
tx_mutex_cnt = tx_mutex_cnt_; tx_mutex_cnt = tx_mutex_cnt_;
memcpy(&tx_time, &tx_time_, sizeof(srslte_timestamp_t)); memcpy(&tx_time, &tx_time_, sizeof(srslte_timestamp_t));
} }
@ -245,7 +250,7 @@ void phch_worker::rem_rnti(uint16_t rnti)
srslte_enb_ul_rem_rnti(&enb_ul, rnti); srslte_enb_ul_rem_rnti(&enb_ul, rnti);
// remove any pending grant for each subframe // remove any pending grant for each subframe
for (uint32_t i=0;i<10;i++) { for (uint32_t i=0;i<TTIMOD_SZ;i++) {
for (uint32_t j=0;j<phy->ul_grants[i].nof_grants;j++) { for (uint32_t j=0;j<phy->ul_grants[i].nof_grants;j++) {
if (phy->ul_grants[i].sched_grants[j].rnti == rnti) { if (phy->ul_grants[i].sched_grants[j].rnti == rnti) {
phy->ul_grants[i].sched_grants[j].rnti = 0; phy->ul_grants[i].sched_grants[j].rnti = 0;
@ -265,8 +270,6 @@ void phch_worker::rem_rnti(uint16_t rnti)
void phch_worker::work_imp() void phch_worker::work_imp()
{ {
uint32_t sf_ack;
if (!running) { if (!running) {
return; return;
} }
@ -290,48 +293,47 @@ void phch_worker::work_imp()
srslte_enb_ul_fft(&enb_ul, signal_buffer_rx); srslte_enb_ul_fft(&enb_ul, signal_buffer_rx);
// Decode pending UL grants for the tti they were scheduled // Decode pending UL grants for the tti they were scheduled
decode_pusch(ul_grants[sf_rx].sched_grants, ul_grants[sf_rx].nof_grants, sf_rx); decode_pusch(ul_grants[t_rx].sched_grants, ul_grants[t_rx].nof_grants);
// Decode remaining PUCCH ACKs not associated with PUSCH transmission and SR signals // Decode remaining PUCCH ACKs not associated with PUSCH transmission and SR signals
decode_pucch(tti_rx); decode_pucch();
// Get DL scheduling for the TX TTI from MAC // Get DL scheduling for the TX TTI from MAC
if (mac->get_dl_sched(tti_tx, &dl_grants[sf_tx]) < 0) { if (mac->get_dl_sched(tti_tx_dl, &dl_grants[t_tx_dl]) < 0) {
Error("Getting DL scheduling from MAC\n"); Error("Getting DL scheduling from MAC\n");
goto unlock; goto unlock;
} }
if (dl_grants[sf_tx].cfi < 1 || dl_grants[sf_tx].cfi > 3) { if (dl_grants[t_tx_dl].cfi < 1 || dl_grants[t_tx_dl].cfi > 3) {
Error("Invalid CFI=%d\n", dl_grants[sf_tx].cfi); Error("Invalid CFI=%d\n", dl_grants[t_tx_dl].cfi);
goto unlock; goto unlock;
} }
// Get UL scheduling for the TX TTI from MAC // Get UL scheduling for the TX TTI from MAC
if (mac->get_ul_sched(tti_sched_ul, &ul_grants[sf_sched_ul]) < 0) { if (mac->get_ul_sched(tti_tx_ul, &ul_grants[t_tx_ul]) < 0) {
Error("Getting UL scheduling from MAC\n"); Error("Getting UL scheduling from MAC\n");
goto unlock; goto unlock;
} }
// Put base signals (references, PBCH, PCFICH and PSS/SSS) into the resource grid // Put base signals (references, PBCH, PCFICH and PSS/SSS) into the resource grid
srslte_enb_dl_clear_sf(&enb_dl); srslte_enb_dl_clear_sf(&enb_dl);
srslte_enb_dl_set_cfi(&enb_dl, dl_grants[sf_tx].cfi); srslte_enb_dl_set_cfi(&enb_dl, dl_grants[t_tx_dl].cfi);
srslte_enb_dl_put_base(&enb_dl, tti_tx); srslte_enb_dl_put_base(&enb_dl, tti_tx_dl);
// Put UL/DL grants to resource grid. PDSCH data will be encoded as well. // Put UL/DL grants to resource grid. PDSCH data will be encoded as well.
encode_pdcch_dl(dl_grants[sf_tx].sched_grants, dl_grants[sf_tx].nof_grants, sf_tx); encode_pdcch_dl(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants);
encode_pdcch_ul(ul_grants[sf_sched_ul].sched_grants, ul_grants[sf_sched_ul].nof_grants, sf_tx); encode_pdcch_ul(ul_grants[t_tx_ul].sched_grants, ul_grants[t_tx_ul].nof_grants);
encode_pdsch(dl_grants[sf_tx].sched_grants, dl_grants[sf_tx].nof_grants, sf_tx); encode_pdsch(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants);
// Put pending PHICH HARQ ACK/NACK indications into subframe // Put pending PHICH HARQ ACK/NACK indications into subframe
encode_phich(ul_grants[sf_sched_ul].phich, ul_grants[sf_sched_ul].nof_phich, sf_tx); encode_phich(ul_grants[t_tx_ul].phich, ul_grants[t_tx_ul].nof_phich);
// Prepare for receive ACK for DL grants in sf_tx+4 // Prepare for receive ACK for DL grants in t_tx_dl+4
sf_ack = (sf_tx+4)%10; phy->ack_clear(TTIMOD(TTI_TX(t_tx_dl)));
phy->ack_clear(sf_ack); for (uint32_t i=0;i<dl_grants[t_tx_dl].nof_grants;i++) {
for (uint32_t i=0;i<dl_grants[sf_tx].nof_grants;i++) {
// SI-RNTI and RAR-RNTI do not have ACK // SI-RNTI and RAR-RNTI do not have ACK
if (dl_grants[sf_tx].sched_grants[i].rnti >= SRSLTE_CRNTI_START && dl_grants[sf_tx].sched_grants[i].rnti <= SRSLTE_CRNTI_END) { if (dl_grants[t_tx_dl].sched_grants[i].rnti >= SRSLTE_CRNTI_START && dl_grants[t_tx_dl].sched_grants[i].rnti <= SRSLTE_CRNTI_END) {
phy->ack_set_pending(sf_ack, dl_grants[sf_tx].sched_grants[i].rnti, dl_grants[sf_tx].sched_grants[i].location.ncce); phy->ack_set_pending(TTIMOD(TTI_TX(t_tx_dl)), dl_grants[t_tx_dl].sched_grants[i].rnti, dl_grants[t_tx_dl].sched_grants[i].location.ncce);
} }
} }
@ -345,7 +347,7 @@ void phch_worker::work_imp()
#endif #endif
#ifdef DEBUG_WRITE_FILE #ifdef DEBUG_WRITE_FILE
if (tti_tx == 10) { if (tti_tx_dl == 10) {
fclose(f); fclose(f);
exit(-1); exit(-1);
} }
@ -364,7 +366,7 @@ unlock:
} }
int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch, uint32_t tti) int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch)
{ {
srslte_uci_data_t uci_data; srslte_uci_data_t uci_data;
bzero(&uci_data, sizeof(srslte_uci_data_t)); bzero(&uci_data, sizeof(srslte_uci_data_t));
@ -383,7 +385,7 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch,
#endif #endif
// Get pending ACKs with an associated PUSCH transmission // Get pending ACKs with an associated PUSCH transmission
if (phy->ack_is_pending(sf_rx, rnti)) { if (phy->ack_is_pending(t_rx, rnti)) {
uci_data.uci_ack_len = 1; uci_data.uci_ack_len = 1;
} }
// Configure PUSCH CQI channel // Configure PUSCH CQI channel
@ -406,7 +408,7 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch,
srslte_ra_ul_grant_t phy_grant; srslte_ra_ul_grant_t phy_grant;
int res = -1; int res = -1;
if (!srslte_ra_ul_dci_to_grant(&grants[i].grant, enb_ul.cell.nof_prb, n_rb_ho, &phy_grant, tti%8)) { if (!srslte_ra_ul_dci_to_grant(&grants[i].grant, enb_ul.cell.nof_prb, n_rb_ho, &phy_grant, tti_rx%8)) {
if (phy_grant.mcs.mod == SRSLTE_MOD_64QAM) { if (phy_grant.mcs.mod == SRSLTE_MOD_64QAM) {
phy_grant.mcs.mod = SRSLTE_MOD_16QAM; phy_grant.mcs.mod = SRSLTE_MOD_16QAM;
} }
@ -416,7 +418,7 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch,
grants[i].current_tx_nb, grants[i].current_tx_nb,
grants[i].data, grants[i].data,
&uci_data, &uci_data,
tti); sf_rx);
} else { } else {
Error("Computing PUSCH grant\n"); Error("Computing PUSCH grant\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -502,9 +504,8 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch,
} }
int phch_worker::decode_pucch(uint32_t tti_rx) int phch_worker::decode_pucch()
{ {
uint32_t sf_rx = tti_rx%10;
srslte_uci_data_t uci_data; srslte_uci_data_t uci_data;
for(std::map<uint16_t, ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { for(std::map<uint16_t, ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
@ -523,7 +524,8 @@ int phch_worker::decode_pucch(uint32_t tti_rx)
uci_data.scheduling_request = true; uci_data.scheduling_request = true;
} }
} }
if (phy->ack_is_pending(sf_rx, rnti, &last_n_pdcch)) {
if (phy->ack_is_pending(t_rx, rnti, &last_n_pdcch)) {
needs_pucch = true; needs_pucch = true;
needs_ack = true; needs_ack = true;
uci_data.uci_ack_len = 1; uci_data.uci_ack_len = 1;
@ -581,7 +583,7 @@ int phch_worker::decode_pucch(uint32_t tti_rx)
} }
int phch_worker::encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks, uint32_t sf_idx) int phch_worker::encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks)
{ {
for (uint32_t i=0;i<nof_acks;i++) { for (uint32_t i=0;i<nof_acks;i++) {
uint16_t rnti = acks[i].rnti; uint16_t rnti = acks[i].rnti;
@ -589,36 +591,36 @@ int phch_worker::encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks, ui
srslte_enb_dl_put_phich(&enb_dl, acks[i].ack, srslte_enb_dl_put_phich(&enb_dl, acks[i].ack,
ue_db[rnti].phich_info.n_prb_lowest, ue_db[rnti].phich_info.n_prb_lowest,
ue_db[rnti].phich_info.n_dmrs, ue_db[rnti].phich_info.n_dmrs,
sf_idx); sf_tx);
Info("PHICH: rnti=0x%x, hi=%d, I_lowest=%d, n_dmrs=%d, tti_tx=%d\n", Info("PHICH: rnti=0x%x, hi=%d, I_lowest=%d, n_dmrs=%d, tti_tx_dl=%d\n",
rnti, acks[i].ack, rnti, acks[i].ack,
ue_db[rnti].phich_info.n_prb_lowest, ue_db[rnti].phich_info.n_prb_lowest,
ue_db[rnti].phich_info.n_dmrs, tti_tx); ue_db[rnti].phich_info.n_dmrs, tti_tx_dl);
} }
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int phch_worker::encode_pdcch_ul(srslte_enb_ul_pusch_t *grants, uint32_t nof_grants, uint32_t sf_idx) int phch_worker::encode_pdcch_ul(srslte_enb_ul_pusch_t *grants, uint32_t nof_grants)
{ {
for (uint32_t i=0;i<nof_grants;i++) { for (uint32_t i=0;i<nof_grants;i++) {
uint16_t rnti = grants[i].rnti; uint16_t rnti = grants[i].rnti;
if (grants[i].needs_pdcch && rnti) { if (grants[i].needs_pdcch && rnti) {
if (srslte_enb_dl_put_pdcch_ul(&enb_dl, &grants[i].grant, grants[i].location, rnti, sf_idx)) { if (srslte_enb_dl_put_pdcch_ul(&enb_dl, &grants[i].grant, grants[i].location, rnti, sf_tx)) {
fprintf(stderr, "Error putting PUSCH %d\n",i); fprintf(stderr, "Error putting PUSCH %d\n",i);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
Info("PDCCH: UL DCI Format0 rnti=0x%x, cce_index=%d, L=%d, tti_tx=%d\n", Info("PDCCH: UL DCI Format0 rnti=0x%x, cce_index=%d, L=%d, tpc=%d, tti_tx_dl=%d\n",
rnti, grants[i].location.ncce, (1<<grants[i].location.L), tti_tx); rnti, grants[i].location.ncce, (1<<grants[i].location.L), grants[i].grant.tpc_pusch, tti_tx_dl);
} }
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int phch_worker::encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants, uint32_t sf_idx) int phch_worker::encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants)
{ {
for (uint32_t i=0;i<nof_grants;i++) { for (uint32_t i=0;i<nof_grants;i++) {
uint16_t rnti = grants[i].rnti; uint16_t rnti = grants[i].rnti;
@ -633,21 +635,21 @@ int phch_worker::encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_gra
format = SRSLTE_DCI_FORMAT1A; format = SRSLTE_DCI_FORMAT1A;
break; break;
} }
if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, format, grants[i].location, rnti, sf_idx)) { if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, format, grants[i].location, rnti, sf_tx)) {
fprintf(stderr, "Error putting PDCCH %d\n",i); fprintf(stderr, "Error putting PDCCH %d\n",i);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (LOG_THIS(rnti)) { if (LOG_THIS(rnti)) {
Info("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti_tx=%d\n", srslte_dci_format_string(format), Info("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti_tx_dl=%d\n", srslte_dci_format_string(format),
rnti, grants[i].location.ncce, (1<<grants[i].location.L), tti_tx); rnti, grants[i].location.ncce, (1<<grants[i].location.L), tti_tx_dl);
} }
} }
} }
return 0; return 0;
} }
int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants, uint32_t sf_idx) int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants)
{ {
for (uint32_t i=0;i<nof_grants;i++) { for (uint32_t i=0;i<nof_grants;i++) {
uint16_t rnti = grants[i].rnti; uint16_t rnti = grants[i].rnti;
@ -683,9 +685,9 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants
len = 1; len = 1;
} }
log_h->info_hex(ptr, len, log_h->info_hex(ptr, len,
"PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx=%d\n", "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx_dl=%d\n",
rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process,
phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx); phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx_dl);
} }
srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL}; srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL};
@ -693,7 +695,7 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants
int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, 0}; int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, 0};
if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, rv, sf_idx, d, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0)) if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, rv, sf_tx, d, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0))
{ {
fprintf(stderr, "Error putting PDSCH %d\n",i); fprintf(stderr, "Error putting PDSCH %d\n",i);
return SRSLTE_ERROR; return SRSLTE_ERROR;

@ -115,7 +115,7 @@ void txrx::run_thread()
/* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */
srslte_timestamp_copy(&tx_time, &rx_time); srslte_timestamp_copy(&tx_time, &rx_time);
srslte_timestamp_add(&tx_time, 0, 4e-3); srslte_timestamp_add(&tx_time, 0, HARQ_DELAY_MS*1e-3);
Debug("Settting TTI=%d, tx_mutex=%d, tx_time=%d:%f to worker %d\n", Debug("Settting TTI=%d, tx_mutex=%d, tx_time=%d:%f to worker %d\n",
tti, tx_mutex_cnt, tti, tx_mutex_cnt,

@ -26,6 +26,9 @@
#include "upper/gtpu.h" #include "upper/gtpu.h"
#include <unistd.h> #include <unistd.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
using namespace srslte; using namespace srslte;
@ -42,16 +45,51 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_
pool = byte_buffer_pool::get_instance(); pool = byte_buffer_pool::get_instance();
if(0 != srslte_netsource_init(&src, gtp_bind_addr.c_str(), GTPU_PORT, SRSLTE_NETSOURCE_UDP)) { // Set up sink socket
gtpu_log->error("Failed to create source socket on %s:%d", gtp_bind_addr.c_str(), GTPU_PORT); snk_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (snk_fd < 0) {
gtpu_log->error("Failed to create sink socket\n");
return false; return false;
} }
if(0 != srslte_netsink_init(&snk, mme_addr.c_str(), GTPU_PORT, SRSLTE_NETSINK_UDP)) { if (fcntl(snk_fd, F_SETFL, O_NONBLOCK)) {
gtpu_log->error("Failed to create sink socket on %s:%d", mme_addr.c_str(), GTPU_PORT); gtpu_log->error("Failed to set non-blocking sink socket\n");
return false;
}
int enable = 1;
#if defined (SO_REUSEADDR)
if (setsockopt(snk_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
gtpu_log->error("setsockopt(SO_REUSEADDR) failed\n");
#endif
#if defined (SO_REUSEPORT)
if (setsockopt(snk_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0)
gtpu_log->error("setsockopt(SO_REUSEPORT) failed\n");
#endif
// Set up source socket
src_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (src_fd < 0) {
gtpu_log->error("Failed to create source socket\n");
return false;
}
#if defined (SO_REUSEADDR)
if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
gtpu_log->error("setsockopt(SO_REUSEADDR) failed\n");
#endif
#if defined (SO_REUSEPORT)
if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0)
gtpu_log->error("setsockopt(SO_REUSEPORT) failed\n");
#endif
struct sockaddr_in bindaddr;
bindaddr.sin_family = AF_INET;
bindaddr.sin_addr.s_addr = inet_addr(gtp_bind_addr.c_str());
bindaddr.sin_port = htons(GTPU_PORT);
if (bind(src_fd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in))) {
gtpu_log->error("Failed to bind on address %s, port %d\n", gtp_bind_addr.c_str(), GTPU_PORT);
return false; return false;
} }
srslte_netsink_set_nonblocking(&snk);
// Setup a thread to receive packets from the src socket // Setup a thread to receive packets from the src socket
start(THREAD_PRIO); start(THREAD_PRIO);
@ -61,7 +99,7 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_
void gtpu::stop() void gtpu::stop()
{ {
if(run_enable) { if (run_enable) {
run_enable = false; run_enable = false;
// Wait thread to exit gracefully otherwise might leave a mutex locked // Wait thread to exit gracefully otherwise might leave a mutex locked
int cnt=0; int cnt=0;
@ -75,8 +113,12 @@ void gtpu::stop()
wait_thread_finish(); wait_thread_finish();
} }
srslte_netsink_free(&snk); if (snk_fd) {
srslte_netsource_free(&src); close(snk_fd);
}
if (src_fd) {
close(src_fd);
}
} }
// gtpu_interface_pdcp // gtpu_interface_pdcp
@ -89,28 +131,35 @@ void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* pdu)
header.length = pdu->N_bytes; header.length = pdu->N_bytes;
header.teid = rnti_bearers[rnti].teids_out[lcid]; header.teid = rnti_bearers[rnti].teids_out[lcid];
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(rnti_bearers[rnti].spgw_addrs[lcid]);
servaddr.sin_port = htons(GTPU_PORT);
gtpu_write_header(&header, pdu); gtpu_write_header(&header, pdu);
srslte_netsink_write(&snk, pdu->msg, pdu->N_bytes); sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in));
pool->deallocate(pdu); pool->deallocate(pdu);
} }
// gtpu_interface_rrc // gtpu_interface_rrc
void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in) void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in)
{ {
// Allocate a TEID for the incoming tunnel // Allocate a TEID for the incoming tunnel
rntilcid_to_teidin(rnti, lcid, teid_in); rntilcid_to_teidin(rnti, lcid, teid_in);
gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, teid_out, *teid_in); gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, addr: 0x%x, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, addr, teid_out, *teid_in);
// Initialize maps if it's a new RNTI // Initialize maps if it's a new RNTI
if(rnti_bearers.count(rnti) == 0) { if(rnti_bearers.count(rnti) == 0) {
for(int i=0;i<SRSENB_N_RADIO_BEARERS;i++) { for(int i=0;i<SRSENB_N_RADIO_BEARERS;i++) {
rnti_bearers[rnti].teids_in[i] = 0; rnti_bearers[rnti].teids_in[i] = 0;
rnti_bearers[rnti].teids_out[i] = 0; rnti_bearers[rnti].teids_out[i] = 0;
rnti_bearers[rnti].spgw_addrs[i] = 0;
} }
} }
rnti_bearers[rnti].teids_in[lcid] = *teid_in; rnti_bearers[rnti].teids_in[lcid] = *teid_in;
rnti_bearers[rnti].teids_out[lcid] = teid_out; rnti_bearers[rnti].teids_out[lcid] = teid_out;
rnti_bearers[rnti].spgw_addrs[lcid] = addr;
} }
void gtpu::rem_bearer(uint16_t rnti, uint32_t lcid) void gtpu::rem_bearer(uint16_t rnti, uint32_t lcid)
@ -146,10 +195,19 @@ void gtpu::run_thread()
running=true; running=true;
while(run_enable) { while(run_enable) {
pdu->reset(); pdu->reset();
gtpu_log->debug("Waiting for read...\n"); gtpu_log->debug("Waiting for read...\n");
pdu->N_bytes = srslte_netsource_read(&src, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET); int n = 0;
do{
n = recv(src_fd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0);
} while (n == -1 && errno == EAGAIN);
if (n < 0) {
gtpu_log->error("Failed to read from socket\n");
}
pdu->N_bytes = (uint32_t) n;
gtpu_header_t header; gtpu_header_t header;
gtpu_read_header(pdu, &header); gtpu_read_header(pdu, &header);

@ -24,9 +24,10 @@
* *
*/ */
#include <srslte/interfaces/sched_interface.h> #include "srslte/interfaces/sched_interface.h"
#include <srslte/asn1/liblte_rrc.h> #include "srslte/asn1/liblte_rrc.h"
#include <upper/rrc.h> #include "upper/rrc.h"
#include "srslte/srslte.h"
#include "srslte/asn1/liblte_mme.h" #include "srslte/asn1/liblte_mme.h"
#include "upper/rrc.h" #include "upper/rrc.h"
@ -946,20 +947,16 @@ bool rrc::ue::setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e)
if(erab->iE_Extensions_present) { if(erab->iE_Extensions_present) {
parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n");
} }
if(erab->transportLayerAddress.n_bits > 32) {
uint8_t id = erab->e_RAB_ID.E_RAB_ID; parent->rrc_log->error("IPv6 addresses not currently supported\n");
erabs[id].id = id; return false;
memcpy(&erabs[id].qos_params, &erab->e_RABlevelQoSParameters, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT));
memcpy(&erabs[id].address, &erab->transportLayerAddress, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT));
uint8_to_uint32(erab->gTP_TEID.buffer, &erabs[id].teid_out);
uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1)
parent->gtpu->add_bearer(rnti, lcid, erabs[id].teid_out, &(erabs[id].teid_in));
if(erab->nAS_PDU_present) {
memcpy(parent->erab_info.msg, erab->nAS_PDU.buffer, erab->nAS_PDU.n_octets);
parent->erab_info.N_bytes = erab->nAS_PDU.n_octets;
} }
uint32_t teid_out;
uint8_to_uint32(erab->gTP_TEID.buffer, &teid_out);
LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu = erab->nAS_PDU_present ? &erab->nAS_PDU : NULL;
setup_erab(erab->e_RAB_ID.E_RAB_ID, &erab->e_RABlevelQoSParameters,
&erab->transportLayerAddress, teid_out, nas_pdu);
} }
return true; return true;
} }
@ -974,25 +971,43 @@ bool rrc::ue::setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e)
if(erab->iE_Extensions_present) { if(erab->iE_Extensions_present) {
parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n");
} }
if(erab->transportLayerAddress.n_bits > 32) {
parent->rrc_log->error("IPv6 addresses not currently supported\n");
return false;
}
uint8_t id = erab->e_RAB_ID.E_RAB_ID; uint32_t teid_out;
erabs[id].id = id; uint8_to_uint32(erab->gTP_TEID.buffer, &teid_out);
memcpy(&erabs[id].qos_params, &erab->e_RABlevelQoSParameters, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT)); setup_erab(erab->e_RAB_ID.E_RAB_ID, &erab->e_RABlevelQoSParameters,
memcpy(&erabs[id].address, &erab->transportLayerAddress, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT)); &erab->transportLayerAddress, teid_out, &erab->nAS_PDU);
uint8_to_uint32(erab->gTP_TEID.buffer, &erabs[id].teid_out);
uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1)
parent->gtpu->add_bearer(rnti, lcid, erabs[id].teid_out, &(erabs[id].teid_in));
memcpy(parent->erab_info.msg, erab->nAS_PDU.buffer, erab->nAS_PDU.n_octets);
parent->erab_info.N_bytes = erab->nAS_PDU.n_octets;
} }
// Work in progress // Work in progress
notify_s1ap_ue_erab_setup_response(e); notify_s1ap_ue_erab_setup_response(e);
send_connection_reconf_new_bearer(e); send_connection_reconf_new_bearer(e);
return true; return true;
} }
void rrc::ue::setup_erab(uint8_t id, LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *qos,
LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *addr, uint32_t teid_out,
LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu)
{
erabs[id].id = id;
memcpy(&erabs[id].qos_params, qos, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT));
memcpy(&erabs[id].address, addr, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT));
erabs[id].teid_out = teid_out;
uint8_t* bit_ptr = addr->buffer;
uint32_t addr_ = liblte_bits_2_value(&bit_ptr, addr->n_bits);
uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1)
parent->gtpu->add_bearer(rnti, lcid, addr_, erabs[id].teid_out, &(erabs[id].teid_in));
if(nas_pdu) {
memcpy(parent->erab_info.msg, nas_pdu->buffer, nas_pdu->n_octets);
parent->erab_info.N_bytes = nas_pdu->n_octets;
}
}
bool rrc::ue::release_erabs() bool rrc::ue::release_erabs()
{ {
typedef std::map<uint8_t, erab_t>::iterator it_t; typedef std::map<uint8_t, erab_t>::iterator it_t;
@ -1163,6 +1178,7 @@ void rrc::ue::send_connection_setup(bool is_setup)
sched_cfg.pucch_cfg.delta_pucch_shift = liblte_rrc_delta_pucch_shift_num[parent->sib2.rr_config_common_sib.pucch_cnfg.delta_pucch_shift%LIBLTE_RRC_DELTA_PUCCH_SHIFT_N_ITEMS]; sched_cfg.pucch_cfg.delta_pucch_shift = liblte_rrc_delta_pucch_shift_num[parent->sib2.rr_config_common_sib.pucch_cnfg.delta_pucch_shift%LIBLTE_RRC_DELTA_PUCCH_SHIFT_N_ITEMS];
sched_cfg.pucch_cfg.N_cs = parent->sib2.rr_config_common_sib.pucch_cnfg.n_cs_an; sched_cfg.pucch_cfg.N_cs = parent->sib2.rr_config_common_sib.pucch_cnfg.n_cs_an;
sched_cfg.pucch_cfg.n_rb_2 = parent->sib2.rr_config_common_sib.pucch_cnfg.n_rb_cqi; sched_cfg.pucch_cfg.n_rb_2 = parent->sib2.rr_config_common_sib.pucch_cnfg.n_rb_cqi;
sched_cfg.pucch_cfg.n1_pucch_an = parent->sib2.rr_config_common_sib.pucch_cnfg.n1_pucch_an;
// Configure MAC // Configure MAC
parent->mac->ue_cfg(rnti, &sched_cfg); parent->mac->ue_cfg(rnti, &sched_cfg);

@ -109,7 +109,7 @@ private:
static const int MAC_MAIN_THREAD_PRIO = 5; static const int MAC_MAIN_THREAD_PRIO = 5;
static const int MAC_PDU_THREAD_PRIO = 6; static const int MAC_PDU_THREAD_PRIO = 6;
static const int MAC_NOF_HARQ_PROC = 8; static const int MAC_NOF_HARQ_PROC = 2*HARQ_DELAY_MS;
// Interaction with PHY // Interaction with PHY
srslte::tti_sync_cv ttisync; srslte::tti_sync_cv ttisync;

@ -82,7 +82,6 @@ private:
const static int MIN_RLC_SDU_LEN = 0; const static int MIN_RLC_SDU_LEN = 0;
const static int MAX_NOF_SUBHEADERS = 20; const static int MAX_NOF_SUBHEADERS = 20;
const static int MAX_HARQ_PROC = 8;
std::vector<lchid_t> lch; std::vector<lchid_t> lch;

@ -138,7 +138,7 @@ namespace srsue {
uint32_t I_lowest; uint32_t I_lowest;
uint32_t n_dmrs; uint32_t n_dmrs;
} pending_ack_t; } pending_ack_t;
pending_ack_t pending_ack[10]; pending_ack_t pending_ack[TTIMOD_SZ];
bool is_first_tx; bool is_first_tx;

@ -53,6 +53,7 @@ public:
void set_agc_enable(bool enable); void set_agc_enable(bool enable);
void set_earfcn(std::vector<uint32_t> earfcn); void set_earfcn(std::vector<uint32_t> earfcn);
void force_freq(float dl_freq, float ul_freq);
void reset_sync(); void reset_sync();
void cell_search_start(); void cell_search_start();
@ -171,6 +172,10 @@ private:
int cell_meas_rsrp(); int cell_meas_rsrp();
int cell_search(int force_N_id_2 = -1); int cell_search(int force_N_id_2 = -1);
bool set_cell(); bool set_cell();
float dl_freq;
float ul_freq;
}; };
} // namespace srsue } // namespace srsue

@ -76,6 +76,7 @@ public:
void write_trace(std::string filename); void write_trace(std::string filename);
void set_earfcn(std::vector<uint32_t> earfcns); void set_earfcn(std::vector<uint32_t> earfcns);
void force_freq(float dl_freq, float ul_freq);
/********** RRC INTERFACE ********************/ /********** RRC INTERFACE ********************/
void reset(); void reset();

@ -91,10 +91,10 @@ public:
bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi); bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi);
void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code); void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code);
void plmn_search_end();
// UE interface // UE interface
void attach_request(); void attach_request();
void deattach_request(); void deattach_request();
private: private:

@ -177,8 +177,8 @@ private:
// PHY interface // PHY interface
void in_sync(); void in_sync();
void out_of_sync(); void out_of_sync();
void earfcn_end();
void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp); void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp);
// MAC interface // MAC interface

@ -61,6 +61,7 @@ public:
// NAS interface // NAS interface
void get_imsi_vec(uint8_t* imsi_, uint32_t n); void get_imsi_vec(uint8_t* imsi_, uint32_t n);
void get_imei_vec(uint8_t* imei_, uint32_t n); void get_imei_vec(uint8_t* imei_, uint32_t n);
int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id);
void generate_authentication_response(uint8_t *rand, void generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
@ -119,6 +120,8 @@ private:
uint8_t k_asme[32]; uint8_t k_asme[32];
uint8_t k_enb[32]; uint8_t k_enb[32];
bool initiated;
}; };
} // namespace srsue } // namespace srsue

@ -307,7 +307,6 @@ void mac::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::
void mac::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t* action) void mac::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t* action)
{ {
log_h->info("new_grant_ul_ack\n");
int tbs = ul_harq.get_current_tbs(tti); int tbs = ul_harq.get_current_tbs(tti);
ul_harq.new_grant_ul_ack(grant, ack, action); ul_harq.new_grant_ul_ack(grant, ack, action);
if (!ack) { if (!ack) {

@ -368,7 +368,7 @@ bool bsr_proc::need_to_reset_sr() {
bool bsr_proc::need_to_send_sr(uint32_t tti) { bool bsr_proc::need_to_send_sr(uint32_t tti) {
if (!sr_is_sent && triggered_bsr_type == REGULAR) { if (!sr_is_sent && triggered_bsr_type == REGULAR) {
if (srslte_tti_interval(tti,next_tx_tti)>0 && srslte_tti_interval(tti,next_tx_tti) < 10240-4) { if (srslte_tti_interval(tti,next_tx_tti)>0 && srslte_tti_interval(tti,next_tx_tti) < 10240-HARQ_DELAY_MS) {
reset_sr = false; reset_sr = false;
sr_is_sent = true; sr_is_sent = true;
Debug("BSR: Need to send sr: sr_is_sent=true, reset_sr=false, tti=%d, next_tx_tti=%d\n", tti, next_tx_tti); Debug("BSR: Need to send sr: sr_is_sent=true, reset_sr=false, tti=%d, next_tx_tti=%d\n", tti, next_tx_tti);

@ -65,6 +65,8 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
common.add_options() common.add_options()
("rf.dl_earfcn", bpo::value<uint32_t>(&args->rf.dl_earfcn)->default_value(3400), "Downlink EARFCN") ("rf.dl_earfcn", bpo::value<uint32_t>(&args->rf.dl_earfcn)->default_value(3400), "Downlink EARFCN")
("rf.freq_offset", bpo::value<float>(&args->rf.freq_offset)->default_value(0), "(optional) Frequency offset") ("rf.freq_offset", bpo::value<float>(&args->rf.freq_offset)->default_value(0), "(optional) Frequency offset")
("rf.dl_freq", bpo::value<float>(&args->rf.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)")
("rf.ul_freq", bpo::value<float>(&args->rf.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)")
("rf.rx_gain", bpo::value<float>(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain") ("rf.rx_gain", bpo::value<float>(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain")
("rf.tx_gain", bpo::value<float>(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain") ("rf.tx_gain", bpo::value<float>(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain")
("rf.nof_rx_ant", bpo::value<uint32_t>(&args->rf.nof_rx_ant)->default_value(1), "Number of RX antennas") ("rf.nof_rx_ant", bpo::value<uint32_t>(&args->rf.nof_rx_ant)->default_value(1), "Number of RX antennas")

@ -92,7 +92,7 @@ void metrics_stdout::set_metrics(ue_metrics_t &metrics, float metrics_report_per
if (metrics.mac.rx_pkts > 0) { if (metrics.mac.rx_pkts > 0) {
cout << float_to_string((float) 100*metrics.mac.rx_errors/metrics.mac.rx_pkts, 1) << "%"; cout << float_to_string((float) 100*metrics.mac.rx_errors/metrics.mac.rx_pkts, 1) << "%";
} else { } else {
cout << float_to_string(0, 2) << "%"; cout << float_to_string(0, 1) << "%";
} }
cout << float_to_string(metrics.phy.ul.mcs, 2); cout << float_to_string(metrics.phy.ul.mcs, 2);
cout << float_to_eng_string((float) metrics.mac.ul_buffer, 2); cout << float_to_eng_string((float) metrics.mac.ul_buffer, 2);
@ -100,7 +100,7 @@ void metrics_stdout::set_metrics(ue_metrics_t &metrics, float metrics_report_per
if (metrics.mac.tx_pkts > 0) { if (metrics.mac.tx_pkts > 0) {
cout << float_to_string((float) 100*metrics.mac.tx_errors/metrics.mac.tx_pkts, 1) << "%"; cout << float_to_string((float) 100*metrics.mac.tx_errors/metrics.mac.tx_pkts, 1) << "%";
} else { } else {
cout << float_to_string(0, 2) << "%"; cout << float_to_string(0, 1) << "%";
} }
cout << endl; cout << endl;

@ -137,11 +137,13 @@ void phch_common::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_G
{ {
srslte_dci_rar_grant_unpack(&rar_grant, grant_payload); srslte_dci_rar_grant_unpack(&rar_grant, grant_payload);
rar_grant_pending = true; rar_grant_pending = true;
// PUSCH is at n+6 or n+7 and phch_worker assumes default delay of 4 ttis if (MSG3_DELAY_MS < 0) {
fprintf(stderr, "Error MSG3_DELAY_MS can't be negative\n");
}
if (rar_grant.ul_delay) { if (rar_grant.ul_delay) {
rar_grant_tti = (tti + 3) % 10240; rar_grant_tti = (tti + MSG3_DELAY_MS + 1) % 10240;
} else { } else {
rar_grant_tti = (tti + 2) % 10240; rar_grant_tti = (tti + MSG3_DELAY_MS) % 10240;
} }
} }
@ -195,13 +197,13 @@ void phch_common::set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int
} }
void phch_common::reset_pending_ack(uint32_t tti) { void phch_common::reset_pending_ack(uint32_t tti) {
pending_ack[tti%10].enabled = false; pending_ack[TTIMOD(tti)].enabled = false;
} }
void phch_common::set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs) { void phch_common::set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs) {
pending_ack[tti%10].enabled = true; pending_ack[TTIMOD(tti)].enabled = true;
pending_ack[tti%10].I_lowest = I_lowest; pending_ack[TTIMOD(tti)].I_lowest = I_lowest;
pending_ack[tti%10].n_dmrs = n_dmrs; pending_ack[TTIMOD(tti)].n_dmrs = n_dmrs;
Debug("Set pending ACK for tti=%d I_lowest=%d, n_dmrs=%d\n", tti, I_lowest, n_dmrs); Debug("Set pending ACK for tti=%d I_lowest=%d, n_dmrs=%d\n", tti, I_lowest, n_dmrs);
} }
@ -211,12 +213,12 @@ bool phch_common::get_pending_ack(uint32_t tti) {
bool phch_common::get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs) { bool phch_common::get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs) {
if (I_lowest) { if (I_lowest) {
*I_lowest = pending_ack[tti%10].I_lowest; *I_lowest = pending_ack[TTIMOD(tti)].I_lowest;
} }
if (n_dmrs) { if (n_dmrs) {
*n_dmrs = pending_ack[tti%10].n_dmrs; *n_dmrs = pending_ack[TTIMOD(tti)].n_dmrs;
} }
return pending_ack[tti%10].enabled; return pending_ack[TTIMOD(tti)].enabled;
} }
/* The transmisison of UL subframes must be in sequence. Each worker uses this function to indicate /* The transmisison of UL subframes must be in sequence. Each worker uses this function to indicate

@ -63,6 +63,8 @@ double callback_set_rx_gain(void *h, double gain) {
phch_recv::phch_recv() { phch_recv::phch_recv() {
dl_freq = -1;
ul_freq = -1;
bzero(&cell, sizeof(srslte_cell_t)); bzero(&cell, sizeof(srslte_cell_t));
running = false; running = false;
} }
@ -171,6 +173,7 @@ void phch_recv::radio_error() {
// Need to find a method to effectively reset radio, reloading the driver does not work // Need to find a method to effectively reset radio, reloading the driver does not work
//radio_h->reset(); //radio_h->reset();
radio_h->stop();
fprintf(stdout, "Error while receiving samples. Restart srsUE\n"); fprintf(stdout, "Error while receiving samples. Restart srsUE\n");
exit(-1); exit(-1);
@ -444,6 +447,11 @@ void phch_recv::set_earfcn(std::vector<uint32_t> earfcn) {
this->earfcn = earfcn; this->earfcn = earfcn;
} }
void phch_recv::force_freq(float dl_freq, float ul_freq) {
this->dl_freq = dl_freq;
this->ul_freq = ul_freq;
}
bool phch_recv::stop_sync() { bool phch_recv::stop_sync() {
wait_radio_reset(); wait_radio_reset();
@ -478,6 +486,7 @@ void phch_recv::cell_search_inc()
if (cur_earfcn_index >= 0) { if (cur_earfcn_index >= 0) {
if (cur_earfcn_index >= (int) earfcn.size() - 1) { if (cur_earfcn_index >= (int) earfcn.size() - 1) {
cur_earfcn_index = 0; cur_earfcn_index = 0;
rrc->earfcn_end();
} }
} }
Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size()); Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size());
@ -566,17 +575,25 @@ bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) {
bool phch_recv::set_frequency() bool phch_recv::set_frequency()
{ {
double dl_freq = 1e6*srslte_band_fd(current_earfcn); double set_dl_freq = 0;
double ul_freq = 1e6*srslte_band_fu(srslte_band_ul_earfcn(current_earfcn)); double set_ul_freq = 0;
if (dl_freq > 0 && ul_freq > 0) {
if (this->dl_freq > 0 && this->ul_freq > 0) {
set_dl_freq = this->dl_freq;
set_ul_freq = this->ul_freq;
} else {
set_dl_freq = 1e6*srslte_band_fd(current_earfcn);
set_ul_freq = 1e6*srslte_band_fu(srslte_band_ul_earfcn(current_earfcn));
}
if (set_dl_freq > 0 && set_ul_freq > 0) {
log_h->info("SYNC: Set DL EARFCN=%d, f_dl=%.1f MHz, f_ul=%.1f MHz\n", log_h->info("SYNC: Set DL EARFCN=%d, f_dl=%.1f MHz, f_ul=%.1f MHz\n",
current_earfcn, dl_freq / 1e6, ul_freq / 1e6); current_earfcn, set_dl_freq / 1e6, set_ul_freq / 1e6);
log_h->console("Searching cell in DL EARFCN=%d, f_dl=%.1f MHz, f_ul=%.1f MHz\n", log_h->console("Searching cell in DL EARFCN=%d, f_dl=%.1f MHz, f_ul=%.1f MHz\n",
current_earfcn, dl_freq / 1e6, ul_freq / 1e6); current_earfcn, set_dl_freq / 1e6, set_ul_freq / 1e6);
radio_h->set_rx_freq(dl_freq); radio_h->set_rx_freq(set_dl_freq);
radio_h->set_tx_freq(ul_freq); radio_h->set_tx_freq(set_ul_freq);
ul_dl_factor = radio_h->get_tx_freq()/radio_h->get_rx_freq(); ul_dl_factor = radio_h->get_tx_freq()/radio_h->get_rx_freq();
srslte_ue_sync_reset(&ue_sync); srslte_ue_sync_reset(&ue_sync);
@ -715,11 +732,11 @@ void phch_recv::run_thread() {
worker->set_sample_offset(srslte_ue_sync_get_sfo(&ue_sync)/1000); worker->set_sample_offset(srslte_ue_sync_get_sfo(&ue_sync)/1000);
/* Compute TX time: Any transmission happens in TTI4 thus advance 4 ms the reception time */ /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */
srslte_timestamp_t rx_time, tx_time, tx_time_prach; srslte_timestamp_t rx_time, tx_time, tx_time_prach;
srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time); srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time);
srslte_timestamp_copy(&tx_time, &rx_time); srslte_timestamp_copy(&tx_time, &rx_time);
srslte_timestamp_add(&tx_time, 0, 4e-3 - time_adv_sec); srslte_timestamp_add(&tx_time, 0, HARQ_DELAY_MS*1e-3 - time_adv_sec);
worker->set_tx_time(tx_time, next_offset); worker->set_tx_time(tx_time, next_offset);
next_offset = 0; next_offset = 0;

@ -293,6 +293,13 @@ void phch_worker::work_imp()
} }
} }
// Process RAR before UL to enable zero-delay Msg3
bool rar_delivered = false;
if (HARQ_DELAY_MS == MSG3_DELAY_MS && dl_mac_grant.rnti_type == SRSLTE_RNTI_RAR) {
rar_delivered = true;
phy->mac->tb_decoded(dl_ack[0], 0, dl_mac_grant.rnti_type, dl_mac_grant.pid);
}
// Decode PHICH // Decode PHICH
bool ul_ack = false; bool ul_ack = false;
bool ul_ack_available = decode_phich(&ul_ack); bool ul_ack_available = decode_phich(&ul_ack);
@ -313,8 +320,8 @@ void phch_worker::work_imp()
set_uci_periodic_cqi(); set_uci_periodic_cqi();
} }
/* TTI offset for UL is always 4 for LTE */ /* TTI offset for UL */
ul_action.tti_offset = 4; ul_action.tti_offset = HARQ_DELAY_MS;
/* Send UL grant or HARQ information (from PHICH) to MAC */ /* Send UL grant or HARQ information (from PHICH) to MAC */
if (ul_grant_available && ul_ack_available) { if (ul_grant_available && ul_ack_available) {
@ -335,7 +342,7 @@ void phch_worker::work_imp()
&ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar); &ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar);
signal_ready = true; signal_ready = true;
if (ul_action.expect_ack) { if (ul_action.expect_ack) {
phy->set_pending_ack(tti + 8, ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs); phy->set_pending_ack(TTI_RX_ACK(tti), ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs);
} }
} else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0) { } else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0) {
@ -357,7 +364,7 @@ void phch_worker::work_imp()
if (!dl_action.generate_ack_callback) { if (!dl_action.generate_ack_callback) {
if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH && dl_action.decode_enabled[0]) { if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH && dl_action.decode_enabled[0]) {
phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]); phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]);
} else { } else if (!rar_delivered) {
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (dl_action.decode_enabled[tb]) { if (dl_action.decode_enabled[tb]) {
phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid);
@ -475,7 +482,7 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant)
/* Fill MAC grant structure */ /* Fill MAC grant structure */
grant->ndi[0] = dci_unpacked.ndi; grant->ndi[0] = dci_unpacked.ndi;
grant->ndi[1] = dci_unpacked.ndi_1; grant->ndi[1] = dci_unpacked.ndi_1;
grant->pid = dci_unpacked.harq_process; grant->pid = ASYNC_DL_SCHED?dci_unpacked.harq_process:(tti%(2*HARQ_DELAY_MS));
grant->n_bytes[0] = grant->phy_grant.dl.mcs[0].tbs / (uint32_t) 8; grant->n_bytes[0] = grant->phy_grant.dl.mcs[0].tbs / (uint32_t) 8;
grant->n_bytes[1] = grant->phy_grant.dl.mcs[1].tbs / (uint32_t) 8; grant->n_bytes[1] = grant->phy_grant.dl.mcs[1].tbs / (uint32_t) 8;
grant->tti = tti; grant->tti = tti;
@ -663,7 +670,7 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant)
char timestr[64]; char timestr[64];
timestr[0]='\0'; timestr[0]='\0';
phy->reset_pending_ack(tti + 8); phy->reset_pending_ack(TTI_RX_ACK(tti));
srslte_dci_msg_t dci_msg; srslte_dci_msg_t dci_msg;
srslte_ra_ul_dci_t dci_unpacked; srslte_ra_ul_dci_t dci_unpacked;
@ -776,7 +783,7 @@ void phch_worker::set_uci_sr()
{ {
uci_data.scheduling_request = false; uci_data.scheduling_request = false;
if (phy->sr_enabled) { if (phy->sr_enabled) {
uint32_t sr_tx_tti = (tti+4)%10240; uint32_t sr_tx_tti = TTI_TX(tti);
// Get I_sr parameter // Get I_sr parameter
if (srslte_ue_ul_sr_send_tti(I_sr, sr_tx_tti)) { if (srslte_ue_ul_sr_send_tti(I_sr, sr_tx_tti)) {
Info("PUCCH: SR transmission at TTI=%d, I_sr=%d\n", sr_tx_tti, I_sr); Info("PUCCH: SR transmission at TTI=%d, I_sr=%d\n", sr_tx_tti, I_sr);
@ -793,7 +800,7 @@ void phch_worker::set_uci_periodic_cqi()
int cqi_max = phy->args->cqi_max; int cqi_max = phy->args->cqi_max;
if (period_cqi.configured && rnti_is_set) { if (period_cqi.configured && rnti_is_set) {
if (period_cqi.ri_idx_present && srslte_ri_send(period_cqi.pmi_idx, period_cqi.ri_idx, (tti+4)%10240)) { if (period_cqi.ri_idx_present && srslte_ri_send(period_cqi.pmi_idx, period_cqi.ri_idx, TTI_TX(tti))) {
if (uci_data.uci_ri_len) { if (uci_data.uci_ri_len) {
uci_data.uci_cqi[0] = uci_data.uci_ri; uci_data.uci_cqi[0] = uci_data.uci_ri;
uci_data.uci_cqi_len = uci_data.uci_ri_len; uci_data.uci_cqi_len = uci_data.uci_ri_len;
@ -802,7 +809,7 @@ void phch_worker::set_uci_periodic_cqi()
uci_data.uci_pmi_len = 0; uci_data.uci_pmi_len = 0;
Info("PUCCH: Periodic RI=%d\n", uci_data.uci_cqi[0]); Info("PUCCH: Periodic RI=%d\n", uci_data.uci_cqi[0]);
} }
} else if (srslte_cqi_send(period_cqi.pmi_idx, (tti+4)%10240)) { } else if (srslte_cqi_send(period_cqi.pmi_idx, TTI_TX(tti))) {
srslte_cqi_value_t cqi_report; srslte_cqi_value_t cqi_report;
if (period_cqi.format_is_subband) { if (period_cqi.format_is_subband) {
// TODO: Implement subband periodic reports // TODO: Implement subband periodic reports
@ -868,8 +875,8 @@ void phch_worker::set_uci_aperiodic_cqi()
bool phch_worker::srs_is_ready_to_send() { bool phch_worker::srs_is_ready_to_send() {
if (srs_cfg.configured) { if (srs_cfg.configured) {
if (srslte_refsignal_srs_send_cs(srs_cfg.subframe_config, (tti+4)%10) == 1 && if (srslte_refsignal_srs_send_cs(srs_cfg.subframe_config, TTI_TX(tti)%10) == 1 &&
srslte_refsignal_srs_send_ue(srs_cfg.I_srs, (tti+4)%10240) == 1) srslte_refsignal_srs_send_ue(srs_cfg.I_srs, TTI_TX(tti)) == 1)
{ {
return true; return true;
} }
@ -889,7 +896,7 @@ void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, ui
char timestr[64]; char timestr[64];
timestr[0]='\0'; timestr[0]='\0';
if (srslte_ue_ul_cfg_grant(&ue_ul, grant, (tti+4)%10240, rv, current_tx_nb)) { if (srslte_ue_ul_cfg_grant(&ue_ul, grant, TTI_TX(tti), rv, current_tx_nb)) {
Error("Configuring UL grant\n"); Error("Configuring UL grant\n");
} }
@ -915,16 +922,16 @@ void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, ui
#ifdef LOG_EXECTIME #ifdef LOG_EXECTIME
gettimeofday(&logtime_start[2], NULL); gettimeofday(&logtime_start[2], NULL);
get_time_interval(logtime_start); get_time_interval(logtime_start);
snprintf(timestr, 64, ", total_time=%4d us", (int) logtime_start[0].tv_usec); snprintf(timestr, 64, ", tot_time=%4d us", (int) logtime_start[0].tv_usec);
#endif #endif
Info("PUSCH: tti_tx=%d, n_prb=%d, rb_start=%d, tbs=%d, mod=%d, mcs=%d, rv_idx=%d, ack=%s, ri=%s, cfo=%.1f Hz%s\n", Info("PUSCH: tti_tx=%d, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d, ack=%s, ri=%s, cfo=%.1f KHz%s\n",
(tti+4)%10240, (tti+4)%10240,
grant->L_prb, grant->n_prb[0], grant->n_prb[0], grant->n_prb[0]+grant->L_prb,
grant->mcs.tbs/8, grant->mcs.mod, grant->mcs.idx, rv, grant->mcs.tbs/8, grant->mcs.idx, rv,
uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no", uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no",
uci_data.uci_ri_len>0?(uci_data.uci_ri?"1":"0"):"no", uci_data.uci_ri_len>0?(uci_data.uci_ri?"1":"0"):"no",
cfo*15000, timestr); cfo*15, timestr);
// Store metrics // Store metrics
ul_metrics.mcs = grant->mcs.idx; ul_metrics.mcs = grant->mcs.idx;
@ -950,7 +957,7 @@ void phch_worker::encode_pucch()
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
#endif #endif
if (srslte_ue_ul_pucch_encode(&ue_ul, uci_data, last_dl_pdcch_ncce, (tti+4)%10240, signal_buffer[0])) { if (srslte_ue_ul_pucch_encode(&ue_ul, uci_data, last_dl_pdcch_ncce, TTI_TX(tti), signal_buffer[0])) {
Error("Encoding PUCCH\n"); Error("Encoding PUCCH\n");
} }
@ -959,22 +966,22 @@ void phch_worker::encode_pucch()
memcpy(&t[2], &logtime_start[2], sizeof(struct timeval)); memcpy(&t[2], &logtime_start[2], sizeof(struct timeval));
get_time_interval(logtime_start); get_time_interval(logtime_start);
get_time_interval(t); get_time_interval(t);
snprintf(timestr, 64, ", enc_time=%d, total_time=%d us", (int) t[0].tv_usec, (int) logtime_start[0].tv_usec); snprintf(timestr, 64, ", tot_time=%d us", (int) logtime_start[0].tv_usec);
#endif #endif
float tx_power = srslte_ue_ul_pucch_power(&ue_ul, phy->pathloss, ue_ul.last_pucch_format, uci_data.uci_cqi_len, uci_data.uci_ack_len); float tx_power = srslte_ue_ul_pucch_power(&ue_ul, phy->pathloss, ue_ul.last_pucch_format, uci_data.uci_cqi_len, uci_data.uci_ack_len);
float gain = set_power(tx_power); float gain = set_power(tx_power);
Info("PUCCH: tti_tx=%d, n_cce=%3d, n_pucch=%d, n_prb=%d, ack=%s%s, ri=%s, pmi=%s%s, sr=%s, cfo=%.1f Hz%s\n", Info("PUCCH: tti_tx=%d, n_pucch=%d, n_prb=%d, ack=%s%s, ri=%s, pmi=%s%s, sr=%s, cfo=%.1f KHz%s\n",
(tti+4)%10240, (tti+4)%10240,
last_dl_pdcch_ncce, ue_ul.pucch.last_n_pucch, ue_ul.pucch.last_n_prb, ue_ul.pucch.last_n_pucch, ue_ul.pucch.last_n_prb,
uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no", uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no",
uci_data.uci_ack_len>1?(uci_data.uci_ack_2?"1":"0"):"", uci_data.uci_ack_len>1?(uci_data.uci_ack_2?"1":"0"):"",
uci_data.uci_ri_len>0?(uci_data.uci_ri?"1":"0"):"no", uci_data.uci_ri_len>0?(uci_data.uci_ri?"1":"0"):"no",
uci_data.uci_pmi_len>0?(uci_data.uci_pmi[1]?"1":"0"):"no", uci_data.uci_pmi_len>0?(uci_data.uci_pmi[1]?"1":"0"):"no",
uci_data.uci_pmi_len>0?(uci_data.uci_pmi[0]?"1":"0"):"", uci_data.uci_pmi_len>0?(uci_data.uci_pmi[0]?"1":"0"):"",
uci_data.scheduling_request?"yes":"no", uci_data.scheduling_request?"yes":"no",
cfo*15000, timestr); cfo*15, timestr);
} }
if (uci_data.scheduling_request) { if (uci_data.scheduling_request) {
@ -987,7 +994,7 @@ void phch_worker::encode_srs()
char timestr[64]; char timestr[64];
timestr[0]='\0'; timestr[0]='\0';
if (srslte_ue_ul_srs_encode(&ue_ul, (tti+4)%10240, signal_buffer[0])) if (srslte_ue_ul_srs_encode(&ue_ul, TTI_TX(tti), signal_buffer[0]))
{ {
Error("Encoding SRS\n"); Error("Encoding SRS\n");
} }
@ -995,14 +1002,14 @@ void phch_worker::encode_srs()
#ifdef LOG_EXECTIME #ifdef LOG_EXECTIME
gettimeofday(&logtime_start[2], NULL); gettimeofday(&logtime_start[2], NULL);
get_time_interval(logtime_start); get_time_interval(logtime_start);
snprintf(timestr, 64, ", total_time=%4d us", (int) logtime_start[0].tv_usec); snprintf(timestr, 64, ", tot_time=%4d us", (int) logtime_start[0].tv_usec);
#endif #endif
float tx_power = srslte_ue_ul_srs_power(&ue_ul, phy->pathloss); float tx_power = srslte_ue_ul_srs_power(&ue_ul, phy->pathloss);
float gain = set_power(tx_power); float gain = set_power(tx_power);
uint32_t fi = srslte_vec_max_fi((float*) signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb)); uint32_t fi = srslte_vec_max_fi((float*) signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb));
float *f = (float*) signal_buffer; float *f = (float*) signal_buffer;
Info("SRS: power=%.2f dBm, tti_tx=%d%s\n", tx_power, (tti+4)%10240, timestr); Info("SRS: power=%.2f dBm, tti_tx=%d%s\n", tx_power, TTI_TX(tti), timestr);
} }

@ -332,6 +332,11 @@ void phy::set_earfcn(vector< uint32_t > earfcns)
sf_recv.set_earfcn(earfcns); sf_recv.set_earfcn(earfcns);
} }
void phy::force_freq(float dl_freq, float ul_freq)
{
sf_recv.force_freq(dl_freq, ul_freq);
}
bool phy::sync_status() bool phy::sync_status()
{ {
return sf_recv.status_is_sync(); return sf_recv.status_is_sync();

@ -181,11 +181,10 @@ bool ue::init(all_args_t *args_)
rlc.init(&pdcp, &rrc, this, &rlc_log, &mac, 0 /* RB_ID_SRB0 */); rlc.init(&pdcp, &rrc, this, &rlc_log, &mac, 0 /* RB_ID_SRB0 */);
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK); pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK);
usim.init(&args->usim, &usim_log);
nas.init(&usim, &rrc, &gw, &nas_log, 1 /* RB_ID_SRB1 */); nas.init(&usim, &rrc, &gw, &nas_log, 1 /* RB_ID_SRB1 */);
gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */); gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */);
usim.init(&args->usim, &usim_log);
rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log); rrc.init(&phy, &mac, &rlc, &pdcp, &nas, &usim, &mac, &rrc_log);
rrc.set_ue_category(atoi(args->expert.ue_cateogry.c_str())); rrc.set_ue_category(atoi(args->expert.ue_cateogry.c_str()));
@ -194,6 +193,10 @@ bool ue::init(all_args_t *args_)
earfcn_list.push_back(args->rf.dl_earfcn); earfcn_list.push_back(args->rf.dl_earfcn);
phy.set_earfcn(earfcn_list); phy.set_earfcn(earfcn_list);
if (args->rf.dl_freq > 0 && args->rf.ul_freq > 0) {
phy.force_freq(args->rf.dl_freq, args->rf.ul_freq);
}
printf("Waiting PHY to initialize...\n"); printf("Waiting PHY to initialize...\n");
phy.wait_initialize(); phy.wait_initialize();
phy.configure_ul_params(); phy.configure_ul_params();

@ -50,8 +50,12 @@ void nas::init(usim_interface_nas *usim_,
nas_log = nas_log_; nas_log = nas_log_;
state = EMM_STATE_DEREGISTERED; state = EMM_STATE_DEREGISTERED;
plmn_selection = PLMN_NOT_SELECTED; plmn_selection = PLMN_NOT_SELECTED;
if (usim->get_home_plmn_id(&home_plmn)) {
nas_log->error("Getting Home PLMN Id from USIM. Defaulting to 001-01\n");
home_plmn.mcc = 61441; // This is 001 home_plmn.mcc = 61441; // This is 001
home_plmn.mnc = 65281; // This is 01 home_plmn.mnc = 65281; // This is 01
}
cfg = cfg_; cfg = cfg_;
} }
@ -64,6 +68,7 @@ emm_state_t nas::get_state() {
/******************************************************************************* /*******************************************************************************
UE interface UE interface
*******************************************************************************/ *******************************************************************************/
void nas::attach_request() { void nas::attach_request() {
nas_log->info("Attach Request\n"); nas_log->info("Attach Request\n");
if (state == EMM_STATE_DEREGISTERED) { if (state == EMM_STATE_DEREGISTERED) {
@ -72,7 +77,7 @@ void nas::attach_request() {
nas_log->info("Starting PLMN Search...\n"); nas_log->info("Starting PLMN Search...\n");
rrc->plmn_search(); rrc->plmn_search();
} else if (plmn_selection == PLMN_SELECTED) { } else if (plmn_selection == PLMN_SELECTED) {
nas_log->info("Selecting PLMN %s\n", plmn_id_to_c_str(current_plmn).c_str()); nas_log->info("Selecting PLMN %s\n", plmn_id_to_string(current_plmn).c_str());
rrc->plmn_select(current_plmn); rrc->plmn_select(current_plmn);
selecting_plmn = current_plmn; selecting_plmn = current_plmn;
} }
@ -96,25 +101,49 @@ RRC interface
void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) { void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) {
// Store PLMN if not registered // Check if already registered
for (uint32_t i=0;i<known_plmns.size();i++) { for (uint32_t i=0;i<known_plmns.size();i++) {
if (plmn_id.mcc == known_plmns[i].mcc && plmn_id.mnc == known_plmns[i].mnc) { if (plmn_id.mcc == known_plmns[i].mcc && plmn_id.mnc == known_plmns[i].mnc) {
nas_log->info("Detected known PLMN %s\n", plmn_id_to_c_str(plmn_id).c_str()); nas_log->info("Found known PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str());
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) { if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) {
nas_log->info("Connecting Home PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str());
rrc->plmn_select(plmn_id); rrc->plmn_select(plmn_id);
selecting_plmn = plmn_id; selecting_plmn = plmn_id;
} }
return; return;
} }
} }
nas_log->info("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_c_str(plmn_id).c_str(),
// Save if new PLMN
known_plmns.push_back(plmn_id);
nas_log->info("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(plmn_id).c_str(),
tracking_area_code); tracking_area_code);
nas_log->console("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_c_str(plmn_id).c_str(), nas_log->console("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(plmn_id).c_str(),
tracking_area_code); tracking_area_code);
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) { if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) {
rrc->plmn_select(plmn_id); rrc->plmn_select(plmn_id);
selecting_plmn = plmn_id; selecting_plmn = plmn_id;
} }
}
// RRC indicates that the UE has gone through all EARFCN and finished PLMN selection
void nas::plmn_search_end() {
if (known_plmns.size() > 0) {
nas_log->info("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n",
plmn_id_to_string(home_plmn).c_str(),
plmn_id_to_string(known_plmns[0]).c_str());
nas_log->console("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n",
plmn_id_to_string(home_plmn).c_str(),
plmn_id_to_string(known_plmns[0]).c_str());
rrc->plmn_select(known_plmns[0]);
} else {
nas_log->debug("Finished searching PLMN in current EARFCN set but no networks were found.\n");
}
} }
bool nas::is_attached() { bool nas::is_attached() {

@ -177,7 +177,7 @@ void rrc::run_thread() {
case RRC_STATE_PLMN_SELECTION: case RRC_STATE_PLMN_SELECTION:
plmn_select_timeout++; plmn_select_timeout++;
if (plmn_select_timeout >= RRC_PLMN_SELECT_TIMEOUT) { if (plmn_select_timeout >= RRC_PLMN_SELECT_TIMEOUT) {
rrc_log->info("RRC PLMN Search: timeout expired. Searching again\n"); rrc_log->info("RRC PLMN Search: timeout expired\n");
phy->cell_search_stop(); phy->cell_search_stop();
sleep(1); sleep(1);
rrc_log->console("\nRRC PLMN Search: timeout expired. Searching again\n"); rrc_log->console("\nRRC PLMN Search: timeout expired. Searching again\n");
@ -369,7 +369,7 @@ void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
state = RRC_STATE_CELL_SELECTING; state = RRC_STATE_CELL_SELECTING;
select_cell_timeout = 0; select_cell_timeout = 0;
} else { } else {
rrc_log->info("PLMN %s selected\n", plmn_id_to_c_str(plmn_id).c_str()); rrc_log->info("PLMN Id=%s selected\n", plmn_id_to_string(plmn_id).c_str());
// Sort cells according to RSRP // Sort cells according to RSRP
selected_plmn_id = plmn_id; selected_plmn_id = plmn_id;
@ -427,10 +427,12 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) {
if (!known_cells[i].has_valid_sib1) { if (!known_cells[i].has_valid_sib1) {
si_acquire_state = SI_ACQUIRE_SIB1; si_acquire_state = SI_ACQUIRE_SIB1;
} else { } else if (state == RRC_STATE_PLMN_SELECTION) {
for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) { for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) {
nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code); nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code);
} }
usleep(5000);
phy->cell_search_next();
} }
return; return;
} }
@ -454,6 +456,15 @@ void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) {
cell.earfcn, cell.rsrp); cell.earfcn, cell.rsrp);
} }
// PHY indicates that has gone through all known EARFCN
void rrc::earfcn_end() {
rrc_log->debug("Finished searching cells in EARFCN set while in state %s\n", rrc_state_text[state]);
// If searching for PLMN, indicate NAS we scanned all frequencies
if (state == RRC_STATE_PLMN_SELECTION) {
nas->plmn_search_end();
}
}

@ -25,13 +25,15 @@
*/ */
#include <sstream>
#include "upper/usim.h" #include "upper/usim.h"
#include "srslte/common/bcd_helpers.h"
using namespace srslte; using namespace srslte;
namespace srsue{ namespace srsue{
usim::usim() usim::usim() : initiated(false)
{} {}
void usim::init(usim_args_t *args, srslte::log *usim_log_) void usim::init(usim_args_t *args, srslte::log *usim_log_)
@ -91,6 +93,7 @@ void usim::init(usim_args_t *args, srslte::log *usim_log_)
if("xor" == args->algo) { if("xor" == args->algo) {
auth_algo = auth_algo_xor; auth_algo = auth_algo_xor;
} }
initiated = true;
} }
void usim::stop() void usim::stop()
@ -102,6 +105,11 @@ void usim::stop()
void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n)
{ {
if (!initiated)
{
usim_log->error("Getting IMSI: USIM not initiated\n");
return;
}
if(NULL == imsi_ || n < 15) if(NULL == imsi_ || n < 15)
{ {
usim_log->error("Invalid parameters to get_imsi_vec"); usim_log->error("Invalid parameters to get_imsi_vec");
@ -118,6 +126,11 @@ void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n)
void usim::get_imei_vec(uint8_t* imei_, uint32_t n) void usim::get_imei_vec(uint8_t* imei_, uint32_t n)
{ {
if (!initiated)
{
usim_log->error("Getting IMEI: USIM not initiated\n");
return;
}
if(NULL == imei_ || n < 15) if(NULL == imei_ || n < 15)
{ {
usim_log->error("Invalid parameters to get_imei_vec"); usim_log->error("Invalid parameters to get_imei_vec");
@ -132,6 +145,48 @@ void usim::get_imei_vec(uint8_t* imei_, uint32_t n)
} }
} }
int usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id)
{
if (!initiated)
{
usim_log->error("Getting Home PLMN Id: USIM not initiated\n");
return -1;
}
int mcc_len = 3;
int mnc_len = 2;
uint8_t imsi_vec[15];
get_imsi_vec(imsi_vec, 15);
std::ostringstream mcc_str, mnc_str;
for (int i=0;i<mcc_len;i++) {
mcc_str << (int) imsi_vec[i];
}
// US MCC uses 3 MNC digits
if (!mcc_str.str().compare("310") ||
!mcc_str.str().compare("311") ||
!mcc_str.str().compare("312") ||
!mcc_str.str().compare("313") ||
!mcc_str.str().compare("316"))
{
mnc_len = 3;
}
for (int i=mcc_len;i<mcc_len+mnc_len;i++) {
mnc_str << (int) imsi_vec[i];
}
string_to_mcc(mcc_str.str(), &home_plmn_id->mcc);
string_to_mnc(mnc_str.str(), &home_plmn_id->mnc);
usim_log->info("Read Home PLMN Id=%s\n",
plmn_id_to_string(*home_plmn_id).c_str());
return 0;
}
void usim::generate_authentication_response(uint8_t *rand, void usim::generate_authentication_response(uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,

@ -9,6 +9,8 @@
# rx_gain: Optional receive gain (dB). If disabled, AGC if enabled # rx_gain: Optional receive gain (dB). If disabled, AGC if enabled
# #
# Optional parameters: # Optional parameters:
# dl_freq: Override DL frequency corresponding to dl_earfcn
# ul_freq: Override UL frequency corresponding to dl_earfcn
# nof_rx_ant: Number of RX antennas (Default 1, supported 1 or 2) # nof_rx_ant: Number of RX antennas (Default 1, supported 1 or 2)
# device_name: Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF" # device_name: Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF"
# device_args: Arguments for the device driver. Options are "auto" or any string. # device_args: Arguments for the device driver. Options are "auto" or any string.

Loading…
Cancel
Save