Merge branch 'next' into mobility

master
Ismael Gomez 7 years ago
commit d428760b20

@ -55,6 +55,12 @@ if(NOT CMAKE_BUILD_TYPE)
endif(NOT CMAKE_BUILD_TYPE) endif(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
# Generate CMake to include build information
configure_file(
${CMAKE_SOURCE_DIR}/cmake/modules/SRSLTEbuildinfo.cmake.in
${CMAKE_BINARY_DIR}/SRSLTEbuildinfo.cmake
)
######################################################################## ########################################################################
# Options # Options
######################################################################## ########################################################################

@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 2.6)
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@"
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND git log -1 --format=%h
WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@"
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(STATUS "Generating build_info.h")
configure_file(
@CMAKE_SOURCE_DIR@/lib/include/srslte/build_info.h.in
@CMAKE_BINARY_DIR@/lib/include/srslte/build_info.h
)

@ -163,6 +163,8 @@ int main(int argc, char **argv) {
float cfo = 0; float cfo = 0;
bool acks[SRSLTE_MAX_CODEWORDS] = {false}; bool acks[SRSLTE_MAX_CODEWORDS] = {false};
srslte_debug_handle_crash(argc, argv);
if (parse_args(&prog_args, argc, argv)) { if (parse_args(&prog_args, argc, argv)) {
exit(-1); exit(-1);
} }

@ -153,6 +153,8 @@ int main(int argc, char **argv) {
uint32_t freq; uint32_t freq;
uint32_t n_found_cells=0; uint32_t n_found_cells=0;
srslte_debug_handle_crash(argc, argv);
parse_args(argc, argv); parse_args(argc, argv);
printf("Opening RF device...\n"); printf("Opening RF device...\n");

@ -701,6 +701,8 @@ int main(int argc, char **argv) {
srslte_refsignal_t csr_refs; srslte_refsignal_t csr_refs;
srslte_refsignal_t mbsfn_refs; srslte_refsignal_t mbsfn_refs;
srslte_debug_handle_crash(argc, argv);
#ifdef DISABLE_RF #ifdef DISABLE_RF
if (argc < 3) { if (argc < 3) {
usage(argv[0]); usage(argv[0]);

@ -326,6 +326,7 @@ srslte_netsink_t net_sink, net_sink_signal;
#define PRINT_LINE_ADVANCE_CURSOR() printf("\033[%dB", prev_nof_lines + 1) #define PRINT_LINE_ADVANCE_CURSOR() printf("\033[%dB", prev_nof_lines + 1)
int main(int argc, char **argv) { int main(int argc, char **argv) {
struct timeval t[3];
int ret; int ret;
int decimate = 1; int decimate = 1;
srslte_cell_t cell; srslte_cell_t cell;
@ -340,6 +341,8 @@ int main(int argc, char **argv) {
int sfn_offset; int sfn_offset;
float cfo = 0; float cfo = 0;
srslte_debug_handle_crash(argc, argv);
parse_args(&prog_args, argc, argv); parse_args(&prog_args, argc, argv);
for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) { for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) {
@ -559,7 +562,7 @@ int main(int argc, char **argv) {
// Variables for measurements // Variables for measurements
uint32_t nframes=0; uint32_t nframes=0;
uint8_t ri = 0, pmi = 0; uint8_t ri = 0, pmi = 0;
float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0, float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0, procrate = 0.0,
sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS], cn = 0.0; sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS], cn = 0.0;
bool decode_pdsch = false; bool decode_pdsch = false;
@ -655,6 +658,7 @@ int main(int argc, char **argv) {
decode_pdsch = false; decode_pdsch = false;
} }
} }
gettimeofday(&t[1], NULL);
if (decode_pdsch) { if (decode_pdsch) {
if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe
if (cell.nof_ports == 1) { if (cell.nof_ports == 1) {
@ -690,6 +694,8 @@ int main(int argc, char **argv) {
INFO("mbsfn PDU size is %d\n", n); INFO("mbsfn PDU size is %d\n", n);
} }
} }
gettimeofday(&t[2], NULL);
get_time_interval(t);
if (n < 0) { if (n < 0) {
// fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); // fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
} else if (n > 0) { } else if (n > 0) {
@ -725,14 +731,17 @@ int main(int argc, char **argv) {
nof_trials++; nof_trials++;
uint32_t nof_bits = ((acks[0]?ue_dl.pdsch_cfg.grant.mcs[0].tbs:0) + (acks[1]?ue_dl.pdsch_cfg.grant.mcs[1].tbs:0));
rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1f); rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1f);
rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05f); rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05f);
rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05f); rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05f);
noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05f); noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05f);
enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs[0].tbs + ue_dl.pdsch_cfg.grant.mcs[1].tbs)/1000.0f, enodebrate, 0.05f); enodebrate = SRSLTE_VEC_EMA(nof_bits/1000.0f, enodebrate, 0.05f);
uerate = SRSLTE_VEC_EMA(((acks[0]?ue_dl.pdsch_cfg.grant.mcs[0].tbs:0) + (acks[1]?ue_dl.pdsch_cfg.grant.mcs[1].tbs:0))/1000.0f, uerate, 0.01f); uerate = SRSLTE_VEC_EMA(nof_bits/1000.0f, uerate, 0.001f);
float elapsed = (float) t[0].tv_usec + t[0].tv_sec*1.0e+6f;
if (elapsed != 0.0f) {
procrate = SRSLTE_VEC_EMA(nof_bits/elapsed, procrate, 0.01f);
}
nframes++; nframes++;
if (isnan(rsrq)) { if (isnan(rsrq)) {
@ -769,7 +778,7 @@ int main(int argc, char **argv) {
PRINT_LINE("nof codewords: %d", SRSLTE_RA_DL_GRANT_NOF_TB(&ue_dl.pdsch_cfg.grant)); PRINT_LINE("nof codewords: %d", SRSLTE_RA_DL_GRANT_NOF_TB(&ue_dl.pdsch_cfg.grant));
PRINT_LINE(" CFO: %+5.2f kHz", srslte_ue_sync_get_cfo(&ue_sync) / 1000); PRINT_LINE(" CFO: %+5.2f kHz", srslte_ue_sync_get_cfo(&ue_sync) / 1000);
PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise)); PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise));
PRINT_LINE(" Rb: %6.2f / %6.2f Mbps (net/maximum)", uerate, enodebrate); PRINT_LINE(" Rb: %6.2f / %6.2f / %6.2f Mbps (net/maximum/processing)", uerate, enodebrate, procrate);
PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials));
PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pdsch_pkt_errors / ue_dl.pdsch_pkts_total); PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pdsch_pkt_errors / ue_dl.pdsch_pkts_total);
if(prog_args.mbsfn_area_id > -1){ if(prog_args.mbsfn_area_id > -1){

@ -2721,6 +2721,10 @@ typedef struct{
// Functions // Functions
LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req, LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req,
LIBLTE_BYTE_MSG_STRUCT *msg); LIBLTE_BYTE_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req,
uint8 sec_hdr_type,
uint32 count,
LIBLTE_BYTE_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req); LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req);

@ -3930,7 +3930,7 @@ typedef enum{
}LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM; }LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM;
static const char liblte_rrc_pdsch_config_p_a_text[LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS][20] = { "-6", "-4.77", "-3", "-1.77", static const char liblte_rrc_pdsch_config_p_a_text[LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS][20] = { "-6", "-4.77", "-3", "-1.77",
"0", "1", "2", "3"}; "0", "1", "2", "3"};
static const double liblte_rrc_pdsch_config_p_a_num[LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS] = {-6, -4.77, -3, -1.77, 0, 1, 2, 3}; static const float liblte_rrc_pdsch_config_p_a_num[LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS] = {-6, -4.77f, -3, -1.77f, 0, 1, 2, 3};
// Structs // Structs
// PDSCH Config Common struct defined above // PDSCH Config Common struct defined above
// Functions // Functions

@ -0,0 +1,56 @@
/**
*
* \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/.
*
*/
#ifndef BUILD_INFO_
#define BUILD_INFO_
# ifdef __cplusplus
extern "C" {
# endif
#ifdef NDEBUG
static char build_mode[] = "Release";
#else
static char build_mode[] = "Debug";
#endif
// the configured build options for srsLTE
static char build_info[] = "commit @GIT_COMMIT_HASH@ on branch @GIT_BRANCH@";
SRSLTE_API char* srslte_get_build_info() {
return build_info;
};
SRSLTE_API char* srslte_get_build_mode() {
return build_mode;
}
# ifdef __cplusplus
}
# endif
#endif // BUILD_INFO_

@ -123,8 +123,6 @@ public:
used.erase(elem); used.erase(elem);
available.push(b); available.push(b);
ret = true; ret = true;
} else {
printf("Error deallocating from buffer pool: buffer not created in this pool.\n");
} }
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
return ret; return ret;

@ -46,9 +46,12 @@
#define HARQ_DELAY_MS 4 #define HARQ_DELAY_MS 4
#define MSG3_DELAY_MS 2 // Delay added to HARQ_DELAY_MS #define MSG3_DELAY_MS 2 // Delay added to HARQ_DELAY_MS
#define TTI_RX(tti) (tti>HARQ_DELAY_MS?((tti-HARQ_DELAY_MS)%10240):(10240+tti-HARQ_DELAY_MS))
#define TTI_TX(tti) ((tti+HARQ_DELAY_MS)%10240) #define TTI_TX(tti) ((tti+HARQ_DELAY_MS)%10240)
#define TTI_RX_ACK(tti) ((tti+(2*HARQ_DELAY_MS))%10240) #define TTI_RX_ACK(tti) ((tti+(2*HARQ_DELAY_MS))%10240)
#define UL_PIDOF(tti) (tti%(2*HARQ_DELAY_MS))
#define TTIMOD_SZ (((2*HARQ_DELAY_MS) < 10)?10:20) #define TTIMOD_SZ (((2*HARQ_DELAY_MS) < 10)?10:20)
#define TTIMOD(tti) (tti%TTIMOD_SZ) #define TTIMOD(tti) (tti%TTIMOD_SZ)

@ -52,16 +52,20 @@ class ue_interface
class usim_interface_nas class usim_interface_nas
{ {
public: public:
virtual void get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; virtual std::string get_imsi_str() = 0;
virtual void get_imei_vec(uint8_t* imei_, uint32_t n) = 0; virtual std::string get_imei_str() = 0;
virtual int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0; virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0;
virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0;
virtual bool 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,
uint16_t mnc, uint16_t mnc,
bool *net_valid, bool *net_valid,
uint8_t *res) = 0; uint8_t *res,
virtual void generate_nas_keys(uint8_t *k_nas_enc, uint8_t *k_asme) = 0;
virtual void generate_nas_keys(uint8_t *k_asme,
uint8_t *k_nas_enc,
uint8_t *k_nas_int, uint8_t *k_nas_int,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0;
@ -71,7 +75,8 @@ public:
class usim_interface_rrc class usim_interface_rrc
{ {
public: public:
virtual void generate_as_keys(uint32_t count_ul, virtual void generate_as_keys(uint8_t *k_asme,
uint32_t count_ul,
uint8_t *k_rrc_enc, uint8_t *k_rrc_enc,
uint8_t *k_rrc_int, uint8_t *k_rrc_int,
uint8_t *k_up_enc, uint8_t *k_up_enc,
@ -112,6 +117,7 @@ public:
virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
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 bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0;
virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0; virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0;
virtual void plmn_search_end() = 0; virtual void plmn_search_end() = 0;
}; };

@ -49,18 +49,21 @@
*/ */
SRSLTE_API int srslte_precoding_single(cf_t *x, SRSLTE_API int srslte_precoding_single(cf_t *x,
cf_t *y, cf_t *y,
int nof_symbols); int nof_symbols,
float scaling);
SRSLTE_API int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], SRSLTE_API int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS],
cf_t *y[SRSLTE_MAX_PORTS], cf_t *y[SRSLTE_MAX_PORTS],
int nof_ports, int nof_ports,
int nof_symbols); int nof_symbols,
float scaling);
SRSLTE_API int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], SRSLTE_API int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS],
cf_t *y[SRSLTE_MAX_PORTS], cf_t *y[SRSLTE_MAX_PORTS],
int nof_layers, int nof_layers,
int nof_ports, int nof_ports,
int nof_symbols); int nof_symbols,
float scaling);
SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS],
cf_t *y[SRSLTE_MAX_PORTS], cf_t *y[SRSLTE_MAX_PORTS],
@ -68,6 +71,7 @@ SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_ports,
int codebook_idx, int codebook_idx,
int nof_symbols, int nof_symbols,
float scaling,
srslte_mimo_type_t type); srslte_mimo_type_t type);
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "h" /* Estimates the vector "x" based on the received signal "y" and the channel estimates "h"
@ -76,6 +80,7 @@ SRSLTE_API int srslte_predecoding_single(cf_t *y,
cf_t *h, cf_t *h,
cf_t *x, cf_t *x,
int nof_symbols, int nof_symbols,
float scaling,
float noise_estimate); float noise_estimate);
SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS],
@ -83,33 +88,27 @@ SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *x, cf_t *x,
int nof_rxant, int nof_rxant,
int nof_symbols, int nof_symbols,
float scaling,
float noise_estimate); float noise_estimate);
SRSLTE_API int srslte_predecoding_diversity(cf_t *y, SRSLTE_API int srslte_predecoding_diversity(cf_t *y,
cf_t *h[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_ports,
int nof_symbols); int nof_symbols,
float scaling);
SRSLTE_API int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], SRSLTE_API int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_rxant,
int nof_ports, int nof_ports,
int nof_symbols);
SRSLTE_API int srslte_predecoding_type(cf_t *y,
cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports,
int nof_layers,
int nof_symbols, int nof_symbols,
srslte_mimo_type_t type, float scaling);
float noise_estimate);
SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder); SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder);
SRSLTE_API int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], SRSLTE_API int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_rxant,
@ -118,6 +117,7 @@ SRSLTE_API int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS],
int codebook_idx, int codebook_idx,
int nof_symbols, int nof_symbols,
srslte_mimo_type_t type, srslte_mimo_type_t type,
float scaling,
float noise_estimate); float noise_estimate);
SRSLTE_API int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], SRSLTE_API int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],

@ -65,6 +65,9 @@ typedef struct SRSLTE_API {
uint16_t ue_rnti; uint16_t ue_rnti;
bool is_ue; bool is_ue;
/* Power allocation parameter 3GPP 36.213 Clause 5.2 Rho_b */
float rho_a;
/* buffers */ /* buffers */
// void buffers are shared for tx and rx // void buffers are shared for tx and rx
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */ cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */
@ -101,6 +104,9 @@ SRSLTE_API int srslte_pdsch_set_cell(srslte_pdsch_t *q,
SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t *q, SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t *q,
uint16_t rnti); uint16_t rnti);
SRSLTE_API void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q,
float rho_a);
SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t *q, SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t *q,
uint16_t rnti); uint16_t rnti);

@ -39,6 +39,13 @@
#include "srslte/phy/fec/softbuffer.h" #include "srslte/phy/fec/softbuffer.h"
#include "srslte/phy/fec/cbsegm.h" #include "srslte/phy/fec/cbsegm.h"
/* 3GPP 36.213 Table 5.2-1: The cell-specific ratio rho_B / rho_A for 1, 2, or 4 cell specific antenna ports */
static const float pdsch_cfg_cell_specific_ratio_table[2][4] =
{ /* One antenna port */ {1.0f / 1.0f, 4.0f / 5.0f, 3.0f / 5.0f, 2.0f / 5.0f},
/* Two or more antenna port */ {5.0f / 4.0f, 1.0f / 1.0f, 3.0f / 4.0f, 1.0f / 2.0f}
};
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_cbsegm_t cb_segm[SRSLTE_MAX_CODEWORDS]; srslte_cbsegm_t cb_segm[SRSLTE_MAX_CODEWORDS];
srslte_ra_dl_grant_t grant; srslte_ra_dl_grant_t grant;

@ -38,10 +38,13 @@
#define RESAMPLE_ARB_ #define RESAMPLE_ARB_
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include <complex.h> #include <complex.h>
#include "srslte/config.h" #include "srslte/config.h"
#define SRSLTE_RESAMPLE_ARB_N_35 35
#define SRSLTE_RESAMPLE_ARB_N 32 // Polyphase filter rows #define SRSLTE_RESAMPLE_ARB_N 32 // Polyphase filter rows
#define SRSLTE_RESAMPLE_ARB_M 8 // Polyphase filter columns #define SRSLTE_RESAMPLE_ARB_M 8 // Polyphase filter columns
@ -49,11 +52,13 @@ typedef struct SRSLTE_API {
float rate; // Resample rate float rate; // Resample rate
float step; // Step increment through filter float step; // Step increment through filter
float acc; // Index into filter float acc; // Index into filter
bool interpolate;
cf_t reg[SRSLTE_RESAMPLE_ARB_M]; // Our window of samples cf_t reg[SRSLTE_RESAMPLE_ARB_M]; // Our window of samples
} srslte_resample_arb_t; } srslte_resample_arb_t;
SRSLTE_API void srslte_resample_arb_init(srslte_resample_arb_t *q, SRSLTE_API void srslte_resample_arb_init(srslte_resample_arb_t *q,
float rate); float rate, bool interpolate);
SRSLTE_API int srslte_resample_arb_compute(srslte_resample_arb_t *q, SRSLTE_API int srslte_resample_arb_compute(srslte_resample_arb_t *q,
cf_t *input, cf_t *input,

@ -139,6 +139,10 @@ SRSLTE_API srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q,
uint32_t find_offset, uint32_t find_offset,
uint32_t *peak_position); uint32_t *peak_position);
SRSLTE_API float srslte_sync_cfo_estimate(srslte_sync_t *q,
cf_t *input,
int find_offset);
/* Estimates the CP length */ /* Estimates the CP length */
SRSLTE_API srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, SRSLTE_API srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q,
cf_t *input, cf_t *input,

