diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index f4e26ea4b..42f5f8b78 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -486,7 +486,9 @@ typedef struct { int worker_cpu_mask = -1; int sync_cpu_affinity = -1; - uint32_t nof_carriers = 1; + uint32_t nof_lte_carriers = 1; + uint32_t nof_nr_carriers = 0; + uint32_t nr_nof_prb = 50; uint32_t nof_rx_ant = 1; std::string equalizer_mode = "mmse"; int cqi_max = 15; diff --git a/lib/include/srslte/phy/common/phy_common_nr.h b/lib/include/srslte/phy/common/phy_common_nr.h index 813db9b12..e07983a95 100644 --- a/lib/include/srslte/phy/common/phy_common_nr.h +++ b/lib/include/srslte/phy/common/phy_common_nr.h @@ -272,6 +272,13 @@ SRSLTE_API uint32_t srslte_coreset_get_bw(const srslte_coreset_t* coreset); */ SRSLTE_API uint32_t srslte_coreset_get_sz(const srslte_coreset_t* coreset); +/** + * @brief Get the NR PDSCH mapping type in string + * @param mapping_type Mapping type + * @return Constant string with PDSCH mapping type + */ +SRSLTE_API const char* srslte_pdsch_mapping_type_to_str(srslte_pdsch_mapping_type_t mapping_type); + /** * @brief Get the MCS table string * @param mcs_table MCS table value diff --git a/lib/include/srslte/phy/phch/pdsch_nr.h b/lib/include/srslte/phy/phch/pdsch_nr.h index f1f3494a3..9a5110f30 100644 --- a/lib/include/srslte/phy/phch/pdsch_nr.h +++ b/lib/include/srslte/phy/phch/pdsch_nr.h @@ -34,6 +34,7 @@ typedef struct SRSLTE_API { srslte_sch_nr_args_t sch; bool measure_evm; + bool measure_time; } srslte_pdsch_args_t; /** @@ -50,6 +51,8 @@ typedef struct SRSLTE_API { cf_t* x[SRSLTE_MAX_LAYERS_NR]; ///< PDSCH modulated bits srslte_modem_table_t modem_tables[SRSLTE_MOD_NITEMS]; ///< Modulator tables srslte_evm_buffer_t* evm_buffer; + bool meas_time_en; + uint32_t meas_time_us; } srslte_pdsch_nr_t; /** @@ -82,16 +85,17 @@ SRSLTE_API int srslte_pdsch_nr_decode(srslte_pdsch_nr_t* q, cf_t* sf_symbols[SRSLTE_MAX_PORTS], srslte_pdsch_res_nr_t data[SRSLTE_MAX_TB]); -SRSLTE_API uint32_t srslte_pdsch_nr_grant_rx_info(srslte_pdsch_grant_nr_t* grant, - srslte_pdsch_res_nr_t res[SRSLTE_MAX_CODEWORDS], - char* str, - uint32_t str_len); - -SRSLTE_API uint32_t srslte_pdsch_nr_rx_info(srslte_pdsch_cfg_nr_t* cfg, - srslte_pdsch_res_nr_t res[SRSLTE_MAX_CODEWORDS], - char* str, - uint32_t str_len); - -SRSLTE_API uint32_t srslte_pdsch_nr_tx_info(srslte_pdsch_cfg_nr_t* cfg, char* str, uint32_t str_len); +SRSLTE_API uint32_t srslte_pdsch_nr_rx_info(const srslte_pdsch_nr_t* q, + const srslte_pdsch_cfg_nr_t* cfg, + const srslte_pdsch_grant_nr_t* grant, + const srslte_pdsch_res_nr_t* res, + char* str, + uint32_t str_len); + +SRSLTE_API uint32_t srslte_pdsch_nr_tx_info(const srslte_pdsch_nr_t* q, + const srslte_pdsch_cfg_nr_t* cfg, + const srslte_pdsch_grant_nr_t* grant, + char* str, + uint32_t str_len); #endif // srslte_pdsch_nr_H diff --git a/lib/include/srslte/phy/phch/sch_nr.h b/lib/include/srslte/phy/phch/sch_nr.h index 863d255ee..3574b2e10 100644 --- a/lib/include/srslte/phy/phch/sch_nr.h +++ b/lib/include/srslte/phy/phch/sch_nr.h @@ -138,4 +138,6 @@ SRSLTE_API int srslte_dlsch_nr_decode(srslte_sch_nr_t* q, uint8_t* data, bool* crc_ok); +SRSLTE_API int srslte_sch_nr_tb_info(const srslte_sch_tb_t* tb, char* str, uint32_t str_len); + #endif // SRSLTE_SCH_NR_H \ No newline at end of file diff --git a/lib/include/srslte/phy/ue/ue_dl_nr.h b/lib/include/srslte/phy/ue/ue_dl_nr.h index a887372cf..de8df64b7 100644 --- a/lib/include/srslte/phy/ue/ue_dl_nr.h +++ b/lib/include/srslte/phy/ue/ue_dl_nr.h @@ -24,6 +24,7 @@ extern "C" { typedef struct SRSLTE_API { srslte_pdsch_args_t pdsch; uint32_t nof_rx_antennas; + uint32_t nof_max_prb; } srslte_ue_dl_nr_args_t; typedef struct SRSLTE_API { @@ -53,6 +54,14 @@ SRSLTE_API int srslte_ue_dl_nr_pdsch_get(srslte_ue_dl_nr_t* q, const srslte_pdsch_cfg_nr_t* cfg, const srslte_pdsch_grant_nr_t* grant, srslte_pdsch_res_nr_t* res); + +SRSLTE_API int srslte_ue_dl_nr_pdsch_info(const srslte_ue_dl_nr_t* q, + const srslte_pdsch_cfg_nr_t* cfg, + const srslte_pdsch_grant_nr_t* grant, + const srslte_pdsch_res_nr_t res[SRSLTE_MAX_CODEWORDS], + char* str, + uint32_t str_len); + #ifdef __cplusplus } #endif diff --git a/lib/src/phy/ch_estimation/dmrs_pdsch.c b/lib/src/phy/ch_estimation/dmrs_pdsch.c index 0c2ff10d5..979f0f957 100644 --- a/lib/src/phy/ch_estimation/dmrs_pdsch.c +++ b/lib/src/phy/ch_estimation/dmrs_pdsch.c @@ -424,6 +424,7 @@ int srslte_dmrs_pdsch_get_N_prb(const srslte_pdsch_cfg_nr_t* cfg, const srslte_p uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS] = {}; int ret = srslte_dmrs_pdsch_get_symbols_idx(cfg, grant, symbols); if (ret < SRSLTE_SUCCESS) { + ERROR("Error getting PDSCH DMRS symbol indexes\n"); return SRSLTE_ERROR; } @@ -667,7 +668,8 @@ int srslte_dmrs_pdsch_estimate(srslte_dmrs_pdsch_t* q, // Get symbols indexes uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS] = {}; int nof_symbols = srslte_dmrs_pdsch_get_symbols_idx(pdsch_cfg, grant, symbols); - if (nof_symbols < SRSLTE_SUCCESS) { + if (nof_symbols <= SRSLTE_SUCCESS) { + ERROR("Error getting symbol indexes\n"); return SRSLTE_ERROR; } @@ -681,6 +683,11 @@ int srslte_dmrs_pdsch_estimate(srslte_dmrs_pdsch_t* q, nof_pilots_x_symbol = srslte_dmrs_pdsch_get_symbol( q, pdsch_cfg, grant, cinit, delta, &sf_symbols[symbol_sz * l], &q->pilot_estimates[nof_pilots_x_symbol * i]); + + if (nof_pilots_x_symbol == 0) { + ERROR("Error, no pilots extracted (i=%d, l=%d)\n", i, l); + return SRSLTE_ERROR; + } } // Perform measurements here @@ -700,14 +707,20 @@ int srslte_dmrs_pdsch_estimate(srslte_dmrs_pdsch_t* q, (dmrs_cfg->type == srslte_dmrs_pdsch_type_1) ? nof_pilots_x_symbol * 2 : nof_pilots_x_symbol * 3; if (dmrs_cfg->type == srslte_dmrs_pdsch_type_1) { // Prepare interpolator - srslte_interp_linear_resize(&q->interpolator_type1, nof_pilots_x_symbol, 2); + if (srslte_interp_linear_resize(&q->interpolator_type1, nof_pilots_x_symbol, 2) < SRSLTE_SUCCESS) { + ERROR("Resizing interpolator nof_pilots_x_symbol=%d; M=%d;\n", nof_pilots_x_symbol, 2); + return SRSLTE_ERROR; + } // Interpolate srslte_interp_linear_offset(&q->interpolator_type1, q->pilot_estimates, ce, delta, 2 - delta); } else { // Prepare interpolator - srslte_interp_linear_resize(&q->interpolator_type2, nof_pilots_x_symbol, 3); + if (srslte_interp_linear_resize(&q->interpolator_type2, nof_pilots_x_symbol, 3) < SRSLTE_SUCCESS) { + ERROR("Resizing interpolator nof_pilots_x_symbol=%d; M=%d;\n", nof_pilots_x_symbol, 3); + return SRSLTE_ERROR; + } // Interpolate srslte_interp_linear_offset(&q->interpolator_type2, q->pilot_estimates, ce, delta, 3 - delta); diff --git a/lib/src/phy/common/phy_common_nr.c b/lib/src/phy/common/phy_common_nr.c index 8ddf8b12c..86e5b2c41 100644 --- a/lib/src/phy/common/phy_common_nr.c +++ b/lib/src/phy/common/phy_common_nr.c @@ -35,10 +35,21 @@ uint32_t srslte_coreset_get_sz(const srslte_coreset_t* coreset) return srslte_coreset_get_bw(coreset) * SRSLTE_NRE * coreset->duration; } +const char* srslte_pdsch_mapping_type_to_str(srslte_pdsch_mapping_type_t mapping_type) +{ + switch (mapping_type) { + case srslte_pdsch_mapping_type_A: + return "A"; + case srslte_pdsch_mapping_type_B: + return "B"; + default: + return "undefined"; + } +} + const char* srslte_mcs_table_to_str(srslte_mcs_table_t mcs_table) { switch (mcs_table) { - case srslte_mcs_table_64qam: return "64qam"; case srslte_mcs_table_256qam: diff --git a/lib/src/phy/phch/pdsch_nr.c b/lib/src/phy/phch/pdsch_nr.c index f60769311..566a01ba2 100644 --- a/lib/src/phy/phch/pdsch_nr.c +++ b/lib/src/phy/phch/pdsch_nr.c @@ -69,6 +69,8 @@ int srslte_pdsch_nr_init_ue(srslte_pdsch_nr_t* q, const srslte_pdsch_args_t* arg } } + q->meas_time_en = args->measure_time; + return SRSLTE_SUCCESS; } @@ -427,13 +429,17 @@ int srslte_pdsch_nr_encode(srslte_pdsch_nr_t* q, uint8_t* data[SRSLTE_MAX_TB], cf_t* sf_symbols[SRSLTE_MAX_PORTS]) { - uint32_t nof_cw = 0; // Check input pointers if (!q || !cfg || !grant || !data || !sf_symbols) { return SRSLTE_ERROR_INVALID_INPUTS; } + struct timeval t[3]; + if (q->meas_time_en) { + gettimeofday(&t[1], NULL); + } + // Check number of layers if (q->max_layers < grant->nof_layers) { ERROR("Error number of layers (%d) exceeds configured maximum (%d)\n", grant->nof_layers, q->max_layers); @@ -441,6 +447,7 @@ int srslte_pdsch_nr_encode(srslte_pdsch_nr_t* q, } // 7.3.1.1 and 7.3.1.2 + uint32_t nof_cw = 0; for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { nof_cw += grant->tb[tb].enabled ? 1 : 0; @@ -466,6 +473,12 @@ int srslte_pdsch_nr_encode(srslte_pdsch_nr_t* q, // 7.3.1.6 Mapping from virtual to physical resource blocks srslte_pdsch_nr_put(q, cfg, grant, x[0], sf_symbols[0]); + if (q->meas_time_en) { + gettimeofday(&t[2], NULL); + get_time_interval(t); + q->meas_time_us = (uint32_t)t[0].tv_usec; + } + return SRSLTE_SUCCESS; } @@ -542,6 +555,16 @@ int srslte_pdsch_nr_decode(srslte_pdsch_nr_t* q, cf_t* sf_symbols[SRSLTE_MAX_PORTS], srslte_pdsch_res_nr_t data[SRSLTE_MAX_TB]) { + // Check input pointers + if (!q || !cfg || !grant || !data || !sf_symbols) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + struct timeval t[3]; + if (q->meas_time_en) { + gettimeofday(&t[1], NULL); + } + uint32_t nof_cw = 0; for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { nof_cw += grant->tb[tb].enabled ? 1 : 0; @@ -591,5 +614,113 @@ int srslte_pdsch_nr_decode(srslte_pdsch_nr_t* q, } } + if (q->meas_time_en) { + gettimeofday(&t[2], NULL); + get_time_interval(t); + q->meas_time_us = (uint32_t)t[0].tv_usec; + } + return SRSLTE_SUCCESS; } + +static uint32_t srslte_pdsch_nr_grant_info(const srslte_pdsch_cfg_nr_t* cfg, + const srslte_pdsch_grant_nr_t* grant, + char* str, + uint32_t str_len) +{ + uint32_t len = 0; + len = srslte_print_check(str, str_len, len, "rnti=0x%x", grant->rnti); + + // Append time-domain resource mapping + len = srslte_print_check(str, + str_len, + len, + ",k0=%d,S=%d,L=%d,mapping=%s", + grant->k0, + grant->S, + grant->L, + srslte_pdsch_mapping_type_to_str(grant->mapping)); + + // Skip frequency domain resources... + // ... + + // Append spatial resources + len = srslte_print_check(str, str_len, len, ",Nl=%d", grant->nof_layers); + + // Append scrambling ID + len = srslte_print_check(str, str_len, len, ",n_scid=%d", grant->n_scid); + + // Append TB info + for (uint32_t i = 0; i < SRSLTE_MAX_TB; i++) { + len += srslte_sch_nr_tb_info(&grant->tb[i], &str[len], str_len - len); + } + + return len; +} + +uint32_t srslte_pdsch_nr_rx_info(const srslte_pdsch_nr_t* q, + const srslte_pdsch_cfg_nr_t* cfg, + const srslte_pdsch_grant_nr_t* grant, + const srslte_pdsch_res_nr_t res[SRSLTE_MAX_CODEWORDS], + char* str, + uint32_t str_len) +{ + + uint32_t len = 0; + + len += srslte_pdsch_nr_grant_info(cfg, grant, &str[len], str_len - len); + + if (q->evm_buffer != NULL) { + len = srslte_print_check(str, str_len, len, ",evm={", 0); + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (grant->tb[i].enabled && !isnan(res[i].evm)) { + len = srslte_print_check(str, str_len, len, "%.2f", res[i].evm); + if (i < SRSLTE_MAX_CODEWORDS - 1) { + if (grant->tb[i + 1].enabled) { + len = srslte_print_check(str, str_len, len, ",", 0); + } + } + } + } + len = srslte_print_check(str, str_len, len, "}", 0); + } + + if (res != NULL) { + len = srslte_print_check(str, str_len, len, ",crc={", 0); + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (grant->tb[i].enabled) { + len = srslte_print_check(str, str_len, len, "%s", res[i].crc ? "OK" : "KO"); + if (i < SRSLTE_MAX_CODEWORDS - 1) { + if (grant->tb[i + 1].enabled) { + len = srslte_print_check(str, str_len, len, ",", 0); + } + } + } + } + len = srslte_print_check(str, str_len, len, "}", 0); + } + + if (q->meas_time_en) { + len = srslte_print_check(str, str_len, len, ", t=%d us\n", q->meas_time_us); + } + + return len; +} + +uint32_t srslte_pdsch_nr_tx_info(const srslte_pdsch_nr_t* q, + const srslte_pdsch_cfg_nr_t* cfg, + const srslte_pdsch_grant_nr_t* grant, + char* str, + uint32_t str_len) +{ + + uint32_t len = 0; + + len += srslte_pdsch_nr_grant_info(cfg, grant, &str[len], str_len - len); + + if (q->meas_time_en) { + len = srslte_print_check(str, str_len, len, ", t=%d us\n", q->meas_time_us); + } + + return len; +} diff --git a/lib/src/phy/phch/ra_nr.c b/lib/src/phy/phch/ra_nr.c index 79a93a615..615001818 100644 --- a/lib/src/phy/phch/ra_nr.c +++ b/lib/src/phy/phch/ra_nr.c @@ -208,6 +208,7 @@ int srslte_ra_dl_nr_slot_nof_re(const srslte_pdsch_cfg_nr_t* pdsch_cfg, const sr // the number of REs for DM-RS per PRB in the scheduled duration int n_prb_dmrs = srslte_dmrs_pdsch_get_N_prb(pdsch_cfg, grant); if (n_prb_dmrs < SRSLTE_SUCCESS) { + ERROR("Invalid number of DMRS RE\n"); return SRSLTE_ERROR; } @@ -358,7 +359,8 @@ int srslte_ra_nr_fill_tb(const srslte_pdsch_cfg_nr_t* pdsch_cfg, // 1) The UE shall first determine the number of REs (N RE ) within the slot. int N_re = srslte_ra_dl_nr_slot_nof_re(pdsch_cfg, grant); - if (N_re < SRSLTE_SUCCESS) { + if (N_re <= SRSLTE_SUCCESS) { + ERROR("Invalid number of RE\n"); return SRSLTE_ERROR; } diff --git a/lib/src/phy/phch/sch_nr.c b/lib/src/phy/phch/sch_nr.c index f3d7a5945..d89850698 100644 --- a/lib/src/phy/phch/sch_nr.c +++ b/lib/src/phy/phch/sch_nr.c @@ -639,3 +639,25 @@ int srslte_dlsch_nr_decode(srslte_sch_nr_t* q, return SRSLTE_SUCCESS; } + +int srslte_sch_nr_tb_info(const srslte_sch_tb_t* tb, char* str, uint32_t str_len) +{ + int len = 0; + + if (tb->enabled) { + len += srslte_print_check(str, + str_len, + len, + "tb={mod=%s,Nl=%d,TBS=%d,R=%.3f,rv=%d,Nre=%d,Nbit=%d,cw=%d}", + srslte_mod_string(tb->mod), + tb->N_L, + tb->tbs, + tb->R, + tb->rv, + tb->nof_re, + tb->nof_bits, + tb->cw_idx); + } + + return len; +} \ No newline at end of file diff --git a/lib/src/phy/ue/ue_dl_nr.c b/lib/src/phy/ue/ue_dl_nr.c index 7965a69c8..25b0f9112 100644 --- a/lib/src/phy/ue/ue_dl_nr.c +++ b/lib/src/phy/ue/ue_dl_nr.c @@ -55,14 +55,14 @@ int srslte_ue_dl_nr_init(srslte_ue_dl_nr_t* q, cf_t* input[SRSLTE_MAX_PORTS], co return SRSLTE_ERROR; } - if (ue_dl_alloc_prb(q, SRSLTE_MAX_PRB_NR)) { + if (ue_dl_alloc_prb(q, args->nof_max_prb)) { ERROR("Error allocating\n"); return SRSLTE_ERROR; } srslte_ofdm_cfg_t fft_cfg = {}; - fft_cfg.nof_prb = 100; - fft_cfg.symbol_sz = srslte_symbol_sz(100); + fft_cfg.nof_prb = args->nof_max_prb; + fft_cfg.symbol_sz = srslte_symbol_sz(args->nof_max_prb); fft_cfg.keep_dc = true; for (uint32_t i = 0; i < q->nof_rx_antennas; i++) { @@ -153,5 +153,29 @@ int srslte_ue_dl_nr_pdsch_get(srslte_ue_dl_nr_t* q, return SRSLTE_ERROR; } + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + char str[512]; + srslte_ue_dl_nr_pdsch_info(q, cfg, grant, res, str, sizeof(str)); + INFO("PDSCH: %s\n", str); + } + return SRSLTE_SUCCESS; } + +int srslte_ue_dl_nr_pdsch_info(const srslte_ue_dl_nr_t* q, + const srslte_pdsch_cfg_nr_t* cfg, + const srslte_pdsch_grant_nr_t* grant, + const srslte_pdsch_res_nr_t* res, + char* str, + uint32_t str_len) +{ + int len = 0; + + // Append channel estimator info + // ... + + // Append PDSCH info + len += srslte_pdsch_nr_rx_info(&q->pdsch, cfg, grant, res, &str[len], str_len - len); + + return len; +} \ No newline at end of file diff --git a/lib/test/phy/phy_dl_nr_test.c b/lib/test/phy/phy_dl_nr_test.c index f36dff7fb..2a6f1501e 100644 --- a/lib/test/phy/phy_dl_nr_test.c +++ b/lib/test/phy/phy_dl_nr_test.c @@ -94,8 +94,10 @@ int main(int argc, char** argv) srslte_ue_dl_nr_args_t ue_dl_args = {}; ue_dl_args.nof_rx_antennas = 1; + ue_dl_args.nof_max_prb = carrier.nof_prb; ue_dl_args.pdsch.sch.disable_simd = true; ue_dl_args.pdsch.measure_evm = true; + ue_dl_args.pdsch.measure_time = true; srslte_enb_dl_nr_args_t enb_dl_args = {}; enb_dl_args.nof_tx_antennas = 1; @@ -108,10 +110,6 @@ int main(int argc, char** argv) goto clean_exit; } - srslte_pdsch_args_t pdsch_args = {}; - pdsch_args.sch.disable_simd = true; - pdsch_args.measure_evm = true; - if (srslte_ue_dl_nr_init(&ue_dl, &buffer, &ue_dl_args)) { ERROR("Error UE DL\n"); goto clean_exit; diff --git a/srsue/hdr/phy/nr/cc_worker.h b/srsue/hdr/phy/nr/cc_worker.h index 29a863a0f..bff0e0d13 100644 --- a/srsue/hdr/phy/nr/cc_worker.h +++ b/srsue/hdr/phy/nr/cc_worker.h @@ -33,7 +33,6 @@ namespace nr { typedef struct { uint32_t nof_carriers; - uint32_t max_prb; srslte_ue_dl_nr_args_t dl; } phy_nr_args_t; @@ -50,9 +49,10 @@ public: phy_nr_state() { args.nof_carriers = 1; - args.max_prb = SRSLTE_MAX_PRB; args.dl.nof_rx_antennas = 1; + args.dl.nof_max_prb = 100; args.dl.pdsch.measure_evm = true; + args.dl.pdsch.measure_time = true; args.dl.pdsch.sch.disable_simd = true; } }; @@ -72,12 +72,13 @@ public: bool work_dl(); private: - srslte_dl_slot_cfg_t dl_slot_cfg = {}; - uint32_t cc_idx = 0; - std::array, SRSLTE_MAX_PORTS> rx_buffer = {}; - std::array, SRSLTE_MAX_PORTS> tx_buffer = {}; - phy_nr_state* phy_state; - srslte_ue_dl_nr_t ue_dl = {}; + srslte_dl_slot_cfg_t dl_slot_cfg = {}; + uint32_t cc_idx = 0; + std::array rx_buffer = {}; + std::array tx_buffer = {}; + phy_nr_state* phy_state = nullptr; + srslte_ue_dl_nr_t ue_dl = {}; + srslte::log* log_h = nullptr; // Temporal attributes srslte_softbuffer_rx_t softbuffer_rx = {}; diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index 60fdbf0a6..e386e4a7a 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -25,6 +25,7 @@ #include "srslte/radio/radio.h" #include "srslte/srslte.h" #include "srsue/hdr/phy/lte/worker_pool.h" +#include "srsue/hdr/phy/nr/worker_pool.h" #include "srsue/hdr/phy/ue_lte_phy_base.h" #include "sync.h" @@ -66,7 +67,8 @@ private: class phy final : public ue_lte_phy_base, public srslte::thread { public: - explicit phy(srslte::logger* logger_) : logger(logger_), lte_workers(MAX_WORKERS), common(), thread("PHY"){}; + explicit phy(srslte::logger* logger_) : + logger(logger_), lte_workers(MAX_WORKERS), nr_workers(MAX_WORKERS), common(), thread("PHY"){}; ~phy() final { stop(); } // Init defined in base class @@ -177,6 +179,7 @@ private: srsue::stack_interface_phy_lte* stack = nullptr; lte::worker_pool lte_workers; + nr::worker_pool nr_workers; phy_common common; sync sfsync; prach prach_buffer; diff --git a/srsue/hdr/phy/sync.h b/srsue/hdr/phy/sync.h index 8cf5c8320..ed27bab4f 100644 --- a/srsue/hdr/phy/sync.h +++ b/srsue/hdr/phy/sync.h @@ -33,6 +33,7 @@ #include "srslte/phy/channel/channel.h" #include "srslte/srslte.h" #include "srsue/hdr/phy/lte/worker_pool.h" +#include "srsue/hdr/phy/nr/worker_pool.h" #include "sync_state.h" namespace srsue { @@ -52,7 +53,8 @@ public: void init(srslte::radio_interface_phy* radio_, stack_interface_phy_lte* _stack, prach* prach_buffer, - lte::worker_pool* _workers_pool, + lte::worker_pool* _lte_workers_pool, + nr::worker_pool* _nr_workers_pool, phy_common* _worker_com, srslte::log* _log_h, srslte::log* _log_phy_lib_h, @@ -161,10 +163,12 @@ private: /** * Helper method, executed when the UE is camping and in-sync - * @param worker Selected worker for the current TTI + * @param lte_worker Selected LTE worker for the current TTI + * @param nr_worker Selected NR worker for the current TTI * @param sync_buffer Sub-frame buffer for the current TTI */ - void run_camping_in_sync_state(lte::sf_worker* worker, srslte::rf_buffer_t& sync_buffer); + void + run_camping_in_sync_state(lte::sf_worker* lte_worker, nr::sf_worker* nr_worker, srslte::rf_buffer_t& sync_buffer); /** * Helper method, executed in a TTI basis for signaling to the stack a new TTI execution @@ -197,7 +201,8 @@ private: stack_interface_phy_lte* stack = nullptr; srslte::log* log_h = nullptr; srslte::log* log_phy_lib_h = nullptr; - lte::worker_pool* workers_pool = nullptr; + lte::worker_pool* lte_worker_pool = nullptr; + nr::worker_pool* nr_worker_pool = nullptr; srslte::radio_interface_phy* radio_h = nullptr; phy_common* worker_com = nullptr; prach* prach_buffer = nullptr; diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 261d4310f..12da698d0 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -426,6 +426,8 @@ static int parse_args(all_args_t* args, int argc, char* argv[]) ("vnf.type", bpo::value(&args->phy.vnf_args.type)->default_value("ue"), "VNF instance type [gnb,ue]") ("vnf.addr", bpo::value(&args->phy.vnf_args.bind_addr)->default_value("localhost"), "Address to bind VNF interface") ("vnf.port", bpo::value(&args->phy.vnf_args.bind_port)->default_value(3334), "Bind port") + ("nr.nof_carriers", bpo::value(&args->phy.nof_nr_carriers)->default_value(1), "Number of NR carriers") + ("nr.nof_prb", bpo::value(&args->phy.nr_nof_prb)->default_value(50), "NR carrier bandwidth") ; // Positional options - config file location diff --git a/srsue/src/phy/lte/cc_worker.cc b/srsue/src/phy/lte/cc_worker.cc index 04ac1e212..9b9f8aa6d 100644 --- a/srsue/src/phy/lte/cc_worker.cc +++ b/srsue/src/phy/lte/cc_worker.cc @@ -839,7 +839,7 @@ void cc_worker::set_uci_ack(srslte_uci_data_t* uci_data, uint32_t nof_configured_carriers = 0; // Only PCell generates ACK for all SCell - for (uint32_t i = 0; i < phy->args->nof_carriers; i++) { + for (uint32_t i = 0; i < phy->args->nof_lte_carriers; i++) { if (phy->cell_state.is_configured(i)) { phy->get_dl_pending_ack(&sf_cfg_ul, i, &ack_info.cc[i]); nof_configured_carriers++; diff --git a/srsue/src/phy/lte/sf_worker.cc b/srsue/src/phy/lte/sf_worker.cc index 4b788ad1f..4ac2bd2e2 100644 --- a/srsue/src/phy/lte/sf_worker.cc +++ b/srsue/src/phy/lte/sf_worker.cc @@ -53,14 +53,14 @@ sf_worker::sf_worker(uint32_t max_prb, phy_common* phy_, srslte::log* log_h_) log_h = log_h_; // ue_sync in phy.cc requires a buffer for 3 subframes - for (uint32_t r = 0; r < phy->args->nof_carriers; r++) { + for (uint32_t r = 0; r < phy->args->nof_lte_carriers; r++) { cc_workers.push_back(new cc_worker(r, max_prb, phy, log_h)); } } sf_worker::~sf_worker() { - for (uint32_t r = 0; r < phy->args->nof_carriers; r++) { + for (uint32_t r = 0; r < phy->args->nof_lte_carriers; r++) { delete cc_workers[r]; } } @@ -214,8 +214,8 @@ void sf_worker::work_imp() // Fill periodic CQI data; In case of periodic CSI report collision, lower carrier index have preference, so // stop as soon as either CQI data is enabled or RI is carried - for (uint32_t carrier_idx = 0; - carrier_idx < phy->args->nof_carriers and not uci_data.cfg.cqi.data_enable and uci_data.cfg.cqi.ri_len == 0; + for (uint32_t carrier_idx = 0; carrier_idx < phy->args->nof_lte_carriers and not uci_data.cfg.cqi.data_enable and + uci_data.cfg.cqi.ri_len == 0; carrier_idx++) { if (phy->cell_state.is_active(carrier_idx, TTI_TX(tti))) { cc_workers[carrier_idx]->set_uci_periodic_cqi(&uci_data); @@ -223,7 +223,7 @@ void sf_worker::work_imp() } // Loop through all carriers - for (uint32_t carrier_idx = 0; carrier_idx < phy->args->nof_carriers; carrier_idx++) { + for (uint32_t carrier_idx = 0; carrier_idx < phy->args->nof_lte_carriers; carrier_idx++) { if (phy->cell_state.is_active(carrier_idx, tti)) { tx_signal_ready |= cc_workers[carrier_idx]->work_ul(uci_cc_idx == carrier_idx ? &uci_data : nullptr); diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index e01a9769e..ff98b61ea 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -26,17 +26,19 @@ namespace srsue { namespace nr { cc_worker::cc_worker(uint32_t cc_idx_, srslte::log* log, phy_nr_state* phy_state_) : - cc_idx(cc_idx_), phy_state(phy_state_) + cc_idx(cc_idx_), phy_state(phy_state_), log_h(log) { cf_t* buffer_c[SRSLTE_MAX_PORTS] = {}; // Allocate buffers - for (uint32_t i = 0; phy_state_->args.dl.nof_rx_antennas; i++) { - rx_buffer[i].resize(SRSLTE_SF_LEN_PRB(phy_state->args.max_prb)); - buffer_c[i] = rx_buffer[i].data(); + uint32_t sf_len = SRSLTE_SF_LEN_PRB(phy_state->args.dl.nof_max_prb); + for (uint32_t i = 0; i < phy_state_->args.dl.nof_rx_antennas; i++) { + rx_buffer[i] = srslte_vec_cf_malloc(sf_len); + tx_buffer[i] = srslte_vec_cf_malloc(sf_len); + buffer_c[i] = rx_buffer[i]; } - if (srslte_ue_dl_nr_init(&ue_dl, buffer_c, &phy_state_->args.dl)) { + if (srslte_ue_dl_nr_init(&ue_dl, buffer_c, &phy_state_->args.dl) < SRSLTE_SUCCESS) { ERROR("Error initiating UE DL NR\n"); return; } @@ -46,18 +48,29 @@ cc_worker::cc_worker(uint32_t cc_idx_, srslte::log* log, phy_nr_state* phy_state ERROR("Error init soft-buffer\n"); return; } - data.resize(SRSLTE_SCH_NR_MAX_NOF_CB_LDPC * SRSLTE_LDPC_MAX_LEN_ENCODED_CB); + data.resize(SRSLTE_SCH_NR_MAX_NOF_CB_LDPC * SRSLTE_LDPC_MAX_LEN_ENCODED_CB / 8); } cc_worker::~cc_worker() { srslte_ue_dl_nr_free(&ue_dl); srslte_softbuffer_rx_free(&softbuffer_rx); + for (cf_t* p : rx_buffer) { + if (p != nullptr) { + free(p); + } + } + for (cf_t* p : tx_buffer) { + if (p != nullptr) { + free(p); + } + } } bool cc_worker::set_carrier(const srslte_carrier_nr_t* carrier) { if (srslte_ue_dl_nr_set_carrier(&ue_dl, carrier) < SRSLTE_SUCCESS) { + ERROR("Error setting carrier\n"); return false; } @@ -75,7 +88,7 @@ cf_t* cc_worker::get_rx_buffer(uint32_t antenna_idx) return nullptr; } - return rx_buffer.at(antenna_idx).data(); + return rx_buffer.at(antenna_idx); } uint32_t cc_worker::get_buffer_len() @@ -85,9 +98,9 @@ uint32_t cc_worker::get_buffer_len() bool cc_worker::work_dl() { - srslte_pdsch_grant_nr_t pdsch_grant = {}; - srslte_pdsch_cfg_nr_t pdsch_cfg = phy_state->cfg.pdsch; - srslte_pdsch_res_nr_t pdsch_res = {}; + srslte_pdsch_grant_nr_t pdsch_grant = {}; + srslte_pdsch_cfg_nr_t pdsch_cfg = phy_state->cfg.pdsch; + std::array pdsch_res = {}; // Use grant default A time resources with m=0 if (srslte_ue_dl_nr_pdsch_time_resource_default_A(0, pdsch_cfg.dmrs_cfg_typeA.typeA_pos, &pdsch_grant) < @@ -97,27 +110,35 @@ bool cc_worker::work_dl() } pdsch_grant.nof_layers = ue_dl.carrier.max_mimo_layers; pdsch_grant.dci_format = srslte_dci_format_nr_1_0; + pdsch_grant.rnti = 0x1234; for (uint32_t i = 0; i < ue_dl.carrier.nof_prb; i++) { pdsch_grant.prb_idx[i] = true; } - if (srslte_ra_nr_fill_tb(&pdsch_cfg, &pdsch_grant, 20, &pdsch_grant.tb[0]) < SRSLTE_SUCCESS) { + if (srslte_ra_nr_fill_tb(&pdsch_cfg, &pdsch_grant, 27, &pdsch_grant.tb[0]) < SRSLTE_SUCCESS) { ERROR("Error filing tb\n"); return false; } - pdsch_res.payload = data.data(); + pdsch_res[0].payload = data.data(); pdsch_grant.tb[0].softbuffer.rx = &softbuffer_rx; srslte_softbuffer_rx_reset(pdsch_grant.tb[0].softbuffer.rx); srslte_ue_dl_nr_estimate_fft(&ue_dl); - if (srslte_ue_dl_nr_pdsch_get(&ue_dl, &dl_slot_cfg, &pdsch_cfg, &pdsch_grant, &pdsch_res) < SRSLTE_SUCCESS) { + if (srslte_ue_dl_nr_pdsch_get(&ue_dl, &dl_slot_cfg, &pdsch_cfg, &pdsch_grant, pdsch_res.data()) < SRSLTE_SUCCESS) { ERROR("Error decoding PDSCH\n"); return false; } + // Logging + if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) { + char str[512]; + srslte_ue_dl_nr_pdsch_info(&ue_dl, &pdsch_cfg, &pdsch_grant, pdsch_res.data(), str, sizeof(str)); + log_h->info("PDSCH: cc=%d, %s\n", cc_idx, str); + } + return true; } diff --git a/srsue/src/phy/nr/sf_worker.cc b/srsue/src/phy/nr/sf_worker.cc index 7d3693003..d1eaf8498 100644 --- a/srsue/src/phy/nr/sf_worker.cc +++ b/srsue/src/phy/nr/sf_worker.cc @@ -69,5 +69,5 @@ void sf_worker::work_imp() } } -}; // namespace nr -}; // namespace srsue \ No newline at end of file +} // namespace nr +} // namespace srsue \ No newline at end of file diff --git a/srsue/src/phy/nr/worker_pool.cc b/srsue/src/phy/nr/worker_pool.cc index 9fcf7cc45..cf3e5a289 100644 --- a/srsue/src/phy/nr/worker_pool.cc +++ b/srsue/src/phy/nr/worker_pool.cc @@ -27,6 +27,15 @@ worker_pool::worker_pool(uint32_t max_workers) : pool(max_workers) {} bool worker_pool::init(phy_common* common, srslte::logger* logger, int prio) { + // Set NR arguments + phy_state.args.nof_carriers = common->args->nof_nr_carriers; + phy_state.args.dl.nof_max_prb = common->args->nr_nof_prb; + + // Skip init of workers if no NR carriers + if (phy_state.args.nof_carriers == 0) { + return true; + } + // Create logs // Create array of pointers to phy_logs for (uint32_t i = 0; i < common->args->nof_phy_threads; i++) { @@ -41,9 +50,17 @@ bool worker_pool::init(phy_common* common, srslte::logger* logger, int prio) // Add workers to workers pool and start threads for (uint32_t i = 0; i < common->args->nof_phy_threads; i++) { - auto w = std::unique_ptr(new sf_worker(common, &phy_state, (srslte::log*)log_vec[i].get())); - pool.init_worker(i, w.get(), prio, common->args->worker_cpu_mask); - workers.push_back(std::move(w)); + auto w = new sf_worker(common, &phy_state, (srslte::log*)log_vec[i].get()); + pool.init_worker(i, w, prio, common->args->worker_cpu_mask); + workers.push_back(std::unique_ptr(w)); + + srslte_carrier_nr_t c = {}; + c.nof_prb = phy_state.args.dl.nof_max_prb; + c.max_mimo_layers = 1; + + if (not w->set_carrier_unlocked(0, &c)) { + return false; + } } return true; @@ -69,5 +86,5 @@ void worker_pool::stop() pool.stop(); } -}; // namespace nr -}; // namespace srsue \ No newline at end of file +} // namespace nr +} // namespace srsue \ No newline at end of file diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index a491d0659..b14d1f994 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -157,12 +157,14 @@ void phy::run_thread() // Initialise workers lte_workers.init(&common, logger, WORKERS_THREAD_PRIO); + nr_workers.init(&common, logger, WORKERS_THREAD_PRIO); // Warning this must be initialized after all workers have been added to the pool sfsync.init(radio, stack, &prach_buffer, <e_workers, + &nr_workers, &common, log_h.get(), log_phy_lib_h.get(), @@ -198,6 +200,7 @@ void phy::stop() if (is_configured) { sfsync.stop(); lte_workers.stop(); + nr_workers.stop(); prach_buffer.stop(); wait_thread_finish(); @@ -213,7 +216,7 @@ void phy::get_metrics(phy_metrics_t* m) m->info[0].pci = cell.id; m->info[0].dl_earfcn = dl_earfcn; - for (uint32_t i = 1; i < args.nof_carriers; i++) { + for (uint32_t i = 1; i < args.nof_lte_carriers; i++) { m->info[i].dl_earfcn = common.cell_state.get_earfcn(i); m->info[i].pci = common.cell_state.get_pci(i); } @@ -222,7 +225,7 @@ void phy::get_metrics(phy_metrics_t* m) common.get_dl_metrics(m->dl); common.get_ul_metrics(m->ul); common.get_sync_metrics(m->sync); - m->nof_active_cc = args.nof_carriers; + m->nof_active_cc = args.nof_lte_carriers; } void phy::set_timeadv_rar(uint32_t ta_cmd) @@ -455,7 +458,7 @@ bool phy::set_config(srslte::phy_cfg_t config_, uint32_t cc_idx) } // Check parameters are valid - if (cc_idx >= args.nof_carriers) { + if (cc_idx >= args.nof_lte_carriers) { srslte::console("Received SCell configuration for index %d but there are not enough CC workers available\n", cc_idx); return false; @@ -510,7 +513,7 @@ bool phy::set_scell(srslte_cell_t cell_info, uint32_t cc_idx, uint32_t earfcn) } // Check parameters are valid - if (cc_idx >= args.nof_carriers) { + if (cc_idx >= args.nof_lte_carriers) { srslte::console("Received SCell configuration for index %d but there are not enough CC workers available\n", cc_idx); return false; diff --git a/srsue/src/phy/phy_common.cc b/srsue/src/phy/phy_common.cc index ad46c9634..2582e7d3c 100644 --- a/srsue/src/phy/phy_common.cc +++ b/srsue/src/phy/phy_common.cc @@ -57,7 +57,8 @@ void phy_common::init(phy_args_t* _args, // Instantiate UL channel emulator if (args->ul_channel_args.enable) { - ul_channel = srslte::channel_ptr(new srslte::channel(args->ul_channel_args, args->nof_carriers * args->nof_rx_ant)); + ul_channel = + srslte::channel_ptr(new srslte::channel(args->ul_channel_args, args->nof_lte_carriers * args->nof_rx_ant)); } } @@ -363,7 +364,7 @@ bool phy_common::get_ul_pending_grant(srslte_ul_sf_cfg_t* sf, uint32_t cc_idx, u uint32_t phy_common::get_ul_uci_cc(uint32_t tti_tx) const { std::lock_guard lock(pending_ul_grant_mutex); - for (uint32_t cc = 0; cc < args->nof_carriers; cc++) { + for (uint32_t cc = 0; cc < args->nof_lte_carriers; cc++) { const pending_ul_grant_t& grant = pending_ul_grant[cc][tti_tx]; if (grant.enable) { return cc; @@ -789,7 +790,7 @@ void phy_common::get_dl_metrics(dl_metrics_t m[SRSLTE_MAX_CARRIERS]) { std::unique_lock lock(metrics_mutex); - for (uint32_t i = 0; i < args->nof_carriers; i++) { + for (uint32_t i = 0; i < args->nof_lte_carriers; i++) { m[i] = dl_metrics[i]; dl_metrics[i] = {}; dl_metrics_count[i] = 0; @@ -816,7 +817,7 @@ void phy_common::get_ch_metrics(ch_metrics_t m[SRSLTE_MAX_CARRIERS]) { std::unique_lock lock(metrics_mutex); - for (uint32_t i = 0; i < args->nof_carriers; i++) { + for (uint32_t i = 0; i < args->nof_lte_carriers; i++) { m[i] = ch_metrics[i]; ch_metrics[i] = {}; ch_metrics_count[i] = 0; @@ -836,7 +837,7 @@ void phy_common::get_ul_metrics(ul_metrics_t m[SRSLTE_MAX_CARRIERS]) { std::unique_lock lock(metrics_mutex); - for (uint32_t i = 0; i < args->nof_carriers; i++) { + for (uint32_t i = 0; i < args->nof_lte_carriers; i++) { m[i] = ul_metrics[i]; ul_metrics[i] = {}; ul_metrics_count[i] = 0; @@ -857,7 +858,7 @@ void phy_common::get_sync_metrics(sync_metrics_t m[SRSLTE_MAX_CARRIERS]) { std::unique_lock lock(metrics_mutex); - for (uint32_t i = 0; i < args->nof_carriers; i++) { + for (uint32_t i = 0; i < args->nof_lte_carriers; i++) { m[i] = sync_metrics[i]; sync_metrics[i] = {}; sync_metrics_count[i] = 0; @@ -920,7 +921,7 @@ void phy_common::reset() // Release mapping of secondary cells if (args != nullptr && radio_h != nullptr) { - for (uint32_t i = 1; i < args->nof_carriers; i++) { + for (uint32_t i = 1; i < args->nof_lte_carriers; i++) { radio_h->release_freq(i); } } diff --git a/srsue/src/phy/sync.cc b/srsue/src/phy/sync.cc index d02e7e38f..86e99777b 100644 --- a/srsue/src/phy/sync.cc +++ b/srsue/src/phy/sync.cc @@ -48,22 +48,24 @@ static SRSLTE_AGC_CALLBACK(callback_set_rx_gain) void sync::init(srslte::radio_interface_phy* _radio, stack_interface_phy_lte* _stack, prach* _prach_buffer, - lte::worker_pool* _workers_pool, + lte::worker_pool* _lte_workers_pool, + nr::worker_pool* _nr_workers_pool, phy_common* _worker_com, srslte::log* _log_h, srslte::log* _log_phy_lib_h, uint32_t prio, int sync_cpu_affinity) { - radio_h = _radio; - log_h = _log_h; - log_phy_lib_h = _log_phy_lib_h; - stack = _stack; - workers_pool = _workers_pool; - worker_com = _worker_com; - prach_buffer = _prach_buffer; - - nof_rf_channels = worker_com->args->nof_carriers * worker_com->args->nof_rx_ant; + radio_h = _radio; + log_h = _log_h; + log_phy_lib_h = _log_phy_lib_h; + stack = _stack; + lte_worker_pool = _lte_workers_pool; + nr_worker_pool = _nr_workers_pool; + worker_com = _worker_com; + prach_buffer = _prach_buffer; + + nof_rf_channels = worker_com->args->nof_lte_carriers * worker_com->args->nof_rx_ant; if (nof_rf_channels == 0 || nof_rf_channels > SRSLTE_MAX_CHANNELS) { Error("SYNC: Invalid number of RF channels (%d)\n", nof_rf_channels); return; @@ -86,14 +88,14 @@ void sync::init(srslte::radio_interface_phy* _radio, sfn_p.init(&ue_sync, worker_com->args, sf_buffer, sf_buffer.size(), log_h); // Start intra-frequency measurement - for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) { + for (uint32_t i = 0; i < worker_com->args->nof_lte_carriers; i++) { scell::intra_measure* q = new scell::intra_measure; q->init(i, worker_com, this, log_h); intra_freq_meas.push_back(std::unique_ptr(q)); } // Allocate Secondary serving cell synchronization - for (uint32_t i = 1; i < worker_com->args->nof_carriers; i++) { + for (uint32_t i = 1; i < worker_com->args->nof_lte_carriers; i++) { // Give the logical channel scell_sync[i] = std::unique_ptr(new scell::sync(this, i * worker_com->args->nof_rx_ant)); } @@ -400,7 +402,9 @@ void sync::run_sfn_sync_state() } } -void sync::run_camping_in_sync_state(lte::sf_worker* worker, srslte::rf_buffer_t& sync_buffer) +void sync::run_camping_in_sync_state(lte::sf_worker* lte_worker, + nr::sf_worker* nr_worker, + srslte::rf_buffer_t& sync_buffer) { // Update logging TTI log_h->step(tti); @@ -454,12 +458,12 @@ void sync::run_camping_in_sync_state(lte::sf_worker* worker, srslte::rf_buffer_t } } - Debug("SYNC: Worker %d synchronized\n", worker->get_id()); + Debug("SYNC: Worker %d synchronized\n", lte_worker->get_id()); metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); metrics.ta_us = worker_com->ta.get_usec(); - for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) { + for (uint32_t i = 0; i < worker_com->args->nof_lte_carriers; i++) { worker_com->set_sync_metrics(i, metrics); } @@ -471,22 +475,22 @@ void sync::run_camping_in_sync_state(lte::sf_worker* worker, srslte::rf_buffer_t } } - worker->set_prach(prach_ptr ? &prach_ptr[prach_sf_cnt * SRSLTE_SF_LEN_PRB(cell.nof_prb)] : nullptr, prach_power); + lte_worker->set_prach(prach_ptr ? &prach_ptr[prach_sf_cnt * SRSLTE_SF_LEN_PRB(cell.nof_prb)] : nullptr, prach_power); // Execute Serving Cell state FSM worker_com->cell_state.run_tti(tti); // Set CFO for all Carriers - for (uint32_t cc = 0; cc < worker_com->args->nof_carriers; cc++) { - worker->set_cfo_unlocked(cc, get_tx_cfo()); + for (uint32_t cc = 0; cc < worker_com->args->nof_lte_carriers; cc++) { + lte_worker->set_cfo_unlocked(cc, get_tx_cfo()); worker_com->update_cfo_measurement(cc, srslte_ue_sync_get_cfo(&ue_sync)); } - worker->set_tti(tti); + lte_worker->set_tti(tti); // Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time last_rx_time.add(FDD_HARQ_DELAY_DL_MS * 1e-3); - worker->set_tx_time(last_rx_time); + lte_worker->set_tx_time(last_rx_time); // Advance/reset prach subframe pointer if (prach_ptr) { @@ -497,37 +501,57 @@ void sync::run_camping_in_sync_state(lte::sf_worker* worker, srslte::rf_buffer_t } } - // Start worker - worker_com->semaphore.push(worker); - workers_pool->start_worker(worker); + // Start LTE worker + worker_com->semaphore.push(lte_worker); + lte_worker_pool->start_worker(lte_worker); + + // Start NR worker only if present + if (nr_worker != nullptr) { + nr_worker_pool->start_worker(nr_worker); + } } void sync::run_camping_state() { - lte::sf_worker* worker = (lte::sf_worker*)workers_pool->wait_worker(tti); + lte::sf_worker* lte_worker = lte_worker_pool->wait_worker(tti); srslte::rf_buffer_t sync_buffer = {}; - if (worker == nullptr) { + if (lte_worker == nullptr) { // wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here running = false; return; } + nr::sf_worker* nr_worker = nullptr; + if (worker_com->args->nof_nr_carriers > 0) { + nr_worker = nr_worker_pool->wait_worker(tti); + if (nr_worker == nullptr) { + running = false; + return; + } + } + // Map carrier/antenna buffers to worker buffers - for (uint32_t c = 0; c < worker_com->args->nof_carriers; c++) { + uint32_t cc_idx = 0; + for (uint32_t lte_cc_idx = 0; lte_cc_idx < worker_com->args->nof_lte_carriers; lte_cc_idx++, cc_idx++) { + for (uint32_t i = 0; i < worker_com->args->nof_rx_ant; i++) { + sync_buffer.set(cc_idx, i, worker_com->args->nof_rx_ant, lte_worker->get_buffer(lte_cc_idx, i)); + } + } + for (uint32_t nr_cc_idx = 0; nr_cc_idx < worker_com->args->nof_nr_carriers; nr_cc_idx++, cc_idx++) { for (uint32_t i = 0; i < worker_com->args->nof_rx_ant; i++) { - sync_buffer.set(c, i, worker_com->args->nof_rx_ant, worker->get_buffer(c, i)); + sync_buffer.set(cc_idx, i, worker_com->args->nof_rx_ant, nr_worker->get_buffer(nr_cc_idx, i)); } } // Primary Cell (PCell) Synchronization - switch (srslte_ue_sync_zerocopy(&ue_sync, sync_buffer.to_cf_t(), worker->get_buffer_len())) { + switch (srslte_ue_sync_zerocopy(&ue_sync, sync_buffer.to_cf_t(), lte_worker->get_buffer_len())) { case 1: - run_camping_in_sync_state(worker, sync_buffer); + run_camping_in_sync_state(lte_worker, nr_worker, sync_buffer); break; case 0: Warning("SYNC: Out-of-sync detected in PSS/SSS\n"); out_of_sync(); - worker->release(); + lte_worker->release(); // Force decoding MIB, for making sure that the TTI will be right if (!force_camping_sfn_sync) { @@ -537,7 +561,7 @@ void sync::run_camping_state() break; default: radio_error(); - worker->release(); + lte_worker->release(); break; } @@ -774,12 +798,12 @@ bool sync::set_cell(float cfo) // Reset cell configuration for (uint32_t i = 0; i < worker_com->args->nof_phy_threads; i++) { - (*workers_pool)[i]->reset_cell_unlocked(0); + (*lte_worker_pool)[i]->reset_cell_unlocked(0); } bool success = true; for (uint32_t i = 0; i < worker_com->args->nof_phy_threads; i++) { - lte::sf_worker* w = (lte::sf_worker*)workers_pool->wait_worker_id(i); + lte::sf_worker* w = lte_worker_pool->wait_worker_id(i); if (w) { success &= w->set_cell_unlocked(0, cell); w->release(); diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 762f2b8ad..bab1a0a23 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -199,8 +199,16 @@ int ue::parse_args(const all_args_t& args_) return SRSLTE_ERROR; } + if (args.rf.nof_carriers <= args.phy.nof_nr_carriers) { + fprintf(stderr, + "Maximum number of carriers enough for NR and LTE (%d <= %d)\n", + args.rf.nof_carriers, + args.phy.nof_nr_carriers); + return SRSLTE_ERROR; + } + // replicate some RF parameter to make them available to PHY - args.phy.nof_carriers = args.rf.nof_carriers; + args.phy.nof_lte_carriers = args.rf.nof_carriers - args.phy.nof_nr_carriers; args.phy.nof_rx_ant = args.rf.nof_antennas; args.phy.agc_enable = args.rf.rx_gain < 0.0f; @@ -241,7 +249,7 @@ int ue::parse_args(const all_args_t& args_) args.stack.rrc.ue_category = (uint32_t)strtoul(args.stack.rrc.ue_category_str.c_str(), nullptr, 10); // Consider Carrier Aggregation support if more than one - args.stack.rrc.support_ca = (args.rf.nof_carriers > 1); + args.stack.rrc.support_ca = (args.phy.nof_lte_carriers > 1); return SRSLTE_SUCCESS; }