diff --git a/lib/include/srsran/asn1/rrc_nr_utils.h b/lib/include/srsran/asn1/rrc_nr_utils.h index a303f7815..d08dce7ae 100644 --- a/lib/include/srsran/asn1/rrc_nr_utils.h +++ b/lib/include/srsran/asn1/rrc_nr_utils.h @@ -129,6 +129,9 @@ bool fill_phy_ssb_cfg(const srsran_carrier_nr_t& carrier phy_cfg_nr_t::ssb_cfg_t* out_ssb); void fill_ssb_pos_in_burst(const asn1::rrc_nr::serving_cell_cfg_common_sib_s& ssb_pos, phy_cfg_nr_t::ssb_cfg_t* out_ssb); +bool fill_ssb_pattern_scs(const srsran_carrier_nr_t& carrier, + srsran_ssb_patern_t* pattern, + srsran_subcarrier_spacing_t* ssb_scs); bool fill_phy_ssb_cfg(const srsran_carrier_nr_t& carrier, const asn1::rrc_nr::serving_cell_cfg_common_sib_s& serv_cell_cfg, srsran_ssb_cfg_t* out_ssb); @@ -140,7 +143,7 @@ bool make_pdsch_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_ bool make_csi_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_csi_hl_cfg_t* csi_hl); bool make_duplex_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell, srsran_duplex_config_nr_t* duplex_cfg); -void fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch); +bool fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch); bool fill_phy_pdcch_cfg(const asn1::rrc_nr::pdcch_cfg_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch); bool fill_phy_pdsch_cfg_common(const asn1::rrc_nr::pdsch_cfg_common_s& pdsch_cfg, srsran_sch_hl_cfg_nr_t* pdsch); void fill_phy_pucch_cfg_common(const asn1::rrc_nr::pucch_cfg_common_s& pucch_cfg, srsran_pucch_nr_common_cfg_t* pucch); diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index c48c41706..204b9a9b7 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -1775,7 +1775,7 @@ bool fill_phy_pdcch_cfg(const asn1::rrc_nr::pdcch_cfg_s& pdcch_cfg, srsran_pdcch return true; } -void fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch) +bool fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch) { if (pdcch_cfg.common_ctrl_res_set_present) { pdcch->coreset_present[pdcch_cfg.common_ctrl_res_set.ctrl_res_set_id] = true; @@ -1783,7 +1783,10 @@ void fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg } for (const search_space_s& ss : pdcch_cfg.common_search_space_list) { pdcch->search_space_present[ss.search_space_id] = true; - make_phy_search_space_cfg(ss, &pdcch->search_space[ss.search_space_id]); + if (not make_phy_search_space_cfg(ss, &pdcch->search_space[ss.search_space_id])) { + asn1::log_error("Failed to convert SearchSpace Configuration"); + return false; + } if (pdcch_cfg.ra_search_space_present and pdcch_cfg.ra_search_space == ss.search_space_id) { pdcch->ra_search_space_present = true; pdcch->ra_search_space = pdcch->search_space[ss.search_space_id]; @@ -1792,6 +1795,7 @@ void fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg pdcch->ra_search_space.formats[1] = srsran_dci_format_nr_1_0; } } + return true; } void fill_phy_pucch_cfg_common(const asn1::rrc_nr::pucch_cfg_common_s& pucch_cfg, srsran_pucch_nr_common_cfg_t* pucch) diff --git a/srsgnb/hdr/phy/phy_nr_interfaces.h b/srsgnb/hdr/phy/phy_nr_interfaces.h index 6784909fc..4f91fb479 100644 --- a/srsgnb/hdr/phy/phy_nr_interfaces.h +++ b/srsgnb/hdr/phy/phy_nr_interfaces.h @@ -27,7 +27,6 @@ struct phy_cell_cfg_nr_t { uint32_t root_seq_idx; uint32_t num_ra_preambles; float gain_db; - srsran_pdcch_cfg_nr_t pdcch = {}; ///< Common CORESET and Search Space configuration srsran_pdsch_cfg_t pdsch = {}; srsran_prach_cfg_t prach = {}; bool dl_measure; diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_config.h b/srsgnb/hdr/stack/rrc/rrc_nr_config.h index 5312f6b5b..95cfe1dae 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_config.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_config.h @@ -23,19 +23,21 @@ namespace srsenb { // Cell/Sector configuration for NR cells struct rrc_cell_cfg_nr_t { - phy_cell_cfg_nr_t phy_cell; // already contains all PHY-related parameters (i.e. RF port, PCI, etc.) - uint32_t tac; // Tracking area code - uint32_t dl_arfcn; // DL freq already included in phy_cell - uint32_t ul_arfcn; // UL freq also in phy_cell - uint32_t dl_absolute_freq_point_a; // derived from DL ARFCN - uint32_t ul_absolute_freq_point_a; // derived from UL ARFCN - uint32_t band; - uint32_t coreset0_idx; // Table 13-{1,...15} row index - srsran_duplex_mode_t duplex_mode; - double ssb_freq_hz; - uint32_t ssb_absolute_freq_point; // derived from DL ARFCN (SSB arfcn) - srsran_subcarrier_spacing_t ssb_scs; - srsran_ssb_patern_t ssb_pattern; + phy_cell_cfg_nr_t phy_cell; // already contains all PHY-related parameters (i.e. RF port, PCI, etc.) + uint32_t tac; // Tracking area code + uint32_t dl_arfcn; // DL freq already included in phy_cell + uint32_t ul_arfcn; // UL freq also in phy_cell + uint32_t dl_absolute_freq_point_a; // derived from DL ARFCN + uint32_t ul_absolute_freq_point_a; // derived from UL ARFCN + uint32_t band; + uint32_t coreset0_idx; // Table 13-{1,...15} row index + srsran_duplex_mode_t duplex_mode; + double ssb_freq_hz; + uint32_t ssb_absolute_freq_point; // derived from DL ARFCN (SSB arfcn) + srsran_subcarrier_spacing_t ssb_scs; + srsran_ssb_patern_t ssb_pattern; + asn1::rrc_nr::pdcch_cfg_common_s pdcch_cfg_common; + asn1::rrc_nr::pdcch_cfg_s pdcch_cfg_ded; }; typedef std::vector rrc_cell_list_nr_t; diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h b/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h index 05e063e4f..d0f930a8a 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h @@ -31,6 +31,11 @@ public: asn1::rrc_nr::sib1_s sib1; srsran::unique_byte_buffer_t packed_sib1; + asn1::rrc_nr::subcarrier_spacing_e ssb_scs; + srsran_ssb_patern_t ssb_pattern; + double ssb_center_freq_hz; + double dl_freq_hz; + const asn1::rrc_nr::serving_cell_cfg_common_sib_s& serv_cell_cfg_common() const { return sib1.serving_cell_cfg_common; @@ -63,6 +68,8 @@ private: std::vector > cells; }; +void fill_phy_pdcch_cfg_common(const du_cell_config& cell, srsran_pdcch_cfg_nr_t* pdcch); + } // namespace srsenb #endif // SRSRAN_RRC_NR_DU_MANAGER_H diff --git a/srsgnb/src/stack/rrc/cell_asn1_config.cc b/srsgnb/src/stack/rrc/cell_asn1_config.cc index a79188f0c..4080a5fd2 100644 --- a/srsgnb/src/stack/rrc/cell_asn1_config.cc +++ b/srsgnb/src/stack/rrc/cell_asn1_config.cc @@ -499,32 +499,6 @@ int fill_csi_meas_from_enb_cfg(const rrc_nr_cfg_t& cfg, csi_meas_cfg_s& csi_meas return SRSRAN_SUCCESS; } -/// Fill InitDlBwp with gNB config -int fill_pdcch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pdcch_cfg_s& pdcch_cfg) -{ - auto& cell_cfg = cfg.cell_list.at(cc); - for (uint32_t ss_idx = 1; ss_idx < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; ss_idx++) { - if (cell_cfg.phy_cell.pdcch.search_space_present[ss_idx]) { - auto& search_space_cfg = cell_cfg.phy_cell.pdcch.search_space[ss_idx]; - if (search_space_cfg.type != srsran_search_space_type_ue) { - // Only add UE-specific search spaces at this stage - continue; - } - - // Add UE-specific SearchSpace - pdcch_cfg.search_spaces_to_add_mod_list.push_back({}); - set_search_space_from_phy_cfg(search_space_cfg, pdcch_cfg.search_spaces_to_add_mod_list.back()); - - // Add CORESET associated with SearchSpace - uint32_t coreset_id = search_space_cfg.coreset_id; - auto& coreset_cfg = cell_cfg.phy_cell.pdcch.coreset[coreset_id]; - pdcch_cfg.ctrl_res_set_to_add_mod_list.push_back({}); - set_coreset_from_phy_cfg(coreset_cfg, pdcch_cfg.ctrl_res_set_to_add_mod_list.back()); - } - } - return SRSRAN_SUCCESS; -} - void fill_pdsch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pdsch_cfg_s& out) { out.dmrs_dl_for_pdsch_map_type_a_present = true; @@ -571,8 +545,8 @@ void fill_pdsch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pdsch_cfg /// Fill InitDlBwp with gNB config int fill_init_dl_bwp_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, bwp_dl_ded_s& init_dl_bwp) { - init_dl_bwp.pdcch_cfg_present = true; - HANDLE_ERROR(fill_pdcch_cfg_from_enb_cfg(cfg, cc, init_dl_bwp.pdcch_cfg.set_setup())); + init_dl_bwp.pdcch_cfg_present = true; + init_dl_bwp.pdcch_cfg.set_setup() = cfg.cell_list[cc].pdcch_cfg_ded; init_dl_bwp.pdsch_cfg_present = true; fill_pdsch_cfg_from_enb_cfg(cfg, cc, init_dl_bwp.pdsch_cfg.set_setup()); @@ -1070,7 +1044,7 @@ int fill_mib_from_enb_cfg(const rrc_cell_cfg_nr_t& cell_cfg, asn1::rrc_nr::mib_s return SRSRAN_SUCCESS; } -// Called for SA +// Called for SA and NSA void fill_pdcch_cfg_common(const rrc_nr_cfg_t& cfg, uint32_t cc, pdcch_cfg_common_s& out) { auto& cell_cfg = cfg.cell_list[cc]; @@ -1078,13 +1052,9 @@ void fill_pdcch_cfg_common(const rrc_nr_cfg_t& cfg, uint32_t cc, pdcch_cfg_commo out.ctrl_res_set_zero_present = false; out.search_space_zero_present = false; - if (not cfg.is_standalone) { - // In NSA, Common CORESET is passed in RRC Reconfiguration - out.common_ctrl_res_set_present = true; - set_coreset_from_phy_cfg(cfg.cell_list[cc].phy_cell.pdcch.coreset[1], out.common_ctrl_res_set); - } - out.common_search_space_list.resize(1); - set_search_space_from_phy_cfg(cell_cfg.phy_cell.pdcch.search_space[1], out.common_search_space_list.back()); + out.common_ctrl_res_set_present = cell_cfg.pdcch_cfg_common.common_ctrl_res_set_present; + out.common_ctrl_res_set = cell_cfg.pdcch_cfg_common.common_ctrl_res_set; + out.common_search_space_list = cell_cfg.pdcch_cfg_ded.search_spaces_to_add_mod_list; out.search_space_sib1_present = true; out.search_space_sib1 = 0; diff --git a/srsgnb/src/stack/rrc/rrc_nr.cc b/srsgnb/src/stack/rrc/rrc_nr.cc index b7a0afc8d..9ab5cc2a4 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -273,10 +273,13 @@ void rrc_nr::config_phy() { srsenb::phy_interface_rrc_nr::common_cfg_t common_cfg = {}; common_cfg.carrier = cfg.cell_list[0].phy_cell.carrier; - common_cfg.pdcch = cfg.cell_list[0].phy_cell.pdcch; - common_cfg.prach = cfg.cell_list[0].phy_cell.prach; - common_cfg.duplex_mode = cfg.cell_list[0].duplex_mode; - bool ret = srsran::fill_phy_ssb_cfg( + fill_phy_pdcch_cfg_common(du_cfg->cell(0), &common_cfg.pdcch); + bool ret = srsran::fill_phy_pdcch_cfg( + cell_ctxt->master_cell_group->sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg.setup(), &common_cfg.pdcch); + srsran_assert(ret, "Failed to generate Dedicated PDCCH config"); + common_cfg.prach = cfg.cell_list[0].phy_cell.prach; + common_cfg.duplex_mode = cfg.cell_list[0].duplex_mode; + ret = srsran::fill_phy_ssb_cfg( cfg.cell_list[0].phy_cell.carrier, du_cfg->cell(0).serv_cell_cfg_common(), &common_cfg.ssb); srsran_assert(ret, "Failed to generate PHY config"); if (phy->set_common_cfg(common_cfg) < SRSRAN_SUCCESS) { @@ -298,7 +301,10 @@ void rrc_nr::config_mac() sched_nr_cell_cfg_t& cell = sched_cells_cfg[cc]; // Derive cell config from rrc_nr_cfg_t - cell.bwps[0].pdcch = cfg.cell_list[cc].phy_cell.pdcch; + fill_phy_pdcch_cfg_common(du_cfg->cell(cc), &cell.bwps[0].pdcch); + bool ret = srsran::fill_phy_pdcch_cfg( + cell_ctxt->master_cell_group->sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg.setup(), &cell.bwps[0].pdcch); + srsran_assert(ret, "Failed to generate Dedicated PDCCH config"); cell.pci = cfg.cell_list[cc].phy_cell.carrier.pci; cell.nof_layers = cfg.cell_list[cc].phy_cell.carrier.max_mimo_layers; cell.dl_cell_nof_prb = cfg.cell_list[cc].phy_cell.carrier.nof_prb; diff --git a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc index 77ac0e6dd..fbf29d151 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc @@ -30,6 +30,33 @@ namespace srsenb { +uint32_t coreset_get_bw(const asn1::rrc_nr::ctrl_res_set_s& coreset) +{ + uint32_t prb_count = 0; + + // Iterate all the frequency domain resources bit-map... + for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { + // ... and count 6 PRB for every frequency domain resource that it is enabled + if (coreset.freq_domain_res.get(i)) { + prb_count += 6; + } + } + + // Return the total count of physical resource blocks + return prb_count; +} + +int coreset_get_pdcch_nr_max_candidates(const asn1::rrc_nr::ctrl_res_set_s& coreset, uint32_t aggregation_level) +{ + uint32_t coreset_bw = coreset_get_bw(coreset); + uint32_t nof_cce = (coreset_bw * coreset.dur) / 6; + + uint32_t L = 1U << aggregation_level; + uint32_t nof_candidates = nof_cce / L; + + return SRSRAN_MIN(nof_candidates, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR); +} + /// Generate default phy cell configuration void generate_default_nr_phy_cell(phy_cell_cfg_nr_t& phy_cell) { @@ -50,35 +77,9 @@ void generate_default_nr_phy_cell(phy_cell_cfg_nr_t& phy_cell) phy_cell.prach.freq_offset = 1; // msg1-FrequencyStart (zero not supported with current PRACH implementation) phy_cell.prach.zero_corr_zone = 0; phy_cell.prach.num_ra_preambles = phy_cell.num_ra_preambles; - phy_cell.prach.hs_flag = false; + phy_cell.prach.hs_flag = false; phy_cell.prach.tdd_config.configured = false; - // PDCCH - // - Add CORESET#2 as UE-specific - phy_cell.pdcch.coreset_present[2] = true; - phy_cell.pdcch.coreset[2].id = 2; - phy_cell.pdcch.coreset[2].duration = 1; - phy_cell.pdcch.coreset[2].mapping_type = srsran_coreset_mapping_type_non_interleaved; - phy_cell.pdcch.coreset[2].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[2].freq_resources[i] = i < SRSRAN_FLOOR(phy_cell.carrier.nof_prb, 6); - } - // - Add SearchSpace#2 as UE-specific - phy_cell.pdcch.search_space_present[2] = true; - phy_cell.pdcch.search_space[2].id = 2; - phy_cell.pdcch.search_space[2].coreset_id = 2; - phy_cell.pdcch.search_space[2].type = srsran_search_space_type_ue; - // Generate frequency resources for the full BW - for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) { - phy_cell.pdcch.search_space[2].nof_candidates[L] = - SRSRAN_MIN(2, srsran_pdcch_nr_max_candidates_coreset(&phy_cell.pdcch.coreset[2], L)); - } - phy_cell.pdcch.search_space[2].nof_formats = 2; - phy_cell.pdcch.search_space[2].formats[0] = srsran_dci_format_nr_0_0; // DCI format for PUSCH - phy_cell.pdcch.search_space[2].formats[1] = srsran_dci_format_nr_1_0; // DCI format for PDSCH - phy_cell.pdcch.search_space[2].duration = 1; - // PDSCH phy_cell.pdsch.rs_power = 0; phy_cell.pdsch.p_b = 0; @@ -91,29 +92,45 @@ void generate_default_nr_cell(rrc_cell_cfg_nr_t& 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.carrier.pci, - ssb_pointA_freq_offset_Hz, - cell.ssb_scs, - cell.phy_cell.carrier.scs, - cell.coreset0_idx, - &cell.phy_cell.pdcch.coreset[0]); - ERROR_IF_NOT(ret == SRSRAN_SUCCESS, "Failed to generate CORESET#0"); - return SRSRAN_SUCCESS; + // PDCCH + // - Add CORESET#2 as UE-specific + cell.pdcch_cfg_ded.ctrl_res_set_to_add_mod_list.resize(1); + auto& coreset2 = cell.pdcch_cfg_ded.ctrl_res_set_to_add_mod_list[0]; + coreset2.ctrl_res_set_id = 2; + // Generate frequency resources for the full BW + for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { + coreset2.freq_domain_res.set(i, i < SRSRAN_FLOOR(cell.phy_cell.carrier.nof_prb, 6)); + } + coreset2.dur = 1; + coreset2.cce_reg_map_type.set_non_interleaved(); + coreset2.precoder_granularity.value = asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; + + // - Add SearchSpace#2 as UE-specific -> CORESET#2 + cell.pdcch_cfg_ded.search_spaces_to_add_mod_list.resize(1); + auto& ss2 = cell.pdcch_cfg_ded.search_spaces_to_add_mod_list[0]; + ss2.search_space_id = 2; + ss2.ctrl_res_set_id_present = true; + ss2.ctrl_res_set_id = coreset2.ctrl_res_set_id; + ss2.dur_present = false; // false for duration=1 + ss2.monitoring_slot_periodicity_and_offset_present = true; + ss2.monitoring_slot_periodicity_and_offset.set_sl1(); + ss2.monitoring_symbols_within_slot_present = true; + ss2.monitoring_symbols_within_slot.from_number(0b10000000000000); + ss2.search_space_type_present = true; + ss2.search_space_type.set_ue_specific().dci_formats.value = asn1::rrc_nr::search_space_s::search_space_type_c_:: + ue_specific_s_::dci_formats_opts::formats0_minus0_and_minus1_minus0; + ss2.nrof_candidates_present = true; + uint32_t nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 0), 2); + asn1::number_to_enum(ss2.nrof_candidates.aggregation_level1, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 1), 2); + asn1::number_to_enum(ss2.nrof_candidates.aggregation_level2, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 2), 2); + asn1::number_to_enum(ss2.nrof_candidates.aggregation_level4, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 3), 2); + asn1::number_to_enum(ss2.nrof_candidates.aggregation_level8, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 4), 2); + asn1::number_to_enum(ss2.nrof_candidates.aggregation_level16, nof_cand); } int derive_ssb_params(bool is_sa, @@ -243,66 +260,65 @@ int set_derived_nr_cell_params(bool is_sa, rrc_cell_cfg_nr_t& cell) cell.ssb_absolute_freq_point = band_helper.freq_to_nr_arfcn(cell.ssb_freq_hz); // Derive remaining config params + cell.pdcch_cfg_common.common_search_space_list.resize(1); // SearchSpace#1 + auto& ss1 = cell.pdcch_cfg_common.common_search_space_list[0]; + ss1.search_space_id = 1; + ss1.dur_present = false; // false for duration=1 + ss1.monitoring_slot_periodicity_and_offset_present = true; + ss1.monitoring_slot_periodicity_and_offset.set_sl1(); + ss1.monitoring_symbols_within_slot_present = true; + ss1.monitoring_symbols_within_slot.from_number(0b10000000000000); + ss1.nrof_candidates_present = true; + ss1.search_space_type_present = true; + ss1.search_space_type.set_common().dci_format0_minus0_and_format1_minus0_present = true; + cell.pdcch_cfg_common.ra_search_space_present = true; + cell.pdcch_cfg_common.ra_search_space = cell.pdcch_cfg_common.common_search_space_list[0].search_space_id; 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].nof_candidates[3] = 0; - cell.phy_cell.pdcch.search_space[0].nof_candidates[4] = 0; - cell.phy_cell.pdcch.search_space[0].nof_formats = 1; - cell.phy_cell.pdcch.search_space[0].formats[0] = srsran_dci_format_nr_1_0; - cell.phy_cell.pdcch.search_space[0].duration = 1; - cell.phy_cell.pdcch.search_space_present[1] = true; - cell.phy_cell.pdcch.search_space[1].id = 1; - cell.phy_cell.pdcch.search_space[1].coreset_id = 0; - cell.phy_cell.pdcch.search_space[1].type = srsran_search_space_type_common_1; - cell.phy_cell.pdcch.search_space[1].nof_candidates[0] = 0; - cell.phy_cell.pdcch.search_space[1].nof_candidates[1] = 0; - cell.phy_cell.pdcch.search_space[1].nof_candidates[2] = 1; - cell.phy_cell.pdcch.search_space[1].nof_candidates[3] = 0; - cell.phy_cell.pdcch.search_space[1].nof_candidates[4] = 0; - cell.phy_cell.pdcch.search_space[1].nof_formats = 2; - cell.phy_cell.pdcch.search_space[1].formats[0] = srsran_dci_format_nr_0_0; // DCI format for PUSCH - cell.phy_cell.pdcch.search_space[1].formats[1] = srsran_dci_format_nr_1_0; // DCI format for PDSCH - cell.phy_cell.pdcch.search_space[1].duration = 1; + // Configure SearchSpace#1 -> CORESET#0 + ss1.ctrl_res_set_id_present = true; + ss1.ctrl_res_set_id = 0; + ss1.nrof_candidates.aggregation_level1.value = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level1_opts::n0; + ss1.nrof_candidates.aggregation_level2.value = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level2_opts::n0; + ss1.nrof_candidates.aggregation_level4.value = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level4_opts::n1; + ss1.nrof_candidates.aggregation_level8.value = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level8_opts::n0; + ss1.nrof_candidates.aggregation_level16.value = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level16_opts::n0; } else { // Configure CORESET#1 - cell.phy_cell.pdcch.coreset_present[1] = true; - cell.phy_cell.pdcch.coreset[1].id = 1; - cell.phy_cell.pdcch.coreset[1].duration = 1; - cell.phy_cell.pdcch.coreset[1].mapping_type = srsran_coreset_mapping_type_non_interleaved; - cell.phy_cell.pdcch.coreset[1].precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle; - + // Note: In NSA, Common CORESET is passed in RRC Reconfiguration + cell.pdcch_cfg_common.common_ctrl_res_set_present = true; + auto& coreset1 = cell.pdcch_cfg_common.common_ctrl_res_set; + coreset1.ctrl_res_set_id = 1; // Generate frequency resources for the full BW - for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { - cell.phy_cell.pdcch.coreset[1].freq_resources[i] = i < SRSRAN_FLOOR(cell.phy_cell.carrier.nof_prb, 6); + for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; ++i) { + coreset1.freq_domain_res.set(i, i < SRSRAN_FLOOR(cell.phy_cell.carrier.nof_prb, 6)); } + coreset1.dur = 1; + coreset1.cce_reg_map_type.set_non_interleaved(); + coreset1.precoder_granularity.value = asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; // Configure SearchSpace#1 -> CORESET#1 - cell.phy_cell.pdcch.search_space_present[1] = true; - cell.phy_cell.pdcch.search_space[1].id = 1; - cell.phy_cell.pdcch.search_space[1].coreset_id = 1; - cell.phy_cell.pdcch.search_space[1].type = srsran_search_space_type_common_3; - // Generate frequency resources for the full BW - for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) { - cell.phy_cell.pdcch.search_space[1].nof_candidates[L] = - SRSRAN_MIN(2, srsran_pdcch_nr_max_candidates_coreset(&cell.phy_cell.pdcch.coreset[1], L)); - } - cell.phy_cell.pdcch.search_space[1].nof_formats = 2; - cell.phy_cell.pdcch.search_space[1].formats[0] = srsran_dci_format_nr_0_0; // DCI format for PUSCH - cell.phy_cell.pdcch.search_space[1].formats[1] = srsran_dci_format_nr_1_0; // DCI format for PDSCH - cell.phy_cell.pdcch.search_space[1].duration = 1; + ss1.ctrl_res_set_id_present = true; + ss1.ctrl_res_set_id = coreset1.ctrl_res_set_id; + uint32_t nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 0), 2); + asn1::number_to_enum(ss1.nrof_candidates.aggregation_level1, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 1), 2); + asn1::number_to_enum(ss1.nrof_candidates.aggregation_level2, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 2), 2); + asn1::number_to_enum(ss1.nrof_candidates.aggregation_level4, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 3), 2); + asn1::number_to_enum(ss1.nrof_candidates.aggregation_level8, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 4), 2); + asn1::number_to_enum(ss1.nrof_candidates.aggregation_level16, nof_cand); + ss1.search_space_type_present = true; + ss1.search_space_type.set_common().dci_format0_minus0_and_format1_minus0_present = true; + // cell.phy_cell.pdcch.search_space[1].type = srsran_search_space_type_common_3; } - cell.phy_cell.pdcch.ra_search_space_present = true; - cell.phy_cell.pdcch.ra_search_space = cell.phy_cell.pdcch.search_space[1]; - cell.phy_cell.pdcch.ra_search_space.type = srsran_search_space_type_common_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); @@ -327,16 +343,11 @@ int check_nr_cell_cfg_valid(const rrc_cell_cfg_nr_t& cell, bool is_sa) // verify SSB params are consistent HANDLE_ERROR(check_nr_phy_cell_cfg_valid(cell.phy_cell)); - if (is_sa) { - ERROR_IF_NOT(cell.phy_cell.pdcch.coreset_present[0], "CORESET#0 must be defined in Standalone mode"); - } - return SRSRAN_SUCCESS; } int check_nr_phy_cell_cfg_valid(const phy_cell_cfg_nr_t& phy_cell) { - HANDLE_ERROR(check_nr_pdcch_cfg_valid(phy_cell.pdcch)); return SRSRAN_SUCCESS; } diff --git a/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc b/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc index 7faf37b17..0b8f2f4f0 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc @@ -12,6 +12,7 @@ #include "srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h" #include "srsgnb/hdr/stack/rrc/cell_asn1_config.h" +#include "srsran/asn1/rrc_nr_utils.h" #include "srsran/common/string_helpers.h" using namespace asn1::rrc_nr; @@ -89,8 +90,60 @@ int du_config_manager::add_cell() cell.sib1.to_json(js); logger.info("SIB1 content: %s", js.to_string().c_str()); + // Generate SSB SCS + srsran_subcarrier_spacing_t ssb_scs; + if (not srsran::fill_ssb_pattern_scs(cfg.cell_list[cell.cc].phy_cell.carrier, &cell.ssb_pattern, &ssb_scs)) { + return SRSRAN_ERROR; + } + cell.ssb_scs.value = (subcarrier_spacing_e::options)ssb_scs; + cell.ssb_center_freq_hz = cfg.cell_list[cell.cc].ssb_freq_hz; + cell.dl_freq_hz = cfg.cell_list[cell.cc].phy_cell.carrier.dl_center_frequency_hz; + cells.push_back(std::move(obj)); return SRSRAN_SUCCESS; } +void fill_phy_pdcch_cfg_common(const du_cell_config& cell, srsran_pdcch_cfg_nr_t* pdcch) +{ + const serving_cell_cfg_common_sib_s& serv_cell = cell.serv_cell_cfg_common(); + const pdcch_cfg_common_s& pdcch_common = serv_cell.dl_cfg_common.init_dl_bwp.pdcch_cfg_common.setup(); + + bool is_sa = pdcch_common.ctrl_res_set_zero_present; + uint8_t coreset0_idx = pdcch_common.ctrl_res_set_zero; + auto scs = (srsran_subcarrier_spacing_t)serv_cell.dl_cfg_common.init_dl_bwp.generic_params.subcarrier_spacing.value; + auto ssb_scs = (srsran_subcarrier_spacing_t)cell.ssb_scs.value; + uint32_t nof_prb = serv_cell.dl_cfg_common.freq_info_dl.scs_specific_carrier_list[0].carrier_bw; + + if (is_sa) { + // Generate CORESET#0 + pdcch->coreset_present[0] = true; + // Get pointA and SSB absolute frequencies + double pointA_abs_freq_Hz = cell.dl_freq_hz - nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(scs) / 2; + double ssb_abs_freq_Hz = cell.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.pci, ssb_pointA_freq_offset_Hz, ssb_scs, scs, coreset0_idx, &pdcch->coreset[0]); + srsran_assert(ret == SRSRAN_SUCCESS, "Failed to generate CORESET#0"); + + // Generate SearchSpace#0 + pdcch->search_space_present[0] = true; + pdcch->search_space[0].id = 0; + pdcch->search_space[0].coreset_id = 0; + pdcch->search_space[0].type = srsran_search_space_type_common_0; + pdcch->search_space[0].nof_candidates[0] = 1; + pdcch->search_space[0].nof_candidates[1] = 1; + pdcch->search_space[0].nof_candidates[2] = 1; + pdcch->search_space[0].nof_candidates[3] = 0; + pdcch->search_space[0].nof_candidates[4] = 0; + pdcch->search_space[0].nof_formats = 1; + pdcch->search_space[0].formats[0] = srsran_dci_format_nr_1_0; + pdcch->search_space[0].duration = 1; + } + + // Generate Common CORESETs and Search Spaces + bool ret = srsran::fill_phy_pdcch_cfg_common(pdcch_common, pdcch); + srsran_assert(ret, "PDCCH Config Common"); +} + } // namespace srsenb \ No newline at end of file diff --git a/srsgnb/src/stack/rrc/rrc_nr_ue.cc b/srsgnb/src/stack/rrc/rrc_nr_ue.cc index 194e36d1a..9a7cb2601 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_ue.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_ue.cc @@ -39,7 +39,9 @@ rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_, uint32_t pcell_cc_idx, bool star if (not parent->cfg.is_standalone) { // Add the final PDCCH config in case of NSA - uecfg.phy_cfg.pdcch = parent->cfg.cell_list[0].phy_cell.pdcch; + srsran::fill_phy_pdcch_cfg( + parent->cell_ctxt->master_cell_group->sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg.setup(), + &uecfg.phy_cfg.pdcch); } else { cell_group_cfg = *parent->cell_ctxt->master_cell_group; next_cell_group_cfg = cell_group_cfg; @@ -1479,13 +1481,11 @@ int rrc_nr::ue::update_mac(const cell_group_cfg_s& cell_group_config, bool is_co auto& pdcch = cell_group_config.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg.setup(); for (auto& ss : pdcch.search_spaces_to_add_mod_list) { uecfg.phy_cfg.pdcch.search_space_present[ss.search_space_id] = true; - uecfg.phy_cfg.pdcch.search_space[ss.search_space_id] = - parent->cfg.cell_list[0].phy_cell.pdcch.search_space[ss.search_space_id]; + srsran::make_phy_search_space_cfg(ss, &uecfg.phy_cfg.pdcch.search_space[ss.search_space_id]); } for (auto& cs : pdcch.ctrl_res_set_to_add_mod_list) { uecfg.phy_cfg.pdcch.coreset_present[cs.ctrl_res_set_id] = true; - uecfg.phy_cfg.pdcch.coreset[cs.ctrl_res_set_id] = - parent->cfg.cell_list[0].phy_cell.pdcch.coreset[cs.ctrl_res_set_id]; + srsran::make_phy_coreset_cfg(cs, &uecfg.phy_cfg.pdcch.coreset[cs.ctrl_res_set_id]); } } diff --git a/test/phy/nr_phy_test.cc b/test/phy/nr_phy_test.cc index 2d163128e..9fb47b0cf 100644 --- a/test/phy/nr_phy_test.cc +++ b/test/phy/nr_phy_test.cc @@ -185,7 +185,6 @@ test_bench::args_t::args_t(int argc, char** argv) cell_list[0].carrier = phy_cfg.carrier; cell_list[0].rf_port = 0; cell_list[0].cell_id = 0; - cell_list[0].pdcch = phy_cfg.pdcch; ue_stack.rnti = rnti;