@ -104,6 +104,9 @@ typedef struct SRSLTE_API {
uint32_t pmi[SRSLTE_MAX_LAYERS]; uint32_t pmi[SRSLTE_MAX_LAYERS];
uint32_t ri; uint32_t ri;
/* Power allocation parameter 3GPP 36.213 Clause 5.2 Rho_b */
float rho_b;
srslte_dci_format_t dci_format; srslte_dci_format_t dci_format;
uint64_t pkt_errors; uint64_t pkt_errors;
uint64_t pkts_total; uint64_t pkts_total;
@ -244,6 +247,9 @@ SRSLTE_API int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t *q,
SRSLTE_API void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q, SRSLTE_API void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q,
uint8_t non_mbsfn_region_length); uint8_t non_mbsfn_region_length);
SRSLTE_API void srslte_ue_dl_set_power_alloc(srslte_ue_dl_t *q,
float rho_a,
float rho_b);
SRSLTE_API void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, SRSLTE_API void srslte_ue_dl_save_signal(srslte_ue_dl_t *q,

@ -89,6 +89,11 @@ typedef struct SRSLTE_API {
float file_cfo; float file_cfo;
srslte_cfo_t file_cfo_correct; srslte_cfo_t file_cfo_correct;
bool mean_cfo_isunset;
float cfo;
float mean_cfo;
float cfo_ema_alpha;
srslte_ue_sync_state_t state; srslte_ue_sync_state_t state;
uint32_t frame_len; uint32_t frame_len;

@ -70,4 +70,6 @@ SRSLTE_API extern int srslte_verbose;
#define ERROR(_fmt, ...) fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__) #define ERROR(_fmt, ...) fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__)
#endif /* CMAKE_BUILD_TYPE==Debug */ #endif /* CMAKE_BUILD_TYPE==Debug */
void srslte_debug_handle_crash(int argc, char **argv);
#endif // DEBUG_H #endif // DEBUG_H

@ -449,7 +449,12 @@ static inline simd_f_t srslte_simd_f_sqrt(simd_f_t a) {
#ifdef HAVE_NEON #ifdef HAVE_NEON
float32x4_t sqrt_reciprocal = vrsqrteq_f32(a); float32x4_t sqrt_reciprocal = vrsqrteq_f32(a);
sqrt_reciprocal = vmulq_f32(vrsqrtsq_f32(vmulq_f32(a,sqrt_reciprocal), sqrt_reciprocal),sqrt_reciprocal); sqrt_reciprocal = vmulq_f32(vrsqrtsq_f32(vmulq_f32(a,sqrt_reciprocal), sqrt_reciprocal),sqrt_reciprocal);
return vmulq_f32(a,sqrt_reciprocal); float32x4_t result = vmulq_f32(a,sqrt_reciprocal);
/* Detect zeros in NEON 1/sqrtf for preventing NaN */
float32x4_t zeros = vmovq_n_f32(0); /* Zero vector */
uint32x4_t mask = vceqq_f32(a, zeros); /* Zero vector mask */
return vbslq_f32(mask, zeros, result); /* Force zero results and return */
#endif /* HAVE_NEON */ #endif /* HAVE_NEON */
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX2 */ #endif /* LV_HAVE_AVX2 */

@ -1411,9 +1411,9 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_eps_mobile_id_ie(LIBLTE_MME_EPS_MOBILE_ID_STRU
**ie_ptr = (((eps_mobile_id->guti.mnc/10) % 10) << 4) | ((eps_mobile_id->guti.mnc/100) % 10); **ie_ptr = (((eps_mobile_id->guti.mnc/10) % 10) << 4) | ((eps_mobile_id->guti.mnc/100) % 10);
*ie_ptr += 1; *ie_ptr += 1;
} }
**ie_ptr = (eps_mobile_id->guti.mme_group_id >> 8) & 0x0F; **ie_ptr = (eps_mobile_id->guti.mme_group_id >> 8) & 0xFF;
*ie_ptr += 1; *ie_ptr += 1;
**ie_ptr = eps_mobile_id->guti.mme_group_id & 0x0F; **ie_ptr = eps_mobile_id->guti.mme_group_id & 0xFF;
*ie_ptr += 1; *ie_ptr += 1;
**ie_ptr = eps_mobile_id->guti.mme_code; **ie_ptr = eps_mobile_id->guti.mme_code;
*ie_ptr += 1; *ie_ptr += 1;
@ -5518,6 +5518,14 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_reject_msg(LIBLTE_BYTE_MSG_STRUCT
*********************************************************************/ *********************************************************************/
LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req, LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req,
LIBLTE_BYTE_MSG_STRUCT *msg) LIBLTE_BYTE_MSG_STRUCT *msg)
{
return liblte_mme_pack_attach_request_msg(attach_req, LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS, 0, msg);
}
LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req,
uint8 sec_hdr_type,
uint32 count,
LIBLTE_BYTE_MSG_STRUCT *msg)
{ {
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg; uint8 *msg_ptr = msg->msg;
@ -5525,6 +5533,20 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_M
if(attach_req != NULL && if(attach_req != NULL &&
msg != NULL) msg != NULL)
{ {
if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type)
{
// Protocol Discriminator and Security Header Type
*msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg_ptr++;
// MAC will be filled in later
msg_ptr += 4;
// Sequence Number
*msg_ptr = count & 0xFF;
msg_ptr++;
}
// Protocol Discriminator and Security Header Type // Protocol Discriminator and Security Header Type
*msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg_ptr++; msg_ptr++;

@ -22,7 +22,9 @@ file(GLOB CXX_SOURCES "*.cc")
file(GLOB C_SOURCES "*.c") file(GLOB C_SOURCES "*.c")
add_library(srslte_common STATIC ${C_SOURCES} ${CXX_SOURCES}) add_library(srslte_common STATIC ${C_SOURCES} ${CXX_SOURCES})
add_custom_target(gen_build_info COMMAND cmake -P ${CMAKE_BINARY_DIR}/SRSLTEbuildinfo.cmake)
add_dependencies(srslte_common gen_build_info)
target_include_directories(srslte_common PUBLIC ${SEC_INCLUDE_DIRS}) target_include_directories(srslte_common PUBLIC ${SEC_INCLUDE_DIRS})
target_link_libraries(srslte_common ${SEC_LIBRARIES}) target_link_libraries(srslte_common ${SEC_LIBRARIES})
install(TARGETS srslte_common DESTINATION ${LIBRARY_DIR}) install(TARGETS srslte_common DESTINATION ${LIBRARY_DIR})

@ -117,7 +117,7 @@ void srslte_agc_lock(srslte_agc_t *q, bool enable) {
void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) {
if (!q->lock) { if (!q->lock) {
float gain_db = 10*log10(q->gain); float gain_db = 10*log10(q->gain);
float gain_uhd_db = 1.0; float gain_uhd_db = 50.0;
//float gain_uhd = 1.0; //float gain_uhd = 1.0;
float y = 0; float y = 0;
// Apply current gain to input signal // Apply current gain to input signal
@ -125,10 +125,10 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) {
srslte_vec_sc_prod_cfc(signal, q->gain, signal, len); srslte_vec_sc_prod_cfc(signal, q->gain, signal, len);
} else { } else {
if (gain_db < 0) { if (gain_db < 0) {
gain_db = 0.0; gain_db = 5.0;
} }
if (isinf(gain_db) || isnan(gain_db)) { if (isinf(gain_db) || isnan(gain_db)) {
gain_db = 10.0; gain_db = 40.0;
} else { } else {
gain_uhd_db = q->set_gain_callback(q->uhd_handler, gain_db); gain_uhd_db = q->set_gain_callback(q->uhd_handler, gain_db);
q->gain = pow(10, gain_uhd_db/10); q->gain = pow(10, gain_uhd_db/10);

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

@ -37,13 +37,13 @@
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
#include <immintrin.h> #include <immintrin.h>
int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate);
int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_symbols); int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_symbols, float scaling);
#endif #endif
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
#include <immintrin.h> #include <immintrin.h>
int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate);
#endif #endif
#include "srslte/phy/utils/mat.h" #include "srslte/phy/utils/mat.h"
@ -59,7 +59,7 @@ static srslte_mimo_decoder_t mimo_decoder = SRSLTE_MIMO_DECODER_MMSE;
#define PROD(a,b) _mm_addsub_ps(_mm_mul_ps(a,_mm_moveldup_ps(b)),_mm_mul_ps(_mm_shuffle_ps(a,a,0xB1),_mm_movehdup_ps(b))) #define PROD(a,b) _mm_addsub_ps(_mm_mul_ps(a,_mm_moveldup_ps(b)),_mm_mul_ps(_mm_shuffle_ps(a,a,0xB1),_mm_movehdup_ps(b)))
int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate) {
float *xPtr = (float*) x; float *xPtr = (float*) x;
const float *hPtr1 = (const float*) h[0]; const float *hPtr1 = (const float*) h[0];
@ -123,6 +123,9 @@ int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
x1Val1 = _mm_div_ps(x1Val1, h1square); x1Val1 = _mm_div_ps(x1Val1, h1square);
x2Val1 = _mm_div_ps(x2Val1, h2square); x2Val1 = _mm_div_ps(x2Val1, h2square);
x1Val1 = _mm_mul_ps(x1Val1, _mm_set1_ps(1/scaling));
x2Val1 = _mm_mul_ps(x2Val1, _mm_set1_ps(1/scaling));
_mm_store_ps(xPtr, x1Val1); xPtr+=4; _mm_store_ps(xPtr, x1Val1); xPtr+=4;
_mm_store_ps(xPtr, x2Val1); xPtr+=4; _mm_store_ps(xPtr, x2Val1); xPtr+=4;
@ -134,7 +137,7 @@ int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
r += y[p][i]*conj(h[p][i]); r += y[p][i]*conj(h[p][i]);
hh += conj(h[p][i])*h[p][i]; hh += conj(h[p][i])*h[p][i];
} }
x[i] = r/(hh+noise_estimate); x[i] = scaling*r/(hh+noise_estimate);
} }
return nof_symbols; return nof_symbols;
} }
@ -147,7 +150,7 @@ int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate) {
float *xPtr = (float*) x; float *xPtr = (float*) x;
const float *hPtr1 = (const float*) h[0]; const float *hPtr1 = (const float*) h[0];
@ -160,6 +163,8 @@ int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
__m256 noise = _mm256_set1_ps(noise_estimate); __m256 noise = _mm256_set1_ps(noise_estimate);
__m256 h1Val1, h2Val1, y1Val1, y2Val1, h12square, h1square, h2square, h1_p, h2_p, h1conj1, h2conj1, x1Val, x2Val; __m256 h1Val1, h2Val1, y1Val1, y2Val1, h12square, h1square, h2square, h1_p, h2_p, h1conj1, h2conj1, x1Val, x2Val;
__m256 h1Val2, h2Val2, y1Val2, y2Val2, h1conj2, h2conj2; __m256 h1Val2, h2Val2, y1Val2, y2Val2, h1conj2, h2conj2;
__m256 avx_scaling = _mm256_set1_ps(1/scaling);
for (int i=0;i<nof_symbols/8;i++) { for (int i=0;i<nof_symbols/8;i++) {
y1Val1 = _mm256_load_ps(yPtr1); yPtr1+=8; y1Val1 = _mm256_load_ps(yPtr1); yPtr1+=8;
@ -214,6 +219,9 @@ int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
x1Val = _mm256_div_ps(x1Val, h1square); x1Val = _mm256_div_ps(x1Val, h1square);
x2Val = _mm256_div_ps(x2Val, h2square); x2Val = _mm256_div_ps(x2Val, h2square);
x1Val = _mm256_mul_ps(x1Val, avx_scaling);
x2Val = _mm256_mul_ps(x2Val, avx_scaling);
_mm256_store_ps(xPtr, x1Val); xPtr+=8; _mm256_store_ps(xPtr, x1Val); xPtr+=8;
_mm256_store_ps(xPtr, x2Val); xPtr+=8; _mm256_store_ps(xPtr, x2Val); xPtr+=8;
} }
@ -224,14 +232,14 @@ int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
r += y[p][i]*conj(h[p][i]); r += y[p][i]*conj(h[p][i]);
hh += conj(h[p][i])*h[p][i]; hh += conj(h[p][i])*h[p][i];
} }
x[i] = r/(hh+noise_estimate); x[i] = r/((hh+noise_estimate) * scaling);
} }
return nof_symbols; return nof_symbols;
} }
#endif #endif
int srslte_predecoding_single_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { int srslte_predecoding_single_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate) {
for (int i=0;i<nof_symbols;i++) { for (int i=0;i<nof_symbols;i++) {
cf_t r = 0; cf_t r = 0;
cf_t hh = 0; cf_t hh = 0;
@ -239,13 +247,13 @@ int srslte_predecoding_single_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
r += y[p][i]*conj(h[p][i]); r += y[p][i]*conj(h[p][i]);
hh += conj(h[p][i])*h[p][i]; hh += conj(h[p][i])*h[p][i];
} }
x[i] = r/(hh+noise_estimate); x[i] = r / ((hh+noise_estimate) * scaling);
} }
return nof_symbols; return nof_symbols;
} }
/* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/ /* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/
int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, float noise_estimate) { int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, float scaling, float noise_estimate) {
cf_t *y[SRSLTE_MAX_PORTS]; cf_t *y[SRSLTE_MAX_PORTS];
cf_t *h[SRSLTE_MAX_PORTS]; cf_t *h[SRSLTE_MAX_PORTS];
@ -255,40 +263,41 @@ int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, floa
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
if (nof_symbols > 32 && nof_rxant <= 2) { if (nof_symbols > 32 && nof_rxant <= 2) {
return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} else { } else {
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} }
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
if (nof_symbols > 32 && nof_rxant <= 2) { if (nof_symbols > 32 && nof_rxant <= 2) {
return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} else { } else {
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} }
#else #else
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
#endif #endif
#endif #endif
} }
/* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/ /* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/
int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x,
int nof_rxant, int nof_symbols, float scaling, float noise_estimate) {
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
if (nof_symbols > 32) { if (nof_symbols > 32) {
return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} else { } else {
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} }
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
if (nof_symbols > 32) { if (nof_symbols > 32) {
return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} else { } else {
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} }
#else #else
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
#endif #endif
#endif #endif
} }
@ -296,7 +305,7 @@ int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MA
/* C implementatino of the SFBC equalizer */ /* C implementatino of the SFBC equalizer */
int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_symbols, int symbol_start) int nof_rxant, int nof_ports, int nof_symbols, int symbol_start, float scaling)
{ {
int i; int i;
if (nof_ports == 2) { if (nof_ports == 2) {
@ -321,6 +330,7 @@ int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
x0 += (conjf(h00) * r0 + h11 * conjf(r1)); x0 += (conjf(h00) * r0 + h11 * conjf(r1));
x1 += (-h10 * conj(r0) + conj(h01) * r1); x1 += (-h10 * conj(r0) + conj(h01) * r1);
} }
hh *= scaling;
x[0][i] = x0 / hh * sqrt(2); x[0][i] = x0 / hh * sqrt(2);
x[1][i] = x1 / hh * sqrt(2); x[1][i] = x1 / hh * sqrt(2);
} }
@ -351,6 +361,10 @@ int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
x2 += (conjf(h1) * r2 + h3 * conjf(r3)); x2 += (conjf(h1) * r2 + h3 * conjf(r3));
x3 += (-h3 * conjf(r2) + conjf(h1) * r3); x3 += (-h3 * conjf(r2) + conjf(h1) * r3);
} }
hh02 *= scaling;
hh13 *= scaling;
x[0][i] = x0 / hh02 * sqrt(2); x[0][i] = x0 / hh02 * sqrt(2);
x[1][i] = x1 / hh02 * sqrt(2); x[1][i] = x1 / hh02 * sqrt(2);
x[2][i] = x2 / hh13 * sqrt(2); x[2][i] = x2 / hh13 * sqrt(2);
@ -365,15 +379,15 @@ int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
int srslte_predecoding_diversity_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_diversity_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_symbols) { int nof_rxant, int nof_ports, int nof_symbols, float scaling) {
return srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, nof_ports, nof_symbols, 0); return srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, nof_ports, nof_symbols, 0, scaling);
} }
/* SSE implementation of the 2-port SFBC equalizer */ /* SSE implementation of the 2-port SFBC equalizer */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_symbols) int nof_rxant, int nof_symbols, float scaling)
{ {
float *x0Ptr = (float*) x[0]; float *x0Ptr = (float*) x[0];
float *x1Ptr = (float*) x[1]; float *x1Ptr = (float*) x[1];
@ -385,7 +399,7 @@ int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
const float *yPtr1 = (const float*) y[1]; const float *yPtr1 = (const float*) y[1];
__m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f); __m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f);
__m128 sqrt2 = _mm_setr_ps(sqrt(2), sqrt(2), sqrt(2), sqrt(2)); __m128 sqrt2 = _mm_set1_ps(sqrtf(2)/scaling);
__m128 h0Val_00, h0Val_10, h1Val_00, h1Val_10, h000, h00conj0, h010, h01conj0, h100, h110; __m128 h0Val_00, h0Val_10, h1Val_00, h1Val_10, h000, h00conj0, h010, h01conj0, h100, h110;
__m128 h0Val_01, h0Val_11, h1Val_01, h1Val_11, h001, h00conj1, h011, h01conj1, h101, h111; __m128 h0Val_01, h0Val_11, h1Val_01, h1Val_11, h001, h00conj1, h011, h01conj1, h101, h111;
@ -474,13 +488,13 @@ int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
_mm_store_ps(x1Ptr, x1); x1Ptr+=4; _mm_store_ps(x1Ptr, x1); x1Ptr+=4;
} }
// Compute remaining symbols using generic implementation // Compute remaining symbols using generic implementation
srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, 2, nof_symbols, 4*(nof_symbols/4)); srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, 2, nof_symbols, 4*(nof_symbols/4), scaling);
return nof_symbols; return nof_symbols;
} }
#endif #endif
int srslte_predecoding_diversity(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_diversity(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_symbols) int nof_ports, int nof_symbols, float scaling)
{ {
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
cf_t *y[SRSLTE_MAX_PORTS]; cf_t *y[SRSLTE_MAX_PORTS];
@ -493,47 +507,31 @@ int srslte_predecoding_diversity(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[S
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
if (nof_symbols > 32 && nof_ports == 2) { if (nof_symbols > 32 && nof_ports == 2) {
return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols); return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols, scaling);
} else { } else {
return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling);
} }
#else #else
return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling);
#endif #endif
} }
int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_symbols) int nof_rxant, int nof_ports, int nof_symbols, float scaling)
{ {
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
if (nof_symbols > 32 && nof_ports == 2) { if (nof_symbols > 32 && nof_ports == 2) {
return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols); return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols, scaling);
} else { } else {
return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling);
} }
#else #else
return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling);
#endif #endif
} }
int srslte_predecoding_type(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_layers, int nof_symbols, srslte_mimo_type_t type, float noise_estimate)
{
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
cf_t *y[SRSLTE_MAX_PORTS];
uint32_t nof_rxant = 1;
for (int i=0;i<nof_ports;i++) {
h[i][0] = h_[i];
}
y[0] = y_;
return srslte_predecoding_type_multi(y, h, x, nof_rxant, nof_ports, nof_layers, 0, nof_symbols, type, noise_estimate);
}
int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_symbols, float noise_estimate) int nof_symbols, float scaling, float noise_estimate)
{ {
cf_t G[2][2], Gx[2][2]; cf_t G[2][2], Gx[2][2];
@ -559,8 +557,8 @@ int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t
} }
// x=G*y // x=G*y
x[0][i] = Gx[0][0]*y[0][i] + Gx[0][1]*y[1][i]; x[0][i] = (Gx[0][0]*y[0][i] + Gx[0][1]*y[1][i]) * scaling;
x[1][i] = Gx[1][0]*y[0][i] + Gx[1][1]*y[1][i]; x[1][i] = (Gx[1][0]*y[0][i] + Gx[1][1]*y[1][i]) * scaling;
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
@ -572,7 +570,8 @@ int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t
int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
uint32_t nof_symbols) { uint32_t nof_symbols,
float scaling) {
uint32_t i = 0; uint32_t i = 0;
__m256 mask0 = _mm256_setr_ps(+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f); __m256 mask0 = _mm256_setr_ps(+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f);
@ -596,7 +595,7 @@ int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS],
__m256 x0, x1; __m256 x0, x1;
srslte_mat_2x2_zf_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f); srslte_mat_2x2_zf_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f / scaling);
_mm256_store_ps((float *) &x[0][i], x0); _mm256_store_ps((float *) &x[0][i], x0);
_mm256_store_ps((float *) &x[1][i], x1); _mm256_store_ps((float *) &x[1][i], x1);
@ -612,7 +611,8 @@ int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS],
int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
uint32_t nof_symbols) { uint32_t nof_symbols,
float scaling) {
uint32_t i = 0; uint32_t i = 0;
for (i = 0; i < nof_symbols - 1; i += 2) { for (i = 0; i < nof_symbols - 1; i += 2) {
@ -633,7 +633,7 @@ int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS],
__m128 x0, x1; __m128 x0, x1;
srslte_mat_2x2_zf_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f); srslte_mat_2x2_zf_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f / scaling);
_mm_store_ps((float *) &x[0][i], x0); _mm_store_ps((float *) &x[0][i], x0);
_mm_store_ps((float *) &x[1][i], x1); _mm_store_ps((float *) &x[1][i], x1);
@ -644,9 +644,13 @@ int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS],
#endif #endif
// Generic implementation of ZF 2x2 CCD equalizer // Generic implementation of ZF 2x2 CCD equalizer
int srslte_predecoding_ccd_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_ccd_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS],
int nof_symbols) { cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t h00, h01, h10, h11, det; cf_t *x[SRSLTE_MAX_LAYERS],
int nof_symbols,
float scaling) {
cf_t h00, h01, h10, h11;
for (int i = 0; i < nof_symbols; i++) { for (int i = 0; i < nof_symbols; i++) {
// Even precoder // Even precoder
@ -654,11 +658,8 @@ int srslte_predecoding_ccd_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
h10 = +h[0][1][i] + h[1][1][i]; h10 = +h[0][1][i] + h[1][1][i];
h01 = +h[0][0][i] - h[1][0][i]; h01 = +h[0][0][i] - h[1][0][i];
h11 = +h[0][1][i] - h[1][1][i]; h11 = +h[0][1][i] - h[1][1][i];
det = (h00 * h11 - h01 * h10);
det = conjf(det) * ((float) 2.0 / (crealf(det) * crealf(det) + cimagf(det) * cimagf(det)));
x[0][i] = (+h11 * y[0][i] - h01 * y[1][i]) * det; srslte_mat_2x2_zf_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], 2.0f / scaling);
x[1][i] = (-h10 * y[0][i] + h00 * y[1][i]) * det;
i++; i++;
@ -667,28 +668,24 @@ int srslte_predecoding_ccd_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
h10 = h[0][1][i] - h[1][1][i]; h10 = h[0][1][i] - h[1][1][i];
h01 = h[0][0][i] + h[1][0][i]; h01 = h[0][0][i] + h[1][0][i];
h11 = h[0][1][i] + h[1][1][i]; h11 = h[0][1][i] + h[1][1][i];
det = (h00 * h11 - h01 * h10);
det = conjf(det) * ((float) 2.0 / (crealf(det) * crealf(det) + cimagf(det) * cimagf(det)));
x[0][i] = (+h11 * y[0][i] - h01 * y[1][i]) * det;
x[1][i] = (-h10 * y[0][i] + h00 * y[1][i]) * det;
srslte_mat_2x2_zf_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], 2.0f / scaling);
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int srslte_predecoding_ccd_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_ccd_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_layers, int nof_symbols) int nof_rxant, int nof_ports, int nof_layers, int nof_symbols, float scaling)
{ {
if (nof_ports == 2 && nof_rxant == 2) { if (nof_ports == 2 && nof_rxant == 2) {
if (nof_layers == 2) { if (nof_layers == 2) {
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
return srslte_predecoding_ccd_2x2_zf_avx(y, h, x, nof_symbols); return srslte_predecoding_ccd_2x2_zf_avx(y, h, x, nof_symbols, scaling);
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_predecoding_ccd_2x2_zf_sse(y, h, x, nof_symbols); return srslte_predecoding_ccd_2x2_zf_sse(y, h, x, nof_symbols, scaling);
#else #else
return srslte_predecoding_ccd_2x2_zf_gen(y, h, x, nof_symbols); return srslte_predecoding_ccd_2x2_zf_gen(y, h, x, nof_symbols, scaling);
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
} else { } else {
@ -709,7 +706,7 @@ int srslte_predecoding_ccd_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORT
int srslte_predecoding_ccd_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS], int srslte_predecoding_ccd_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
uint32_t nof_symbols, float noise_estimate) { uint32_t nof_symbols, float scaling, float noise_estimate) {
uint32_t i = 0; uint32_t i = 0;
for (i = 0; i < nof_symbols - 3; i += 4) { for (i = 0; i < nof_symbols - 3; i += 4) {
@ -730,7 +727,7 @@ int srslte_predecoding_ccd_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS],
__m256 x0, x1; __m256 x0, x1;
srslte_mat_2x2_mmse_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f); srslte_mat_2x2_mmse_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f / scaling);
_mm256_store_ps((float *) &x[0][i], x0); _mm256_store_ps((float *) &x[0][i], x0);
_mm256_store_ps((float *) &x[1][i], x1); _mm256_store_ps((float *) &x[1][i], x1);
@ -746,7 +743,7 @@ int srslte_predecoding_ccd_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS],
int srslte_predecoding_ccd_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS], int srslte_predecoding_ccd_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
uint32_t nof_symbols, float noise_estimate) { uint32_t nof_symbols, float scaling, float noise_estimate) {
uint32_t i = 0; uint32_t i = 0;
for (i = 0; i < nof_symbols - 1; i += 2) { for (i = 0; i < nof_symbols - 1; i += 2) {
@ -767,7 +764,7 @@ int srslte_predecoding_ccd_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS],
__m128 x0, x1; __m128 x0, x1;
srslte_mat_2x2_mmse_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f); srslte_mat_2x2_mmse_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f / scaling);
_mm_store_ps((float *) &x[0][i], x0); _mm_store_ps((float *) &x[0][i], x0);
_mm_store_ps((float *) &x[1][i], x1); _mm_store_ps((float *) &x[1][i], x1);
@ -779,8 +776,9 @@ int srslte_predecoding_ccd_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS],
// Generic implementation of ZF 2x2 CCD equalizer // Generic implementation of ZF 2x2 CCD equalizer
int srslte_predecoding_ccd_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_ccd_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_symbols, float noise_estimate) { int nof_symbols, float scaling, float noise_estimate) {
cf_t h00, h01, h10, h11; cf_t h00, h01, h10, h11;
for (int i = 0; i < nof_symbols; i++) { for (int i = 0; i < nof_symbols; i++) {
// Even precoder // Even precoder
@ -788,7 +786,7 @@ int srslte_predecoding_ccd_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLT
h10 = +h[0][1][i] + h[1][1][i]; h10 = +h[0][1][i] + h[1][1][i];
h01 = +h[0][0][i] - h[1][0][i]; h01 = +h[0][0][i] - h[1][0][i];
h11 = +h[0][1][i] - h[1][1][i]; h11 = +h[0][1][i] - h[1][1][i];
srslte_mat_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f); srslte_mat_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f / scaling);
i++; i++;
@ -797,24 +795,24 @@ int srslte_predecoding_ccd_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLT
h10 = h[0][1][i] - h[1][1][i]; h10 = h[0][1][i] - h[1][1][i];
h01 = h[0][0][i] + h[1][0][i]; h01 = h[0][0][i] + h[1][0][i];
h11 = h[0][1][i] + h[1][1][i]; h11 = h[0][1][i] + h[1][1][i];
srslte_mat_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f); srslte_mat_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f / scaling);
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int srslte_predecoding_ccd_mmse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_ccd_mmse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_layers, int nof_symbols, float noise_estimate) int nof_rxant, int nof_ports, int nof_layers, int nof_symbols, float scaling, float noise_estimate)
{ {
if (nof_ports == 2 && nof_rxant == 2) { if (nof_ports == 2 && nof_rxant == 2) {
if (nof_layers == 2) { if (nof_layers == 2) {
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
return srslte_predecoding_ccd_2x2_mmse_avx(y, h, x, nof_symbols, noise_estimate); return srslte_predecoding_ccd_2x2_mmse_avx(y, h, x, nof_symbols, scaling, noise_estimate);
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_predecoding_ccd_2x2_mmse_sse(y, h, x, nof_symbols, noise_estimate); return srslte_predecoding_ccd_2x2_mmse_sse(y, h, x, nof_symbols, scaling, noise_estimate);
#else #else
return srslte_predecoding_ccd_2x2_mmse_gen(y, h, x, nof_symbols, noise_estimate); return srslte_predecoding_ccd_2x2_mmse_gen(y, h, x, nof_symbols, scaling, noise_estimate);
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
} else { } else {
@ -833,16 +831,16 @@ int srslte_predecoding_ccd_mmse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PO
// Generic implementation of ZF 2x2 Spatial Multiplexity equalizer // Generic implementation of ZF 2x2 Spatial Multiplexity equalizer
int srslte_predecoding_multiplex_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, float scaling) {
float norm = 1.0; float norm = 1.0;
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
norm = (float) M_SQRT2; norm = (float) M_SQRT2 / scaling;
break; break;
case 1: case 1:
case 2: case 2:
norm = 2.0f; norm = 2.0f / scaling;
break; break;
default: default:
ERROR("Wrong codebook_idx=%d", codebook_idx); ERROR("Wrong codebook_idx=%d", codebook_idx);
@ -901,16 +899,16 @@ int srslte_predecoding_multiplex_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[S
// SSE implementation of ZF 2x2 Spatial Multiplexity equalizer // SSE implementation of ZF 2x2 Spatial Multiplexity equalizer
int srslte_predecoding_multiplex_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, float scaling) {
float norm = 1.0; float norm = 1.0;
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
norm = (float) M_SQRT2; norm = (float) M_SQRT2 / scaling;
break; break;
case 1: case 1:
case 2: case 2:
norm = 2.0f; norm = 2.0f / scaling;
break; break;
default: default:
ERROR("Wrong codebook_idx=%d", codebook_idx); ERROR("Wrong codebook_idx=%d", codebook_idx);
@ -968,16 +966,16 @@ int srslte_predecoding_multiplex_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[S
// Generic implementation of ZF 2x2 Spatial Multiplexity equalizer // Generic implementation of ZF 2x2 Spatial Multiplexity equalizer
int srslte_predecoding_multiplex_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, float scaling) {
float norm = 1.0; float norm = 1.0;
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
norm = (float) M_SQRT2; norm = (float) M_SQRT2 / scaling;
break; break;
case 1: case 1:
case 2: case 2:
norm = 2.0f; norm = 2.0f / scaling;
break; break;
default: default:
fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx);
@ -1025,16 +1023,16 @@ int srslte_predecoding_multiplex_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[S
// AVX implementation of ZF 2x2 Spatial Multiplexity equalizer // AVX implementation of ZF 2x2 Spatial Multiplexity equalizer
int srslte_predecoding_multiplex_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols,
float noise_estimate) { float scaling, float noise_estimate) {
float norm = 1.0; float norm = 1.0;
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
norm = (float) M_SQRT2; norm = (float) M_SQRT2 / scaling;
break; break;
case 1: case 1:
case 2: case 2:
norm = 2.0f; norm = 2.0f / scaling;
break; break;
default: default:
fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx);
@ -1095,16 +1093,16 @@ int srslte_predecoding_multiplex_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h
// SSE implementation of ZF 2x2 Spatial Multiplexity equalizer // SSE implementation of ZF 2x2 Spatial Multiplexity equalizer
int srslte_predecoding_multiplex_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols,
float noise_estimate) { float scaling, float noise_estimate) {
float norm; float norm;
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
norm = (float) M_SQRT2; norm = (float) M_SQRT2 / scaling;
break; break;
case 1: case 1:
case 2: case 2:
norm = 2.0f; norm = 2.0f / scaling;
break; break;
default: default:
fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx);
@ -1161,16 +1159,16 @@ int srslte_predecoding_multiplex_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h
// Generic implementation of ZF 2x2 Spatial Multiplexity equalizer // Generic implementation of ZF 2x2 Spatial Multiplexity equalizer
int srslte_predecoding_multiplex_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols,
float noise_estimate) { float scaling, float noise_estimate) {
float norm = 1.0; float norm = 1.0;
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
norm = (float) M_SQRT2; norm = (float) M_SQRT2 / scaling;
break; break;
case 1: case 1:
case 2: case 2:
norm = 2.0f; norm = 2.0f / scaling;
break; break;
default: default:
ERROR("Wrong codebook_idx=%d", codebook_idx); ERROR("Wrong codebook_idx=%d", codebook_idx);
@ -1213,7 +1211,7 @@ int srslte_predecoding_multiplex_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h
// Generic implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer // Generic implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer
int srslte_predecoding_multiplex_2x1_mrc_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x1_mrc_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, float scaling) {
for (int i = 0; i < nof_symbols - 3; i += 4) { for (int i = 0; i < nof_symbols - 3; i += 4) {
__m256 _h00 = _mm256_load_ps((float*)&(h[0][0][i])); __m256 _h00 = _mm256_load_ps((float*)&(h[0][0][i]));
@ -1251,7 +1249,7 @@ int srslte_predecoding_multiplex_2x1_mrc_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[
__m256 hh = _mm256_add_ps(hh0, hh1); __m256 hh = _mm256_add_ps(hh0, hh1);
__m256 hhrec = _mm256_rcp_ps(hh); __m256 hhrec = _mm256_rcp_ps(hh);
hhrec = _mm256_mul_ps(hhrec, _mm256_set1_ps((float) M_SQRT2)); hhrec = _mm256_mul_ps(hhrec, _mm256_set1_ps((float) M_SQRT2 / scaling));
__m256 y0 = _mm256_load_ps((float*)&y[0][i]); __m256 y0 = _mm256_load_ps((float*)&y[0][i]);
__m256 y1 = _mm256_load_ps((float*)&y[1][i]); __m256 y1 = _mm256_load_ps((float*)&y[1][i]);
@ -1272,7 +1270,7 @@ int srslte_predecoding_multiplex_2x1_mrc_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
int srslte_predecoding_multiplex_2x1_mrc_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x1_mrc_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, float scaling) {
for (int i = 0; i < nof_symbols - 1; i += 2) { for (int i = 0; i < nof_symbols - 1; i += 2) {
__m128 _h00 = _mm_load_ps((float*)&(h[0][0][i])); __m128 _h00 = _mm_load_ps((float*)&(h[0][0][i]));
@ -1310,7 +1308,7 @@ int srslte_predecoding_multiplex_2x1_mrc_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[
__m128 hh = _mm_add_ps(hh0, hh1); __m128 hh = _mm_add_ps(hh0, hh1);
__m128 hhrec = _mm_rcp_ps(hh); __m128 hhrec = _mm_rcp_ps(hh);
hhrec = _mm_mul_ps(hhrec, _mm_set1_ps((float) M_SQRT2)); hhrec = _mm_mul_ps(hhrec, _mm_set1_ps((float) M_SQRT2 / scaling));
__m128 y0 = _mm_load_ps((float*)&y[0][i]); __m128 y0 = _mm_load_ps((float*)&y[0][i]);
__m128 y1 = _mm_load_ps((float*)&y[1][i]); __m128 y1 = _mm_load_ps((float*)&y[1][i]);
@ -1329,7 +1327,9 @@ int srslte_predecoding_multiplex_2x1_mrc_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[
// Generic implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer // Generic implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer
int srslte_predecoding_multiplex_2x1_mrc_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x1_mrc_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, float scaling) {
float norm = (float) M_SQRT2 / scaling;
for (int i = 0; i < nof_symbols; i += 1) { for (int i = 0; i < nof_symbols; i += 1) {
cf_t h0, h1; cf_t h0, h1;
float hh; float hh;
@ -1356,7 +1356,7 @@ int srslte_predecoding_multiplex_2x1_mrc_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
hh = (float) M_SQRT2/(crealf(h0)*crealf(h0) + cimagf(h0)*cimagf(h0) + crealf(h1)*crealf(h1) + cimagf(h1)*cimagf(h1)); hh = norm / (crealf(h0) * crealf(h0) + cimagf(h0) * cimagf(h0) + crealf(h1) * crealf(h1) + cimagf(h1) * cimagf(h1));
x[0][i] = (conjf(h0) * y[0][i] + conjf(h1) * y[1][i]) * hh; x[0][i] = (conjf(h0) * y[0][i] + conjf(h1) * y[1][i]) * hh;
} }
@ -1365,42 +1365,42 @@ int srslte_predecoding_multiplex_2x1_mrc_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[
int srslte_predecoding_multiplex(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_multiplex(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_layers, int codebook_idx, int nof_symbols, int nof_rxant, int nof_ports, int nof_layers, int codebook_idx, int nof_symbols,
float noise_estimate) float scaling, float noise_estimate)
{ {
if (nof_ports == 2 && nof_rxant <= 2) { if (nof_ports == 2 && nof_rxant <= 2) {
if (nof_layers == 2) { if (nof_layers == 2) {
switch (mimo_decoder) { switch (mimo_decoder) {
case SRSLTE_MIMO_DECODER_ZF: case SRSLTE_MIMO_DECODER_ZF:
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
return srslte_predecoding_multiplex_2x2_zf_avx(y, h, x, codebook_idx, nof_symbols); return srslte_predecoding_multiplex_2x2_zf_avx(y, h, x, codebook_idx, nof_symbols, scaling);
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_predecoding_multiplex_2x2_zf_sse(y, h, x, codebook_idx, nof_symbols); return srslte_predecoding_multiplex_2x2_zf_sse(y, h, x, codebook_idx, nof_symbols, scaling);
#else #else
return srslte_predecoding_multiplex_2x2_zf_gen(y, h, x, codebook_idx, nof_symbols); return srslte_predecoding_multiplex_2x2_zf_gen(y, h, x, codebook_idx, nof_symbols, scaling);
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
break; break;
case SRSLTE_MIMO_DECODER_MMSE: case SRSLTE_MIMO_DECODER_MMSE:
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
return srslte_predecoding_multiplex_2x2_mmse_avx(y, h, x, codebook_idx, nof_symbols, noise_estimate); return srslte_predecoding_multiplex_2x2_mmse_avx(y, h, x, codebook_idx, nof_symbols, scaling, noise_estimate);
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_predecoding_multiplex_2x2_mmse_sse(y, h, x, codebook_idx, nof_symbols, noise_estimate); return srslte_predecoding_multiplex_2x2_mmse_sse(y, h, x, codebook_idx, nof_symbols, scaling, noise_estimate);
#else #else
return srslte_predecoding_multiplex_2x2_mmse_gen(y, h, x, codebook_idx, nof_symbols, noise_estimate); return srslte_predecoding_multiplex_2x2_mmse_gen(y, h, x, codebook_idx, nof_symbols, scaling, noise_estimate);
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
break; break;
} }
} else { } else {
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
return srslte_predecoding_multiplex_2x1_mrc_avx(y, h, x, codebook_idx, nof_symbols); return srslte_predecoding_multiplex_2x1_mrc_avx(y, h, x, codebook_idx, nof_symbols, scaling);
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_predecoding_multiplex_2x1_mrc_sse(y, h, x, codebook_idx, nof_symbols); return srslte_predecoding_multiplex_2x1_mrc_sse(y, h, x, codebook_idx, nof_symbols, scaling);
#else #else
return srslte_predecoding_multiplex_2x1_mrc_gen(y, h, x, codebook_idx, nof_symbols); return srslte_predecoding_multiplex_2x1_mrc_gen(y, h, x, codebook_idx, nof_symbols, scaling);
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
} }
@ -1417,9 +1417,10 @@ void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder) {
} }
/* 36.211 v10.3.0 Section 6.3.4 */ /* 36.211 v10.3.0 Section 6.3.4 */
int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_ports, int nof_layers, cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_ports, int nof_layers,
int codebook_idx, int nof_symbols, srslte_mimo_type_t type, float noise_estimate) { int codebook_idx, int nof_symbols, srslte_mimo_type_t type, float scaling,
float noise_estimate) {
if (nof_ports > SRSLTE_MAX_PORTS) { if (nof_ports > SRSLTE_MAX_PORTS) {
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS,
@ -1437,10 +1438,10 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
if (nof_layers >= 2 && nof_layers <= 4) { if (nof_layers >= 2 && nof_layers <= 4) {
switch (mimo_decoder) { switch (mimo_decoder) {
case SRSLTE_MIMO_DECODER_ZF: case SRSLTE_MIMO_DECODER_ZF:
return srslte_predecoding_ccd_zf(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols); return srslte_predecoding_ccd_zf(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, scaling);
break; break;
case SRSLTE_MIMO_DECODER_MMSE: case SRSLTE_MIMO_DECODER_MMSE:
return srslte_predecoding_ccd_mmse(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, noise_estimate); return srslte_predecoding_ccd_mmse(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, scaling, noise_estimate);
break; break;
} }
} else { } else {
@ -1451,7 +1452,7 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
return -1; return -1;
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) { if (nof_ports == 1 && nof_layers == 1) {
return srslte_predecoding_single_multi(y, h[0], x[0], nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_multi(y, h[0], x[0], nof_rxant, nof_symbols, scaling, noise_estimate);
} else { } else {
fprintf(stderr, fprintf(stderr,
"Number of ports and layers must be 1 for transmission on single antenna ports (%d, %d)\n", nof_ports, nof_layers); "Number of ports and layers must be 1 for transmission on single antenna ports (%d, %d)\n", nof_ports, nof_layers);
@ -1460,7 +1461,7 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
break; break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY: case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
if (nof_ports == nof_layers) { if (nof_ports == nof_layers) {
return srslte_predecoding_diversity_multi(y, h, x, nof_rxant, nof_ports, nof_symbols); return srslte_predecoding_diversity_multi(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling);
} else { } else {
fprintf(stderr, fprintf(stderr,
"Error number of layers must equal number of ports in transmit diversity\n"); "Error number of layers must equal number of ports in transmit diversity\n");
@ -1469,7 +1470,7 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
break; break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
return srslte_predecoding_multiplex(y, h, x, nof_rxant, nof_ports, nof_layers, codebook_idx, nof_symbols, return srslte_predecoding_multiplex(y, h, x, nof_rxant, nof_ports, nof_layers, codebook_idx, nof_symbols,
noise_estimate); scaling, noise_estimate);
default: default:
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -1487,12 +1488,16 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
* *
**************************************************/ **************************************************/
int srslte_precoding_single(cf_t *x, cf_t *y, int nof_symbols) { int srslte_precoding_single(cf_t *x, cf_t *y, int nof_symbols, float scaling) {
if (scaling == 1.0f) {
memcpy(y, x, nof_symbols * sizeof(cf_t)); memcpy(y, x, nof_symbols * sizeof(cf_t));
} else {
srslte_vec_sc_prod_cfc(x, scaling, y, (uint32_t) nof_symbols);
}
return nof_symbols; return nof_symbols;
} }
int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_ports, int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_ports,
int nof_symbols) { int nof_symbols, float scaling) {
int i; int i;
if (nof_ports == 2) { if (nof_ports == 2) {
for (i = 0; i < nof_symbols; i++) { for (i = 0; i < nof_symbols; i++) {
@ -1502,32 +1507,34 @@ int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
y[1][2 * i + 1] = conjf(x[0][i]); y[1][2 * i + 1] = conjf(x[0][i]);
} }
// normalize // normalize
srslte_vec_sc_prod_cfc(y[0], 1.0/sqrtf(2), y[0], 2*nof_symbols); srslte_vec_sc_prod_cfc(y[0], scaling/sqrtf(2), y[0], 2*nof_symbols);
srslte_vec_sc_prod_cfc(y[1], 1.0/sqrtf(2), y[1], 2*nof_symbols); srslte_vec_sc_prod_cfc(y[1], scaling/sqrtf(2), y[1], 2*nof_symbols);
return 2 * i; return 2 * i;
} else if (nof_ports == 4) { } else if (nof_ports == 4) {
scaling /= sqrtf(2);
//int m_ap = (nof_symbols%4)?(nof_symbols*4-2):nof_symbols*4; //int m_ap = (nof_symbols%4)?(nof_symbols*4-2):nof_symbols*4;
int m_ap = 4 * nof_symbols; int m_ap = 4 * nof_symbols;
for (i = 0; i < m_ap / 4; i++) { for (i = 0; i < m_ap / 4; i++) {
y[0][4 * i] = x[0][i] / sqrtf(2); y[0][4 * i] = x[0][i] * scaling;
y[1][4 * i] = 0; y[1][4 * i] = 0;
y[2][4 * i] = -conjf(x[1][i]) / sqrtf(2); y[2][4 * i] = -conjf(x[1][i]) * scaling;
y[3][4 * i] = 0; y[3][4 * i] = 0;
y[0][4 * i + 1] = x[1][i] / sqrtf(2); y[0][4 * i + 1] = x[1][i] * scaling;
y[1][4 * i + 1] = 0; y[1][4 * i + 1] = 0;
y[2][4 * i + 1] = conjf(x[0][i]) / sqrtf(2); y[2][4 * i + 1] = conjf(x[0][i]) * scaling;
y[3][4 * i + 1] = 0; y[3][4 * i + 1] = 0;
y[0][4 * i + 2] = 0; y[0][4 * i + 2] = 0;
y[1][4 * i + 2] = x[2][i] / sqrtf(2); y[1][4 * i + 2] = x[2][i] * scaling;
y[2][4 * i + 2] = 0; y[2][4 * i + 2] = 0;
y[3][4 * i + 2] = -conjf(x[3][i]) / sqrtf(2); y[3][4 * i + 2] = -conjf(x[3][i]) * scaling;
y[0][4 * i + 3] = 0; y[0][4 * i + 3] = 0;
y[1][4 * i + 3] = x[3][i] / sqrtf(2); y[1][4 * i + 3] = x[3][i] * scaling;
y[2][4 * i + 3] = 0; y[2][4 * i + 3] = 0;
y[3][4 * i + 3] = conjf(x[2][i]) / sqrtf(2); y[3][4 * i + 3] = conjf(x[2][i]) * scaling;
} }
return 4 * i; return 4 * i;
} else { } else {
@ -1538,9 +1545,9 @@ int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
int srslte_precoding_cdd_2x2_avx(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols) int srslte_precoding_cdd_2x2_avx(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols, float scaling)
{ {
__m256 norm_avx = _mm256_set1_ps(0.5f); __m256 norm_avx = _mm256_set1_ps(0.5f * scaling);
for (int i = 0; i < nof_symbols - 3; i += 4) { for (int i = 0; i < nof_symbols - 3; i += 4) {
__m256 x0 = _mm256_load_ps((float*) &x[0][i]); __m256 x0 = _mm256_load_ps((float*) &x[0][i]);
__m256 x1 = _mm256_load_ps((float*) &x[1][i]); __m256 x1 = _mm256_load_ps((float*) &x[1][i]);
@ -1563,9 +1570,9 @@ int srslte_precoding_cdd_2x2_avx(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
int srslte_precoding_cdd_2x2_sse(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols) int srslte_precoding_cdd_2x2_sse(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols, float scaling)
{ {
__m128 norm_sse = _mm_set1_ps(0.5f); __m128 norm_sse = _mm_set1_ps(0.5f * scaling);
for (int i = 0; i < nof_symbols - 1; i += 2) { for (int i = 0; i < nof_symbols - 1; i += 2) {
__m128 x0 = _mm_load_ps((float*) &x[0][i]); __m128 x0 = _mm_load_ps((float*) &x[0][i]);
__m128 x1 = _mm_load_ps((float*) &x[1][i]); __m128 x1 = _mm_load_ps((float*) &x[1][i]);
@ -1587,19 +1594,20 @@ int srslte_precoding_cdd_2x2_sse(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
int srslte_precoding_cdd_2x2_gen(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols) int srslte_precoding_cdd_2x2_gen(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols, float scaling)
{ {
scaling /= 2.0f;
for (int i = 0; i < nof_symbols; i++) { for (int i = 0; i < nof_symbols; i++) {
y[0][i] = (x[0][i]+x[1][i])/2.0f; y[0][i] = (x[0][i]+x[1][i]) * scaling;
y[1][i] = (x[0][i]-x[1][i])/2.0f; y[1][i] = (x[0][i]-x[1][i]) * scaling;
i++; i++;
y[0][i] = (x[0][i]+x[1][i])/2.0f; y[0][i] = (x[0][i]+x[1][i]) * scaling;
y[1][i] = (-x[0][i]+x[1][i])/2.0f; y[1][i] = (-x[0][i]+x[1][i]) * scaling;
} }
return 2 * nof_symbols; return 2 * nof_symbols;
} }
int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols) int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols, float scaling)
{ {
if (nof_ports == 2) { if (nof_ports == 2) {
if (nof_layers != 2) { if (nof_layers != 2) {
@ -1607,12 +1615,12 @@ int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS],
return -1; return -1;
} }
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
return srslte_precoding_cdd_2x2_avx(x, y, nof_symbols); return srslte_precoding_cdd_2x2_avx(x, y, nof_symbols, scaling);
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_precoding_cdd_2x2_sse(x, y, nof_symbols); return srslte_precoding_cdd_2x2_sse(x, y, nof_symbols, scaling);
#else #else
return srslte_precoding_cdd_2x2_gen(x, y, nof_symbols); return srslte_precoding_cdd_2x2_gen(x, y, nof_symbols, scaling);
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
} else if (nof_ports == 4) { } else if (nof_ports == 4) {
@ -1625,27 +1633,28 @@ int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS],
} }
int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports,
int codebook_idx, uint32_t nof_symbols) int codebook_idx, uint32_t nof_symbols, float scaling)
{ {
int i = 0; int i = 0;
if (nof_ports == 2) { if (nof_ports == 2) {
if (nof_layers == 1) { if (nof_layers == 1) {
scaling /= sqrtf(2.0f);
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols);
srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[1], nof_symbols); srslte_vec_sc_prod_cfc(x[0], scaling, y[1], nof_symbols);
break; break;
case 1: case 1:
srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols);
srslte_vec_sc_prod_cfc(x[0], -1.0f/sqrtf(2.0f), y[1], nof_symbols); srslte_vec_sc_prod_cfc(x[0], -scaling, y[1], nof_symbols);
break; break;
case 2: case 2:
srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols);
srslte_vec_sc_prod_ccc(x[0], _Complex_I/sqrtf(2.0f), y[1], nof_symbols); srslte_vec_sc_prod_ccc(x[0], _Complex_I * scaling, y[1], nof_symbols);
break; break;
case 3: case 3:
srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols);
srslte_vec_sc_prod_ccc(x[0], -_Complex_I/sqrtf(2.0f), y[1], nof_symbols); srslte_vec_sc_prod_ccc(x[0], -_Complex_I * scaling, y[1], nof_symbols);
break; break;
default: default:
fprintf(stderr, "Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n", fprintf(stderr, "Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n",
@ -1655,17 +1664,19 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
} else if (nof_layers == 2) { } else if (nof_layers == 2) {
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); scaling /= sqrtf(2.0f);
srslte_vec_sc_prod_cfc(x[1], 1.0f/sqrtf(2.0f), y[1], nof_symbols); srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols);
srslte_vec_sc_prod_cfc(x[1], scaling, y[1], nof_symbols);
break; break;
case 1: case 1:
scaling /= 2.0f;
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
for (; i < nof_symbols - 3; i += 4) { for (; i < nof_symbols - 3; i += 4) {
__m256 x0 = _mm256_load_ps((float *) &x[0][i]); __m256 x0 = _mm256_load_ps((float *) &x[0][i]);
__m256 x1 = _mm256_load_ps((float *) &x[1][i]); __m256 x1 = _mm256_load_ps((float *) &x[1][i]);
__m256 y0 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_add_ps(x0, x1)); __m256 y0 = _mm256_mul_ps(_mm256_set1_ps(scaling), _mm256_add_ps(x0, x1));
__m256 y1 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_sub_ps(x0, x1)); __m256 y1 = _mm256_mul_ps(_mm256_set1_ps(scaling), _mm256_sub_ps(x0, x1));
_mm256_store_ps((float *) &y[0][i], y0); _mm256_store_ps((float *) &y[0][i], y0);
_mm256_store_ps((float *) &y[1][i], y1); _mm256_store_ps((float *) &y[1][i], y1);
@ -1677,8 +1688,8 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
__m128 x0 = _mm_load_ps((float *) &x[0][i]); __m128 x0 = _mm_load_ps((float *) &x[0][i]);
__m128 x1 = _mm_load_ps((float *) &x[1][i]); __m128 x1 = _mm_load_ps((float *) &x[1][i]);
__m128 y0 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_add_ps(x0, x1)); __m128 y0 = _mm_mul_ps(_mm_set1_ps(scaling), _mm_add_ps(x0, x1));
__m128 y1 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_sub_ps(x0, x1)); __m128 y1 = _mm_mul_ps(_mm_set1_ps(scaling), _mm_sub_ps(x0, x1));
_mm_store_ps((float *) &y[0][i], y0); _mm_store_ps((float *) &y[0][i], y0);
_mm_store_ps((float *) &y[1][i], y1); _mm_store_ps((float *) &y[1][i], y1);
@ -1686,18 +1697,19 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
for (; i < nof_symbols; i++) { for (; i < nof_symbols; i++) {
y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; y[0][i] = (x[0][i] + x[1][i]) * scaling;
y[1][i] = 0.5f*x[0][i] - 0.5f*x[1][i]; y[1][i] = (x[0][i] - x[1][i]) * scaling;
} }
break; break;
case 2: case 2:
scaling /= 2.0f;
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
for (; i < nof_symbols - 3; i += 4) { for (; i < nof_symbols - 3; i += 4) {
__m256 x0 = _mm256_load_ps((float*)&x[0][i]); __m256 x0 = _mm256_load_ps((float*)&x[0][i]);
__m256 x1 = _mm256_load_ps((float*)&x[1][i]); __m256 x1 = _mm256_load_ps((float*)&x[1][i]);
__m256 y0 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_add_ps(x0, x1)); __m256 y0 = _mm256_mul_ps(_mm256_set1_ps(scaling), _mm256_add_ps(x0, x1));
__m256 y1 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _MM256_MULJ_PS(_mm256_sub_ps(x0, x1))); __m256 y1 = _mm256_mul_ps(_mm256_set1_ps(scaling), _MM256_MULJ_PS(_mm256_sub_ps(x0, x1)));
_mm256_store_ps((float*)&y[0][i], y0); _mm256_store_ps((float*)&y[0][i], y0);
_mm256_store_ps((float*)&y[1][i], y1); _mm256_store_ps((float*)&y[1][i], y1);
@ -1709,8 +1721,8 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
__m128 x0 = _mm_load_ps((float*)&x[0][i]); __m128 x0 = _mm_load_ps((float*)&x[0][i]);
__m128 x1 = _mm_load_ps((float*)&x[1][i]); __m128 x1 = _mm_load_ps((float*)&x[1][i]);
__m128 y0 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_add_ps(x0, x1)); __m128 y0 = _mm_mul_ps(_mm_set1_ps(scaling), _mm_add_ps(x0, x1));
__m128 y1 = _mm_mul_ps(_mm_set1_ps(0.5f), _MM_MULJ_PS(_mm_sub_ps(x0, x1))); __m128 y1 = _mm_mul_ps(_mm_set1_ps(scaling), _MM_MULJ_PS(_mm_sub_ps(x0, x1)));
_mm_store_ps((float*)&y[0][i], y0); _mm_store_ps((float*)&y[0][i], y0);
_mm_store_ps((float*)&y[1][i], y1); _mm_store_ps((float*)&y[1][i], y1);
@ -1718,8 +1730,8 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
for (; i < nof_symbols; i++) { for (; i < nof_symbols; i++) {
y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; y[0][i] = (x[0][i] + x[1][i])*scaling;
y[1][i] = 0.5f*_Complex_I*x[0][i] - 0.5f*_Complex_I*x[1][i]; y[1][i] = (_Complex_I*x[0][i] - _Complex_I*x[1][i])*scaling;
} }
break; break;
case 3: case 3:
@ -1739,7 +1751,7 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
/* 36.211 v10.3.0 Section 6.3.4 */ /* 36.211 v10.3.0 Section 6.3.4 */
int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers,
int nof_ports, int codebook_idx, int nof_symbols, srslte_mimo_type_t type) { int nof_ports, int codebook_idx, int nof_symbols, float scaling, srslte_mimo_type_t type) {
if (nof_ports > SRSLTE_MAX_PORTS) { if (nof_ports > SRSLTE_MAX_PORTS) {
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS,
@ -1754,10 +1766,10 @@ int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS],
switch (type) { switch (type) {
case SRSLTE_MIMO_TYPE_CDD: case SRSLTE_MIMO_TYPE_CDD:
return srslte_precoding_cdd(x, y, nof_layers, nof_ports, nof_symbols); return srslte_precoding_cdd(x, y, nof_layers, nof_ports, nof_symbols, scaling);
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) { if (nof_ports == 1 && nof_layers == 1) {
return srslte_precoding_single(x[0], y[0], nof_symbols); return srslte_precoding_single(x[0], y[0], nof_symbols, scaling);
} else { } else {
fprintf(stderr, fprintf(stderr,
"Number of ports and layers must be 1 for transmission on single antenna ports\n"); "Number of ports and layers must be 1 for transmission on single antenna ports\n");
@ -1766,14 +1778,14 @@ int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS],
break; break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY: case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
if (nof_ports == nof_layers) { if (nof_ports == nof_layers) {
return srslte_precoding_diversity(x, y, nof_ports, nof_symbols); return srslte_precoding_diversity(x, y, nof_ports, nof_symbols, scaling);
} else { } else {
fprintf(stderr, fprintf(stderr,
"Error number of layers must equal number of ports in transmit diversity\n"); "Error number of layers must equal number of ports in transmit diversity\n");
return -1; return -1;
} }
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
return srslte_precoding_multiplex(x, y, nof_layers, nof_ports, codebook_idx, nof_symbols); return srslte_precoding_multiplex(x, y, nof_layers, nof_ports, codebook_idx, (uint32_t) nof_symbols, scaling);
default: default:
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }

@ -44,14 +44,16 @@ int nof_layers = 1, nof_tx_ports = 1, nof_rx_ports = 1, nof_re = 1;
char *mimo_type_name = NULL; char *mimo_type_name = NULL;
char decoder_type_name [16] = "zf"; char decoder_type_name [16] = "zf";
float snr_db = 100.0f; float snr_db = 100.0f;
float scaling = 0.1f;
void usage(char *prog) { void usage(char *prog) {
printf( printf(
"Usage: %s -m [single|diversity|multiplex|cdd] -l [nof_layers] -p [nof_tx_ports]\n" "Usage: %s -m [single|diversity|multiplex|cdd] -l [nof_layers] -p [nof_tx_ports]\n"
" -r [nof_rx_ports]\n", prog); " -r [nof_rx_ports] -g [scaling]\n", prog);
printf("\t-n num_symbols [Default %d]\n", nof_symbols); printf("\t-n num_symbols [Default %d]\n", nof_symbols);
printf("\t-c codebook_idx [Default %d]\n", codebook_idx); printf("\t-c codebook_idx [Default %d]\n", codebook_idx);
printf("\t-s SNR in dB [Default %.1fdB]*\n", snr_db); printf("\t-s SNR in dB [Default %.1fdB]*\n", snr_db);
printf("\t-g Scaling [Default %.1f]*\n", scaling);
printf("\t-d decoder type [zf|mmse] [Default %s]\n", decoder_type_name); printf("\t-d decoder type [zf|mmse] [Default %s]\n", decoder_type_name);
printf("\n"); printf("\n");
printf("* Performance test example:\n\t for snr in {0..20..1}; do ./precoding_test -m single -s $snr; done; \n\n", decoder_type_name); printf("* Performance test example:\n\t for snr in {0..20..1}; do ./precoding_test -m single -s $snr; done; \n\n", decoder_type_name);
@ -59,7 +61,7 @@ void usage(char *prog) {
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "mplnrcds")) != -1) { while ((opt = getopt(argc, argv, "mplnrcdsg")) != -1) {
switch (opt) { switch (opt) {
case 'n': case 'n':
nof_symbols = atoi(argv[optind]); nof_symbols = atoi(argv[optind]);
@ -85,6 +87,9 @@ void parse_args(int argc, char **argv) {
case 's': case 's':
snr_db = (float) atof(argv[optind]); snr_db = (float) atof(argv[optind]);
break; break;
case 'g':
scaling = (float) atof(argv[optind]);
break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
@ -149,7 +154,7 @@ void populate_channel(srslte_mimo_type_t type, cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_
static void awgn(cf_t *y[SRSLTE_MAX_PORTS], uint32_t n, float snr) { static void awgn(cf_t *y[SRSLTE_MAX_PORTS], uint32_t n, float snr) {
int i; int i;
float std_dev = powf(10, - (snr + 3.0f) / 20.0f); float std_dev = powf(10, - (snr + 3.0f) / 20.0f) * scaling;
for (i = 0; i < nof_rx_ports; i++) { for (i = 0; i < nof_rx_ports; i++) {
srslte_ch_awgn_c(y[i], y[i], std_dev, n); srslte_ch_awgn_c(y[i], y[i], std_dev, n);
@ -250,7 +255,7 @@ int main(int argc, char **argv) {
} }
/* Execute Precoding (Tx) */ /* Execute Precoding (Tx) */
if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, codebook_idx, nof_symbols, type) < 0) { if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, codebook_idx, nof_symbols, scaling, type) < 0) {
fprintf(stderr, "Error layer mapper encoder\n"); fprintf(stderr, "Error layer mapper encoder\n");
exit(-1); exit(-1);
} }
@ -285,8 +290,8 @@ int main(int argc, char **argv) {
/* predecoding / equalization */ /* predecoding / equalization */
struct timeval t[3]; struct timeval t[3];
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
srslte_predecoding_type_multi(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers, srslte_predecoding_type(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers,
codebook_idx, nof_re, type, powf(10, -snr_db/10)); codebook_idx, nof_re, type, scaling, powf(10, -snr_db / 10));
gettimeofday(&t[2], NULL); gettimeofday(&t[2], NULL);
get_time_interval(t); get_time_interval(t);

@ -497,10 +497,10 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
/* in control channels, only diversity is supported */ /* in control channels, only diversity is supported */
if (nant == 1) { if (nant == 1) {
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, noise_estimate); srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, 1.0f, noise_estimate);
} else { } else {
srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant, srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant,
q->nof_symbols); q->nof_symbols, 1.0f);
srslte_layerdemap_diversity(x, q->d, nant, q->nof_symbols / nant); srslte_layerdemap_diversity(x, q->d, nant, q->nof_symbols / nant);
} }
@ -591,7 +591,7 @@ int srslte_pbch_encode(srslte_pbch_t *q, uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols); srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols);
srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports,
q->nof_symbols / q->cell.nof_ports); q->nof_symbols / q->cell.nof_ports, 1.0f);
} else { } else {
memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t));
} }

@ -219,9 +219,9 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P
/* in control channels, only diversity is supported */ /* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) { if (q->cell.nof_ports == 1) {
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, q->nof_rx_antennas, q->nof_symbols, noise_estimate); srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, q->nof_rx_antennas, q->nof_symbols, 1.0f, noise_estimate);
} else { } else {
srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols); srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols, 1.0f);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports);
} }
@ -278,7 +278,7 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR
/* layer mapping & precoding */ /* layer mapping & precoding */
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols); srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols);
srslte_precoding_diversity(x, q_symbols, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); srslte_precoding_diversity(x, q_symbols, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports, 1.0f);
} else { } else {
memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t));
} }

@ -485,9 +485,9 @@ int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MA
/* in control channels, only diversity is supported */ /* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) { if (q->cell.nof_ports == 1) {
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, nof_symbols, noise_estimate/2); srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, nof_symbols, 1.0f, noise_estimate/2);
} else { } else {
srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols); srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols, 1.0f);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
} }
@ -618,7 +618,7 @@ int srslte_pdcch_encode(srslte_pdcch_t *q, srslte_dci_msg_t *msg, srslte_dci_loc
/* layer mapping & precoding */ /* layer mapping & precoding */
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, nof_symbols); srslte_layermap_diversity(q->d, x, q->cell.nof_ports, nof_symbols);
srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports, 1.0f);
} else { } else {
memcpy(q->symbols[0], q->d, nof_symbols * sizeof(cf_t)); memcpy(q->symbols[0], q->d, nof_symbols * sizeof(cf_t));
} }

@ -386,6 +386,12 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) {
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q, float rho_a) {
if (q) {
q->rho_a = rho_a;
}
}
void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti)
{ {
uint32_t rnti_idx = q->is_ue?0:rnti; uint32_t rnti_idx = q->is_ue?0:rnti;
@ -680,9 +686,14 @@ int srslte_pdsch_decode(srslte_pdsch_t *q,
memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers));
} }
float pdsch_scaling = 1.0f;
if (q->rho_a != 0.0f) {
pdsch_scaling = q->rho_a;
}
// Pre-decoder // Pre-decoder
if (srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, if (srslte_predecoding_type(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers,
cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate)<0) { cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, pdsch_scaling, noise_estimate)<0) {
return -1; return -1;
} }
@ -822,7 +833,7 @@ int srslte_pdsch_encode(srslte_pdsch_t *q,
/* Precode */ /* Precode */
srslte_precoding_type(x, q->symbols, cfg->nof_layers, q->cell.nof_ports, cfg->codebook_idx, srslte_precoding_type(x, q->symbols, cfg->nof_layers, q->cell.nof_ports, cfg->codebook_idx,
nof_symbols, cfg->mimo_type); nof_symbols, 1.0f, cfg->mimo_type);
} else { } else {
memcpy(q->symbols[0], q->d[0], cfg->nbits[0].nof_re * sizeof(cf_t)); memcpy(q->symbols[0], q->d[0], cfg->nbits[0].nof_re * sizeof(cf_t));
} }

@ -239,9 +239,9 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS],
/* in control channels, only diversity is supported */ /* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) { if (q->cell.nof_ports == 1) {
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, noise_estimate); srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, 1.0f, noise_estimate);
} else { } else {
srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB); srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB, 1.0f);
srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports);
} }
DEBUG("Recv!!: \n", 0); DEBUG("Recv!!: \n", 0);
@ -405,7 +405,7 @@ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d0, x, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB); srslte_layermap_diversity(q->d0, x, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB);
srslte_precoding_diversity(x, symbols_precoding, q->cell.nof_ports, srslte_precoding_diversity(x, symbols_precoding, q->cell.nof_ports,
SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports, 1.0f);
/**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */ /**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */
} else { } else {
memcpy(q->sf_symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); memcpy(q->sf_symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t));

@ -378,7 +378,7 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q,
} }
// No tx diversity in MBSFN // No tx diversity in MBSFN
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits[0].nof_re, noise_estimate); srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits[0].nof_re, 1.0f, noise_estimate);
if (SRSLTE_VERBOSE_ISDEBUG()) { if (SRSLTE_VERBOSE_ISDEBUG()) {
DEBUG("SAVED FILE subframe.dat: received subframe symbols\n"); DEBUG("SAVED FILE subframe.dat: received subframe symbols\n");

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

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

@ -590,11 +590,12 @@ int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci,
ret = dl_dci_to_grant_mcs(dci, grant, crc_is_crnti); ret = dl_dci_to_grant_mcs(dci, grant, crc_is_crnti);
if (ret == SRSLTE_SUCCESS) { if (ret == SRSLTE_SUCCESS) {
// Apply Section 7.1.7.3. If RA-RNTI and Format1C rv_idx=0 // Apply Section 7.1.7.3. If RA-RNTI and Format1C rv_idx=0
if (msg_rnti >= SRSLTE_RARNTI_START && msg_rnti <= SRSLTE_RARNTI_END && if (dci->dci_is_1c) {
dci->dci_is_1c) if ((msg_rnti >= SRSLTE_RARNTI_START && msg_rnti <= SRSLTE_RARNTI_END) || msg_rnti == SRSLTE_PRNTI)
{ {
dci->rv_idx = 0; dci->rv_idx = 0;
} }
}
} else { } else {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }

@ -53,7 +53,7 @@ srslte_cell_t cell = {
char mimo_type_str [32] = "single"; char mimo_type_str [32] = "single";
srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
uint32_t cfi = 2; uint32_t cfi = 1;
uint32_t mcs[SRSLTE_MAX_CODEWORDS] = {0, 0}; uint32_t mcs[SRSLTE_MAX_CODEWORDS] = {0, 0};
uint32_t subframe = 1; uint32_t subframe = 1;
int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1}; int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1};
@ -496,7 +496,9 @@ int main(int argc, char **argv) {
if (grant.tb_en[tb]) { if (grant.tb_en[tb]) {
for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) { for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) {
if (data_tx[tb][byte] != data_rx[tb][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]); ERROR("Found BYTE (%d) error in TB %d (%02X != %02X), quiting...", byte, tb, data_tx[tb][byte], data_rx[tb][byte]);
printf("Tx: "); srslte_vec_fprint_byte(stdout, data_tx[tb], grant.mcs[tb].tbs / 8);
printf("Rx: "); srslte_vec_fprint_byte(stdout, data_rx[tb], grant.mcs[tb].tbs / 8);
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
goto quit; goto quit;
} }

@ -28,64 +28,104 @@
#include <string.h> #include <string.h>
#include "srslte/phy/resampling/resample_arb.h" #include "srslte/phy/resampling/resample_arb.h"
#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
float srslte_resample_arb_polyfilt[SRSLTE_RESAMPLE_ARB_N][SRSLTE_RESAMPLE_ARB_M] =
{{0,0.002400347599485495,-0.006922416132556366,0.0179104136912176,0.99453086623794,-0.008521087756729117,0.0008598969867484128,0.0004992625165376107},
{-0.001903604727400391,0.004479591950094871,-0.01525319260830623,0.04647449496926549,0.9910477342662829,-0.03275243420114668,0.008048813755373533,-0.001216900416836847}, float srslte_resample_arb_polyfilt[SRSLTE_RESAMPLE_ARB_N][SRSLTE_RESAMPLE_ARB_M] __attribute__((aligned(256))) =
{-0.001750442300940216,0.006728826416921727,-0.02407540632178267,0.07708575473589654,0.9841056525667189,-0.05473739187922162,0.01460652754040275,-0.002745266140572769}, {{0.000499262532685, 0.000859897001646, -0.008521087467670, 0.994530856609344, 0.017910413444042, -0.006922415923327, 0.002400347497314, 0.000000000000000 },
{-0.001807302702047332,0.009130494591071001,-0.03332524241797466,0.1096377743266821,0.9737536341125557,-0.07444712408657775,0.0205085154280773,-0.004077596041064956}, {-0.001216900418513, 0.008048813790083, -0.032752435654402, 0.991047739982605, 0.046474494040012, -0.015253192745149, 0.004479591734707, -0.001903604716063 },
{-0.002005048395707184,0.01166717081713966,-0.04292591596219218,0.1440068251440274,0.9600641782991848,-0.09187282739868929,0.02573649090563353,-0.005218582609802016}, {-0.002745266072452, 0.014606527984142, -0.054737392812967, 0.984105646610260, 0.077085755765438, -0.024075405672193, 0.006728826556355, -0.001750442315824 },
{-0.002303606593778858,0.01431549924598744,-0.05279365431190471,0.1800496557331084,0.9431333663677619,-0.107022659158021,0.03028295984887362,-0.006178495199082676}, {-0.004077596124262, 0.020508514717221, -0.074447125196457, 0.973753631114960, 0.109637774527073, -0.033325243741274, 0.009130494669080, -0.001807302702218 },
{-0.002673824939871474,0.01705308556587308,-0.06283262272105428,0.2176066284621515,0.9230793648715676,-0.1199244901666642,0.03414559686566755,-0.006951034565279722}, {-0.005218582693487, 0.025736490264535, -0.091872826218605, 0.960064172744751, 0.144006818532944, -0.042925916612148, 0.011667170561850, -0.002005048329011 },
{-0.003099294850834212,0.01985022208215894,-0.07294100481214681,0.2564996326404178,0.9000412628278351,-0.1306207218667012,0.03733448898243594,-0.007554128492547957}, {-0.006178495008498, 0.030282959342003, -0.107022657990456, 0.943133354187012, 0.180049657821655, -0.052793655544519, 0.014315498992801, -0.002303606597707 },
{-0.003564415127592977,0.02267702927238637,-0.08300660359189582,0.2965368855416621,0.874178327911914,-0.1391710078036285,0.03986356581130199,-0.007992692892036229}, {-0.006951034534723, 0.034145597368479, -0.119924493134022, 0.923079371452332, 0.217606633901596, -0.062832623720169, 0.017053086310625, -0.002673825016245 },
{-0.004060222849803048,0.02549633298710617,-0.09291211362877161,0.3375102453232687,0.8456688916962831,-0.1456479420005528,0.04175429631970297,-0.00827816851803391}, {-0.007554128300399, 0.037334490567446, -0.130620718002319, 0.900041282176971, 0.256499618291855, -0.072941005229950, 0.019850222393870, -0.003099294845015 },
{-0.004574770330592958,0.02827133859849648,-0.1025308044303699,0.379200979038518,0.8147072909915275,-0.1501397816831265,0.04303284689167361,-0.008423951215857236}, {-0.007992693223059, 0.039863564074039, -0.139171004295349, 0.874178349971771, 0.296536892652512, -0.083006605505943, 0.022677028551698, -0.003564415033907 },
{-0.005100453570725489,0.0309593063669097,-0.1117325201826136,0.4213772298764557,0.7815036335229155,-0.1527444636485677,0.0437349357738538,-0.008441129184587313}, {-0.008278168737888, 0.041754297912121, -0.145647943019867, 0.845668911933899, 0.337510257959366, -0.092912115156651, 0.025496333837509, -0.004060222767293 },
{-0.005625340687997995,0.03351877124912608,-0.1203802123857154,0.463798444519773,0.7462810500374923,-0.1535722712206338,0.04389261707032224,-0.008345136869130621}, {-0.008423951454461, 0.043032847344875, -0.150139778852463, 0.814707279205322, 0.379200965166092, -0.102530807256699, 0.028271337971091, -0.004574770107865 },
{-0.006140888413286479,0.03590276234084221,-0.1283350405000867,0.5062161107254219,0.7092744343987509,-0.152741400055636,0.04355110899623683,-0.008147838953503964}, {-0.008441128768027, 0.043734934180975, -0.152744457125664, 0.781503617763519, 0.421377241611481, -0.111732520163059, 0.030959306284785, -0.005100453738123 },
{-0.006634012711933725,0.03806645580467819,-0.1354549138065051,0.5483763739419955,0.6707272107491931,-0.1503798528838644,0.0427502160096194,-0.007865132034489236}, {-0.008345136418939, 0.043892618268728, -0.153572276234627, 0.746281027793884, 0.463798433542252, -0.120380215346813, 0.033518772572279, -0.005625340621918 },
{-0.007094909626785393,0.03996043743797257,-0.1415969539549883,0.5900207719663111,0.6308907308946271,-0.1466186670140106,0.04153829696698895,-0.007508971112586246}, {-0.008147838525474, 0.043551109731197, -0.152741402387619, 0.709274411201477, 0.506216108798981, -0.128335043787956, 0.035902760922909, -0.006140888202935 },
{-0.007508971112586246,0.04153829696698895,-0.1466186670140106,0.6308907308946271,0.5900207719663111,-0.1415969539549883,0.03996043743797257,-0.007094909626785393}, {-0.007865131832659, 0.042750217020512, -0.150379851460457, 0.670727193355560, 0.548376381397247, -0.135454908013344, 0.038066454231739, -0.006634012795985 },
{-0.007865132034489236,0.0427502160096194,-0.1503798528838644,0.6707272107491931,0.5483763739419955,-0.1354549138065051,0.03806645580467819,-0.006634012711933725}, {-0.007508971262723, 0.041538298130035, -0.146618664264679, 0.630890727043152, 0.590020775794983, -0.141596958041191, 0.039960436522961, -0.007094909437001 },
{-0.008147838953503964,0.04355110899623683,-0.152741400055636,0.7092744343987509,0.5062161107254219,-0.1283350405000867,0.03590276234084221,-0.006140888413286479}, {-0.007094909437001, 0.039960436522961, -0.141596958041191, 0.590020775794983, 0.630890727043152, -0.146618664264679, 0.041538298130035, -0.007508971262723 },
{-0.008345136869130621,0.04389261707032224,-0.1535722712206338,0.7462810500374923,0.463798444519773,-0.1203802123857154,0.03351877124912608,-0.005625340687997995}, {-0.006634012795985, 0.038066454231739, -0.135454908013344, 0.548376381397247, 0.670727193355560, -0.150379851460457, 0.042750217020512, -0.007865131832659 },
{-0.008441129184587313,0.0437349357738538,-0.1527444636485677,0.7815036335229155,0.4213772298764557,-0.1117325201826136,0.0309593063669097,-0.005100453570725489}, {-0.006140888202935, 0.035902760922909, -0.128335043787956, 0.506216108798981, 0.709274411201477, -0.152741402387619, 0.043551109731197, -0.008147838525474 },
{-0.008423951215857236,0.04303284689167361,-0.1501397816831265,0.8147072909915275,0.379200979038518,-0.1025308044303699,0.02827133859849648,-0.004574770330592958}, {-0.005625340621918, 0.033518772572279, -0.120380215346813, 0.463798433542252, 0.746281027793884, -0.153572276234627, 0.043892618268728, -0.008345136418939 },
{-0.00827816851803391,0.04175429631970297,-0.1456479420005528,0.8456688916962831,0.3375102453232687,-0.09291211362877161,0.02549633298710617,-0.004060222849803048}, {-0.005100453738123, 0.030959306284785, -0.111732520163059, 0.421377241611481, 0.781503617763519, -0.152744457125664, 0.043734934180975, -0.008441128768027 },
{-0.007992692892036229,0.03986356581130199,-0.1391710078036285,0.874178327911914,0.2965368855416621,-0.08300660359189582,0.02267702927238637,-0.003564415127592977}, {-0.004574770107865, 0.028271337971091, -0.102530807256699, 0.379200965166092, 0.814707279205322, -0.150139778852463, 0.043032847344875, -0.008423951454461 },
{-0.007554128492547957,0.03733448898243594,-0.1306207218667012,0.9000412628278351,0.2564996326404178,-0.07294100481214681,0.01985022208215894,-0.003099294850834212}, {-0.004060222767293, 0.025496333837509, -0.092912115156651, 0.337510257959366, 0.845668911933899, -0.145647943019867, 0.041754297912121, -0.008278168737888 },
{-0.006951034565279722,0.03414559686566755,-0.1199244901666642,0.9230793648715676,0.2176066284621515,-0.06283262272105428,0.01705308556587308,-0.002673824939871474}, {-0.003564415033907, 0.022677028551698, -0.083006605505943, 0.296536892652512, 0.874178349971771, -0.139171004295349, 0.039863564074039, -0.007992693223059 },
{-0.006178495199082676,0.03028295984887362,-0.107022659158021,0.9431333663677619,0.1800496557331084,-0.05279365431190471,0.01431549924598744,-0.002303606593778858}, {-0.003099294845015, 0.019850222393870, -0.072941005229950, 0.256499618291855, 0.900041282176971, -0.130620718002319, 0.037334490567446, -0.007554128300399 },
{-0.005218582609802016,0.02573649090563353,-0.09187282739868929,0.9600641782991848,0.1440068251440274,-0.04292591596219218,0.01166717081713966,-0.002005048395707184}, {-0.002673825016245, 0.017053086310625, -0.062832623720169, 0.217606633901596, 0.923079371452332, -0.119924493134022, 0.034145597368479, -0.006951034534723 },
{-0.004077596041064956,0.0205085154280773,-0.07444712408657775,0.9737536341125557,0.1096377743266821,-0.03332524241797466,0.009130494591071001,-0.001807302702047332}, {-0.002303606597707, 0.014315498992801, -0.052793655544519, 0.180049657821655, 0.943133354187012, -0.107022657990456, 0.030282959342003, -0.006178495008498 },
{-0.002745266140572769,0.01460652754040275,-0.05473739187922162,0.9841056525667189,0.07708575473589654,-0.02407540632178267,0.006728826416921727,-0.001750442300940216}, {-0.002005048329011, 0.011667170561850, -0.042925916612148, 0.144006818532944, 0.960064172744751, -0.091872826218605, 0.025736490264535, -0.005218582693487 },
{-0.001216900416836847,0.008048813755373533,-0.03275243420114668,0.9910477342662829,0.04647449496926549,-0.01525319260830623,0.004479591950094871,-0.001903604727400391}, {-0.001807302702218, 0.009130494669080, -0.033325243741274, 0.109637774527073, 0.973753631114960, -0.074447125196457, 0.020508514717221, -0.004077596124262 },
{0.0004992625165376107,0.0008598969867484128,-0.008521087756729117,0.99453086623794,0.0179104136912176,-0.006922416132556366,0.002400347599485495,0}}; {-0.001750442315824, 0.006728826556355, -0.024075405672193, 0.077085755765438, 0.984105646610260, -0.054737392812967, 0.014606527984142, -0.002745266072452 },
{-0.001903604716063, 0.004479591734707, -0.015253192745149, 0.046474494040012, 0.991047739982605, -0.032752435654402, 0.008048813790083, -0.001216900418513 },
{0.000000000000000, 0.002400347497314, -0.006922415923327, 0.017910413444042, 0.994530856609344, -0.008521087467670, 0.000859897001646, 0.000499262532685 }};
// TODO: use lte/utils/vector.h and Volk
cf_t srslte_resample_arb_dot_prod(cf_t* x, float *y, int len)
{
cf_t res = 0+0*I;
for(int i=0;i<len;i++){ float srslte_resample_arb_polyfilt_35[SRSLTE_RESAMPLE_ARB_N_35][SRSLTE_RESAMPLE_ARB_M] __attribute__((aligned(256))) =
res += x[i]*y[i]; {{0.000002955485215, 0.000657994314549, -0.033395686652146, 0.188481383863832, 0.704261032406613, 0.171322660416961, -0.032053439082436, 0.000722236729272},
} {0.000003596427925, 0.000568080243211, -0.034615802155152, 0.206204344739138, 0.702921418438421, 0.154765509342932, -0.030612377229395, 0.000764085430796},
return res; {0.000005121937258, 0.000449039680445, -0.035689076986744, 0.224449928603191, 0.700248311996698, 0.138842912406449, -0.029094366813032, 0.000786624971348},
{0.000007718609465, 0.000297261794949, -0.036589488825594, 0.243172347408947, 0.696253915778072, 0.123583456372980, -0.027519775698206, 0.000792734165095},
{0.000011575047600, 0.000109005258838, -0.037289794881918, 0.262321777662990, 0.690956433427623, 0.109011322456059, -0.025907443019580, 0.000785077624893},
{0.000016882508098, -0.000119571475197, -0.037761641428480, 0.281844530653151, 0.684379949985066, 0.095146306185631, -0.024274662580170, 0.000766100891437},
{0.000023834849457, -0.000392374989948, -0.037975689603840, 0.301683254255907, 0.676554274013489, 0.082003866618022, -0.022637179782782, 0.000738028846774},
{0.000032627688404, -0.000713336731203, -0.037901757319987, 0.321777165554580, 0.667514742706306, 0.069595203590358, -0.021009201268519, 0.000702867092175},
{0.000043456678971, -0.001086367817537, -0.037508976943232, 0.342062313218325, 0.657301991568526, 0.057927361522269, -0.019403416364306, 0.000662405963124},
{0.000056514841640, -0.001515308860252, -0.036765968249551, 0.362471868314761, 0.645961690553484, 0.047003358086968, -0.017831029382043, 0.000618226851332},
{0.000071988882997, -0.002003874882511, -0.035641025985104, 0.382936441958648, 0.633544248803284, 0.036822335913581, -0.016301801765629, 0.000571710504985},
{0.000090054461223, -0.002555595491550, -0.034102321191048, 0.403384427938144, 0.620104490387788, 0.027379735343965, -0.014824103048525, 0.000524046983526},
{0.000110870369116, -0.003173750525766, -0.032118115280935, 0.423742368211529, 0.605701303660781, 0.018667486151043, -0.013404969563367, 0.000476246951838},
{0.000134571624077, -0.003861301468941, -0.029656985690720, 0.443935338933583, 0.590397267050922, 0.010674216032341, -0.012050169836157, 0.000429154010367},
{0.000161261473605, -0.004620818996097, -0.026688061757620, 0.463887354454611, 0.574258254277514, 0.003385473622292, -0.010764275599988, 0.000383457772129},
{0.000191002345063, -0.005454407088752, -0.023181269326746, 0.483521786538780, 0.557353022125450, -0.003216036280022, -0.009550737376604, 0.000339707414324},
{0.000223805789820, -0.006363624230896, -0.019107582435436, 0.502761795874207, 0.539752784028766, -0.009150207594916, -0.008411963597610, 0.000298325451050},
{0.000259621494011, -0.007349402269867, -0.014439280286493, 0.521530772797177, 0.521530772797177, -0.014439280286493, -0.007349402269867, 0.000259621494011},
{0.000298325451050, -0.008411963597610, -0.009150207594916, 0.539752784028765, 0.502761795874207, -0.019107582435436, -0.006363624230896, 0.000223805789820},
{0.000339707414324, -0.009550737376604, -0.003216036280022, 0.557353022125450, 0.483521786538780, -0.023181269326746, -0.005454407088752, 0.000191002345063},
{0.000383457772129, -0.010764275599988, 0.003385473622292, 0.574258254277514, 0.463887354454611, -0.026688061757620, -0.004620818996097, 0.000161261473605},
{0.000429154010367, -0.012050169836157, 0.010674216032341, 0.590397267050922, 0.443935338933583, -0.029656985690720, -0.003861301468941, 0.000134571624077},
{0.000476246951838, -0.013404969563367, 0.018667486151043, 0.605701303660781, 0.423742368211529, -0.032118115280935, -0.003173750525766, 0.000110870369116},
{0.000524046983526, -0.014824103048525, 0.027379735343965, 0.620104490387787, 0.403384427938144, -0.034102321191048, -0.002555595491550, 0.000090054461223},
{0.000571710504985, -0.016301801765629, 0.036822335913581, 0.633544248803283, 0.382936441958648, -0.035641025985104, -0.002003874882511, 0.000071988882997},
{0.000618226851332, -0.017831029382043, 0.047003358086968, 0.645961690553484, 0.362471868314761, -0.036765968249551, -0.001515308860252, 0.000056514841640},
{0.000662405963124, -0.019403416364306, 0.057927361522269, 0.657301991568526, 0.342062313218325, -0.037508976943232, -0.001086367817537, 0.000043456678971},
{0.000702867092175, -0.021009201268519, 0.069595203590358, 0.667514742706306, 0.321777165554580, -0.037901757319987, -0.000713336731203, 0.000032627688404},
{0.000738028846774, -0.022637179782782, 0.082003866618022, 0.676554274013489, 0.301683254255907, -0.037975689603840, -0.000392374989948, 0.000023834849457},
{0.000766100891437, -0.024274662580170, 0.095146306185631, 0.684379949985066, 0.281844530653151, -0.037761641428480, -0.000119571475197, 0.000016882508098},
{0.000785077624893, -0.025907443019580, 0.109011322456059, 0.690956433427623, 0.262321777662990, -0.037289794881918, 0.000109005258838, 0.000011575047600},
{0.000792734165095, -0.027519775698206, 0.123583456372980, 0.696253915778072, 0.243172347408947, -0.036589488825594, 0.000297261794949, 0.000007718609465},
{0.000786624971348, -0.029094366813032, 0.138842912406449, 0.700248311996698, 0.224449928603191, -0.035689076986744, 0.000449039680445, 0.000005121937258},
{0.000764085430796, -0.030612377229395, 0.154765509342932, 0.702921418438421, 0.206204344739138, -0.034615802155152, 0.000568080243211, 0.000003596427925},
{0.000722236729272, -0.032053439082436, 0.171322660416961, 0.704261032406613, 0.188481383863832, -0.033395686652146, 0.000657994314549 , 0.000002955485215}};
static inline cf_t srslte_resample_arb_dot_prod(cf_t* x, float *y, int len){
cf_t res1 = srslte_vec_dot_prod_cfc(x,y,len);
return res1;
} }
// Right-shift our window of samples // Right-shift our window of samples
void srslte_resample_arb_push(srslte_resample_arb_t *q, cf_t x) void srslte_resample_arb_push(srslte_resample_arb_t *q, cf_t x){
{
memmove(&q->reg[1], &q->reg[0], (SRSLTE_RESAMPLE_ARB_M-1)*sizeof(cf_t)); memmove(&q->reg[1], &q->reg[0], (SRSLTE_RESAMPLE_ARB_M-1)*sizeof(cf_t));
q->reg[0] = x; q->reg[0] = x;
} }
// Initialize our struct // Initialize our struct
void srslte_resample_arb_init(srslte_resample_arb_t *q, float rate){ void srslte_resample_arb_init(srslte_resample_arb_t *q, float rate, bool interpolate){
memset(q->reg, 0, SRSLTE_RESAMPLE_ARB_M*sizeof(cf_t)); memset(q->reg, 0, SRSLTE_RESAMPLE_ARB_M*sizeof(cf_t));
q->acc = 0.0; q->acc = 0.0;
q->rate = rate; q->rate = rate;
q->interpolate = interpolate;
q->step = (1/rate)*SRSLTE_RESAMPLE_ARB_N; q->step = (1/rate)*SRSLTE_RESAMPLE_ARB_N;
} }
@ -94,19 +134,48 @@ int srslte_resample_arb_compute(srslte_resample_arb_t *q, cf_t *input, cf_t *out
int cnt = 0; int cnt = 0;
int n_out = 0; int n_out = 0;
int idx = 0; int idx = 0;
cf_t res1,res2;
cf_t *filter_input;
float frac = 0;
memset(q->reg, 0, SRSLTE_RESAMPLE_ARB_M*sizeof(cf_t));
while (cnt < n_in) {
if(cnt<SRSLTE_RESAMPLE_ARB_M){
memcpy(&q->reg[SRSLTE_RESAMPLE_ARB_M - cnt], input, (cnt)*sizeof(cf_t));
filter_input = q->reg;
} else{
filter_input = &input[cnt-SRSLTE_RESAMPLE_ARB_M];
}
res1 = srslte_resample_arb_dot_prod(filter_input, srslte_resample_arb_polyfilt[idx], SRSLTE_RESAMPLE_ARB_M);
if(q->interpolate){
res2 = srslte_resample_arb_dot_prod(filter_input, srslte_resample_arb_polyfilt[(idx%SRSLTE_RESAMPLE_ARB_N)+1], SRSLTE_RESAMPLE_ARB_M);
}
if(idx == SRSLTE_RESAMPLE_ARB_N){
*output = res1;
}else {
*output = (q->interpolate)?(res1 + (res2-res1)*frac):res1;
}
while(cnt < n_in)
{
*output = srslte_resample_arb_dot_prod(q->reg, srslte_resample_arb_polyfilt[idx], SRSLTE_RESAMPLE_ARB_M);
output++; output++;
n_out++; n_out++;
q->acc += q->step; q->acc += q->step;
idx = (int)roundf(q->acc); idx = (int)(q->acc);
while(idx >= SRSLTE_RESAMPLE_ARB_N){ while(idx >= SRSLTE_RESAMPLE_ARB_N){
q->acc -= SRSLTE_RESAMPLE_ARB_N; q->acc -= SRSLTE_RESAMPLE_ARB_N;
idx -= SRSLTE_RESAMPLE_ARB_N; idx -= SRSLTE_RESAMPLE_ARB_N;
if(cnt < n_in) if(cnt < n_in){
srslte_resample_arb_push(q, input[cnt++]); cnt++;
}
}
if(q->interpolate){
frac = q->acc - idx;
if(frac < 0)
frac = frac*(-1);
} }
} }
return n_out; return n_out;

@ -35,9 +35,9 @@
#include "srslte/phy/resampling/resample_arb.h" #include "srslte/phy/resampling/resample_arb.h"
#define ITERATIONS 10000
int main(int argc, char **argv) { int main(int argc, char **argv) {
int N=10000000; int N=9000;
float rate = 24.0/25.0; float rate = 24.0/25.0;
cf_t *in = malloc(N*sizeof(cf_t)); cf_t *in = malloc(N*sizeof(cf_t));
cf_t *out = malloc(N*sizeof(cf_t)); cf_t *out = malloc(N*sizeof(cf_t));
@ -46,12 +46,15 @@ int main(int argc, char **argv) {
in[i] = sin(i*2*M_PI/100); in[i] = sin(i*2*M_PI/100);
srslte_resample_arb_t r; srslte_resample_arb_t r;
srslte_resample_arb_init(&r, rate); srslte_resample_arb_init(&r, rate, 0);
clock_t start = clock(), diff; clock_t start = clock(), diff;
//int n_out = srslte_resample_arb_compute(&r, in, out, N); for(int xx = 0; xx<ITERATIONS;xx++){
srslte_resample_arb_compute(&r, in, out, N);
}
diff = clock() - start; diff = clock() - start;
diff = diff/ITERATIONS;
int msec = diff * 1000 / CLOCKS_PER_SEC; int msec = diff * 1000 / CLOCKS_PER_SEC;
float thru = (CLOCKS_PER_SEC/(float)diff)*(N/1e6); float thru = (CLOCKS_PER_SEC/(float)diff)*(N/1e6);
printf("Time taken %d seconds %d milliseconds\n", msec/1000, msec%1000); printf("Time taken %d seconds %d milliseconds\n", msec/1000, msec%1000);

@ -35,12 +35,14 @@
#include "srslte/phy/resampling/resample_arb.h" #include "srslte/phy/resampling/resample_arb.h"
int main(int argc, char **argv) { int main(int argc, char **argv) {
int N = 100; // Number of sinwave samples int N = 100; // Number of sinwave samples
int delay = 5; // Delay of our resampling filter int delay = 5; // Delay of our resampling filter
float down = 25.0; // Downsampling rate float down = 25.0; // Downsampling rate
for(int up=1;up<down;up++) for(int up=1;up<down;up++)
{ {
float rate = up/down; float rate = up/down;
@ -62,7 +64,7 @@ int main(int argc, char **argv) {
// Resample // Resample
srslte_resample_arb_t r; srslte_resample_arb_t r;
srslte_resample_arb_init(&r, rate); srslte_resample_arb_init(&r, rate, 0);
int n_out = srslte_resample_arb_compute(&r, in, out, N); int n_out = srslte_resample_arb_compute(&r, in, out, N);
// Check interp values // Check interp values
@ -74,12 +76,11 @@ int main(int argc, char **argv) {
float diff = fabs(creal(in[pre])-creal(in[post])); float diff = fabs(creal(in[pre])-creal(in[post]));
float diff2 = fabs(creal(out[i])-creal(in[round])); float diff2 = fabs(creal(out[i])-creal(in[round]));
if(diff2 > diff && pre != post){ if(diff2 > diff && pre != post){
printf("Interpolation failed at index %f", idx); printf("Interpolation failed at index %f\n", idx);
exit(-1); exit(-1);
} }
} }
free(in); free(in);
free(out); free(out);
} }

@ -41,7 +41,7 @@ int rf_get_available_devices(char **devnames, int max_strlen) {
double srslte_rf_set_rx_gain_th(srslte_rf_t *rf, double gain) double srslte_rf_set_rx_gain_th(srslte_rf_t *rf, double gain)
{ {
if (gain > rf->new_rx_gain + 0.5 || gain < rf->new_rx_gain - 0.5) { if (gain > rf->new_rx_gain + 2 || gain < rf->new_rx_gain - 2) {
pthread_mutex_lock(&rf->mutex); pthread_mutex_lock(&rf->mutex);
rf->new_rx_gain = gain; rf->new_rx_gain = gain;
pthread_cond_signal(&rf->cond); pthread_cond_signal(&rf->cond);
@ -69,6 +69,7 @@ static void* thread_gain_fcn(void *h) {
srslte_rf_set_rx_gain(h, rf->cur_rx_gain); srslte_rf_set_rx_gain(h, rf->cur_rx_gain);
} }
if (rf->tx_gain_same_rx) { if (rf->tx_gain_same_rx) {
printf("setting also tx\n");
srslte_rf_set_tx_gain(h, rf->cur_rx_gain+rf->tx_rx_gain_offset); srslte_rf_set_tx_gain(h, rf->cur_rx_gain+rf->tx_rx_gain_offset);
} }
pthread_mutex_unlock(&rf->mutex); pthread_mutex_unlock(&rf->mutex);

@ -38,6 +38,7 @@
#include <SoapySDR/Formats.h> #include <SoapySDR/Formats.h>
typedef struct { typedef struct {
char *devname;
SoapySDRKwargs args; SoapySDRKwargs args;
SoapySDRDevice *device; SoapySDRDevice *device;
SoapySDRRange *ranges; SoapySDRRange *ranges;
@ -51,7 +52,6 @@ typedef struct {
cf_t zero_mem[64*1024]; cf_t zero_mem[64*1024];
int soapy_error(void *h) int soapy_error(void *h)
{ {
return 0; return 0;
@ -90,7 +90,8 @@ 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"; rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h;
return handler->devname;
} }
@ -196,11 +197,15 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
printf("No Soapy devices found.\n"); printf("No Soapy devices found.\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
char* devname;
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]);
if(!strcmp(soapy_args[i].keys[j],"name") && !strcmp(soapy_args[i].vals[j], "LimeSDR-USB")){
devname = DEVNAME_LIME;
}
} }
printf("\n"); printf("\n");
} }
@ -218,7 +223,7 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
handler->device = sdr; handler->device = sdr;
handler->tx_stream_active = false; handler->tx_stream_active = false;
handler->rx_stream_active = false; handler->rx_stream_active = false;
handler->devname = devname;
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) {
@ -234,6 +239,14 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }
size_t sensor_length;
char** sensors;
sensors = SoapySDRDevice_listSensors(handler->device, &sensor_length);
for(int i = 0; i < sensor_length;i++)
{
printf("available sensors are : \n");
puts(sensors[i]);
}
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -267,7 +280,7 @@ int rf_soapy_close(void *h)
void rf_soapy_set_master_clock_rate(void *h, double rate) void rf_soapy_set_master_clock_rate(void *h, double rate)
{ {
// Allow the soapy to automatically set the appropriate clock rate // Allow the soapy to automatically set the appropriate clock rate
// TODO: implement this function
} }
@ -285,7 +298,6 @@ double rf_soapy_set_rx_srate(void *h, double rate)
printf("setSampleRate Rx fail: %s\n", SoapySDRDevice_lastError()); printf("setSampleRate Rx fail: %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);
} }
@ -296,7 +308,6 @@ double rf_soapy_set_tx_srate(void *h, double rate)
printf("setSampleRate Tx fail: %s\n", SoapySDRDevice_lastError()); printf("setSampleRate Tx fail: %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);
} }

@ -28,7 +28,7 @@
#include <stdint.h> #include <stdint.h>
#include "srslte/config.h" #include "srslte/config.h"
#include "srslte/phy/rf/rf.h" #include "srslte/phy/rf/rf.h"
#define DEVNAME_LIME "lime"
SRSLTE_API int rf_soapy_open(char *args, SRSLTE_API int rf_soapy_open(char *args,
void **handler); void **handler);

@ -293,6 +293,13 @@ int rf_uhd_open(char *args, void **h)
return rf_uhd_open_multi(args, h, 1); return rf_uhd_open_multi(args, h, 1);
} }
#define REMOVE_SUBSTRING_WITHCOMAS(S, TOREMOVE) \
remove_substring(S, TOREMOVE ",");\
remove_substring(S, TOREMOVE ", ");\
remove_substring(S, "," TOREMOVE);\
remove_substring(S, ", " TOREMOVE);\
remove_substring(S, TOREMOVE)
static void remove_substring(char *s,const char *toremove) static void remove_substring(char *s,const char *toremove)
{ {
while((s=strstr(s,toremove))) { while((s=strstr(s,toremove))) {
@ -300,6 +307,17 @@ static void remove_substring(char *s,const char *toremove)
} }
} }
static void copy_subdev_string(char *dst, char *src) {
int n = 0;
size_t len = strlen(src);
/* Copy until end of string or comma */
while (n < len && src[n] != '\0' && src[n] != ',') {
dst[n] = src[n];
n++;
}
dst[n] = '\0';
}
int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
{ {
if (h) { if (h) {
@ -338,11 +356,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
// Check external clock argument // Check external clock argument
enum {DEFAULT, EXTERNAL, GPSDO} clock_src; enum {DEFAULT, EXTERNAL, GPSDO} clock_src;
if (strstr(args, "clock=external")) { if (strstr(args, "clock=external")) {
remove_substring(args, "clock=external"); REMOVE_SUBSTRING_WITHCOMAS(args, "clock=external");
clock_src = EXTERNAL; clock_src = EXTERNAL;
} else if (strstr(args, "clock=gpsdo")) { } else if (strstr(args, "clock=gpsdo")) {
printf("Using GPSDO clock\n"); printf("Using GPSDO clock\n");
remove_substring(args, "clock=gpsdo"); REMOVE_SUBSTRING_WITHCOMAS(args, "clock=gpsdo");
clock_src = GPSDO; clock_src = GPSDO;
} else { } else {
clock_src = DEFAULT; clock_src = DEFAULT;
@ -351,14 +369,42 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
// Set over the wire format // Set over the wire format
char *otw_format = "sc16"; char *otw_format = "sc16";
if (strstr(args, "otw_format=sc12")) { if (strstr(args, "otw_format=sc12")) {
REMOVE_SUBSTRING_WITHCOMAS(args, "otw_format=sc12");
otw_format = "sc12"; otw_format = "sc12";
} else if (strstr(args, "otw_format=sc16")) { } else if (strstr(args, "otw_format=sc16")) {
REMOVE_SUBSTRING_WITHCOMAS(args, "otw_format=sc16");
/* Do nothing */ /* Do nothing */
} else if (strstr(args, "otw_format=")) { } else if (strstr(args, "otw_format=")) {
fprintf(stderr, "Wrong over the wire format. Valid formats: sc12, sc16\n"); fprintf(stderr, "Wrong over the wire format. Valid formats: sc12, sc16\n");
return -1; return -1;
} }
// Set transmitter subdevice spec string
const char tx_subdev_arg[] = "tx_subdev_spec=";
char tx_subdev_str[64] = {0};
char *tx_subdev_ptr = strstr(args, tx_subdev_arg);
if (tx_subdev_ptr) {
copy_subdev_string(tx_subdev_str, tx_subdev_ptr + strlen(tx_subdev_arg));
}
// Set receiver subdevice spec string
const char rx_subdev_arg[] = "rx_subdev_spec=";
char rx_subdev_str[64] = {0};
char *rx_subdev_ptr = strstr(args, rx_subdev_arg);
if (rx_subdev_ptr) {
copy_subdev_string(rx_subdev_str, rx_subdev_ptr + strlen(rx_subdev_arg));
}
if (tx_subdev_ptr) {
remove_substring(args, tx_subdev_arg);
remove_substring(args, tx_subdev_str);
}
if (rx_subdev_ptr) {
remove_substring(args, rx_subdev_arg);
remove_substring(args, rx_subdev_str);
}
/* If device type or name not given in args, choose a B200 */ /* If device type or name not given in args, choose a B200 */
if (args[0]=='\0') { if (args[0]=='\0') {
if (find_string(devices_str, "type=b200") && !strstr(args, "recv_frame_size")) { if (find_string(devices_str, "type=b200") && !strstr(args, "recv_frame_size")) {
@ -399,6 +445,28 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
return -1; return -1;
} }
/* Set transmitter subdev spec if specified */
if (strlen(tx_subdev_str)) {
uhd_subdev_spec_handle subdev_spec_handle = {0};
printf("Setting tx_subdev_spec to '%s'\n", tx_subdev_str);
uhd_subdev_spec_make(&subdev_spec_handle, tx_subdev_str);
uhd_usrp_set_tx_subdev_spec(handler->usrp, subdev_spec_handle, 0);
uhd_subdev_spec_free(&subdev_spec_handle);
}
/* Set receiver subdev spec if specified */
if (strlen(rx_subdev_str)) {
uhd_subdev_spec_handle subdev_spec_handle = {0};
printf("Setting rx_subdev_spec to '%s'\n", rx_subdev_str);
uhd_subdev_spec_make(&subdev_spec_handle, rx_subdev_str);
uhd_usrp_set_rx_subdev_spec(handler->usrp, subdev_spec_handle, 0);
uhd_subdev_spec_free(&subdev_spec_handle);
}
if (!handler->devname) { if (!handler->devname) {
char dev_str[1024]; char dev_str[1024];
uhd_usrp_get_mboard_name(handler->usrp, 0, dev_str, 1024); uhd_usrp_get_mboard_name(handler->usrp, 0, dev_str, 1024);

@ -587,6 +587,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t
} }
} }
if (q->enable_cfo_corr) {
if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) {
float cfo2 = srslte_pss_synch_cfo_compute(&q->pss, &input[find_offset + peak_pos - q->fft_size]); float cfo2 = srslte_pss_synch_cfo_compute(&q->pss, &input[find_offset + peak_pos - q->fft_size]);
if (q->mean_cfo2_isunset) { if (q->mean_cfo2_isunset) {
@ -600,6 +601,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t
} else { } else {
ret = SRSLTE_SYNC_FOUND_NOSPACE; ret = SRSLTE_SYNC_FOUND_NOSPACE;
} }
}
} else { } else {
ret = SRSLTE_SYNC_NOFOUND; ret = SRSLTE_SYNC_NOFOUND;
} }

@ -308,7 +308,38 @@ void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q,
srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, non_mbsfn_region_length); srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, non_mbsfn_region_length);
} }
void srslte_ue_dl_set_power_alloc(srslte_ue_dl_t *q, float rho_a, float rho_b) {
if (q) {
srslte_pdsch_set_power_allocation(&q->pdsch, rho_a);
q->rho_b = rho_b;
uint32_t nof_symbols_slot = SRSLTE_CP_NSYMB(q->cell.cp);
uint32_t nof_re_symbol = SRSLTE_NRE * q->cell.nof_prb;
/* Apply rho_b if required according to 3GPP 36.213 Table 5.2-2 */
if (rho_b != 0.0f && rho_b != 1.0f) {
float scaling = 1.0f / rho_b;
for (uint32_t i = 0; i < q->nof_rx_antennas; i++) {
for (uint32_t j = 0; j < 2; j++) {
cf_t *ptr;
ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 0);
srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol);
if (q->cell.cp == SRSLTE_CP_NORM) {
ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 4);
srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol);
} else {
ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 3);
srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol);
}
if (q->cell.nof_ports == 4) {
ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 1);
srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol);
}
}
}
}
}
}
void srslte_ue_dl_reset(srslte_ue_dl_t *q) { void srslte_ue_dl_reset(srslte_ue_dl_t *q) {
for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){ for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){

@ -47,6 +47,10 @@
#define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0 #define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0
#define DEFAULT_SFO_EMA_COEFF 0.1 #define DEFAULT_SFO_EMA_COEFF 0.1
//#define DO_CFO_IN_SYNC
cf_t dummy_buffer0[15*2048/2]; cf_t dummy_buffer0[15*2048/2];
cf_t dummy_buffer1[15*2048/2]; cf_t dummy_buffer1[15*2048/2];
@ -118,6 +122,8 @@ int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, double (set_gain_callback)(voi
q->do_agc = n==0?true:false; q->do_agc = n==0?true:false;
if (q->do_agc) { if (q->do_agc) {
srslte_agc_set_gain(&q->agc, init_gain_value); srslte_agc_set_gain(&q->agc, init_gain_value);
srslte_agc_set_target(&q->agc, 0.3);
srslte_agc_set_bandwidth(&q->agc, 0.8);
} }
return n; return n;
} }
@ -182,6 +188,9 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q,
q->sample_offset_correct_period = DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD; q->sample_offset_correct_period = DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD;
q->sfo_ema = DEFAULT_SFO_EMA_COEFF; q->sfo_ema = DEFAULT_SFO_EMA_COEFF;
q->mean_cfo_isunset = true;
q->mean_cfo = 0;
q->cfo_ema_alpha = 0.4;
q->max_prb = max_prb; q->max_prb = max_prb;
if (search_cell) { if (search_cell) {
@ -218,6 +227,11 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q,
} }
} }
#ifndef DO_CFO_IN_SYNC
// Disable CFO correction in sync object and do it here every subframe
srslte_sync_set_cfo_enable(&q->strack, false);
#endif
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
@ -362,6 +376,7 @@ uint32_t srslte_ue_sync_peak_idx(srslte_ue_sync_t *q) {
void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float ema) { void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float ema) {
srslte_sync_set_cfo_ema_alpha(&q->sfind, ema); srslte_sync_set_cfo_ema_alpha(&q->sfind, ema);
srslte_sync_set_cfo_ema_alpha(&q->strack, ema); srslte_sync_set_cfo_ema_alpha(&q->strack, ema);
q->cfo_ema_alpha = ema;
} }
srslte_ue_sync_state_t srslte_ue_sync_get_state(srslte_ue_sync_t *q) { srslte_ue_sync_state_t srslte_ue_sync_get_state(srslte_ue_sync_t *q) {
@ -377,7 +392,11 @@ void srslte_ue_sync_cfo_i_detec_en(srslte_ue_sync_t *q, bool enable) {
} }
float srslte_ue_sync_get_cfo(srslte_ue_sync_t *q) { float srslte_ue_sync_get_cfo(srslte_ue_sync_t *q) {
#ifdef DO_CFO_IN_SYNC
return 15000 * srslte_sync_get_cfo(&q->strack); return 15000 * srslte_sync_get_cfo(&q->strack);
#else
return 15000 * q->mean_cfo;
#endif
} }
void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q, float cfo) { void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q, float cfo) {
@ -662,6 +681,23 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
q->sf_idx = (q->sf_idx + q->nof_recv_sf) % 10; q->sf_idx = (q->sf_idx + q->nof_recv_sf) % 10;
#ifndef DO_CFO_IN_SYNC
/* We found that CP-based correction performs better in low SNR than PSS-based.
*
* Estimate, average and correct here instead of inside sync object
*/
q->cfo = srslte_sync_cfo_estimate(&q->strack, input_buffer[0], 0);
if (q->mean_cfo_isunset) {
q->mean_cfo = q->cfo;
q->mean_cfo_isunset = false;
} else {
/* compute exponential moving average CFO */
q->mean_cfo = SRSLTE_VEC_EMA(q->cfo, q->mean_cfo, q->cfo_ema_alpha);
}
srslte_cfo_correct(&q->strack.cfocorr2, input_buffer[0], input_buffer[0], -q->mean_cfo / q->fft_size);
#endif
/* Every SF idx 0 and 5, find peak around known position q->peak_idx */ /* Every SF idx 0 and 5, find peak around known position q->peak_idx */
if (q->sf_idx == 0 || q->sf_idx == 5) { if (q->sf_idx == 0 || q->sf_idx == 5) {

@ -453,7 +453,7 @@ int srslte_ue_ul_pusch_encode_rnti_softbuffer(srslte_ue_ul_t *q,
if (srslte_pusch_encode(&q->pusch, &q->pusch_cfg, softbuffer, data, uci_data, rnti, q->sf_symbols)) { if (srslte_pusch_encode(&q->pusch, &q->pusch_cfg, softbuffer, data, uci_data, rnti, q->sf_symbols)) {
fprintf(stderr, "Error encoding TB\n"); fprintf(stderr, "Error encoding TB\n");
return ret; return SRSLTE_ERROR;
} }
if (q->signals_pregenerated) { if (q->signals_pregenerated) {

@ -24,7 +24,14 @@
* *
*/ */
#include <pthread.h>
#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/debug.h"
#include "srslte/version.h"
int srslte_verbose = 0; int srslte_verbose = 0;
@ -37,3 +44,57 @@ void get_time_interval(struct timeval * tdata) {
tdata[0].tv_usec += 1000000; tdata[0].tv_usec += 1000000;
} }
} }
const static char crash_file_name[] = "./srsLTE.backtrace.crash";
static int bt_argc;
static char **bt_argv;
static void crash_handler(int sig) {
void *array[128];
int size;
/* Get all stack traces */
size = backtrace(array, 128);
FILE *f = fopen(crash_file_name, "a");
if (!f) {
printf("srsLTE crashed... we could not save backtrace in '%s'...\n", crash_file_name);
} else {
char **symbols = backtrace_symbols(array, size);
time_t lnTime;
struct tm *stTime;
char strdate[32];
time(&lnTime);
stTime = localtime(&lnTime);
strftime(strdate, 32, "%d/%m/%Y %H:%M:%S", stTime);
fprintf(f, "--- command='");
for (int i = 0; i < bt_argc; i++) {
fprintf(f, "%s%s", (i == 0) ? "" : " ", bt_argv[i]);
}
fprintf(f, "' version=%s signal=%d date='%s' ---\n", SRSLTE_VERSION_STRING, sig, strdate);
for (int i = 0; i < size; i++) {
fprintf(f, "\t%s\n", symbols[i]);
}
fprintf(f, "\n");
printf("srsLTE crashed... backtrace saved in '%s'...\n", crash_file_name);
fclose(f);
}
printf("--- exiting ---\n");
exit(1);
}
void srslte_debug_handle_crash(int argc, char **argv) {
bt_argc = argc;
bt_argv = argv;
signal(SIGSEGV, crash_handler);
signal(SIGABRT, crash_handler);
signal(SIGILL, crash_handler);
signal(SIGFPE, crash_handler);
}

@ -502,6 +502,7 @@ TEST(srslte_vec_abs_cf,
for (int i = 0; i < block_size; i++) { for (int i = 0; i < block_size; i++) {
x[i] = RANDOM_CF(); x[i] = RANDOM_CF();
} }
x[0] = 0.0f;
TEST_CALL(srslte_vec_abs_cf(x, z, block_size)) TEST_CALL(srslte_vec_abs_cf(x, z, block_size))

@ -199,7 +199,6 @@ void srslte_vec_lut_sss_simd(short *x, unsigned short *lut, short *y, int len) {
} }
} }
/* Modified from volk_32f_s32f_convert_16i_a_simd2. Removed clipping */
void srslte_vec_convert_fi_simd(float *x, int16_t *z, float scale, int len) { void srslte_vec_convert_fi_simd(float *x, int16_t *z, float scale, int len) {
int i = 0; int i = 0;

@ -59,6 +59,7 @@ bool radio::init(char *args, char *devname)
} else if (strstr(srslte_rf_name(&rf_device), "bladerf")) { } else if (strstr(srslte_rf_name(&rf_device), "bladerf")) {
burst_preamble_sec = blade_default_burst_preamble_sec; burst_preamble_sec = blade_default_burst_preamble_sec;
} else { } else {
burst_preamble_sec = 0;
printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device));
} }
@ -329,7 +330,6 @@ void radio::set_tx_srate(double srate)
} }
burst_preamble_time_rounded = (double) burst_preamble_samples/cur_tx_srate; burst_preamble_time_rounded = (double) burst_preamble_samples/cur_tx_srate;
int nsamples=0; int nsamples=0;
/* Set time advance for each known device if in auto mode */ /* Set time advance for each known device if in auto mode */
if (tx_adv_auto) { if (tx_adv_auto) {
@ -356,6 +356,47 @@ void radio::set_tx_srate(double srate)
printf("\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", cur_tx_srate); 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); 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), "uhd_usrp2")) {
double srate_khz = round(cur_tx_srate/1e3);
if (srate_khz == 1.92e3) {
nsamples = 14;// estimated
} else if (srate_khz == 3.84e3) {
nsamples = 32;
} else if (srate_khz == 5.76e3) {
nsamples = 43;
} else if (srate_khz == 11.52e3) {
nsamples = 54;
} else if (srate_khz == 15.36e3) {
nsamples = 65;// to calc
} else if (srate_khz == 23.04e3) {
nsamples = 80; // to calc
} 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), "lime")) {
double srate_khz = round(cur_tx_srate/1e3);
if (srate_khz == 1.92e3) {
nsamples = 70;// estimated
} else if (srate_khz == 3.84e3) {
nsamples = 76;//estimated
} else if (srate_khz == 5.76e3) {
nsamples = 76;
} else if (srate_khz == 11.52e3) {
nsamples = 76;
} else if (srate_khz == 15.36e3) {
nsamples = 73;
} else if (srate_khz == 23.04e3) {
nsamples = 87;
} 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), "uhd_x300")) { } else if (!strcmp(srslte_rf_name(&rf_device), "uhd_x300")) {
// In X300 TX/RX offset is independent of sampling rate // In X300 TX/RX offset is independent of sampling rate

@ -201,10 +201,16 @@ uint32_t rlc_am::get_total_buffer_state()
rlc_amd_retx_t retx = retx_queue.front(); rlc_amd_retx_t retx = retx_queue.front();
log->debug("Buffer state - retx - SN: %d, Segment: %s, %d:%d\n", retx.sn, retx.is_segment ? "true" : "false", retx.so_start, retx.so_end); log->debug("Buffer state - retx - SN: %d, Segment: %s, %d:%d\n", retx.sn, retx.is_segment ? "true" : "false", retx.so_start, retx.so_end);
if(tx_window.end() != tx_window.find(retx.sn)) { if(tx_window.end() != tx_window.find(retx.sn)) {
n_bytes += required_buffer_size(retx); int req_bytes = required_buffer_size(retx);
if (req_bytes < 0) {
log->error("In get_total_buffer_state(): Removing retx.sn=%d from queue\n", retx.sn);
retx_queue.pop_front();
} else {
n_bytes += req_bytes;
log->debug("Buffer state - retx: %d bytes\n", n_bytes); log->debug("Buffer state - retx: %d bytes\n", n_bytes);
} }
} }
}
// Bytes needed for tx SDUs // Bytes needed for tx SDUs
if(tx_window.size() < 1024) { if(tx_window.size() < 1024) {
@ -250,7 +256,13 @@ uint32_t rlc_am::get_buffer_state()
rlc_amd_retx_t retx = retx_queue.front(); rlc_amd_retx_t retx = retx_queue.front();
log->debug("Buffer state - retx - SN: %d, Segment: %s, %d:%d\n", retx.sn, retx.is_segment ? "true" : "false", retx.so_start, retx.so_end); log->debug("Buffer state - retx - SN: %d, Segment: %s, %d:%d\n", retx.sn, retx.is_segment ? "true" : "false", retx.so_start, retx.so_end);
if(tx_window.end() != tx_window.find(retx.sn)) { if(tx_window.end() != tx_window.find(retx.sn)) {
n_bytes = required_buffer_size(retx); int req_bytes = required_buffer_size(retx);
if (req_bytes < 0) {
log->error("In get_buffer_state(): Removing retx.sn=%d from queue\n", retx.sn);
retx_queue.pop_front();
goto unlock_and_return;
}
n_bytes = (uint32_t) req_bytes;
log->debug("Buffer state - retx: %d bytes\n", n_bytes); log->debug("Buffer state - retx: %d bytes\n", n_bytes);
goto unlock_and_return; goto unlock_and_return;
} }
@ -296,8 +308,9 @@ int rlc_am::read_pdu(uint8_t *payload, uint32_t nof_bytes)
} }
// RETX if required // RETX if required
if(retx_queue.size() > 0) { if(retx_queue.size() > 0) {
int ret = build_retx_pdu(payload, nof_bytes);
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
return build_retx_pdu(payload, nof_bytes); return ret;
} }
// Build a PDU from SDUs // Build a PDU from SDUs
@ -438,16 +451,33 @@ int rlc_am::build_status_pdu(uint8_t *payload, uint32_t nof_bytes)
int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes) int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes)
{ {
// Check there is at least 1 element before calling front()
if (retx_queue.empty()) {
log->error("In build_retx_pdu(): retx_queue is empty\n");
return -1;
}
rlc_amd_retx_t retx = retx_queue.front(); rlc_amd_retx_t retx = retx_queue.front();
// Sanity check - drop any retx SNs not present in tx_window // Sanity check - drop any retx SNs not present in tx_window
while(tx_window.end() == tx_window.find(retx.sn)) { while(tx_window.end() == tx_window.find(retx.sn)) {
retx_queue.pop_front(); retx_queue.pop_front();
if (!retx_queue.empty()) {
retx = retx_queue.front(); retx = retx_queue.front();
} else {
log->error("In build_retx_pdu(): retx_queue is empty during sanity check\n");
return -1;
}
} }
// Is resegmentation needed? // Is resegmentation needed?
if(retx.is_segment || required_buffer_size(retx) > (int)nof_bytes) { int req_size = required_buffer_size(retx);
if (req_size < 0) {
log->error("In build_retx_pdu(): Removing retx.sn=%d from queue\n", retx.sn);
retx_queue.pop_front();
return -1;
}
if(retx.is_segment || req_size > (int)nof_bytes) {
log->debug("%s build_retx_pdu - resegmentation required\n", rrc->get_rb_name(lcid).c_str()); log->debug("%s build_retx_pdu - resegmentation required\n", rrc->get_rb_name(lcid).c_str());
return build_segment(payload, nof_bytes, retx); return build_segment(payload, nof_bytes, retx);
} }
@ -481,6 +511,10 @@ int rlc_am::build_retx_pdu(uint8_t *payload, uint32_t nof_bytes)
int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx) int rlc_am::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_amd_retx_t retx)
{ {
if (!tx_window[retx.sn].buf) {
log->error("In build_segment: retx.sn=%d has null buffer\n", retx.sn);
return 0;
}
if(!retx.is_segment){ if(!retx.is_segment){
retx.so_start = 0; retx.so_start = 0;
retx.so_end = tx_window[retx.sn].buf->N_bytes; retx.so_end = tx_window[retx.sn].buf->N_bytes;
@ -1147,7 +1181,17 @@ bool rlc_am::add_segment_and_check(rlc_amd_rx_pdu_segments_t *pdu, rlc_amd_rx_pd
int rlc_am::required_buffer_size(rlc_amd_retx_t retx) int rlc_am::required_buffer_size(rlc_amd_retx_t retx)
{ {
if(!retx.is_segment){ if(!retx.is_segment){
if (tx_window.count(retx.sn)) {
if (tx_window[retx.sn].buf) {
return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes;
} else {
log->warning("retx.sn=%d has null ptr in required_buffer_size()\n", retx.sn);
return -1;
}
} else {
log->warning("retx.sn=%d does not exist in required_buffer_size()\n", retx.sn);
return -1;
}
} }
// Construct new header // Construct new header

@ -112,6 +112,11 @@ private:
void metrics_read(phy_metrics_t *metrics); void metrics_read(phy_metrics_t *metrics);
void metrics_dl(uint32_t mcs); void metrics_dl(uint32_t mcs);
void metrics_ul(uint32_t mcs, float rssi, float sinr, uint32_t turbo_iters); void metrics_ul(uint32_t mcs, float rssi, float sinr, uint32_t turbo_iters);
int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS];
int last_ul_tbs[2*HARQ_DELAY_MS];
srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS];
private: private:
phy_metrics_t metrics; phy_metrics_t metrics;
}; };

@ -767,7 +767,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
{ {
ul_harq_proc::ul_alloc_t alloc = h->get_alloc(); ul_harq_proc::ul_alloc_t alloc = h->get_alloc();
bool is_newtx = h->is_empty(); bool is_newtx = h->is_empty();
bool needs_pdcch = !h->is_adaptive_retx() && !is_rar; bool needs_pdcch = h->is_adaptive_retx() && !is_rar;
// Set number of retx // Set number of retx
if (is_newtx) { if (is_newtx) {

@ -198,13 +198,13 @@ ul_harq_proc::ul_alloc_t ul_harq_proc::get_alloc()
void ul_harq_proc::set_alloc(ul_harq_proc::ul_alloc_t alloc) void ul_harq_proc::set_alloc(ul_harq_proc::ul_alloc_t alloc)
{ {
is_adaptive = false; is_adaptive = true;
memcpy(&allocation, &alloc, sizeof(ul_alloc_t)); memcpy(&allocation, &alloc, sizeof(ul_alloc_t));
} }
void ul_harq_proc::same_alloc() void ul_harq_proc::same_alloc()
{ {
is_adaptive = true; is_adaptive = false;
} }
bool ul_harq_proc::is_adaptive_retx() bool ul_harq_proc::is_adaptive_retx()
@ -243,7 +243,6 @@ void ul_harq_proc::reset_pending_data()
} }
} }
uint32_t ul_harq_proc::get_pending_data() uint32_t ul_harq_proc::get_pending_data()
{ {
return pending_data; return pending_data;

@ -25,11 +25,6 @@
*/ */
#include <string.h> #include <string.h>
#include <boost/concept_check.hpp>
#include <srslte/interfaces/sched_interface.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"
@ -397,12 +392,6 @@ int sched_ue::generate_format1(dl_harq_proc *h,
h->new_tx(tti, mcs, tbs, data->dci_location.ncce); h->new_tx(tti, mcs, tbs, data->dci_location.ncce);
Debug("SCHED: Alloc format1 new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes);
} else {
h->new_retx(tti, &mcs, &tbs);
Debug("SCHED: Alloc format1 previous mcs=%d, tbs=%d\n", mcs, tbs);
}
// Allocate MAC ConRes CE // Allocate MAC ConRes CE
if (need_conres_ce) { if (need_conres_ce) {
data->pdu[0].lcid = srslte::sch_subh::CON_RES_ID; data->pdu[0].lcid = srslte::sch_subh::CON_RES_ID;
@ -420,6 +409,12 @@ int sched_ue::generate_format1(dl_harq_proc *h,
} }
} while(rem_tbs > 0 && x > 0); } while(rem_tbs > 0 && x > 0);
Debug("SCHED: Alloc format1 new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes);
} else {
h->new_retx(tti, &mcs, &tbs);
Debug("SCHED: Alloc format1 previous mcs=%d, tbs=%d\n", mcs, tbs);
}
data->rnti = rnti; data->rnti = rnti;
if (tbs > 0) { if (tbs > 0) {
@ -450,6 +445,7 @@ int sched_ue::generate_format0(ul_harq_proc *h,
ul_harq_proc::ul_alloc_t allocation = h->get_alloc(); ul_harq_proc::ul_alloc_t allocation = h->get_alloc();
bool is_newtx = true;
if (h->get_rar_mcs(&mcs)) { if (h->get_rar_mcs(&mcs)) {
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8; tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8;
h->new_tx(tti, mcs, tbs); h->new_tx(tti, mcs, tbs);
@ -469,6 +465,7 @@ int sched_ue::generate_format0(ul_harq_proc *h,
h->new_tx(tti, mcs, tbs); h->new_tx(tti, mcs, tbs);
} else { } else {
is_newtx = false;
h->new_retx(tti, &mcs, NULL); h->new_retx(tti, &mcs, NULL);
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8; tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8;
} }
@ -479,8 +476,12 @@ int sched_ue::generate_format0(ul_harq_proc *h,
if (tbs > 0) { if (tbs > 0) {
dci->type2_alloc.L_crb = allocation.L; dci->type2_alloc.L_crb = allocation.L;
dci->type2_alloc.RB_start = allocation.RB_start; dci->type2_alloc.RB_start = allocation.RB_start;
dci->mcs_idx = mcs;
dci->rv_idx = sched::get_rvidx(h->nof_retx()); dci->rv_idx = sched::get_rvidx(h->nof_retx());
if (!is_newtx && h->is_adaptive_retx()) {
dci->mcs_idx = 28+dci->rv_idx;
} else {
dci->mcs_idx = mcs;
}
dci->ndi = h->get_ndi(); dci->ndi = h->get_ndi();
dci->cqi_request = cqi_request; dci->cqi_request = cqi_request;
dci->freq_hop_fl = srslte_ra_ul_dci_t::SRSLTE_RA_PUSCH_HOP_DISABLED; dci->freq_hop_fl = srslte_ra_ul_dci_t::SRSLTE_RA_PUSCH_HOP_DISABLED;

@ -350,6 +350,8 @@ int main(int argc, char *argv[])
metrics_stdout metrics; metrics_stdout metrics;
enb *enb = enb::get_instance(); enb *enb = enb::get_instance();
srslte_debug_handle_crash(argc, argv);
cout << "--- Software Radio Systems LTE eNodeB ---" << endl << endl; cout << "--- Software Radio Systems LTE eNodeB ---" << endl << endl;
parse_args(&args, argc, argv); parse_args(&args, argc, argv);

@ -412,6 +412,22 @@ 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)) { if (!srslte_ra_ul_dci_to_grant(&grants[i].grant, enb_ul.cell.nof_prb, n_rb_ho, &phy_grant)) {
// Handle Format0 adaptive retx
// Use last TBS for this TB in case of mcs>28
if (phy_grant.mcs.idx > 28) {
phy_grant.mcs.tbs = ue_db[rnti].last_ul_tbs[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)];
Info("RETX: mcs=%d, old_tbs=%d pid=%d\n", phy_grant.mcs.idx, phy_grant.mcs.tbs, TTI_TX(tti_rx)%(2*HARQ_DELAY_MS));
}
ue_db[rnti].last_ul_tbs[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)] = phy_grant.mcs.tbs;
if (phy_grant.mcs.mod == SRSLTE_MOD_LAST) {
phy_grant.mcs.mod = ue_db[rnti].last_ul_mod[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)];
phy_grant.Qm = srslte_mod_bits_x_symbol(phy_grant.mcs.mod);
}
ue_db[rnti].last_ul_mod[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)] = phy_grant.mcs.mod;
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;
} }

@ -44,16 +44,13 @@
namespace srsue { namespace srsue {
template <std::size_t N, typename Tgrant, typename Taction, typename Tphygrant> template <std::size_t N, typename Tgrant, typename Taction, typename Tphygrant>
class ul_harq_entity class ul_harq_entity {
{
public: public:
static uint32_t pidof(uint32_t tti) static uint32_t pidof(uint32_t tti) {
{
return (uint32_t) tti % N; return (uint32_t) tti % N;
} }
ul_harq_entity() : proc(N) ul_harq_entity() : proc(N) {
{
contention_timer = NULL; contention_timer = NULL;
pcap = NULL; pcap = NULL;
@ -69,8 +66,7 @@ public:
mac_interface_rrc_common::ue_rnti_t *rntis_, mac_interface_rrc_common::ue_rnti_t *rntis_,
mac_interface_rrc_common::ul_harq_params_t *params_, mac_interface_rrc_common::ul_harq_params_t *params_,
srslte::timers::timer *contention_timer_, srslte::timers::timer *contention_timer_,
mux *mux_unit_) mux *mux_unit_) {
{
log_h = log_h_; log_h = log_h_;
mux_unit = mux_unit_; mux_unit = mux_unit_;
params = params_; params = params_;
@ -84,29 +80,29 @@ public:
return true; return true;
} }
void reset() void reset() {
{
for (uint32_t i = 0; i < N; i++) { for (uint32_t i = 0; i < N; i++) {
proc[i].reset(); proc[i].reset();
} }
ul_sps_assig.clear(); ul_sps_assig.clear();
} }
void reset_ndi() void reset_ndi() {
{
for (uint32_t i = 0; i < N; i++) { for (uint32_t i = 0; i < N; i++) {
proc[i].reset_ndi(); proc[i].reset_ndi();
} }
} }
void start_pcap(srslte::mac_pcap* pcap_) void start_pcap(srslte::mac_pcap *pcap_) {
{
pcap = pcap_; pcap = pcap_;
} }
/***************** PHY->MAC interface for UL processes **************************/ /***************** PHY->MAC interface for UL processes **************************/
void new_grant_ul(Tgrant grant, Taction *action) void new_grant_ul(Tgrant grant, Taction *action) {
new_grant_ul_ack(grant, NULL, action);
}
void new_grant_ul_ack(Tgrant grant, bool *ack, Taction *action)
{ {
if (grant.rnti_type == SRSLTE_RNTI_USER || if (grant.rnti_type == SRSLTE_RNTI_USER ||
grant.rnti_type == SRSLTE_RNTI_TEMP || grant.rnti_type == SRSLTE_RNTI_TEMP ||
@ -115,27 +111,20 @@ public:
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) { if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) {
grant.ndi[0] = true; grant.ndi[0] = true;
} }
run_tti(grant.tti, &grant, action); run_tti(grant.tti, &grant, ack, action);
} else if (grant.rnti_type == SRSLTE_RNTI_SPS) { } else if (grant.rnti_type == SRSLTE_RNTI_SPS) {
if (grant.ndi[0]) { if (grant.ndi[0]) {
grant.ndi[0] = proc[pidof(grant.tti)].get_ndi(); grant.ndi[0] = proc[pidof(grant.tti)].get_ndi();
run_tti(grant.tti, &grant, action); run_tti(grant.tti, &grant, ack, action);
} else { } else {
Info("Not implemented\n"); Info("Not implemented\n");
} }
} }
} }
void new_grant_ul_ack(Tgrant grant, bool ack, Taction *action)
{
set_ack(grant.tti, ack, action);
new_grant_ul(grant, action);
}
void harq_recv(uint32_t tti, bool ack, Taction *action) void harq_recv(uint32_t tti, bool ack, Taction *action)
{ {
set_ack(tti, ack, action); run_tti(tti, NULL, &ack, action);
run_tti(tti, NULL, action);
} }
int get_current_tbs(uint32_t tti) int get_current_tbs(uint32_t tti)
@ -206,10 +195,19 @@ private:
bzero(&cur_grant, sizeof(Tgrant)); bzero(&cur_grant, sizeof(Tgrant));
} }
void reset_ndi() { ndi = false; } void reset_ndi() { cur_grant.ndi[0] = false; }
void run_tti(uint32_t tti_tx, Tgrant *grant, Taction* action) void run_tti(uint32_t tti_tx, Tgrant *grant, bool *ack, Taction* action)
{ {
if (ack) {
if (grant) {
if (grant->ndi[0] == get_ndi()) {
*ack = false;
}
}
set_harq_feedback(*ack);
}
uint32_t max_retx; uint32_t max_retx;
if (is_msg3) { if (is_msg3) {
max_retx = harq_entity->params->max_harq_msg3_tx; max_retx = harq_entity->params->max_harq_msg3_tx;
@ -219,7 +217,7 @@ private:
// Receive and route HARQ feedbacks // Receive and route HARQ feedbacks
if (grant) { if (grant) {
if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi()) || if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi() && ack) ||
(grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) || (grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) ||
grant->is_from_rar) grant->is_from_rar)
{ {
@ -245,7 +243,7 @@ private:
Warning("Uplink grant but no MAC PDU in Multiplex Unit buffer\n"); Warning("Uplink grant but no MAC PDU in Multiplex Unit buffer\n");
} }
} }
} else { } else if (has_grant()) {
// Adaptive Re-TX // Adaptive Re-TX
if (current_tx_nb >= max_retx) { if (current_tx_nb >= max_retx) {
Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx);
@ -254,6 +252,8 @@ private:
} else { } else {
generate_retx(tti_tx, grant, action); generate_retx(tti_tx, grant, action);
} }
} else {
Warning("UL %d: Received retransmission but no previous grant available for this PID.\n", pid);
} }
} else if (has_grant()) { } else if (has_grant()) {
// Non-Adaptive Re-Tx // Non-Adaptive Re-Tx
@ -292,9 +292,8 @@ private:
} }
bool has_grant() { return is_grant_configured; } bool has_grant() { return is_grant_configured; }
bool get_ndi() { return ndi; } bool get_ndi() { return cur_grant.ndi[0]; }
bool is_sps() { return false; } bool is_sps() { return false; }
uint32_t last_tx_tti() { return tti_last_tx; }
uint32_t get_nof_retx() { return current_tx_nb; } uint32_t get_nof_retx() { return current_tx_nb; }
int get_current_tbs() { return cur_grant.n_bytes[0]*8; } int get_current_tbs() { return cur_grant.n_bytes[0]*8; }
@ -305,7 +304,6 @@ private:
uint32_t current_tx_nb; uint32_t current_tx_nb;
uint32_t current_irv; uint32_t current_irv;
bool harq_feedback; bool harq_feedback;
bool ndi;
srslte::log *log_h; srslte::log *log_h;
ul_harq_entity *harq_entity; ul_harq_entity *harq_entity;
bool is_grant_configured; bool is_grant_configured;
@ -396,22 +394,10 @@ private:
// Implements Section 5.4.2.1 // Implements Section 5.4.2.1
// Called with UL grant // Called with UL grant
void run_tti(uint32_t tti, Tgrant *grant, Taction* action) void run_tti(uint32_t tti, Tgrant *grant, bool *ack, Taction* action)
{ {
uint32_t tti_tx = (tti+action->tti_offset)%10240; uint32_t tti_tx = (tti+action->tti_offset)%10240;
proc[pidof(tti_tx)].run_tti(tti_tx, grant, action); proc[pidof(tti_tx)].run_tti(tti_tx, grant, ack, action);
}
void set_ack(uint32_t tti, bool ack, Taction *action)
{
int tti_harq = (int) tti - action->tti_offset;
if (tti_harq < 0) {
tti_harq += 10240;
}
uint32_t pid_harq = pidof(tti_harq);
if (proc[pid_harq].has_grant() && (proc[pid_harq].last_tx_tti() <= (uint32_t)tti_harq)) {
proc[pid_harq].set_harq_feedback(ack);
}
} }
ul_sps ul_sps_assig; ul_sps ul_sps_assig;

@ -69,6 +69,14 @@ namespace srsue {
bool pcell_meas_enabled; bool pcell_meas_enabled;
uint32_t pcell_report_period; uint32_t pcell_report_period;
// Save last TBS for mcs>28 cases
int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS];
uint32_t last_dl_tti[2*HARQ_DELAY_MS];
int last_ul_tbs[2*HARQ_DELAY_MS];
uint32_t last_ul_tti[2*HARQ_DELAY_MS];
srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS];
phch_common(uint32_t max_mutex = 3); phch_common(uint32_t max_mutex = 3);
void init(phy_interface_rrc::phy_cfg_t *config, void init(phy_interface_rrc::phy_cfg_t *config,
phy_args_t *args, phy_args_t *args,

@ -80,6 +80,7 @@ public:
const static int MUTEX_X_WORKER = 4; const static int MUTEX_X_WORKER = 4;
double set_rx_gain(double gain);
int radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); int radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time);
int scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); int scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time);

