diff --git a/srsenb/hdr/phy/phy_common.h b/srsenb/hdr/phy/phy_common.h index dfde7bf58..06e4cd327 100644 --- a/srsenb/hdr/phy/phy_common.h +++ b/srsenb/hdr/phy/phy_common.h @@ -142,6 +142,21 @@ public: return ret; } + double get_ssb_freq_hz(uint32_t cc_idx) + { + double ret = 0.0; + + if (cc_idx < cell_list_lte.size()) { + ret = cell_list_lte[cc_idx].dl_freq_hz; + } + + cc_idx -= cell_list_lte.size(); + if (cc_idx < cell_list_nr.size()) { + ret = cell_list_nr[cc_idx].carrier.ssb_center_freq_hz; + } + + return ret; + } uint32_t get_rf_port(uint32_t cc_idx) { uint32_t ret = 0; diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 812d6d1f6..7d6440eca 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -1519,6 +1519,7 @@ static int parse_nr_cell_list(all_args_t* args, rrc_nr_cfg_t* rrc_cfg_nr, rrc_cf parse_opt_field(cell_cfg.phy_cell.rf_port, cellroot, "rf_port"); HANDLEPARSERCODE(parse_required_field(cell_cfg.phy_cell.carrier.pci, cellroot, "pci")); HANDLEPARSERCODE(parse_required_field(cell_cfg.phy_cell.cell_id, cellroot, "cell_id")); + HANDLEPARSERCODE(parse_required_field(cell_cfg.coreset0_idx, cellroot, "coreset0_idx")); HANDLEPARSERCODE(parse_required_field(cell_cfg.prach_root_seq_idx, cellroot, "root_seq_idx")); HANDLEPARSERCODE(parse_required_field(cell_cfg.tac, cellroot, "tac")); @@ -2140,54 +2141,11 @@ int set_derived_args_nr(all_args_t* args_, rrc_nr_cfg_t* rrc_nr_cfg_, phy_cfg_t* ERROR("Only 10 MHz bandwidth supported."); return SRSRAN_ERROR; } - if (rrc_nr_cfg_->is_standalone) { - if (is_valid_arfcn(cfg.band, cfg.dl_arfcn) == false) { - ERROR("DL-ARFCN %d in band n%d not supported with coreset0 config.", cfg.dl_arfcn, cfg.band); - ERROR("Valid ARFCNs for band n%d are: %s", cfg.band, valid_arfcns_to_string(cfg.band).c_str()); - return SRSRAN_ERROR; - } - if (cfg.duplex_mode == SRSRAN_DUPLEX_MODE_TDD) { - ERROR("Only FDD duplex supported in SA mode."); - return SRSRAN_ERROR; - } - } } return SRSRAN_SUCCESS; } -// List of selected ARFCNs in band n3, n7 and n20 that match the coreset0 config -using arfcn_list_t = std::list; -std::map valid_arfcn = {{3, {363500, 368500, 369500, 374500, 375000}}, - {7, {525000, 526200, 531000}}, - {20, {159000, 160200}}}; - -std::string valid_arfcns_to_string(uint32_t band) -{ - std::string band_string; - if (valid_arfcn.find(band) != valid_arfcn.end()) { - for (const auto& arfcn : valid_arfcn.at(band)) { - band_string += std::to_string(arfcn); - band_string += ", "; - } - } - return band_string; -} - -bool is_valid_arfcn(uint32_t band, uint32_t dl_arfcn) -{ - if (valid_arfcn.find(band) == valid_arfcn.end()) { - return false; - } - const auto& arfcn_list = valid_arfcn.at(band); - for (const auto& arfcn : arfcn_list) { - if (arfcn == dl_arfcn) { - return true; - } - } - return false; -} - } // namespace enb_conf_sections namespace sib_sections { diff --git a/srsenb/src/phy/txrx.cc b/srsenb/src/phy/txrx.cc index 09a0f55d8..141262035 100644 --- a/srsenb/src/phy/txrx.cc +++ b/srsenb/src/phy/txrx.cc @@ -12,11 +12,11 @@ #include +#include "srsenb/hdr/phy/txrx.h" +#include "srsran/common/band_helper.h" #include "srsran/common/threads.h" #include "srsran/srsran.h" -#include "srsenb/hdr/phy/txrx.h" - #define Error(fmt, ...) \ if (SRSRAN_DEBUG_ENABLED) \ logger.error(fmt, ##__VA_ARGS__) @@ -85,6 +85,8 @@ void txrx::run_thread() float samp_rate = srsran_sampling_freq_hz(worker_com->get_nof_prb(0)); + srsran::srsran_band_helper band_helper; + // Configure radio radio_h->set_rx_srate(samp_rate); radio_h->set_tx_srate(samp_rate); @@ -94,11 +96,14 @@ void txrx::run_thread() double tx_freq_hz = worker_com->get_dl_freq_hz(cc_idx); double rx_freq_hz = worker_com->get_ul_freq_hz(cc_idx); uint32_t rf_port = worker_com->get_rf_port(cc_idx); - srsran::console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz for cc_idx=%d nof_prb=%d\n", - tx_freq_hz / 1e6f, - rx_freq_hz / 1e6f, - cc_idx, - worker_com->get_nof_prb(cc_idx)); + srsran::console( + "Setting frequency: DL=%.1f Mhz, DL_SSB=%.2f Mhz (SSB-ARFCN=%d), UL=%.1f MHz for cc_idx=%d nof_prb=%d\n", + tx_freq_hz / 1e6f, + worker_com->get_ssb_freq_hz(cc_idx) / 1e6f, + band_helper.freq_to_nr_arfcn(worker_com->get_ssb_freq_hz(cc_idx)), + rx_freq_hz / 1e6f, + cc_idx, + worker_com->get_nof_prb(cc_idx)); radio_h->set_tx_freq(rf_port, tx_freq_hz); radio_h->set_rx_freq(rf_port, rx_freq_hz); } diff --git a/srsgnb/hdr/stack/mac/sched_nr_interface.h b/srsgnb/hdr/stack/mac/sched_nr_interface.h index d27808718..ca7409d69 100644 --- a/srsgnb/hdr/stack/mac/sched_nr_interface.h +++ b/srsgnb/hdr/stack/mac/sched_nr_interface.h @@ -80,6 +80,7 @@ struct sched_nr_cell_cfg_t { uint32_t nof_layers; uint32_t pci; + uint32_t ssb_offset; uint32_t dl_cell_nof_prb; uint32_t ul_cell_nof_prb; asn1::rrc_nr::dl_cfg_common_sib_s dl_cfg_common; diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_config.h b/srsgnb/hdr/stack/rrc/rrc_nr_config.h index 74469b535..23d37fa7d 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_config.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_config.h @@ -36,6 +36,7 @@ struct rrc_cell_cfg_nr_t { srsran_duplex_mode_t duplex_mode; double ssb_freq_hz; uint32_t ssb_absolute_freq_point; // derived from DL ARFCN (SSB arfcn) + uint32_t ssb_offset; srsran_subcarrier_spacing_t ssb_scs; srsran_ssb_pattern_t ssb_pattern; asn1::rrc_nr::pdcch_cfg_common_s pdcch_cfg_common; diff --git a/srsgnb/src/stack/mac/sched_nr_interface_utils.cc b/srsgnb/src/stack/mac/sched_nr_interface_utils.cc index 39f57451c..648a49606 100644 --- a/srsgnb/src/stack/mac/sched_nr_interface_utils.cc +++ b/srsgnb/src/stack/mac/sched_nr_interface_utils.cc @@ -27,7 +27,7 @@ void make_mib_cfg(const sched_nr_cell_cfg_t& cfg, srsran_mib_nr_t* mib) { *mib = {}; mib->scs_common = (srsran_subcarrier_spacing_t)cfg.dl_cfg_common.init_dl_bwp.generic_params.subcarrier_spacing.value; - mib->ssb_offset = 6; // TODO + mib->ssb_offset = cfg.ssb_offset; mib->dmrs_typeA_pos = (srsran_dmrs_sch_typeA_pos_t)cfg.dmrs_type_a_position.value; mib->coreset0_idx = cfg.pdcch_cfg_sib1.ctrl_res_set_zero; mib->ss0_idx = cfg.pdcch_cfg_sib1.search_space_zero; diff --git a/srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h b/srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h index e48bf0619..f6ca7d41e 100644 --- a/srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h +++ b/srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h @@ -71,7 +71,7 @@ inline sched_nr_cell_cfg_t get_default_cell_cfg(const srsran::phy_cfg_nr_t& phy_ // TODO: phy_cfg.ssb_positions_in_burst.group_presence_present cell_cfg.dmrs_type_a_position.value = asn1::rrc_nr::mib_s::dmrs_type_a_position_opts::pos2; cell_cfg.ssb_scs.value = (asn1::rrc_nr::subcarrier_spacing_opts::options)phy_cfg.ssb.scs; - cell_cfg.pdcch_cfg_sib1.ctrl_res_set_zero = 6; + cell_cfg.pdcch_cfg_sib1.ctrl_res_set_zero = 0; cell_cfg.pdcch_cfg_sib1.search_space_zero = 0; cell_cfg.bwps.resize(1); diff --git a/srsgnb/src/stack/rrc/cell_asn1_config.cc b/srsgnb/src/stack/rrc/cell_asn1_config.cc index 2a1a9d2fc..314811c49 100644 --- a/srsgnb/src/stack/rrc/cell_asn1_config.cc +++ b/srsgnb/src/stack/rrc/cell_asn1_config.cc @@ -1089,7 +1089,7 @@ int fill_mib_from_enb_cfg(const rrc_cell_cfg_nr_t& cell_cfg, asn1::rrc_nr::mib_s default: srsran_terminate("Invalid carrier SCS=%d Hz", SRSRAN_SUBC_SPACING_NR(cell_cfg.phy_cell.carrier.scs)); } - mib.ssb_subcarrier_offset = 6; // TODO: currently hard-coded + mib.ssb_subcarrier_offset = cell_cfg.ssb_offset; mib.dmrs_type_a_position.value = mib_s::dmrs_type_a_position_opts::pos2; mib.pdcch_cfg_sib1.search_space_zero = 0; mib.pdcch_cfg_sib1.ctrl_res_set_zero = cell_cfg.coreset0_idx; diff --git a/srsgnb/src/stack/rrc/rrc_nr.cc b/srsgnb/src/stack/rrc/rrc_nr.cc index 8b20dd4c6..59ed42aff 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -338,6 +338,7 @@ void rrc_nr::config_mac() cell.ssb_positions_in_burst = du_cfg->cell(cc).serv_cell_cfg_common().ssb_positions_in_burst; cell.ssb_periodicity_ms = du_cfg->cell(cc).serv_cell_cfg_common().ssb_periodicity_serving_cell.to_number(); cell.ssb_scs.value = (subcarrier_spacing_e::options)cfg.cell_list[0].phy_cell.carrier.scs; + cell.ssb_offset = du_cfg->cell(cc).mib.ssb_subcarrier_offset; if (not cfg.is_standalone) { const serving_cell_cfg_common_s& serv_cell = cell_ctxt->master_cell_group->sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common; diff --git a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc index c29caad9a..bbd0a56cf 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc @@ -115,7 +115,7 @@ void generate_default_nr_phy_cell(phy_cell_cfg_nr_t& phy_cell) void generate_default_nr_cell(rrc_cell_cfg_nr_t& cell) { cell = {}; - cell.coreset0_idx = 6; + cell.coreset0_idx = 7; cell.ssb_absolute_freq_point = 0; // auto derived cell.num_ra_preambles = 8; generate_default_nr_phy_cell(cell.phy_cell); @@ -187,7 +187,41 @@ int derive_ssb_params(bool is_sa, band); // Convert to frequency for PHY - cell.ssb_freq_hz = band_helper.nr_arfcn_to_freq(ssb_abs_freq_point); + cell.ssb_absolute_freq_point = ssb_abs_freq_point; + cell.ssb_freq_hz = band_helper.nr_arfcn_to_freq(ssb_abs_freq_point); + + double pointA_abs_freq_Hz = dl_freq_hz - nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(pdcch_scs) / 2; + uint32_t ssb_pointA_freq_offset_Hz = + (cell.ssb_freq_hz > pointA_abs_freq_Hz) ? (uint32_t)(cell.ssb_freq_hz - pointA_abs_freq_Hz) : 0; + + cell.ssb_offset = (uint32_t)(ssb_pointA_freq_offset_Hz / SRSRAN_SUBC_SPACING_NR(pdcch_scs)) % SRSRAN_NRE; + + // Validate Coreset0 has space + srsran_coreset_t coreset0 = {}; + ERROR_IF_NOT( + srsran_coreset_zero( + cell.phy_cell.cell_id, ssb_pointA_freq_offset_Hz, cell.ssb_scs, pdcch_scs, coreset0_idx, &coreset0) == 0, + "Deriving parameters for coreset0: index=%d, ssb_pointA_offset=%d kHz\n", + coreset0_idx, + ssb_pointA_freq_offset_Hz / 1000); + + ERROR_IF_NOT(srsran_coreset_start_rb(&coreset0) + srsran_coreset_get_bw(&coreset0) <= cell.phy_cell.carrier.nof_prb, + "Coreset0 index=%d is not compatible with DL ARFCN %d in band %d\n", + coreset0_idx, + cell.dl_arfcn, + cell.band); + + // Validate Coreset0 has less than 3 symbols + ERROR_IF_NOT(coreset0.duration < 3, + "Coreset0 index=%d is not supported due to overlap with SSB. Select a coreset0 index from 38.213 Table " + "13-1 such that N_symb_coreset < 3\n", + coreset0_idx); + + // Validate Coreset0 has more than 24 RB + ERROR_IF_NOT(srsran_coreset_get_bw(&coreset0) > 24, + "Coreset0 configuration index=%d has only %d RB. A coreset0 index >= 6 is required such as N_rb >= 48\n", + srsran_coreset_get_bw(&coreset0), + coreset0_idx); return SRSRAN_SUCCESS; } @@ -246,15 +280,16 @@ int set_derived_nr_cell_params(bool is_sa, rrc_cell_cfg_nr_t& cell) 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); + ERROR_IF_NOT(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) == 0, + "Deriving SSB parameters\n"); + cell.phy_cell.carrier.ssb_center_freq_hz = cell.ssb_freq_hz; - cell.ssb_absolute_freq_point = band_helper.freq_to_nr_arfcn(cell.ssb_freq_hz); // Derive remaining config params if (not is_sa) {