diff --git a/include/srsran/ran/csi_rs/csi_meas_config.h b/include/srsran/ran/csi_rs/csi_meas_config.h index 3893f8b349..fed5593540 100644 --- a/include/srsran/ran/csi_rs/csi_meas_config.h +++ b/include/srsran/ran/csi_rs/csi_meas_config.h @@ -281,10 +281,10 @@ struct csi_aperiodic_trigger_state { bool operator!=(const csi_aperiodic_trigger_state& rhs) const { return !(rhs == *this); } }; -/// Used to configure the UE with a list of aperiodic trigger states. Each codepoint of the DCI field "CSI request" is -/// associated with one trigger state. +/// \brief Used to configure the UE with a list of aperiodic trigger states. Each codepoint of the DCI field +/// "CSI request" is associated with one trigger state. List size ranges from 0 to MAX_NOF_CSI_APERIODIC_TRIGGERS. /// \remark TS 38.331, \c CSI-AperiodicTriggerStateList. -using csi_aperiodic_trigger_state_list = static_vector; +using csi_aperiodic_trigger_state_list = std::vector; /// See TS 38.331, \c CSI-SemiPersistentOnPUSCH-TriggerState. struct csi_semi_persistent_on_pusch_trigger_state { @@ -322,7 +322,7 @@ struct csi_meas_config { std::vector csi_report_cfg_list; /// Size of CSI request field in DCI (bits). See TS 38.214, clause 5.2.1.5.1. std::optional report_trigger_size; - std::optional aperiodic_trigger_state_list; + csi_aperiodic_trigger_state_list aperiodic_trigger_state_list; std::optional semi_persistent_on_pusch_trigger_state_list; bool operator==(const csi_meas_config& rhs) const diff --git a/include/srsran/ran/meas_gap_config.h b/include/srsran/ran/meas_gap_config.h new file mode 100644 index 0000000000..0532f9b83f --- /dev/null +++ b/include/srsran/ran/meas_gap_config.h @@ -0,0 +1,50 @@ +/* + * + * Copyright 2021-2024 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. + * + */ + +#pragma once + +#include "srsran/ran/slot_point.h" +#include "srsran/ran/subcarrier_spacing.h" + +namespace srsran { + +/// Measurement Gap Repetition Period (MGRP) in msec, as per TS 38.331. +enum class meas_gap_repetition_period : uint8_t { ms20 = 20, ms40 = 40, ms80 = 80, ms160 = 160 }; + +/// Measurement Gap Length (MGL) in msec, as per TS 38.331. +enum class meas_gap_length : uint8_t { ms1dot5, ms3, ms3dot5, ms4, ms5dot5, ms6 }; + +/// Configuration of a Measurement Gap as per TS 38.331, GapConfig. +struct meas_gap_config { + /// Gap offset of the pattern in msec. Value must be between 0 and gap repetition period - 1. + unsigned offset; + /// Measurement Gap Length (MGL). + meas_gap_length mgl; + /// Measurement Gap Repetition Period (MGRP). + meas_gap_repetition_period mgrp; +}; + +/// Convert measurement gap length into a float in milliseconds. +inline unsigned meas_gap_length_to_msec(meas_gap_length len) +{ + constexpr static std::array vals{1.5, 3, 3.5, 4, 5.5, 6}; + return vals[static_cast(len)]; +} + +/// Determines whether a slot is inside the measurement gap. +inline bool is_inside_meas_gap(const meas_gap_config& gap, slot_point sl) +{ + unsigned period_slots = static_cast(gap.mgrp) * sl.nof_slots_per_subframe(); + unsigned length_slots = meas_gap_length_to_msec(gap.mgl) * sl.nof_slots_per_subframe(); + unsigned slot_mod = sl.to_uint() % period_slots; + return slot_mod <= length_slots; +} + +} // namespace srsran \ No newline at end of file diff --git a/include/srsran/scheduler/config/serving_cell_config.h b/include/srsran/scheduler/config/serving_cell_config.h index 216608fe50..0e8fdc4a58 100644 --- a/include/srsran/scheduler/config/serving_cell_config.h +++ b/include/srsran/scheduler/config/serving_cell_config.h @@ -14,6 +14,7 @@ #include "srsran/mac/time_alignment_group_config.h" #include "srsran/ran/carrier_configuration.h" #include "srsran/ran/csi_rs/csi_meas_config.h" +#include "srsran/ran/meas_gap_config.h" #include "srsran/ran/pdcch/downlink_preemption.h" #include "srsran/ran/pdsch/pdsch_mcs.h" #include "srsran/ran/pdsch/pdsch_prb_bundling.h" @@ -250,10 +251,13 @@ struct serving_cell_config { tag_id_t tag_id; }; -/// UE-dedicated configuration for serving cell, as per TS38.331. +/// UE-dedicated configuration for serving cell. struct cell_config_dedicated { - serv_cell_index_t serv_cell_idx; + serv_cell_index_t serv_cell_idx; + /// Serving Cell Configuration as per TS 38.331. serving_cell_config serv_cell_cfg; + /// Measurement Gap Configuration for the cell. + std::optional meas_gap_cfg; }; } // namespace srsran diff --git a/lib/du/du_high/CMakeLists.txt b/lib/du/du_high/CMakeLists.txt index d40d28c400..67204fe9f8 100644 --- a/lib/du/du_high/CMakeLists.txt +++ b/lib/du/du_high/CMakeLists.txt @@ -6,8 +6,8 @@ # the distribution. # -add_subdirectory(adapters) add_subdirectory(du_manager) +add_subdirectory(test_mode) add_library(srsran_du_high STATIC du_high_impl.cpp diff --git a/lib/du/du_high/adapters/CMakeLists.txt b/lib/du/du_high/adapters/CMakeLists.txt index 9b186c2b55..b1ef0ba4b3 100644 --- a/lib/du/du_high/adapters/CMakeLists.txt +++ b/lib/du/du_high/adapters/CMakeLists.txt @@ -6,7 +6,3 @@ # the distribution. # -add_library(srsran_du_high_adapters - mac_test_mode_adapter.cpp - f1ap_test_mode_adapter.cpp) -target_link_libraries(srsran_du_high_adapters srslog srsran_support srsran_du_manager srsran_mac srsran_f1ap_du srsran_e2) diff --git a/lib/du/du_high/du_high_impl.cpp b/lib/du/du_high/du_high_impl.cpp index e013c91c66..ac5e44727e 100644 --- a/lib/du/du_high/du_high_impl.cpp +++ b/lib/du/du_high/du_high_impl.cpp @@ -12,7 +12,7 @@ #include "adapters/adapters.h" #include "adapters/du_high_adapter_factories.h" #include "adapters/f1ap_adapters.h" -#include "adapters/f1ap_test_mode_adapter.h" +#include "test_mode/f1ap_test_mode_adapter.h" #include "srsran/du/du_high/du_manager/du_manager_factory.h" #include "srsran/f1ap/du/f1ap_du_factory.h" #include "srsran/support/executors/task_redispatcher.h" diff --git a/lib/du/du_high/du_manager/converters/asn1_csi_meas_config_helpers.cpp b/lib/du/du_high/du_manager/converters/asn1_csi_meas_config_helpers.cpp index 742001fd85..4fb13a65e9 100644 --- a/lib/du/du_high/du_manager/converters/asn1_csi_meas_config_helpers.cpp +++ b/lib/du/du_high/du_manager/converters/asn1_csi_meas_config_helpers.cpp @@ -1273,15 +1273,15 @@ void srsran::srs_du::calculate_csi_meas_config_diff(asn1::rrc_nr::csi_meas_cfg_s out.report_trigger_size = dest.report_trigger_size.value(); } - if ((dest.aperiodic_trigger_state_list.has_value() and not src.aperiodic_trigger_state_list.has_value()) or - (dest.aperiodic_trigger_state_list.has_value() and src.aperiodic_trigger_state_list.has_value() and + if ((not dest.aperiodic_trigger_state_list.empty() and src.aperiodic_trigger_state_list.empty()) or + (not dest.aperiodic_trigger_state_list.empty() and not src.aperiodic_trigger_state_list.empty() and dest.aperiodic_trigger_state_list != src.aperiodic_trigger_state_list)) { out.aperiodic_trigger_state_list_present = true; auto& ap_trigger_state_list = out.aperiodic_trigger_state_list.set_setup(); - for (const auto& trigger_state : dest.aperiodic_trigger_state_list.value()) { + for (const auto& trigger_state : dest.aperiodic_trigger_state_list) { ap_trigger_state_list.push_back(make_asn1_aperiodic_trigger_state(trigger_state)); } - } else if (src.aperiodic_trigger_state_list.has_value() and not dest.aperiodic_trigger_state_list.has_value()) { + } else if (not src.aperiodic_trigger_state_list.empty() and dest.aperiodic_trigger_state_list.empty()) { out.aperiodic_trigger_state_list_present = true; out.aperiodic_trigger_state_list.set_release(); } diff --git a/lib/du/du_high/test_mode/CMakeLists.txt b/lib/du/du_high/test_mode/CMakeLists.txt new file mode 100644 index 0000000000..c80e7adf43 --- /dev/null +++ b/lib/du/du_high/test_mode/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# Copyright 2021-2024 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. +# + +add_library(srsran_du_high_adapters + mac_test_mode_adapter.cpp + f1ap_test_mode_adapter.cpp + mac_test_mode_helpers.cpp) +target_link_libraries(srsran_du_high_adapters srslog srsran_support srsran_du_manager srsran_mac srsran_f1ap_du srsran_e2) diff --git a/lib/du/du_high/adapters/f1ap_test_mode_adapter.cpp b/lib/du/du_high/test_mode/f1ap_test_mode_adapter.cpp similarity index 100% rename from lib/du/du_high/adapters/f1ap_test_mode_adapter.cpp rename to lib/du/du_high/test_mode/f1ap_test_mode_adapter.cpp diff --git a/lib/du/du_high/adapters/f1ap_test_mode_adapter.h b/lib/du/du_high/test_mode/f1ap_test_mode_adapter.h similarity index 100% rename from lib/du/du_high/adapters/f1ap_test_mode_adapter.h rename to lib/du/du_high/test_mode/f1ap_test_mode_adapter.h diff --git a/lib/du/du_high/adapters/mac_test_mode_adapter.cpp b/lib/du/du_high/test_mode/mac_test_mode_adapter.cpp similarity index 73% rename from lib/du/du_high/adapters/mac_test_mode_adapter.cpp rename to lib/du/du_high/test_mode/mac_test_mode_adapter.cpp index d2bf8fae2f..ff1dd8db97 100644 --- a/lib/du/du_high/adapters/mac_test_mode_adapter.cpp +++ b/lib/du/du_high/test_mode/mac_test_mode_adapter.cpp @@ -9,7 +9,8 @@ */ #include "mac_test_mode_adapter.h" -#include "du_high_adapter_factories.h" +#include "../adapters/du_high_adapter_factories.h" +#include "mac_test_mode_helpers.h" #include "srsran/adt/ring_buffer.h" #include "srsran/mac/mac_factory.h" #include "srsran/ran/csi_report/csi_report_on_pucch_helpers.h" @@ -25,26 +26,6 @@ using namespace srs_du; // the largest TB possible. static const unsigned TEST_UE_DL_BUFFER_STATE_UPDATE_SIZE = 10000000; -static expected create_test_pdu_with_bsr(slot_point sl_rx, rnti_t test_rnti, harq_id_t harq_id) -{ - // - 8-bit R/LCID MAC subheader. - // - MAC CE with Long BSR. - // - // | | | | | | | | | - // | R | R | LCID | Octet 1 - // | L | Octet 2 - // | LCG7 | LCG6 | ... | LCG0 | Octet 3 - // | Buffer Size 1 | Octet 4 - - // We pass BSR=254, which according to TS38.321 is the maximum value for the LBSR size. - auto buf = byte_buffer::create({0x3e, 0x02, 0x01, 254}); - if (not buf.has_value()) { - return make_unexpected(default_error_t{}); - } - return mac_rx_data_indication{ - sl_rx, to_du_cell_index(0), mac_rx_pdu_list{mac_rx_pdu{test_rnti, 0, harq_id, std::move(buf.value())}}}; -} - namespace { /// \brief Adapter for the MAC SDU TX builder that auto fills the DL buffer state update. @@ -176,27 +157,13 @@ void mac_test_mode_cell_adapter::handle_slot_indication(slot_point sl_tx) // > Handle pending PUCCHs. for (const pucch_info& pucch : entry.pucchs) { - mac_uci_pdu& pdu = uci_ind.ucis.emplace_back(); - pdu.rnti = pucch.crnti; - switch (pucch.format) { - case pucch_format::FORMAT_0: - case pucch_format::FORMAT_1: { - fill_uci_pdu(pdu.pdu.emplace(), pucch); - } break; - case pucch_format::FORMAT_2: { - fill_uci_pdu(pdu.pdu.emplace(), pucch); - } break; - default: - break; - } + uci_ind.ucis.emplace_back(create_uci_pdu(pucch, test_ue_cfg)); } // > Handle pending PUSCHs. for (const ul_sched_info& pusch : entry.puschs) { if (pusch.uci.has_value()) { - mac_uci_pdu& pdu = uci_ind.ucis.emplace_back(); - pdu.rnti = pusch.pusch_cfg.rnti; - fill_uci_pdu(pdu.pdu.emplace(), pusch); + uci_ind.ucis.emplace_back(create_uci_pdu(pusch, test_ue_cfg)); } } @@ -283,118 +250,6 @@ void mac_test_mode_cell_adapter::handle_crc(const mac_crc_indication_message& ms forward_crc_ind_to_mac(msg_copy); } -void mac_test_mode_cell_adapter::fill_uci_pdu(mac_uci_pdu::pucch_f0_or_f1_type& pucch_ind, - const pucch_info& pucch) const -{ - pucch_ind.ul_sinr_dB = 100; - srsran_assert(pucch.format == pucch_format::FORMAT_0 or pucch.format == pucch_format::FORMAT_1, - "Expected PUCCH Format is F0 or F1"); - if (pucch.format == pucch_format::FORMAT_0) { - // In case of Format 0, unlike with Format 0, the GNB only schedules 1 PUCCH per slot; this PUCCH (and the - // corresponding UCI indication) can have HARQ-ACK bits or SR bits, or both. - if (pucch.format_0.sr_bits != sr_nof_bits::no_sr) { - // In test mode, SRs are never detected, and instead BSR is injected. - pucch_ind.sr_info.emplace(); - pucch_ind.sr_info.value().detected = false; - } - if (pucch.format_0.harq_ack_nof_bits > 0) { - pucch_ind.harq_info.emplace(); - pucch_ind.harq_info->harqs.resize(pucch.format_0.harq_ack_nof_bits, uci_pucch_f0_or_f1_harq_values::ack); - } - } else { - if (pucch.format_1.sr_bits != sr_nof_bits::no_sr) { - // In test mode, SRs are never detected, and instead BSR is injected. - pucch_ind.sr_info.emplace(); - pucch_ind.sr_info.value().detected = false; - } - if (pucch.format_1.harq_ack_nof_bits > 0) { - pucch_ind.harq_info.emplace(); - // In case of PUCCH F1 with only HARQ-ACK bits, set all HARQ-ACK bits to ACK. If SR is included, then we - // consider that the PUCCH is not detected. - auto ack_val = pucch.format_1.sr_bits == sr_nof_bits::no_sr ? uci_pucch_f0_or_f1_harq_values::ack - : uci_pucch_f0_or_f1_harq_values::dtx; - pucch_ind.harq_info->harqs.resize(pucch.format_1.harq_ack_nof_bits, ack_val); - } - } -} - -void mac_test_mode_cell_adapter::fill_uci_pdu(mac_uci_pdu::pucch_f2_or_f3_or_f4_type& pucch_ind, - const pucch_info& pucch) const -{ - pucch_ind.ul_sinr_dB = 100; - if (pucch.format_2.sr_bits != sr_nof_bits::no_sr) { - // Set SR to not detected. - pucch_ind.sr_info.emplace(); - pucch_ind.sr_info->resize(sr_nof_bits_to_uint(pucch.format_2.sr_bits)); - } - if (pucch.format_2.harq_ack_nof_bits > 0) { - // Set all HARQ-ACK bits to ACK. - pucch_ind.harq_info.emplace(); - pucch_ind.harq_info->is_valid = true; - pucch_ind.harq_info->payload.resize(pucch.format_2.harq_ack_nof_bits); - pucch_ind.harq_info->payload.fill(); - } - if (pucch.csi_rep_cfg.has_value()) { - pucch_ind.csi_part1_info.emplace(); - pucch_ind.csi_part1_info->is_valid = true; - fill_csi_bits(pucch.crnti, pucch_ind.csi_part1_info->payload); - } -} - -void mac_test_mode_cell_adapter::fill_uci_pdu(mac_uci_pdu::pusch_type& pusch_ind, const ul_sched_info& ul_grant) const -{ - const uci_info& uci_info = *ul_grant.uci; - pusch_ind.ul_sinr_dB = 100; - if (uci_info.harq.has_value() and uci_info.harq->harq_ack_nof_bits > 0) { - pusch_ind.harq_info.emplace(); - pusch_ind.harq_info->is_valid = true; - pusch_ind.harq_info->payload.resize(uci_info.harq.value().harq_ack_nof_bits); - pusch_ind.harq_info->payload.fill(); - } - if (uci_info.csi.has_value() and uci_info.csi->csi_part1_nof_bits > 0) { - pusch_ind.csi_part1_info.emplace(); - pusch_ind.csi_part1_info->is_valid = true; - fill_csi_bits(ul_grant.pusch_cfg.rnti, pusch_ind.csi_part1_info->payload); - } -} - -static bool pucch_info_and_uci_ind_match(const pucch_info& pucch, const mac_uci_pdu& uci_ind) -{ - if (pucch.crnti != uci_ind.rnti) { - return false; - } - if ((pucch.format == pucch_format::FORMAT_0 or pucch.format == pucch_format::FORMAT_1) and - std::holds_alternative(uci_ind.pdu)) { - const auto pucch_pdu_sr_bits = - pucch.format == pucch_format::FORMAT_1 ? pucch.format_1.sr_bits : pucch.format_0.sr_bits; - const auto& f1_ind = std::get(uci_ind.pdu); - if (f1_ind.sr_info.has_value() != (pucch_pdu_sr_bits != sr_nof_bits::no_sr)) { - return false; - } - const auto pucch_pdu_harq_bits = - pucch.format == pucch_format::FORMAT_1 ? pucch.format_1.harq_ack_nof_bits : pucch.format_0.harq_ack_nof_bits; - if (f1_ind.harq_info.has_value() != (pucch_pdu_harq_bits > 0)) { - return false; - } - return true; - } - if (pucch.format == pucch_format::FORMAT_2 and - std::holds_alternative(uci_ind.pdu)) { - const auto& f2_ind = std::get(uci_ind.pdu); - if (f2_ind.sr_info.has_value() != (pucch.format_2.sr_bits != sr_nof_bits::no_sr)) { - return false; - } - if (f2_ind.harq_info.has_value() != (pucch.format_2.harq_ack_nof_bits > 0)) { - return false; - } - if (f2_ind.csi_part1_info.has_value() != pucch.csi_rep_cfg.has_value()) { - return false; - } - return true; - } - return false; -} - void mac_test_mode_cell_adapter::forward_uci_ind_to_mac(const mac_uci_indication_message& uci_msg) { if (uci_msg.ucis.empty()) { @@ -448,7 +303,7 @@ void mac_test_mode_cell_adapter::handle_uci(const mac_uci_indication_message& ms if (std::holds_alternative(test_uci.pdu)) { for (const ul_sched_info& pusch : entry.puschs) { if (pusch.pusch_cfg.rnti == test_uci.rnti and pusch.uci.has_value()) { - fill_uci_pdu(std::get(test_uci.pdu), pusch); + test_uci = create_uci_pdu(pusch, test_ue_cfg); entry_found = true; } } @@ -457,11 +312,7 @@ void mac_test_mode_cell_adapter::handle_uci(const mac_uci_indication_message& ms for (const pucch_info& pucch : entry.pucchs) { if (pucch_info_and_uci_ind_match(pucch, test_uci)) { // Intercept the UCI indication and force HARQ-ACK=ACK and UCI. - if (pucch.format == pucch_format::FORMAT_0 or pucch.format == pucch_format::FORMAT_1) { - fill_uci_pdu(std::get(test_uci.pdu), pucch); - } else { - fill_uci_pdu(std::get(test_uci.pdu), pucch); - } + test_uci = create_uci_pdu(pucch, test_ue_cfg); entry_found = true; } } @@ -578,43 +429,6 @@ void mac_test_mode_cell_adapter::on_new_uplink_scheduler_results(const mac_ul_sc result_notifier.on_new_uplink_scheduler_results(ul_res); } -void mac_test_mode_cell_adapter::fill_csi_bits( - rnti_t rnti, - bounded_bitset& payload) const -{ - static constexpr size_t CQI_BITLEN = 4; - - const sched_ue_config_request& ue_cfg_req = ue_info_mgr.get_sched_ue_cfg_request(rnti); - - if (ue_cfg_req.cells->empty() or not(*ue_cfg_req.cells)[0].serv_cell_cfg.csi_meas_cfg.has_value()) { - return; - } - payload.resize(0); - - unsigned nof_ports = (*ue_cfg_req.cells)[0].serv_cell_cfg.csi_meas_cfg->nzp_csi_rs_res_list[0].res_mapping.nof_ports; - if (nof_ports == 2) { - const size_t RI_BITLEN = 1; - const size_t PMI_BITLEN = 2; - payload.push_back(test_ue_cfg.ri - 1, RI_BITLEN); - payload.push_back(test_ue_cfg.pmi, PMI_BITLEN); - } else if (nof_ports > 2) { - const size_t RI_BITLEN = 2; - const size_t I_1_1_BITLEN = 3; - const size_t I_1_3_BITLEN = test_ue_cfg.ri == 2 ? 1 : 0; - const size_t I_2_BITLEN = test_ue_cfg.ri == 1 ? 2 : 1; - payload.push_back(test_ue_cfg.ri - 1, RI_BITLEN); - if (I_2_BITLEN + I_1_1_BITLEN + I_1_3_BITLEN < 5) { - payload.push_back(false); - } - payload.push_back(test_ue_cfg.i_1_1, I_1_1_BITLEN); - if (I_1_3_BITLEN > 0) { - payload.push_back(*test_ue_cfg.i_1_3, I_1_3_BITLEN); - } - payload.push_back(test_ue_cfg.i_2, I_2_BITLEN); - } - payload.push_back(test_ue_cfg.cqi, CQI_BITLEN); -} - // ---- mac_cell_result_notifier& phy_test_mode_adapter::get_cell(du_cell_index_t cell_index) diff --git a/lib/du/du_high/adapters/mac_test_mode_adapter.h b/lib/du/du_high/test_mode/mac_test_mode_adapter.h similarity index 95% rename from lib/du/du_high/adapters/mac_test_mode_adapter.h rename to lib/du/du_high/test_mode/mac_test_mode_adapter.h index db1d19c595..063287a7f8 100644 --- a/lib/du/du_high/adapters/mac_test_mode_adapter.h +++ b/lib/du/du_high/test_mode/mac_test_mode_adapter.h @@ -52,6 +52,12 @@ class test_ue_info_manager return rnti_to_ue_info_lookup.at(rnti).sched_ue_cfg_req; } + const sched_ue_config_request* find_sched_ue_cfg_request(rnti_t rnti) const + { + auto it = rnti_to_ue_info_lookup.find(rnti); + return it != rnti_to_ue_info_lookup.end() ? &it->second.sched_ue_cfg_req : nullptr; + } + bool is_msg4_rxed(rnti_t rnti) const { if (rnti_to_ue_info_lookup.count(rnti) > 0) { @@ -162,10 +168,6 @@ class mac_test_mode_cell_adapter : public mac_cell_control_information_handler, std::vector puschs; }; - void fill_csi_bits(rnti_t rnti, bounded_bitset& payload) const; - void fill_uci_pdu(mac_uci_pdu::pucch_f0_or_f1_type& pucch_ind, const pucch_info& pucch) const; - void fill_uci_pdu(mac_uci_pdu::pucch_f2_or_f3_or_f4_type& pucch_ind, const pucch_info& pucch) const; - void fill_uci_pdu(mac_uci_pdu::pusch_type& pusch_ind, const ul_sched_info& ul_grant) const; void forward_uci_ind_to_mac(const mac_uci_indication_message& uci_msg); void forward_crc_ind_to_mac(const mac_crc_indication_message& crc_msg); diff --git a/lib/du/du_high/test_mode/mac_test_mode_helpers.cpp b/lib/du/du_high/test_mode/mac_test_mode_helpers.cpp new file mode 100644 index 0000000000..ba52c66326 --- /dev/null +++ b/lib/du/du_high/test_mode/mac_test_mode_helpers.cpp @@ -0,0 +1,248 @@ +/* + * + * Copyright 2021-2024 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 "mac_test_mode_helpers.h" + +using namespace srsran; +using namespace srs_du; + +expected +srsran::srs_du::create_test_pdu_with_bsr(slot_point sl_rx, rnti_t test_rnti, harq_id_t harq_id) +{ + // - 8-bit R/LCID MAC subheader. + // - MAC CE with Long BSR. + // + // | | | | | | | | | + // | R | R | LCID | Octet 1 + // | L | Octet 2 + // | LCG7 | LCG6 | ... | LCG0 | Octet 3 + // | Buffer Size 1 | Octet 4 + + // We pass BSR=254, which according to TS38.321 is the maximum value for the LBSR size. + auto buf = byte_buffer::create({0x3e, 0x02, 0x01, 254}); + if (not buf.has_value()) { + return make_unexpected(default_error_t{}); + } + return mac_rx_data_indication{ + sl_rx, to_du_cell_index(0), mac_rx_pdu_list{mac_rx_pdu{test_rnti, 0, harq_id, std::move(buf.value())}}}; +} + +static void fill_csi_bits(bounded_bitset& payload, + rnti_t rnti, + unsigned nof_ports, + const du_test_mode_config::test_mode_ue_config& test_ue_cfg) +{ + static constexpr size_t CQI_BITLEN = 4; + + payload.resize(0); + if (nof_ports == 2) { + const size_t RI_BITLEN = 1; + const size_t PMI_BITLEN = 2; + payload.push_back(test_ue_cfg.ri - 1, RI_BITLEN); + payload.push_back(test_ue_cfg.pmi, PMI_BITLEN); + } else if (nof_ports > 2) { + const size_t RI_BITLEN = 2; + const size_t I_1_1_BITLEN = 3; + const size_t I_1_3_BITLEN = test_ue_cfg.ri == 2 ? 1 : 0; + const size_t I_2_BITLEN = test_ue_cfg.ri == 1 ? 2 : 1; + payload.push_back(test_ue_cfg.ri - 1, RI_BITLEN); + if (I_2_BITLEN + I_1_1_BITLEN + I_1_3_BITLEN < 5) { + payload.push_back(false); + } + payload.push_back(test_ue_cfg.i_1_1, I_1_1_BITLEN); + if (I_1_3_BITLEN > 0) { + payload.push_back(*test_ue_cfg.i_1_3, I_1_3_BITLEN); + } + payload.push_back(test_ue_cfg.i_2, I_2_BITLEN); + } + payload.push_back(test_ue_cfg.cqi, CQI_BITLEN); +} + +static unsigned get_nof_ports(const csi_report_configuration& csi_rep_cfg) +{ + switch (csi_rep_cfg.pmi_codebook) { + case pmi_codebook_type::one: + return 1; + break; + case pmi_codebook_type::two: + return 2; + break; + case pmi_codebook_type::typeI_single_panel_4ports_mode1: + return 4; + break; + default: + report_fatal_error("Unsupported CSI report type"); + } + return 1; +} + +static void fill_csi_bits(bounded_bitset& payload, + rnti_t rnti, + const pucch_info& pucch, + const du_test_mode_config::test_mode_ue_config& test_ue_cfg) +{ + unsigned nof_ports = pucch.csi_rep_cfg.has_value() ? get_nof_ports(pucch.csi_rep_cfg.value()) : 1; + fill_csi_bits(payload, rnti, nof_ports, test_ue_cfg); +} + +static void fill_csi_bits(bounded_bitset& payload, + rnti_t rnti, + const ul_sched_info& pusch, + const du_test_mode_config::test_mode_ue_config& test_ue_cfg) +{ + if (not pusch.uci.has_value() or not pusch.uci.value().csi.has_value()) { + return; + } + const auto& csi_rep_cfg = pusch.uci.value().csi.value().csi_rep_cfg; + unsigned nof_ports = get_nof_ports(csi_rep_cfg); + fill_csi_bits(payload, rnti, nof_ports, test_ue_cfg); +} + +static mac_uci_pdu::pucch_f0_or_f1_type make_f0f1_uci_pdu(const pucch_info& pucch, + const du_test_mode_config::test_mode_ue_config& test_ue_cfg) +{ + mac_uci_pdu::pucch_f0_or_f1_type pucch_ind; + + pucch_ind.ul_sinr_dB = 100; + srsran_assert(pucch.format == pucch_format::FORMAT_0 or pucch.format == pucch_format::FORMAT_1, + "Expected PUCCH Format is F0 or F1"); + if (pucch.format == pucch_format::FORMAT_0) { + // In case of Format 0, unlike with Format 0, the GNB only schedules 1 PUCCH per slot; this PUCCH (and the + // corresponding UCI indication) can have HARQ-ACK bits or SR bits, or both. + if (pucch.format_0.sr_bits != sr_nof_bits::no_sr) { + // In test mode, SRs are never detected, and instead BSR is injected. + pucch_ind.sr_info.emplace(); + pucch_ind.sr_info.value().detected = false; + } + if (pucch.format_0.harq_ack_nof_bits > 0) { + pucch_ind.harq_info.emplace(); + pucch_ind.harq_info->harqs.resize(pucch.format_0.harq_ack_nof_bits, uci_pucch_f0_or_f1_harq_values::ack); + } + } else { + if (pucch.format_1.sr_bits != sr_nof_bits::no_sr) { + // In test mode, SRs are never detected, and instead BSR is injected. + pucch_ind.sr_info.emplace(); + pucch_ind.sr_info.value().detected = false; + } + if (pucch.format_1.harq_ack_nof_bits > 0) { + pucch_ind.harq_info.emplace(); + // In case of PUCCH F1 with only HARQ-ACK bits, set all HARQ-ACK bits to ACK. If SR is included, then we + // consider that the PUCCH is not detected. + auto ack_val = pucch.format_1.sr_bits == sr_nof_bits::no_sr ? uci_pucch_f0_or_f1_harq_values::ack + : uci_pucch_f0_or_f1_harq_values::dtx; + pucch_ind.harq_info->harqs.resize(pucch.format_1.harq_ack_nof_bits, ack_val); + } + } + return pucch_ind; +} + +static mac_uci_pdu::pucch_f2_or_f3_or_f4_type +make_f2_uci_pdu(const pucch_info& pucch, const du_test_mode_config::test_mode_ue_config& test_ue_cfg) +{ + mac_uci_pdu::pucch_f2_or_f3_or_f4_type pucch_ind; + pucch_ind.ul_sinr_dB = 100; + if (pucch.format_2.sr_bits != sr_nof_bits::no_sr) { + // Set SR to not detected. + pucch_ind.sr_info.emplace(); + pucch_ind.sr_info->resize(sr_nof_bits_to_uint(pucch.format_2.sr_bits)); + } + if (pucch.format_2.harq_ack_nof_bits > 0) { + // Set all HARQ-ACK bits to ACK. + pucch_ind.harq_info.emplace(); + pucch_ind.harq_info->is_valid = true; + pucch_ind.harq_info->payload.resize(pucch.format_2.harq_ack_nof_bits); + pucch_ind.harq_info->payload.fill(); + } + if (pucch.csi_rep_cfg.has_value()) { + pucch_ind.csi_part1_info.emplace(); + pucch_ind.csi_part1_info->is_valid = true; + fill_csi_bits(pucch_ind.csi_part1_info->payload, pucch.crnti, pucch, test_ue_cfg); + } + return pucch_ind; +} + +mac_uci_pdu srsran::srs_du::create_uci_pdu(const pucch_info& pucch, + const du_test_mode_config::test_mode_ue_config& test_ue_cfg) +{ + mac_uci_pdu pdu; + pdu.rnti = pucch.crnti; + switch (pucch.format) { + case pucch_format::FORMAT_0: + case pucch_format::FORMAT_1: + pdu.pdu = make_f0f1_uci_pdu(pucch, test_ue_cfg); + break; + case pucch_format::FORMAT_2: + pdu.pdu = make_f2_uci_pdu(pucch, test_ue_cfg); + break; + default: + report_fatal_error("Invalid format"); + } + return pdu; +} + +mac_uci_pdu srsran::srs_du::create_uci_pdu(const ul_sched_info& pusch, + const du_test_mode_config::test_mode_ue_config& test_ue_cfg) +{ + mac_uci_pdu pdu; + pdu.rnti = pusch.pusch_cfg.rnti; + auto& pusch_ind = pdu.pdu.emplace(); + const uci_info& uci_info = *pusch.uci; + pusch_ind.ul_sinr_dB = 100; + if (uci_info.harq.has_value() and uci_info.harq->harq_ack_nof_bits > 0) { + // If it has HARQ-ACK bits. + pusch_ind.harq_info.emplace(); + pusch_ind.harq_info->is_valid = true; + pusch_ind.harq_info->payload.resize(uci_info.harq.value().harq_ack_nof_bits); + pusch_ind.harq_info->payload.fill(); + } + if (uci_info.csi.has_value() and uci_info.csi->csi_part1_nof_bits > 0) { + pusch_ind.csi_part1_info.emplace(); + pusch_ind.csi_part1_info->is_valid = true; + fill_csi_bits(pusch_ind.csi_part1_info->payload, pusch.pusch_cfg.rnti, pusch, test_ue_cfg); + } + return pdu; +} + +bool srsran::srs_du::pucch_info_and_uci_ind_match(const pucch_info& pucch, const mac_uci_pdu& uci_ind) +{ + if (pucch.crnti != uci_ind.rnti) { + return false; + } + if ((pucch.format == pucch_format::FORMAT_0 or pucch.format == pucch_format::FORMAT_1) and + std::holds_alternative(uci_ind.pdu)) { + const auto pucch_pdu_sr_bits = + pucch.format == pucch_format::FORMAT_1 ? pucch.format_1.sr_bits : pucch.format_0.sr_bits; + const auto& f1_ind = std::get(uci_ind.pdu); + if (f1_ind.sr_info.has_value() != (pucch_pdu_sr_bits != sr_nof_bits::no_sr)) { + return false; + } + const auto pucch_pdu_harq_bits = + pucch.format == pucch_format::FORMAT_1 ? pucch.format_1.harq_ack_nof_bits : pucch.format_0.harq_ack_nof_bits; + if (f1_ind.harq_info.has_value() != (pucch_pdu_harq_bits > 0)) { + return false; + } + return true; + } + if (pucch.format == pucch_format::FORMAT_2 and + std::holds_alternative(uci_ind.pdu)) { + const auto& f2_ind = std::get(uci_ind.pdu); + if (f2_ind.sr_info.has_value() != (pucch.format_2.sr_bits != sr_nof_bits::no_sr)) { + return false; + } + if (f2_ind.harq_info.has_value() != (pucch.format_2.harq_ack_nof_bits > 0)) { + return false; + } + if (f2_ind.csi_part1_info.has_value() != pucch.csi_rep_cfg.has_value()) { + return false; + } + return true; + } + return false; +} diff --git a/lib/du/du_high/test_mode/mac_test_mode_helpers.h b/lib/du/du_high/test_mode/mac_test_mode_helpers.h new file mode 100644 index 0000000000..31e10b9556 --- /dev/null +++ b/lib/du/du_high/test_mode/mac_test_mode_helpers.h @@ -0,0 +1,34 @@ +/* + * + * Copyright 2021-2024 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. + * + */ + +#pragma once + +#include "srsran/du/du_high/du_test_mode_config.h" +#include "srsran/mac/mac_cell_control_information_handler.h" +#include "srsran/mac/mac_pdu_handler.h" +#include "srsran/scheduler/harq_id.h" +#include "srsran/scheduler/scheduler_configurator.h" +#include "srsran/scheduler/scheduler_slot_handler.h" + +namespace srsran { +namespace srs_du { + +/// Create dummy PDU with BSR. +expected create_test_pdu_with_bsr(slot_point sl_rx, rnti_t test_rnti, harq_id_t harq_id); + +/// Setters for UCI PDUs based on config values. +mac_uci_pdu create_uci_pdu(const pucch_info& pucch, const du_test_mode_config::test_mode_ue_config& test_ue_cfg); +mac_uci_pdu create_uci_pdu(const ul_sched_info& pusch, const du_test_mode_config::test_mode_ue_config& test_ue_cfg); + +/// Check whether a PUCCH grant and MAC UCI PDU match in C-RNTI, format and expected info. +bool pucch_info_and_uci_ind_match(const pucch_info& pucch, const mac_uci_pdu& uci_ind); + +} // namespace srs_du +} // namespace srsran \ No newline at end of file diff --git a/lib/f1ap/du/f1ap_du_impl.cpp b/lib/f1ap/du/f1ap_du_impl.cpp index dfe768adf1..094cbe5455 100644 --- a/lib/f1ap/du/f1ap_du_impl.cpp +++ b/lib/f1ap/du/f1ap_du_impl.cpp @@ -163,7 +163,7 @@ void f1ap_du_impl::handle_ue_context_setup_request(const asn1::f1ap::ue_context_ // Schedule UE Context Setup Procedure. du_mng.get_ue_handler(du_ue_index) - .schedule_async_task(launch_async(msg, ues, du_mng, du_ue_index)); + .schedule_async_task(launch_async(msg, ues, du_mng, du_ue_index, ctxt)); } void f1ap_du_impl::handle_ue_context_release_command(const asn1::f1ap::ue_context_release_cmd_s& msg) diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp index cad1bc3722..6cf5b49ede 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.cpp @@ -50,6 +50,13 @@ void f1ap_du_ue_context_modification_procedure::operator()(coro_contexttx_action_ind_present) { + // "If the UE CONTEXT MODIFICATION REQUEST message contains the Transmission Action Indicator IE, the gNB-DU + // shall stop or restart (if already stopped) data transmission for the UE, according to the value of this IE. + // It is up to gNB-DU implementation when to stop or restart the UE scheduling. + CORO_AWAIT(handle_tx_action_indicator()); + } + if (du_response.result) { send_ue_context_modification_response(); } else { @@ -187,3 +194,13 @@ async_task f1ap_du_ue_context_modification_procedure::handle_rrc_container return srb1->handle_pdu_and_await_transmission( req->rrc_container.copy(), req->rrc_delivery_status_request_present, rrc_container_delivery_timeout); } + +async_task f1ap_du_ue_context_modification_procedure::handle_tx_action_indicator() +{ + if (req->tx_action_ind.value == asn1::f1ap::tx_action_ind_opts::stop) { + return ue.du_handler.request_ue_drb_deactivation(ue.context.ue_index); + } + logger.error("{}: Ignoring Transmission Action Indicator IE with \"restart\" value. Cause: Feature not supported", + f1ap_log_prefix{ue.context, name()}); + return launch_no_op_task(); +} diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.h b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.h index 8c61cc5975..908a33b924 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.h +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_modification_procedure.h @@ -31,6 +31,7 @@ class f1ap_du_ue_context_modification_procedure void send_ue_context_modification_failure(); async_task handle_rrc_container(); + async_task handle_tx_action_indicator(); const asn1::f1ap::ue_context_mod_request_s req; f1ap_du_ue& ue; diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp index af670dc902..1c4965be55 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp @@ -27,8 +27,14 @@ f1ap_du_ue_context_setup_procedure::f1ap_du_ue_context_setup_procedure( const asn1::f1ap::ue_context_setup_request_s& msg_, f1ap_du_ue_manager& ue_mng_, f1ap_du_configurator& du_mng_, - du_ue_index_t ue_index_) : - msg(msg_), ue_mng(ue_mng_), du_mng(du_mng_), ue_index(ue_index_), logger(srslog::fetch_basic_logger("DU-F1")) + du_ue_index_t ue_index_, + const f1ap_du_context& ctxt_) : + msg(msg_), + ue_mng(ue_mng_), + du_mng(du_mng_), + ue_index(ue_index_), + logger(srslog::fetch_basic_logger("DU-F1")), + du_ctxt(ctxt_) { } @@ -53,10 +59,24 @@ void f1ap_du_ue_context_setup_procedure::operator()(coro_contextsp_cell_id.plmn_id.to_bytes()).value(), + nr_cell_identity::create(msg->sp_cell_id.nr_cell_id.to_number()).value()}); + if (not sp_cell_index.has_value()) { + // Failed to create UE context in the DU. + logger.warning("{}: Failed to to find spCell with PLMN '{}' and NCI '{}' in DU.", + f1ap_log_prefix{int_to_gnb_cu_ue_f1ap_id(msg->gnb_cu_ue_f1ap_id), name()}, + plmn_identity::from_bytes(msg->sp_cell_id.plmn_id.to_bytes()).value(), + nr_cell_identity::create(msg->sp_cell_id.nr_cell_id.to_number()).value()); + send_ue_context_setup_failure(); + CORO_EARLY_RETURN(); + } + // Request the creation of a new UE context in the DU. - CORO_AWAIT_VALUE( - du_ue_create_response, - du_mng.request_ue_creation(f1ap_ue_context_creation_request{ue_index, to_du_cell_index(msg->serv_cell_idx)})); + CORO_AWAIT_VALUE(du_ue_create_response, + du_mng.request_ue_creation( + f1ap_ue_context_creation_request{ue_index, to_du_cell_index(sp_cell_index.value())})); if (not du_ue_create_response->result) { // Failed to create UE context in the DU. logger.warning("{}: Failed to allocate new UE context in DU.", @@ -125,6 +145,19 @@ async_task f1ap_du_ue_context_setup_procedure::handle_rrc_container() msg->rrc_container.copy(), msg->rrc_delivery_status_request_present, rrc_container_delivery_timeout); } +expected f1ap_du_ue_context_setup_procedure::get_cell_index_from_nr_cgi(nr_cell_global_id_t nr_cgi) const +{ + // Find the spCell index in the F1AP DU context. + if (const auto I = std::find_if(du_ctxt.served_cells.cbegin(), + du_ctxt.served_cells.cend(), + [&nr_cgi](const f1ap_du_cell_context& cell) { return nr_cgi == cell.nr_cgi; }); + I != du_ctxt.served_cells.cend()) { + return std::distance(du_ctxt.served_cells.begin(), I); + } + + return make_unexpected(default_error_t()); +} + async_task f1ap_du_ue_context_setup_procedure::request_du_ue_config() { // Construct DU request. @@ -243,7 +276,9 @@ void f1ap_du_ue_context_setup_procedure::send_ue_context_setup_failure() resp->cause.set_radio_network().value = asn1::f1ap::cause_radio_network_opts::no_radio_res_available; // Send UE CONTEXT SETUP FAILURE to CU-CP. - ue->f1ap_msg_notifier.on_new_message(f1ap_msg); + if (ue != nullptr) { + ue->f1ap_msg_notifier.on_new_message(f1ap_msg); + } logger.debug("{}: Procedure finished with failure.", ue == nullptr ? f1ap_log_prefix{int_to_gnb_cu_ue_f1ap_id(resp->gnb_cu_ue_f1ap_id), name()} diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.h b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.h index 2d639c491a..bb722f12ea 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.h +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.h @@ -10,6 +10,7 @@ #pragma once +#include "../f1ap_du_context.h" #include "../ue_context/f1ap_du_ue.h" #include "srsran/asn1/f1ap/f1ap_pdu_contents_ue.h" @@ -18,29 +19,35 @@ namespace srs_du { class f1ap_du_ue_manager; -/// \brief This procedure handles UE CONTEXT SETUP REQUEST as per TS38.473, Section 8.3.1. +/// This procedure handles UE CONTEXT SETUP REQUEST as per TS38.473, Section 8.3.1. class f1ap_du_ue_context_setup_procedure { public: f1ap_du_ue_context_setup_procedure(const asn1::f1ap::ue_context_setup_request_s& msg, f1ap_du_ue_manager& ue_mng_, f1ap_du_configurator& du_mng_, - du_ue_index_t ue_index_); + du_ue_index_t ue_index_, + const f1ap_du_context& ctxt_); void operator()(coro_context>& ctx); private: - // Initiate UE Configuration in the DU. + /// Initiates UE Configuration in the DU. async_task request_du_ue_config(); - // Send UE Context Setup Response to CU. + /// Sends UE Context Setup Response to CU. void send_ue_context_setup_response(); - // Send UE Context Setup Failure to CU. + /// Sends UE Context Setup Failure to CU. void send_ue_context_setup_failure(); + /// Handles the RRC container. async_task handle_rrc_container(); + /// Gets the cell index that matches the given NR-CGI from the F1AP DU context. + expected get_cell_index_from_nr_cgi(nr_cell_global_id_t nr_cgi) const; + + /// Returns the name of this procedure. const char* name() const { return "UE Context Setup"; } const asn1::f1ap::ue_context_setup_request_s msg; @@ -51,6 +58,9 @@ class f1ap_du_ue_context_setup_procedure f1ap_du_ue* ue = nullptr; + const f1ap_du_context& du_ctxt; + expected sp_cell_index = 0; + std::optional du_ue_create_response; f1ap_ue_context_update_response du_ue_cfg_response; }; diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx2.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx2.cpp index 2c34ad7d52..f90ac739b5 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx2.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx2.cpp @@ -136,6 +136,17 @@ void ldpc_decoder_avx2::analyze_var_to_check_msgs(span } } +void ldpc_decoder_avx2::scale(span out, span in) +{ + mm256::avx2_const_span in_avx2(in, node_size_avx2); + mm256::avx2_span out_avx2(out, node_size_avx2); + for (unsigned i_block = 0; i_block != node_size_avx2; ++i_block) { + out_avx2.set_at( + i_block, + mm256::scale_epi8(in_avx2.get_at(i_block), scaling_factor, log_likelihood_ratio::max().to_value_type())); + } +} + void ldpc_decoder_avx2::compute_check_to_var_msgs(span this_check_to_var, span /*this_var_to_check*/, span rotated_node, @@ -162,9 +173,6 @@ void ldpc_decoder_avx2::compute_check_to_var_msgs(span thi __m256i mask_is_min_epi8 = _mm256_cmpeq_epi8(this_var_index_epi8, min_var_to_check_index_avx2.get_at(i_block)); __m256i check_to_var_epi8 = _mm256_blendv_epi8( min_var_to_check_avx2.get_at(i_block), second_min_var_to_check_avx2.get_at(i_block), mask_is_min_epi8); - // Scale the message to compensate for approximations. - check_to_var_epi8 = - mm256::scale_epi8(check_to_var_epi8, scaling_factor, log_likelihood_ratio::max().to_value_type()); // Sign of the cumulative product of all variable-to-check messages but the current one (same as multiplying the // sign of all messages by the sign of the current one). diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx2.h b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx2.h index 5636d03e72..eb349e84bc 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx2.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx2.h @@ -41,6 +41,8 @@ class ldpc_decoder_avx2 : public ldpc_decoder_impl span rotated_node, unsigned var_node) override; + void scale(span out, span in) override; + void compute_check_to_var_msgs(span this_check_to_var, span this_var_to_check, span rotated_node, diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx512.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx512.cpp index 5db3d45334..87bb912642 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx512.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx512.cpp @@ -152,6 +152,17 @@ void ldpc_decoder_avx512::analyze_var_to_check_msgs(span } } +void ldpc_decoder_avx512::scale(span out, span in) +{ + mm512::avx512_const_span in_avx512(in, node_size_avx512); + mm512::avx512_span out_avx512(out, node_size_avx512); + for (unsigned i_block = 0; i_block != node_size_avx512; ++i_block) { + out_avx512.set_at( + i_block, + mm512::scale_epi8(in_avx512.get_at(i_block), scaling_factor, log_likelihood_ratio::max().to_value_type())); + } +} + void ldpc_decoder_avx512::compute_check_to_var_msgs(span this_check_to_var, span /*this_var_to_check*/, span rotated_node, @@ -179,9 +190,6 @@ void ldpc_decoder_avx512::compute_check_to_var_msgs(span t _mm512_cmpeq_epi8_mask(this_var_index_epi8, min_var_to_check_index_avx512.get_at(i_block)); __m512i check_to_var_epi8 = _mm512_mask_blend_epi8( mask_is_min_epi8, min_var_to_check_avx512.get_at(i_block), second_min_var_to_check_avx512.get_at(i_block)); - // Scale the message to compensate for approximations. - check_to_var_epi8 = - mm512::scale_epi8(check_to_var_epi8, scaling_factor, log_likelihood_ratio::max().to_value_type()); // Sign of the cumulative product of all variable-to-check messages but the current one (same as multiplying the // sign of all messages by the sign of the current one). diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx512.h b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx512.h index b5da3ede1a..c7c5a0e757 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx512.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_avx512.h @@ -41,6 +41,8 @@ class ldpc_decoder_avx512 : public ldpc_decoder_impl span rotated_node, unsigned var_node) override; + void scale(span out, span in) override; + void compute_check_to_var_msgs(span this_check_to_var, span this_var_to_check, span rotated_node, diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_generic.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_generic.cpp index fe0b70618c..48465855d1 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_generic.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_generic.cpp @@ -66,6 +66,8 @@ static log_likelihood_ratio scale_llr(log_likelihood_ratio llr, float scaling_fa std::round(static_cast(llr.to_value_type()) * scaling_factor)); } +void ldpc_decoder_generic::scale(span out, span in) {} + // In the generic implementation we don't physically rotate the node, since we can access the corresponding values by // a simple shift - therefore the unused parameter. void ldpc_decoder_generic::compute_check_to_var_msgs(span this_check_to_var, diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_generic.h b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_generic.h index cb7c7363e1..e64f639ceb 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_generic.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_generic.h @@ -40,6 +40,8 @@ class ldpc_decoder_generic : public ldpc_decoder_impl span rotated_node, unsigned var_node) override; + void scale(span out, span in) override; + void compute_check_to_var_msgs(span this_check_to_var, span this_var_to_check, span rotated_node, diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.cpp index d5ed89e891..9627165480 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.cpp @@ -281,6 +281,10 @@ void ldpc_decoder_impl::update_check_to_variable_messages(unsigned check_node) var_node); } + // Scale the message to compensate for approximations. + scale(min_var_to_check_view, min_var_to_check_view); + scale(second_min_var_to_check_view, second_min_var_to_check_view); + // For all variable nodes connected to this check node. var_node = 0; for (const auto* this_var_index_itr = current_var_indices.cbegin(); this_var_index_itr != this_var_index_end; diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.h b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.h index 9511bdb1a9..b1a4f6f319 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_impl.h @@ -102,6 +102,11 @@ class ldpc_decoder_impl : public ldpc_decoder span rotated_node, unsigned var_node) = 0; + /// \brief helper function for scaling buffers of log-likelihood ratios. + /// \param[out] out Buffer with the output log-likelihood ratios. + /// \param[in] in Buffer with the input log-likelihood ratios. + virtual void scale(span out, span in) = 0; + /// \brief Helper function for \ref update_check_to_variable_messages - Computes the new check-to-variable messages. /// /// The function operates on all the messages corresponding to the variable-to-check edges obtained from lifting a diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_neon.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_neon.cpp index 0679cf005b..72ccfb8db6 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_neon.cpp +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_neon.cpp @@ -135,6 +135,16 @@ void ldpc_decoder_neon::analyze_var_to_check_msgs(span } } +void ldpc_decoder_neon::scale(span out, span in) +{ + neon::neon_const_span in_neon(in, node_size_neon); + neon::neon_span out_neon(out, node_size_neon); + for (unsigned i_block = 0; i_block != node_size_neon; ++i_block) { + out_neon.set_at( + i_block, neon::scale_s8(in_neon.get_at(i_block), scaling_factor, log_likelihood_ratio::max().to_value_type())); + } +} + void ldpc_decoder_neon::compute_check_to_var_msgs(span this_check_to_var, span /*this_var_to_check*/, span rotated_node, @@ -161,8 +171,6 @@ void ldpc_decoder_neon::compute_check_to_var_msgs(span thi uint8x16_t mask_is_min_u8 = vceqq_s8(this_var_index_s8, min_var_to_check_index_neon.get_at(i_block)); int8x16_t check_to_var_s8 = vbslq_s8(mask_is_min_u8, second_min_var_to_check_neon.get_at(i_block), min_var_to_check_neon.get_at(i_block)); - // Scale the message to compensate for approximations. - check_to_var_s8 = neon::scale_s8(check_to_var_s8, scaling_factor, log_likelihood_ratio::max().to_value_type()); // Sign of the cumulative product of all variable-to-check messages but the current one (same as multiplying the // sign of all messages by the sign of the current one). diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_neon.h b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_neon.h index 1e4ef17443..47127464c6 100644 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_neon.h +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_decoder_neon.h @@ -41,6 +41,8 @@ class ldpc_decoder_neon : public ldpc_decoder_impl span rotated_node, unsigned var_node) override; + void scale(span out, span in) override; + void compute_check_to_var_msgs(span this_check_to_var, span this_var_to_check, span rotated_node, diff --git a/lib/scheduler/config/sched_config_manager.cpp b/lib/scheduler/config/sched_config_manager.cpp index 21dd8a4f9d..164f5c8fdd 100644 --- a/lib/scheduler/config/sched_config_manager.cpp +++ b/lib/scheduler/config/sched_config_manager.cpp @@ -215,7 +215,10 @@ void sched_config_manager::handle_ue_config_complete(du_ue_index_t ue_index, std } // Stores new UE config and deletes old config. - ue_cfg_list[ue_index] = std::move(next_cfg); + ue_cfg_list[ue_index].swap(next_cfg); + if (not ues_to_rem.try_push(std::move(next_cfg))) { + logger.warning("Failed to offload UE config removal. Performance may be affected"); + } // Notifies MAC that event is complete. config_notifier.on_ue_config_complete(ue_index, true); diff --git a/lib/scheduler/config/ue_configuration.cpp b/lib/scheduler/config/ue_configuration.cpp index a7e37c2e13..997254b3b8 100644 --- a/lib/scheduler/config/ue_configuration.cpp +++ b/lib/scheduler/config/ue_configuration.cpp @@ -566,17 +566,18 @@ static void assert_dci_size_config(search_space_id ss_id, const dci_size_config& srsran_assert(validate_dci_sz_cfg(), "Invalid DCI size configuration for SearchSpace={}: {}", ss_id, error_msg); } -ue_cell_configuration::ue_cell_configuration(rnti_t crnti_, - const cell_configuration& cell_cfg_common_, - const serving_cell_config& serv_cell_cfg_, - bool multi_cells_configured_) : +ue_cell_configuration::ue_cell_configuration(rnti_t crnti_, + const cell_configuration& cell_cfg_common_, + const serving_cell_config& serv_cell_cfg_, + const std::optional& meas_gap_cfg_, + bool multi_cells_configured_) : crnti(crnti_), cell_cfg_common(cell_cfg_common_), multi_cells_configured(multi_cells_configured_), nof_dl_ports(compute_nof_dl_ports(serv_cell_cfg_)) { // Apply UE-dedicated Config. - reconfigure(serv_cell_cfg_); + reconfigure(serv_cell_cfg_, meas_gap_cfg_); } ue_cell_configuration::ue_cell_configuration(const ue_cell_configuration& other) : @@ -588,9 +589,11 @@ ue_cell_configuration::ue_cell_configuration(const ue_cell_configuration& other) reconfigure(other.cell_cfg_ded); } -void ue_cell_configuration::reconfigure(const serving_cell_config& cell_cfg_ded_req) +void ue_cell_configuration::reconfigure(const serving_cell_config& cell_cfg_ded_req, + const std::optional& meas_gaps_) { cell_cfg_ded = cell_cfg_ded_req; + meas_gap_cfg = meas_gaps_; // Clear previous lookup tables. bwp_table = {}; @@ -750,6 +753,34 @@ bool ue_cell_configuration::is_cfg_dedicated_complete() const (cell_cfg_ded.ul_config.has_value() and cell_cfg_ded.ul_config->init_ul_bwp.pucch_cfg.has_value()); } +bool ue_cell_configuration::is_dl_enabled(slot_point dl_slot) const +{ + if (not cell_cfg_common.is_dl_enabled(dl_slot)) { + return false; + } + if (meas_gap_cfg.has_value()) { + if (is_inside_meas_gap(meas_gap_cfg.value(), dl_slot)) { + return false; + } + } + return true; +} + +bool ue_cell_configuration::is_ul_enabled(slot_point ul_slot) const +{ + if (not cell_cfg_common.is_ul_enabled(ul_slot)) { + return false; + } + if (meas_gap_cfg.has_value()) { + if (is_inside_meas_gap(meas_gap_cfg.value(), ul_slot)) { + return false; + } + } + return true; +} + +// + ue_configuration::ue_configuration(du_ue_index_t ue_index_, rnti_t crnti_) : ue_index(ue_index_), crnti(crnti_) {} ue_configuration::ue_configuration(du_ue_index_t ue_index_, @@ -806,12 +837,12 @@ void ue_configuration::update(const cell_common_configuration_list& common_cells if (not du_cells.contains(cell_index)) { // New Cell. - du_cells.emplace( - cell_index, - std::make_unique(crnti, *common_cells[cell_index], ded_cell.serv_cell_cfg, e > 1)); + du_cells.emplace(cell_index, + std::make_unique( + crnti, *common_cells[cell_index], ded_cell.serv_cell_cfg, ded_cell.meas_gap_cfg, e > 1)); } else { // Reconfiguration of existing cell. - du_cells[cell_index]->reconfigure(ded_cell.serv_cell_cfg); + du_cells[cell_index]->reconfigure(ded_cell.serv_cell_cfg, ded_cell.meas_gap_cfg); } } diff --git a/lib/scheduler/config/ue_configuration.h b/lib/scheduler/config/ue_configuration.h index 084b60ff7f..e010ac8c3c 100644 --- a/lib/scheduler/config/ue_configuration.h +++ b/lib/scheduler/config/ue_configuration.h @@ -91,16 +91,18 @@ struct search_space_info { class ue_cell_configuration { public: - ue_cell_configuration(rnti_t crnti_, - const cell_configuration& cell_cfg_common_, - const serving_cell_config& serv_cell_cfg_, - bool multi_cells_configured = false); + ue_cell_configuration(rnti_t crnti_, + const cell_configuration& cell_cfg_common_, + const serving_cell_config& serv_cell_cfg_, + const std::optional& meas_gap_cfg_ = std::nullopt, + bool multi_cells_configured = false); ue_cell_configuration(const ue_cell_configuration& other); ue_cell_configuration(ue_cell_configuration&&) = delete; ue_cell_configuration& operator=(const ue_cell_configuration&) = delete; ue_cell_configuration& operator=(ue_cell_configuration&&) = delete; - void reconfigure(const serving_cell_config& cell_cfg_ded_); + void reconfigure(const serving_cell_config& cell_cfg_ded_, + const std::optional& meas_gaps = std::nullopt); void set_rrm_config(const sched_ue_resource_alloc_config& ue_res_alloc_cfg); @@ -148,6 +150,12 @@ class ue_cell_configuration /// Get the number of active DL ports for this UE. unsigned get_nof_dl_ports() const { return nof_dl_ports; } + /// Determines whether DL allocations are possible in the provided slot. + bool is_dl_enabled(slot_point dl_slot) const; + + /// Determines whether UL allocations are possible in the provided slot. + bool is_ul_enabled(slot_point ul_slot) const; + /// Determines the use of transform precoding for DCI Format 0_1 for C-RNTI. bool use_pusch_transform_precoding_dci_0_1() const { @@ -209,8 +217,9 @@ class ue_cell_configuration void configure_bwp_ded_cfg(bwp_id_t bwpid, const bwp_uplink_dedicated& bwp_ul_ded); /// Dedicated cell configuration. - serving_cell_config cell_cfg_ded; - bool multi_cells_configured; + serving_cell_config cell_cfg_ded; + std::optional meas_gap_cfg; + bool multi_cells_configured; /// Lookup table for BWP params indexed by BWP-Id. std::array bwp_table = {}; diff --git a/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.cpp b/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.cpp index 3aea01677d..30140f7ef2 100644 --- a/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.cpp +++ b/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.cpp @@ -15,6 +15,12 @@ using namespace srsran; +pdcch_slot_allocator::pdcch_slot_allocator() +{ + dfs_tree.reserve(MAX_DL_PDCCH_PDUS_PER_SLOT + MAX_UL_PDCCH_PDUS_PER_SLOT); + saved_dfs_tree.reserve(MAX_DL_PDCCH_PDUS_PER_SLOT + MAX_UL_PDCCH_PDUS_PER_SLOT); +} + pdcch_slot_allocator::~pdcch_slot_allocator() {} void pdcch_slot_allocator::clear() diff --git a/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.h b/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.h index 99cf6db01b..8e2a9b7e77 100644 --- a/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.h +++ b/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.h @@ -42,6 +42,7 @@ class pdcch_slot_allocator unsigned record_index; }; + pdcch_slot_allocator(); ~pdcch_slot_allocator(); /// Erase the current PDCCH allocations and stored context for this slot. diff --git a/lib/scheduler/policy/scheduler_time_pf.cpp b/lib/scheduler/policy/scheduler_time_pf.cpp index e47a3cbdfd..f58206f11d 100644 --- a/lib/scheduler/policy/scheduler_time_pf.cpp +++ b/lib/scheduler/policy/scheduler_time_pf.cpp @@ -41,7 +41,8 @@ void scheduler_time_pf::dl_sched(ue_pdsch_allocator& pdsch_alloc, ue_history_db.emplace(u.ue_index(), ue_ctxt{u.ue_index(), u.get_pcell().cell_index, this}); } ue_ctxt& ctxt = ue_history_db[u.ue_index()]; - ctxt.compute_dl_prio(u, slice_candidate.id()); + ctxt.compute_dl_prio( + u, slice_candidate.id(), res_grid.get_pdcch_slot(u.get_pcell().cell_index), slice_candidate.get_slot_tx()); dl_queue.push(&ctxt); } @@ -90,7 +91,8 @@ void scheduler_time_pf::ul_sched(ue_pusch_allocator& pusch_alloc, ue_history_db.emplace(u.ue_index(), ue_ctxt{u.ue_index(), u.get_pcell().cell_index, this}); } ue_ctxt& ctxt = ue_history_db[u.ue_index()]; - ctxt.compute_ul_prio(u, res_grid, slice_candidate.id()); + ctxt.compute_ul_prio( + u, slice_candidate.id(), res_grid.get_pdcch_slot(u.get_pcell().cell_index), slice_candidate.get_slot_tx()); ul_queue.push(&ctxt); } @@ -248,7 +250,10 @@ static double compute_ul_rate_weight(const slice_ue& u, double current_ue_ul_avg return qos_gbr_rate_sum / current_ue_ul_avg_rate; } -void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u, ran_slice_id_t slice_id) +void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u, + ran_slice_id_t slice_id, + slot_point pdcch_slot, + slot_point pdsch_slot) { dl_retx_h.reset(); has_empty_dl_harq = false; @@ -260,6 +265,10 @@ void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u, ran_slice_id srsran_assert(ue_cc->is_active() and not ue_cc->is_in_fallback_mode(), "policy scheduler called for UE={} in fallback", ue_cc->ue_index); + if (not ue_cc->is_dl_enabled(pdcch_slot) or not ue_cc->is_dl_enabled(pdsch_slot)) { + // Cannot allocate PDCCH/PDSCH for this UE in this slot. + return; + } std::optional oldest_dl_harq_candidate; for (unsigned i = 0; i != ue_cc->harqs.nof_dl_harqs(); ++i) { @@ -330,9 +339,10 @@ void scheduler_time_pf::ue_ctxt::compute_dl_prio(const slice_ue& u, ran_slice_id has_empty_dl_harq = false; } -void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, - const ue_resource_grid_view& res_grid, - ran_slice_id_t slice_id) +void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, + ran_slice_id_t slice_id, + slot_point pdcch_slot, + slot_point pusch_slot) { ul_retx_h.reset(); has_empty_ul_harq = false; @@ -345,6 +355,10 @@ void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, srsran_assert(ue_cc->is_active() and not ue_cc->is_in_fallback_mode(), "policy scheduler called for UE={} in fallback", ue_cc->ue_index); + if (not ue_cc->is_dl_enabled(pdcch_slot) or not ue_cc->is_ul_enabled(pusch_slot)) { + // Cannot allocate PDCCH/PUSCH for this UE in the provided slots. + return; + } std::optional oldest_ul_harq_candidate; for (unsigned i = 0; i != ue_cc->harqs.nof_ul_harqs(); ++i) { @@ -376,9 +390,8 @@ void scheduler_time_pf::ue_ctxt::compute_ul_prio(const slice_ue& u, const pusch_time_domain_resource_allocation& pusch_td_cfg = pusch_td_res_list.front(); // [Implementation-defined] We assume nof. HARQ ACK bits is zero at PUSCH slot as a simplification in calculating // estimated instantaneous achievable rate. - constexpr unsigned nof_harq_ack_bits = 0; - const bool is_csi_report_slot = csi_helper::is_csi_reporting_slot( - u.get_pcell().cfg().cfg_dedicated(), res_grid.get_pusch_slot(cell_index, pusch_td_cfg.k2)); + constexpr unsigned nof_harq_ack_bits = 0; + const bool is_csi_report_slot = csi_helper::is_csi_reporting_slot(u.get_pcell().cfg().cfg_dedicated(), pusch_slot); pusch_config_params pusch_cfg; switch (ss_info->get_ul_dci_format()) { diff --git a/lib/scheduler/policy/scheduler_time_pf.h b/lib/scheduler/policy/scheduler_time_pf.h index 0804b6eec5..a265fbc044 100644 --- a/lib/scheduler/policy/scheduler_time_pf.h +++ b/lib/scheduler/policy/scheduler_time_pf.h @@ -50,9 +50,9 @@ class scheduler_time_pf : public scheduler_policy [[nodiscard]] double total_ul_avg_rate() const { return ul_nof_samples == 0 ? 0 : total_ul_avg_rate_; } /// Computes the priority of the UE to be scheduled in DL based on the QoS and proportional fair metric. - void compute_dl_prio(const slice_ue& u, ran_slice_id_t slice_id); + void compute_dl_prio(const slice_ue& u, ran_slice_id_t slice_id, slot_point pdcch_slot, slot_point pdsch_slot); /// Computes the priority of the UE to be scheduled in UL based on the proportional fair metric. - void compute_ul_prio(const slice_ue& u, const ue_resource_grid_view& res_grid, ran_slice_id_t slice_id); + void compute_ul_prio(const slice_ue& u, ran_slice_id_t slice_id, slot_point pdcch_slot, slot_point pusch_slot); void save_dl_alloc(uint32_t total_alloc_bytes, const dl_msg_tb_info& tb_info, const slice_ue& u); void save_ul_alloc(uint32_t alloc_bytes); diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index 98362ac3fc..2f8fe7703c 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -250,7 +250,8 @@ static dl_alloc_result alloc_dl_retxs(const slice_ue_repository& ue_db, ue_cc.ue_index); // [Implementation-defined] Skip UE if PDCCH is already allocated for this UE in this slot. - if (res_grid.has_ue_dl_pdcch(ue_cc.cell_index, u.crnti())) { + if (res_grid.has_ue_dl_pdcch(ue_cc.cell_index, u.crnti()) or + not ue_cc.is_dl_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index))) { continue; } @@ -272,11 +273,12 @@ static dl_alloc_result alloc_dl_retxs(const slice_ue_repository& ue_db, } /// Allocate UE PDSCH grant for new transmissions. -static dl_alloc_result alloc_dl_ue_newtx(const slice_ue& u, - const ue_resource_grid_view& res_grid, - ue_pdsch_allocator& pdsch_alloc, - srslog::basic_logger& logger, - std::optional dl_new_tx_max_nof_rbs_per_ue_per_slot = {}) +static dl_alloc_result alloc_dl_ue_newtx(const slice_ue& u, + const ue_resource_grid_view& res_grid, + const dl_ran_slice_candidate& slice_candidate, + ue_pdsch_allocator& pdsch_alloc, + srslog::basic_logger& logger, + std::optional max_pdsch_rbs = {}) { if (not u.has_pending_dl_newtx_bytes()) { return {alloc_status::skip_ue}; @@ -289,15 +291,15 @@ static dl_alloc_result alloc_dl_ue_newtx(const slice_ue& u, "policy scheduler called for UE={} in fallback", ue_cc.ue_index); - // UE is already allocated in the PDCCH for this slot (e.g. we should skip a newTx if a reTx has already been - // allocated for this UE). - if (res_grid.has_ue_dl_pdcch(ue_cc.cell_index, u.crnti())) { + if (res_grid.has_ue_dl_pdcch(ue_cc.cell_index, u.crnti()) or + not ue_cc.is_dl_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index)) or + not ue_cc.is_dl_enabled(slice_candidate.get_slot_tx())) { + // UE is either already allocated for this slot (e.g. a reTx already took place) or it is not active. return {alloc_status::skip_ue}; } if (can_allocate_dl_newtx(u, to_ue_cell_index(i), logger)) { - ue_pdsch_grant grant{ - &u, ue_cc.cell_index, INVALID_HARQ_ID, u.pending_dl_newtx_bytes(), dl_new_tx_max_nof_rbs_per_ue_per_slot}; + ue_pdsch_grant grant{&u, ue_cc.cell_index, INVALID_HARQ_ID, u.pending_dl_newtx_bytes(), max_pdsch_rbs}; const dl_alloc_result result = pdsch_alloc.allocate_dl_grant(grant); // If the allocation failed due to invalid parameters, we continue iteration. if (result.status != alloc_status::invalid_params) { @@ -309,16 +311,17 @@ static dl_alloc_result alloc_dl_ue_newtx(const slice_ue& u, } /// Allocates UE PUSCH grant for retransmissions. -static ul_alloc_result alloc_ul_retxs(const slice_ue_repository& ue_db, - ue_pusch_allocator& pusch_alloc, - ran_slice_id_t slice_id, - ul_harq_pending_retx_list harq_list) +static ul_alloc_result alloc_ul_retxs(const slice_ue_repository& ue_db, + ue_pusch_allocator& pusch_alloc, + const ue_resource_grid_view& res_grid, + ul_ran_slice_candidate& slice_candidate, + ul_harq_pending_retx_list harq_list) { for (auto it = harq_list.begin(); it != harq_list.end();) { // Note: During retx alloc, the pending HARQ list will mutate. So, we prefetch the next node. auto prev_it = it++; auto h = *prev_it; - if (h.get_grant_params().slice_id != slice_id or not ue_db.contains(h.ue_index())) { + if (h.get_grant_params().slice_id != slice_candidate.id() or not ue_db.contains(h.ue_index())) { continue; } const slice_ue& u = ue_db[h.ue_index()]; @@ -329,6 +332,12 @@ static ul_alloc_result alloc_ul_retxs(const slice_ue_repository& ue_db, "policy scheduler called for UE={} in fallback", ue_cc.ue_index); + if (not ue_cc.is_dl_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index)) or + not ue_cc.is_ul_enabled(slice_candidate.get_slot_tx())) { + // Either the PDCCH slot or PUSCH slots are not available. + continue; + } + ue_pusch_grant grant{&u, ue_cc.cell_index, h.id()}; const ul_alloc_result result = pusch_alloc.allocate_ul_grant(grant); // Continue iteration until skip slot indication is received. @@ -347,10 +356,12 @@ static ul_alloc_result alloc_ul_retxs(const slice_ue_repository& ue_db, } /// Allocate UE PUSCH grant for new transmissions. -static ul_alloc_result alloc_ul_ue_newtx(const slice_ue& u, - ue_pusch_allocator& pusch_alloc, - srslog::basic_logger& logger, - std::optional ul_new_tx_max_nof_rbs_per_ue_per_slot = {}) +static ul_alloc_result alloc_ul_ue_newtx(const slice_ue& u, + ue_pusch_allocator& pusch_alloc, + const ue_resource_grid_view& res_grid, + const ul_ran_slice_candidate& slice_candidate, + srslog::basic_logger& logger, + std::optional max_grant_rbs = {}) { unsigned pending_newtx_bytes = 0; pending_newtx_bytes = u.pending_ul_newtx_bytes(); @@ -365,9 +376,14 @@ static ul_alloc_result alloc_ul_ue_newtx(const slice_ue& u, "policy scheduler called for UE={} in fallback", ue_cc.ue_index); + if (not ue_cc.is_dl_enabled(res_grid.get_pdcch_slot(ue_cc.cell_index)) or + not ue_cc.is_ul_enabled(slice_candidate.get_slot_tx())) { + // Either the PDCCH slot or PUSCH slots are not available. + continue; + } + if (can_allocate_ul_newtx(u, to_ue_cell_index(i), logger)) { - ue_pusch_grant grant{ - &u, ue_cc.cell_index, INVALID_HARQ_ID, pending_newtx_bytes, ul_new_tx_max_nof_rbs_per_ue_per_slot}; + ue_pusch_grant grant{&u, ue_cc.cell_index, INVALID_HARQ_ID, pending_newtx_bytes, max_grant_rbs}; const ul_alloc_result result = pusch_alloc.allocate_ul_grant(grant); // If the allocation failed due to invalid parameters, we continue iteration. if (result.status != alloc_status::invalid_params) { @@ -408,14 +424,13 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, return; } - const unsigned dl_new_tx_max_nof_rbs_per_ue_per_slot = + const unsigned max_pdsch_rbs = compute_max_nof_rbs_per_ue_per_slot(ues, true, res_grid, expert_cfg, slice_candidate.get_slot_tx(), max_rbs); - if (dl_new_tx_max_nof_rbs_per_ue_per_slot > 0) { + if (max_pdsch_rbs > 0) { // Then, schedule UEs with new transmissions. - auto drb_newtx_ue_function = - [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const slice_ue& u) { - return alloc_dl_ue_newtx(u, res_grid, pdsch_alloc, logger, dl_new_tx_max_nof_rbs_per_ue_per_slot); - }; + auto drb_newtx_ue_function = [this, &res_grid, &slice_candidate, &pdsch_alloc, max_pdsch_rbs](const slice_ue& u) { + return alloc_dl_ue_newtx(u, res_grid, slice_candidate, pdsch_alloc, logger, max_pdsch_rbs); + }; auto result = round_robin_apply(ues, next_dl_ue_index, drb_newtx_ue_function); next_dl_ue_index = result.first; } @@ -426,9 +441,8 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, ul_ran_slice_candidate& slice_candidate, ul_harq_pending_retx_list harq_pending_retx_list) { - const slice_ue_repository& ues = slice_candidate.get_slice_ues(); - const unsigned max_rbs = slice_candidate.remaining_rbs(); - const ran_slice_id_t slice_id = slice_candidate.id(); + const slice_ue_repository& ues = slice_candidate.get_slice_ues(); + const unsigned max_rbs = slice_candidate.remaining_rbs(); if (ues.empty() or max_rbs == 0) { // No UEs to be scheduled or if there are no RBs to be scheduled in slice. @@ -436,17 +450,17 @@ void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, } // First, schedule UEs with re-transmissions. - auto retx_result = alloc_ul_retxs(ues, pusch_alloc, slice_id, harq_pending_retx_list); + auto retx_result = alloc_ul_retxs(ues, pusch_alloc, res_grid, slice_candidate, harq_pending_retx_list); if (retx_result.status == alloc_status::skip_slot) { return; } // Then, schedule UEs with new transmissions. - const unsigned ul_new_tx_max_nof_rbs_per_ue_per_slot = + const unsigned max_grant_rbs = compute_max_nof_rbs_per_ue_per_slot(ues, false, res_grid, expert_cfg, slice_candidate.get_slot_tx(), max_rbs); - if (ul_new_tx_max_nof_rbs_per_ue_per_slot > 0) { - auto data_tx_ue_function = [this, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot](const slice_ue& u) { - return alloc_ul_ue_newtx(u, pusch_alloc, logger, ul_new_tx_max_nof_rbs_per_ue_per_slot); + if (max_grant_rbs > 0) { + auto data_tx_ue_function = [this, &pusch_alloc, &res_grid, &slice_candidate, max_grant_rbs](const slice_ue& u) { + return alloc_ul_ue_newtx(u, pusch_alloc, res_grid, slice_candidate, logger, max_grant_rbs); }; auto result = round_robin_apply(ues, next_ul_ue_index, data_tx_ue_function); next_ul_ue_index = result.first; diff --git a/lib/scheduler/uci_scheduling/uci_allocator_impl.cpp b/lib/scheduler/uci_scheduling/uci_allocator_impl.cpp index 8d033b075f..a699c326cf 100644 --- a/lib/scheduler/uci_scheduling/uci_allocator_impl.cpp +++ b/lib/scheduler/uci_scheduling/uci_allocator_impl.cpp @@ -214,6 +214,9 @@ std::optional uci_allocator_impl::alloc_uci_harq_ue(cell_resourc if (not cell_cfg.is_fully_ul_enabled(uci_slot)) { continue; } + if (not ue_cell_cfg.is_ul_enabled(uci_slot)) { + continue; + } if (uci_alloc_grid[slot_alloc.slot.to_uint()].ucis.full()) { logger.info( diff --git a/lib/scheduler/ue_scheduling/ue_cell.cpp b/lib/scheduler/ue_scheduling/ue_cell.cpp index 83b8fee31b..b5f03a4408 100644 --- a/lib/scheduler/ue_scheduling/ue_cell.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell.cpp @@ -111,6 +111,22 @@ void ue_cell::set_fallback_state(bool set_fallback) logger.debug("ue={} rnti={}: {} fallback mode", ue_index, rnti(), in_fallback_mode ? "Entering" : "Leaving"); } +bool ue_cell::is_dl_enabled(slot_point dl_slot) const +{ + if (not active) { + return false; + } + return cfg().is_dl_enabled(dl_slot); +} + +bool ue_cell::is_ul_enabled(slot_point ul_slot) const +{ + if (not active) { + return false; + } + return cfg().is_ul_enabled(ul_slot); +} + std::optional ue_cell::handle_dl_ack_info(slot_point uci_slot, mac_harq_ack_report_status ack_value, unsigned harq_bit_idx, diff --git a/lib/scheduler/ue_scheduling/ue_cell.h b/lib/scheduler/ue_scheduling/ue_cell.h index ad220f0ab3..985a9813fd 100644 --- a/lib/scheduler/ue_scheduling/ue_cell.h +++ b/lib/scheduler/ue_scheduling/ue_cell.h @@ -72,6 +72,9 @@ class ue_cell void set_fallback_state(bool in_fallback); + bool is_dl_enabled(slot_point dl_slot) const; + bool is_ul_enabled(slot_point ul_slot) const; + struct dl_ack_info_result { dl_harq_process_handle::status_update update; dl_harq_process_handle h_dl; diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index a9f3c627d2..7f56374720 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -341,8 +341,8 @@ class cu_cp_simulator : public srs_du::f1c_connection_client int_to_gnb_du_ue_f1ap_id(init_msg.value.ul_rrc_msg_transfer()->gnb_du_ue_f1ap_id); gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(init_msg.value.ul_rrc_msg_transfer()->gnb_du_ue_f1ap_id); - f1ap_message uectxt_msg = - test_helpers::create_ue_context_setup_request(cu_ue_id, du_ue_id, 0, {drb_id_t::drb1}); + f1ap_message uectxt_msg = test_helpers::create_ue_context_setup_request( + cu_ue_id, du_ue_id, 0, {drb_id_t::drb1}, config_helpers::make_default_du_cell_config().nr_cgi); auto& ue_ctxt_setup = *uectxt_msg.pdu.init_msg().value.ue_context_setup_request(); // Do not send RRC container, otherwise we have to send an RLC ACK. ue_ctxt_setup.rrc_container_present = false; diff --git a/tests/integrationtests/du_high/du_high_test.cpp b/tests/integrationtests/du_high/du_high_test.cpp index d9d73b8210..9a032c0f81 100644 --- a/tests/integrationtests/du_high/du_high_test.cpp +++ b/tests/integrationtests/du_high/du_high_test.cpp @@ -202,7 +202,8 @@ TEST_F(du_high_tester, when_ue_context_setup_received_for_inexistent_ue_then_ue_ gnb_cu_ue_f1ap_id_t cu_ue_id = int_to_gnb_cu_ue_f1ap_id(test_rgen::uniform_int(0, (uint64_t)gnb_cu_ue_f1ap_id_t::max)); - f1ap_message cu_cp_msg = test_helpers::create_ue_context_setup_request(cu_ue_id, std::nullopt, 0, {drb_id_t::drb1}); + f1ap_message cu_cp_msg = test_helpers::create_ue_context_setup_request( + cu_ue_id, std::nullopt, 0, {drb_id_t::drb1}, {plmn_identity::test_value(), nr_cell_identity::create(0).value()}); this->du_hi->get_f1ap_message_handler().handle_message(cu_cp_msg); ASSERT_TRUE(this->run_until([this]() { return not cu_notifier.last_f1ap_msgs.empty(); })); diff --git a/tests/integrationtests/du_high/mac_test_mode_adapter_test.cpp b/tests/integrationtests/du_high/mac_test_mode_adapter_test.cpp index 7d31430b37..08956a1d33 100644 --- a/tests/integrationtests/du_high/mac_test_mode_adapter_test.cpp +++ b/tests/integrationtests/du_high/mac_test_mode_adapter_test.cpp @@ -8,7 +8,7 @@ * */ -#include "lib/du/du_high/adapters/mac_test_mode_adapter.h" +#include "lib/du/du_high/test_mode/mac_test_mode_adapter.h" #include "tests/unittests/mac/mac_test_helpers.h" #include "srsran/ran/csi_report/csi_report_config_helpers.h" #include "srsran/ran/csi_report/csi_report_on_pucch_helpers.h" diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index 3350a03ced..52afc18303 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -425,8 +425,12 @@ bool du_high_env_simulator::run_ue_context_setup(rnti_t rnti) // DU receives UE Context Setup Request. cu_notifier.last_f1ap_msgs.clear(); - f1ap_message msg = test_helpers::create_ue_context_setup_request( - *u.cu_ue_id, u.du_ue_id, u.srbs[LCID_SRB1].next_pdcp_sn++, {drb_id_t::drb1}); + f1ap_message msg = + test_helpers::create_ue_context_setup_request(*u.cu_ue_id, + u.du_ue_id, + u.srbs[LCID_SRB1].next_pdcp_sn++, + {drb_id_t::drb1}, + {plmn_identity::test_value(), nr_cell_identity::create(0).value()}); asn1::f1ap::ue_context_setup_request_s& cmd = msg.pdu.init_msg().value.ue_context_setup_request(); cmd->drbs_to_be_setup_list[0] .value() diff --git a/tests/test_doubles/f1ap/f1ap_test_messages.cpp b/tests/test_doubles/f1ap/f1ap_test_messages.cpp index 5e44312b0b..3782ac8d37 100644 --- a/tests/test_doubles/f1ap/f1ap_test_messages.cpp +++ b/tests/test_doubles/f1ap/f1ap_test_messages.cpp @@ -173,7 +173,8 @@ static drbs_to_be_setup_item_s generate_drb_am_setup_item(drb_id_t drbid) f1ap_message srsran::test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t cu_ue_id, std::optional du_ue_id, uint32_t rrc_container_pdcp_sn, - const std::vector& drbs_to_setup) + const std::vector& drbs_to_setup, + nr_cell_global_id_t nr_cgi) { using namespace asn1::f1ap; f1ap_message msg; @@ -187,6 +188,10 @@ f1ap_message srsran::test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1a dl_msg->gnb_du_ue_f1ap_id = (unsigned)*du_ue_id; } + // spCell. + dl_msg->sp_cell_id.plmn_id = nr_cgi.plmn_id.to_bytes(); + dl_msg->sp_cell_id.nr_cell_id.from_number(nr_cgi.nci.value()); + // SRB2. dl_msg->srbs_to_be_setup_list_present = true; dl_msg->srbs_to_be_setup_list.resize(1); @@ -194,7 +199,7 @@ f1ap_message srsran::test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1a srbs_to_be_setup_item_s& srb2 = dl_msg->srbs_to_be_setup_list[0]->srbs_to_be_setup_item(); srb2.srb_id = 2; - // drbs-to-be-setup + // drbs-to-be-setup. dl_msg->drbs_to_be_setup_list_present = drbs_to_setup.size() > 0; dl_msg->drbs_to_be_setup_list.resize(drbs_to_setup.size()); unsigned count = 0; diff --git a/tests/test_doubles/f1ap/f1ap_test_messages.h b/tests/test_doubles/f1ap/f1ap_test_messages.h index 1797c4340b..3acbf9f722 100644 --- a/tests/test_doubles/f1ap/f1ap_test_messages.h +++ b/tests/test_doubles/f1ap/f1ap_test_messages.h @@ -18,7 +18,7 @@ #include "srsran/f1ap/f1ap_ue_id_types.h" #include "srsran/ran/gnb_du_id.h" #include "srsran/ran/lcid.h" -#include "srsran/ran/nr_cell_identity.h" +#include "srsran/ran/nr_cgi.h" #include "srsran/ran/pci.h" #include "srsran/ran/rnti.h" @@ -54,7 +54,8 @@ f1ap_message generate_f1_removal_response(const f1ap_message& f1_removal_request f1ap_message create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t cu_ue_id, std::optional du_ue_id, uint32_t rrc_container_pdcp_sn, - const std::vector& drbs_to_setup); + const std::vector& drbs_to_setup, + nr_cell_global_id_t nr_cgi); /// \brief Generates F1AP Initial UL RRC TRANSFER message. f1ap_message create_init_ul_rrc_message_transfer(gnb_du_ue_f1ap_id_t du_ue_id, diff --git a/tests/unittests/du_manager/serving_cell_config_converter_test.cpp b/tests/unittests/du_manager/serving_cell_config_converter_test.cpp index e630b96d84..e4205955bc 100644 --- a/tests/unittests/du_manager/serving_cell_config_converter_test.cpp +++ b/tests/unittests/du_manager/serving_cell_config_converter_test.cpp @@ -1125,11 +1125,10 @@ TEST(serving_cell_config_converter_test, test_custom_csi_meas_cfg_conversion) dest_csi_meas_cfg.report_trigger_size = 2; - dest_csi_meas_cfg.aperiodic_trigger_state_list.emplace(); auto associated_report_cfg_info_list = csi_associated_report_config_info{.report_cfg_id = static_cast(1), .res_for_channel = csi_associated_report_config_info::csi_ssb_resource_set{1}}; - dest_csi_meas_cfg.aperiodic_trigger_state_list.value().push_back( + dest_csi_meas_cfg.aperiodic_trigger_state_list.push_back( csi_aperiodic_trigger_state{.associated_report_cfg_info_list = {associated_report_cfg_info_list}}); dest_csi_meas_cfg.semi_persistent_on_pusch_trigger_state_list.emplace(); diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp index 03d0cf6d44..74f5808c00 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_modification_test.cpp @@ -26,8 +26,8 @@ class f1ap_du_ue_context_modification_test : public f1ap_du_test // Test Preamble. run_f1_setup_procedure(); run_f1ap_ue_create(test_ue_index); - f1ap_message msg = - test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {}); + f1ap_message msg = test_helpers::create_ue_context_setup_request( + gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {}, config_helpers::make_default_du_cell_config().nr_cgi); run_ue_context_setup_procedure(test_ue_index, msg); this->f1c_gw.clear_tx_pdus(); diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_release_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_release_test.cpp index f7d0aeea80..b1568b5260 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_release_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_release_test.cpp @@ -25,8 +25,8 @@ class f1ap_du_ue_context_release_test : public f1ap_du_test run_f1_setup_procedure(); du_ue_index_t ue_index = to_du_ue_index(test_rgen::uniform_int(0, MAX_DU_UE_INDEX)); test_ue = run_f1ap_ue_create(ue_index); - f1ap_message msg = - test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {}); + f1ap_message msg = test_helpers::create_ue_context_setup_request( + gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {}, config_helpers::make_default_du_cell_config().nr_cgi); run_ue_context_setup_procedure(ue_index, msg); } diff --git a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp index fcad4071d6..a8bb17ec4e 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ue_context_setup_procedure_test.cpp @@ -10,6 +10,8 @@ #include "f1ap_du_test_helpers.h" #include "tests/test_doubles/f1ap/f1ap_test_messages.h" + +#include "srsran/du/du_cell_config_helpers.h" #include "srsran/support/test_utils.h" #include @@ -100,8 +102,11 @@ class f1ap_du_ue_context_setup_test : public f1ap_du_test TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_notifies_du_of_ue_context_update) { du_creates_f1_logical_connection(); - start_procedure(test_helpers::create_ue_context_setup_request( - gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1})); + start_procedure(test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, + gnb_du_ue_f1ap_id_t{0}, + 1, + {drb_id_t::drb1}, + config_helpers::make_default_du_cell_config().nr_cgi)); // DU manager receives UE Context Update Request. ASSERT_TRUE(this->f1ap_du_cfg_handler.last_ue_context_update_req.has_value()); @@ -118,8 +123,12 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_notif TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_responds_back_with_ue_context_setup_response) { du_creates_f1_logical_connection(); - f1ap_message msg = test_helpers::create_ue_context_setup_request( - gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1}); + f1ap_message msg = + test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, + gnb_du_ue_f1ap_id_t{0}, + 1, + {drb_id_t::drb1}, + config_helpers::make_default_du_cell_config().nr_cgi); start_procedure(msg); // Lower layers handle RRC container. @@ -154,8 +163,12 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_f1ap_respo TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_the_rrc_container_is_sent_dl_via_srb1) { du_creates_f1_logical_connection(); - f1ap_message msg = test_helpers::create_ue_context_setup_request( - gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1}); + f1ap_message msg = + test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, + gnb_du_ue_f1ap_id_t{0}, + 1, + {drb_id_t::drb1}, + config_helpers::make_default_du_cell_config().nr_cgi); start_procedure(msg); // F1AP sends RRC Container present in UE CONTEXT SETUP REQUEST via SRB1. @@ -166,8 +179,12 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_the_rrc_co TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_new_srbs_become_active) { du_creates_f1_logical_connection(); - f1ap_message msg = test_helpers::create_ue_context_setup_request( - gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {drb_id_t::drb1}); + f1ap_message msg = + test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, + gnb_du_ue_f1ap_id_t{0}, + 1, + {drb_id_t::drb1}, + config_helpers::make_default_du_cell_config().nr_cgi); run_ue_context_setup_procedure(test_ue->ue_index, msg); // UL data through created SRB2 reaches F1-C. @@ -185,8 +202,8 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_then_new_srbs_b TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ue_f1ap_id_then_ue_is_created) { - f1ap_message msg = - test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, std::nullopt, 1, {drb_id_t::drb1}); + f1ap_message msg = test_helpers::create_ue_context_setup_request( + gnb_cu_ue_f1ap_id_t{0}, std::nullopt, 1, {drb_id_t::drb1}, config_helpers::make_default_du_cell_config().nr_cgi); start_procedure(msg); @@ -196,8 +213,8 @@ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ TEST_F(f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ue_f1ap_id_then_ue_context_is_updated) { - f1ap_message msg = - test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, std::nullopt, 1, {drb_id_t::drb1}); + f1ap_message msg = test_helpers::create_ue_context_setup_request( + gnb_cu_ue_f1ap_id_t{0}, std::nullopt, 1, {drb_id_t::drb1}, config_helpers::make_default_du_cell_config().nr_cgi); start_procedure(msg); @@ -214,8 +231,8 @@ TEST_F( f1ap_du_ue_context_setup_test, when_f1ap_receives_request_without_gnb_du_ue_f1ap_id_then_ue_context_setup_response_is_sent_to_cu_cp_with_crnti_ie) { - f1ap_message msg = - test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, std::nullopt, 1, {drb_id_t::drb1}); + f1ap_message msg = test_helpers::create_ue_context_setup_request( + gnb_cu_ue_f1ap_id_t{0}, std::nullopt, 1, {drb_id_t::drb1}, config_helpers::make_default_du_cell_config().nr_cgi); start_procedure(msg); on_rrc_container_transmitted(1); diff --git a/tests/unittests/f1ap/du/f1ap_du_ul_rrc_message_transfer_test.cpp b/tests/unittests/f1ap/du/f1ap_du_ul_rrc_message_transfer_test.cpp index 5e0aab80b6..075d2308e8 100644 --- a/tests/unittests/f1ap/du/f1ap_du_ul_rrc_message_transfer_test.cpp +++ b/tests/unittests/f1ap/du/f1ap_du_ul_rrc_message_transfer_test.cpp @@ -23,9 +23,9 @@ TEST_F(f1ap_du_test, when_sdu_is_received_then_sdu_is_forwarded_to_tx_pdu_notifi { // Run Test Preamble. run_f1_setup_procedure(); - ue_test_context* ue = run_f1ap_ue_create(to_du_ue_index(0)); - f1ap_message msg = - test_helpers::create_ue_context_setup_request(gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {}); + ue_test_context* ue = run_f1ap_ue_create(to_du_ue_index(0)); + f1ap_message msg = test_helpers::create_ue_context_setup_request( + gnb_cu_ue_f1ap_id_t{0}, gnb_du_ue_f1ap_id_t{0}, 1, {}, config_helpers::make_default_du_cell_config().nr_cgi); run_ue_context_setup_procedure(ue->ue_index, msg); this->f1c_gw.clear_tx_pdus();