@ -151,11 +151,6 @@ private:
float cfo; float cfo;
bool rar_cqi_request; bool rar_cqi_request;
// Save last TBS for mcs>28 cases
int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS];
int last_ul_tbs[2*HARQ_DELAY_MS];
srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS];
// Metrics // Metrics
dl_metrics_t dl_metrics; dl_metrics_t dl_metrics;
ul_metrics_t ul_metrics; ul_metrics_t ul_metrics;

@ -38,6 +38,7 @@
#include "srslte/radio/radio_multi.h" #include "srslte/radio/radio_multi.h"
#include "phy/phy.h" #include "phy/phy.h"
#include "upper/usim.h" #include "upper/usim.h"
#include "upper/rrc.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/logger.h" #include "srslte/common/logger.h"
@ -107,7 +108,6 @@ typedef struct {
phy_args_t phy; phy_args_t phy;
float metrics_period_secs; float metrics_period_secs;
bool pregenerate_signals; bool pregenerate_signals;
std::string ue_cateogry;
bool metrics_csv_enable; bool metrics_csv_enable;
std::string metrics_csv_filename; std::string metrics_csv_filename;
}expert_args_t; }expert_args_t;
@ -120,6 +120,8 @@ typedef struct {
log_args_t log; log_args_t log;
gui_args_t gui; gui_args_t gui;
usim_args_t usim; usim_args_t usim;
rrc_args_t rrc;
std::string ue_category_str;
expert_args_t expert; expert_args_t expert;
}all_args_t; }all_args_t;
@ -161,6 +163,10 @@ public:
srslte::log_filter rf_log; srslte::log_filter rf_log;
rf_metrics_t rf_metrics; rf_metrics_t rf_metrics;
srslte::LOG_LEVEL_ENUM level(std::string l); srslte::LOG_LEVEL_ENUM level(std::string l);
std::string get_build_mode();
std::string get_build_info();
std::string get_build_string();
}; };
} // namespace srsue } // namespace srsue

