diff --git a/CMakeLists.txt b/CMakeLists.txt index 73b38ceb1..fe2d99690 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,12 @@ if(NOT CMAKE_BUILD_TYPE) endif(NOT CMAKE_BUILD_TYPE) 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 ######################################################################## diff --git a/cmake/modules/SRSLTEbuildinfo.cmake.in b/cmake/modules/SRSLTEbuildinfo.cmake.in new file mode 100644 index 000000000..d8715afbc --- /dev/null +++ b/cmake/modules/SRSLTEbuildinfo.cmake.in @@ -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 +) diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index 1fc5e1640..333e9aaa4 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -163,6 +163,8 @@ int main(int argc, char **argv) { float cfo = 0; bool acks[SRSLTE_MAX_CODEWORDS] = {false}; + srslte_debug_handle_crash(argc, argv); + if (parse_args(&prog_args, argc, argv)) { exit(-1); } diff --git a/lib/examples/cell_search.c b/lib/examples/cell_search.c index e7740d892..17e75369f 100644 --- a/lib/examples/cell_search.c +++ b/lib/examples/cell_search.c @@ -153,6 +153,8 @@ int main(int argc, char **argv) { uint32_t freq; uint32_t n_found_cells=0; + srslte_debug_handle_crash(argc, argv); + parse_args(argc, argv); printf("Opening RF device...\n"); diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index 1d807973c..fa5483003 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -701,6 +701,8 @@ int main(int argc, char **argv) { srslte_refsignal_t csr_refs; srslte_refsignal_t mbsfn_refs; + srslte_debug_handle_crash(argc, argv); + #ifdef DISABLE_RF if (argc < 3) { usage(argv[0]); diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index ecff9267f..a655e090c 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -326,7 +326,8 @@ srslte_netsink_t net_sink, net_sink_signal; #define PRINT_LINE_ADVANCE_CURSOR() printf("\033[%dB", prev_nof_lines + 1) int main(int argc, char **argv) { - int ret; + struct timeval t[3]; + int ret; int decimate = 1; srslte_cell_t cell; int64_t sf_cnt; @@ -340,6 +341,8 @@ int main(int argc, char **argv) { int sfn_offset; float cfo = 0; + srslte_debug_handle_crash(argc, argv); + parse_args(&prog_args, argc, argv); for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) { @@ -559,7 +562,7 @@ int main(int argc, char **argv) { // Variables for measurements uint32_t nframes=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; bool decode_pdsch = false; @@ -655,6 +658,7 @@ int main(int argc, char **argv) { decode_pdsch = false; } } + gettimeofday(&t[1], NULL); if (decode_pdsch) { if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe if (cell.nof_ports == 1) { @@ -690,6 +694,8 @@ int main(int argc, char **argv) { INFO("mbsfn PDU size is %d\n", n); } } + gettimeofday(&t[2], NULL); + get_time_interval(t); if (n < 0) { // fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); } else if (n > 0) { @@ -723,16 +729,19 @@ 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); 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); 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); - 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); - + enodebrate = SRSLTE_VEC_EMA(nof_bits/1000.0f, enodebrate, 0.05f); + 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++; 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(" 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(" 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(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pdsch_pkt_errors / ue_dl.pdsch_pkts_total); if(prog_args.mbsfn_area_id > -1){ diff --git a/lib/include/srslte/asn1/liblte_mme.h b/lib/include/srslte/asn1/liblte_mme.h index 15799f7ca..977f309ce 100644 --- a/lib/include/srslte/asn1/liblte_mme.h +++ b/lib/include/srslte/asn1/liblte_mme.h @@ -2721,6 +2721,10 @@ typedef struct{ // Functions LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req, 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_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req); diff --git a/lib/include/srslte/asn1/liblte_rrc.h b/lib/include/srslte/asn1/liblte_rrc.h index cd0c3f087..e0fb43aef 100644 --- a/lib/include/srslte/asn1/liblte_rrc.h +++ b/lib/include/srslte/asn1/liblte_rrc.h @@ -3930,7 +3930,7 @@ typedef 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", "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 // PDSCH Config Common struct defined above // Functions diff --git a/lib/include/srslte/build_info.h.in b/lib/include/srslte/build_info.h.in new file mode 100644 index 000000000..a8acb306b --- /dev/null +++ b/lib/include/srslte/build_info.h.in @@ -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_ diff --git a/lib/include/srslte/common/buffer_pool.h b/lib/include/srslte/common/buffer_pool.h index 1c6dfc53a..567203c75 100644 --- a/lib/include/srslte/common/buffer_pool.h +++ b/lib/include/srslte/common/buffer_pool.h @@ -123,8 +123,6 @@ public: used.erase(elem); available.push(b); ret = true; - } else { - printf("Error deallocating from buffer pool: buffer not created in this pool.\n"); } pthread_mutex_unlock(&mutex); return ret; diff --git a/lib/include/srslte/common/common.h b/lib/include/srslte/common/common.h index 6372af73e..41a89fb36 100644 --- a/lib/include/srslte/common/common.h +++ b/lib/include/srslte/common/common.h @@ -46,9 +46,12 @@ #define HARQ_DELAY_MS 4 #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_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(tti) (tti%TTIMOD_SZ) diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index df2d74c33..294606bb5 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -52,16 +52,20 @@ class ue_interface class usim_interface_nas { public: - virtual void get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; - virtual void get_imei_vec(uint8_t* imei_, uint32_t n) = 0; - virtual int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0; + virtual std::string get_imsi_str() = 0; + virtual std::string get_imei_str() = 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, uint8_t *autn_enb, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res) = 0; - virtual void generate_nas_keys(uint8_t *k_nas_enc, + uint8_t *res, + uint8_t *k_asme) = 0; + virtual void generate_nas_keys(uint8_t *k_asme, + uint8_t *k_nas_enc, uint8_t *k_nas_int, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; @@ -71,7 +75,8 @@ public: class usim_interface_rrc { 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_int, uint8_t *k_up_enc, @@ -112,6 +117,7 @@ public: virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; virtual uint32_t get_ul_count() = 0; virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0; + virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0; virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0; virtual void plmn_search_end() = 0; }; diff --git a/lib/include/srslte/phy/mimo/precoding.h b/lib/include/srslte/phy/mimo/precoding.h index 58fe22a40..f8463d1cb 100644 --- a/lib/include/srslte/phy/mimo/precoding.h +++ b/lib/include/srslte/phy/mimo/precoding.h @@ -49,18 +49,21 @@ */ SRSLTE_API int srslte_precoding_single(cf_t *x, cf_t *y, - int nof_symbols); + int nof_symbols, + float scaling); SRSLTE_API 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); SRSLTE_API 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 nof_symbols, + float scaling); SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], 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 codebook_idx, int nof_symbols, + float scaling, srslte_mimo_type_t type); /* 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 *x, int nof_symbols, + float scaling, float noise_estimate); SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], @@ -83,42 +88,37 @@ SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, + float scaling, float noise_estimate); SRSLTE_API 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_symbols, + float scaling); SRSLTE_API 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); - -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, - srslte_mimo_type_t type, - float noise_estimate); + int nof_symbols, + float scaling); 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], - 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, - srslte_mimo_type_t type, - float noise_estimate); +SRSLTE_API int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], + cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], + int nof_rxant, + int nof_ports, + int nof_layers, + int codebook_idx, + int nof_symbols, + srslte_mimo_type_t type, + float scaling, + float noise_estimate); SRSLTE_API int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index 459bcc209..dab900d77 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -65,6 +65,9 @@ typedef struct SRSLTE_API { uint16_t ue_rnti; bool is_ue; + /* Power allocation parameter 3GPP 36.213 Clause 5.2 Rho_b */ + float rho_a; + /* buffers */ // void buffers are shared for tx and rx 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, 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, uint16_t rnti); diff --git a/lib/include/srslte/phy/phch/pdsch_cfg.h b/lib/include/srslte/phy/phch/pdsch_cfg.h index 63b3fefcc..569d1ef7e 100644 --- a/lib/include/srslte/phy/phch/pdsch_cfg.h +++ b/lib/include/srslte/phy/phch/pdsch_cfg.h @@ -39,6 +39,13 @@ #include "srslte/phy/fec/softbuffer.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 { srslte_cbsegm_t cb_segm[SRSLTE_MAX_CODEWORDS]; srslte_ra_dl_grant_t grant; diff --git a/lib/include/srslte/phy/resampling/resample_arb.h b/lib/include/srslte/phy/resampling/resample_arb.h index 98d004b0b..4ebb8dc08 100644 --- a/lib/include/srslte/phy/resampling/resample_arb.h +++ b/lib/include/srslte/phy/resampling/resample_arb.h @@ -38,10 +38,13 @@ #define RESAMPLE_ARB_ #include +#include #include #include "srslte/config.h" + +#define SRSLTE_RESAMPLE_ARB_N_35 35 #define SRSLTE_RESAMPLE_ARB_N 32 // Polyphase filter rows #define SRSLTE_RESAMPLE_ARB_M 8 // Polyphase filter columns @@ -49,11 +52,13 @@ typedef struct SRSLTE_API { float rate; // Resample rate float step; // Step increment through filter float acc; // Index into filter + bool interpolate; cf_t reg[SRSLTE_RESAMPLE_ARB_M]; // Our window of samples + } srslte_resample_arb_t; 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, cf_t *input, diff --git a/lib/include/srslte/phy/sync/sync.h b/lib/include/srslte/phy/sync/sync.h index 1c70b2449..135a19160 100644 --- a/lib/include/srslte/phy/sync/sync.h +++ b/lib/include/srslte/phy/sync/sync.h @@ -139,6 +139,10 @@ SRSLTE_API srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, uint32_t find_offset, 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 */ SRSLTE_API srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, cf_t *input, diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 0486ad7d4..a60761a37 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -104,6 +104,9 @@ typedef struct SRSLTE_API { uint32_t pmi[SRSLTE_MAX_LAYERS]; uint32_t ri; + /* Power allocation parameter 3GPP 36.213 Clause 5.2 Rho_b */ + float rho_b; + srslte_dci_format_t dci_format; uint64_t pkt_errors; 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, 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, diff --git a/lib/include/srslte/phy/ue/ue_sync.h b/lib/include/srslte/phy/ue/ue_sync.h index e5877dd23..0d12f846c 100644 --- a/lib/include/srslte/phy/ue/ue_sync.h +++ b/lib/include/srslte/phy/ue/ue_sync.h @@ -88,7 +88,12 @@ typedef struct SRSLTE_API { bool file_mode; float file_cfo; 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; uint32_t frame_len; diff --git a/lib/include/srslte/phy/utils/debug.h b/lib/include/srslte/phy/utils/debug.h index c88e1a3ce..11c7a23df 100644 --- a/lib/include/srslte/phy/utils/debug.h +++ b/lib/include/srslte/phy/utils/debug.h @@ -70,4 +70,6 @@ SRSLTE_API extern int srslte_verbose; #define ERROR(_fmt, ...) fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__) #endif /* CMAKE_BUILD_TYPE==Debug */ +void srslte_debug_handle_crash(int argc, char **argv); + #endif // DEBUG_H diff --git a/lib/include/srslte/phy/utils/simd.h b/lib/include/srslte/phy/utils/simd.h index 09e9cff8e..a9a79c486 100644 --- a/lib/include/srslte/phy/utils/simd.h +++ b/lib/include/srslte/phy/utils/simd.h @@ -449,7 +449,12 @@ static inline simd_f_t srslte_simd_f_sqrt(simd_f_t a) { #ifdef HAVE_NEON float32x4_t sqrt_reciprocal = vrsqrteq_f32(a); 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 /* LV_HAVE_SSE */ #endif /* LV_HAVE_AVX2 */ diff --git a/lib/src/asn1/liblte_mme.cc b/lib/src/asn1/liblte_mme.cc index 4447b001f..215ffd838 100644 --- a/lib/src/asn1/liblte_mme.cc +++ b/lib/src/asn1/liblte_mme.cc @@ -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 += 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 = eps_mobile_id->guti.mme_group_id & 0x0F; + **ie_ptr = eps_mobile_id->guti.mme_group_id & 0xFF; *ie_ptr += 1; **ie_ptr = eps_mobile_id->guti.mme_code; *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_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; 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 && 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 *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; diff --git a/lib/src/common/CMakeLists.txt b/lib/src/common/CMakeLists.txt index 723085e24..010f8f730 100644 --- a/lib/src/common/CMakeLists.txt +++ b/lib/src/common/CMakeLists.txt @@ -22,7 +22,9 @@ file(GLOB CXX_SOURCES "*.cc") file(GLOB C_SOURCES "*.c") 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_link_libraries(srslte_common ${SEC_LIBRARIES}) install(TARGETS srslte_common DESTINATION ${LIBRARY_DIR}) - diff --git a/lib/src/phy/agc/agc.c b/lib/src/phy/agc/agc.c index 3134de729..42a6ef09d 100644 --- a/lib/src/phy/agc/agc.c +++ b/lib/src/phy/agc/agc.c @@ -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) { if (!q->lock) { 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 y = 0; // Apply current gain to input signal @@ -125,12 +125,12 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { srslte_vec_sc_prod_cfc(signal, q->gain, signal, len); } else { if (gain_db < 0) { - gain_db = 0.0; + gain_db = 5.0; } if (isinf(gain_db) || isnan(gain_db)) { - gain_db = 10.0; + gain_db = 40.0; } 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); } } @@ -166,7 +166,7 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { } } - double gg = 1.0; + double gg = 1.0; if (q->isfirst) { q->y_out = y; q->isfirst = false; @@ -177,7 +177,7 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { gg = expf(-0.5*q->bandwidth*logf(q->y_out/q->target)); q->gain *= gg; } - DEBUG("AGC gain: %.2f (%.2f) y_out=%.3f, y=%.3f target=%.1f gg=%.2f\n", gain_db, gain_uhd_db, q->y_out, y, q->target, gg); + DEBUG("AGC gain: %.2f (%.2f) y_out=%.3f, y=%.3f target=%.1f gg=%.2f\n", gain_db, gain_uhd_db, q->y_out, y, q->target, gg); } } } diff --git a/lib/src/phy/ch_estimation/test/chest_test_dl.c b/lib/src/phy/ch_estimation/test/chest_test_dl.c index 0f5a6d6ea..62f7e1c86 100644 --- a/lib/src/phy/ch_estimation/test/chest_test_dl.c +++ b/lib/src/phy/ch_estimation/test/chest_test_dl.c @@ -173,7 +173,7 @@ int main(int argc, char **argv) { gettimeofday(&t[1], NULL); for (int j=0;j<100;j++) { - srslte_predecoding_single(input, ce, output, num_re, 0); + srslte_predecoding_single(input, ce, output, num_re, 1.0f, 0); } gettimeofday(&t[2], NULL); get_time_interval(t); @@ -188,7 +188,7 @@ int main(int argc, char **argv) { gettimeofday(&t[1], NULL); for (int j=0;j<100;j++) { - srslte_predecoding_single(input, ce, output, num_re, 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); get_time_interval(t); diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index 5d96bed27..31ba2ca0a 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -37,13 +37,13 @@ #ifdef LV_HAVE_SSE #include -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_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_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, float scaling); #endif #ifdef LV_HAVE_AVX #include -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 #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))) -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; const float *hPtr1 = (const float*) h[0]; @@ -122,7 +122,10 @@ int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ x1Val1 = _mm_div_ps(x1Val1, h1square); 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, 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]); hh += conj(h[p][i])*h[p][i]; } - x[i] = r/(hh+noise_estimate); + x[i] = scaling*r/(hh+noise_estimate); } 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; 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 h1Val1, h2Val1, y1Val1, y2Val1, h12square, h1square, h2square, h1_p, h2_p, h1conj1, h2conj1, x1Val, x2Val; __m256 h1Val2, h2Val2, y1Val2, y2Val2, h1conj2, h2conj2; + __m256 avx_scaling = _mm256_set1_ps(1/scaling); + for (int i=0;i 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 { - 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 #ifdef LV_HAVE_SSE 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 { - 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 - 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 } /* 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 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 { - 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 #ifdef LV_HAVE_SSE 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 { - 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 - 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 } @@ -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 */ 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], - 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; 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)); x1 += (-h10 * conj(r0) + conj(h01) * r1); } + hh *= scaling; x[0][i] = x0 / 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)); x3 += (-h3 * conjf(r2) + conjf(h1) * r3); } + + hh02 *= scaling; + hh13 *= scaling; + x[0][i] = x0 / hh02 * sqrt(2); x[1][i] = x1 / hh02 * 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], cf_t *x[SRSLTE_MAX_LAYERS], - int nof_rxant, int nof_ports, int nof_symbols) { - return srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, nof_ports, nof_symbols, 0); + 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, scaling); } /* SSE implementation of the 2-port SFBC equalizer */ #ifdef LV_HAVE_SSE 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 nof_rxant, int nof_symbols, float scaling) { float *x0Ptr = (float*) x[0]; 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]; __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_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; } // 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; } #endif 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 *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 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 { - 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 - 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 } 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 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 { - 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 - 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 } - -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 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) { switch (mimo_decoder) { 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; 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; } } else { @@ -1451,7 +1452,7 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ return -1; case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: if (nof_ports == 1 && nof_layers == 1) { - return srslte_predecoding_single_multi(y, h[0], x[0], nof_rxant, nof_symbols, noise_estimate); + return srslte_predecoding_single_multi(y, h[0], x[0], nof_rxant, nof_symbols, scaling, noise_estimate); } else { fprintf(stderr, "Number of ports and layers must be 1 for transmission on single antenna ports (%d, %d)\n", nof_ports, nof_layers); @@ -1460,7 +1461,7 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ break; case SRSLTE_MIMO_TYPE_TX_DIVERSITY: 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 { fprintf(stderr, "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; case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: return srslte_predecoding_multiplex(y, h, x, nof_rxant, nof_ports, nof_layers, codebook_idx, nof_symbols, - noise_estimate); + scaling, noise_estimate); default: 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) { - memcpy(y, x, nof_symbols * sizeof(cf_t)); +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)); + } else { + srslte_vec_sc_prod_cfc(x, scaling, y, (uint32_t) 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 nof_symbols) { + int nof_symbols, float scaling) { int i; if (nof_ports == 2) { 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]); } // normalize - srslte_vec_sc_prod_cfc(y[0], 1.0/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[0], scaling/sqrtf(2), y[0], 2*nof_symbols); + srslte_vec_sc_prod_cfc(y[1], scaling/sqrtf(2), y[1], 2*nof_symbols); return 2 * i; } else if (nof_ports == 4) { + scaling /= sqrtf(2); + //int m_ap = (nof_symbols%4)?(nof_symbols*4-2):nof_symbols*4; int m_ap = 4 * nof_symbols; 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[2][4 * i] = -conjf(x[1][i]) / sqrtf(2); + y[2][4 * i] = -conjf(x[1][i]) * scaling; 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[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[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[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[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[3][4 * i + 3] = conjf(x[2][i]) / sqrtf(2); + y[3][4 * i + 3] = conjf(x[2][i]) * scaling; } return 4 * i; } 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 -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) { __m256 x0 = _mm256_load_ps((float*) &x[0][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 -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) { __m128 x0 = _mm_load_ps((float*) &x[0][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 */ -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++) { - y[0][i] = (x[0][i]+x[1][i])/2.0f; - y[1][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]) * scaling; i++; - y[0][i] = (x[0][i]+x[1][i])/2.0f; - y[1][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]) * scaling; } 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_layers != 2) { @@ -1607,12 +1615,12 @@ int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], return -1; } #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 #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 - 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_AVX */ } 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 codebook_idx, uint32_t nof_symbols) + int codebook_idx, uint32_t nof_symbols, float scaling) { int i = 0; if (nof_ports == 2) { if (nof_layers == 1) { + scaling /= sqrtf(2.0f); switch(codebook_idx) { 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], 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[0], scaling, y[1], nof_symbols); break; 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], -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[0], -scaling, y[1], nof_symbols); break; case 2: - srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); - srslte_vec_sc_prod_ccc(x[0], _Complex_I/sqrtf(2.0f), y[1], nof_symbols); + srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols); + srslte_vec_sc_prod_ccc(x[0], _Complex_I * scaling, y[1], nof_symbols); break; case 3: - srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); - srslte_vec_sc_prod_ccc(x[0], -_Complex_I/sqrtf(2.0f), y[1], nof_symbols); + srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols); + srslte_vec_sc_prod_ccc(x[0], -_Complex_I * scaling, y[1], nof_symbols); break; default: fprintf(stderr, "Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n", @@ -1655,49 +1664,52 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO } else if (nof_layers == 2) { switch(codebook_idx) { case 0: - srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); - srslte_vec_sc_prod_cfc(x[1], 1.0f/sqrtf(2.0f), y[1], nof_symbols); + scaling /= sqrtf(2.0f); + 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; case 1: + scaling /= 2.0f; #ifdef LV_HAVE_AVX for (; i < nof_symbols - 3; i += 4) { - __m256 x0 = _mm256_load_ps((float*)&x[0][i]); - __m256 x1 = _mm256_load_ps((float*)&x[1][i]); + __m256 x0 = _mm256_load_ps((float *) &x[0][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 y1 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_sub_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(scaling), _mm256_sub_ps(x0, x1)); - _mm256_store_ps((float*)&y[0][i], y0); - _mm256_store_ps((float*)&y[1][i], y1); + _mm256_store_ps((float *) &y[0][i], y0); + _mm256_store_ps((float *) &y[1][i], y1); } #endif /* LV_HAVE_AVX */ #ifdef LV_HAVE_SSE for (; i < nof_symbols - 1; i += 2) { - __m128 x0 = _mm_load_ps((float*)&x[0][i]); - __m128 x1 = _mm_load_ps((float*)&x[1][i]); + __m128 x0 = _mm_load_ps((float *) &x[0][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 y1 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_sub_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(scaling), _mm_sub_ps(x0, x1)); - _mm_store_ps((float*)&y[0][i], y0); - _mm_store_ps((float*)&y[1][i], y1); + _mm_store_ps((float *) &y[0][i], y0); + _mm_store_ps((float *) &y[1][i], y1); } #endif /* LV_HAVE_SSE */ for (; i < nof_symbols; i++) { - y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; - y[1][i] = 0.5f*x[0][i] - 0.5f*x[1][i]; + y[0][i] = (x[0][i] + x[1][i]) * scaling; + y[1][i] = (x[0][i] - x[1][i]) * scaling; } break; case 2: + scaling /= 2.0f; #ifdef LV_HAVE_AVX for (; i < nof_symbols - 3; i += 4) { __m256 x0 = _mm256_load_ps((float*)&x[0][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 y1 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _MM256_MULJ_PS(_mm256_sub_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(scaling), _MM256_MULJ_PS(_mm256_sub_ps(x0, x1))); _mm256_store_ps((float*)&y[0][i], y0); _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 x1 = _mm_load_ps((float*)&x[1][i]); - __m128 y0 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_add_ps(x0, x1)); - __m128 y1 = _mm_mul_ps(_mm_set1_ps(0.5f), _MM_MULJ_PS(_mm_sub_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(scaling), _MM_MULJ_PS(_mm_sub_ps(x0, x1))); _mm_store_ps((float*)&y[0][i], y0); _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 */ for (; i < nof_symbols; i++) { - y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; - y[1][i] = 0.5f*_Complex_I*x[0][i] - 0.5f*_Complex_I*x[1][i]; + y[0][i] = (x[0][i] + x[1][i])*scaling; + y[1][i] = (_Complex_I*x[0][i] - _Complex_I*x[1][i])*scaling; } break; 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 */ 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) { 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) { 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: 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 { fprintf(stderr, "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; case SRSLTE_MIMO_TYPE_TX_DIVERSITY: 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 { fprintf(stderr, "Error number of layers must equal number of ports in transmit diversity\n"); return -1; } 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: return SRSLTE_ERROR; } diff --git a/lib/src/phy/mimo/test/precoder_test.c b/lib/src/phy/mimo/test/precoder_test.c index 1bbd9e3c0..589e3d51c 100644 --- a/lib/src/phy/mimo/test/precoder_test.c +++ b/lib/src/phy/mimo/test/precoder_test.c @@ -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 decoder_type_name [16] = "zf"; float snr_db = 100.0f; +float scaling = 0.1f; void usage(char *prog) { printf( "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-c codebook_idx [Default %d]\n", codebook_idx); 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("\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); @@ -59,7 +61,7 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "mplnrcds")) != -1) { + while ((opt = getopt(argc, argv, "mplnrcdsg")) != -1) { switch (opt) { case 'n': nof_symbols = atoi(argv[optind]); @@ -85,6 +87,9 @@ void parse_args(int argc, char **argv) { case 's': snr_db = (float) atof(argv[optind]); break; + case 'g': + scaling = (float) atof(argv[optind]); + break; default: usage(argv[0]); 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) { 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++) { srslte_ch_awgn_c(y[i], y[i], std_dev, n); @@ -250,7 +255,7 @@ int main(int argc, char **argv) { } /* 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"); exit(-1); } @@ -285,8 +290,8 @@ int main(int argc, char **argv) { /* predecoding / equalization */ struct timeval t[3]; gettimeofday(&t[1], NULL); - srslte_predecoding_type_multi(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers, - codebook_idx, nof_re, type, powf(10, -snr_db/10)); + srslte_predecoding_type(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers, + codebook_idx, nof_re, type, scaling, powf(10, -snr_db / 10)); gettimeofday(&t[2], NULL); get_time_interval(t); diff --git a/lib/src/phy/phch/pbch.c b/lib/src/phy/phch/pbch.c index 2eaa20501..c72b12c60 100644 --- a/lib/src/phy/phch/pbch.c +++ b/lib/src/phy/phch/pbch.c @@ -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 */ if (nant == 1) { /* 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 { 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); } @@ -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) { 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); + q->nof_symbols / q->cell.nof_ports, 1.0f); } else { memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); } diff --git a/lib/src/phy/phch/pcfich.c b/lib/src/phy/phch/pcfich.c index d960504fe..7269000a8 100644 --- a/lib/src/phy/phch/pcfich.c +++ b/lib/src/phy/phch/pcfich.c @@ -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 */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, q->nof_rx_antennas, q->nof_symbols, 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 { - 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); } @@ -278,7 +278,7 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR /* layer mapping & precoding */ if (q->cell.nof_ports > 1) { 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 { memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); } diff --git a/lib/src/phy/phch/pdcch.c b/lib/src/phy/phch/pdcch.c index 215324e6b..58d5bf6db 100644 --- a/lib/src/phy/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -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 */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, nof_symbols, 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 { - 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); } @@ -618,7 +618,7 @@ int srslte_pdcch_encode(srslte_pdcch_t *q, srslte_dci_msg_t *msg, srslte_dci_loc /* layer mapping & precoding */ if (q->cell.nof_ports > 1) { 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 { memcpy(q->symbols[0], q->d, nof_symbols * sizeof(cf_t)); } diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index b984adee3..f9899ef99 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -386,6 +386,12 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { 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) { 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)); } + float pdsch_scaling = 1.0f; + if (q->rho_a != 0.0f) { + pdsch_scaling = q->rho_a; + } + // Pre-decoder - if (srslte_predecoding_type_multi(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) { + 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, pdsch_scaling, noise_estimate)<0) { return -1; } @@ -822,7 +833,7 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, /* Precode */ 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 { memcpy(q->symbols[0], q->d[0], cfg->nbits[0].nof_re * sizeof(cf_t)); } diff --git a/lib/src/phy/phch/phich.c b/lib/src/phy/phch/phich.c index 14a0d5426..37b8e1b7a 100644 --- a/lib/src/phy/phch/phich.c +++ b/lib/src/phy/phch/phich.c @@ -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 */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, 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 { - 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); } 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) { 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_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! */ } else { memcpy(q->sf_symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); diff --git a/lib/src/phy/phch/pmch.c b/lib/src/phy/phch/pmch.c index aa7fd77b1..c1c322f34 100644 --- a/lib/src/phy/phch/pmch.c +++ b/lib/src/phy/phch/pmch.c @@ -378,7 +378,7 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q, } // No tx diversity in MBSFN - srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits[0].nof_re, 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()) { DEBUG("SAVED FILE subframe.dat: received subframe symbols\n"); diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index 498d34f3a..f9c6bebc1 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -787,7 +787,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, } // Equalization - srslte_predecoding_single(q->z_tmp, q->ce, q->z, nof_re, noise_estimate); + srslte_predecoding_single(q->z_tmp, q->ce, q->z, nof_re, 1.0f, noise_estimate); // Perform ML-decoding float corr=0, corr_max=-1e9; diff --git a/lib/src/phy/phch/pusch.c b/lib/src/phy/phch/pusch.c index ba1195507..a8c6064fc 100644 --- a/lib/src/phy/phch/pusch.c +++ b/lib/src/phy/phch/pusch.c @@ -596,7 +596,7 @@ int srslte_pusch_decode(srslte_pusch_t *q, } // Equalization - srslte_predecoding_single(q->d, q->ce, q->z, cfg->nbits.nof_re, noise_estimate); + srslte_predecoding_single(q->d, q->ce, q->z, cfg->nbits.nof_re, 1.0f, noise_estimate); // DFT predecoding srslte_dft_precoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb); diff --git a/lib/src/phy/phch/ra.c b/lib/src/phy/phch/ra.c index 735794e35..17866f5d3 100644 --- a/lib/src/phy/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -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); if (ret == SRSLTE_SUCCESS) { // 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 && - dci->dci_is_1c) - { - dci->rv_idx = 0; - } + if (dci->dci_is_1c) { + if ((msg_rnti >= SRSLTE_RARNTI_START && msg_rnti <= SRSLTE_RARNTI_END) || msg_rnti == SRSLTE_PRNTI) + { + dci->rv_idx = 0; + } + } } else { return SRSLTE_ERROR; } diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index b97e8b299..0b18d8b10 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -53,7 +53,7 @@ srslte_cell_t cell = { char mimo_type_str [32] = "single"; 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 subframe = 1; int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1}; @@ -496,7 +496,9 @@ int main(int argc, char **argv) { if (grant.tb_en[tb]) { for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) { if (data_tx[tb][byte] != data_rx[tb][byte]) { - ERROR("Found BYTE error in TB %d (%02X != %02X), quiting...", tb, data_tx[tb][byte], data_rx[tb][byte]); + 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; goto quit; } diff --git a/lib/src/phy/resampling/resample_arb.c b/lib/src/phy/resampling/resample_arb.c index 7bdb4deec..441e8c0dc 100644 --- a/lib/src/phy/resampling/resample_arb.c +++ b/lib/src/phy/resampling/resample_arb.c @@ -28,64 +28,104 @@ #include #include "srslte/phy/resampling/resample_arb.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}, -{-0.001750442300940216,0.006728826416921727,-0.02407540632178267,0.07708575473589654,0.9841056525667189,-0.05473739187922162,0.01460652754040275,-0.002745266140572769}, -{-0.001807302702047332,0.009130494591071001,-0.03332524241797466,0.1096377743266821,0.9737536341125557,-0.07444712408657775,0.0205085154280773,-0.004077596041064956}, -{-0.002005048395707184,0.01166717081713966,-0.04292591596219218,0.1440068251440274,0.9600641782991848,-0.09187282739868929,0.02573649090563353,-0.005218582609802016}, -{-0.002303606593778858,0.01431549924598744,-0.05279365431190471,0.1800496557331084,0.9431333663677619,-0.107022659158021,0.03028295984887362,-0.006178495199082676}, -{-0.002673824939871474,0.01705308556587308,-0.06283262272105428,0.2176066284621515,0.9230793648715676,-0.1199244901666642,0.03414559686566755,-0.006951034565279722}, -{-0.003099294850834212,0.01985022208215894,-0.07294100481214681,0.2564996326404178,0.9000412628278351,-0.1306207218667012,0.03733448898243594,-0.007554128492547957}, -{-0.003564415127592977,0.02267702927238637,-0.08300660359189582,0.2965368855416621,0.874178327911914,-0.1391710078036285,0.03986356581130199,-0.007992692892036229}, -{-0.004060222849803048,0.02549633298710617,-0.09291211362877161,0.3375102453232687,0.8456688916962831,-0.1456479420005528,0.04175429631970297,-0.00827816851803391}, -{-0.004574770330592958,0.02827133859849648,-0.1025308044303699,0.379200979038518,0.8147072909915275,-0.1501397816831265,0.04303284689167361,-0.008423951215857236}, -{-0.005100453570725489,0.0309593063669097,-0.1117325201826136,0.4213772298764557,0.7815036335229155,-0.1527444636485677,0.0437349357738538,-0.008441129184587313}, -{-0.005625340687997995,0.03351877124912608,-0.1203802123857154,0.463798444519773,0.7462810500374923,-0.1535722712206338,0.04389261707032224,-0.008345136869130621}, -{-0.006140888413286479,0.03590276234084221,-0.1283350405000867,0.5062161107254219,0.7092744343987509,-0.152741400055636,0.04355110899623683,-0.008147838953503964}, -{-0.006634012711933725,0.03806645580467819,-0.1354549138065051,0.5483763739419955,0.6707272107491931,-0.1503798528838644,0.0427502160096194,-0.007865132034489236}, -{-0.007094909626785393,0.03996043743797257,-0.1415969539549883,0.5900207719663111,0.6308907308946271,-0.1466186670140106,0.04153829696698895,-0.007508971112586246}, -{-0.007508971112586246,0.04153829696698895,-0.1466186670140106,0.6308907308946271,0.5900207719663111,-0.1415969539549883,0.03996043743797257,-0.007094909626785393}, -{-0.007865132034489236,0.0427502160096194,-0.1503798528838644,0.6707272107491931,0.5483763739419955,-0.1354549138065051,0.03806645580467819,-0.006634012711933725}, -{-0.008147838953503964,0.04355110899623683,-0.152741400055636,0.7092744343987509,0.5062161107254219,-0.1283350405000867,0.03590276234084221,-0.006140888413286479}, -{-0.008345136869130621,0.04389261707032224,-0.1535722712206338,0.7462810500374923,0.463798444519773,-0.1203802123857154,0.03351877124912608,-0.005625340687997995}, -{-0.008441129184587313,0.0437349357738538,-0.1527444636485677,0.7815036335229155,0.4213772298764557,-0.1117325201826136,0.0309593063669097,-0.005100453570725489}, -{-0.008423951215857236,0.04303284689167361,-0.1501397816831265,0.8147072909915275,0.379200979038518,-0.1025308044303699,0.02827133859849648,-0.004574770330592958}, -{-0.00827816851803391,0.04175429631970297,-0.1456479420005528,0.8456688916962831,0.3375102453232687,-0.09291211362877161,0.02549633298710617,-0.004060222849803048}, -{-0.007992692892036229,0.03986356581130199,-0.1391710078036285,0.874178327911914,0.2965368855416621,-0.08300660359189582,0.02267702927238637,-0.003564415127592977}, -{-0.007554128492547957,0.03733448898243594,-0.1306207218667012,0.9000412628278351,0.2564996326404178,-0.07294100481214681,0.01985022208215894,-0.003099294850834212}, -{-0.006951034565279722,0.03414559686566755,-0.1199244901666642,0.9230793648715676,0.2176066284621515,-0.06283262272105428,0.01705308556587308,-0.002673824939871474}, -{-0.006178495199082676,0.03028295984887362,-0.107022659158021,0.9431333663677619,0.1800496557331084,-0.05279365431190471,0.01431549924598744,-0.002303606593778858}, -{-0.005218582609802016,0.02573649090563353,-0.09187282739868929,0.9600641782991848,0.1440068251440274,-0.04292591596219218,0.01166717081713966,-0.002005048395707184}, -{-0.004077596041064956,0.0205085154280773,-0.07444712408657775,0.9737536341125557,0.1096377743266821,-0.03332524241797466,0.009130494591071001,-0.001807302702047332}, -{-0.002745266140572769,0.01460652754040275,-0.05473739187922162,0.9841056525667189,0.07708575473589654,-0.02407540632178267,0.006728826416921727,-0.001750442300940216}, -{-0.001216900416836847,0.008048813755373533,-0.03275243420114668,0.9910477342662829,0.04647449496926549,-0.01525319260830623,0.004479591950094871,-0.001903604727400391}, -{0.0004992625165376107,0.0008598969867484128,-0.008521087756729117,0.99453086623794,0.0179104136912176,-0.006922416132556366,0.002400347599485495,0}}; -// 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;ireg[1], &q->reg[0], (SRSLTE_RESAMPLE_ARB_M-1)*sizeof(cf_t)); q->reg[0] = x; } // 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)); q->acc = 0.0; q->rate = rate; + q->interpolate = interpolate; 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 n_out = 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(cntreg[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); + } - while(cnt < n_in) - { - *output = srslte_resample_arb_dot_prod(q->reg, srslte_resample_arb_polyfilt[idx], SRSLTE_RESAMPLE_ARB_M); + if(idx == SRSLTE_RESAMPLE_ARB_N){ + *output = res1; + }else { + *output = (q->interpolate)?(res1 + (res2-res1)*frac):res1; + } + output++; n_out++; q->acc += q->step; - idx = (int)roundf(q->acc); + idx = (int)(q->acc); + while(idx >= SRSLTE_RESAMPLE_ARB_N){ q->acc -= SRSLTE_RESAMPLE_ARB_N; idx -= SRSLTE_RESAMPLE_ARB_N; - if(cnt < n_in) - srslte_resample_arb_push(q, input[cnt++]); + if(cnt < n_in){ + cnt++; + } + } + + if(q->interpolate){ + frac = q->acc - idx; + if(frac < 0) + frac = frac*(-1); } } return n_out; diff --git a/lib/src/phy/resampling/test/resample_arb_bench.c b/lib/src/phy/resampling/test/resample_arb_bench.c index 48879d036..e9ef3c442 100644 --- a/lib/src/phy/resampling/test/resample_arb_bench.c +++ b/lib/src/phy/resampling/test/resample_arb_bench.c @@ -35,9 +35,9 @@ #include "srslte/phy/resampling/resample_arb.h" - +#define ITERATIONS 10000 int main(int argc, char **argv) { - int N=10000000; + int N=9000; float rate = 24.0/25.0; cf_t *in = 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); srslte_resample_arb_t r; - srslte_resample_arb_init(&r, rate); + srslte_resample_arb_init(&r, rate, 0); clock_t start = clock(), diff; - //int n_out = srslte_resample_arb_compute(&r, in, out, N); + for(int xx = 0; xx diff && pre != post){ - printf("Interpolation failed at index %f", idx); + printf("Interpolation failed at index %f\n", idx); exit(-1); } } - free(in); free(out); } diff --git a/lib/src/phy/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c index 79f0e017e..267370b52 100644 --- a/lib/src/phy/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -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) { - 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); rf->new_rx_gain = gain; 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); } 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); } pthread_mutex_unlock(&rf->mutex); diff --git a/lib/src/phy/rf/rf_soapy_imp.c b/lib/src/phy/rf/rf_soapy_imp.c index 3e8d83eb8..83f5c3a23 100644 --- a/lib/src/phy/rf/rf_soapy_imp.c +++ b/lib/src/phy/rf/rf_soapy_imp.c @@ -38,6 +38,7 @@ #include typedef struct { + char *devname; SoapySDRKwargs args; SoapySDRDevice *device; SoapySDRRange *ranges; @@ -51,7 +52,6 @@ typedef struct { cf_t zero_mem[64*1024]; - int soapy_error(void *h) { 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) { - 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"); return SRSLTE_ERROR; } - + char* devname; for (size_t i = 0; i < length; i++) { printf("Soapy has Found device #%d: ", (int)i); for (size_t j = 0; j < soapy_args[i].size; 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"); } @@ -218,7 +223,7 @@ int rf_soapy_open_multi(char *args, void **h, uint32_t nof_rx_antennas) handler->device = sdr; handler->tx_stream_active = false; handler->rx_stream_active = false; - + handler->devname = devname; if(SoapySDRDevice_getNumChannels(handler->device,SOAPY_SDR_RX) > 0){ printf("setting up RX stream\n"); 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; } } + 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; } @@ -267,7 +280,7 @@ int rf_soapy_close(void *h) void rf_soapy_set_master_clock_rate(void *h, double 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()); return SRSLTE_ERROR; } - 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()); return SRSLTE_ERROR; } - return SoapySDRDevice_getSampleRate(handler->device, SOAPY_SDR_TX,0); } diff --git a/lib/src/phy/rf/rf_soapy_imp.h b/lib/src/phy/rf/rf_soapy_imp.h index 18850e520..4974157d1 100644 --- a/lib/src/phy/rf/rf_soapy_imp.h +++ b/lib/src/phy/rf/rf_soapy_imp.h @@ -28,7 +28,7 @@ #include #include "srslte/config.h" #include "srslte/phy/rf/rf.h" - +#define DEVNAME_LIME "lime" SRSLTE_API int rf_soapy_open(char *args, void **handler); diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index f5bed7362..c39bb2604 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -293,6 +293,13 @@ int rf_uhd_open(char *args, void **h) 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) { 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) { if (h) { @@ -338,11 +356,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) // Check external clock argument enum {DEFAULT, EXTERNAL, GPSDO} clock_src; if (strstr(args, "clock=external")) { - remove_substring(args, "clock=external"); + REMOVE_SUBSTRING_WITHCOMAS(args, "clock=external"); clock_src = EXTERNAL; } else if (strstr(args, "clock=gpsdo")) { printf("Using GPSDO clock\n"); - remove_substring(args, "clock=gpsdo"); + REMOVE_SUBSTRING_WITHCOMAS(args, "clock=gpsdo"); clock_src = GPSDO; } else { 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 char *otw_format = "sc16"; if (strstr(args, "otw_format=sc12")) { + REMOVE_SUBSTRING_WITHCOMAS(args, "otw_format=sc12"); otw_format = "sc12"; } else if (strstr(args, "otw_format=sc16")) { + REMOVE_SUBSTRING_WITHCOMAS(args, "otw_format=sc16"); /* Do nothing */ } else if (strstr(args, "otw_format=")) { fprintf(stderr, "Wrong over the wire format. Valid formats: sc12, sc16\n"); 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 (args[0]=='\0') { if (find_string(devices_str, "type=b200") && !strstr(args, "recv_frame_size")) { @@ -398,7 +444,29 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) fprintf(stderr, "Error opening UHD: code %d\n", error); 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) { char dev_str[1024]; uhd_usrp_get_mboard_name(handler->usrp, 0, dev_str, 1024); diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index 0fb1b819d..ae92396d0 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -586,19 +586,21 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t DEBUG("Not enough room to detect CP length. Peak position: %d\n", peak_pos); } } - - 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]); - if (q->mean_cfo2_isunset) { - q->mean_cfo2 = cfo2; - q->mean_cfo2_isunset = true; + + if (q->enable_cfo_corr) { + 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]); + if (q->mean_cfo2_isunset) { + q->mean_cfo2 = cfo2; + q->mean_cfo2_isunset = true; + } else { + q->mean_cfo2 = SRSLTE_VEC_EMA(cfo2, q->mean_cfo2, q->cfo_ema_alpha); + } + + ret = SRSLTE_SYNC_FOUND; } else { - q->mean_cfo2 = SRSLTE_VEC_EMA(cfo2, q->mean_cfo2, q->cfo_ema_alpha); + ret = SRSLTE_SYNC_FOUND_NOSPACE; } - - ret = SRSLTE_SYNC_FOUND; - } else { - ret = SRSLTE_SYNC_FOUND_NOSPACE; } } else { ret = SRSLTE_SYNC_NOFOUND; diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 1c3b79440..494eecba7 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -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); } - +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) { for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){ diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index e9c02ca8b..d11811cf3 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -47,6 +47,10 @@ #define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0 #define DEFAULT_SFO_EMA_COEFF 0.1 + +//#define DO_CFO_IN_SYNC + + cf_t dummy_buffer0[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; if (q->do_agc) { srslte_agc_set_gain(&q->agc, init_gain_value); + srslte_agc_set_target(&q->agc, 0.3); + srslte_agc_set_bandwidth(&q->agc, 0.8); } 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->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; 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; } @@ -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) { srslte_sync_set_cfo_ema_alpha(&q->sfind, 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) { @@ -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) { +#ifdef DO_CFO_IN_SYNC 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) { @@ -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; +#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 */ if (q->sf_idx == 0 || q->sf_idx == 5) { diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index 853937f7c..ec2809dfe 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -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)) { fprintf(stderr, "Error encoding TB\n"); - return ret; + return SRSLTE_ERROR; } if (q->signals_pregenerated) { diff --git a/lib/src/phy/utils/debug.c b/lib/src/phy/utils/debug.c index 423abee6c..7cb9c0f11 100644 --- a/lib/src/phy/utils/debug.c +++ b/lib/src/phy/utils/debug.c @@ -24,7 +24,14 @@ * */ +#include +#include +#include +#include +#include + #include "srslte/phy/utils/debug.h" +#include "srslte/version.h" int srslte_verbose = 0; @@ -37,3 +44,57 @@ void get_time_interval(struct timeval * tdata) { 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); +} diff --git a/lib/src/phy/utils/test/vector_test.c b/lib/src/phy/utils/test/vector_test.c index 4ebed9862..9058e8813 100644 --- a/lib/src/phy/utils/test/vector_test.c +++ b/lib/src/phy/utils/test/vector_test.c @@ -502,6 +502,7 @@ TEST(srslte_vec_abs_cf, for (int i = 0; i < block_size; i++) { x[i] = RANDOM_CF(); } + x[0] = 0.0f; TEST_CALL(srslte_vec_abs_cf(x, z, block_size)) diff --git a/lib/src/phy/utils/vector_simd.c b/lib/src/phy/utils/vector_simd.c index ab281a653..23c58cfce 100644 --- a/lib/src/phy/utils/vector_simd.c +++ b/lib/src/phy/utils/vector_simd.c @@ -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) { int i = 0; diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index 66e28b1d3..00272a6a4 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -59,6 +59,7 @@ bool radio::init(char *args, char *devname) } else if (strstr(srslte_rf_name(&rf_device), "bladerf")) { burst_preamble_sec = blade_default_burst_preamble_sec; } 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)); } @@ -329,11 +330,10 @@ void radio::set_tx_srate(double srate) } burst_preamble_time_rounded = (double) burst_preamble_samples/cur_tx_srate; - int nsamples=0; /* Set time advance for each known device if in auto mode */ if (tx_adv_auto) { - + /* This values have been calibrated using the prach_test_usrp tool in srsLTE */ if (!strcmp(srslte_rf_name(&rf_device), "uhd_b200")) { @@ -355,7 +355,48 @@ void radio::set_tx_srate(double srate) /* 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_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")) { // In X300 TX/RX offset is independent of sampling rate diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index 05f35ad76..f8abc0aef 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -201,8 +201,14 @@ uint32_t rlc_am::get_total_buffer_state() 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); 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); + } } } @@ -250,7 +256,13 @@ uint32_t rlc_am::get_buffer_state() 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); 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); goto unlock_and_return; } @@ -296,8 +308,9 @@ int rlc_am::read_pdu(uint8_t *payload, uint32_t nof_bytes) } // RETX if required if(retx_queue.size() > 0) { + int ret = build_retx_pdu(payload, nof_bytes); pthread_mutex_unlock(&mutex); - return build_retx_pdu(payload, nof_bytes); + return ret; } // 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) { + // 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(); // Sanity check - drop any retx SNs not present in tx_window while(tx_window.end() == tx_window.find(retx.sn)) { retx_queue.pop_front(); - retx = retx_queue.front(); + if (!retx_queue.empty()) { + retx = retx_queue.front(); + } else { + log->error("In build_retx_pdu(): retx_queue is empty during sanity check\n"); + return -1; + } } // 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()); 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) { + 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){ retx.so_start = 0; 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) { if(!retx.is_segment){ - return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes; + 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; + } 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 diff --git a/srsenb/hdr/phy/phch_worker.h b/srsenb/hdr/phy/phch_worker.h index dd95aaa93..523fefeec 100644 --- a/srsenb/hdr/phy/phch_worker.h +++ b/srsenb/hdr/phy/phch_worker.h @@ -95,7 +95,7 @@ private: srslte_enb_dl_t enb_dl; srslte_enb_ul_t enb_ul; - srslte_timestamp_t tx_time; + srslte_timestamp_t tx_time; // Class to store user information class ue { @@ -112,6 +112,11 @@ private: void metrics_read(phy_metrics_t *metrics); void metrics_dl(uint32_t mcs); 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: phy_metrics_t metrics; }; diff --git a/srsenb/src/mac/scheduler.cc b/srsenb/src/mac/scheduler.cc index 81ed0882e..f477895b5 100644 --- a/srsenb/src/mac/scheduler.cc +++ b/srsenb/src/mac/scheduler.cc @@ -709,7 +709,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched /* Indicate PHICH acknowledgment if needed */ if (h->has_pending_ack()) { - sched_result->phich[nof_phich_elems].phich = h->get_ack()?ul_sched_phich_t::ACK:ul_sched_phich_t::NACK; + sched_result->phich[nof_phich_elems].phich = h->get_ack()?ul_sched_phich_t::ACK:ul_sched_phich_t::NACK; sched_result->phich[nof_phich_elems].rnti = rnti; nof_phich_elems++; } @@ -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(); 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 if (is_newtx) { diff --git a/srsenb/src/mac/scheduler_harq.cc b/srsenb/src/mac/scheduler_harq.cc index f5209b374..88ae6b74d 100644 --- a/srsenb/src/mac/scheduler_harq.cc +++ b/srsenb/src/mac/scheduler_harq.cc @@ -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) { - is_adaptive = false; + is_adaptive = true; memcpy(&allocation, &alloc, sizeof(ul_alloc_t)); } void ul_harq_proc::same_alloc() { - is_adaptive = true; + is_adaptive = false; } bool ul_harq_proc::is_adaptive_retx() @@ -243,8 +243,7 @@ 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; } diff --git a/srsenb/src/mac/scheduler_ue.cc b/srsenb/src/mac/scheduler_ue.cc index 94056b990..87949179e 100644 --- a/srsenb/src/mac/scheduler_ue.cc +++ b/srsenb/src/mac/scheduler_ue.cc @@ -25,11 +25,6 @@ */ #include -#include -#include -#include -#include -#include #include "srslte/srslte.h" #include "srslte/common/pdu.h" @@ -395,32 +390,32 @@ int sched_ue::generate_format1(dl_harq_proc *h, mcs = fixed_mcs_dl; } - h->new_tx(tti, mcs, tbs, data->dci_location.ncce); - + h->new_tx(tti, mcs, tbs, data->dci_location.ncce); + + // Allocate MAC ConRes CE + if (need_conres_ce) { + data->pdu[0].lcid = srslte::sch_subh::CON_RES_ID; + data->nof_pdu_elems++; + Info("SCHED: Added MAC Contention Resolution CE for rnti=0x%x\n", rnti); + } + + int rem_tbs = tbs; + int x = 0; + do { + x = alloc_pdu(rem_tbs, &data->pdu[data->nof_pdu_elems]); + rem_tbs -= x; + if (x) { + data->nof_pdu_elems++; + } + } 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); } - - // Allocate MAC ConRes CE - if (need_conres_ce) { - data->pdu[0].lcid = srslte::sch_subh::CON_RES_ID; - data->nof_pdu_elems++; - Info("SCHED: Added MAC Contention Resolution CE for rnti=0x%x\n", rnti); - } - - int rem_tbs = tbs; - int x = 0; - do { - x = alloc_pdu(rem_tbs, &data->pdu[data->nof_pdu_elems]); - rem_tbs -= x; - if (x) { - data->nof_pdu_elems++; - } - } while(rem_tbs > 0 && x > 0); - - data->rnti = rnti; + + data->rnti = rnti; if (tbs > 0) { dci->harq_process = h->get_id(); @@ -449,7 +444,8 @@ int sched_ue::generate_format0(ul_harq_proc *h, int tbs = 0; ul_harq_proc::ul_alloc_t allocation = h->get_alloc(); - + + bool is_newtx = true; if (h->get_rar_mcs(&mcs)) { tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8; h->new_tx(tti, mcs, tbs); @@ -468,7 +464,8 @@ int sched_ue::generate_format0(ul_harq_proc *h, h->new_tx(tti, mcs, tbs); - } else { + } else { + is_newtx = false; h->new_retx(tti, &mcs, NULL); tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs), allocation.L)/8; } @@ -479,9 +476,13 @@ int sched_ue::generate_format0(ul_harq_proc *h, if (tbs > 0) { dci->type2_alloc.L_crb = allocation.L; dci->type2_alloc.RB_start = allocation.RB_start; - dci->mcs_idx = mcs; - dci->rv_idx = sched::get_rvidx(h->nof_retx()); - dci->ndi = h->get_ndi(); + 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->cqi_request = cqi_request; dci->freq_hop_fl = srslte_ra_ul_dci_t::SRSLTE_RA_PUSCH_HOP_DISABLED; dci->tpc_pusch = next_tpc_pusch; diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 528878388..5cc4f5b1c 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -350,6 +350,8 @@ int main(int argc, char *argv[]) metrics_stdout metrics; enb *enb = enb::get_instance(); + srslte_debug_handle_crash(argc, argv); + cout << "--- Software Radio Systems LTE eNodeB ---" << endl << endl; parse_args(&args, argc, argv); diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index 103017fcc..c023c13e0 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -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; int res = -1; 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) { phy_grant.mcs.mod = SRSLTE_MOD_16QAM; } diff --git a/srsue/hdr/mac/ul_harq.h b/srsue/hdr/mac/ul_harq.h index 4749971b6..72b691c00 100644 --- a/srsue/hdr/mac/ul_harq.h +++ b/srsue/hdr/mac/ul_harq.h @@ -44,39 +44,35 @@ namespace srsue { template -class ul_harq_entity -{ +class ul_harq_entity { public: - static uint32_t pidof(uint32_t tti) - { - return (uint32_t) tti%N; + static uint32_t pidof(uint32_t tti) { + return (uint32_t) tti % N; } - - ul_harq_entity() : proc(N) - { + + ul_harq_entity() : proc(N) { contention_timer = NULL; - pcap = NULL; - mux_unit = NULL; - log_h = NULL; - params = NULL; - rntis = NULL; - average_retx = 0; - nof_pkts = 0; + pcap = NULL; + mux_unit = NULL; + log_h = NULL; + params = NULL; + rntis = NULL; + average_retx = 0; + nof_pkts = 0; } - bool init(srslte::log *log_h_, + bool init(srslte::log *log_h_, mac_interface_rrc_common::ue_rnti_t *rntis_, mac_interface_rrc_common::ul_harq_params_t *params_, - srslte::timers::timer* contention_timer_, - mux *mux_unit_) - { - log_h = log_h_; - mux_unit = mux_unit_; - params = params_; - rntis = rntis_; + srslte::timers::timer *contention_timer_, + mux *mux_unit_) { + log_h = log_h_; + mux_unit = mux_unit_; + params = params_; + rntis = rntis_; contention_timer = contention_timer_; - for (uint32_t i=0;iMAC 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 || grant.rnti_type == SRSLTE_RNTI_TEMP || @@ -115,27 +111,20 @@ public: if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) { 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) { if (grant.ndi[0]) { grant.ndi[0] = proc[pidof(grant.tti)].get_ndi(); - run_tti(grant.tti, &grant, action); + run_tti(grant.tti, &grant, ack, action); } else { 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) { - set_ack(tti, ack, action); - run_tti(tti, NULL, action); + run_tti(tti, NULL, &ack, action); } int get_current_tbs(uint32_t tti) @@ -206,10 +195,19 @@ private: bzero(&cur_grant, sizeof(Tgrant)); } - void reset_ndi() { ndi = false; } - - void run_tti(uint32_t tti_tx, Tgrant *grant, Taction* action) + void reset_ndi() { cur_grant.ndi[0] = false; } + + 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; if (is_msg3) { max_retx = harq_entity->params->max_harq_msg3_tx; @@ -219,9 +217,9 @@ private: // Receive and route HARQ feedbacks if (grant) { - if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi()) || - (grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) || - grant->is_from_rar) + if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi() && ack) || + (grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) || + grant->is_from_rar) { // New transmission @@ -245,7 +243,7 @@ private: Warning("Uplink grant but no MAC PDU in Multiplex Unit buffer\n"); } } - } else { + } else if (has_grant()) { // Adaptive Re-TX if (current_tx_nb >= max_retx) { Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); @@ -254,6 +252,8 @@ private: } else { 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()) { // Non-Adaptive Re-Tx @@ -292,9 +292,8 @@ private: } 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; } - uint32_t last_tx_tti() { return tti_last_tx; } uint32_t get_nof_retx() { return current_tx_nb; } int get_current_tbs() { return cur_grant.n_bytes[0]*8; } @@ -305,7 +304,6 @@ private: uint32_t current_tx_nb; uint32_t current_irv; bool harq_feedback; - bool ndi; srslte::log *log_h; ul_harq_entity *harq_entity; bool is_grant_configured; @@ -396,24 +394,12 @@ private: // Implements Section 5.4.2.1 // 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; - 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; srslte::timers::timer *contention_timer; diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h index aa7c53ab7..39eb594bc 100644 --- a/srsue/hdr/phy/phch_common.h +++ b/srsue/hdr/phy/phch_common.h @@ -69,6 +69,14 @@ namespace srsue { bool pcell_meas_enabled; 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); void init(phy_interface_rrc::phy_cfg_t *config, phy_args_t *args, @@ -144,7 +152,7 @@ namespace srsue { uint32_t n_dmrs; } pending_ack_t; pending_ack_t pending_ack[TTIMOD_SZ]; - + bool is_first_tx; uint32_t nof_workers; diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index 93ace4d68..eea156298 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -80,6 +80,7 @@ public: 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 scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index 73547a9aa..067a3a8fb 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -151,11 +151,6 @@ private: float cfo; 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 dl_metrics_t dl_metrics; ul_metrics_t ul_metrics; diff --git a/srsue/hdr/ue_base.h b/srsue/hdr/ue_base.h index b547945a9..e23adf3d2 100644 --- a/srsue/hdr/ue_base.h +++ b/srsue/hdr/ue_base.h @@ -38,6 +38,7 @@ #include "srslte/radio/radio_multi.h" #include "phy/phy.h" #include "upper/usim.h" +#include "upper/rrc.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/logger.h" @@ -104,12 +105,11 @@ typedef struct { typedef struct { std::string ip_netmask; - phy_args_t phy; - float metrics_period_secs; - bool pregenerate_signals; - std::string ue_cateogry; - bool metrics_csv_enable; - std::string metrics_csv_filename; + phy_args_t phy; + float metrics_period_secs; + bool pregenerate_signals; + bool metrics_csv_enable; + std::string metrics_csv_filename; }expert_args_t; typedef struct { @@ -120,6 +120,8 @@ typedef struct { log_args_t log; gui_args_t gui; usim_args_t usim; + rrc_args_t rrc; + std::string ue_category_str; expert_args_t expert; }all_args_t; @@ -161,6 +163,10 @@ public: srslte::log_filter rf_log; rf_metrics_t rf_metrics; 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 diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index e743165fb..d79eddea8 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -57,6 +57,9 @@ static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL", "DEREGISTERED 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 { PLMN_NOT_SELECTED = 0, PLMN_SELECTED @@ -80,16 +83,12 @@ public: // RRC interface void notify_connection_setup(); - void write_pdu(uint32_t lcid, byte_buffer_t *pdu); - uint32_t get_ul_count(); - bool is_attached(); bool is_attaching(); - 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_search_end(); @@ -115,72 +114,73 @@ private: std::vector known_plmns; - // Save short MAC + LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT emm_info; // Identifiers 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; uint8_t eps_bearer_id; uint8_t transaction_id; - // NAS counters - incremented for each security-protected message recvd/sent - uint32_t count_ul; - uint32_t count_dl; - // Security - uint8_t ksi; uint8_t k_nas_enc[32]; uint8_t k_nas_int[32]; - srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; - srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; - - void integrity_generate(uint8_t *key_128, + void integrity_generate(uint8_t integ_algo, + uint8_t *key_128, uint32_t count, uint8_t rb_id, uint8_t direction, uint8_t *msg, uint32_t msg_len, uint8_t *mac); - void integrity_check(); - void cipher_encrypt(); - void cipher_decrypt(); + bool check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps); // Parsers void parse_attach_accept(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_reject(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_service_reject(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); // Senders void send_attach_request(); - void send_identity_response(); - void send_service_request(); - void send_esm_information_response(); - 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 diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 5a49a9275..0e77e29b0 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -40,6 +40,13 @@ #include #include +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; namespace srsue { @@ -74,7 +81,7 @@ public: rrc_state_t get_state(); - void set_ue_category(int category); + void set_args(rrc_args_t *args); // Timeout callback interface void timer_expired(uint32_t timeout_id); @@ -142,6 +149,9 @@ private: uint8_t transaction_id; bool drb_up; + rrc_args_t args; + bool first_stimsi_attempt; + bool reestablishment_in_progress; bool pending_mob_reconf; @@ -174,10 +184,11 @@ private: // RRC constants and 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 n311_cnt, N311; uint32_t t301, t310, t311, t304; - int ue_category; typedef struct { uint32_t earfcn; @@ -375,7 +386,6 @@ private: void set_mac_default(); void set_rrc_default(); void set_bearers(); - }; } // namespace srsue diff --git a/srsue/hdr/upper/usim.h b/srsue/hdr/upper/usim.h index 3b122d416..6ad3acce5 100644 --- a/srsue/hdr/upper/usim.h +++ b/srsue/hdr/upper/usim.h @@ -1,4 +1,4 @@ -/** +/** * * \section COPYRIGHT * @@ -59,24 +59,30 @@ public: void stop(); // NAS interface - void get_imsi_vec(uint8_t* imsi_, uint32_t n); - void get_imei_vec(uint8_t* imei_, uint32_t n); - int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id); + std::string get_imsi_str(); + std::string get_imei_str(); + + 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, uint8_t *autn_enb, uint16_t mcc, uint16_t mnc, 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, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); // 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_int, uint8_t *k_up_enc, @@ -100,13 +106,15 @@ private: uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res); + uint8_t *res, + uint8_t *k_asme); void gen_auth_res_xor( uint8_t *rand, uint8_t *autn_enb, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res); + uint8_t *res, + uint8_t *k_asme); void str_to_hex(std::string str, uint8_t *hex); srslte::log *usim_log; @@ -119,6 +127,9 @@ private: uint64_t imei; uint8_t k[16]; + std::string imsi_str; + std::string imei_str; + // Security variables uint8_t rand[16]; uint8_t ck[16]; @@ -126,7 +137,6 @@ private: uint8_t ak[6]; uint8_t mac[8]; uint8_t autn[16]; - uint8_t k_asme[32]; uint8_t k_enb[32]; uint8_t k_enb_star[32]; diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index e543c0fd5..368050f7d 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -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) { 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) { metrics.tx_errors++; } else { diff --git a/srsue/src/mac/mux.cc b/srsue/src/mac/mux.cc index 2b92061e9..d624d2d62 100644 --- a/srsue/src/mac/mux.cc +++ b/srsue/src/mac/mux.cc @@ -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;iinfo("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); } } @@ -296,8 +294,8 @@ bool mux::sched_sdu(lchid_t *ch, int *sdu_space, int max_sdu_sz) sched_len = *sdu_space; } - log_h->info("SDU: scheduled lcid=%d, rlc_buffer=%d, allocated=%d/%d\n", - ch->id, ch->buffer_len, sched_len, *sdu_space); + log_h->debug("SDU: scheduled lcid=%d, rlc_buffer=%d, allocated=%d/%d\n", + ch->id, ch->buffer_len, sched_len, sdu_space?*sdu_space:0); *sdu_space -= 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; } 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; - } + } if (sdu_len > MIN_RLC_SDU_LEN) { 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); 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()); return true; } else { diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 0cd31a3d6..113f4d5c0 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -75,8 +75,12 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { ("rf.device_args", bpo::value(&args->rf.device_args)->default_value("auto"), "Front-end device arguments") ("rf.time_adv_nsamples", bpo::value(&args->rf.time_adv_nsamples)->default_value("auto"), "Transmission time advance") - ("rf.burst_preamble_us", bpo::value(&args->rf.burst_preamble)->default_value("auto"), - "Transmission time advance") + ("rf.burst_preamble_us", bpo::value(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance") + + ("rrc.feature_group", bpo::value(&args->rrc.feature_group)->default_value(0xe6041c00), "Hex value of the featureGroupIndicators field in the" + "UECapabilityInformation message. Default 0xe6041c00") + ("rrc.ue_category", bpo::value(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)") + ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") @@ -134,10 +138,6 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { bpo::value(&args->expert.phy.sync_cpu_affinity)->default_value(-1), "index of the core used by the sync thread") - ("expert.ue_category", - bpo::value(&args->expert.ue_cateogry)->default_value("4"), - "UE Category (1 to 5)") - ("expert.metrics_period_secs", bpo::value(&args->expert.metrics_period_secs)->default_value(1.0), "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.") ("expert.cfo_ema", - bpo::value(&args->expert.phy.cfo_ema)->default_value(0.4), + bpo::value(&args->expert.phy.cfo_ema)->default_value(0.3), "CFO Exponential Moving Average coefficient. Lower makes it more robust to noise " "but vulnerable to periodic interruptions due to VCO corrections.") @@ -369,6 +369,9 @@ int main(int argc, char *argv[]) srslte::metrics_hub metricshub; signal(SIGINT, sig_int_handler); all_args_t args; + + srslte_debug_handle_crash(argc, argv); + parse_args(&args, argc, argv); srsue_instance_type_t type = LTE; diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 1e863ec99..3070721ba 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -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) { - srslte::radio_multi *radio_handler = (srslte::radio_multi *) h; - return radio_handler->set_rx_gain_th(gain); + return ((phch_recv*) h)->set_rx_gain(gain); } @@ -395,8 +394,6 @@ bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { current_earfcn = earfcn; - printf("cell select called set frequency\n"); - if (set_frequency()) { this->cell = cell; 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); +} diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index e811baefc..8c487bc48 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -27,6 +27,7 @@ #include #include #include "phy/phch_worker.h" +#include "srslte/srslte.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/asn1/liblte_rrc.h" @@ -40,8 +41,6 @@ #ifdef ENABLE_GUI #include "srsgui/srsgui.h" #include -#include "srslte/srslte.h" -#include "srslte/interfaces/ue_interfaces.h" void init_plots(srsue::phch_worker *worker); 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_cfo_enable(&ue_ul, true); + srslte_ue_ul_set_cfo_tol(&ue_ul, phy->args->cfo_correct_tol_hz); mem_initiated = true; @@ -324,7 +324,7 @@ void phch_worker::work_imp() ul_action.tti_offset = HARQ_DELAY_MS; /* Send UL grant or HARQ information (from PHICH) to MAC */ - if (ul_grant_available && ul_ack_available) { + if (ul_grant_available && ul_ack_available) { phy->mac->new_grant_ul_ack(ul_mac_grant, ul_ack, &ul_action); } else if (ul_grant_available && !ul_ack_available) { phy->mac->new_grant_ul(ul_mac_grant, &ul_action); @@ -479,15 +479,19 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) 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;iphy_grant.dl.mcs[i].tbs < 0) { - grant->phy_grant.dl.mcs[i].tbs = last_dl_tbs[grant->pid%(2*HARQ_DELAY_MS)][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) { + Info("Invalid TBS size for PDSCH grant\n"); + grant->phy_grant.dl.mcs[i].tbs = 0; } // 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 */ @@ -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++) { if (grant->tb_en[tb] && (rv[tb] < 0 || rv[tb] > 3)) { 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) { /* Implemented Tx Modes */ case LIBLTE_RRC_TRANSMISSION_MODE_1: 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; case LIBLTE_RRC_TRANSMISSION_MODE_2: 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 { 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; 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; - } 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; } else { 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; } break; 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; - } 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; } else { 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; } break; @@ -590,6 +603,19 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL 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); /* 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"); ret = SRSLTE_ERROR; } + } else { + Error("Error invalid DL config\n"); + ret = SRSLTE_ERROR; } return ret; } @@ -729,29 +758,30 @@ 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 - if (grant->phy_grant.ul.mcs.tbs < 0) { - grant->phy_grant.ul.mcs.tbs = last_ul_tbs[tti%(2*HARQ_DELAY_MS)]; - } - last_ul_tbs[tti%(2*HARQ_DELAY_MS)] = grant->phy_grant.ul.mcs.tbs; - - if (grant->phy_grant.ul.mcs.mod == SRSLTE_MOD_LAST) { - grant->phy_grant.ul.mcs.mod = last_ul_mod[tti%(2*HARQ_DELAY_MS)]; + if (grant->phy_grant.ul.mcs.idx > 28) { + // 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))]; + grant->phy_grant.ul.mcs.mod = phy->last_ul_mod[UL_PIDOF(TTI_TX(tti))]; 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; } - - /* Limit UL modulation if not supported by the UE or disabled by higher layers */ - if (!phy->config->enable_64qam) { - if (grant->phy_grant.ul.mcs.mod >= SRSLTE_MOD_64QAM) { - grant->phy_grant.ul.mcs.mod = SRSLTE_MOD_16QAM; - grant->phy_grant.ul.Qm = 4; + 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 */ + if (!phy->config->enable_64qam) { + if (grant->phy_grant.ul.mcs.mod >= SRSLTE_MOD_64QAM) { + grant->phy_grant.ul.mcs.mod = SRSLTE_MOD_16QAM; + grant->phy_grant.ul.Qm = 4; + } } } - + /* 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) { Warning("Received invalid UL grant. L=%d\n", grant->phy_grant.ul.L_prb); @@ -768,11 +798,9 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant) if (SRSLTE_VERBOSE_ISINFO()) { srslte_ra_pusch_fprint(stdout, &dci_unpacked, cell.nof_prb); } - - return true; - } else { - return false; - } + } + + return ret; } void phch_worker::reset_uci() diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 880f8e609..96949e94c 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -199,9 +199,10 @@ void phy::set_timeadv_rar(uint32_t ta_cmd) { } void phy::set_timeadv(uint32_t ta_cmd) { - n_ta = srslte_N_ta_new(n_ta, ta_cmd); - sf_recv.set_time_adv_sec(((float) 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); + uint32_t new_nta = srslte_N_ta_new(n_ta, ta_cmd); + sf_recv.set_time_adv_sec(((float) (new_nta - n_ta))*SRSLTE_LTE_TS); + 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() diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index a99281e6f..b7e744bd8 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -32,7 +32,6 @@ #include #include #include -#include using namespace srslte; @@ -58,6 +57,7 @@ bool ue::init(all_args_t *args_) } else { logger_file.init(args->log.filename); logger_file.log("\n\n"); + logger_file.log(get_build_string().c_str()); logger = &logger_file; } @@ -117,7 +117,11 @@ bool ue::init(all_args_t *args_) // Init layers - // PHY initis in background, start before radio + if (args->rf.rx_gain < 0) { + phy.set_agc_enable(true); + } + + // PHY initis in background, start before radio args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant; 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) { radio.start_agc(false); - radio.set_tx_rx_gain_offset(10); - phy.set_agc_enable(true); } else { 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); 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 std::vector earfcn_list; diff --git a/srsue/src/ue_base.cc b/srsue/src/ue_base.cc index 94b9b5155..4b2c372ae 100644 --- a/srsue/src/ue_base.cc +++ b/srsue/src/ue_base.cc @@ -24,13 +24,14 @@ * */ - #include "ue_base.h" #include "ue.h" #include "srslte/srslte.h" +#include "srslte/build_info.h" #include #include #include +#include #include #include @@ -58,6 +59,9 @@ ue_base* ue_base::get_instance(srsue_instance_type_t type) } ue_base::ue_base() { + // print build info + std::cout << std::endl << get_build_string() << std::endl; + // load FFTW wisdom 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 diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 110c8c78e..2b01efcec 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -25,6 +25,11 @@ */ +#include +#include +#include +#include +#include #include "srslte/asn1/liblte_rrc.h" #include "upper/nas.h" #include "srslte/common/bcd_helpers.h" @@ -33,9 +38,78 @@ using namespace srslte; 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(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; ifull_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() - : state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), is_guti_set(false), ip_addr(0), eps_bearer_id(0), - count_ul(0), count_dl(0) {} + : state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), have_guti(false), ip_addr(0), eps_bearer_id(0) +{ + ctxt.rx_count = 0; + ctxt.tx_count = 0; +} void nas::init(usim_interface_nas *usim_, rrc_interface_nas *rrc_, @@ -51,15 +125,26 @@ void nas::init(usim_interface_nas *usim_, state = EMM_STATE_DEREGISTERED; 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"); home_plmn.mcc = 61441; // This is 001 home_plmn.mnc = 65281; // This is 01 } 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() { return state; @@ -207,11 +292,11 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { } 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) { - if (is_guti_set) { + if (have_guti) { s_tmsi->mmec = guti.mme_code; s_tmsi->m_tmsi = guti.m_tmsi; 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 *******************************************************************************/ -void nas::integrity_generate(uint8_t *key_128, +void nas::integrity_generate(uint8_t integ_algo, + uint8_t *key_128, uint32_t count, uint8_t rb_id, 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 @@ -289,8 +399,8 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { //FIXME: Handle tai_list if (attach_accept.guti_present) { memcpy(&guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); - is_guti_set = true; - // TODO: log message to console + have_guti = true; + write_guti_file(guti); } 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; current_plmn = selecting_plmn; - count_dl++; + ctxt.rx_count++; // 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.proc_transaction_id = transaction_id; 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); liblte_mme_pack_attach_complete_msg(&attach_complete, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, - count_ul, + ctxt.tx_count, (LIBLTE_BYTE_MSG_STRUCT *) pdu); - integrity_generate(&k_nas_int[16], - count_ul, + integrity_generate(ctxt.integ_algo, + &k_nas_int[16], + ctxt.tx_count, lcid - 1, SECURITY_DIRECTION_UPLINK, &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"); rrc->write_sdu(lcid, pdu); + ctxt.tx_count++; } else { 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_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); // 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; 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) { 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"); 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) { @@ -451,107 +567,154 @@ void nas::parse_authentication_reject(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) { - bool success; +void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) +{ LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd; 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); + 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; - cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eea; - integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eia; - // FIXME: Handle nonce_ue, nonce_mme - // FIXME: Currently only handling ciphering EEA0 (null) and integrity EIA1,EIA2 - // FIXME: Use selected_nas_sec_algs to choose correct algos + if(sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE) { + nas_log->error("Mapped security context not supported\n"); + pool->deallocate(pdu); + return; + } - nas_log->debug("Security details: ksi=%d, eea=%s, eia=%s\n", - ksi, ciphering_algorithm_id_text[cipher_algo], integrity_algorithm_id_text[integ_algo]); + if(sec_mode_cmd.nas_ksi.nas_ksi != ctxt.ksi) + { + 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 || - (INTEGRITY_ALGORITHM_ID_128_EIA2 != integ_algo && - 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; + // Check capabilities replay + if(!check_cap_replay(&sec_mode_cmd.ue_security_cap)) { nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n"); - success = false; - } else { - // Generate NAS encryption key and integrity protection key - usim->generate_nas_keys(k_nas_enc, k_nas_int, cipher_algo, 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"); - - // Check incoming MAC - uint8_t *inMAC = &pdu->msg[1]; - uint8_t genMAC[4]; - integrity_generate(&k_nas_int[16], - count_dl, - lcid - 1, - SECURITY_DIRECTION_DOWNLINK, - &pdu->msg[5], - pdu->N_bytes - 5, - genMAC); + send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH); + pool->deallocate(pdu); + return; + } - nas_log->info_hex(inMAC, 4, "Incoming PDU MAC:"); - nas_log->info_hex(genMAC, 4, "Generated PDU MAC:"); + // Reset counterd (as per 24.301 5.4.3.2) + ctxt.rx_count = 0; + ctxt.tx_count = 0; - bool match = true; - for (int i = 0; i < 4; i++) { - if (inMAC[i] != genMAC[i]) { - match = false; - } - } - 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"); - success = false; - } else { + 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; - 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.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEISV; - usim->get_imei_vec(sec_mode_comp.imeisv.imeisv, 15); - sec_mode_comp.imeisv.imeisv[14] = 5; - sec_mode_comp.imeisv.imeisv[15] = 3; - } else { - sec_mode_comp.imeisv_present = false; - } + // 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; + } - // Reuse pdu for response - pdu->reset(); - liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp, - LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, - count_ul, - (LIBLTE_BYTE_MSG_STRUCT *) pdu); - integrity_generate(&k_nas_int[16], - count_ul, - lcid - 1, - SECURITY_DIRECTION_UPLINK, - &pdu->msg[5], - pdu->N_bytes - 5, - &pdu->msg[1]); - nas_log->info("Sending Security Mode Complete nas_count_ul=%d, RB=%s\n", - count_ul, - rrc->get_rb_name(lcid).c_str()); - success = true; + // 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_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 + uint8_t *inMAC = &pdu->msg[1]; + uint8_t genMAC[4]; + integrity_generate(ctxt.integ_algo, + &k_nas_int[16], + ctxt.rx_count, + lcid - 1, + SECURITY_DIRECTION_DOWNLINK, + &pdu->msg[5], + pdu->N_bytes - 5, + genMAC); + + nas_log->info_hex(inMAC, 4, "Incoming PDU MAC:"); + nas_log->info_hex(genMAC, 4, "Generated PDU MAC:"); + + ctxt.rx_count++; + + bool match = true; + for (int i = 0; i < 4; i++) { + if (inMAC[i] != genMAC[i]) { + match = false; } } + if(!match) { + nas_log->warning("Sending Security Mode Reject due to integrity check failure\n"); + send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED); + pool->deallocate(pdu); + return; + } - count_dl++; + // Take security context into use + have_ctxt = true; - if (!success) { - // Reuse pdu for response - pdu->reset(); - liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) pdu); + 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.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEISV; + usim->get_imei_vec(sec_mode_comp.imeisv.imeisv, 15); + sec_mode_comp.imeisv.imeisv[14] = 5; + sec_mode_comp.imeisv.imeisv[15] = 3; + } else { + sec_mode_comp.imeisv_present = false; } - rrc->write_sdu(lcid, pdu); + // Send response + byte_buffer_t *sdu = pool_allocate; + liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp, + LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, + ctxt.tx_count, + (LIBLTE_BYTE_MSG_STRUCT *) sdu); + integrity_generate(ctxt.integ_algo, + &k_nas_int[16], + ctxt.tx_count, + lcid - 1, + SECURITY_DIRECTION_UPLINK, + &sdu->msg[5], + sdu->N_bytes - 5, + &sdu->msg[1]); + nas_log->info("Sending Security Mode Complete nas_current_ctxt.tx_count=%d, RB=%s\n", + ctxt.tx_count, + rrc->get_rb_name(lcid).c_str()); + rrc->write_sdu(lcid, sdu); + ctxt.tx_count++; + pool->deallocate(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) { nas_log->error("TODO:parse_esm_information_request\n"); + } 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; for (i = 0; i < 8; i++) { - attach_req.ue_network_cap.eea[i] = false; - attach_req.ue_network_cap.eia[i] = false; + attach_req.ue_network_cap.eea[i] = eea_caps[i]; + 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.uia_present = false; // UMTS integrity algos - - 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.ue_network_cap.uea_present = false; // UMTS encryption 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.old_p_tmsi_signature_present = false; attach_req.additional_guti_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.old_guti_type_present = false; - // Pack the message - liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg); + // 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); + } nas_log->info("Sending attach request\n"); rrc->write_sdu(cfg.lcid, msg); + + if(have_ctxt) { + ctxt.tx_count++; + } } void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) { @@ -640,27 +832,36 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *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_service_request() { byte_buffer_t *msg = pool_allocate; - count_ul++; // Pack the service request message directly msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg->N_bytes++; - msg->msg[1] = (ksi & 0x07) << 5; - msg->msg[1] |= count_ul & 0x1F; + msg->msg[1] = (ctxt.ksi & 0x07) << 5; + msg->msg[1] |= ctxt.tx_count & 0x1F; msg->N_bytes++; uint8_t mac[4]; - integrity_generate(&k_nas_int[16], - count_ul, - cfg.lcid-1, - SECURITY_DIRECTION_UPLINK, - &msg->msg[0], - 2, - &mac[0]); + integrity_generate(ctxt.integ_algo, + &k_nas_int[16], + ctxt.tx_count, + cfg.lcid-1, + SECURITY_DIRECTION_UPLINK, + &msg->msg[0], + 2, + &mac[0]); // Set the short MAC msg->msg[2] = mac[2]; msg->N_bytes++; @@ -668,8 +869,239 @@ void nas::send_service_request() { msg->N_bytes++; nas_log->info("Sending service request\n"); rrc->write_sdu(cfg.lcid, msg); + ctxt.tx_count++; } 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 diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index ecd797a9a..39aa8825d 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -26,12 +26,12 @@ #include +#include #include -#include "srslte/asn1/liblte_rrc.h" +#include +#include #include "upper/rrc.h" -#include -#include -#include +#include "srslte/asn1/liblte_rrc.h" #include "srslte/common/security.h" #include "srslte/common/bcd_helpers.h" @@ -48,6 +48,9 @@ rrc::rrc() :state(RRC_STATE_IDLE) ,drb_up(false) { + sync_reset_cnt = 0; + n310_cnt = 0; + n311_cnt = 0; } 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); + first_stimsi_attempt = 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(); t310 = 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(); measurements.init(this); + // set seed for rand (used in attach) + srand(time(NULL)); } void rrc::stop() { @@ -137,12 +147,8 @@ bool rrc::have_drb() { return drb_up; } -void rrc::set_ue_category(int category) { - if (category >= 1 && category <= 5) { - ue_category = category; - } else { - rrc_log->error("Unsupported UE category %d\n", category); - } +void rrc::set_args(rrc_args_t *args) { + memcpy(&this->args, args, sizeof(rrc_args_t)); } /* @@ -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) 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; if (!mac_timers->timer_get(t311)->is_running() && !mac_timers->timer_get(t310)->is_running()) { n310_cnt++; if (n310_cnt == N310) { - // attempt resync - //phy->sync_reset(); - mac_timers->timer_get(t310)->reset(); mac_timers->timer_get(t310)->run(); n310_cnt = 0; @@ -632,13 +642,15 @@ void rrc::send_con_request() { // Prepare ConnectionRequest packet ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ; + 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.s_tmsi = s_tmsi; } 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.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; 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; 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; - rrc_log->info("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); - 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); + 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.mmec, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi.m_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) { rrc_log->info("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; // 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); send_security_mode_complete(lcid, pdu); break; @@ -1287,7 +1303,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { * *******************************************************************************/ 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"); 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; 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.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.tx_antenna_selection_supported = false; - //TODO: Generate this from user input? - cap->rf_params.N_supported_band_eutras = 3; - cap->rf_params.supported_band_eutra[0].band_eutra = 3; - cap->rf_params.supported_band_eutra[0].half_duplex = false; - cap->rf_params.supported_band_eutra[1].band_eutra = 7; - cap->rf_params.supported_band_eutra[1].half_duplex = false; - cap->rf_params.supported_band_eutra[2].band_eutra = 20; - 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->rf_params.N_supported_band_eutras = args.nof_supported_bands; + cap->meas_params.N_band_list_eutra = args.nof_supported_bands; + for (uint32_t i=0;irf_params.supported_band_eutra[i].band_eutra = args.supported_bands[i]; + cap->rf_params.supported_band_eutra[i].half_duplex = false; + cap->meas_params.band_list_eutra[i].N_inter_freq_need_for_gaps = 1; + cap->meas_params.band_list_eutra[i].inter_freq_need_for_gaps[0] = 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_tdd128_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) { 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) { 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) { diff --git a/srsue/src/upper/usim.cc b/srsue/src/upper/usim.cc index 842f9b361..305da7b25 100644 --- a/srsue/src/upper/usim.cc +++ b/srsue/src/upper/usim.cc @@ -39,9 +39,11 @@ usim::usim() : initiated(false) void usim::init(usim_args_t *args, srslte::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 *imei_str = args->imei.c_str(); + const char *imsi_c = args->imsi.c_str(); + const char *imei_c = args->imei.c_str(); uint32_t i; 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++) { imsi *= 10; - imsi += imsi_str[i] - '0'; + imsi += imsi_c[i] - '0'; } } else { 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++) { imei *= 10; - imei += imei_str[i] - '0'; + imei += imei_c[i] - '0'; } } else { usim_log->error("Invalid length for IMEI: %d should be %d", args->imei.length(), 15); @@ -103,16 +105,25 @@ void usim::stop() 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) { fprintf(stderr, "USIM not initiated!\n"); - return; + return false; } if(NULL == imsi_ || n < 15) { usim_log->error("Invalid parameters to get_imsi_vec"); - return; + return false; } uint64_t temp = imsi; @@ -120,18 +131,19 @@ void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) imsi_[i] = 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) { fprintf(stderr, "USIM not initiated!\n"); - return; + return false; } if(NULL == imei_ || n < 15) { usim_log->error("Invalid parameters to get_imei_vec"); - return; + return false; } uint64 temp = imei; @@ -140,13 +152,14 @@ void usim::get_imei_vec(uint8_t* imei_, uint32_t n) imei_[i] = 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) { fprintf(stderr, "USIM not initiated!\n"); - return -1; + return false; } 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", plmn_id_to_string(*home_plmn_id).c_str()); - return 0; + return true; } 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 mnc, bool *net_valid, - uint8_t *res) + uint8_t *res, + uint8_t *k_asme) { 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 { - 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, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) @@ -214,7 +229,8 @@ void usim::generate_nas_keys(uint8_t *k_nas_enc, 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_int, uint8_t *k_up_enc, @@ -285,7 +301,8 @@ void usim::gen_auth_res_milenage( uint8_t *rand, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res) + uint8_t *res, + uint8_t *k_asme) { uint32_t i; uint8_t sqn[6]; @@ -354,7 +371,8 @@ void usim::gen_auth_res_xor(uint8_t *rand, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res) + uint8_t *res, + uint8_t *k_asme) { uint32_t i; uint8_t sqn[6]; diff --git a/srsue/test/upper/usim_test.cc b/srsue/test/upper/usim_test.cc index c8a248184..00003bc28 100644 --- a/srsue/test/upper/usim_test.cc +++ b/srsue/test/upper/usim_test.cc @@ -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 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 mnc = 93; @@ -74,14 +75,14 @@ int main(int argc, char **argv) usim_args_t args; args.algo = "milenage"; args.amf = "8000"; - args.imei = "35609204079301"; + args.imei = "356092040793011"; args.imsi = "208930000000001"; args.k = "8BAF473F2F8FD09487CCCBD7097C6862"; args.op = "11111111111111111111111111111111"; srsue::usim usim; 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); } diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 5b3559ae9..3373c562f 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -92,19 +92,36 @@ k = 00112233445566778899aabbccddeeff imsi = 001010123456789 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] enable = false ##################################################################### # 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 # 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. -# 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. # cqi_max: Upper bound on the maximum CQI to be reported. Default 15. # cqi_fixed: Fixes the reported CQI to a constant value. Default disabled. @@ -146,7 +163,6 @@ enable = false [expert] #ip_netmask = 255.255.255.0 #rssi_sensor_enabled = false -#ue_category = 4 #prach_gain = 30 #cqi_max = 15 #cqi_fixed = 10 @@ -156,7 +172,7 @@ enable = false #attach_enable_64qam = false #nof_phy_threads = 2 #equalizer_mode = mmse -#cfo_ema = 0.4 +#cfo_ema = 0.3 #cfo_integer_enabled = false #cfo_correct_tol_hz = 50 #time_correct_period = 5