From fec97689a25ec381ea9f129399962aa1f67ebce4 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 15 Nov 2021 20:31:15 +0000 Subject: [PATCH] rrc,nr,gnb: refactored rrc nr cfg default and derived param generation to be mostly independent of parser --- lib/include/srsran/rrc/nr/rrc_nr_cfg_utils.h | 2 +- lib/src/rrc/nr/rrc_nr_cfg_utils.cc | 7 +- srsenb/src/CMakeLists.txt | 2 +- srsenb/src/enb_cfg_parser.cc | 128 +------- srsgnb/hdr/stack/rrc/cell_asn1_config.h | 2 +- srsgnb/hdr/stack/rrc/rrc_nr.h | 2 +- .../rrc/{rrc_config_nr.h => rrc_nr_config.h} | 7 +- srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h | 28 ++ srsgnb/src/stack/rrc/CMakeLists.txt | 6 +- srsgnb/src/stack/rrc/cell_asn1_config.cc | 6 +- srsgnb/src/stack/rrc/rrc_nr.cc | 31 -- srsgnb/src/stack/rrc/rrc_nr_config_utils.cc | 292 ++++++++++++++++++ srsgnb/src/stack/rrc/test/CMakeLists.txt | 2 +- srsgnb/src/stack/rrc/test/rrc_nr_test.cc | 2 +- 14 files changed, 354 insertions(+), 163 deletions(-) rename srsgnb/hdr/stack/rrc/{rrc_config_nr.h => rrc_nr_config.h} (92%) create mode 100644 srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h create mode 100644 srsgnb/src/stack/rrc/rrc_nr_config_utils.cc diff --git a/lib/include/srsran/rrc/nr/rrc_nr_cfg_utils.h b/lib/include/srsran/rrc/nr/rrc_nr_cfg_utils.h index e3d0f0e4b..745742d26 100644 --- a/lib/include/srsran/rrc/nr/rrc_nr_cfg_utils.h +++ b/lib/include/srsran/rrc/nr/rrc_nr_cfg_utils.h @@ -32,7 +32,7 @@ void generate_default_pdcch_cfg_common(asn1::rrc_nr::pdcch_cfg_common_s& cfg, co void generate_default_init_dl_bwp(asn1::rrc_nr::bwp_dl_common_s& cfg, const basic_cell_args_t& args = {}); void generate_default_dl_cfg_common(asn1::rrc_nr::dl_cfg_common_s& cfg, const basic_cell_args_t& args = {}); -void generate_default_mib(const basic_cell_args_t& args, asn1::rrc_nr::mib_s& cfg); +void generate_default_mib(uint32_t pdcch_scs, uint32_t coreset0_idx, asn1::rrc_nr::mib_s& cfg); void generate_default_serv_cell_cfg_common_sib(const basic_cell_args_t& args, asn1::rrc_nr::serving_cell_cfg_common_sib_s& cfg); diff --git a/lib/src/rrc/nr/rrc_nr_cfg_utils.cc b/lib/src/rrc/nr/rrc_nr_cfg_utils.cc index 205ac9ba9..5327e997b 100644 --- a/lib/src/rrc/nr/rrc_nr_cfg_utils.cc +++ b/lib/src/rrc/nr/rrc_nr_cfg_utils.cc @@ -172,14 +172,15 @@ void generate_default_serv_cell_cfg_common_sib(const basic_cell_args_t& args, se cfg.ss_pbch_block_pwr = -16; } -void generate_default_mib(const basic_cell_args_t& args, mib_s& cfg) +void generate_default_mib(uint32_t pdcch_scs, uint32_t coreset0_idx, mib_s& cfg) { - asn1::number_to_enum(cfg.sub_carrier_spacing_common, args.scs); + bool ret = asn1::number_to_enum(cfg.sub_carrier_spacing_common, pdcch_scs); + srsran_assert(ret, "Invalid SCS=%d kHz", pdcch_scs); cfg.ssb_subcarrier_offset = 0; cfg.intra_freq_resel.value = mib_s::intra_freq_resel_opts::allowed; cfg.cell_barred.value = mib_s::cell_barred_opts::not_barred; cfg.pdcch_cfg_sib1.search_space_zero = 0; - cfg.pdcch_cfg_sib1.ctrl_res_set_zero = 0; + cfg.pdcch_cfg_sib1.ctrl_res_set_zero = coreset0_idx; cfg.dmrs_type_a_position.value = mib_s::dmrs_type_a_position_opts::pos2; cfg.sys_frame_num.from_number(0); } diff --git a/srsenb/src/CMakeLists.txt b/srsenb/src/CMakeLists.txt index ae3250670..2db4196cb 100644 --- a/srsenb/src/CMakeLists.txt +++ b/srsenb/src/CMakeLists.txt @@ -22,7 +22,7 @@ if (RPATH) endif (RPATH) add_library(enb_cfg_parser STATIC parser.cc enb_cfg_parser.cc) -target_link_libraries(enb_cfg_parser srsran_common ${LIBCONFIGPP_LIBRARIES}) +target_link_libraries(enb_cfg_parser srsran_common srsgnb_rrc_config_utils ${LIBCONFIGPP_LIBRARIES}) add_executable(srsenb main.cc enb.cc metrics_stdout.cc metrics_csv.cc metrics_json.cc) diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index d30357f2b..7a771886c 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -12,6 +12,7 @@ #include "enb_cfg_parser.h" #include "srsenb/hdr/enb.h" +#include "srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h" #include "srsran/asn1/rrc_utils.h" #include "srsran/common/band_helper.h" #include "srsran/common/multiqueue.h" @@ -961,8 +962,10 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root) static int parse_nr_cell_list(all_args_t* args, rrc_nr_cfg_t* rrc_cfg_nr, rrc_cfg_t* rrc_cfg_eutra, Setting& root) { for (uint32_t n = 0; n < (uint32_t)root.getLength(); ++n) { + auto& cellroot = root[n]; + rrc_cell_cfg_nr_t cell_cfg = {}; - auto& cellroot = root[n]; + generate_default_nr_cell(cell_cfg); parse_opt_field(cell_cfg.phy_cell.rf_port, cellroot, "rf_port"); HANDLEPARSERCODE(parse_required_field(cell_cfg.phy_cell.carrier.pci, cellroot, "pci")); @@ -1530,7 +1533,8 @@ int set_derived_args_nr(all_args_t* args_, rrc_nr_cfg_t* rrc_nr_cfg_, phy_cfg_t* // Create NR dedicated cell configuration from RRC configuration for (auto it = rrc_nr_cfg_->cell_list.begin(); it != rrc_nr_cfg_->cell_list.end(); ++it) { - auto& cfg = *it; + auto& cfg = *it; + cfg.phy_cell.carrier.max_mimo_layers = args_->enb.nof_ports; // NR cells have the same bandwidth as EUTRA cells, adjust PRB sizes @@ -1548,130 +1552,22 @@ int set_derived_args_nr(all_args_t* args_, rrc_nr_cfg_t* rrc_nr_cfg_, phy_cfg_t* ERROR("The only accepted number of PRB is: 25, 50, 100"); return SRSRAN_ERROR; } - // phy_cell_cfg.root_seq_idx = cfg.root_seq_idx; - cfg.phy_cell.num_ra_preambles = 52; // FIXME: read from config - - if (cfg.phy_cell.dl_freq_hz == 0) { - cfg.phy_cell.dl_freq_hz = band_helper.nr_arfcn_to_freq(cfg.dl_arfcn); - } - if (cfg.phy_cell.ul_freq_hz == 0) { - // auto-detect UL frequency - if (cfg.ul_arfcn == 0) { - // derive UL ARFCN from given DL ARFCN - cfg.ul_arfcn = band_helper.get_ul_arfcn_from_dl_arfcn(cfg.dl_arfcn); - if (cfg.ul_arfcn == 0) { - ERROR("Can't derive UL ARFCN from DL ARFCN %d", cfg.dl_arfcn); - return SRSRAN_ERROR; - } - } - cfg.phy_cell.ul_freq_hz = band_helper.nr_arfcn_to_freq(cfg.ul_arfcn); + // Derive cross-dependent cell params + if (set_derived_nr_cell_params(rrc_nr_cfg_->is_standalone, cfg) != SRSRAN_SUCCESS) { + ERROR("Failed to derive NR cell params."); + return SRSRAN_ERROR; } - // duplex mode - cfg.duplex_mode = band_helper.get_duplex_mode(cfg.band); + // phy_cell_cfg.root_seq_idx = cfg.root_seq_idx; // PRACH - cfg.phy_cell.prach.is_nr = true; - cfg.phy_cell.prach.config_idx = 8; - cfg.phy_cell.prach.root_seq_idx = 0; - cfg.phy_cell.prach.freq_offset = 1; - cfg.phy_cell.prach.num_ra_preambles = cfg.phy_cell.num_ra_preambles; - cfg.phy_cell.prach.hs_flag = phy_cfg_->prach_cnfg.prach_cfg_info.high_speed_flag; - cfg.phy_cell.prach.tdd_config.configured = (cfg.duplex_mode == SRSRAN_DUPLEX_MODE_TDD); - - // PDCCH - // Configure CORESET ID 1 - cfg.phy_cell.pdcch.coreset_present[1] = true; - cfg.phy_cell.pdcch.coreset[1].id = 1; - cfg.phy_cell.pdcch.coreset[1].duration = 1; - cfg.phy_cell.pdcch.coreset[1].mapping_type = srsran_coreset_mapping_type_non_interleaved; - cfg.phy_cell.pdcch.coreset[1].precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle; - - // Generate frequency resources for the full BW - for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { - cfg.phy_cell.pdcch.coreset[1].freq_resources[i] = i < SRSRAN_FLOOR(cfg.phy_cell.carrier.nof_prb, 6); - } - - // Configure Search Space 1 as common - cfg.phy_cell.pdcch.search_space_present[1] = true; - cfg.phy_cell.pdcch.search_space[1].id = 1; - cfg.phy_cell.pdcch.search_space[1].coreset_id = 1; - cfg.phy_cell.pdcch.search_space[1].duration = 1; - cfg.phy_cell.pdcch.search_space[1].formats[0] = srsran_dci_format_nr_0_0; // DCI format for PUSCH - cfg.phy_cell.pdcch.search_space[1].formats[1] = srsran_dci_format_nr_1_0; // DCI format for PDSCH - cfg.phy_cell.pdcch.search_space[1].nof_formats = 2; - cfg.phy_cell.pdcch.search_space[1].type = srsran_search_space_type_common_3; - - // Generate 1 candidate for each aggregation level if possible - for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) { - cfg.phy_cell.pdcch.search_space[1].nof_candidates[L] = - SRSRAN_MIN(2, srsran_pdcch_nr_max_candidates_coreset(&cfg.phy_cell.pdcch.coreset[1], L)); - } - - cfg.phy_cell.pdcch.ra_search_space_present = true; - cfg.phy_cell.pdcch.ra_search_space = cfg.phy_cell.pdcch.search_space[1]; - cfg.phy_cell.pdcch.ra_search_space.type = srsran_search_space_type_common_1; + cfg.phy_cell.prach.hs_flag = phy_cfg_->prach_cnfg.prach_cfg_info.high_speed_flag; // PDSCH cfg.phy_cell.pdsch.rs_power = phy_cfg_->pdsch_cnfg.ref_sig_pwr; cfg.phy_cell.pdsch.p_b = phy_cfg_->pdsch_cnfg.p_b; - // copy center frequencies - cfg.phy_cell.carrier.dl_center_frequency_hz = cfg.phy_cell.dl_freq_hz; - cfg.phy_cell.carrier.ul_center_frequency_hz = cfg.phy_cell.ul_freq_hz; - - cfg.dl_absolute_freq_point_a = band_helper.get_abs_freq_point_a_arfcn(cfg.phy_cell.carrier.nof_prb, cfg.dl_arfcn); - cfg.ul_absolute_freq_point_a = band_helper.get_abs_freq_point_a_arfcn(cfg.phy_cell.carrier.nof_prb, cfg.ul_arfcn); - - // Calculate SSB params depending on band/duplex - cfg.ssb_cfg.duplex_mode = band_helper.get_duplex_mode(cfg.band); - cfg.ssb_cfg.pattern = band_helper.get_ssb_pattern(cfg.band, srsran_subcarrier_spacing_15kHz); - if (cfg.ssb_cfg.pattern == SRSRAN_SSB_PATTERN_A) { - // 15kHz SSB SCS - cfg.ssb_cfg.scs = srsran_subcarrier_spacing_15kHz; - } else { - // try to optain SSB pattern for same band with 30kHz SCS - cfg.ssb_cfg.pattern = band_helper.get_ssb_pattern(cfg.band, srsran_subcarrier_spacing_30kHz); - if (cfg.ssb_cfg.pattern == SRSRAN_SSB_PATTERN_B || cfg.ssb_cfg.pattern == SRSRAN_SSB_PATTERN_C) { - // SSB SCS is 30 kHz - cfg.ssb_cfg.scs = srsran_subcarrier_spacing_30kHz; - } else { - ERROR("Can't derive SSB pattern for band %d", cfg.band); - return SRSRAN_ERROR; - } - } - - // fill remaining SSB fields - int coreset0_rb_offset = 0; - if (rrc_nr_cfg_->is_standalone) { - const uint32_t coreset0_idx = 6; // See TS 38.331 - controlResourceSetZero / Table 13-1 index - cfg.phy_cell.pdcch.coreset_present[0] = true; - // Get offset in RBs between CORESET#0 and SSB - coreset0_rb_offset = srsran_coreset0_ssb_offset(coreset0_idx, cfg.ssb_cfg.scs, cfg.phy_cell.carrier.scs); - srsran_assert(coreset0_rb_offset >= 0, "Failed to compute RB offset between CORESET#0 and SSB"); - } - cfg.ssb_absolute_freq_point = - band_helper.get_abs_freq_ssb_arfcn(cfg.band, cfg.ssb_cfg.scs, cfg.dl_absolute_freq_point_a, coreset0_rb_offset); - srsran_assert(cfg.ssb_absolute_freq_point > 0, - "Can't derive SSB freq point for dl_arfcn %d and band %d", - cfg.dl_arfcn, - cfg.band); - - // Convert to frequency for PHY - cfg.phy_cell.carrier.ssb_center_freq_hz = band_helper.nr_arfcn_to_freq(cfg.ssb_absolute_freq_point); - - cfg.ssb_cfg.center_freq_hz = cfg.phy_cell.carrier.dl_center_frequency_hz; - cfg.ssb_cfg.ssb_freq_hz = cfg.phy_cell.carrier.ssb_center_freq_hz; - cfg.ssb_cfg.periodicity_ms = 10; // TODO: make a param - cfg.ssb_cfg.beta_pss = 0.0; - cfg.ssb_cfg.beta_sss = 0.0; - cfg.ssb_cfg.beta_pbch = 0.0; - cfg.ssb_cfg.beta_pbch_dmrs = 0.0; - // set by PHY layer in worker_pool::set_common_cfg - cfg.ssb_cfg.srate_hz = 0.0; - cfg.ssb_cfg.scaling = 0.0; - phy_cfg_->phy_cell_cfg_nr.push_back(cfg.phy_cell); } diff --git a/srsgnb/hdr/stack/rrc/cell_asn1_config.h b/srsgnb/hdr/stack/rrc/cell_asn1_config.h index b9a2d8f06..202f18a49 100644 --- a/srsgnb/hdr/stack/rrc/cell_asn1_config.h +++ b/srsgnb/hdr/stack/rrc/cell_asn1_config.h @@ -13,7 +13,7 @@ #ifndef SRSRAN_CELL_ASN1_CONFIG_H #define SRSRAN_CELL_ASN1_CONFIG_H -#include "rrc_config_nr.h" +#include "rrc_nr_config.h" #include "srsran/asn1/rrc_nr.h" namespace srsenb { diff --git a/srsgnb/hdr/stack/rrc/rrc_nr.h b/srsgnb/hdr/stack/rrc/rrc_nr.h index ab3cd2a3b..9f3b3c39c 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr.h @@ -16,7 +16,7 @@ #include "srsenb/hdr/stack/enb_stack_base.h" #include "srsenb/hdr/stack/rrc/rrc_config_common.h" #include "srsenb/hdr/stack/rrc/rrc_metrics.h" -#include "srsgnb/hdr/stack/rrc/rrc_config_nr.h" +#include "srsgnb/hdr/stack/rrc/rrc_nr_config.h" #include "srsran/asn1/rrc_nr.h" #include "srsran/common/block_queue.h" #include "srsran/common/buffer_pool.h" diff --git a/srsgnb/hdr/stack/rrc/rrc_config_nr.h b/srsgnb/hdr/stack/rrc/rrc_nr_config.h similarity index 92% rename from srsgnb/hdr/stack/rrc/rrc_config_nr.h rename to srsgnb/hdr/stack/rrc/rrc_nr_config.h index 5a67958f5..fcae77a11 100644 --- a/srsgnb/hdr/stack/rrc/rrc_config_nr.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_config.h @@ -10,8 +10,8 @@ * */ -#ifndef SRSRAN_RRC_CONFIG_NR_H -#define SRSRAN_RRC_CONFIG_NR_H +#ifndef SRSRAN_RRC_NR_CONFIG_H +#define SRSRAN_RRC_NR_CONFIG_H #include "srsenb/hdr/phy/phy_interfaces.h" #include "srsenb/hdr/stack/rrc/rrc_config_common.h" @@ -40,6 +40,7 @@ struct rrc_cell_cfg_nr_t { uint32_t ul_absolute_freq_point_a; // derived from UL ARFCN uint32_t ssb_absolute_freq_point; // derived from DL ARFCN uint32_t band; + uint32_t coreset0_idx; // Table 13-{1,...15} row index srsran_duplex_mode_t duplex_mode; srsran_ssb_cfg_t ssb_cfg; }; @@ -61,4 +62,4 @@ struct rrc_nr_cfg_t { } // namespace srsenb -#endif // SRSRAN_RRC_CONFIG_NR_H +#endif // SRSRAN_RRC_NR_CONFIG_H diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h b/srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h new file mode 100644 index 000000000..6d63646f6 --- /dev/null +++ b/srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h @@ -0,0 +1,28 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSRAN_RRC_NR_CONFIG_DEFAULT_H +#define SRSRAN_RRC_NR_CONFIG_DEFAULT_H + +#include "rrc_nr_config.h" + +namespace srsenb { + +void generate_default_nr_cell(rrc_cell_cfg_nr_t& cell); + +int set_derived_nr_cell_params(bool is_sa, rrc_cell_cfg_nr_t& cell); + +int check_nr_cell_cfg_valid(const rrc_cell_cfg_nr_t& cell, bool is_sa); + +} // namespace srsenb + +#endif // SRSRAN_RRC_NR_CONFIG_DEFAULT_H diff --git a/srsgnb/src/stack/rrc/CMakeLists.txt b/srsgnb/src/stack/rrc/CMakeLists.txt index 0e63798ee..3b1cdb05d 100644 --- a/srsgnb/src/stack/rrc/CMakeLists.txt +++ b/srsgnb/src/stack/rrc/CMakeLists.txt @@ -6,9 +6,13 @@ # the distribution. # +set(SOURCES rrc_nr_config_utils.cc) +add_library(srsgnb_rrc_config_utils STATIC ${SOURCES}) +target_link_libraries(srsgnb_rrc_config_utils srsran_rrc_nr srsran_phy) + set(SOURCES rrc_nr.cc rrc_nr_ue.cc cell_asn1_config.cc) add_library(srsgnb_rrc STATIC ${SOURCES}) -target_link_libraries(srsgnb_rrc srsran_rrc_nr) +target_link_libraries(srsgnb_rrc srsran_rrc_nr srsgnb_rrc_config_utils) include_directories(${PROJECT_SOURCE_DIR}) diff --git a/srsgnb/src/stack/rrc/cell_asn1_config.cc b/srsgnb/src/stack/rrc/cell_asn1_config.cc index 56a329d89..16db18d9d 100644 --- a/srsgnb/src/stack/rrc/cell_asn1_config.cc +++ b/srsgnb/src/stack/rrc/cell_asn1_config.cc @@ -586,9 +586,9 @@ int fill_sp_cell_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, sp_cell_ int fill_mib_from_enb_cfg(const rrc_nr_cfg_t& cfg, asn1::rrc_nr::mib_s& mib) { - srsran::basic_cell_args_t args; - args.scs = cfg.cell_list[0].phy_cell.carrier.scs; - srsran::generate_default_mib(args, mib); + uint32_t scs = + subcarrier_spacing_e{(subcarrier_spacing_opts::options)cfg.cell_list[0].phy_cell.carrier.scs}.to_number(); + srsran::generate_default_mib(scs, cfg.cell_list[0].coreset0_idx, mib); return SRSRAN_SUCCESS; } diff --git a/srsgnb/src/stack/rrc/rrc_nr.cc b/srsgnb/src/stack/rrc/rrc_nr.cc index f26fa7b2c..89babc3c7 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -49,37 +49,6 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_, rrc_eutra = rrc_eutra_; cfg = cfg_; - if (cfg.is_standalone) { - // Generate parameters of Coreset#0 and SS#0 - const uint32_t coreset0_idx = 6; // See TS 38.331 - controlResourceSetZero - cfg.cell_list[0].phy_cell.pdcch.coreset_present[0] = true; - // Get pointA and SSB absolute frequencies - double pointA_abs_freq_Hz = cfg.cell_list[0].phy_cell.carrier.dl_center_frequency_hz - - cfg.cell_list[0].phy_cell.carrier.nof_prb * SRSRAN_NRE * - SRSRAN_SUBC_SPACING_NR(cfg.cell_list[0].phy_cell.carrier.scs) / 2; - double ssb_abs_freq_Hz = cfg.cell_list[0].phy_cell.carrier.ssb_center_freq_hz; - // Calculate integer SSB to pointA frequency offset in Hz - uint32_t ssb_pointA_freq_offset_Hz = - (ssb_abs_freq_Hz > pointA_abs_freq_Hz) ? (uint32_t)(ssb_abs_freq_Hz - pointA_abs_freq_Hz) : 0; - int ret = srsran_coreset_zero(cfg.cell_list[0].phy_cell.cell_id, - ssb_pointA_freq_offset_Hz, - cfg.cell_list[0].ssb_cfg.scs, - cfg.cell_list[0].phy_cell.carrier.scs, - coreset0_idx, - &cfg.cell_list[0].phy_cell.pdcch.coreset[0]); - srsran_assert(ret == SRSRAN_SUCCESS, "Failed to generate CORESET#0"); - cfg.cell_list[0].phy_cell.pdcch.search_space_present[0] = true; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].id = 0; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].coreset_id = 0; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].type = srsran_search_space_type_common_0; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].nof_candidates[0] = 1; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].nof_candidates[1] = 1; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].nof_candidates[2] = 1; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].formats[0] = srsran_dci_format_nr_1_0; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].nof_formats = 1; - cfg.cell_list[0].phy_cell.pdcch.search_space[0].duration = 1; - } - cell_ctxt.reset(new cell_ctxt_t{}); // derived diff --git a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc new file mode 100644 index 000000000..625c2c54f --- /dev/null +++ b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc @@ -0,0 +1,292 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h" +#include "srsran/common/band_helper.h" + +#define INVALID_PARAM(x, fmt, ...) \ + do { \ + if (not(x)) { \ + get_logger().error("ERROR: " fmt, ##__VA_ARGS__); \ + return SRSRAN_ERROR; \ + } \ + } while (0) + +namespace srsenb { + +static srslog::basic_logger& get_logger() +{ + static srslog::basic_logger& logger = srslog::fetch_basic_logger("ALL"); + return logger; +} + +/// Generate default phy cell configuration +void generate_default_nr_phy_cell(phy_cell_cfg_nr_t& phy_cell) +{ + phy_cell = {}; + + phy_cell.carrier.scs = srsran_subcarrier_spacing_15kHz; + phy_cell.carrier.nof_prb = 52; + phy_cell.carrier.max_mimo_layers = 1; + + phy_cell.dl_freq_hz = 0; // auto set + phy_cell.ul_freq_hz = 0; + phy_cell.num_ra_preambles = 52; + + // PRACH + phy_cell.prach.is_nr = true; + phy_cell.prach.config_idx = 8; + phy_cell.prach.root_seq_idx = 0; + phy_cell.prach.freq_offset = 1; + phy_cell.prach.num_ra_preambles = phy_cell.num_ra_preambles; + phy_cell.prach.hs_flag = false; + phy_cell.prach.tdd_config.configured = false; + + // PDCCH + // Configure CORESET ID 1 + phy_cell.pdcch.coreset_present[1] = true; + phy_cell.pdcch.coreset[1].id = 1; + phy_cell.pdcch.coreset[1].duration = 1; + phy_cell.pdcch.coreset[1].mapping_type = srsran_coreset_mapping_type_non_interleaved; + phy_cell.pdcch.coreset[1].precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle; + + // Generate frequency resources for the full BW + for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { + phy_cell.pdcch.coreset[1].freq_resources[i] = i < SRSRAN_FLOOR(phy_cell.carrier.nof_prb, 6); + } + + // Configure Search Space 1 as common + phy_cell.pdcch.search_space_present[1] = true; + phy_cell.pdcch.search_space[1].id = 1; + phy_cell.pdcch.search_space[1].coreset_id = 1; + phy_cell.pdcch.search_space[1].duration = 1; + phy_cell.pdcch.search_space[1].formats[0] = srsran_dci_format_nr_0_0; // DCI format for PUSCH + phy_cell.pdcch.search_space[1].formats[1] = srsran_dci_format_nr_1_0; // DCI format for PDSCH + phy_cell.pdcch.search_space[1].nof_formats = 2; + phy_cell.pdcch.search_space[1].type = srsran_search_space_type_common_3; + + // Generate 1 candidate for each aggregation level if possible + for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) { + phy_cell.pdcch.search_space[1].nof_candidates[L] = + SRSRAN_MIN(2, srsran_pdcch_nr_max_candidates_coreset(&phy_cell.pdcch.coreset[1], L)); + } + + phy_cell.pdcch.ra_search_space_present = true; + phy_cell.pdcch.ra_search_space = phy_cell.pdcch.search_space[1]; + phy_cell.pdcch.ra_search_space.type = srsran_search_space_type_common_1; + + // PDSCH + phy_cell.pdsch.rs_power = 0; + phy_cell.pdsch.p_b = 0; +} + +/// Generate default rrc nr cell configuration +void generate_default_nr_cell(rrc_cell_cfg_nr_t& cell) +{ + cell = {}; + cell.coreset0_idx = 6; + cell.ssb_absolute_freq_point = 0; // auto derived + generate_default_nr_phy_cell(cell.phy_cell); +} + +/// Generate CORESET#0 and SSB absolute frequency (if not specified) +int derive_coreset0_params(rrc_cell_cfg_nr_t& cell) +{ + // Generate CORESET#0 + cell.phy_cell.pdcch.coreset_present[0] = true; + // Get pointA and SSB absolute frequencies + double pointA_abs_freq_Hz = + cell.phy_cell.carrier.dl_center_frequency_hz - + cell.phy_cell.carrier.nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(cell.phy_cell.carrier.scs) / 2; + double ssb_abs_freq_Hz = cell.phy_cell.carrier.ssb_center_freq_hz; + // Calculate integer SSB to pointA frequency offset in Hz + uint32_t ssb_pointA_freq_offset_Hz = + (ssb_abs_freq_Hz > pointA_abs_freq_Hz) ? (uint32_t)(ssb_abs_freq_Hz - pointA_abs_freq_Hz) : 0; + int ret = srsran_coreset_zero(cell.phy_cell.cell_id, + ssb_pointA_freq_offset_Hz, + cell.ssb_cfg.scs, + cell.phy_cell.carrier.scs, + cell.coreset0_idx, + &cell.phy_cell.pdcch.coreset[0]); + INVALID_PARAM(ret == SRSRAN_SUCCESS, "Failed to generate CORESET#0"); + return SRSRAN_SUCCESS; +} + +int derive_ssb_params(bool is_sa, + uint32_t dl_arfcn, + uint32_t band, + srsran_subcarrier_spacing_t pdcch_scs, + uint32_t coreset0_idx, + uint32_t nof_prb, + srsran_ssb_cfg_t& ssb) +{ + // Verify essential parameters are specified and valid + INVALID_PARAM(dl_arfcn > 0, "Invalid DL ARFCN=%d", dl_arfcn); + INVALID_PARAM(band > 0, "Band is a mandatory parameter"); + INVALID_PARAM(pdcch_scs < srsran_subcarrier_spacing_invalid, "Invalid carrier SCS"); + INVALID_PARAM(coreset0_idx < 15, "Invalid controlResourceSetZero"); + INVALID_PARAM(nof_prb > 0, "Invalid DL number of PRBS=%d", nof_prb); + + srsran::srsran_band_helper band_helper; + + double dl_freq_hz = band_helper.nr_arfcn_to_freq(dl_arfcn); + uint32_t dl_absolute_freq_point_a = band_helper.get_abs_freq_point_a_arfcn(nof_prb, dl_arfcn); + + ssb.center_freq_hz = dl_freq_hz; + ssb.duplex_mode = band_helper.get_duplex_mode(band); + + // derive SSB pattern and scs + ssb.pattern = band_helper.get_ssb_pattern(band, srsran_subcarrier_spacing_15kHz); + if (ssb.pattern == SRSRAN_SSB_PATTERN_A) { + // 15kHz SSB SCS + ssb.scs = srsran_subcarrier_spacing_15kHz; + } else { + // try to optain SSB pattern for same band with 30kHz SCS + ssb.pattern = band_helper.get_ssb_pattern(band, srsran_subcarrier_spacing_30kHz); + if (ssb.pattern == SRSRAN_SSB_PATTERN_B || ssb.pattern == SRSRAN_SSB_PATTERN_C) { + // SSB SCS is 30 kHz + ssb.scs = srsran_subcarrier_spacing_30kHz; + } else { + srsran_terminate("Can't derive SSB pattern from band %d", band); + } + } + + // derive SSB position + int coreset0_rb_offset = 0; + if (is_sa) { + // Get offset in RBs between CORESET#0 and SSB + coreset0_rb_offset = srsran_coreset0_ssb_offset(coreset0_idx, ssb.scs, pdcch_scs); + INVALID_PARAM(coreset0_rb_offset >= 0, "Failed to compute RB offset between CORESET#0 and SSB"); + } else { + // TODO: Verify if specified SSB frequency is valid + } + uint32_t ssb_abs_freq_point = + band_helper.get_abs_freq_ssb_arfcn(band, ssb.scs, dl_absolute_freq_point_a, coreset0_rb_offset); + INVALID_PARAM(ssb_abs_freq_point > 0, + "Can't derive SSB freq point for dl_arfcn=%d and band %d", + band_helper.freq_to_nr_arfcn(dl_freq_hz), + band); + + // Convert to frequency for PHY + ssb.ssb_freq_hz = band_helper.nr_arfcn_to_freq(ssb_abs_freq_point); + + ssb.periodicity_ms = 10; // TODO: make a param + ssb.beta_pss = 0.0; + ssb.beta_sss = 0.0; + ssb.beta_pbch = 0.0; + ssb.beta_pbch_dmrs = 0.0; + // set by PHY layer in worker_pool::set_common_cfg + ssb.srate_hz = 0.0; + ssb.scaling = 0.0; + + return SRSRAN_SUCCESS; +} + +int derive_phy_cell_freq_params(uint32_t dl_arfcn, uint32_t ul_arfcn, phy_cell_cfg_nr_t& phy_cell) +{ + // Verify essential parameters are specified and valid + INVALID_PARAM(dl_arfcn > 0, "DL ARFCN is a mandatory parameter"); + + // Use helper class to derive NR carrier parameters + srsran::srsran_band_helper band_helper; + + // derive DL freq from ARFCN + if (phy_cell.dl_freq_hz == 0) { + phy_cell.dl_freq_hz = band_helper.nr_arfcn_to_freq(dl_arfcn); + } + + // derive UL freq from ARFCN + if (phy_cell.ul_freq_hz == 0) { + // auto-detect UL frequency + if (ul_arfcn == 0) { + // derive UL ARFCN from given DL ARFCN + ul_arfcn = band_helper.get_ul_arfcn_from_dl_arfcn(dl_arfcn); + INVALID_PARAM(ul_arfcn > 0, "Can't derive UL ARFCN from DL ARFCN %d", dl_arfcn); + } + phy_cell.ul_freq_hz = band_helper.nr_arfcn_to_freq(ul_arfcn); + } + + // copy center frequencies + phy_cell.carrier.dl_center_frequency_hz = phy_cell.dl_freq_hz; + phy_cell.carrier.ul_center_frequency_hz = phy_cell.ul_freq_hz; + + return SRSRAN_SUCCESS; +} + +int set_derived_nr_cell_params(bool is_sa, rrc_cell_cfg_nr_t& cell) +{ + // Verify essential parameters are specified and valid + INVALID_PARAM(cell.dl_arfcn > 0, "DL ARFCN is a mandatory parameter"); + INVALID_PARAM(cell.band > 0, "Band is a mandatory parameter"); + INVALID_PARAM(cell.phy_cell.carrier.nof_prb > 0, "Number of PRBs is a mandatory parameter"); + + // Use helper class to derive NR carrier parameters + srsran::srsran_band_helper band_helper; + + if (cell.ul_arfcn == 0) { + // derive UL ARFCN from given DL ARFCN + cell.ul_arfcn = band_helper.get_ul_arfcn_from_dl_arfcn(cell.dl_arfcn); + INVALID_PARAM(cell.ul_arfcn > 0, "Can't derive UL ARFCN from DL ARFCN %d", cell.dl_arfcn); + } + + // duplex mode + cell.duplex_mode = band_helper.get_duplex_mode(cell.band); + + // PointA + cell.dl_absolute_freq_point_a = band_helper.get_abs_freq_point_a_arfcn(cell.phy_cell.carrier.nof_prb, cell.dl_arfcn); + cell.ul_absolute_freq_point_a = band_helper.get_abs_freq_point_a_arfcn(cell.phy_cell.carrier.nof_prb, cell.ul_arfcn); + + // Derive phy_cell parameters that depend on ARFCNs + derive_phy_cell_freq_params(cell.dl_arfcn, cell.ul_arfcn, cell.phy_cell); + + // Derive SSB params + derive_ssb_params(is_sa, + cell.dl_arfcn, + cell.band, + cell.phy_cell.carrier.scs, + cell.coreset0_idx, + cell.phy_cell.carrier.nof_prb, + cell.ssb_cfg); + cell.phy_cell.carrier.ssb_center_freq_hz = cell.ssb_cfg.ssb_freq_hz; + cell.ssb_absolute_freq_point = band_helper.freq_to_nr_arfcn(cell.ssb_cfg.ssb_freq_hz); + + // Derive remaining config params + if (is_sa) { + derive_coreset0_params(cell); + cell.phy_cell.pdcch.search_space_present[0] = true; + cell.phy_cell.pdcch.search_space[0].id = 0; + cell.phy_cell.pdcch.search_space[0].coreset_id = 0; + cell.phy_cell.pdcch.search_space[0].type = srsran_search_space_type_common_0; + cell.phy_cell.pdcch.search_space[0].nof_candidates[0] = 1; + cell.phy_cell.pdcch.search_space[0].nof_candidates[1] = 1; + cell.phy_cell.pdcch.search_space[0].nof_candidates[2] = 1; + cell.phy_cell.pdcch.search_space[0].formats[0] = srsran_dci_format_nr_1_0; + cell.phy_cell.pdcch.search_space[0].nof_formats = 1; + cell.phy_cell.pdcch.search_space[0].duration = 1; + } + + // Derive remaining PHY cell params + cell.phy_cell.prach.num_ra_preambles = cell.phy_cell.num_ra_preambles; + cell.phy_cell.prach.tdd_config.configured = (cell.duplex_mode == SRSRAN_DUPLEX_MODE_TDD); + + return check_nr_cell_cfg_valid(cell, is_sa); +} + +int check_nr_cell_cfg_valid(const rrc_cell_cfg_nr_t& cell, bool is_sa) +{ + // verify SSB params are consistent + INVALID_PARAM(cell.ssb_cfg.center_freq_hz == cell.phy_cell.dl_freq_hz, "Invalid SSB param generation"); + + return SRSRAN_SUCCESS; +} + +} // namespace srsenb \ No newline at end of file diff --git a/srsgnb/src/stack/rrc/test/CMakeLists.txt b/srsgnb/src/stack/rrc/test/CMakeLists.txt index 3e5ab83cf..45df0892d 100644 --- a/srsgnb/src/stack/rrc/test/CMakeLists.txt +++ b/srsgnb/src/stack/rrc/test/CMakeLists.txt @@ -9,5 +9,5 @@ add_library(rrc_nr_test_helpers rrc_nr_test_helpers.cc) add_executable(rrc_nr_test rrc_nr_test.cc) -target_link_libraries(rrc_nr_test srsgnb_rrc test_helpers rrc_nr_test_helpers ${ATOMIC_LIBS}) +target_link_libraries(rrc_nr_test srsgnb_rrc srsgnb_rrc_config_utils test_helpers rrc_nr_test_helpers ${ATOMIC_LIBS}) add_test(rrc_nr_test rrc_nr_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..) \ No newline at end of file diff --git a/srsgnb/src/stack/rrc/test/rrc_nr_test.cc b/srsgnb/src/stack/rrc/test/rrc_nr_test.cc index 828ecd988..02bcbedea 100644 --- a/srsgnb/src/stack/rrc/test/rrc_nr_test.cc +++ b/srsgnb/src/stack/rrc/test/rrc_nr_test.cc @@ -168,7 +168,7 @@ int main(int argc, char** argv) auto& logger = srslog::fetch_basic_logger("ASN1"); logger.set_level(srslog::basic_levels::info); auto& rrc_logger = srslog::fetch_basic_logger("RRC-NR"); - rrc_logger.set_level(srslog::basic_levels::info); + rrc_logger.set_level(srslog::basic_levels::debug); srslog::init();