@ -57,6 +57,9 @@ static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL",
"DEREGISTERED INITIATED", "DEREGISTERED INITIATED",
"TRACKING AREA UPDATE INITIATED"}; "TRACKING AREA UPDATE INITIATED"};
static const bool eia_caps[8] = {false, true, true, false, false, false, false, false};
static const bool eea_caps[8] = {true, false, false, false, false, false, false, false};
typedef enum { typedef enum {
PLMN_NOT_SELECTED = 0, PLMN_NOT_SELECTED = 0,
PLMN_SELECTED PLMN_SELECTED
@ -80,16 +83,12 @@ public:
// RRC interface // RRC interface
void notify_connection_setup(); void notify_connection_setup();
void write_pdu(uint32_t lcid, byte_buffer_t *pdu); void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
uint32_t get_ul_count(); uint32_t get_ul_count();
bool is_attached(); bool is_attached();
bool is_attaching(); bool is_attaching();
bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi); bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi);
bool get_k_asme(uint8_t *k_asme_, uint32_t n);
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(); void plmn_search_end();
@ -115,72 +114,73 @@ private:
std::vector<LIBLTE_RRC_PLMN_IDENTITY_STRUCT > known_plmns; std::vector<LIBLTE_RRC_PLMN_IDENTITY_STRUCT > known_plmns;
// Save short MAC LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT emm_info;
// Identifiers // Identifiers
LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti; LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti;
bool is_guti_set; bool have_guti;
// Security context
struct nas_sec_ctxt{
uint8_t ksi;
uint8_t k_asme[32];
uint32_t tx_count;
uint32_t rx_count;
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
};
bool have_ctxt;
nas_sec_ctxt ctxt;
uint32_t ip_addr; uint32_t ip_addr;
uint8_t eps_bearer_id; uint8_t eps_bearer_id;
uint8_t transaction_id; uint8_t transaction_id;
// NAS counters - incremented for each security-protected message recvd/sent
uint32_t count_ul;
uint32_t count_dl;
// Security // Security
uint8_t ksi;
uint8_t k_nas_enc[32]; uint8_t k_nas_enc[32];
uint8_t k_nas_int[32]; uint8_t k_nas_int[32];
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; void integrity_generate(uint8_t integ_algo,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; uint8_t *key_128,
void integrity_generate(uint8_t *key_128,
uint32_t count, uint32_t count,
uint8_t rb_id, uint8_t rb_id,
uint8_t direction, uint8_t direction,
uint8_t *msg, uint8_t *msg,
uint32_t msg_len, uint32_t msg_len,
uint8_t *mac); uint8_t *mac);
void integrity_check(); void integrity_check();
void cipher_encrypt(); void cipher_encrypt();
void cipher_decrypt(); void cipher_decrypt();
bool check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps);
// Parsers // Parsers
void parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu); void parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu);
void parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu); void parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu);
void parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu); void parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu);
void parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu); void parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu);
void parse_identity_request(uint32_t lcid, byte_buffer_t *pdu); void parse_identity_request(uint32_t lcid, byte_buffer_t *pdu);
void parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu); void parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu);
void parse_service_reject(uint32_t lcid, byte_buffer_t *pdu); void parse_service_reject(uint32_t lcid, byte_buffer_t *pdu);
void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu); void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu);
void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu); void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu);
// Senders // Senders
void send_attach_request(); void send_attach_request();
void send_identity_response(); void send_identity_response();
void send_service_request(); void send_service_request();
void send_esm_information_response(); void send_esm_information_response();
void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg); void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg);
void send_security_mode_reject(uint8_t cause);
// guti persistence file
bool read_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT *guti);
bool write_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti);
// security context persistence file
bool read_ctxt_file(nas_sec_ctxt *ctxt);
bool write_ctxt_file(nas_sec_ctxt ctxt);
}; };
} // namespace srsue } // namespace srsue

@ -40,6 +40,13 @@
#include <map> #include <map>
#include <queue> #include <queue>
typedef struct {
uint32_t ue_category;
uint32_t feature_group;
uint8_t supported_bands[LIBLTE_RRC_BAND_N_ITEMS];
uint32_t nof_supported_bands;
}rrc_args_t;
using srslte::byte_buffer_t; using srslte::byte_buffer_t;
namespace srsue { namespace srsue {
@ -74,7 +81,7 @@ public:
rrc_state_t get_state(); rrc_state_t get_state();
void set_ue_category(int category); void set_args(rrc_args_t *args);
// Timeout callback interface // Timeout callback interface
void timer_expired(uint32_t timeout_id); void timer_expired(uint32_t timeout_id);
@ -142,6 +149,9 @@ private:
uint8_t transaction_id; uint8_t transaction_id;
bool drb_up; bool drb_up;
rrc_args_t args;
bool first_stimsi_attempt;
bool reestablishment_in_progress; bool reestablishment_in_progress;
bool pending_mob_reconf; bool pending_mob_reconf;
@ -174,10 +184,11 @@ private:
// RRC constants and timers // RRC constants and timers
srslte::mac_interface_timers *mac_timers; srslte::mac_interface_timers *mac_timers;
uint32_t sync_reset_cnt;
const static uint32_t SYNC_RESET_TIMEOUT = 10;
uint32_t n310_cnt, N310; uint32_t n310_cnt, N310;
uint32_t n311_cnt, N311; uint32_t n311_cnt, N311;
uint32_t t301, t310, t311, t304; uint32_t t301, t310, t311, t304;
int ue_category;
typedef struct { typedef struct {
uint32_t earfcn; uint32_t earfcn;
@ -375,7 +386,6 @@ private:
void set_mac_default(); void set_mac_default();
void set_rrc_default(); void set_rrc_default();
void set_bearers(); void set_bearers();
}; };
} // namespace srsue } // namespace srsue

@ -1,4 +1,4 @@
/** /**
* *
* \section COPYRIGHT * \section COPYRIGHT
* *
@ -59,24 +59,30 @@ public:
void stop(); void stop();
// NAS interface // NAS interface
void get_imsi_vec(uint8_t* imsi_, uint32_t n); std::string get_imsi_str();
void get_imei_vec(uint8_t* imei_, uint32_t n); std::string get_imei_str();
int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id);
bool get_imsi_vec(uint8_t* imsi_, uint32_t n);
bool get_imei_vec(uint8_t* imei_, uint32_t n);
bool 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,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid, bool *net_valid,
uint8_t *res); uint8_t *res,
uint8_t *k_asme);
void generate_nas_keys(uint8_t *k_nas_enc, void generate_nas_keys(uint8_t *k_asme,
uint8_t *k_nas_enc,
uint8_t *k_nas_int, uint8_t *k_nas_int,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo);
// RRC interface // RRC interface
void generate_as_keys(uint32_t count_ul, void generate_as_keys(uint8_t *k_asme,
uint32_t count_ul,
uint8_t *k_rrc_enc, uint8_t *k_rrc_enc,
uint8_t *k_rrc_int, uint8_t *k_rrc_int,
uint8_t *k_up_enc, uint8_t *k_up_enc,
@ -100,13 +106,15 @@ private:
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid, bool *net_valid,
uint8_t *res); uint8_t *res,
uint8_t *k_asme);
void gen_auth_res_xor( uint8_t *rand, void gen_auth_res_xor( uint8_t *rand,
uint8_t *autn_enb, uint8_t *autn_enb,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid, bool *net_valid,
uint8_t *res); uint8_t *res,
uint8_t *k_asme);
void str_to_hex(std::string str, uint8_t *hex); void str_to_hex(std::string str, uint8_t *hex);
srslte::log *usim_log; srslte::log *usim_log;
@ -119,6 +127,9 @@ private:
uint64_t imei; uint64_t imei;
uint8_t k[16]; uint8_t k[16];
std::string imsi_str;
std::string imei_str;
// Security variables // Security variables
uint8_t rand[16]; uint8_t rand[16];
uint8_t ck[16]; uint8_t ck[16];
@ -126,7 +137,6 @@ private:
uint8_t ak[6]; uint8_t ak[6];
uint8_t mac[8]; uint8_t mac[8];
uint8_t autn[16]; uint8_t autn[16];
uint8_t k_asme[32];
uint8_t k_enb[32]; uint8_t k_enb[32];
uint8_t k_enb_star[32]; uint8_t k_enb_star[32];

@ -319,7 +319,7 @@ 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)
{ {
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) {
metrics.tx_errors++; metrics.tx_errors++;
} else { } else {

@ -243,10 +243,8 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32
} }
} }
} }
// Now allocate the SDUs from the RLC
for (uint32_t i=0;i<lch.size();i++) { for (uint32_t i=0;i<lch.size();i++) {
if (lch[i].sched_len != 0) { if (lch[i].sched_len != 0) {
log_h->info("Allocating scheduled lch=%d len=%d\n", lch[i].id, lch[i].sched_len);
allocate_sdu(lch[i].id, &pdu_msg, lch[i].sched_len); allocate_sdu(lch[i].id, &pdu_msg, lch[i].sched_len);
} }
} }
@ -296,8 +294,8 @@ bool mux::sched_sdu(lchid_t *ch, int *sdu_space, int max_sdu_sz)
sched_len = *sdu_space; sched_len = *sdu_space;
} }
log_h->info("SDU: scheduled lcid=%d, rlc_buffer=%d, allocated=%d/%d\n", log_h->debug("SDU: scheduled lcid=%d, rlc_buffer=%d, allocated=%d/%d\n",
ch->id, ch->buffer_len, sched_len, *sdu_space); ch->id, ch->buffer_len, sched_len, sdu_space?*sdu_space:0);
*sdu_space -= sched_len; *sdu_space -= sched_len;
ch->buffer_len -= sched_len; ch->buffer_len -= sched_len;
@ -320,16 +318,15 @@ bool mux::allocate_sdu(uint32_t lcid, srslte::sch_pdu* pdu_msg, int max_sdu_sz)
sdu_len = max_sdu_sz; sdu_len = max_sdu_sz;
} }
int sdu_space = pdu_msg->get_sdu_space(); int sdu_space = pdu_msg->get_sdu_space();
if (sdu_len > sdu_space) { if (sdu_len > sdu_space || max_sdu_sz < 0) {
sdu_len = sdu_space; sdu_len = sdu_space;
} }
if (sdu_len > MIN_RLC_SDU_LEN) { if (sdu_len > MIN_RLC_SDU_LEN) {
if (pdu_msg->new_subh()) { // there is space for a new subheader if (pdu_msg->new_subh()) { // there is space for a new subheader
int sdu_len2 = sdu_len;
sdu_len = pdu_msg->get()->set_sdu(lcid, sdu_len, rlc); sdu_len = pdu_msg->get()->set_sdu(lcid, sdu_len, rlc);
if (sdu_len > 0) { // new SDU could be added if (sdu_len > 0) { // new SDU could be added
Info("SDU: allocated lcid=%d, rlc_buffer=%d, allocated=%d/%d, max_sdu_sz=%d, remaining=%d\n", Debug("SDU: allocated lcid=%d, rlc_buffer=%d, allocated=%d/%d, max_sdu_sz=%d, remaining=%d\n",
lcid, buffer_state, sdu_len, sdu_space, max_sdu_sz, pdu_msg->rem_size()); lcid, buffer_state, sdu_len, sdu_space, max_sdu_sz, pdu_msg->rem_size());
return true; return true;
} else { } else {

@ -75,8 +75,12 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
("rf.device_args", bpo::value<string>(&args->rf.device_args)->default_value("auto"), "Front-end device arguments") ("rf.device_args", bpo::value<string>(&args->rf.device_args)->default_value("auto"), "Front-end device arguments")
("rf.time_adv_nsamples", bpo::value<string>(&args->rf.time_adv_nsamples)->default_value("auto"), ("rf.time_adv_nsamples", bpo::value<string>(&args->rf.time_adv_nsamples)->default_value("auto"),
"Transmission time advance") "Transmission time advance")
("rf.burst_preamble_us", bpo::value<string>(&args->rf.burst_preamble)->default_value("auto"), ("rf.burst_preamble_us", bpo::value<string>(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance")
"Transmission time advance")
("rrc.feature_group", bpo::value<uint32_t>(&args->rrc.feature_group)->default_value(0xe6041c00), "Hex value of the featureGroupIndicators field in the"
"UECapabilityInformation message. Default 0xe6041c00")
("rrc.ue_category", bpo::value<string>(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)")
("pcap.enable", bpo::value<bool>(&args->pcap.enable)->default_value(false), ("pcap.enable", bpo::value<bool>(&args->pcap.enable)->default_value(false),
"Enable MAC packet captures for wireshark") "Enable MAC packet captures for wireshark")
@ -134,10 +138,6 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
bpo::value<int>(&args->expert.phy.sync_cpu_affinity)->default_value(-1), bpo::value<int>(&args->expert.phy.sync_cpu_affinity)->default_value(-1),
"index of the core used by the sync thread") "index of the core used by the sync thread")
("expert.ue_category",
bpo::value<string>(&args->expert.ue_cateogry)->default_value("4"),
"UE Category (1 to 5)")
("expert.metrics_period_secs", ("expert.metrics_period_secs",
bpo::value<float>(&args->expert.metrics_period_secs)->default_value(1.0), bpo::value<float>(&args->expert.metrics_period_secs)->default_value(1.0),
"Periodicity for metrics in seconds") "Periodicity for metrics in seconds")
@ -203,7 +203,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
"Tolerance (in Hz) for digial CFO compensation.") "Tolerance (in Hz) for digial CFO compensation.")
("expert.cfo_ema", ("expert.cfo_ema",
bpo::value<float>(&args->expert.phy.cfo_ema)->default_value(0.4), bpo::value<float>(&args->expert.phy.cfo_ema)->default_value(0.3),
"CFO Exponential Moving Average coefficient. Lower makes it more robust to noise " "CFO Exponential Moving Average coefficient. Lower makes it more robust to noise "
"but vulnerable to periodic interruptions due to VCO corrections.") "but vulnerable to periodic interruptions due to VCO corrections.")
@ -369,6 +369,9 @@ int main(int argc, char *argv[])
srslte::metrics_hub<ue_metrics_t> metricshub; srslte::metrics_hub<ue_metrics_t> metricshub;
signal(SIGINT, sig_int_handler); signal(SIGINT, sig_int_handler);
all_args_t args; all_args_t args;
srslte_debug_handle_crash(argc, argv);
parse_args(&args, argc, argv); parse_args(&args, argc, argv);
srsue_instance_type_t type = LTE; srsue_instance_type_t type = LTE;

@ -43,8 +43,7 @@ int radio_recv_callback(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsampl
} }
double callback_set_rx_gain(void *h, double gain) { double callback_set_rx_gain(void *h, double gain) {
srslte::radio_multi *radio_handler = (srslte::radio_multi *) h; return ((phch_recv*) h)->set_rx_gain(gain);
return radio_handler->set_rx_gain_th(gain);
} }
@ -395,8 +394,6 @@ bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) {
current_earfcn = earfcn; current_earfcn = earfcn;
printf("cell select called set frequency\n");
if (set_frequency()) { if (set_frequency()) {
this->cell = cell; this->cell = cell;
log_h->info("Cell Select: Configuring cell...\n"); log_h->info("Cell Select: Configuring cell...\n");
@ -519,6 +516,9 @@ int phch_recv::radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, s
} }
} }
double phch_recv::set_rx_gain(double gain) {
return radio_h->set_rx_gain_th(gain);
}

@ -27,6 +27,7 @@
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include "phy/phch_worker.h" #include "phy/phch_worker.h"
#include "srslte/srslte.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/asn1/liblte_rrc.h" #include "srslte/asn1/liblte_rrc.h"
@ -40,8 +41,6 @@
#ifdef ENABLE_GUI #ifdef ENABLE_GUI
#include "srsgui/srsgui.h" #include "srsgui/srsgui.h"
#include <semaphore.h> #include <semaphore.h>
#include "srslte/srslte.h"
#include "srslte/interfaces/ue_interfaces.h"
void init_plots(srsue::phch_worker *worker); void init_plots(srsue::phch_worker *worker);
pthread_t plot_thread; pthread_t plot_thread;
@ -130,6 +129,7 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h)
srslte_ue_ul_set_normalization(&ue_ul, true); srslte_ue_ul_set_normalization(&ue_ul, true);
srslte_ue_ul_set_cfo_enable(&ue_ul, true); srslte_ue_ul_set_cfo_enable(&ue_ul, true);
srslte_ue_ul_set_cfo_tol(&ue_ul, phy->args->cfo_correct_tol_hz);
mem_initiated = true; mem_initiated = true;
@ -479,15 +479,19 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant)
return false; return false;
} }
grant->pid = ASYNC_DL_SCHED?dci_unpacked.harq_process:(tti%(2*HARQ_DELAY_MS)); grant->pid = ASYNC_DL_SCHED?dci_unpacked.harq_process:(UL_PIDOF(TTI_TX(tti)));
// Set last TBS for this TB (pid) in case of mcs>29 (7.1.7.2 of 36.213) // Set last TBS for this TB (pid) in case of mcs>28 (7.1.7.2 of 36.213)
for (int i=0;i<SRSLTE_MAX_CODEWORDS;i++) { for (int i=0;i<SRSLTE_MAX_CODEWORDS;i++) {
if (grant->phy_grant.dl.mcs[i].idx > 28) {
grant->phy_grant.dl.mcs[i].tbs = phy->last_dl_tbs[grant->pid][i];
}
if(grant->phy_grant.dl.mcs[i].tbs < 0) { if(grant->phy_grant.dl.mcs[i].tbs < 0) {
grant->phy_grant.dl.mcs[i].tbs = last_dl_tbs[grant->pid%(2*HARQ_DELAY_MS)][i]; Info("Invalid TBS size for PDSCH grant\n");
grant->phy_grant.dl.mcs[i].tbs = 0;
} }
// save it // save it
last_dl_tbs[grant->pid%(2*HARQ_DELAY_MS)][i] = grant->phy_grant.dl.mcs[i].tbs; phy->last_dl_tbs[grant->pid][i] = grant->phy_grant.dl.mcs[i].tbs;
} }
/* Fill MAC grant structure */ /* Fill MAC grant structure */
@ -536,14 +540,19 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL
for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
if (grant->tb_en[tb] && (rv[tb] < 0 || rv[tb] > 3)) { if (grant->tb_en[tb] && (rv[tb] < 0 || rv[tb] > 3)) {
valid_config = false; valid_config = false;
Error("Wrong RV (%d) for TB index %d", rv[tb], tb); Error("Wrong RV (%d) for TB index %d\n", rv[tb], tb);
} }
} }
uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(grant);
switch(phy->config->dedicated.antenna_info_explicit_value.tx_mode) { switch(phy->config->dedicated.antenna_info_explicit_value.tx_mode) {
/* Implemented Tx Modes */ /* Implemented Tx Modes */
case LIBLTE_RRC_TRANSMISSION_MODE_1: case LIBLTE_RRC_TRANSMISSION_MODE_1:
mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
if (nof_tb != 1) {
Error("Wrong number of transport blocks (%d) for single antenna.", nof_tb);
valid_config = false;
}
break; break;
case LIBLTE_RRC_TRANSMISSION_MODE_2: case LIBLTE_RRC_TRANSMISSION_MODE_2:
if (cell.nof_ports > 1) { if (cell.nof_ports > 1) {
@ -551,26 +560,30 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL
} else { } else {
mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
} }
if (nof_tb != 1) {
Error("Wrong number of transport blocks (%d) for transmit diversity.", nof_tb);
valid_config = false;
}
break; break;
case LIBLTE_RRC_TRANSMISSION_MODE_3: case LIBLTE_RRC_TRANSMISSION_MODE_3:
if (SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 1) { if (nof_tb == 1) {
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else if (ue_dl.nof_rx_antennas > 1 && SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 2) { } else if (ue_dl.nof_rx_antennas > 1 && nof_tb == 2) {
mimo_type = SRSLTE_MIMO_TYPE_CDD; mimo_type = SRSLTE_MIMO_TYPE_CDD;
} else { } else {
Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM3\n", ue_dl.nof_rx_antennas, Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM3\n", ue_dl.nof_rx_antennas,
SRSLTE_RA_DL_GRANT_NOF_TB(grant)); nof_tb);
valid_config = false; valid_config = false;
} }
break; break;
case LIBLTE_RRC_TRANSMISSION_MODE_4: case LIBLTE_RRC_TRANSMISSION_MODE_4:
if (SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 1) { if (nof_tb == 1) {
mimo_type = (grant->pinfo == 0) ? SRSLTE_MIMO_TYPE_TX_DIVERSITY : SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; mimo_type = (grant->pinfo == 0) ? SRSLTE_MIMO_TYPE_TX_DIVERSITY : SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
} else if (ue_dl.nof_rx_antennas > 1 && SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 2) { } else if (ue_dl.nof_rx_antennas > 1 && nof_tb == 2) {
mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
} else { } else {
Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM3\n", ue_dl.nof_rx_antennas, Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM3\n", ue_dl.nof_rx_antennas,
SRSLTE_RA_DL_GRANT_NOF_TB(grant)); nof_tb);
valid_config = false; valid_config = false;
} }
break; break;
@ -590,6 +603,19 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL
valid_config = false; valid_config = false;
} }
/* Set power allocation according to 3GPP 36.213 clause 5.2 Downlink power allocation */
float rho_a = 1.0f, rho_b = 1.0f;
if (phy->config->dedicated.pdsch_cnfg_ded < LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS) {
float rho_a_db = liblte_rrc_pdsch_config_p_a_num[(int) phy->config->dedicated.pdsch_cnfg_ded];
rho_a = powf(10.0f, rho_a_db / 20.0f) * ((cell.nof_ports == 1) ? 1.0f : sqrtf(2.0f));
}
if (phy->config->common.pdsch_cnfg.p_b < 4) {
uint32_t idx0 = (cell.nof_ports == 1) ? 0 : 1;
float cell_specific_ratio = pdsch_cfg_cell_specific_ratio_table[idx0][phy->config->common.pdsch_cnfg.p_b];
rho_b = sqrtf(cell_specific_ratio);
}
srslte_ue_dl_set_power_alloc(&ue_dl, rho_a, rho_b);
Debug("DL Buffer TTI %d: Decoding PDSCH\n", tti); Debug("DL Buffer TTI %d: Decoding PDSCH\n", tti);
/* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */ /* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */
@ -646,6 +672,9 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL
Error("Error configuring DL grant\n"); Error("Error configuring DL grant\n");
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
} }
} else {
Error("Error invalid DL config\n");
ret = SRSLTE_ERROR;
} }
return ret; return ret;
} }
@ -729,21 +758,21 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant)
} }
} }
if (ret) {
// Handle Format0 adaptive retx
if (ret) {
// Use last TBS for this TB in case of mcs>28 // Use last TBS for this TB in case of mcs>28
if (grant->phy_grant.ul.mcs.tbs < 0) { if (grant->phy_grant.ul.mcs.idx > 28) {
grant->phy_grant.ul.mcs.tbs = last_ul_tbs[tti%(2*HARQ_DELAY_MS)]; // Make sure we received a grant in the previous TTI for this PID
} grant->phy_grant.ul.mcs.tbs = phy->last_ul_tbs[UL_PIDOF(TTI_TX(tti))];
last_ul_tbs[tti%(2*HARQ_DELAY_MS)] = grant->phy_grant.ul.mcs.tbs; grant->phy_grant.ul.mcs.mod = phy->last_ul_mod[UL_PIDOF(TTI_TX(tti))];
if (grant->phy_grant.ul.mcs.mod == SRSLTE_MOD_LAST) {
grant->phy_grant.ul.mcs.mod = last_ul_mod[tti%(2*HARQ_DELAY_MS)];
grant->phy_grant.ul.Qm = srslte_mod_bits_x_symbol(grant->phy_grant.ul.mcs.mod); grant->phy_grant.ul.Qm = srslte_mod_bits_x_symbol(grant->phy_grant.ul.mcs.mod);
} }
last_ul_mod[tti%(2*HARQ_DELAY_MS)] = grant->phy_grant.ul.mcs.mod;
} }
if (ret) {
phy->last_ul_tbs[UL_PIDOF(TTI_TX(tti))] = grant->phy_grant.ul.mcs.tbs;
phy->last_ul_mod[UL_PIDOF(TTI_TX(tti))] = grant->phy_grant.ul.mcs.mod;
phy->last_ul_tti[UL_PIDOF(TTI_TX(tti))] = TTI_RX_ACK(tti);
/* Limit UL modulation if not supported by the UE or disabled by higher layers */ /* Limit UL modulation if not supported by the UE or disabled by higher layers */
if (!phy->config->enable_64qam) { if (!phy->config->enable_64qam) {
if (grant->phy_grant.ul.mcs.mod >= SRSLTE_MOD_64QAM) { if (grant->phy_grant.ul.mcs.mod >= SRSLTE_MOD_64QAM) {
@ -751,6 +780,7 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant)
grant->phy_grant.ul.Qm = 4; grant->phy_grant.ul.Qm = 4;
} }
} }
}
/* Make sure the grant is valid */ /* Make sure the grant is valid */
if (ret && !srslte_dft_precoding_valid_prb(grant->phy_grant.ul.L_prb) && grant->phy_grant.ul.L_prb <= cell.nof_prb) { if (ret && !srslte_dft_precoding_valid_prb(grant->phy_grant.ul.L_prb) && grant->phy_grant.ul.L_prb <= cell.nof_prb) {
@ -768,11 +798,9 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant)
if (SRSLTE_VERBOSE_ISINFO()) { if (SRSLTE_VERBOSE_ISINFO()) {
srslte_ra_pusch_fprint(stdout, &dci_unpacked, cell.nof_prb); srslte_ra_pusch_fprint(stdout, &dci_unpacked, cell.nof_prb);
} }
return true;
} else {
return false;
} }
return ret;
} }
void phch_worker::reset_uci() void phch_worker::reset_uci()

@ -199,9 +199,10 @@ void phy::set_timeadv_rar(uint32_t ta_cmd) {
} }
void phy::set_timeadv(uint32_t ta_cmd) { void phy::set_timeadv(uint32_t ta_cmd) {
n_ta = srslte_N_ta_new(n_ta, ta_cmd); uint32_t new_nta = srslte_N_ta_new(n_ta, ta_cmd);
sf_recv.set_time_adv_sec(((float) n_ta)*SRSLTE_LTE_TS); sf_recv.set_time_adv_sec(((float) (new_nta - n_ta))*SRSLTE_LTE_TS);
//Warning("Not supported: Set TA: ta_cmd: %d, n_ta: %d, ta_usec: %.1f\n", ta_cmd, n_ta, ((float) n_ta)*SRSLTE_LTE_TS*1e6); Info("PHY: Set TA: ta_cmd: %d, n_ta: %d, old_n_ta: %d, ta_usec: %.1f\n", ta_cmd, new_nta, n_ta, ((float) new_nta)*SRSLTE_LTE_TS*1e6);
n_ta = new_nta;
} }
void phy::configure_prach_params() void phy::configure_prach_params()

@ -32,7 +32,6 @@
#include <string> #include <string>
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
#include <ue_base.h>
using namespace srslte; using namespace srslte;
@ -58,6 +57,7 @@ bool ue::init(all_args_t *args_)
} else { } else {
logger_file.init(args->log.filename); logger_file.init(args->log.filename);
logger_file.log("\n\n"); logger_file.log("\n\n");
logger_file.log(get_build_string().c_str());
logger = &logger_file; logger = &logger_file;
} }
@ -117,6 +117,10 @@ bool ue::init(all_args_t *args_)
// Init layers // Init layers
if (args->rf.rx_gain < 0) {
phy.set_agc_enable(true);
}
// PHY initis in background, start before radio // PHY initis in background, start before radio
args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant; args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant;
phy.init(&radio, &mac, &rrc, phy_log, &args->expert.phy); phy.init(&radio, &mac, &rrc, phy_log, &args->expert.phy);
@ -160,8 +164,6 @@ bool ue::init(all_args_t *args_)
if (args->rf.rx_gain < 0) { if (args->rf.rx_gain < 0) {
radio.start_agc(false); radio.start_agc(false);
radio.set_tx_rx_gain_offset(10);
phy.set_agc_enable(true);
} else { } else {
radio.set_rx_gain(args->rf.rx_gain); radio.set_rx_gain(args->rf.rx_gain);
} }
@ -188,7 +190,12 @@ bool ue::init(all_args_t *args_)
gw.set_netmask(args->expert.ip_netmask); gw.set_netmask(args->expert.ip_netmask);
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()));
// Get current band from provided EARFCN
args->rrc.supported_bands[0] = srslte_band_get_band(args->rf.dl_earfcn);
args->rrc.nof_supported_bands = 1;
args->rrc.ue_category = atoi(args->ue_category_str.c_str());
rrc.set_args(&args->rrc);
// Currently EARFCN list is set to only one frequency as indicated in ue.conf // Currently EARFCN list is set to only one frequency as indicated in ue.conf
std::vector<uint32_t> earfcn_list; std::vector<uint32_t> earfcn_list;

@ -24,13 +24,14 @@
* *
*/ */
#include "ue_base.h" #include "ue_base.h"
#include "ue.h" #include "ue.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include "srslte/build_info.h"
#include <pthread.h> #include <pthread.h>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <sstream>
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
@ -58,6 +59,9 @@ ue_base* ue_base::get_instance(srsue_instance_type_t type)
} }
ue_base::ue_base() { ue_base::ue_base() {
// print build info
std::cout << std::endl << get_build_string() << std::endl;
// load FFTW wisdom // load FFTW wisdom
srslte_dft_load(); srslte_dft_load();
} }
@ -116,4 +120,21 @@ srslte::LOG_LEVEL_ENUM ue_base::level(std::string l)
} }
} }
std::string ue_base::get_build_mode()
{
return std::string(srslte_get_build_mode());
}
std::string ue_base::get_build_info()
{
return std::string(srslte_get_build_info());
}
std::string ue_base::get_build_string()
{
std::stringstream ss;
ss << "Built in " << get_build_mode() << " mode using " << get_build_info() << "." << std::endl;
return ss.str();
}
} // namespace srsue } // namespace srsue

@ -25,6 +25,11 @@
*/ */
#include <unistd.h>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include "srslte/asn1/liblte_rrc.h" #include "srslte/asn1/liblte_rrc.h"
#include "upper/nas.h" #include "upper/nas.h"
#include "srslte/common/bcd_helpers.h" #include "srslte/common/bcd_helpers.h"
@ -33,9 +38,78 @@ using namespace srslte;
namespace srsue { namespace srsue {
/*********************************************************************
* Conversion helpers
********************************************************************/
std::string hex_to_string(uint8_t *hex, int size)
{
std::stringstream ss;
ss << std::hex << std::setfill('0');
for(int i=0; i<size; i++) {
ss << std::setw(2) << static_cast<unsigned>(hex[i]);
}
return ss.str();
}
bool string_to_hex(std::string hex_str, uint8_t *hex, uint32_t len)
{
static const char* const lut = "0123456789abcdef";
uint32_t str_len = hex_str.length();
if(str_len & 1) {
return false; // uneven hex_str length
}
if(str_len > len*2) {
return false; // not enough space in hex buffer
}
for(uint32_t i=0; i<str_len; i+=2)
{
char a = hex_str[i];
const char* p = std::lower_bound(lut, lut + 16, a);
if (*p != a) {
return false; // invalid char
}
char b = hex_str[i+1];
const char* q = std::lower_bound(lut, lut + 16, b);
if (*q != b) {
return false; // invalid char
}
hex[i/2] = ((p - lut) << 4) | (q - lut);
}
return true;
}
std::string emm_info_str(LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT *info)
{
std::stringstream ss;
if(info->full_net_name_present) {
ss << info->full_net_name.name;
}
if(info->short_net_name_present) {
ss << " (" << info->short_net_name.name << ")";
}
if(info->utc_and_local_time_zone_present) {
ss << " " << (int)info->utc_and_local_time_zone.day;
ss << "/" << (int)info->utc_and_local_time_zone.month;
ss << "/" << (int)info->utc_and_local_time_zone.year;
ss << " " << (int)info->utc_and_local_time_zone.hour;
ss << ":" << (int)info->utc_and_local_time_zone.minute;
ss << ":" << (int)info->utc_and_local_time_zone.second;
ss << " TZ:" << (int)info->utc_and_local_time_zone.tz;
}
return ss.str();
}
nas::nas() nas::nas()
: state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), is_guti_set(false), ip_addr(0), eps_bearer_id(0), : state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), have_guti(false), ip_addr(0), eps_bearer_id(0)
count_ul(0), count_dl(0) {} {
ctxt.rx_count = 0;
ctxt.tx_count = 0;
}
void nas::init(usim_interface_nas *usim_, void nas::init(usim_interface_nas *usim_,
rrc_interface_nas *rrc_, rrc_interface_nas *rrc_,
@ -51,15 +125,26 @@ void nas::init(usim_interface_nas *usim_,
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)) { if (!usim->get_home_plmn_id(&home_plmn)) {
nas_log->error("Getting Home PLMN Id from USIM. Defaulting to 001-01\n"); 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_;
if((have_guti = read_guti_file(&guti))) {
if((have_ctxt = read_ctxt_file(&ctxt))) {
usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int,
ctxt.cipher_algo, ctxt.integ_algo);
nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc");
nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int");
}
}
} }
void nas::stop() {} void nas::stop() {
write_ctxt_file(ctxt);
}
emm_state_t nas::get_state() { emm_state_t nas::get_state() {
return state; return state;
@ -207,11 +292,11 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) {
} }
uint32_t nas::get_ul_count() { uint32_t nas::get_ul_count() {
return count_ul; return ctxt.tx_count;
} }
bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) { bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) {
if (is_guti_set) { if (have_guti) {
s_tmsi->mmec = guti.mme_code; s_tmsi->mmec = guti.mme_code;
s_tmsi->m_tmsi = guti.m_tmsi; s_tmsi->m_tmsi = guti.m_tmsi;
return true; return true;
@ -220,11 +305,26 @@ bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) {
} }
} }
bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) {
if(!have_ctxt) {
nas_log->error("K_asme requested before security context established\n");
return false;
}
if(NULL == k_asme_ || n < 32) {
nas_log->error("Invalid parameters to get_k_asme");
return false;
}
memcpy(k_asme_, ctxt.k_asme, 32);
return true;
}
/******************************************************************************* /*******************************************************************************
Security Security
*******************************************************************************/ *******************************************************************************/
void nas::integrity_generate(uint8_t *key_128, void nas::integrity_generate(uint8_t integ_algo,
uint8_t *key_128,
uint32_t count, uint32_t count,
uint8_t rb_id, uint8_t rb_id,
uint8_t direction, uint8_t direction,
@ -269,6 +369,16 @@ void nas::cipher_decrypt() {
} }
bool nas::check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps)
{
for(uint32_t i=0; i<8; i++) {
if(caps->eea[i] != eea_caps[i] || caps->eia[i] != eia_caps[i]) {
return false;
}
}
return true;
}
/******************************************************************************* /*******************************************************************************
Parsers Parsers
@ -289,8 +399,8 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
//FIXME: Handle tai_list //FIXME: Handle tai_list
if (attach_accept.guti_present) { if (attach_accept.guti_present) {
memcpy(&guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); memcpy(&guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT));
is_guti_set = true; have_guti = true;
// TODO: log message to console write_guti_file(guti);
} }
if (attach_accept.lai_present) { if (attach_accept.lai_present) {
} }
@ -358,10 +468,9 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
state = EMM_STATE_REGISTERED; state = EMM_STATE_REGISTERED;
current_plmn = selecting_plmn; current_plmn = selecting_plmn;
count_dl++; ctxt.rx_count++;
// Send EPS bearer context accept and attach complete // Send EPS bearer context accept and attach complete
count_ul++;
act_def_eps_bearer_context_accept.eps_bearer_id = eps_bearer_id; act_def_eps_bearer_context_accept.eps_bearer_id = eps_bearer_id;
act_def_eps_bearer_context_accept.proc_transaction_id = transaction_id; act_def_eps_bearer_context_accept.proc_transaction_id = transaction_id;
act_def_eps_bearer_context_accept.protocol_cnfg_opts_present = false; act_def_eps_bearer_context_accept.protocol_cnfg_opts_present = false;
@ -369,10 +478,11 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
&attach_complete.esm_msg); &attach_complete.esm_msg);
liblte_mme_pack_attach_complete_msg(&attach_complete, liblte_mme_pack_attach_complete_msg(&attach_complete,
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED,
count_ul, ctxt.tx_count,
(LIBLTE_BYTE_MSG_STRUCT *) pdu); (LIBLTE_BYTE_MSG_STRUCT *) pdu);
integrity_generate(&k_nas_int[16], integrity_generate(ctxt.integ_algo,
count_ul, &k_nas_int[16],
ctxt.tx_count,
lcid - 1, lcid - 1,
SECURITY_DIRECTION_UPLINK, SECURITY_DIRECTION_UPLINK,
&pdu->msg[5], &pdu->msg[5],
@ -384,6 +494,7 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->info("Sending Attach Complete\n"); nas_log->info("Sending Attach Complete\n");
rrc->write_sdu(lcid, pdu); rrc->write_sdu(lcid, pdu);
ctxt.tx_count++;
} else { } else {
nas_log->info("Not handling attach type %u\n", attach_accept.eps_attach_result); nas_log->info("Not handling attach type %u\n", attach_accept.eps_attach_result);
@ -407,7 +518,7 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req; LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req;
LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res; LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res;
nas_log->info("Received Authentication Request\n");; nas_log->info("Received Authentication Request\n");
liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req); liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req);
// Reuse the pdu for the response message // Reuse the pdu for the response message
@ -422,7 +533,15 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
bool net_valid; bool net_valid;
uint8_t res[16]; uint8_t res[16];
usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc, &net_valid, res); usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc,
&net_valid, res, ctxt.k_asme);
nas_log->info("Generated k_asme=%s\n", hex_to_string(ctxt.k_asme, 32).c_str());
if(LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE == auth_req.nas_ksi.tsc_flag) {
ctxt.ksi = auth_req.nas_ksi.nas_ksi;
} else {
nas_log->error("NAS mapped security context not currently supported\n");
nas_log->console("Warning: NAS mapped security context not currently supported\n");
}
if (net_valid) { if (net_valid) {
nas_log->info("Network authentication successful\n"); nas_log->info("Network authentication successful\n");
@ -438,9 +557,6 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->console("Warning: Network authentication failure\n"); nas_log->console("Warning: Network authentication failure\n");
pool->deallocate(pdu); pool->deallocate(pdu);
} }
// Reset DL counter (as per 24.301 5.4.3.2)
count_dl = 0;
} }
void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) {
@ -451,47 +567,97 @@ void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) {
} }
void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->error("TODO:parse_identity_request\n"); LIBLTE_MME_ID_REQUEST_MSG_STRUCT id_req;
LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp;
liblte_mme_unpack_identity_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &id_req);
nas_log->info("Received Identity Request. ID type: %d\n", id_req.id_type);
switch(id_req.id_type) {
case LIBLTE_MME_MOBILE_ID_TYPE_IMSI:
id_resp.mobile_id.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMSI;
usim->get_imsi_vec(id_resp.mobile_id.imsi, 15);
break;
case LIBLTE_MME_MOBILE_ID_TYPE_IMEI:
id_resp.mobile_id.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEI;
usim->get_imei_vec(id_resp.mobile_id.imei, 15);
break;
default:
nas_log->error("Unhandled ID type: %d\n");
pool->deallocate(pdu);
return;
}
pdu->reset();
liblte_mme_pack_identity_response_msg(&id_resp, (LIBLTE_BYTE_MSG_STRUCT *) pdu);
rrc->write_sdu(lcid, pdu);
} }
void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu)
bool success; {
LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd; LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd;
LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sec_mode_comp; LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sec_mode_comp;
LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej;
nas_log->info("Received Security Mode Command\n");
liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &sec_mode_cmd); liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &sec_mode_cmd);
nas_log->info("Received Security Mode Command ksi: %d, eea: %s, eia: %s\n",
sec_mode_cmd.nas_ksi.nas_ksi,
ciphering_algorithm_id_text[sec_mode_cmd.selected_nas_sec_algs.type_of_eea],
integrity_algorithm_id_text[sec_mode_cmd.selected_nas_sec_algs.type_of_eia]);
ksi = sec_mode_cmd.nas_ksi.nas_ksi; if(sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE) {
cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eea; nas_log->error("Mapped security context not supported\n");
integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eia; pool->deallocate(pdu);
// FIXME: Handle nonce_ue, nonce_mme return;
// FIXME: Currently only handling ciphering EEA0 (null) and integrity EIA1,EIA2 }
// FIXME: Use selected_nas_sec_algs to choose correct algos
nas_log->debug("Security details: ksi=%d, eea=%s, eia=%s\n", if(sec_mode_cmd.nas_ksi.nas_ksi != ctxt.ksi)
ksi, ciphering_algorithm_id_text[cipher_algo], integrity_algorithm_id_text[integ_algo]); {
nas_log->warning("Sending Security Mode Reject due to key set ID mismatch\n");
send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED);
pool->deallocate(pdu);
return;
}
// MME is setting up security context
// TODO: check nonce (not sent by Amari)
if (CIPHERING_ALGORITHM_ID_EEA0 != cipher_algo || // Check capabilities replay
(INTEGRITY_ALGORITHM_ID_128_EIA2 != integ_algo && if(!check_cap_replay(&sec_mode_cmd.ue_security_cap)) {
INTEGRITY_ALGORITHM_ID_128_EIA1 != integ_algo) ||
sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE) {
sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH;
nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n"); nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n");
success = false; send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH);
} else { pool->deallocate(pdu);
// Generate NAS encryption key and integrity protection key return;
usim->generate_nas_keys(k_nas_enc, k_nas_int, cipher_algo, integ_algo); }
// Reset counterd (as per 24.301 5.4.3.2)
ctxt.rx_count = 0;
ctxt.tx_count = 0;
ctxt.cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eea;
ctxt.integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eia;
// Check capabilities
if(!eea_caps[ctxt.cipher_algo] || !eia_caps[ctxt.integ_algo]) {
nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n");
send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH);
pool->deallocate(pdu);
return;
}
// Generate NAS keys
usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, ctxt.cipher_algo, ctxt.integ_algo);
nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc"); nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc");
nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int"); nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int");
nas_log->debug("Generating integrity check. integ_algo:%d, count_dl:%d, lcid:%d\n",
ctxt.integ_algo, ctxt.rx_count, lcid);
// Check incoming MAC // Check incoming MAC
uint8_t *inMAC = &pdu->msg[1]; uint8_t *inMAC = &pdu->msg[1];
uint8_t genMAC[4]; uint8_t genMAC[4];
integrity_generate(&k_nas_int[16], integrity_generate(ctxt.integ_algo,
count_dl, &k_nas_int[16],
ctxt.rx_count,
lcid - 1, lcid - 1,
SECURITY_DIRECTION_DOWNLINK, SECURITY_DIRECTION_DOWNLINK,
&pdu->msg[5], &pdu->msg[5],
@ -501,6 +667,8 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->info_hex(inMAC, 4, "Incoming PDU MAC:"); nas_log->info_hex(inMAC, 4, "Incoming PDU MAC:");
nas_log->info_hex(genMAC, 4, "Generated PDU MAC:"); nas_log->info_hex(genMAC, 4, "Generated PDU MAC:");
ctxt.rx_count++;
bool match = true; bool match = true;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (inMAC[i] != genMAC[i]) { if (inMAC[i] != genMAC[i]) {
@ -508,10 +676,14 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) {
} }
} }
if(!match) { if(!match) {
sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED;
nas_log->warning("Sending Security Mode Reject due to integrity check failure\n"); nas_log->warning("Sending Security Mode Reject due to integrity check failure\n");
success = false; send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED);
} else { pool->deallocate(pdu);
return;
}
// Take security context into use
have_ctxt = true;
if (sec_mode_cmd.imeisv_req_present && LIBLTE_MME_IMEISV_REQUESTED == sec_mode_cmd.imeisv_req) { if (sec_mode_cmd.imeisv_req_present && LIBLTE_MME_IMEISV_REQUESTED == sec_mode_cmd.imeisv_req) {
sec_mode_comp.imeisv_present = true; sec_mode_comp.imeisv_present = true;
@ -523,35 +695,26 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) {
sec_mode_comp.imeisv_present = false; sec_mode_comp.imeisv_present = false;
} }
// Reuse pdu for response // Send response
pdu->reset(); byte_buffer_t *sdu = pool_allocate;
liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp, liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp,
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED,
count_ul, ctxt.tx_count,
(LIBLTE_BYTE_MSG_STRUCT *) pdu); (LIBLTE_BYTE_MSG_STRUCT *) sdu);
integrity_generate(&k_nas_int[16], integrity_generate(ctxt.integ_algo,
count_ul, &k_nas_int[16],
ctxt.tx_count,
lcid - 1, lcid - 1,
SECURITY_DIRECTION_UPLINK, SECURITY_DIRECTION_UPLINK,
&pdu->msg[5], &sdu->msg[5],
pdu->N_bytes - 5, sdu->N_bytes - 5,
&pdu->msg[1]); &sdu->msg[1]);
nas_log->info("Sending Security Mode Complete nas_count_ul=%d, RB=%s\n", nas_log->info("Sending Security Mode Complete nas_current_ctxt.tx_count=%d, RB=%s\n",
count_ul, ctxt.tx_count,
rrc->get_rb_name(lcid).c_str()); rrc->get_rb_name(lcid).c_str());
success = true; rrc->write_sdu(lcid, sdu);
} ctxt.tx_count++;
} pool->deallocate(pdu);
count_dl++;
if (!success) {
// Reuse pdu for response
pdu->reset();
liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) pdu);
}
rrc->write_sdu(lcid, pdu);
} }
void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) {
@ -560,10 +723,15 @@ void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) {
void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->error("TODO:parse_esm_information_request\n"); nas_log->error("TODO:parse_esm_information_request\n");
} }
void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->error("TODO:parse_emm_information\n"); liblte_mme_unpack_emm_information_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &emm_info);
std::string str = emm_info_str(&emm_info);
nas_log->info("Received EMM Information: %s\n", str.c_str());
nas_log->console("%s\n", str.c_str());
ctxt.rx_count++;
} }
/******************************************************************************* /*******************************************************************************
@ -578,25 +746,13 @@ void nas::send_attach_request() {
attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH; attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH;
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
attach_req.ue_network_cap.eea[i] = false; attach_req.ue_network_cap.eea[i] = eea_caps[i];
attach_req.ue_network_cap.eia[i] = false; attach_req.ue_network_cap.eia[i] = eia_caps[i];
} }
attach_req.ue_network_cap.eea[0] = true; // EEA0 supported
attach_req.ue_network_cap.eia[0] = true; // EIA0 supported
attach_req.ue_network_cap.eia[1] = true; // EIA1 supported
attach_req.ue_network_cap.eia[2] = true; // EIA2 supported
attach_req.ue_network_cap.uea_present = false; // UMTS encryption algos attach_req.ue_network_cap.uea_present = false; // UMTS encryption algos
attach_req.ue_network_cap.uia_present = false; // UMTS integrity algos attach_req.ue_network_cap.uia_present = false; // UMTS integrity algos
attach_req.ms_network_cap_present = false; // A/Gb mode (2G) or Iu mode (3G) attach_req.ms_network_cap_present = false; // A/Gb mode (2G) or Iu mode (3G)
attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI;
usim->get_imsi_vec(attach_req.eps_mobile_id.imsi, 15);
// ESM message (PDN connectivity request) for first default bearer
gen_pdn_connectivity_request(&attach_req.esm_msg);
attach_req.old_p_tmsi_signature_present = false; attach_req.old_p_tmsi_signature_present = false;
attach_req.additional_guti_present = false; attach_req.additional_guti_present = false;
attach_req.last_visited_registered_tai_present = false; attach_req.last_visited_registered_tai_present = false;
@ -612,11 +768,47 @@ void nas::send_attach_request() {
attach_req.device_properties_present = false; attach_req.device_properties_present = false;
attach_req.old_guti_type_present = false; attach_req.old_guti_type_present = false;
// Pack the message // ESM message (PDN connectivity request) for first default bearer
gen_pdn_connectivity_request(&attach_req.esm_msg);
// GUTI or IMSI attach
if(have_guti && have_ctxt) {
attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_GUTI;
memcpy(&attach_req.eps_mobile_id.guti, &guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT));
attach_req.old_guti_type = LIBLTE_MME_GUTI_TYPE_NATIVE;
attach_req.old_guti_type_present = true;
attach_req.nas_ksi.tsc_flag = LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE;
attach_req.nas_ksi.nas_ksi = ctxt.ksi;
nas_log->info("Requesting GUTI attach. "
"m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n",
guti.m_tmsi, guti.mcc, guti.mnc, guti.mme_group_id, guti.mme_code);
liblte_mme_pack_attach_request_msg(&attach_req,
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY,
ctxt.tx_count,
(LIBLTE_BYTE_MSG_STRUCT *) msg);
// Add MAC
integrity_generate(ctxt.integ_algo,
&k_nas_int[16],
ctxt.tx_count,
cfg.lcid-1,
SECURITY_DIRECTION_UPLINK,
&msg->msg[5],
msg->N_bytes - 5,
&msg->msg[1]);
} else {
attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI;
usim->get_imsi_vec(attach_req.eps_mobile_id.imsi, 15);
nas_log->info("Requesting IMSI attach. imsi: %s\n", usim->get_imsi_str());
liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg); liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg);
}
nas_log->info("Sending attach request\n"); nas_log->info("Sending attach request\n");
rrc->write_sdu(cfg.lcid, msg); rrc->write_sdu(cfg.lcid, msg);
if(have_ctxt) {
ctxt.tx_count++;
}
} }
void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) { void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
@ -640,22 +832,31 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
liblte_mme_pack_pdn_connectivity_request_msg(&pdn_con_req, msg); liblte_mme_pack_pdn_connectivity_request_msg(&pdn_con_req, msg);
} }
void nas::send_security_mode_reject(uint8_t cause) {
byte_buffer_t *msg = pool_allocate;
LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej;
sec_mode_rej.emm_cause = cause;
liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) msg);
rrc->write_sdu(cfg.lcid, msg);
}
void nas::send_identity_response() {} void nas::send_identity_response() {}
void nas::send_service_request() { void nas::send_service_request() {
byte_buffer_t *msg = pool_allocate; byte_buffer_t *msg = pool_allocate;
count_ul++;
// Pack the service request message directly // Pack the service request message directly
msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg->N_bytes++; msg->N_bytes++;
msg->msg[1] = (ksi & 0x07) << 5; msg->msg[1] = (ctxt.ksi & 0x07) << 5;
msg->msg[1] |= count_ul & 0x1F; msg->msg[1] |= ctxt.tx_count & 0x1F;
msg->N_bytes++; msg->N_bytes++;
uint8_t mac[4]; uint8_t mac[4];
integrity_generate(&k_nas_int[16], integrity_generate(ctxt.integ_algo,
count_ul, &k_nas_int[16],
ctxt.tx_count,
cfg.lcid-1, cfg.lcid-1,
SECURITY_DIRECTION_UPLINK, SECURITY_DIRECTION_UPLINK,
&msg->msg[0], &msg->msg[0],
@ -668,8 +869,239 @@ void nas::send_service_request() {
msg->N_bytes++; msg->N_bytes++;
nas_log->info("Sending service request\n"); nas_log->info("Sending service request\n");
rrc->write_sdu(cfg.lcid, msg); rrc->write_sdu(cfg.lcid, msg);
ctxt.tx_count++;
} }
void nas::send_esm_information_response() {} void nas::send_esm_information_response() {}
bool nas::read_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT *guti)
{
std::ifstream file;
std::string line;
if (!guti) {
return false;
}
const char *m_tmsi_str = "m_tmsi=";
size_t m_tmsi_str_len = strlen(m_tmsi_str);
const char *mcc_str = "mcc=";
size_t mcc_str_len = strlen(mcc_str);
const char *mnc_str = "mnc=";
size_t mnc_str_len = strlen(mnc_str);
const char *mme_group_id_str = "mme_group_id=";
size_t mme_group_id_str_len = strlen(mme_group_id_str);
const char *mme_code_str = "mme_code=";
size_t mme_code_str_len = strlen(mme_code_str);
file.open(".guti", std::ios::in);
if (file.is_open()) {
bool read_ok = true;
if (std::getline(file, line)) {
if (!line.substr(0,m_tmsi_str_len).compare(m_tmsi_str)) {
guti->m_tmsi = atoi(line.substr(m_tmsi_str_len).c_str());
} else {
read_ok = false;
}
} else {
read_ok = false;
}
if (std::getline(file, line)) {
if (!line.substr(0,mcc_str_len).compare(mcc_str)) {
guti->mcc = atoi(line.substr(mcc_str_len).c_str());
} else {
read_ok = false;
}
} else {
read_ok = false;
}
if (std::getline(file, line)) {
if (!line.substr(0,mnc_str_len).compare(mnc_str)) {
guti->mnc = atoi(line.substr(mnc_str_len).c_str());
} else {
read_ok = false;
}
} else {
read_ok = false;
}
if (std::getline(file, line)) {
if (!line.substr(0,mme_group_id_str_len).compare(mme_group_id_str)) {
guti->mme_group_id = atoi(line.substr(mme_group_id_str_len).c_str());
} else {
read_ok = false;
}
} else {
read_ok = false;
}
if (std::getline(file, line)) {
if (!line.substr(0,mme_code_str_len).compare(mme_code_str)) {
guti->mme_code = atoi(line.substr(mme_code_str_len).c_str());
} else {
read_ok = false;
}
} else {
read_ok = false;
}
file.close();
if (read_ok) {
nas_log->info("Read GUTI from file .guti. "
"m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n",
guti->m_tmsi, guti->mcc, guti->mnc, guti->mme_group_id, guti->mme_code);
return true;
} else {
nas_log->error("Invalid GUTI file format\n");
return false;
}
} else {
return false;
}
}
bool nas::write_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti) {
std::ofstream file;
if (!have_guti) {
return false;
}
file.open(".guti", std::ios::out | std::ios::trunc);
if (file.is_open()) {
file << "m_tmsi=" << (int) guti.m_tmsi << std::endl;
file << "mcc=" << (int) guti.mcc << std::endl;
file << "mnc=" << (int) guti.mnc << std::endl;
file << "mme_group_id=" << (int) guti.mme_group_id << std::endl;
file << "mme_code=" << (int) guti.mme_code << std::endl;
nas_log->info("Saved GUTI to file .guti. "
"m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n",
guti.m_tmsi, guti.mcc, guti.mnc, guti.mme_group_id, guti.mme_code);
file.close();
return true;
} else {
return false;
}
}
bool nas::read_ctxt_file(nas_sec_ctxt *ctxt)
{
std::ifstream file;
std::string line;
if (!ctxt) {
return false;
}
const char *ksi_str = "ksi=";
size_t ksi_str_len = strlen(ksi_str);
const char *k_asme_str = "k_asme=";
size_t k_asme_str_len = strlen(k_asme_str);
const char *tx_count_str = "tx_count=";
size_t tx_count_str_len = strlen(tx_count_str);
const char *rx_count_str = "rx_count=";
size_t rx_count_str_len = strlen(rx_count_str);
const char *int_alg_str = "int_alg=";
size_t int_alg_str_len = strlen(int_alg_str);
const char *enc_alg_str = "enc_alg=";
size_t enc_alg_str_len = strlen(enc_alg_str);
file.open(".ctxt", std::ios::in);
if (file.is_open()) {
bool read_ok = true;
if (std::getline(file, line)) {
if (!line.substr(0,ksi_str_len).compare(ksi_str)) {
ctxt->ksi = atoi(line.substr(ksi_str_len).c_str());
} else {
read_ok = false;
}
} else {
read_ok = false;
}
if (std::getline(file, line)) {
if (!line.substr(0,k_asme_str_len).compare(k_asme_str)) {
std::string tmp = line.substr(k_asme_str_len);
if(!string_to_hex(tmp, ctxt->k_asme, 32)) {
read_ok = false;
}
} else {
read_ok = false;
}
} else {
read_ok = false;
}
if (std::getline(file, line)) {
if (!line.substr(0,tx_count_str_len).compare(tx_count_str)) {
ctxt->tx_count = atoi(line.substr(tx_count_str_len).c_str());
} else {
read_ok = false;
}
} else {
read_ok = false;
}
if (std::getline(file, line)) {
if (!line.substr(0,rx_count_str_len).compare(rx_count_str)) {
ctxt->rx_count = atoi(line.substr(rx_count_str_len).c_str());
} else {
read_ok = false;
}
} else {
read_ok = false;
}
if (std::getline(file, line)) {
if (!line.substr(0,int_alg_str_len).compare(int_alg_str)) {
ctxt->integ_algo = (srslte::INTEGRITY_ALGORITHM_ID_ENUM)atoi(line.substr(int_alg_str_len).c_str());
} else {
read_ok = false;
}
} else {
read_ok = false;
}
if (std::getline(file, line)) {
if (!line.substr(0,enc_alg_str_len).compare(enc_alg_str)) {
ctxt->cipher_algo = (srslte::CIPHERING_ALGORITHM_ID_ENUM)atoi(line.substr(enc_alg_str_len).c_str());
} else {
read_ok = false;
}
} else {
read_ok = false;
}
file.close();
if (read_ok) {
nas_log->info("Read security ctxt from file .ctxt. "
"ksi: %x, k_asme: %s, "
"tx_count: %x, rx_count: %x, "
"int_alg: %d, enc_alg: %d\n",
ctxt->ksi, hex_to_string(ctxt->k_asme,32).c_str(),
ctxt->tx_count, ctxt->rx_count,
ctxt->integ_algo, ctxt->cipher_algo);
return true;
} else {
nas_log->error("Invalid security ctxt file format\n");
return false;
}
} else {
return false;
}
}
bool nas::write_ctxt_file(nas_sec_ctxt ctxt)
{
std::ofstream file;
file.open(".ctxt", std::ios::out | std::ios::trunc);
if (file.is_open()) {
file << "ksi=" << (int) ctxt.ksi << std::endl;
file << "k_asme=" << hex_to_string(ctxt.k_asme, 32) << std::endl;
file << "tx_count=" << (int) ctxt.tx_count << std::endl;
file << "rx_count=" << (int) ctxt.rx_count << std::endl;
file << "int_alg=" << (int) ctxt.integ_algo << std::endl;
file << "enc_alg=" << (int) ctxt.cipher_algo << std::endl;
nas_log->info("Saved security ctxt to file .ctxt. "
"ksi: %x, k_asme: %s, "
"tx_count: %x, rx_count: %x, "
"int_alg: %d, enc_alg: %d\n",
ctxt.ksi, hex_to_string(ctxt.k_asme,32).c_str(),
ctxt.tx_count, ctxt.rx_count,
ctxt.integ_algo, ctxt.cipher_algo);
file.close();
return true;
} else {
return false;
}
}
} // namespace srsue } // namespace srsue

@ -26,12 +26,12 @@
#include <unistd.h> #include <unistd.h>
#include <iostream>
#include <sstream> #include <sstream>
#include "srslte/asn1/liblte_rrc.h" #include <stdlib.h>
#include <time.h>
#include "upper/rrc.h" #include "upper/rrc.h"
#include <boost/assign.hpp> #include "srslte/asn1/liblte_rrc.h"
#include <upper/rrc.h>
#include <srslte/asn1/liblte_rrc.h>
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/common/bcd_helpers.h" #include "srslte/common/bcd_helpers.h"
@ -48,6 +48,9 @@ rrc::rrc()
:state(RRC_STATE_IDLE) :state(RRC_STATE_IDLE)
,drb_up(false) ,drb_up(false)
{ {
sync_reset_cnt = 0;
n310_cnt = 0;
n311_cnt = 0;
} }
static void liblte_rrc_handler(void *ctx, char *str) { static void liblte_rrc_handler(void *ctx, char *str) {
@ -90,9 +93,14 @@ void rrc::init(phy_interface_rrc *phy_,
pthread_mutex_init(&mutex, NULL); pthread_mutex_init(&mutex, NULL);
first_stimsi_attempt = false;
reestablishment_in_progress = false; reestablishment_in_progress = false;
ue_category = SRSLTE_UE_CATEGORY; args.ue_category = SRSLTE_UE_CATEGORY;
args.supported_bands[0] = 7;
args.nof_supported_bands = 1;
args.feature_group = 0xe6041c00;
t301 = mac_timers->timer_get_unique_id(); t301 = mac_timers->timer_get_unique_id();
t310 = mac_timers->timer_get_unique_id(); t310 = mac_timers->timer_get_unique_id();
t311 = mac_timers->timer_get_unique_id(); t311 = mac_timers->timer_get_unique_id();
@ -114,6 +122,8 @@ void rrc::init(phy_interface_rrc *phy_,
set_mac_default(); set_mac_default();
measurements.init(this); measurements.init(this);
// set seed for rand (used in attach)
srand(time(NULL));
} }
void rrc::stop() { void rrc::stop() {
@ -137,12 +147,8 @@ bool rrc::have_drb() {
return drb_up; return drb_up;
} }
void rrc::set_ue_category(int category) { void rrc::set_args(rrc_args_t *args) {
if (category >= 1 && category <= 5) { memcpy(&this->args, args, sizeof(rrc_args_t));
ue_category = category;
} else {
rrc_log->error("Unsupported UE category %d\n", category);
}
} }
/* /*
@ -527,13 +533,17 @@ void rrc::add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp) {
// Detection of physical layer problems (5.3.11.1) // Detection of physical layer problems (5.3.11.1)
void rrc::out_of_sync() { void rrc::out_of_sync() {
// attempt resync
sync_reset_cnt++;
if (sync_reset_cnt >= SYNC_RESET_TIMEOUT) {
rrc_log->info("Detected %d out-of-sync from PHY. Resynchronizing PHY.\n", sync_reset_cnt);
phy->sync_reset();
sync_reset_cnt = 0;
}
current_cell->in_sync = false; current_cell->in_sync = false;
if (!mac_timers->timer_get(t311)->is_running() && !mac_timers->timer_get(t310)->is_running()) { if (!mac_timers->timer_get(t311)->is_running() && !mac_timers->timer_get(t310)->is_running()) {
n310_cnt++; n310_cnt++;
if (n310_cnt == N310) { if (n310_cnt == N310) {
// attempt resync
//phy->sync_reset();
mac_timers->timer_get(t310)->reset(); mac_timers->timer_get(t310)->reset();
mac_timers->timer_get(t310)->run(); mac_timers->timer_get(t310)->run();
n310_cnt = 0; n310_cnt = 0;
@ -632,13 +642,15 @@ void rrc::send_con_request() {
// Prepare ConnectionRequest packet // Prepare ConnectionRequest packet
ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ; ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ;
if (nas->get_s_tmsi(&s_tmsi)) { if (nas->get_s_tmsi(&s_tmsi)) {
ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI; ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI;
ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = s_tmsi; ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = s_tmsi;
} else { } else {
ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE; ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE;
ul_ccch_msg.msg.rrc_con_req.ue_id.random = 1000; ul_ccch_msg.msg.rrc_con_req.ue_id.random = rand() % 2^40;
} }
ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING; ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING;
liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf);
@ -1082,10 +1094,12 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) {
LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi_paged; LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi_paged;
for (uint32_t i = 0; i < pcch_msg.paging_record_list_size; i++) { for (uint32_t i = 0; i < pcch_msg.paging_record_list_size; i++) {
s_tmsi_paged = &pcch_msg.paging_record_list[i].ue_identity.s_tmsi; s_tmsi_paged = &pcch_msg.paging_record_list[i].ue_identity.s_tmsi;
rrc_log->info("Received paging (%d/%d) for UE 0x%x\n", i + 1, pcch_msg.paging_record_list_size, rrc_log->info("Received paging (%d/%d) for UE %x:%x\n", i + 1, pcch_msg.paging_record_list_size,
pcch_msg.paging_record_list[i].ue_identity.s_tmsi); pcch_msg.paging_record_list[i].ue_identity.s_tmsi.mmec,
rrc_log->console("Received paging (%d/%d) for UE 0x%x\n", i + 1, pcch_msg.paging_record_list_size, pcch_msg.paging_record_list[i].ue_identity.s_tmsi.m_tmsi);
pcch_msg.paging_record_list[i].ue_identity.s_tmsi); rrc_log->console("Received paging (%d/%d) for UE %x:%x\n", i + 1, pcch_msg.paging_record_list_size,
pcch_msg.paging_record_list[i].ue_identity.s_tmsi.mmec,
pcch_msg.paging_record_list[i].ue_identity.s_tmsi.m_tmsi);
if (s_tmsi.mmec == s_tmsi_paged->mmec && s_tmsi.m_tmsi == s_tmsi_paged->m_tmsi) { if (s_tmsi.mmec == s_tmsi_paged->mmec && s_tmsi.m_tmsi == s_tmsi_paged->m_tmsi) {
rrc_log->info("S-TMSI match in paging message\n"); rrc_log->info("S-TMSI match in paging message\n");
rrc_log->console("S-TMSI match in paging message\n"); rrc_log->console("S-TMSI match in paging message\n");
@ -1244,7 +1258,9 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) {
integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg; integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg;
// Configure PDCP for security // Configure PDCP for security
usim->generate_as_keys(nas->get_ul_count(), k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); uint8_t k_asme[32];
nas->get_k_asme(k_asme, 32);
usim->generate_as_keys(k_asme, nas->get_ul_count()-1, k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo);
pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo);
send_security_mode_complete(lcid, pdu); send_security_mode_complete(lcid, pdu);
break; break;
@ -1287,7 +1303,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) {
* *
*******************************************************************************/ *******************************************************************************/
void rrc::enable_capabilities() { void rrc::enable_capabilities() {
bool enable_ul_64 = ue_category >= 5 && current_cell->sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam; bool enable_ul_64 = args.ue_category >= 5 && current_cell->sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam;
rrc_log->info("%s 64QAM PUSCH\n", enable_ul_64 ? "Enabling" : "Disabling"); rrc_log->info("%s 64QAM PUSCH\n", enable_ul_64 ? "Enabling" : "Disabling");
phy->set_config_64qam_en(enable_ul_64); phy->set_config_64qam_en(enable_ul_64);
} }
@ -1305,7 +1321,7 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) {
LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *cap = &info->ue_capability_rat[0].eutra_capability; LIBLTE_RRC_UE_EUTRA_CAPABILITY_STRUCT *cap = &info->ue_capability_rat[0].eutra_capability;
cap->access_stratum_release = LIBLTE_RRC_ACCESS_STRATUM_RELEASE_REL8; cap->access_stratum_release = LIBLTE_RRC_ACCESS_STRATUM_RELEASE_REL8;
cap->ue_category = ue_category; cap->ue_category = args.ue_category;
cap->pdcp_params.max_rohc_ctxts_present = false; cap->pdcp_params.max_rohc_ctxts_present = false;
cap->pdcp_params.supported_rohc_profiles[0] = false; cap->pdcp_params.supported_rohc_profiles[0] = false;
@ -1321,31 +1337,17 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) {
cap->phy_params.specific_ref_sigs_supported = false; cap->phy_params.specific_ref_sigs_supported = false;
cap->phy_params.tx_antenna_selection_supported = false; cap->phy_params.tx_antenna_selection_supported = false;
//TODO: Generate this from user input? cap->rf_params.N_supported_band_eutras = args.nof_supported_bands;
cap->rf_params.N_supported_band_eutras = 3; cap->meas_params.N_band_list_eutra = args.nof_supported_bands;
cap->rf_params.supported_band_eutra[0].band_eutra = 3; for (uint32_t i=0;i<args.nof_supported_bands;i++) {
cap->rf_params.supported_band_eutra[0].half_duplex = false; cap->rf_params.supported_band_eutra[i].band_eutra = args.supported_bands[i];
cap->rf_params.supported_band_eutra[1].band_eutra = 7; cap->rf_params.supported_band_eutra[i].half_duplex = false;
cap->rf_params.supported_band_eutra[1].half_duplex = false; cap->meas_params.band_list_eutra[i].N_inter_freq_need_for_gaps = 1;
cap->rf_params.supported_band_eutra[2].band_eutra = 20; cap->meas_params.band_list_eutra[i].inter_freq_need_for_gaps[0] = true;
cap->rf_params.supported_band_eutra[2].half_duplex = false; }
cap->meas_params.N_band_list_eutra = 3;
cap->meas_params.band_list_eutra[0].N_inter_freq_need_for_gaps = 3;
cap->meas_params.band_list_eutra[0].inter_freq_need_for_gaps[0] = true;
cap->meas_params.band_list_eutra[0].inter_freq_need_for_gaps[1] = true;
cap->meas_params.band_list_eutra[0].inter_freq_need_for_gaps[2] = true;
cap->meas_params.band_list_eutra[1].N_inter_freq_need_for_gaps = 3;
cap->meas_params.band_list_eutra[1].inter_freq_need_for_gaps[0] = true;
cap->meas_params.band_list_eutra[1].inter_freq_need_for_gaps[1] = true;
cap->meas_params.band_list_eutra[1].inter_freq_need_for_gaps[2] = true;
cap->meas_params.band_list_eutra[2].N_inter_freq_need_for_gaps = 3;
cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[0] = true;
cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[1] = true;
cap->meas_params.band_list_eutra[2].inter_freq_need_for_gaps[2] = true;
cap->feature_group_indicator_present = true; cap->feature_group_indicator_present = true;
cap->feature_group_indicator = 0x62001000; cap->feature_group_indicator = args.feature_group;
cap->inter_rat_params.utra_fdd_present = false; cap->inter_rat_params.utra_fdd_present = false;
cap->inter_rat_params.utra_tdd128_present = false; cap->inter_rat_params.utra_tdd128_present = false;
cap->inter_rat_params.utra_tdd384_present = false; cap->inter_rat_params.utra_tdd384_present = false;
@ -1607,8 +1609,10 @@ void rrc::apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT
} }
if (phy_cnfg->pdsch_cnfg_ded_present) { if (phy_cnfg->pdsch_cnfg_ded_present) {
current_cfg->pdsch_cnfg_ded = phy_cnfg->pdsch_cnfg_ded; current_cfg->pdsch_cnfg_ded = phy_cnfg->pdsch_cnfg_ded;
rrc_log->info("Set PDSCH-Config=%s (present)\n", liblte_rrc_pdsch_config_p_a_text[(int) current_cfg->pdsch_cnfg_ded]);
} else if (apply_defaults) { } else if (apply_defaults) {
current_cfg->pdsch_cnfg_ded = LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_0; current_cfg->pdsch_cnfg_ded = LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_0;
rrc_log->info("Set PDSCH-Config=%s (default)\n", liblte_rrc_pdsch_config_p_a_text[(int) current_cfg->pdsch_cnfg_ded]);
} }
if (phy_cnfg->cqi_report_cnfg_present) { if (phy_cnfg->cqi_report_cnfg_present) {

@ -39,9 +39,11 @@ 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_)
{ {
usim_log = usim_log_; usim_log = usim_log_;
imsi_str = args->imsi;
imei_str = args->imei;
const char *imsi_str = args->imsi.c_str(); const char *imsi_c = args->imsi.c_str();
const char *imei_str = args->imei.c_str(); const char *imei_c = args->imei.c_str();
uint32_t i; uint32_t i;
if(32 == args->op.length()) { if(32 == args->op.length()) {
@ -63,7 +65,7 @@ void usim::init(usim_args_t *args, srslte::log *usim_log_)
for(i=0; i<15; i++) for(i=0; i<15; i++)
{ {
imsi *= 10; imsi *= 10;
imsi += imsi_str[i] - '0'; imsi += imsi_c[i] - '0';
} }
} else { } else {
usim_log->error("Invalid length for ISMI: %d should be %d", args->imsi.length(), 15); usim_log->error("Invalid length for ISMI: %d should be %d", args->imsi.length(), 15);
@ -75,7 +77,7 @@ void usim::init(usim_args_t *args, srslte::log *usim_log_)
for(i=0; i<15; i++) for(i=0; i<15; i++)
{ {
imei *= 10; imei *= 10;
imei += imei_str[i] - '0'; imei += imei_c[i] - '0';
} }
} else { } else {
usim_log->error("Invalid length for IMEI: %d should be %d", args->imei.length(), 15); usim_log->error("Invalid length for IMEI: %d should be %d", args->imei.length(), 15);
@ -103,16 +105,25 @@ void usim::stop()
NAS interface NAS interface
*******************************************************************************/ *******************************************************************************/
void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) std::string usim::get_imsi_str()
{
return imsi_str;
}
std::string usim::get_imei_str()
{
return imei_str;
}
bool usim::get_imsi_vec(uint8_t* imsi_, uint32_t n)
{ {
if (!initiated) { if (!initiated) {
fprintf(stderr, "USIM not initiated!\n"); fprintf(stderr, "USIM not initiated!\n");
return; return false;
} }
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");
return; return false;
} }
uint64_t temp = imsi; uint64_t temp = imsi;
@ -120,18 +131,19 @@ void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n)
imsi_[i] = temp % 10; imsi_[i] = temp % 10;
temp /= 10; temp /= 10;
} }
return true;
} }
void usim::get_imei_vec(uint8_t* imei_, uint32_t n) bool usim::get_imei_vec(uint8_t* imei_, uint32_t n)
{ {
if (!initiated) { if (!initiated) {
fprintf(stderr, "USIM not initiated!\n"); fprintf(stderr, "USIM not initiated!\n");
return; return false;
} }
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");
return; return false;
} }
uint64 temp = imei; uint64 temp = imei;
@ -140,13 +152,14 @@ void usim::get_imei_vec(uint8_t* imei_, uint32_t n)
imei_[i] = temp % 10; imei_[i] = temp % 10;
temp /= 10; temp /= 10;
} }
return true;
} }
int usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) bool usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id)
{ {
if (!initiated) { if (!initiated) {
fprintf(stderr, "USIM not initiated!\n"); fprintf(stderr, "USIM not initiated!\n");
return -1; return false;
} }
int mcc_len = 3; int mcc_len = 3;
@ -180,7 +193,7 @@ int usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id)
usim_log->info("Read Home PLMN Id=%s\n", usim_log->info("Read Home PLMN Id=%s\n",
plmn_id_to_string(*home_plmn_id).c_str()); plmn_id_to_string(*home_plmn_id).c_str());
return 0; return true;
} }
void usim::generate_authentication_response(uint8_t *rand, void usim::generate_authentication_response(uint8_t *rand,
@ -188,16 +201,18 @@ void usim::generate_authentication_response(uint8_t *rand,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid, bool *net_valid,
uint8_t *res) uint8_t *res,
uint8_t *k_asme)
{ {
if(auth_algo_xor == auth_algo) { if(auth_algo_xor == auth_algo) {
gen_auth_res_xor(rand, autn_enb, mcc, mnc, net_valid, res); gen_auth_res_xor(rand, autn_enb, mcc, mnc, net_valid, res, k_asme);
} else { } else {
gen_auth_res_milenage(rand, autn_enb, mcc, mnc, net_valid, res); gen_auth_res_milenage(rand, autn_enb, mcc, mnc, net_valid, res, k_asme);
} }
} }
void usim::generate_nas_keys(uint8_t *k_nas_enc, void usim::generate_nas_keys(uint8_t *k_asme,
uint8_t *k_nas_enc,
uint8_t *k_nas_int, uint8_t *k_nas_int,
CIPHERING_ALGORITHM_ID_ENUM cipher_algo, CIPHERING_ALGORITHM_ID_ENUM cipher_algo,
INTEGRITY_ALGORITHM_ID_ENUM integ_algo) INTEGRITY_ALGORITHM_ID_ENUM integ_algo)
@ -214,7 +229,8 @@ void usim::generate_nas_keys(uint8_t *k_nas_enc,
RRC interface RRC interface
*******************************************************************************/ *******************************************************************************/
void usim::generate_as_keys(uint32_t count_ul, void usim::generate_as_keys(uint8_t *k_asme,
uint32_t count_ul,
uint8_t *k_rrc_enc, uint8_t *k_rrc_enc,
uint8_t *k_rrc_int, uint8_t *k_rrc_int,
uint8_t *k_up_enc, uint8_t *k_up_enc,
@ -285,7 +301,8 @@ void usim::gen_auth_res_milenage( uint8_t *rand,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid, bool *net_valid,
uint8_t *res) uint8_t *res,
uint8_t *k_asme)
{ {
uint32_t i; uint32_t i;
uint8_t sqn[6]; uint8_t sqn[6];
@ -354,7 +371,8 @@ void usim::gen_auth_res_xor(uint8_t *rand,
uint16_t mcc, uint16_t mcc,
uint16_t mnc, uint16_t mnc,
bool *net_valid, bool *net_valid,
uint8_t *res) uint8_t *res,
uint8_t *k_asme)
{ {
uint32_t i; uint32_t i;
uint8_t sqn[6]; uint8_t sqn[6];

@ -61,6 +61,7 @@ KASME : a8.27.57.5e.ea.1a.10.17.3a.a1.bf.ce.4b.0c.21.85.e0.51.ef.bd.91.7f.fe.f
uint8_t rand_enb[] = {0x88, 0x38, 0xc3, 0x55, 0xc8, 0x78, 0xaa, 0x57, 0x21, 0x49, 0xfe, 0x69, 0xdb, 0x68, 0x6b, 0x5a}; uint8_t rand_enb[] = {0x88, 0x38, 0xc3, 0x55, 0xc8, 0x78, 0xaa, 0x57, 0x21, 0x49, 0xfe, 0x69, 0xdb, 0x68, 0x6b, 0x5a};
uint8_t autn_enb[] = {0xd7, 0x44, 0x51, 0x9b, 0x25, 0xaa, 0x80, 0x00, 0x84, 0xba, 0x37, 0xb0, 0xf6, 0x73, 0x4d, 0xd1}; uint8_t autn_enb[] = {0xd7, 0x44, 0x51, 0x9b, 0x25, 0xaa, 0x80, 0x00, 0x84, 0xba, 0x37, 0xb0, 0xf6, 0x73, 0x4d, 0xd1};
uint8_t kasme[] = {0xa8, 0x27, 0x57, 0x5e, 0xea, 0x1a, 0x10, 0x17, 0x3a, 0xa1, 0xbf, 0xce, 0x4b, 0x0c, 0x21, 0x85, 0xe0, 0x51, 0xef, 0xbd, 0x91, 0x7f, 0xfe, 0xf5, 0x1f, 0x74, 0x29, 0x61, 0xf9, 0x03, 0x7a, 0x35};
uint16 mcc = 208; uint16 mcc = 208;
uint16 mnc = 93; uint16 mnc = 93;
@ -74,14 +75,14 @@ int main(int argc, char **argv)
usim_args_t args; usim_args_t args;
args.algo = "milenage"; args.algo = "milenage";
args.amf = "8000"; args.amf = "8000";
args.imei = "35609204079301"; args.imei = "356092040793011";
args.imsi = "208930000000001"; args.imsi = "208930000000001";
args.k = "8BAF473F2F8FD09487CCCBD7097C6862"; args.k = "8BAF473F2F8FD09487CCCBD7097C6862";
args.op = "11111111111111111111111111111111"; args.op = "11111111111111111111111111111111";
srsue::usim usim; srsue::usim usim;
usim.init(&args, &usim_log); usim.init(&args, &usim_log);
usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, &net_valid, res); usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, &net_valid, res, kasme);
assert(net_valid == true); assert(net_valid == true);
} }

@ -92,18 +92,35 @@ k = 00112233445566778899aabbccddeeff
imsi = 001010123456789 imsi = 001010123456789
imei = 353490069873319 imei = 353490069873319
#####################################################################
# RRC configuration
#
# stimsi_attach: If enabled, always tries first an S-TMSI attach using the
# S-TMSI value stored in .stimsi file generated in previous run
# mmec_value: If defined (non-zero), overwrites the value stored in .stimsi file
# m_tmsi_value: If defined (non-zero), overwrites the value stored in .stimsi file
#
# ue_category: Sets UE category (range 1-5). Default: 4
# feature_group: Hex value of the featureGroupIndicators field in the
# UECapabilityInformation message. Default 0xe6041c00
#####################################################################
[rrc]
#stmsi_attach = false
#mmec_value = 0
#mtmsi_value = 0
#ue_category = 4
#feature_group = 0xe6041c00
[gui] [gui]
enable = false enable = false
##################################################################### #####################################################################
# Expert configuration options # Expert configuration options
# #
# ue_category: Sets UE category (range 1-5). Default: 4
# ip_netmask: Netmask of the tun_srsue device. Default: 255.255.255.0 # ip_netmask: Netmask of the tun_srsue device. Default: 255.255.255.0
# rssi_sensor_enabled: Enable or disable RF frontend RSSI sensor. Required for RSRP metrics but # rssi_sensor_enabled: Enable or disable RF frontend RSSI sensor. Required for RSRP metrics but
# can cause UHD instability for long-duration testing. Default true. # can cause UHD instability for long-duration testing. Default true.
# ue_category: Sets UE category (range 1-5). Default: 4
#
# prach_gain: PRACH gain (dB). If defined, forces a gain for the tranmsission of PRACH only., # prach_gain: PRACH gain (dB). If defined, forces a gain for the tranmsission of PRACH only.,
# Default is to use tx_gain in [rf] section. # Default is to use tx_gain in [rf] section.
# cqi_max: Upper bound on the maximum CQI to be reported. Default 15. # cqi_max: Upper bound on the maximum CQI to be reported. Default 15.
@ -146,7 +163,6 @@ enable = false
[expert] [expert]
#ip_netmask = 255.255.255.0 #ip_netmask = 255.255.255.0
#rssi_sensor_enabled = false #rssi_sensor_enabled = false
#ue_category = 4
#prach_gain = 30 #prach_gain = 30
#cqi_max = 15 #cqi_max = 15
#cqi_fixed = 10 #cqi_fixed = 10
@ -156,7 +172,7 @@ enable = false
#attach_enable_64qam = false #attach_enable_64qam = false
#nof_phy_threads = 2 #nof_phy_threads = 2
#equalizer_mode = mmse #equalizer_mode = mmse
#cfo_ema = 0.4 #cfo_ema = 0.3
#cfo_integer_enabled = false #cfo_integer_enabled = false
#cfo_correct_tol_hz = 50 #cfo_correct_tol_hz = 50
#time_correct_period = 5 #time_correct_period = 5

Loading…
Cancel
Save